/* Jabber Protocol Plugin for Miranda IM Copyright ( C ) 2002-04 Santithorn Bunchua Copyright ( C ) 2005-12 George Hazan Copyright ( C ) 2007 Maxim Mluhov 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. */ #ifndef _JABBER_IQ_H_ #define _JABBER_IQ_H_ #include "jabber_xml.h" class CJabberIqInfo; typedef enum { IQ_PROC_NONE, IQ_PROC_GETAGENTS, IQ_PROC_GETREGISTER, IQ_PROC_SETREGISTER, IQ_PROC_GETVCARD, IQ_PROC_SETVCARD, IQ_PROC_GETSEARCH, IQ_PROC_GETSEARCHFIELDS, IQ_PROC_BROWSEROOMS, IQ_PROC_DISCOROOMSERVER, IQ_PROC_DISCOAGENTS, IQ_PROC_DISCOBOOKMARKS, IQ_PROC_SETBOOKMARKS, IQ_PROC_DISCOCOMMANDS, IQ_PROC_EXECCOMMANDS, } JABBER_IQ_PROCID; struct CJabberProto; typedef void ( CJabberProto::*JABBER_IQ_PFUNC )( HXML iqNode ); typedef void ( *IQ_USER_DATA_FREE_FUNC )( void *pUserData ); typedef struct { TCHAR* xmlns; JABBER_IQ_PFUNC func; BOOL allowSubNs; // e.g. #info in disco#info } JABBER_IQ_XMLNS_FUNC; void __stdcall replaceStr( char*& dest, const char* src ); void __stdcall replaceStr( WCHAR*& dest, const WCHAR* src ); // 2 minutes, milliseconds #define JABBER_DEFAULT_IQ_REQUEST_TIMEOUT 120000 typedef void ( CJabberProto::*JABBER_IQ_HANDLER )( HXML iqNode, CJabberIqInfo* pInfo ); typedef BOOL ( CJabberProto::*JABBER_PERMANENT_IQ_HANDLER )( HXML iqNode, CJabberIqInfo* pInfo ); #define JABBER_IQ_PARSE_CHILD_TAG_NODE (1) #define JABBER_IQ_PARSE_CHILD_TAG_NAME ((1<<1)|JABBER_IQ_PARSE_CHILD_TAG_NODE) #define JABBER_IQ_PARSE_CHILD_TAG_XMLNS ((1<<2)|JABBER_IQ_PARSE_CHILD_TAG_NODE) #define JABBER_IQ_PARSE_FROM (1<<3) #define JABBER_IQ_PARSE_HCONTACT ((1<<4)|JABBER_IQ_PARSE_FROM) #define JABBER_IQ_PARSE_TO (1<<5) #define JABBER_IQ_PARSE_ID_STR (1<<6) #define JABBER_IQ_PARSE_DEFAULT (JABBER_IQ_PARSE_CHILD_TAG_NODE|JABBER_IQ_PARSE_CHILD_TAG_NAME|JABBER_IQ_PARSE_CHILD_TAG_XMLNS) class CJabberIqInfo { protected: friend class CJabberIqManager; JABBER_IQ_HANDLER m_pHandler; CJabberIqInfo* m_pNext; int m_nIqId; DWORD m_dwParamsToParse; DWORD m_dwRequestTime; DWORD m_dwTimeout; TCHAR *m_szReceiver; int m_iPriority; public: void *m_pUserData; public:// parsed data int m_nIqType; TCHAR *m_szFrom; TCHAR *m_szChildTagXmlns; TCHAR *m_szChildTagName; HXML m_pChildNode; HANDLE m_hContact; TCHAR *m_szTo; TCHAR *m_szId; public: CJabberIqInfo() { ZeroMemory(this, sizeof(CJabberIqInfo)); } ~CJabberIqInfo() { if (m_szReceiver) mir_free(m_szReceiver); } void SetReceiver(const TCHAR *szReceiver) { replaceStr(m_szReceiver, szReceiver); } TCHAR* GetReceiver() { return m_szReceiver; } void SetParamsToParse(DWORD dwParamsToParse) { m_dwParamsToParse = dwParamsToParse; } void SetTimeout(DWORD dwTimeout) { m_dwTimeout = dwTimeout; } int GetIqId() { return m_nIqId; } DWORD GetRequestTime() { return m_dwRequestTime; } int GetIqType() { return m_nIqType; } void* GetUserData() { return m_pUserData; } TCHAR* GetFrom() { return m_szFrom; } TCHAR* GetTo() { return m_szTo; } TCHAR* GetIdStr() { return m_szId; } HANDLE GetHContact() { return m_hContact; } HXML GetChildNode() { return m_pChildNode; } TCHAR* GetChildNodeName() { return m_szChildTagName; } char* GetCharIqType() { switch (m_nIqType) { case JABBER_IQ_TYPE_SET: return "set"; case JABBER_IQ_TYPE_GET: return "get"; case JABBER_IQ_TYPE_ERROR: return "error"; case JABBER_IQ_TYPE_RESULT: return "result"; } return NULL; } }; class CJabberIqPermanentInfo { friend class CJabberIqManager; CJabberIqPermanentInfo* m_pNext; JABBER_PERMANENT_IQ_HANDLER m_pHandler; DWORD m_dwParamsToParse; int m_nIqTypes; TCHAR* m_szXmlns; TCHAR* m_szTag; BOOL m_bAllowPartialNs; void *m_pUserData; IQ_USER_DATA_FREE_FUNC m_pUserDataFree; int m_iPriority; public: CJabberIqPermanentInfo() { ZeroMemory(this, sizeof(CJabberIqPermanentInfo)); } ~CJabberIqPermanentInfo() { if ( m_pUserDataFree ) m_pUserDataFree(m_pUserData); mir_free(m_szXmlns); mir_free(m_szTag); } }; class CJabberIqManager { protected: CJabberProto* ppro; CRITICAL_SECTION m_cs; DWORD m_dwLastUsedHandle; CJabberIqInfo* m_pIqs; // list of iqs ordered by priority HANDLE m_hExpirerThread; BOOL m_bExpirerThreadShutdownRequest; CJabberIqPermanentInfo* m_pPermanentHandlers; CJabberIqInfo* DetachInfo(int nIqId) { if (!m_pIqs) return NULL; CJabberIqInfo* pInfo = m_pIqs; if (m_pIqs->m_nIqId == nIqId) { m_pIqs = pInfo->m_pNext; pInfo->m_pNext = NULL; return pInfo; } while (pInfo->m_pNext) { if (pInfo->m_pNext->m_nIqId == nIqId) { CJabberIqInfo* pRetVal = pInfo->m_pNext; pInfo->m_pNext = pInfo->m_pNext->m_pNext; pRetVal->m_pNext = NULL; return pRetVal; } pInfo = pInfo->m_pNext; } return NULL; } CJabberIqInfo* DetachInfo(void *pUserData) { if (!m_pIqs) return NULL; CJabberIqInfo* pInfo = m_pIqs; if (m_pIqs->m_pUserData == pUserData) { m_pIqs = pInfo->m_pNext; pInfo->m_pNext = NULL; return pInfo; } while (pInfo->m_pNext) { if (pInfo->m_pNext->m_pUserData == pUserData) { CJabberIqInfo* pRetVal = pInfo->m_pNext; pInfo->m_pNext = pInfo->m_pNext->m_pNext; pRetVal->m_pNext = NULL; return pRetVal; } pInfo = pInfo->m_pNext; } return NULL; } CJabberIqInfo* DetachExpired() { if (!m_pIqs) return NULL; DWORD dwCurrentTime = GetTickCount(); CJabberIqInfo* pInfo = m_pIqs; if (dwCurrentTime - pInfo->m_dwRequestTime > pInfo->m_dwTimeout ) { m_pIqs = pInfo->m_pNext; pInfo->m_pNext = NULL; return pInfo; } while (pInfo->m_pNext) { if (dwCurrentTime - pInfo->m_pNext->m_dwRequestTime > pInfo->m_pNext->m_dwTimeout ) { CJabberIqInfo* pRetVal = pInfo->m_pNext; pInfo->m_pNext = pInfo->m_pNext->m_pNext; pRetVal->m_pNext = NULL; return pRetVal; } pInfo = pInfo->m_pNext; } return NULL; } void ExpireInfo( CJabberIqInfo* pInfo, void *pUserData = NULL ); BOOL InsertIq(CJabberIqInfo* pInfo) { // inserts pInfo at a place determined by pInfo->m_iPriority Lock(); if (!m_pIqs) m_pIqs = pInfo; else { if (m_pIqs->m_iPriority > pInfo->m_iPriority) { pInfo->m_pNext = m_pIqs; m_pIqs = pInfo; } else { CJabberIqInfo* pTmp = m_pIqs; while (pTmp->m_pNext && pTmp->m_pNext->m_iPriority <= pInfo->m_iPriority) pTmp = pTmp->m_pNext; pInfo->m_pNext = pTmp->m_pNext; pTmp->m_pNext = pInfo; } } Unlock(); return TRUE; } public: CJabberIqManager( CJabberProto* proto ) { InitializeCriticalSection(&m_cs); m_dwLastUsedHandle = 0; m_pIqs = NULL; m_hExpirerThread = NULL; m_pPermanentHandlers = NULL; ppro = proto; } ~CJabberIqManager() { ExpireAll(); Lock(); CJabberIqPermanentInfo *pInfo = m_pPermanentHandlers; while ( pInfo ) { CJabberIqPermanentInfo *pTmp = pInfo->m_pNext; delete pInfo; pInfo = pTmp; } m_pPermanentHandlers = NULL; Unlock(); DeleteCriticalSection(&m_cs); } BOOL Start(); BOOL Shutdown() { if ( m_bExpirerThreadShutdownRequest || !m_hExpirerThread ) return TRUE; m_bExpirerThreadShutdownRequest = TRUE; WaitForSingleObject( m_hExpirerThread, INFINITE ); CloseHandle( m_hExpirerThread ); m_hExpirerThread = NULL; return TRUE; } void Lock() { EnterCriticalSection(&m_cs); } void Unlock() { LeaveCriticalSection(&m_cs); } // fucking params, maybe just return CJabberIqRequestInfo pointer ? CJabberIqInfo* AddHandler(JABBER_IQ_HANDLER pHandler, int nIqType = JABBER_IQ_TYPE_GET, const TCHAR *szReceiver = NULL, DWORD dwParamsToParse = 0, int nIqId = -1, void *pUserData = NULL, int iPriority = JH_PRIORITY_DEFAULT); CJabberIqPermanentInfo* AddPermanentHandler(JABBER_PERMANENT_IQ_HANDLER pHandler, int nIqTypes, DWORD dwParamsToParse, const TCHAR* szXmlns, BOOL bAllowPartialNs, const TCHAR* szTag, void *pUserData = NULL, IQ_USER_DATA_FREE_FUNC pUserDataFree = NULL, int iPriority = JH_PRIORITY_DEFAULT) { CJabberIqPermanentInfo* pInfo = new CJabberIqPermanentInfo(); if (!pInfo) return NULL; pInfo->m_pHandler = pHandler; pInfo->m_nIqTypes = nIqTypes ? nIqTypes : JABBER_IQ_TYPE_ANY; replaceStr( pInfo->m_szXmlns, szXmlns ); pInfo->m_bAllowPartialNs = bAllowPartialNs; replaceStr( pInfo->m_szTag, szTag ); pInfo->m_dwParamsToParse = dwParamsToParse; pInfo->m_pUserData = pUserData; pInfo->m_pUserDataFree = pUserDataFree; pInfo->m_iPriority = iPriority; Lock(); if (!m_pPermanentHandlers) m_pPermanentHandlers = pInfo; else { if (m_pPermanentHandlers->m_iPriority > pInfo->m_iPriority) { pInfo->m_pNext = m_pPermanentHandlers; m_pPermanentHandlers = pInfo; } else { CJabberIqPermanentInfo* pTmp = m_pPermanentHandlers; while (pTmp->m_pNext && pTmp->m_pNext->m_iPriority <= pInfo->m_iPriority) pTmp = pTmp->m_pNext; pInfo->m_pNext = pTmp->m_pNext; pTmp->m_pNext = pInfo; } } Unlock(); return pInfo; } BOOL DeletePermanentHandler(CJabberIqPermanentInfo *pInfo) { // returns TRUE when pInfo found, or FALSE otherwise Lock(); if (!m_pPermanentHandlers) { Unlock(); return FALSE; } if (m_pPermanentHandlers == pInfo) // check first item { m_pPermanentHandlers = m_pPermanentHandlers->m_pNext; delete pInfo; Unlock(); return TRUE; } else { CJabberIqPermanentInfo* pTmp = m_pPermanentHandlers; while (pTmp->m_pNext) { if (pTmp->m_pNext == pInfo) { pTmp->m_pNext = pTmp->m_pNext->m_pNext; delete pInfo; Unlock(); return TRUE; } pTmp = pTmp->m_pNext; } } Unlock(); return FALSE; } BOOL DeleteHandler(CJabberIqInfo *pInfo) { // returns TRUE when pInfo found, or FALSE otherwise Lock(); if (!m_pIqs) { Unlock(); return FALSE; } if (m_pIqs == pInfo) // check first item { m_pIqs = m_pIqs->m_pNext; Unlock(); ExpireInfo(pInfo); // must expire it to allow the handler to free m_pUserData if necessary delete pInfo; return TRUE; } else { CJabberIqInfo* pTmp = m_pIqs; while (pTmp->m_pNext) { if (pTmp->m_pNext == pInfo) { pTmp->m_pNext = pTmp->m_pNext->m_pNext; Unlock(); ExpireInfo(pInfo); // must expire it to allow the handler to free m_pUserData if necessary delete pInfo; return TRUE; } pTmp = pTmp->m_pNext; } } Unlock(); return FALSE; } BOOL HandleIq(int nIqId, HXML pNode); BOOL HandleIqPermanent(HXML pNode); BOOL ExpireIq(int nIqId) { Lock(); CJabberIqInfo* pInfo = DetachInfo(nIqId); Unlock(); if (pInfo) { ExpireInfo(pInfo); delete pInfo; return TRUE; } return FALSE; } void ExpirerThread( void ); BOOL ExpireByUserData(void *pUserData) { BOOL bRetVal = FALSE; while (1) { Lock(); CJabberIqInfo* pInfo = DetachInfo(pUserData); Unlock(); if (!pInfo) break; ExpireInfo(pInfo, NULL); delete pInfo; bRetVal = TRUE; } return bRetVal; } BOOL ExpireAll(void *pUserData = NULL) { while (1) { Lock(); CJabberIqInfo* pInfo = m_pIqs; if (pInfo) m_pIqs = m_pIqs->m_pNext; Unlock(); if (!pInfo) break; pInfo->m_pNext = NULL; ExpireInfo(pInfo, pUserData); delete pInfo; } return TRUE; } BOOL FillPermanentHandlers(); }; #endif