/* 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; // 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) { replaceStrT(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; replaceStrT(pInfo->m_szXmlns, szXmlns); pInfo->m_bAllowPartialNs = bAllowPartialNs; replaceStrT(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