summaryrefslogtreecommitdiff
path: root/plugins/ClientChangeNotify/src/CommonLibs
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/ClientChangeNotify/src/CommonLibs')
-rw-r--r--plugins/ClientChangeNotify/src/CommonLibs/CString.cpp376
-rw-r--r--plugins/ClientChangeNotify/src/CommonLibs/CString.h306
-rw-r--r--plugins/ClientChangeNotify/src/CommonLibs/Options.cpp981
-rw-r--r--plugins/ClientChangeNotify/src/CommonLibs/Options.h483
-rw-r--r--plugins/ClientChangeNotify/src/CommonLibs/TMyArray.h353
-rw-r--r--plugins/ClientChangeNotify/src/CommonLibs/pcre.cpp272
-rw-r--r--plugins/ClientChangeNotify/src/CommonLibs/pcre.h30
-rw-r--r--plugins/ClientChangeNotify/src/CommonLibs/pcre_main.h298
8 files changed, 3099 insertions, 0 deletions
diff --git a/plugins/ClientChangeNotify/src/CommonLibs/CString.cpp b/plugins/ClientChangeNotify/src/CommonLibs/CString.cpp
new file mode 100644
index 0000000000..fde5e4dc2a
--- /dev/null
+++ b/plugins/ClientChangeNotify/src/CommonLibs/CString.cpp
@@ -0,0 +1,376 @@
+/*
+ TCString.cpp - TCString class
+ Copyright (c) 2005-2008 Chervov Dmitry
+
+ 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 "Common.h"
+#include "CString.h"
+
+#define STR_GROWBY 64
+
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+
+
+template <class T>
+void TString<T>::Empty()
+{
+ nBufSize = 1;
+ SetAllocSize(STR_GROWBY);
+ pBuf[0] = 0;
+}
+
+
+template <class T>
+void TString<T>::Free()
+{
+// HeapFree(GetProcessHeap(), 0, pBuf);
+ free(pBuf);
+ pBuf = NULL;
+ nBufSize = 0;
+ nAllocSize = 0;
+}
+
+
+template <class T>
+T *TString<T>::GetBuffer(int nNewLen)
+{
+ if (nNewLen != -1)
+ {
+ SetBufSize(nNewLen + 1);
+ }
+ _ASSERT(pBuf);
+ return pBuf;
+}
+
+
+template <class T>
+void TString<T>::ReleaseBuffer(int nNewLen)
+{
+ if (nNewLen == -1)
+ {
+ nBufSize = My_lstrlen(pBuf) + 1;
+ } else
+ {
+ nBufSize = nNewLen + 1;
+ pBuf[nNewLen] = 0;
+ _ASSERT(My_lstrlen(pBuf) == nNewLen);
+ }
+ _ASSERT(nBufSize <= nAllocSize); // prevent buffer overruns
+}
+
+
+template <class T>
+void TString<T>::SetAllocSize(int nNewAllocSize)
+{
+ _ASSERT(nNewAllocSize > 0);
+ T *pNewBuf = /*(char *)HeapAlloc(GetProcessHeap(), 0, sizeof(char) * nNewAllocSize);*/
+(T *)malloc(sizeof(T) * nNewAllocSize);
+ if (pBuf)
+ {
+ memcpy(pNewBuf, pBuf, sizeof(T) * min(nBufSize, nNewAllocSize));
+ //HeapFree(GetProcessHeap(), 0, pBuf);
+ free(pBuf);
+ }
+ pBuf = pNewBuf;
+ nAllocSize = nNewAllocSize;
+}
+
+
+template <class T>
+void TString<T>::SetBufSize(int nNewBufSize)
+{
+ _ASSERT(nNewBufSize >= 0);
+ if (nNewBufSize < nBufSize)
+ {
+ _ASSERT(pBuf);
+ pBuf[nNewBufSize - 1] = 0;
+ }
+ if ((unsigned)(nAllocSize - nNewBufSize) / STR_GROWBY)
+ {
+ SetAllocSize((nNewBufSize + STR_GROWBY - 1) - (nNewBufSize + STR_GROWBY - 1) % STR_GROWBY);
+ }
+ nBufSize = nNewBufSize;
+}
+
+
+template <class T>
+TString<T>& TString<T>::Cat(const T *pStr)
+{
+ _ASSERT(pBuf && pStr);
+ int StrLen = My_lstrlen(pStr);
+ SetAllocSize(nBufSize + StrLen);
+ My_lstrcpy(GetBuffer() + GetLen(), pStr);
+ ReleaseBuffer(nBufSize + StrLen - 1);
+ return *this;
+}
+
+
+template <class T>
+TString<T>& TString<T>::Cat(const T c)
+{
+ _ASSERT(pBuf);
+ SetAllocSize(nBufSize + 1);
+ int CurLen = GetLen();
+ T *p = GetBuffer();
+ p[CurLen] = c;
+ p[CurLen + 1] = '\0';
+ ReleaseBuffer(nBufSize);
+ return *this;
+}
+
+
+template <class T>
+TString<T>& TString<T>::DiffCat(const T *pStart, const T *pEnd)
+{
+ _ASSERT(pBuf && pStart && pEnd);
+ int StrLen = pEnd - pStart;
+ SetAllocSize(nBufSize + StrLen);
+ My_strncpy(GetBuffer() + GetLen(), pStart, StrLen);
+ ReleaseBuffer(nBufSize + StrLen - 1);
+ return *this;
+}
+
+
+template <class T>
+TString<T>& TString<T>::Replace(const T *szFind, const T *szReplaceBy)
+{
+ if (!pBuf)
+ {
+ return *this;
+ }
+ T *pCurPos = pBuf;
+ int FindLen = My_lstrlen(szFind);
+ T *p;
+ TString<T> Result;
+ Result.GetBuffer(1)[0] = '\0';
+ Result.ReleaseBuffer(0); // set the string to ""; we can't do it in a usual way (using a constructor or an assignment) because we don't know whether "" needs to be unicode or ansi
+ while (p = ( T* )My_strstr(pCurPos, szFind))
+ {
+ Result.DiffCat(pCurPos, p);
+ Result += szReplaceBy;
+ pCurPos = p + FindLen;
+ }
+ Result += pCurPos;
+ *this = Result;
+ return *this;
+}
+
+
+template <class T>
+TString<T>& TString<T>::Replace(int nIndex, int nCount, const T *szReplaceBy)
+{
+ if (!pBuf || !szReplaceBy || nIndex < 0 || nCount < 0)
+ {
+ return *this;
+ }
+
+ TString<T> Result;
+ Result.GetBuffer(1)[0] = '\0';
+ Result.ReleaseBuffer(0); // set the string to ""; we can't do it in a usual way (using a constructor or an assignment) because we don't know whether "" needs to be unicode or ansi
+ if (nIndex > GetLen())
+ {
+ nIndex = GetLen();
+ }
+ if (nIndex + nCount > GetLen())
+ {
+ nCount = GetLen() - nIndex;
+ }
+ Result.DiffCat(pBuf, pBuf + nIndex);
+ Result += szReplaceBy;
+ Result += pBuf + nIndex + nCount;
+ *this = Result;
+ return *this;
+}
+
+
+template <class T>
+TString<T> TString<T>::Left(int nCount) const
+{
+ _ASSERT(nCount >= 0);
+ TString<T> Result(*this);
+ Result.SetBufSize(nCount + 1);
+ return Result;
+}
+
+
+template <class T>
+TString<T> TString<T>::Right(int nCount) const
+{
+ _ASSERT(nCount >= 0);
+ if (nCount < GetLen())
+ {
+ return &pBuf[GetLen() - nCount];
+ } else
+ {
+ return *this;
+ }
+}
+
+
+template <class T>
+TString<T> TString<T>::SubStr(int nIndex, int nCount) const
+{
+ _ASSERT(nIndex >= 0 && nCount >= 0);
+ TString<T> Result;
+ if (nIndex < GetLen())
+ {
+ My_strncpy(Result.GetBuffer(nCount), &pBuf[nIndex], nCount);
+ Result.ReleaseBuffer();
+ } else
+ {
+ Result.GetBuffer(1)[0] = '\0';
+ Result.ReleaseBuffer(0);
+ }
+ return Result;
+}
+
+
+template <class T>
+TString<T> TString<T>::ToLower() const
+{
+ TString<T> Result(*this);
+ if (!pBuf)
+ {
+ return Result; // return NULL string
+ }
+ My_strlwr((T*)Result);
+ return Result;
+}
+
+
+template <class T>
+TString<T>& TString<T>::operator = (const T *pStr)
+{
+ if (pStr)
+ {
+ int StrLen = My_lstrlen(pStr);
+ SetBufSize(StrLen + 1);
+ My_lstrcpy(GetBuffer(), pStr);
+ ReleaseBuffer(StrLen);
+ } else
+ {
+ Free();
+ }
+ return *this;
+}
+
+
+/*TCString& TCString::Format(char *pszFormat, ...)
+{
+ va_list argList;
+ va_start(argList, pszFormat);
+ int StrLen = _vscprintf(pszFormat, argList); // it's stupidity. in some versions of msvcrt.dll there's no _vscprintf function, so there's no any way to determine needed string length. so actually I can't use _vsnprintf too.
+ _vsnprintf(GetBuffer(StrLen), StrLen, pszFormat, argList);
+ ReleaseBuffer(StrLen);
+ va_end(argList);
+ return *this;
+}
+*/
+
+template class TString<TCHAR>;
+template class TString<char>;
+template class TString<WCHAR>;
+
+
+CString db_get_s(HANDLE hContact, const char *szModule, const char *szSetting, const char *szDefaultValue)
+{
+ DBVARIANT dbv = {0};
+ DBCONTACTGETSETTING dbcgs;
+ dbcgs.szModule = szModule;
+ dbcgs.pValue = &dbv;
+ dbcgs.szSetting = szSetting;
+ int iRes = CallService(MS_DB_CONTACT_GETSETTING, (WPARAM)hContact, (LPARAM)&dbcgs);
+ CString Result;
+ if (!iRes && dbv.type == DBVT_ASCIIZ)
+ {
+ Result = dbv.pszVal;
+ } else
+ {
+ Result = szDefaultValue;
+ }
+ if (!iRes)
+ {
+ CallService(MS_DB_CONTACT_FREEVARIANT, 0, (LPARAM)&dbv);
+ }
+ return Result;
+}
+
+
+
+TCString db_get_s(HANDLE hContact, const char *szModule, const char *szSetting, const TCHAR *szDefaultValue)
+{
+ DBVARIANT dbv = {0};
+ DBCONTACTGETSETTING dbcgs;
+ dbcgs.szModule = szModule;
+ dbcgs.pValue = &dbv;
+ dbcgs.szSetting = szSetting;
+ dbv.type = DBVT_WCHAR;
+ int iRes = CallService(MS_DB_CONTACT_GETSETTING_STR, (WPARAM)hContact, (LPARAM)&dbcgs);
+ TCString Result;
+ if (!iRes && dbv.type == DBVT_WCHAR)
+ {
+ Result = dbv.ptszVal;
+ } else
+ {
+ Result = szDefaultValue;
+ }
+ if (!iRes)
+ {
+ CallService(MS_DB_CONTACT_FREEVARIANT, 0, (LPARAM)&dbv);
+ }
+ return Result;
+}
+
+
+
+int db_get_s(HANDLE hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv)
+{
+ return db_get_s(hContact, szModule, szSetting, dbv, DBVT_ASCIIZ);
+}
+
+
+
+TCString DBGetContactSettingAsString(HANDLE hContact, const char *szModule, const char *szSetting, const TCHAR *szDefaultValue)
+{ // also converts numeric values to a string
+ DBVARIANT dbv = {0};
+ DBCONTACTGETSETTING dbcgs;
+ dbcgs.szModule = szModule;
+ dbcgs.pValue = &dbv;
+ dbcgs.szSetting = szSetting;
+
+ dbv.type = DBVT_WCHAR;
+ int iRes = CallService(MS_DB_CONTACT_GETSETTING_STR, (WPARAM)hContact, (LPARAM)&dbcgs);
+
+ TCString Result;
+ if (!iRes && (dbv.type == DBVT_ASCIIZ || dbv.type == DBVT_WCHAR))
+ {
+ Result = dbv.ptszVal;
+ } else if (dbv.type == DBVT_BYTE || dbv.type == DBVT_WORD || dbv.type == DBVT_DWORD)
+ {
+ long value = (dbv.type == DBVT_DWORD) ? dbv.dVal : (dbv.type == DBVT_WORD ? dbv.wVal : dbv.bVal);
+ _ultot(value, Result.GetBuffer(64), 10);
+ Result.ReleaseBuffer();
+ } else
+ {
+ Result = szDefaultValue;
+ }
+ if (!iRes)
+ {
+ CallService(MS_DB_CONTACT_FREEVARIANT, 0, (LPARAM)&dbv);
+ }
+ return Result;
+}
diff --git a/plugins/ClientChangeNotify/src/CommonLibs/CString.h b/plugins/ClientChangeNotify/src/CommonLibs/CString.h
new file mode 100644
index 0000000000..c9a4a9538e
--- /dev/null
+++ b/plugins/ClientChangeNotify/src/CommonLibs/CString.h
@@ -0,0 +1,306 @@
+/*
+ TCString.h - TCString class
+ Copyright (c) 2005-2008 Chervov Dmitry
+
+ 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
+*/
+
+#pragma once
+
+#include <windows.h>
+#include <tchar.h>
+#include <crtdbg.h>
+#ifdef CHARARRAY_CONVERT
+#include "TMyArray.h"
+#endif
+#include "newpluginapi.h"
+#include "m_system.h"
+#include "m_database.h"
+
+__inline int My_lstrlen(LPCSTR lpString) {return lstrlenA(lpString);}
+__inline int My_lstrlen(LPCWSTR lpString) {return lstrlenW(lpString);}
+__inline int My_lstrcmp(LPCSTR lpString1, LPCSTR lpString2) {return lstrcmpA(lpString1, lpString2);}
+__inline int My_lstrcmp(LPCWSTR lpString1, LPCWSTR lpString2) {return lstrcmpW(lpString1, lpString2);}
+__inline LPCSTR My_strstr(LPCSTR lpString1, LPCSTR lpString2) {return strstr(lpString1, lpString2);}
+__inline LPWSTR My_strstr(LPCWSTR lpString1, LPCWSTR lpString2) {return (LPWSTR)wcsstr(lpString1, lpString2);}
+__inline LPSTR My_lstrcpy(LPSTR lpString1, LPCSTR lpString2) {return lstrcpyA(lpString1, lpString2);}
+__inline LPWSTR My_lstrcpy(LPWSTR lpString1, LPCWSTR lpString2) {return lstrcpyW(lpString1, lpString2);}
+__inline LPSTR My_strncpy(LPSTR lpString1, LPCSTR lpString2, int Len) {return strncpy(lpString1, lpString2, Len);}
+__inline LPWSTR My_strncpy(LPWSTR lpString1, LPCWSTR lpString2, int Len) {return wcsncpy(lpString1, lpString2, Len);}
+__inline LPSTR My_strlwr(LPSTR lpString) {return _strlwr(lpString);}
+__inline LPWSTR My_strlwr(LPWSTR lpString) {return _wcslwr(lpString);}
+
+template <class T>
+class TString
+{
+public:
+ TString(): pBuf(NULL), nBufSize(0), nAllocSize(0) {}
+ TString(const T *pStr): pBuf(NULL), nBufSize(0), nAllocSize(0) {*this = pStr;}
+ TString(const TString<T> &Str): pBuf(NULL), nBufSize(0), nAllocSize(0) {*this = Str.pBuf;}
+ ~TString() {Free();}
+
+ int GetLen() const {return (nBufSize) ? (nBufSize - 1) : 0;};
+ int IsEmpty() const {return (!GetLen());};
+ T *GetBuffer(int nNewLen = -1);
+ void ReleaseBuffer(int nNewLen = -1);
+ TString<T>& Cat(const T *pStr);
+ TString<T>& Cat(const T c);
+ TString<T>& DiffCat(const T *pStart, const T *pEnd);
+ TString<T>& Replace(const T *szFind, const T *szReplaceBy);
+ TString<T>& Replace(int nIndex, int nCount, const T *szReplaceBy);
+ TString<T> Left(int nCount) const;
+ TString<T> Right(int nCount) const;
+ TString<T> SubStr(int nIndex, int nCount) const;
+ TString<T> ToLower() const;
+ void Empty();
+ void Free();
+ T& operator [] (int nIndex) {_ASSERT(nIndex >= 0 && nIndex <= GetLen()); return pBuf[nIndex];}
+ operator const T*() const {return pBuf;}
+ operator T*() {return pBuf;}
+ TString<T>& operator = (const T *pStr);
+ TString<T>& operator = (const TString<T> &Str) {return *this = Str.pBuf;}
+// TCString& operator + (const char *pStr)
+// {_ASSERT(pBuf && pStr); TCString Result(*this); return Result.Cat(pStr);}
+ friend TString<T> operator + (const TString<T> &Str1, const T *Str2)
+ {_ASSERT(Str1.pBuf && Str2); TString<T> Result(Str1); return Result.Cat(Str2);}
+/* friend TCString operator + (const char *Str1, const TCString &Str2)
+ {_ASSERT(Str1 && Str2.pBuf); TCString Result(Str1); return Result.Cat(Str2);}*/
+ TString<T>& operator += (const T *pStr) {_ASSERT(pBuf && pStr); return this->Cat(pStr);}
+ TString<T>& operator += (const T c) {_ASSERT(pBuf); return this->Cat(c);}
+ int operator == (const T *pStr) const {return (!pBuf || !pStr) ? (pBuf == pStr) : !My_lstrcmp(pBuf, pStr);}
+ int operator != (const T *pStr) const {return (!pBuf || !pStr) ? (pBuf != pStr) : My_lstrcmp(pBuf, pStr);}
+ int operator < (const T *pStr) const {_ASSERT(pBuf && pStr); return My_lstrcmp(pBuf, pStr) > 0;}
+ int operator > (const T *pStr) const {_ASSERT(pBuf && pStr); return My_lstrcmp(pBuf, pStr) < 0;}
+ int operator <= (const T *pStr) const {_ASSERT(pBuf && pStr); return My_lstrcmp(pBuf, pStr) >= 0;}
+ int operator >= (const T *pStr) const {_ASSERT(pBuf && pStr); return My_lstrcmp(pBuf, pStr) <= 0;}
+// TCString& Format(char *pszFormat, ...);
+
+private:
+ void SetBufSize(int nNewBufSize);
+ void SetAllocSize(int nNewAllocSize);
+
+ T *pBuf;
+ int nBufSize; // current string length + 1 (including 0 at the end)
+ int nAllocSize; // allocated memory size
+};
+
+
+typedef TString<TCHAR> TCString;
+typedef TString<char> CString;
+typedef TString<WCHAR> WCString;
+
+
+/*#define TCString TString<TCHAR>
+#define CString TString<char>
+#define WCString TString<WCHAR>*/
+
+
+__inline CString TCHAR2ANSI(TCString Str)
+{
+
+ if (Str == NULL)
+ {
+ return CString();
+ }
+ CString AStr;
+ if (!WideCharToMultiByte(CP_ACP, 0, Str, -1, AStr.GetBuffer(Str.GetLen() + 1), Str.GetLen() + 1, NULL, NULL))
+ {
+ AStr.ReleaseBuffer(0);
+ } else
+ {
+ AStr.ReleaseBuffer(Str.GetLen());
+ }
+ return AStr;
+
+}
+
+
+__inline TCString ANSI2TCHAR(CString Str)
+{
+
+ if (Str == NULL)
+ {
+ return TCString();
+ }
+ TCString TStr;
+ int Len = MultiByteToWideChar(CP_ACP, 0, Str, -1, NULL, 0);
+ if (!MultiByteToWideChar(CP_ACP, 0, Str, -1, TStr.GetBuffer(Len), Len))
+ {
+ TStr.ReleaseBuffer(0);
+ } else
+ {
+ TStr.ReleaseBuffer(Len - 1);
+ }
+ return TStr;
+
+}
+
+
+__inline WCString TCHAR2WCHAR(TCString Str)
+{
+
+ return Str;
+
+}
+
+
+__inline TCString WCHAR2TCHAR(WCString Str)
+{
+
+ return Str;
+
+}
+
+
+
+#define WCHAR2ANSI TCHAR2ANSI
+#define ANSI2WCHAR ANSI2TCHAR
+
+
+
+#ifdef CHARARRAY_CONVERT
+
+__inline CHARARRAY WCHAR2ANSI_ARRAY(CHARARRAY &c)
+{
+ CHARARRAY Result;
+ int Len = WideCharToMultiByte(CP_ACP, 0, (WCHAR*)c.GetData(), c.GetSize() / sizeof(WCHAR), NULL, 0, NULL, NULL);
+ if (Len)
+ {
+ Result.SetAtGrow(Len - 1);
+ if (!WideCharToMultiByte(CP_ACP, 0, (WCHAR*)c.GetData(), c.GetSize() / sizeof(WCHAR), Result.GetData(), Len, NULL, NULL))
+ {
+ Result.RemoveAll();
+ }
+ if (Result.GetSize())
+ {
+ Result.RemoveElem(Result.GetSize() - 1); // remove the null terminator
+ }
+ }
+ return Result;
+}
+
+__inline CHARARRAY ANSI2WCHAR_ARRAY(CHARARRAY &c)
+{
+ CHARARRAY Result;
+ int Len = MultiByteToWideChar(CP_ACP, 0, c.GetData(), c.GetSize(), NULL, 0);
+ if (Len)
+ {
+ Result.SetAtGrow(Len * sizeof(WCHAR) - 1);
+ if (!MultiByteToWideChar(CP_ACP, 0, c.GetData(), c.GetSize(), (WCHAR*)Result.GetData(), Len))
+ {
+ Result.RemoveAll();
+ }
+ if (Result.GetSize())
+ {
+ Result.RemoveElem(Result.GetSize() - 1);
+ Result.RemoveElem(Result.GetSize() - 1); // remove the null terminator
+ }
+ }
+ return Result;
+}
+
+
+__inline CHARARRAY WCHAR2UTF8(WCString Str)
+{
+ CHARARRAY Result;
+ int Len = WideCharToMultiByte(CP_UTF8, 0, Str, -1, NULL, 0, NULL, NULL);
+ if (Len)
+ {
+ Result.SetAtGrow(Len - 1);
+ if (!WideCharToMultiByte(CP_UTF8, 0, Str, -1, Result.GetData(), Len, NULL, NULL))
+ {
+ Result.RemoveAll();
+ }
+ }
+ return Result;
+}
+
+
+#endif // CHARARRAY_CONVERT
+
+
+#undef db_get_s
+CString db_get_s(HANDLE hContact, const char *szModule, const char *szSetting, const char *szDefaultValue);
+TCString db_get_s(HANDLE hContact, const char *szModule, const char *szSetting, const TCHAR *szDefaultValue);
+int db_get_s(HANDLE hContact, const char *szModule, const char *szSetting, DBVARIANT *dbv);
+TCString DBGetContactSettingAsString(HANDLE hContact, const char *szModule, const char *szSetting, const TCHAR *szDefaultValue); // also converts numeric values to a string
+
+// various string helpers. their return values are valid only while the class is visible
+class UTF8Encode
+{
+public:
+ UTF8Encode(const char *str) { p = mir_utf8encode(str); }
+ UTF8Encode(const wchar_t *str) { p = mir_utf8encodeW(str); }
+ ~UTF8Encode() { mir_free(p); }
+ operator char*() { return p; }
+
+private:
+ char *p;
+};
+
+class UTF8DecodeA
+{
+public:
+ UTF8DecodeA(const char *str) { p = mir_strdup(str); mir_utf8decode(p, NULL); }
+ ~UTF8DecodeA() { mir_free(p); }
+ operator char*() { return p; }
+
+private:
+ char *p;
+};
+
+class UTF8DecodeW
+{
+public:
+ UTF8DecodeW(const char *str) { p = mir_utf8decodeW(str); }
+ ~UTF8DecodeW() { mir_free(p); }
+ operator wchar_t*() { return p; }
+
+private:
+ wchar_t *p;
+};
+
+
+#define UTF8Decode UTF8DecodeW
+
+
+/*class mallocStrA
+{
+public:
+ mallocStrA(int n) { p = (char*)malloc((n + 1) * sizeof(char)); }
+ mallocStrA(const char *str) { p = str ? strdup(str) : NULL; }
+ ~mallocStrA() { if (p) free(p); }
+ operator char*() { return p; }
+
+private:
+ char *p;
+};
+
+class mallocStrW
+{
+public:
+ mallocStrW(int n) { p = (wchar_t*)malloc((n + 1) * sizeof(wchar_t)); }
+ mallocStrW(const wchar_t *str) { p = str ? _wcsdup(str) : NULL; }
+ ~mallocStrW() { if (p) free(p); }
+ operator wchar_t*() { return p; }
+
+private:
+ wchar_t *p;
+};
+
+
+#define mallocStr mallocStrW
+
+*/ \ No newline at end of file
diff --git a/plugins/ClientChangeNotify/src/CommonLibs/Options.cpp b/plugins/ClientChangeNotify/src/CommonLibs/Options.cpp
new file mode 100644
index 0000000000..36226b0f11
--- /dev/null
+++ b/plugins/ClientChangeNotify/src/CommonLibs/Options.cpp
@@ -0,0 +1,981 @@
+/*
+ Options.cpp
+ Copyright (c) 2005-2008 Chervov Dmitry
+
+ 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 "Common.h"
+#include "Options.h"
+
+static CString sEmptyString("");
+
+
+COptPage::COptPage(const COptPage &Item)
+{
+ *this = Item;
+}
+
+COptPage::~COptPage()
+{
+ int I;
+ for (I = 0; I < Items.GetSize(); I++)
+ {
+ delete Items[I];
+ }
+ Items.RemoveAll();
+}
+
+void COptPage::MemToPage(int OnlyEnable)
+{
+ int I;
+ _ASSERT(hWnd);
+ for (I = 0; I < Items.GetSize(); I++)
+ {
+ if (OnlyEnable)
+ {
+ Items[I]->COptItem::MemToWnd(hWnd);
+ } else
+ {
+ Items[I]->MemToWnd(hWnd);
+ }
+ }
+}
+
+void COptPage::PageToMem()
+{
+ int I;
+ _ASSERT(hWnd);
+ for (I = 0; I < Items.GetSize(); I++)
+ {
+ Items[I]->WndToMem(hWnd);
+ }
+}
+
+void COptPage::DBToMem()
+{
+ int I;
+ _ASSERT(sModule != "");
+ for (I = 0; I < Items.GetSize(); I++)
+ {
+ Items[I]->DBToMem(sModule, &sDBSettingPrefix);
+ }
+}
+
+void COptPage::MemToDB()
+{
+ int I;
+ _ASSERT(sModule != "");
+ for (I = 0; I < Items.GetSize(); I++)
+ {
+ Items[I]->MemToDB(sModule, &sDBSettingPrefix);
+ }
+}
+
+void COptPage::CleanDBSettings()
+{
+ int I;
+ _ASSERT(sModule != "");
+ for (I = 0; I < Items.GetSize(); I++)
+ {
+ Items[I]->CleanDBSettings(sModule, &sDBSettingPrefix);
+ }
+}
+
+bool COptPage::GetModified()
+{
+ int I;
+ _ASSERT(sModule != "");
+ for (I = 0; I < Items.GetSize(); I++)
+ {
+ if (Items[I]->GetModified())
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+void COptPage::SetModified(bool Modified)
+{
+ int I;
+ _ASSERT(sModule != "");
+ for (I = 0; I < Items.GetSize(); I++)
+ {
+ Items[I]->SetModified(Modified);
+ }
+}
+
+COptItem *COptPage::Find(int DlgItemID)
+{
+ int I;
+ for (I = 0; I < Items.GetSize(); I++)
+ {
+ if (Items[I]->GetID() == DlgItemID)
+ {
+ return Items[I];
+ }
+ }
+ _ASSERT(0);
+ return 0;
+}
+
+COptPage& COptPage::operator = (const COptPage& Page)
+{
+ int I;
+ hWnd = Page.hWnd;
+ sModule = Page.sModule;
+ sDBSettingPrefix = Page.sDBSettingPrefix;
+ Items.RemoveAll();
+ for (I = 0; I < Page.Items.GetSize(); I++)
+ {
+ Items.AddElem(Page.Items[I]->Copy());
+ }
+ return *this;
+}
+
+
+int COptItem::GetIntDBVal(CString &sModule, int bSigned, CString *sDBSettingPrefix)
+{ // default procedure for reading value from DB; used only for integral types
+ if (sDBSetting != NULL)
+ {
+ _ASSERT(nValueSize == DBVT_BYTE || nValueSize == DBVT_WORD || nValueSize == DBVT_DWORD);
+ DBVARIANT dbv;
+ DBCONTACTGETSETTING cgs;
+ cgs.szModule = sModule;
+ //NightFox: WTF is this shit
+ //cgs.szSetting = sDBSettingPrefix ? (*sDBSettingPrefix + sDBSetting) : sDBSetting;
+ cgs.szSetting = sDBSetting;
+ cgs.pValue = &dbv;
+ if (CallService(MS_DB_CONTACT_GETSETTING, NULL, (LPARAM)&cgs))
+ {
+ return GetDefValue();
+ }
+ return (nValueSize == DBVT_BYTE) ? (bSigned ? (signed char)dbv.bVal : (unsigned char)dbv.bVal) : ((nValueSize == DBVT_WORD) ? (bSigned ? (signed short)dbv.wVal : (unsigned short)dbv.wVal) : dbv.dVal);
+ }
+ return GetDefValue();
+}
+
+void COptItem::SetIntDBVal(CString &sModule, int Value, CString *sDBSettingPrefix)
+{ // default procedure for writing value to the DB; used only for integral types
+ if (sDBSetting != NULL && !ReadOnly)
+ {
+ _ASSERT(nValueSize == DBVT_BYTE || nValueSize == DBVT_WORD || nValueSize == DBVT_DWORD);
+ DBCONTACTWRITESETTING cws;
+ cws.szModule = sModule;
+ //NightFox: WTF is this shit
+ //cws.szSetting = sDBSettingPrefix ? (*sDBSettingPrefix + sDBSetting) : sDBSetting;
+ cws.szSetting = sDBSetting;
+
+ cws.value.type = nValueSize;
+ cws.value.dVal = Value;
+
+// db_set_b(NULL, sModule, *sDBSettingPrefix + sDBSetting + TREEITEM_DBSTR_FLAGS + StrID, Value[I].Flags);
+
+ //itoa(Value[I].ID, StrID.GetBuffer(64), 10);
+ //StrID.ReleaseBuffer();
+
+ CallService(MS_DB_CONTACT_WRITESETTING, NULL, (LPARAM)&cws);
+
+ }
+}
+
+TCString COptItem::GetStrDBVal(CString &sModule, CString *sDBSettingPrefix)
+{
+ if (sDBSetting != NULL)
+ {
+ _ASSERT(GetDefValue());
+ return db_get_s(NULL, sModule, sDBSettingPrefix ? (*sDBSettingPrefix + sDBSetting) : sDBSetting, *(TCString*)GetDefValue());
+ }
+ return *(TCString*)GetDefValue();
+}
+
+void COptItem::SetStrDBVal(CString &sModule, TCString &Str, CString *sDBSettingPrefix)
+{
+ if (sDBSetting != NULL && !ReadOnly)
+ {
+ db_set_ts(NULL, sModule, sDBSettingPrefix ? (*sDBSettingPrefix + sDBSetting) : sDBSetting, Str);
+ }
+}
+
+
+
+void COptItem_Checkbox::DBToMem(CString &sModule, CString *sDBSettingPrefix)
+{
+ if (ValueMask)
+ {
+ Value = (GetIntDBVal(sModule, false, sDBSettingPrefix) & ValueMask) ? BST_CHECKED : BST_UNCHECKED;
+ } else
+ {
+ Value = GetIntDBVal(sModule, false, sDBSettingPrefix);
+ }
+ COptItem::DBToMem(sModule, sDBSettingPrefix);
+}
+
+void COptItem_Checkbox::MemToDB(CString &sModule, CString *sDBSettingPrefix)
+{
+ if (ValueMask)
+ {
+ if (Value == BST_CHECKED)
+ {
+ SetIntDBVal(sModule, GetIntDBVal(sModule, false, sDBSettingPrefix) | ValueMask, sDBSettingPrefix);
+ } else
+ {
+ SetIntDBVal(sModule, GetIntDBVal(sModule, false, sDBSettingPrefix) & ~ValueMask, sDBSettingPrefix);
+ }
+ } else
+ {
+ SetIntDBVal(sModule, Value, sDBSettingPrefix);
+ }
+ COptItem::MemToDB(sModule, sDBSettingPrefix);
+}
+
+void COptItem_Checkbox::WndToMem(HWND hWnd)
+{
+ Value = IsDlgButtonChecked(hWnd, DlgItemID);
+// tri-state checkboxes in combination with ValueMask != 0 are not supported ;)
+ _ASSERT(!ValueMask || Value != BST_INDETERMINATE);
+ COptItem::WndToMem(hWnd);
+}
+
+void COptItem_Checkbox::MemToWnd(HWND hWnd)
+{
+ CheckDlgButton(hWnd, DlgItemID, Value);
+ COptItem::MemToWnd(hWnd);
+}
+
+
+
+void COptItem_BitDBSetting::DBToMem(CString &sModule, CString *sDBSettingPrefix)
+{
+ if (ValueMask)
+ {
+ Value = (GetIntDBVal(sModule, false, sDBSettingPrefix) & ValueMask) != 0;
+ } else
+ {
+ Value = GetIntDBVal(sModule, false, sDBSettingPrefix);
+ }
+ COptItem::DBToMem(sModule, sDBSettingPrefix);
+}
+
+void COptItem_BitDBSetting::MemToDB(CString &sModule, CString *sDBSettingPrefix)
+{
+ if (ValueMask)
+ {
+ if (Value)
+ {
+ SetIntDBVal(sModule, GetIntDBVal(sModule, false, sDBSettingPrefix) | ValueMask, sDBSettingPrefix);
+ } else
+ {
+ SetIntDBVal(sModule, GetIntDBVal(sModule, false, sDBSettingPrefix) & ~ValueMask, sDBSettingPrefix);
+ }
+ } else
+ {
+ SetIntDBVal(sModule, Value, sDBSettingPrefix);
+ }
+ COptItem::MemToDB(sModule, sDBSettingPrefix);
+}
+
+
+// ================================================ COptItem_TreeCtrl ================================================
+
+int COptItem_TreeCtrl::IDToOrder(int ID)
+{
+ int I;
+ for (I = 0; I < RootItems.GetSize(); I++)
+ {
+ if (RootItems[I].ID == ID)
+ {
+ return ROOT_INDEX_TO_ORDER(I);
+ }
+ }
+ for (I = 0; I < Value.GetSize(); I++)
+ {
+ if (Value[I].ID == ID)
+ {
+ return I;
+ }
+ }
+ return -1;
+}
+
+int COptItem_TreeCtrl::hItemToOrder(HTREEITEM hItem)
+{
+ int I;
+ for (I = 0; I < RootItems.GetSize(); I++)
+ {
+ if (RootItems[I].hItem == hItem)
+ {
+ return ROOT_INDEX_TO_ORDER(I);
+ }
+ }
+ for (I = 0; I < Value.GetSize(); I++)
+ {
+ if (Value[I].hItem == hItem)
+ {
+ return I;
+ }
+ }
+ return -1;
+}
+
+int COptItem_TreeCtrl::GenerateID()
+{
+ int ID = 0;
+ while (IDToOrder(ID) != -1)
+ {
+ ID++;
+ }
+ return ID;
+}
+
+typedef struct
+{
+ COptItem_TreeCtrl *TreeCtrl;
+ CString *sModule;
+ CString *sDBSettingPrefix;
+} sTreeReadEnumData;
+
+int TreeReadEnum(const char *szSetting, LPARAM lParam)
+{
+ sTreeReadEnumData *TreeReadEnumData = (sTreeReadEnumData*)lParam;
+ int Len = TreeReadEnumData->TreeCtrl->sDBSetting.GetLen() + lengthof(TREEITEM_DBSTR_TITLE) - 1;
+ if (!strncmp(szSetting, TreeReadEnumData->TreeCtrl->sDBSetting + TREEITEM_DBSTR_TITLE, Len) && isdigit(szSetting[Len]))
+ {
+ int ID = atol(szSetting + Len);
+ short ParentID = (TreeReadEnumData->TreeCtrl->TreeFlags & TREECTRL_FLAG_IS_SINGLE_LEVEL) ? 0 : db_get_w(NULL, *TreeReadEnumData->sModule,
+ *TreeReadEnumData->sDBSettingPrefix + TreeReadEnumData->TreeCtrl->sDBSetting + TREEITEM_DBSTR_PARENT + (szSetting + Len), -1);
+ short Order = db_get_w(NULL, *TreeReadEnumData->sModule,
+ *TreeReadEnumData->sDBSettingPrefix + TreeReadEnumData->TreeCtrl->sDBSetting + TREEITEM_DBSTR_ORDER + (szSetting + Len), -1);
+ char Flags = (TreeReadEnumData->TreeCtrl->TreeFlags & TREECTRL_FLAG_IS_SINGLE_LEVEL && !(TreeReadEnumData->TreeCtrl->TreeFlags & TREECTRL_FLAG_HAS_CHECKBOXES)) ? 0 : db_get_b(NULL, *TreeReadEnumData->sModule,
+ *TreeReadEnumData->sDBSettingPrefix + TreeReadEnumData->TreeCtrl->sDBSetting + TREEITEM_DBSTR_FLAGS + (szSetting + Len), 0);
+ if (ParentID >= 0 && Order >= 0)
+ {
+ TreeReadEnumData->TreeCtrl->Value.SetAtGrow(Order).ID = ID;
+ TreeReadEnumData->TreeCtrl->Value.SetAtGrow(Order).ParentID = ParentID;
+ TreeReadEnumData->TreeCtrl->Value.SetAtGrow(Order).Flags = Flags;
+ TreeReadEnumData->TreeCtrl->Value.SetAtGrow(Order).hItem = NULL;
+ TreeReadEnumData->TreeCtrl->Value.SetAtGrow(Order).Title = db_get_s(NULL, *TreeReadEnumData->sModule, *TreeReadEnumData->sDBSettingPrefix + szSetting, _T(""));
+ TreeReadEnumData->TreeCtrl->Value.SetAtGrow(Order).User_Str1 = (TreeReadEnumData->TreeCtrl->User_Str1_DBName == NULL) ? NULL :
+ db_get_s(NULL, *TreeReadEnumData->sModule,
+ *TreeReadEnumData->sDBSettingPrefix + TreeReadEnumData->TreeCtrl->sDBSetting + TreeReadEnumData->TreeCtrl->User_Str1_DBName + (szSetting + Len), (TCHAR*)NULL);
+ }
+ }
+ return 0;
+}
+
+void COptItem_TreeCtrl::DBToMem(CString &sModule, CString *sDBSettingPrefix)
+{
+ if (!sDBSettingPrefix)
+ {
+ sDBSettingPrefix = &sEmptyString;
+ }
+ Value.RemoveAll();
+ sTreeReadEnumData TreeReadEnumData;
+ TreeReadEnumData.TreeCtrl = this;
+ TreeReadEnumData.sModule = &sModule;
+ TreeReadEnumData.sDBSettingPrefix = sDBSettingPrefix;
+ DBCONTACTENUMSETTINGS dbEnum;
+ dbEnum.lParam = (LPARAM)&TreeReadEnumData;
+ dbEnum.ofsSettings = 0;
+ dbEnum.pfnEnumProc = TreeReadEnum;
+ dbEnum.szModule = sModule;
+ CallService(MS_DB_CONTACT_ENUMSETTINGS, NULL, (LPARAM)&dbEnum);
+ if (!Value.GetSize())
+ {
+ Value = DefValue;
+ } else
+ {
+ int I;
+ for (I = 0; I < Value.GetSize(); I++)
+ {
+ if (Value[I].Title == NULL)
+ {
+ Value.RemoveElem(I);
+ I--;
+ }
+ }
+ }
+ COptItem::DBToMem(sModule, sDBSettingPrefix);
+}
+
+void COptItem_TreeCtrl::MemToDB(CString &sModule, CString *sDBSettingPrefix)
+{
+ if (!ReadOnly && Modified)
+ {
+ if (!sDBSettingPrefix)
+ {
+ sDBSettingPrefix = &sEmptyString;
+ }
+ CleanDBSettings(sModule, sDBSettingPrefix);
+ int I;
+ for (I = 0; I < Value.GetSize(); I++)
+ {
+ CString StrID;
+ _itoa(Value[I].ID, StrID.GetBuffer(64), 10);
+ StrID.ReleaseBuffer();
+ db_set_ts(NULL, sModule, *sDBSettingPrefix + sDBSetting + TREEITEM_DBSTR_TITLE + StrID, Value[I].Title);
+ if (!(TreeFlags & TREECTRL_FLAG_IS_SINGLE_LEVEL))
+ db_set_w(NULL, sModule, *sDBSettingPrefix + sDBSetting + TREEITEM_DBSTR_PARENT + StrID, Value[I].ParentID);
+
+ db_set_w(NULL, sModule, *sDBSettingPrefix + sDBSetting + TREEITEM_DBSTR_ORDER + StrID, I);
+ if (!(TreeFlags & TREECTRL_FLAG_IS_SINGLE_LEVEL) || TreeFlags & TREECTRL_FLAG_HAS_CHECKBOXES)
+ db_set_b(NULL, sModule, *sDBSettingPrefix + sDBSetting + TREEITEM_DBSTR_FLAGS + StrID, Value[I].Flags);
+
+ if (User_Str1_DBName != NULL && Value[I].User_Str1 != NULL)
+ db_set_ts(NULL, sModule, *sDBSettingPrefix + sDBSetting + User_Str1_DBName + StrID, Value[I].User_Str1);
+ }
+ COptItem::MemToDB(sModule, sDBSettingPrefix);
+ }
+}
+
+void COptItem_TreeCtrl::WndToMem(HWND hWnd)
+{ // only need to gather info of items state (expanded/collapsed, checked/unchecked)
+ HWND hTreeView = GetDlgItem(hWnd, DlgItemID);
+ int I;
+ for (I = 0; I < Value.GetSize(); I++)
+ {
+ DWORD State = TreeView_GetItemState(hTreeView, Value[I].hItem, TVIS_EXPANDED | TVIS_STATEIMAGEMASK);
+ int OldFlags = Value[I].Flags;
+ if (State & TVIS_EXPANDED)
+ {
+ Value[I].Flags |= TIF_EXPANDED;
+ } else
+ {
+ Value[I].Flags &= ~TIF_EXPANDED;
+ }
+ if (TreeFlags & TREECTRL_FLAG_HAS_CHECKBOXES && (State >> 12) - 1)
+ {
+ Value[I].Flags |= TIF_ENABLED;
+ } else
+ {
+ Value[I].Flags &= ~TIF_ENABLED;
+ }
+ if (Value[I].Flags != OldFlags)
+ {
+ Modified = true;
+ }
+ }
+ COptItem::WndToMem(hWnd);
+}
+
+void COptItem_TreeCtrl::MemToWnd(HWND hWnd)
+{
+ HWND hTreeView = GetDlgItem(hWnd, DlgItemID);
+ if (TreeFlags & TREECTRL_FLAG_HAS_CHECKBOXES)
+ { // have to set this in run-time as it's specified in MSDN
+ LONG Style = GetWindowLongPtr(hTreeView, GWL_STYLE);
+ SetWindowLongPtr(hTreeView, GWL_STYLE, Style & ~TVS_CHECKBOXES);
+ SetWindowLongPtr(hTreeView, GWL_STYLE, Style | TVS_CHECKBOXES);
+ }
+ TVINSERTSTRUCT tvIn = {0};
+ int ScrollPos = GetScrollPos(hTreeView, SB_VERT);
+ int SelectOrder = IDToOrder(GetSelectedItemID(hWnd));
+ SendMessage(hTreeView, WM_SETREDRAW, false, 0);
+ TreeView_DeleteAllItems(hTreeView);
+ _ASSERT(RootItems.GetSize());
+ int I;
+ if (!(TreeFlags & TREECTRL_FLAG_IS_SINGLE_LEVEL))
+ {
+ for (I = 0; I < RootItems.GetSize(); I++)
+ {
+ tvIn.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_PARAM;
+ RootItems[I].Flags |= TIF_GROUP;
+ tvIn.item.state = tvIn.item.stateMask = TVIS_BOLD | ((RootItems[I].Flags & TIF_EXPANDED) ? TVIS_EXPANDED : 0);
+ tvIn.item.pszText = RootItems[I].Title;
+ tvIn.hParent = TVI_ROOT;
+ tvIn.hInsertAfter = TVI_LAST;
+ tvIn.item.lParam = RootItems[I].ID;
+ RootItems[I].hItem = TreeView_InsertItem(hTreeView, &tvIn);
+ }
+ }
+ for (I = 0; I < Value.GetSize(); I++)
+ {
+ Value[I].hItem = RootItems[0].hItem; // put an item to first group in case of some strange error
+ }
+ for (I = 0; I < Value.GetSize(); I++)
+ {
+ tvIn.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_PARAM;
+ tvIn.item.state = tvIn.item.stateMask = (Value[I].Flags & TIF_GROUP) ? (TVIS_BOLD | ((Value[I].Flags & TIF_EXPANDED) ? TVIS_EXPANDED : 0)) : 0;
+ if (TreeFlags & TREECTRL_FLAG_HAS_CHECKBOXES)
+ {
+ tvIn.item.stateMask |= TVIS_STATEIMAGEMASK;
+ tvIn.item.state |= INDEXTOSTATEIMAGEMASK((Value[I].Flags & TIF_ENABLED) ? 2 : 1);
+ }
+ tvIn.item.pszText = Value[I].Title;
+ int Order = IDToOrder(Value[I].ParentID);
+ if (Order != -1)
+ {
+ tvIn.hParent = (Order <= TREECTRL_ROOTORDEROFFS) ? RootItems[ROOT_ORDER_TO_INDEX(Order)].hItem : Value[Order].hItem;
+ tvIn.hInsertAfter = TVI_LAST;
+ tvIn.item.lParam = Value[I].ID;
+ Value[I].hItem = TreeView_InsertItem(hTreeView, &tvIn);
+ } else
+ { // found an orphan item; probably it's better just to delete it
+ Value.RemoveElem(I);
+ I--;
+ }
+ }
+ TreeView_SelectItem(hTreeView, (SelectOrder >= 0) ? Value[SelectOrder].hItem : ((SelectOrder <= TREECTRL_ROOTORDEROFFS) ? RootItems[ROOT_ORDER_TO_INDEX(SelectOrder)].hItem : NULL));
+ SendMessage(hTreeView, WM_SETREDRAW, true, 0);
+ SCROLLBARINFO sbi;
+ sbi.cbSize = sizeof(sbi);
+ GetScrollBarInfo(hTreeView, OBJID_VSCROLL, &sbi);
+ if (!(sbi.rgstate[0] & STATE_SYSTEM_INVISIBLE))
+ {
+ int MinPos, MaxPos;
+ GetScrollRange(hTreeView, SB_VERT, &MinPos, &MaxPos);
+ if (ScrollPos < MinPos)
+ {
+ ScrollPos = MinPos;
+ } else if (ScrollPos > MaxPos)
+ {
+ ScrollPos = MaxPos;
+ }
+ SetScrollPos(hTreeView, SB_VERT, ScrollPos, true);
+ }
+ COptItem::MemToWnd(hWnd);
+}
+
+
+typedef struct
+{
+ TMyArray<CString> TreeSettings;
+ COptItem_TreeCtrl *TreeCtrl;
+ CString *sDBSettingPrefix;
+} sTreeDeleteEnumData;
+
+int TreeDeleteEnum(const char *szSetting, LPARAM lParam)
+{
+ sTreeDeleteEnumData *TreeDeleteEnumData = (sTreeDeleteEnumData*)lParam;
+ CString CurSetting;
+ CurSetting = *TreeDeleteEnumData->sDBSettingPrefix + TreeDeleteEnumData->TreeCtrl->sDBSetting + TREEITEM_DBSTR_TITLE;
+ if (!strncmp(szSetting, CurSetting, CurSetting.GetLen()))
+ {
+ TreeDeleteEnumData->TreeSettings.AddElem(szSetting);
+ }
+ CurSetting = *TreeDeleteEnumData->sDBSettingPrefix + TreeDeleteEnumData->TreeCtrl->sDBSetting + TREEITEM_DBSTR_PARENT;
+ if (!strncmp(szSetting, CurSetting, CurSetting.GetLen()))
+ {
+ TreeDeleteEnumData->TreeSettings.AddElem(szSetting);
+ }
+ CurSetting = *TreeDeleteEnumData->sDBSettingPrefix + TreeDeleteEnumData->TreeCtrl->sDBSetting + TREEITEM_DBSTR_ORDER;
+ if (!strncmp(szSetting, CurSetting, CurSetting.GetLen()))
+ {
+ TreeDeleteEnumData->TreeSettings.AddElem(szSetting);
+ }
+ CurSetting = *TreeDeleteEnumData->sDBSettingPrefix + TreeDeleteEnumData->TreeCtrl->sDBSetting + TREEITEM_DBSTR_FLAGS;
+ if (!strncmp(szSetting, CurSetting, CurSetting.GetLen()))
+ {
+ TreeDeleteEnumData->TreeSettings.AddElem(szSetting);
+ }
+ if (TreeDeleteEnumData->TreeCtrl->User_Str1_DBName != NULL)
+ {
+ CurSetting = *TreeDeleteEnumData->sDBSettingPrefix + TreeDeleteEnumData->TreeCtrl->sDBSetting + TreeDeleteEnumData->TreeCtrl->User_Str1_DBName;
+ if (!strncmp(szSetting, CurSetting, CurSetting.GetLen()))
+ {
+ TreeDeleteEnumData->TreeSettings.AddElem(szSetting);
+ }
+ }
+ return 0;
+}
+
+void COptItem_TreeCtrl::CleanDBSettings(CString &sModule, CString *sDBSettingPrefix)
+{
+ if (!sDBSettingPrefix)
+ {
+ sDBSettingPrefix = &sEmptyString;
+ }
+ sTreeDeleteEnumData TreeDeleteEnumData;
+ TreeDeleteEnumData.TreeCtrl = this;
+ TreeDeleteEnumData.sDBSettingPrefix = sDBSettingPrefix;
+ DBCONTACTENUMSETTINGS dbEnum;
+ dbEnum.lParam = (LPARAM)&TreeDeleteEnumData;
+ dbEnum.ofsSettings = 0;
+ dbEnum.pfnEnumProc = TreeDeleteEnum;
+ dbEnum.szModule = sModule;
+ CallService(MS_DB_CONTACT_ENUMSETTINGS, NULL, (LPARAM)&dbEnum);
+ int I;
+ for (I = 0; I < TreeDeleteEnumData.TreeSettings.GetSize(); I++)
+ {
+ db_unset(NULL, sModule, TreeDeleteEnumData.TreeSettings[I]);
+ }
+}
+
+
+int COptItem_TreeCtrl::GetSelectedItemID(HWND hWnd)
+{
+ HWND hTreeView = GetDlgItem(hWnd, DlgItemID);
+ TVITEM tvi = {0};
+ tvi.hItem = TreeView_GetSelection(hTreeView);
+ if (!tvi.hItem)
+ {
+ return -1;
+ }
+ tvi.mask = TVIF_HANDLE | TVIF_PARAM;
+ TreeView_GetItem(hTreeView, &tvi);
+ return tvi.lParam;
+}
+
+void COptItem_TreeCtrl::Delete(HWND hWnd, int ID)
+{
+ int SelectedOrder = IDToOrder(ID);
+ _ASSERT(SelectedOrder >= 0);
+ RecursiveDelete(hWnd, SelectedOrder);
+ Modified = true;
+}
+
+void COptItem_TreeCtrl::RecursiveDelete(HWND hWnd, int I)
+{
+ if (Value[I].Flags & TIF_GROUP)
+ {
+ int J;
+ for (J = I + 1; J < Value.GetSize(); J++)
+ {
+ if (Value[J].ParentID == Value[I].ID)
+ {
+ RecursiveDelete(hWnd, J--);
+ }
+ }
+ }
+ HWND hTreeView = GetDlgItem(hWnd, DlgItemID);
+ TreeView_DeleteItem(hTreeView, Value[I].hItem);
+ Value.RemoveElem(I);
+}
+
+CTreeItem* COptItem_TreeCtrl::InsertItem(HWND hWnd, CTreeItem &Item)
+// Item's ID and ParentID are not used (the new item position is determined by current selection in the tree)
+// returns a pointer to the newly inserted item info
+{
+ _ASSERT(!(TreeFlags & TREECTRL_FLAG_IS_SINGLE_LEVEL) || !(Item.Flags & TIF_GROUP));
+ HWND hTreeView = GetDlgItem(hWnd, DlgItemID);
+ TVITEM tvi;
+ int SelOrder = -1;
+ Item.ParentID = RootItems[0].ID;
+ TVINSERTSTRUCT tvIn = {0};
+ tvIn.hParent = RootItems[0].hItem;
+ tvIn.hInsertAfter = TVI_FIRST;
+ if (tvi.hItem = TreeView_GetSelection(hTreeView))
+ {
+ tvi.mask = TVIF_HANDLE | TVIF_PARAM;
+ TreeView_GetItem(hTreeView, &tvi);
+ SelOrder = IDToOrder(tvi.lParam);
+ if (SelOrder <= TREECTRL_ROOTORDEROFFS)
+ {
+ Item.ParentID = RootItems[ROOT_ORDER_TO_INDEX(SelOrder)].ID;
+ tvIn.hParent = RootItems[ROOT_ORDER_TO_INDEX(SelOrder)].hItem;
+ SelOrder = -1;
+ } else
+ {
+ if (Value[SelOrder].Flags & TIF_GROUP)
+ {
+ Item.ParentID = Value[SelOrder].ID;
+ tvIn.hParent = Value[SelOrder].hItem;
+ } else
+ {
+ Item.ParentID = Value[SelOrder].ParentID;
+ int Order = IDToOrder(Value[SelOrder].ParentID);
+ tvIn.hParent = (Order <= TREECTRL_ROOTORDEROFFS) ? RootItems[ROOT_ORDER_TO_INDEX(Order)].hItem : Value[Order].hItem;
+ tvIn.hInsertAfter = Value[SelOrder].hItem;
+ }
+ }
+ }
+ tvIn.item.mask = TVIF_TEXT | TVIF_STATE | TVIF_PARAM;
+ tvIn.item.state = tvIn.item.stateMask = (Item.Flags & TIF_GROUP) ? (TVIS_BOLD |
+ ((Item.Flags & TIF_EXPANDED) ? TVIS_EXPANDED : 0)) : 0;
+ if (TreeFlags & TREECTRL_FLAG_HAS_CHECKBOXES)
+ {
+ tvIn.item.stateMask |= TVIS_STATEIMAGEMASK;
+ tvIn.item.state |= INDEXTOSTATEIMAGEMASK((Item.Flags & TIF_ENABLED) ? 2 : 1);
+ }
+ tvIn.item.pszText = Item.Title;
+ tvIn.item.lParam = Item.ID = GenerateID();
+ Value.InsertElem(Item, SelOrder + 1);
+ Value[SelOrder + 1].hItem = TreeView_InsertItem(hTreeView, &tvIn);
+ TreeView_SelectItem(hTreeView, Value[SelOrder + 1].hItem);
+ Modified = true;
+ return &Value[SelOrder + 1];
+}
+
+int COptItem_TreeCtrl::RecursiveMove(int ItemOrder, int ParentID, int InsertAtOrder)
+// ItemOrder must be a movable item (i.e. ItemOrder >= 0)
+// InsertAtOrder must be >= 0 too.
+{
+ int ItemsMoved = 1;
+ Value.MoveElem(ItemOrder, InsertAtOrder);
+ Value[InsertAtOrder].ParentID = ParentID;
+ if (Value[InsertAtOrder].Flags & TIF_GROUP) // need to ensure that no items were left before their group by an order.
+ {
+ int GroupID = Value[InsertAtOrder].ID;
+ int I;
+ for (I = ItemOrder; I < InsertAtOrder; I++) // if ItemOrder > InsertAtOrder then there is simply nothing to do
+ {
+ if (Value[I].ParentID == GroupID)
+ {
+ int CurrentItemsMoved = RecursiveMove(I, GroupID, InsertAtOrder);
+ ItemsMoved += CurrentItemsMoved;
+ InsertAtOrder -= CurrentItemsMoved;
+ I--;
+ }
+ }
+ }
+ return ItemsMoved;
+}
+
+void COptItem_TreeCtrl::MoveItem(HWND hWnd, HTREEITEM hItem, HTREEITEM hMoveTo)
+{ // hMoveTo can be NULL and it means that we must move hItem to the beginning of the list
+ _ASSERT(hItem && (hMoveTo || TreeFlags & TREECTRL_FLAG_IS_SINGLE_LEVEL));
+ if (hItem == hMoveTo)
+ {
+ return;
+ }
+ HWND hTreeView = GetDlgItem(hWnd, DlgItemID);
+ TVITEM tvi;
+ tvi.mask = TVIF_HANDLE | TVIF_PARAM;
+ tvi.hItem = hItem;
+ TreeView_GetItem(hTreeView, &tvi);
+ int ItemOrder = IDToOrder(tvi.lParam);
+ _ASSERT(ItemOrder != -1);
+ int MoveToOrder;
+ if (hMoveTo)
+ {
+ tvi.hItem = hMoveTo;
+ TreeView_GetItem(hTreeView, &tvi);
+ MoveToOrder = IDToOrder(tvi.lParam);
+ _ASSERT(MoveToOrder != -1);
+ } else
+ {
+ MoveToOrder = -1;
+ }
+ if (ItemOrder <= TREECTRL_ROOTORDEROFFS)
+ {
+ return; // can't move root items
+ }
+ if (Value[ItemOrder].Flags & TIF_GROUP)
+ { // need to check for a case when trying to move a group to its own subgroup.
+ int Order = MoveToOrder;
+ while (Order >= 0)
+ {
+ Order = IDToOrder(Value[Order].ParentID);
+ if (Order == ItemOrder)
+ {
+ return;
+ }
+ }
+ }
+// well, everything is ok, we really can move that item.
+ WndToMem(hWnd); // save groups state (expanded/collapsed)
+ if (MoveToOrder != -1 && ((MoveToOrder <= TREECTRL_ROOTORDEROFFS) ? RootItems[ROOT_ORDER_TO_INDEX(MoveToOrder)].Flags : Value[MoveToOrder].Flags) & TIF_GROUP)
+ { // if the destination is a group, then move the item to that group
+ RecursiveMove(ItemOrder, (MoveToOrder <= TREECTRL_ROOTORDEROFFS) ? RootItems[ROOT_ORDER_TO_INDEX(MoveToOrder)].ID : Value[MoveToOrder].ID, (MoveToOrder >= 0) ? ((ItemOrder < MoveToOrder) ? MoveToOrder : (MoveToOrder + 1)) : 0);
+ } else
+ { // else place the item after the destination item
+ RecursiveMove(ItemOrder, (MoveToOrder == -1) ? 0 : Value[MoveToOrder].ParentID, (ItemOrder < MoveToOrder) ? MoveToOrder : (MoveToOrder + 1)); // when TREECTRL_FLAG_IS_SINGLE_LEVEL, we always have a root item with ID = 0.
+ }
+ MemToWnd(hWnd); // update the tree
+ Modified = true;
+}
+
+
+// ================================================ COptItem_ListCtrl ================================================
+
+typedef struct
+{
+ COptItem_ListCtrl *ListCtrl;
+ CString *sModule;
+ CString *sDBSettingPrefix;
+} sListReadEnumData;
+
+int ListReadEnum(const char *szSetting, LPARAM lParam)
+{
+ sListReadEnumData *ListReadEnumData = (sListReadEnumData*)lParam;
+ int Len = ListReadEnumData->sDBSettingPrefix->GetLen() + ListReadEnumData->ListCtrl->sDBSetting.GetLen() + lengthof(LISTITEM_DBSTR_TEXT) - 1;
+ if (!strncmp(szSetting, *ListReadEnumData->sDBSettingPrefix + ListReadEnumData->ListCtrl->sDBSetting + LISTITEM_DBSTR_TEXT, Len) && isdigit(szSetting[Len]))
+ {
+ int ID = atol(szSetting + Len);
+ ListReadEnumData->ListCtrl->Value.SetAtGrow(ID).Text = db_get_s(NULL, *ListReadEnumData->sModule, *ListReadEnumData->sDBSettingPrefix + szSetting, _T(""));
+ }
+ return 0;
+}
+
+void COptItem_ListCtrl::DBToMem(CString &sModule, CString *sDBSettingPrefix)
+{
+ if (!sDBSettingPrefix)
+ {
+ sDBSettingPrefix = &sEmptyString;
+ }
+ Value.RemoveAll();
+ sListReadEnumData ListReadEnumData;
+ ListReadEnumData.ListCtrl = this;
+ ListReadEnumData.sModule = &sModule;
+ ListReadEnumData.sDBSettingPrefix = sDBSettingPrefix;
+ DBCONTACTENUMSETTINGS dbEnum;
+ dbEnum.lParam = (LPARAM)&ListReadEnumData;
+ dbEnum.ofsSettings = 0;
+ dbEnum.pfnEnumProc = ListReadEnum;
+ dbEnum.szModule = sModule;
+ CallService(MS_DB_CONTACT_ENUMSETTINGS, NULL, (LPARAM)&dbEnum);
+ if (!Value.GetSize())
+ {
+ Value = DefValue;
+ } else
+ {
+ int I;
+ for (I = 0; I < Value.GetSize(); I++)
+ {
+ if (Value[I].Text == NULL) // NULL is not ""!
+ {
+ Value.RemoveElem(I);
+ I--;
+ }
+ }
+ }
+ COptItem::DBToMem(sModule, sDBSettingPrefix);
+}
+
+void COptItem_ListCtrl::MemToDB(CString &sModule, CString *sDBSettingPrefix)
+{
+ if (!ReadOnly && Modified)
+ {
+ if (!sDBSettingPrefix)
+ {
+ sDBSettingPrefix = &sEmptyString;
+ }
+ CleanDBSettings(sModule, sDBSettingPrefix);
+ int I;
+ for (I = 0; I < Value.GetSize(); I++)
+ {
+ CString StrID;
+ _itoa(I, StrID.GetBuffer(64), 10);
+ StrID.ReleaseBuffer();
+ db_set_ts(NULL, sModule, *sDBSettingPrefix + sDBSetting + LISTITEM_DBSTR_TEXT + StrID, Value[I].Text);
+ }
+ COptItem::MemToDB(sModule, sDBSettingPrefix);
+ }
+}
+
+void COptItem_ListCtrl::WndToMem(HWND hWnd)
+{
+// nothing to do
+ COptItem::WndToMem(hWnd);
+}
+
+void COptItem_ListCtrl::MemToWnd(HWND hWnd)
+{
+ HWND hListView = GetDlgItem(hWnd, DlgItemID);
+ SendMessage(hListView, WM_SETREDRAW, false, 0);
+ SendMessage(hListView, LB_RESETCONTENT, 0, 0);
+ int I;
+ for (I = 0; I < Value.GetSize(); I++)
+ {
+ SendMessage(hListView, LB_INSERTSTRING, -1, (LPARAM)(TCHAR*)Value[I].Text);
+ }
+ SendMessage(hListView, WM_SETREDRAW, true, 0);
+ COptItem::MemToWnd(hWnd);
+}
+
+
+typedef struct
+{
+ TMyArray<CString> ListSettings;
+ COptItem_ListCtrl *ListCtrl;
+ CString *sDBSettingPrefix;
+} sListDeleteEnumData;
+
+int ListDeleteEnum(const char *szSetting, LPARAM lParam)
+{
+ sListDeleteEnumData *ListDeleteEnumData = (sListDeleteEnumData*)lParam;
+ CString CurSetting = *ListDeleteEnumData->sDBSettingPrefix + ListDeleteEnumData->ListCtrl->sDBSetting + LISTITEM_DBSTR_TEXT;
+ if (!strncmp(szSetting, CurSetting, CurSetting.GetLen()))
+ {
+ ListDeleteEnumData->ListSettings.AddElem(szSetting);
+ }
+ return 0;
+}
+
+void COptItem_ListCtrl::CleanDBSettings(CString &sModule, CString *sDBSettingPrefix)
+{
+ if (!sDBSettingPrefix)
+ {
+ sDBSettingPrefix = &sEmptyString;
+ }
+ sListDeleteEnumData ListDeleteEnumData;
+ ListDeleteEnumData.ListCtrl = this;
+ ListDeleteEnumData.sDBSettingPrefix = sDBSettingPrefix;
+ DBCONTACTENUMSETTINGS dbEnum;
+ dbEnum.lParam = (LPARAM)&ListDeleteEnumData;
+ dbEnum.ofsSettings = 0;
+ dbEnum.pfnEnumProc = ListDeleteEnum;
+ dbEnum.szModule = sModule;
+ CallService(MS_DB_CONTACT_ENUMSETTINGS, NULL, (LPARAM)&dbEnum);
+ int I;
+ for (I = 0; I < ListDeleteEnumData.ListSettings.GetSize(); I++)
+ {
+ db_unset(NULL, sModule, ListDeleteEnumData.ListSettings[I]);
+ }
+}
+
+
+int COptItem_ListCtrl::GetSelectedItemID(HWND hWnd)
+{
+ int Res = SendDlgItemMessage(hWnd, DlgItemID, LB_GETCURSEL, 0, 0);
+ return (Res == LB_ERR) ? -1 : Res; // I know that LB_ERR = -1 ;)
+}
+
+int COptItem_ListCtrl::SetSelectedItemID(HWND hWnd, int ID)
+{
+ int Res = SendDlgItemMessage(hWnd, DlgItemID, LB_SETCURSEL, ID, 0);
+ return (Res == LB_ERR) ? -1 : Res;
+}
+
+void COptItem_ListCtrl::Delete(HWND hWnd, int ID)
+{
+ _ASSERT(ID >= 0);
+ HWND hListView = GetDlgItem(hWnd, DlgItemID);
+ int Res = SendMessage(hListView, LB_DELETESTRING, ID, 0);
+ _ASSERT(Res != LB_ERR);
+ Value.RemoveElem(ID);
+ Modified = true;
+}
+
+void COptItem_ListCtrl::ModifyItem(HWND hWnd, int ID, CListItem &Item)
+{ // changes the text of item with the specified ID
+ _ASSERT(ID >= 0);
+ HWND hListView = GetDlgItem(hWnd, DlgItemID);
+ SendMessage(hListView, WM_SETREDRAW, false, 0);
+ int CurSel = SendMessage(hListView, LB_GETCURSEL, 0, 0);
+ int TopIndex = SendMessage(hListView, LB_GETTOPINDEX, 0, 0);
+ int Res = SendMessage(hListView, LB_DELETESTRING, ID, 0);
+ _ASSERT(Res != LB_ERR);
+ Res = SendMessage(hListView, LB_INSERTSTRING, ID, (LPARAM)(TCHAR*)(Item.Text));
+ _ASSERT(Res != LB_ERR && Res != LB_ERRSPACE);
+ SendMessage(hListView, LB_SETCURSEL, CurSel, 0);
+ SendMessage(hListView, LB_SETTOPINDEX, TopIndex, 0);
+ SendMessage(hListView, WM_SETREDRAW, true, 0);
+ Value[ID].Text = Item.Text;
+ Modified = true;
+}
+
+CListItem* COptItem_ListCtrl::InsertItem(HWND hWnd, int ID, CListItem &Item)
+// returns a pointer to the newly inserted item info
+// ID is position at which to insert the item; -1 = add to the end of the list
+{
+ HWND hListView = GetDlgItem(hWnd, DlgItemID);
+ int Res = SendMessage(hListView, LB_INSERTSTRING, ID, (LPARAM)(TCHAR*)(Item.Text)); // LB_INSERTSTRING doesn't sort the lists even with LBS_SORT style
+ _ASSERT(Res != LB_ERR && Res != LB_ERRSPACE);
+ int I = Value.AddElem(Item);
+ Modified = true;
+ return &Value[I];
+}
diff --git a/plugins/ClientChangeNotify/src/CommonLibs/Options.h b/plugins/ClientChangeNotify/src/CommonLibs/Options.h
new file mode 100644
index 0000000000..666162c50a
--- /dev/null
+++ b/plugins/ClientChangeNotify/src/CommonLibs/Options.h
@@ -0,0 +1,483 @@
+/*
+ Options.h
+ Copyright (c) 2005-2008 Chervov Dmitry
+
+ 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
+*/
+
+#pragma once
+
+#include "CString.h"
+#include "TMyArray.h"
+
+#ifndef lengthof
+#define lengthof(s) (sizeof(s) / sizeof(*s))
+#endif
+
+
+class COptItem
+{
+public:
+ COptItem() {}
+ COptItem(int DlgItemID, char *szDBSetting, int nValueSize, int lParam = 0, bool ReadOnly = false):
+ DlgItemID(DlgItemID), nValueSize(nValueSize), sDBSetting(szDBSetting), lParam(lParam), Enabled(true), ReadOnly(ReadOnly), Modified(false) {}
+/* COptItem(const COptItem &Item): DlgItemID(Item.DlgItemID), nValueSize(Item.nValueSize),
+ sDBSetting(Item.szDBSetting), lParam(Item.lParam), Enabled(Item.Enabled) {};*/
+ virtual ~COptItem() {}
+
+ virtual void DBToMem(CString &sModule, CString *sDBSettingPrefix = NULL) {Modified = false;}
+ virtual void MemToDB(CString &sModule, CString *sDBSettingPrefix = NULL) {Modified = false;}
+ virtual void WndToMem(HWND hWnd) {}
+ virtual void MemToWnd(HWND hWnd) {EnableWindow(GetDlgItem(hWnd, DlgItemID), Enabled);}
+ void DBToMemToWnd(CString &sModule, HWND hWnd, CString *sDBSettingPrefix = NULL) {DBToMem(sModule, sDBSettingPrefix); MemToWnd(hWnd);}
+ void WndToMemToDB(HWND hWnd, CString &sModule, CString *sDBSettingPrefix = NULL) {WndToMem(hWnd); MemToDB(sModule, sDBSettingPrefix);}
+ virtual void CleanDBSettings(CString &sModule, CString *sDBSettingPrefix = NULL) {db_unset(NULL, sModule, sDBSettingPrefix ? (*sDBSettingPrefix + sDBSetting) : sDBSetting);}; // TODO: also set Value to DefValue?
+
+ virtual void SetValue(int Value) {Modified = true;}
+ virtual void SetDefValue(int DefValue) {}
+ virtual int GetValue() {return 0;}
+ virtual int GetDefValue() {return 0;}
+ int GetDBValue(CString &sModule, CString *sDBSettingPrefix = NULL) {DBToMem(sModule, sDBSettingPrefix); return GetValue();}
+ void SetDBValue(CString &sModule, int Value, CString *sDBSettingPrefix = NULL) {SetValue(Value); MemToDB(sModule, sDBSettingPrefix);}
+ int GetDBValueCopy(CString &sModule, CString *sDBSettingPrefix = NULL) {COptItem* Item = Copy(); Item->DBToMem(sModule, sDBSettingPrefix); int Value = Item->GetValue(); delete Item; return Value;} // retrieves DB value, but doesn't affect current page/item state; beware! it doesn't work with string values / other dynamic pointers
+ void SetDBValueCopy(CString &sModule, int Value, CString *sDBSettingPrefix = NULL) {COptItem* Item = Copy(); Item->SetValue(Value); Item->MemToDB(sModule, sDBSettingPrefix); delete Item;}
+ int GetWndValue(HWND hWnd) {WndToMem(hWnd); return GetValue();}
+ void SetWndValue(HWND hWnd, int Value) {SetValue(Value); MemToWnd(hWnd);}
+ void SetDlgItemID(int DlgItemID) {this->DlgItemID = DlgItemID;}
+ bool GetModified() {return Modified;}
+ void SetModified(bool Modified) {this->Modified = Modified;}
+
+ void Enable(int Enabled) {this->Enabled = Enabled;}
+ int GetParam() {return lParam;}
+ int GetID() {return DlgItemID;}
+
+// virtual COptItem& operator = (const COptItem& Item) {return *this;};
+ virtual COptItem* Copy() {_ASSERT(0); return NULL;} // Attention! Free Copy() result when it's not needed anymore!
+
+ CString sDBSetting;
+
+protected:
+ int GetIntDBVal(CString &sModule, int bSigned = false, CString *sDBSettingPrefix = NULL);
+ void SetIntDBVal(CString &sModule, int Value, CString *sDBSettingPrefix = NULL);
+ TCString GetStrDBVal(CString &sModule, CString *sDBSettingPrefix = NULL);
+ void SetStrDBVal(CString &sModule, TCString &Str, CString *sDBSettingPrefix = NULL);
+
+ int DlgItemID;
+ int Enabled;
+ bool ReadOnly;
+ bool Modified;
+ int nValueSize; // maximum pValue size in bytes
+ int lParam;
+};
+
+
+class COptItem_Generic : public COptItem
+{
+public:
+ COptItem_Generic() {}
+ COptItem_Generic(int DlgItemID, int lParam = 0): COptItem(DlgItemID, NULL, 0, lParam) {}
+ virtual COptItem* Copy() {return new COptItem_Generic(*this);}
+};
+
+
+class COptItem_Edit : public COptItem
+{
+public:
+ COptItem_Edit() {}
+ COptItem_Edit(int DlgItemID, char *szDBSetting, int nMaxLen, TCHAR *szDefValue, int lParam = 0, bool ReadOnly = false): COptItem(DlgItemID, szDBSetting, nMaxLen, lParam, ReadOnly), sDefValue(szDefValue) {}
+// COptItem_Edit(const COptItem_Edit &Item): sDefValue(Item.sDefValue), sValue(Item.sValue) {}
+ void DBToMem(CString &sModule, CString *sDBSettingPrefix = NULL) {sValue = GetStrDBVal(sModule, sDBSettingPrefix); COptItem::DBToMem(sModule, sDBSettingPrefix);}
+ void MemToDB(CString &sModule, CString *sDBSettingPrefix = NULL) {SetStrDBVal(sModule, sValue, sDBSettingPrefix); COptItem::MemToDB(sModule, sDBSettingPrefix);}
+ void WndToMem(HWND hWnd) {GetDlgItemText(hWnd, DlgItemID, sValue.GetBuffer(nValueSize), nValueSize); sValue.ReleaseBuffer(); COptItem::MemToWnd(hWnd);}
+ void MemToWnd(HWND hWnd) {SetDlgItemText(hWnd, DlgItemID, sValue); COptItem::MemToWnd(hWnd);}
+ void SetValue(int Value) {sValue = *(TCString*)Value; COptItem::SetValue(Value);}
+ void SetDefValue(int DefValue) {sDefValue = *(TCString*)DefValue; COptItem::SetDefValue(DefValue);}
+ int GetValue() {return (int)&sValue;}
+ int GetDefValue() {return (int)&sDefValue;}
+
+// COptItem_Edit& operator = (const COptItem_Edit& Item) {return *this;};
+ virtual COptItem* Copy() {return new COptItem_Edit(*this);}
+
+ TCString sDefValue;
+ TCString sValue;
+};
+
+
+class COptItem_IntEdit : public COptItem
+{
+public:
+ COptItem_IntEdit() {}
+ COptItem_IntEdit(int DlgItemID, char *szDBSetting, int nValueSize = DBVT_BYTE, int bSigned = true, int DefValue = 0, int lParam = 0, bool ReadOnly = false): COptItem(DlgItemID, szDBSetting, nValueSize, lParam, ReadOnly), DefValue(DefValue), Value(0), bSigned(bSigned) {}
+ void DBToMem(CString &sModule, CString *sDBSettingPrefix = NULL) {Value = GetIntDBVal(sModule, bSigned, sDBSettingPrefix); COptItem::DBToMem(sModule, sDBSettingPrefix);}
+ void MemToDB(CString &sModule, CString *sDBSettingPrefix = NULL) {SetIntDBVal(sModule, Value, sDBSettingPrefix); COptItem::MemToDB(sModule, sDBSettingPrefix);}
+ void WndToMem(HWND hWnd) {Value = GetDlgItemInt(hWnd, DlgItemID, NULL, bSigned); COptItem::WndToMem(hWnd);}
+ void MemToWnd(HWND hWnd) {SetDlgItemInt(hWnd, DlgItemID, Value, bSigned); COptItem::MemToWnd(hWnd);}
+ void SetValue(int Value) {this->Value = Value; COptItem::SetValue(Value);}
+ void SetDefValue(int DefValue) {this->DefValue = DefValue; COptItem::SetDefValue(DefValue);}
+ int GetValue() {return Value;}
+ int GetDefValue() {return DefValue;}
+ virtual COptItem* Copy() {return new COptItem_IntEdit(*this);}
+
+ int DefValue;
+ int Value;
+ int bSigned;
+};
+
+
+class COptItem_Checkbox : public COptItem
+{
+public:
+ COptItem_Checkbox() {}
+ COptItem_Checkbox(int DlgItemID, char *szDBSetting, int nValueSize = DBVT_BYTE, int DefValue = 0, int ValueMask = 0, int lParam = 0, bool ReadOnly = false): COptItem(DlgItemID, szDBSetting, nValueSize, lParam, ReadOnly), DefValue(DefValue), Value(0), ValueMask(ValueMask) {}
+
+ void DBToMem(CString &sModule, CString *sDBSettingPrefix = NULL);
+ void MemToDB(CString &sModule, CString *sDBSettingPrefix = NULL);
+ void WndToMem(HWND hWnd);
+ void MemToWnd(HWND hWnd);
+
+ void SetValue(int Value) {this->Value = Value; COptItem::SetValue(Value);}
+ void SetDefValue(int DefValue) {this->DefValue = DefValue; COptItem::SetDefValue(DefValue);}
+ int GetValue() {return Value;}
+ int GetDefValue() {return DefValue;}
+ virtual COptItem* Copy() {return new COptItem_Checkbox(*this);}
+
+ int Value;
+ int DefValue;
+ int ValueMask;
+};
+
+
+class COptItem_Radiobutton : public COptItem
+{
+public:
+ COptItem_Radiobutton() {}
+ COptItem_Radiobutton(int DlgItemID, char *szDBSetting, int nValueSize, int DefValue, int ValueMask, int lParam = 0, bool ReadOnly = false): COptItem(DlgItemID, szDBSetting, nValueSize, lParam, ReadOnly), DefValue(DefValue), Value(0), ValueMask(ValueMask) {}
+
+ void DBToMem(CString &sModule, CString *sDBSettingPrefix = NULL) {Value = (GetIntDBVal(sModule, false, sDBSettingPrefix) == ValueMask) ? BST_CHECKED : BST_UNCHECKED; COptItem::DBToMem(sModule, sDBSettingPrefix);}
+ void MemToDB(CString &sModule, CString *sDBSettingPrefix = NULL) {if ((Value == BST_CHECKED)) SetIntDBVal(sModule, ValueMask, sDBSettingPrefix); COptItem::MemToDB(sModule, sDBSettingPrefix);}
+ void WndToMem(HWND hWnd) {Value = IsDlgButtonChecked(hWnd, DlgItemID); COptItem::WndToMem(hWnd);}
+ void MemToWnd(HWND hWnd) {CheckDlgButton(hWnd, DlgItemID, Value); COptItem::MemToWnd(hWnd);}
+
+ void SetValue(int Value) {this->Value = Value; COptItem::SetValue(Value);}
+ void SetDefValue(int DefValue) {this->DefValue = DefValue; COptItem::SetDefValue(DefValue);}
+ int GetValue() {return Value;}
+ int GetDefValue() {return DefValue;}
+ virtual COptItem* Copy() {return new COptItem_Radiobutton(*this);}
+
+ int Value;
+ int DefValue;
+ int ValueMask;
+};
+
+
+class COptItem_Combobox : public COptItem
+{
+public:
+ COptItem_Combobox() {}
+ COptItem_Combobox(int DlgItemID, char *szDBSetting, int nValueSize = DBVT_BYTE, int DefValue = 0, int lParam = 0, bool ReadOnly = false): COptItem(DlgItemID, szDBSetting, nValueSize, lParam, ReadOnly), DefValue(DefValue), Value(0) {}
+ void DBToMem(CString &sModule, CString *sDBSettingPrefix = NULL) {Value = GetIntDBVal(sModule, false, sDBSettingPrefix); COptItem::DBToMem(sModule, sDBSettingPrefix);}
+ void MemToDB(CString &sModule, CString *sDBSettingPrefix = NULL) {SetIntDBVal(sModule, Value, sDBSettingPrefix); COptItem::MemToDB(sModule, sDBSettingPrefix);}
+ void WndToMem(HWND hWnd) {Value = SendDlgItemMessage(hWnd, DlgItemID, CB_GETITEMDATA, (WPARAM)SendDlgItemMessage(hWnd, DlgItemID, CB_GETCURSEL, 0, 0), 0); COptItem::WndToMem(hWnd);}
+ void MemToWnd(HWND hWnd) {SendDlgItemMessage(hWnd, DlgItemID, CB_SETCURSEL, Value, 0); COptItem::MemToWnd(hWnd);}
+ void SetValue(int Value) {this->Value = Value; COptItem::SetValue(Value);}
+ void SetDefValue(int DefValue) {this->DefValue = DefValue; COptItem::SetDefValue(DefValue);}
+ int GetValue() {return Value;}
+ int GetDefValue() {return DefValue;}
+ virtual COptItem* Copy() {return new COptItem_Combobox(*this);}
+
+ int DefValue;
+ int Value;
+};
+
+
+class COptItem_Colourpicker : public COptItem
+{
+public:
+ COptItem_Colourpicker() {}
+ COptItem_Colourpicker(int DlgItemID, char *szDBSetting, int DefValue = 0, int lParam = 0, bool ReadOnly = false): COptItem(DlgItemID, szDBSetting, DBVT_DWORD, lParam, ReadOnly), DefValue(DefValue), Value(0) {}
+ void DBToMem(CString &sModule, CString *sDBSettingPrefix = NULL) {Value = GetIntDBVal(sModule, false, sDBSettingPrefix); COptItem::DBToMem(sModule, sDBSettingPrefix);}
+ void MemToDB(CString &sModule, CString *sDBSettingPrefix = NULL) {SetIntDBVal(sModule, Value, sDBSettingPrefix); COptItem::MemToDB(sModule, sDBSettingPrefix);}
+ void WndToMem(HWND hWnd) {Value = SendDlgItemMessage(hWnd, DlgItemID, CPM_GETCOLOUR, 0, 0); COptItem::WndToMem(hWnd);}
+ void MemToWnd(HWND hWnd) {SendDlgItemMessage(hWnd, DlgItemID, CPM_SETCOLOUR, 0, Value); COptItem::MemToWnd(hWnd);}
+ void SetValue(int Value) {this->Value = Value; COptItem::SetValue(Value);}
+ void SetDefValue(int DefValue) {this->DefValue = DefValue; COptItem::SetDefValue(DefValue);}
+ int GetValue() {return Value;}
+ int GetDefValue() {return DefValue;}
+ virtual COptItem* Copy() {return new COptItem_Colourpicker(*this);}
+
+ DWORD DefValue;
+ DWORD Value;
+};
+
+
+class COptItem_Slider : public COptItem
+{
+public:
+ COptItem_Slider() {}
+ COptItem_Slider(int DlgItemID, char *szDBSetting, int nValueSize = DBVT_BYTE, int DefValue = 0, int lParam = 0, bool ReadOnly = false): COptItem(DlgItemID, szDBSetting, nValueSize, lParam, ReadOnly), DefValue(DefValue), Value(0) {}
+ void DBToMem(CString &sModule, CString *sDBSettingPrefix = NULL) {Value = GetIntDBVal(sModule, false, sDBSettingPrefix); COptItem::DBToMem(sModule, sDBSettingPrefix);}
+ void MemToDB(CString &sModule, CString *sDBSettingPrefix = NULL) {SetIntDBVal(sModule, Value, sDBSettingPrefix); COptItem::MemToDB(sModule, sDBSettingPrefix);}
+ void WndToMem(HWND hWnd) {Value = SendDlgItemMessage(hWnd, DlgItemID, TBM_GETPOS, 0, 0); COptItem::WndToMem(hWnd);}
+ void MemToWnd(HWND hWnd) {SendDlgItemMessage(hWnd, DlgItemID, TBM_SETPOS, true, Value); COptItem::MemToWnd(hWnd);}
+ void SetValue(int Value) {this->Value = Value; COptItem::SetValue(Value);}
+ void SetDefValue(int DefValue) {this->DefValue = DefValue; COptItem::SetDefValue(DefValue);}
+ int GetValue() {return Value;}
+ int GetDefValue() {return DefValue;}
+ virtual COptItem* Copy() {return new COptItem_Slider(*this);}
+
+ int DefValue;
+ int Value;
+};
+
+
+class COptItem_IntDBSetting : public COptItem
+{
+public:
+ COptItem_IntDBSetting() {}
+ COptItem_IntDBSetting(int DlgItemID, char *szDBSetting, int nValueSize = DBVT_BYTE, int bSigned = true, int DefValue = 0, int lParam = 0, bool ReadOnly = false): COptItem(DlgItemID, szDBSetting, nValueSize, lParam, ReadOnly), DefValue(DefValue), Value(0), bSigned(bSigned) {}
+ void DBToMem(CString &sModule, CString *sDBSettingPrefix = NULL) {Value = GetIntDBVal(sModule, bSigned, sDBSettingPrefix); COptItem::DBToMem(sModule, sDBSettingPrefix);}
+ void MemToDB(CString &sModule, CString *sDBSettingPrefix = NULL) {SetIntDBVal(sModule, Value, sDBSettingPrefix); COptItem::MemToDB(sModule, sDBSettingPrefix);}
+ void WndToMem(HWND hWnd) {COptItem::WndToMem(hWnd);}
+ void MemToWnd(HWND hWnd) {COptItem::MemToWnd(hWnd);}
+ void SetValue(int Value) {this->Value = Value; COptItem::SetValue(Value);}
+ void SetDefValue(int DefValue) {this->DefValue = DefValue; COptItem::SetDefValue(DefValue);}
+ int GetValue() {return Value;}
+ int GetDefValue() {return DefValue;}
+ virtual COptItem* Copy() {return new COptItem_IntDBSetting(*this);}
+
+ int Value;
+ int DefValue;
+ int bSigned;
+};
+
+
+class COptItem_BitDBSetting : public COptItem
+{
+public:
+ COptItem_BitDBSetting() {}
+ COptItem_BitDBSetting(int DlgItemID, char *szDBSetting, int nValueSize = DBVT_BYTE, int DefValue = 0, int ValueMask = 0, int lParam = 0, bool ReadOnly = false): COptItem(DlgItemID, szDBSetting, nValueSize, lParam, ReadOnly), DefValue(DefValue), Value(0), ValueMask(ValueMask) {}
+
+ void DBToMem(CString &sModule, CString *sDBSettingPrefix = NULL);
+ void MemToDB(CString &sModule, CString *sDBSettingPrefix = NULL);
+ void WndToMem(HWND hWnd) {COptItem::WndToMem(hWnd);}
+ void MemToWnd(HWND hWnd) {COptItem::MemToWnd(hWnd);}
+
+ void SetValue(int Value) {this->Value = Value; COptItem::SetValue(Value);}
+ void SetDefValue(int DefValue) {this->DefValue = DefValue; COptItem::SetDefValue(DefValue);}
+ int GetValue() {return Value;}
+ int GetDefValue() {return DefValue;}
+ virtual COptItem* Copy() {return new COptItem_BitDBSetting(*this);}
+
+ int Value;
+ int DefValue;
+ int ValueMask;
+};
+
+
+class COptItem_StrDBSetting : public COptItem
+{
+public:
+ COptItem_StrDBSetting() {}
+ COptItem_StrDBSetting(int DlgItemID, char *szDBSetting, int nMaxLen, TCHAR *szDefValue, int lParam = 0, bool ReadOnly = false): COptItem(DlgItemID, szDBSetting, nMaxLen, lParam, ReadOnly), sDefValue(szDefValue) {}
+ void DBToMem(CString &sModule, CString *sDBSettingPrefix = NULL) {sValue = GetStrDBVal(sModule, sDBSettingPrefix); COptItem::DBToMem(sModule, sDBSettingPrefix);}
+ void MemToDB(CString &sModule, CString *sDBSettingPrefix = NULL) {SetStrDBVal(sModule, sValue, sDBSettingPrefix); COptItem::MemToDB(sModule, sDBSettingPrefix);}
+ void WndToMem(HWND hWnd) {COptItem::WndToMem(hWnd);}
+ void MemToWnd(HWND hWnd) {COptItem::MemToWnd(hWnd);}
+ void SetValue(int Value) {sValue = *(TCString*)Value; COptItem::SetValue(Value);}
+ void SetDefValue(int DefValue) {sDefValue = *(TCString*)DefValue; COptItem::SetDefValue(DefValue);}
+ int GetValue() {return (int)&sValue;}
+ int GetDefValue() {return (int)&sDefValue;}
+ virtual COptItem* Copy() {return new COptItem_StrDBSetting(*this);}
+
+ TCString sDefValue;
+ TCString sValue;
+};
+
+
+// Tree item flags
+#define TIF_GROUP 1 // is a group
+#define TIF_EXPANDED 2 // item is expanded
+#define TIF_ENABLED 4 // item is checked (has sense when the tree has checkboxes)
+#define TIF_ROOTITEM 0x80 // item is a root item
+
+class CBaseTreeItem
+{
+public:
+ CBaseTreeItem();
+ CBaseTreeItem(TCString Title, int ID, int Flags): Title(Title), ID(ID), Flags(Flags), hItem(NULL) {}
+
+ TCString Title;
+ int ID;
+ int Flags;
+ HTREEITEM hItem;
+};
+
+class CTreeItem : public CBaseTreeItem
+{
+public:
+ CTreeItem();
+ CTreeItem(TCString Title, int ParentID, int ID, int Flags = 0, TCString User_Str1 = NULL):
+ CBaseTreeItem(Title, ID, Flags & ~TIF_ROOTITEM), ParentID(ParentID), User_Str1(User_Str1) {}
+
+ int ParentID;
+ TCString User_Str1;
+};
+
+class CTreeRootItem : public CBaseTreeItem
+{
+public:
+ CTreeRootItem();
+ CTreeRootItem(TCString Title, int ID, int Flags): CBaseTreeItem(Title, ID, Flags | TIF_ROOTITEM) {}
+};
+
+typedef TMyArray<CTreeItem> TreeItemArray;
+typedef TMyArray<CTreeRootItem> TreeRootItemArray;
+
+#define TREECTRL_ROOTORDEROFFS -2
+#define ROOT_INDEX_TO_ORDER(i) (TREECTRL_ROOTORDEROFFS - (i))
+#define ROOT_ORDER_TO_INDEX(i) (TREECTRL_ROOTORDEROFFS - (i))
+
+#define TREEITEMTITLE_MAXLEN 128
+#define TREEITEM_DBSTR_TITLE "Title"
+#define TREEITEM_DBSTR_PARENT "Parent"
+#define TREEITEM_DBSTR_ORDER "Order"
+#define TREEITEM_DBSTR_FLAGS "Flags"
+
+// Tree control flags
+#define TREECTRL_FLAG_IS_SINGLE_LEVEL 1 // means that the tree items can't have children, i.e. the tree is a plain list of items
+#define TREECTRL_FLAG_HAS_CHECKBOXES 2
+//#define TREECTRL_FLAG_UNORDERED 4 TODO?
+
+class COptItem_TreeCtrl : public COptItem
+{
+public:
+ COptItem_TreeCtrl() {}
+ COptItem_TreeCtrl(int DlgItemID, char *szDBSetting, TreeItemArray &DefValue, TreeRootItemArray RootItems, int lParam = 0, CString User_Str1_DBName = NULL, bool ReadOnly = false, int TreeFlags = 0): COptItem(DlgItemID, szDBSetting, DBVT_DWORD, lParam, ReadOnly), DefValue(DefValue), RootItems(RootItems), User_Str1_DBName(User_Str1_DBName), TreeFlags(TreeFlags)
+ {
+ if (TreeFlags & TREECTRL_FLAG_IS_SINGLE_LEVEL)
+ {
+ _ASSERT(!RootItems.GetSize()); // there can't be any root items when the tree is a plain list
+ this->RootItems.AddElem(CTreeRootItem(_T(""), 0, TIF_EXPANDED)); // TODO??
+ this->RootItems[0].hItem = TVI_ROOT;
+ }
+ }
+ ~COptItem_TreeCtrl() {}
+ void DBToMem(CString &sModule, CString *sDBSettingPrefix = NULL);
+ void MemToDB(CString &sModule, CString *sDBSettingPrefix = NULL);
+ void WndToMem(HWND hWnd);
+ void MemToWnd(HWND hWnd);
+ void CleanDBSettings(CString &sModule, CString *sDBSettingPrefix = NULL);
+ void SetValue(int Value) {this->Value = *(TreeItemArray*)Value; COptItem::SetValue(Value);}
+ void SetDefValue(int DefValue) {this->DefValue = *(TreeItemArray*)DefValue; COptItem::SetDefValue(DefValue);}
+ int GetValue() {return (int)&Value;}
+ int GetDefValue() {return (int)&DefValue;}
+ virtual COptItem* Copy() {return new COptItem_TreeCtrl(*this);}
+
+ int IDToOrder(int ID);
+ int hItemToOrder(HTREEITEM hItem);
+ int GenerateID();
+ int GetSelectedItemID(HWND hWnd);
+ void Delete(HWND hWnd, int ID);
+ CTreeItem* InsertItem(HWND hWnd, CTreeItem &Item);
+ void MoveItem(HWND hWnd, HTREEITEM hItem, HTREEITEM hMoveTo);
+
+ TreeItemArray DefValue, Value;
+ TreeRootItemArray RootItems;
+ CString User_Str1_DBName;
+ int TreeFlags;
+
+protected:
+ void RecursiveDelete(HWND hWnd, int I);
+ int RecursiveMove(int ItemOrder, int ParentID, int InsertAtOrder);
+};
+
+
+class CListItem
+{
+public:
+ CListItem();
+ CListItem(TCString Text): Text(Text) {}
+
+ TCString Text;
+};
+
+typedef TMyArray<CListItem> ListItemArray;
+
+#define LISTITEM_DBSTR_TEXT "Text"
+
+class COptItem_ListCtrl : public COptItem
+{
+public:
+ COptItem_ListCtrl() {}
+ COptItem_ListCtrl(int DlgItemID, char *szDBSetting, ListItemArray &DefValue, int lParam = 0, bool ReadOnly = false): COptItem(DlgItemID, szDBSetting, DBVT_DWORD, lParam, ReadOnly), DefValue(DefValue) {}
+ ~COptItem_ListCtrl() {}
+ void DBToMem(CString &sModule, CString *sDBSettingPrefix = NULL);
+ void MemToDB(CString &sModule, CString *sDBSettingPrefix = NULL);
+ void WndToMem(HWND hWnd);
+ void MemToWnd(HWND hWnd);
+ void CleanDBSettings(CString &sModule, CString *sDBSettingPrefix = NULL);
+ void SetValue(int Value) {this->Value = *(ListItemArray*)Value; COptItem::SetValue(Value);}
+ void SetDefValue(int DefValue) {this->DefValue = *(ListItemArray*)DefValue; COptItem::SetDefValue(DefValue);}
+ int GetValue() {return (int)&Value;}
+ int GetDefValue() {return (int)&DefValue;}
+ virtual COptItem* Copy() {return new COptItem_ListCtrl(*this);}
+
+ int GetSelectedItemID(HWND hWnd); // returns -1 if there's no selection
+ int SetSelectedItemID(HWND hWnd, int ID);
+ void Delete(HWND hWnd, int ID);
+ CListItem* InsertItem(HWND hWnd, int ID, CListItem &Item);
+ void ModifyItem(HWND hWnd, int ID, CListItem &Item);
+
+ ListItemArray DefValue, Value;
+};
+
+
+class COptPage
+{
+public:
+ COptPage(): hWnd(NULL), sDBSettingPrefix("") {}
+ COptPage(char *szModule, HWND hWnd, CString sDBSettingPrefix = ""): sModule(szModule), hWnd(hWnd), sDBSettingPrefix(sDBSettingPrefix) {}
+ COptPage(const COptPage &Item);
+ ~COptPage();
+
+ void DBToMem();
+ void MemToDB();
+ void MemToPage(int OnlyEnable = 0);
+ void PageToMem();
+ void DBToMemToPage() {DBToMem(); MemToPage();}
+ void PageToMemToDB() {PageToMem(); MemToDB();}
+ void CleanDBSettings();
+
+ COptItem *Find(int DlgItemID);
+ int GetValue(int DlgItemID) {return Find(DlgItemID)->GetValue();}
+ void SetValue(int DlgItemID, int Value) {Find(DlgItemID)->SetValue(Value);}
+ int GetDBValue(int DlgItemID) {return Find(DlgItemID)->GetDBValue(sModule, &sDBSettingPrefix);}
+ void SetDBValue(int DlgItemID, int Value) {Find(DlgItemID)->SetDBValue(sModule, Value, &sDBSettingPrefix);}
+ int GetDBValueCopy(int DlgItemID) {return Find(DlgItemID)->GetDBValueCopy(sModule, &sDBSettingPrefix);}
+ void SetDBValueCopy(int DlgItemID, int Value) {Find(DlgItemID)->SetDBValueCopy(sModule, Value, &sDBSettingPrefix);}
+ int GetWndValue(int DlgItemID) {return Find(DlgItemID)->GetWndValue(hWnd);}
+ void SetWndValue(int DlgItemID, int Value) {Find(DlgItemID)->SetWndValue(hWnd, Value);}
+ HWND GetWnd() {return hWnd;}
+ void SetWnd(HWND hWnd) {_ASSERT(!this->hWnd || !hWnd); this->hWnd = hWnd;}
+ void Enable(int DlgItemID, int Enabled) {Find(DlgItemID)->Enable(Enabled);}
+ bool GetModified();
+ void SetModified(bool Modified);
+
+ COptPage& operator = (const COptPage& Page);
+
+ HWND hWnd;
+ CString sModule, sDBSettingPrefix;
+ TMyArray<COptItem*, COptItem*> Items;
+};
diff --git a/plugins/ClientChangeNotify/src/CommonLibs/TMyArray.h b/plugins/ClientChangeNotify/src/CommonLibs/TMyArray.h
new file mode 100644
index 0000000000..68ca908fe1
--- /dev/null
+++ b/plugins/ClientChangeNotify/src/CommonLibs/TMyArray.h
@@ -0,0 +1,353 @@
+/*
+ TMyArray.h - TMyArray template
+ Copyright (c) 2005-2008 Chervov Dmitry
+
+ 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
+*/
+
+#pragma once
+
+#include <stdlib.h>
+
+#define ARRAY_GROWBY 4
+// if there is more than ARRAY_FREETHRESHOLD free array elements, then we're reallocating the array
+#define ARRAY_FREETHRESHOLD 16
+
+template <class T, class ARG_T = const T&, int GrowBy = ARRAY_GROWBY, int FreeThreshold = ARRAY_FREETHRESHOLD>
+class TMyArray
+{
+public:
+ TMyArray();
+ TMyArray(const TMyArray<T, ARG_T, GrowBy, FreeThreshold> &A);
+ ~TMyArray();
+
+ int GetSize() const;
+ T* GetData() const;
+ int AddElem(ARG_T pElem);
+ int Add(const T *pItems, int nItems);
+ void InsertElem(ARG_T pElem, int nInsertAt);
+ void MoveElem(int nIndex, int nMoveTo);
+ T& SetAtGrow(int nIndex);
+ int Find(ARG_T pElem); // returns an index of the specified item, or -1 if the array doesn't contain the item
+ int BinarySearch(int (*CmpFunc)(ARG_T pItem, LPARAM lParam), LPARAM lParam, int *pIndex = NULL); // returns an index of the specified item, or -1 if the array doesn't contain the item;
+ // also it's possible to specify pIndex so that even if the array doesn't contain the item, the function will set *pIndex to a position where the item can be inserted;
+ // CmpFunc must return -1, 0 and 1 depending whether pItem is lesser, equal or greater than needed;
+ // BinarySearch() requires the array to be sorted in an ascending order
+ void RemoveElem(int nIndex, int nItems = 1);
+ void RemoveAll();
+ const T& operator[](int nIndex) const;
+ T& operator[](int nIndex);
+ TMyArray<T, ARG_T, GrowBy, FreeThreshold>& operator = (const TMyArray<T, ARG_T, GrowBy, FreeThreshold> &A);
+ TMyArray<T, ARG_T, GrowBy, FreeThreshold>& operator += (const TMyArray<T, ARG_T, GrowBy, FreeThreshold> &A);
+
+private:
+ int SetAllocNum(int nNewAllocNum);
+
+ T* pData;
+ int nElemNum;
+ int nAllocNum;
+};
+
+template <class T, class ARG_T, int GrowBy, int FreeThreshold>
+TMyArray<T, ARG_T, GrowBy, FreeThreshold>::TMyArray()
+{
+ nElemNum = 0;
+ nAllocNum = 0;
+ pData = NULL;
+}
+
+template <class T, class ARG_T, int GrowBy, int FreeThreshold>
+TMyArray<T, ARG_T, GrowBy, FreeThreshold>::TMyArray(const TMyArray<T, ARG_T, GrowBy, FreeThreshold> &A)//: TMyArray<T, ARG_T>()
+{
+ nElemNum = 0;
+ nAllocNum = 0;
+ pData = NULL;
+ *this = A;
+}
+
+template <class T, class ARG_T, int GrowBy, int FreeThreshold>
+TMyArray<T, ARG_T, GrowBy, FreeThreshold>::~TMyArray()
+{
+ RemoveAll();
+}
+
+template <class T, class ARG_T, int GrowBy, int FreeThreshold>
+__forceinline int TMyArray<T, ARG_T, GrowBy, FreeThreshold>::GetSize() const
+{
+ return nElemNum;
+}
+
+template <class T, class ARG_T, int GrowBy, int FreeThreshold>
+__forceinline T* TMyArray<T, ARG_T, GrowBy, FreeThreshold>::GetData() const
+{
+ return pData;
+}
+
+template <class T, class ARG_T, int GrowBy, int FreeThreshold>
+__forceinline int TMyArray<T, ARG_T, GrowBy, FreeThreshold>::SetAllocNum(int nNewAllocNum)
+{
+ _ASSERT(nNewAllocNum >= nElemNum);
+ T*pNewData = (nNewAllocNum) ? (T*)malloc(sizeof(T) * nNewAllocNum) : NULL;
+ if (pData)
+ {
+ if (pNewData)
+ {
+ memcpy(pNewData, pData, sizeof(T) * nElemNum);
+ }
+ free(pData);
+ }
+ pData = pNewData;
+ if (!pNewData)
+ {
+ nAllocNum = 0;
+ return -1; // not enough memory?
+ } else
+ {
+ nAllocNum = nNewAllocNum;
+ return 0; // everything's ok
+ }
+}
+
+template <class T, class ARG_T, int GrowBy, int FreeThreshold>
+__forceinline int TMyArray<T, ARG_T, GrowBy, FreeThreshold>::AddElem(ARG_T pElem)
+{
+ if (nElemNum >= nAllocNum)
+ { // reallocate memory to fit new element
+ SetAllocNum(nAllocNum + GrowBy);
+ }
+ memset(pData + nElemNum, 0, sizeof(T));
+ pData[nElemNum] = pElem;
+ return nElemNum++;
+}
+
+template <class T, class ARG_T, int GrowBy, int FreeThreshold>
+__forceinline int TMyArray<T, ARG_T, GrowBy, FreeThreshold>::Add(const T *pItems, int nItems)
+{
+ if (nElemNum + nItems > nAllocNum)
+ { // reallocate memory to fit new items
+ SetAllocNum(nAllocNum + nElemNum + nItems - 1 - ((nElemNum + nItems - 1) % GrowBy) + GrowBy);
+ }
+ memset(pData + nElemNum, 0, sizeof(T) * nItems);
+ int I;
+ for (I = 0; I < nItems; I++)
+ {
+ pData[nElemNum++] = pItems[I];
+ }
+ return nElemNum - nItems; // returns an index of the first item added
+}
+
+template <class T, class ARG_T, int GrowBy, int FreeThreshold>
+__forceinline void TMyArray<T, ARG_T, GrowBy, FreeThreshold>::InsertElem(ARG_T pElem, int nInsertAt)
+{
+ _ASSERT(nInsertAt >= 0 && nInsertAt <= nElemNum);
+ if (nElemNum >= nAllocNum)
+ { // reallocate memory to fit new items
+ SetAllocNum(nAllocNum + GrowBy);
+ }
+ memmove(pData + nInsertAt + 1, pData + nInsertAt, sizeof(T) * (nElemNum - nInsertAt));
+ memset(pData + nInsertAt, 0, sizeof(T));
+ pData[nInsertAt] = pElem;
+ nElemNum++;
+}
+
+template <class T, class ARG_T, int GrowBy, int FreeThreshold>
+__forceinline void TMyArray<T, ARG_T, GrowBy, FreeThreshold>::MoveElem(int nIndex, int nMoveTo)
+{
+ _ASSERT(nIndex >= 0 && nIndex < nElemNum && nMoveTo >= 0 && nMoveTo < nElemNum);
+ if (nIndex == nMoveTo)
+ {
+ return; // nothing to do
+ }
+ char Elem[sizeof(T)];
+ memmove(Elem, pData + nIndex, sizeof(T));
+ if (nIndex < nMoveTo)
+ {
+ memmove(pData + nIndex, pData + nIndex + 1, sizeof(T) * (nMoveTo - nIndex));
+ } else
+ {
+ memmove(pData + nMoveTo + 1, pData + nMoveTo, sizeof(T) * (nIndex - nMoveTo));
+ }
+ memmove(pData + nMoveTo, Elem, sizeof(T));
+}
+
+template <class T, class ARG_T, int GrowBy, int FreeThreshold>
+__forceinline T& TMyArray<T, ARG_T, GrowBy, FreeThreshold>::SetAtGrow(int nIndex)
+{
+ _ASSERT(nIndex >= 0);
+ if (nIndex < nElemNum)
+ {
+ return pData[nIndex];
+ }
+ if (nIndex >= nAllocNum)
+ {
+ if (SetAllocNum(nIndex - (nIndex % GrowBy) + GrowBy))
+ { // if there was an error
+ nElemNum = 0;
+ return *pData;
+ }
+ }
+ memset(pData + nElemNum, 0, sizeof(T) * (nIndex - nElemNum + 1));
+ nElemNum = nIndex + 1;
+ return pData[nIndex];
+}
+
+template <class T, class ARG_T, int GrowBy, int FreeThreshold>
+__forceinline int TMyArray<T, ARG_T, GrowBy, FreeThreshold>::Find(ARG_T pElem)
+{
+ int I;
+ for (I = 0; I < nElemNum; I++)
+ {
+ if (pData[I] == pElem)
+ {
+ return I;
+ }
+ }
+ return -1;
+}
+
+template <class T, class ARG_T, int GrowBy, int FreeThreshold>
+__forceinline int TMyArray<T, ARG_T, GrowBy, FreeThreshold>::BinarySearch(int (*CmpFunc)(ARG_T pItem, LPARAM lParam), LPARAM lParam, int *pIndex)
+{
+ int L, R;
+ int CmpResult;
+ if (!nElemNum)
+ {
+ if (pIndex)
+ {
+ *pIndex = -1;
+ }
+ return -1;
+ }
+ for (L = 0, R = nElemNum; R - L > 1;)
+ {
+ int C = (L + R) >> 1; // rounds always to a lesser index if L + R is odd
+ CmpResult = CmpFunc(pData[C], lParam); // usually, CmpFunc = pData[C] - lParam; i.e. CmpFunc > 0 when pData[C] is greater than necessary, < 0 when pData[C] is less, and = 0 when pData[C] is the item we search for
+ if (CmpResult < 0)
+ {
+ L = C;
+ } else if (CmpResult > 0)
+ {
+ R = C;
+ } else
+ { // CmpResult == 0
+ if (pIndex)
+ {
+ *pIndex = C;
+ }
+ return C;
+ }
+ }
+ if (pIndex)
+ {
+ *pIndex = L;
+ }
+ CmpResult = CmpFunc(pData[L], lParam);
+ if (!CmpResult)
+ {
+ return L;
+ }
+ if (CmpResult > 0)
+ { // we don't need to check pData[R], as pData[R] > pData[L] > lParam, i.e. there are no suitable item in the array
+ return -1;
+ }
+// CmpResult < 0, we have to check pData[R] too
+ if (pIndex)
+ {
+ *pIndex = R;
+ }
+ if (R >= nElemNum)
+ {
+ return -1;
+ }
+ return CmpFunc(pData[R], lParam) ? -1 : R;
+}
+
+template <class T, class ARG_T, int GrowBy, int FreeThreshold>
+__forceinline void TMyArray<T, ARG_T, GrowBy, FreeThreshold>::RemoveElem(int nIndex, int nItems)
+{
+ _ASSERT(nIndex >= 0 && nIndex + nItems <= nElemNum);
+ if (!nItems)
+ {
+ return;
+ }
+// delete pData[nIndex];
+// ~pData[nIndex];
+ int I;
+ for (I = nIndex; I < nIndex + nItems; I++)
+ {
+ (pData + I)->~T();
+ }
+ memmove(pData + nIndex, pData + nIndex + nItems, sizeof(T) * (nElemNum - nIndex - nItems));
+ nElemNum -= nItems;
+ if (nAllocNum - nElemNum >= FreeThreshold)
+ {
+ SetAllocNum(nAllocNum - FreeThreshold);
+ }/* else
+ {
+ memset(pData + nElemNum, 0, sizeof(T));
+ }*/
+}
+
+template <class T, class ARG_T, int GrowBy, int FreeThreshold>
+__forceinline void TMyArray<T, ARG_T, GrowBy, FreeThreshold>::RemoveAll()
+{
+ int I;
+ for (I = 0; I < nElemNum; I++)
+ {
+ //delete pData[I];
+ (pData + I)->~T();
+ }
+ nElemNum = 0;
+ SetAllocNum(0);
+}
+
+template <class T, class ARG_T, int GrowBy, int FreeThreshold>
+__forceinline const T& TMyArray<T, ARG_T, GrowBy, FreeThreshold>::operator[](int nIndex) const
+{
+ _ASSERT(nIndex >= 0 && nIndex < nElemNum);
+ return pData[nIndex];
+}
+
+template <class T, class ARG_T, int GrowBy, int FreeThreshold>
+__forceinline T& TMyArray<T, ARG_T, GrowBy, FreeThreshold>::operator[](int nIndex)
+{
+ _ASSERT(nIndex >= 0 && nIndex < nElemNum);
+ return pData[nIndex];
+}
+
+template <class T, class ARG_T, int GrowBy, int FreeThreshold>
+__forceinline TMyArray<T, ARG_T, GrowBy, FreeThreshold>& TMyArray<T, ARG_T, GrowBy, FreeThreshold>::operator = (const TMyArray<T, ARG_T, GrowBy, FreeThreshold> &A)
+{
+ RemoveAll();
+ int I;
+ for (I = 0; I < A.GetSize(); I++)
+ {
+ AddElem(A[I]);
+ }
+ return *this;
+}
+
+template <class T, class ARG_T, int GrowBy, int FreeThreshold>
+__forceinline TMyArray<T, ARG_T, GrowBy, FreeThreshold>& TMyArray<T, ARG_T, GrowBy, FreeThreshold>::operator += (const TMyArray<T, ARG_T, GrowBy, FreeThreshold> &A)
+{
+ int I;
+ for (I = 0; I < A.GetSize(); I++)
+ {
+ AddElem(A[I]);
+ }
+ return *this;
+}
+
+typedef TMyArray<char, const char&, 1024, 4096> CHARARRAY;
diff --git a/plugins/ClientChangeNotify/src/CommonLibs/pcre.cpp b/plugins/ClientChangeNotify/src/CommonLibs/pcre.cpp
new file mode 100644
index 0000000000..ae82e43435
--- /dev/null
+++ b/plugins/ClientChangeNotify/src/CommonLibs/pcre.cpp
@@ -0,0 +1,272 @@
+/*
+ Pcre.cpp
+ Copyright (c) 2007-2008 Chervov Dmitry
+
+ 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 "common.h"
+#include <windows.h>
+#include <stdio.h>
+#include <crtdbg.h>
+#include "newpluginapi.h"
+#include "m_utils.h"
+#include "TMyArray.h"
+#include "CString.h"
+#include "pcre.h"
+
+
+HMODULE hPcreDLL = NULL;
+
+static pcre* (*pcre_compile)(const char*, int, const char**, int*, const unsigned char*);
+static int (*pcre_config)(int, void*);
+static int (*pcre_exec)(const pcre*, const pcre_extra*, const char*, int, int, int, int*, int);
+static void (*pcre_free)(void*);
+static pcre_extra* (*pcre_study)(const pcre*, int, const char **);
+
+
+typedef struct
+{
+ pcre *pPcre;
+ pcre_extra *pExtra;
+ TCString Pattern; // used when it's not a valid regexp
+ int ID; // user-defined ID of the pattern; returned by PcreCheck on a match
+} sPcreCompileData;
+
+TMyArray<sPcreCompileData> PcreCompileData;
+
+
+void FreePcreCompileData()
+{
+ int I;
+ for (I = 0; I < PcreCompileData.GetSize(); I++)
+ {
+ if (PcreCompileData[I].pPcre)
+ {
+ pcre_free(PcreCompileData[I].pPcre);
+ if (PcreCompileData[I].pExtra)
+ {
+ pcre_free(PcreCompileData[I].pExtra);
+ }
+ }
+ }
+ PcreCompileData.RemoveAll();
+}
+
+
+TCString CompileRegexp(TCString Regexp, int bAddAsUsualSubstring, int ID)
+{
+ TCString Result(_T(""));
+ sPcreCompileData s = {0};
+ int NewID = PcreCompileData.AddElem(s);
+ PcreCompileData[NewID].ID = ID;
+ if (hPcreDLL && !bAddAsUsualSubstring)
+ {
+ const char *Err;
+ int ErrOffs;
+ int Flags = PCRE_CASELESS;
+ if (Regexp[0] == '/')
+ {
+ TCString OrigRegexp = Regexp;
+ Regexp = Regexp.Right(Regexp.GetLen() - 1);
+ TCHAR *pRegexpEnd = (TCHAR*)Regexp + Regexp.GetLen();
+ TCHAR *p = _tcsrchr(Regexp.GetBuffer(), '/');
+ if (!p)
+ {
+ Regexp = OrigRegexp;
+ } else
+ {
+ *p = 0;
+ Flags = 0;
+ while (++p < pRegexpEnd)
+ {
+ switch (*p) {
+ case 'i':
+ Flags |= PCRE_CASELESS;
+ break;
+ case 'm':
+ Flags |= PCRE_MULTILINE;
+ break;
+ case 's':
+ Flags |= PCRE_DOTALL;
+ break;
+ case 'x':
+ Flags |= PCRE_EXTENDED;
+ break;
+ case 'A':
+ Flags |= PCRE_ANCHORED;
+ break;
+ case 'f':
+ Flags |= PCRE_FIRSTLINE;
+ break;
+ case 'D':
+ Flags |= PCRE_DOLLAR_ENDONLY;
+ break;
+ case 'U':
+ Flags |= PCRE_UNGREEDY;
+ break;
+ case 'X':
+ Flags |= PCRE_EXTRA;
+ break;
+ default:
+ // Result += LogMessage(Translate("Warning, unknown pattern modifier '%c':\n"), *p );
+ break;
+ }
+ }
+ }
+ Regexp.ReleaseBuffer();
+ }
+
+ PcreCompileData[NewID].pPcre = pcre_compile(WCHAR2UTF8(Regexp).GetData(), PCRE_UTF8 | PCRE_NO_UTF8_CHECK | Flags, &Err, &ErrOffs, NULL);
+
+ if (PcreCompileData[NewID].pPcre) {
+ PcreCompileData[NewID].pExtra = NULL;
+ if (pcre_study)
+ PcreCompileData[NewID].pExtra = pcre_study(PcreCompileData[NewID].pPcre, 0, &Err);
+ }
+ else {
+ // Result += LogMessage(TranslateT("Syntax error in regexp\n%s\nat offset %d: %s."), (TCHAR*)Regexp, ErrOffs, (TCHAR*)ANSI2TCHAR(Err)) + _T("\n\n");
+ PcreCompileData[NewID].Pattern = Regexp;
+ }
+ }
+ else PcreCompileData[NewID].Pattern = Regexp;
+
+ return Result;
+}
+
+
+HMODULE LoadPcreLibrary(const char *szPath)
+{
+ _ASSERT(szPath);
+ HMODULE hModule = LoadLibraryA(szPath);
+ if (!hModule)
+ {
+ return NULL;
+ }
+ *(FARPROC*)&pcre_config = GetProcAddress(hModule, "pcre_config");
+ *(FARPROC*)&pcre_compile = GetProcAddress(hModule, "pcre_compile");
+ *(FARPROC*)&pcre_exec = GetProcAddress(hModule, "pcre_exec");
+ *(FARPROC*)&pcre_study = GetProcAddress(hModule, "pcre_study");
+ *(FARPROC*)&pcre_free = *(FARPROC*)GetProcAddress(hModule, "pcre_free"); // pcre_free is a pointer to a variable containing pointer to the function %)
+ if (pcre_compile && pcre_exec && pcre_free)
+ {
+
+ int Utf8Supported = 0;
+ if (pcre_config)
+ {
+ pcre_config(PCRE_CONFIG_UTF8, &Utf8Supported);
+ }
+ if (Utf8Supported)
+ {
+ return hModule;
+ }
+
+ }
+ FreeLibrary(hModule);
+ return NULL;
+}
+
+
+void InitPcre()
+{
+ _ASSERT(!hPcreDLL);
+ hPcreDLL = LoadPcreLibrary("pcre.dll");
+ if (!hPcreDLL)
+ {
+ hPcreDLL = LoadPcreLibrary("pcre3.dll");
+ }
+ if (!hPcreDLL)
+ {
+ char path[MAX_PATH];
+ GetModuleFileNameA(NULL, path, sizeof(path));
+ char *p = strrchr(path, '\\');
+ if (p)
+ {
+ strcpy(p + 1, "pcre.dll");
+ } else
+ {
+ strcpy(path, "pcre.dll");
+ }
+ hPcreDLL = LoadPcreLibrary(path);
+ if (!hPcreDLL)
+ {
+ if (p)
+ {
+ strcpy(p + 1, "pcre3.dll");
+ } else
+ {
+ strcpy(path, "pcre3.dll");
+ }
+ hPcreDLL = LoadPcreLibrary(path);
+ }
+ }
+}
+
+
+void UninitPcre()
+{
+ if (hPcreDLL)
+ {
+ FreePcreCompileData();
+ FreeLibrary(hPcreDLL);
+ }
+}
+
+
+int PcreEnabled()
+{
+ return (int)hPcreDLL;
+}
+
+
+int PcreCheck(TCString Str, int StartingID)
+{ // StartingID specifies the pattern from which to start checking, i.e. the check starts from the next pattern after the one that has ID == StartingID
+ int I;
+ if (StartingID == -1)
+ {
+ I = 0;
+ } else
+ {
+ for (I = 0; I < PcreCompileData.GetSize(); I++)
+ {
+ if (PcreCompileData[I].ID == StartingID)
+ {
+ I++;
+ break;
+ }
+ }
+ }
+ for (; I < PcreCompileData.GetSize(); I++)
+ {
+ if (hPcreDLL && PcreCompileData[I].pPcre)
+ {
+
+ CHARARRAY Utf8Str = WCHAR2UTF8(Str);
+ int Res = pcre_exec(PcreCompileData[I].pPcre, PcreCompileData[I].pExtra, Utf8Str.GetData(), Utf8Str.GetSize() - 1, 0, PCRE_NOTEMPTY | PCRE_NO_UTF8_CHECK, NULL, 0);
+
+ if (Res >= 0)
+ {
+ return PcreCompileData[I].ID;
+ }
+ } else
+ {
+ if (_tcsstr(Str.ToLower(), PcreCompileData[I].Pattern.ToLower()))
+ {
+ return PcreCompileData[I].ID;
+ }
+ }
+ }
+ return -1;
+}
diff --git a/plugins/ClientChangeNotify/src/CommonLibs/pcre.h b/plugins/ClientChangeNotify/src/CommonLibs/pcre.h
new file mode 100644
index 0000000000..2663870f85
--- /dev/null
+++ b/plugins/ClientChangeNotify/src/CommonLibs/pcre.h
@@ -0,0 +1,30 @@
+/*
+ Pcre.h
+ Copyright (c) 2007-2008 Chervov Dmitry
+
+ 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 "CString.h"
+#include "pcre_main.h"
+
+#pragma once
+
+void InitPcre();
+void UninitPcre();
+int PcreEnabled();
+int PcreCheck(TCString Str, int StartingID = -1);
+void FreePcreCompileData();
+TCString CompileRegexp(TCString Regexp, int bAddAsUsualSubstring = 0, int ID = 0);
diff --git a/plugins/ClientChangeNotify/src/CommonLibs/pcre_main.h b/plugins/ClientChangeNotify/src/CommonLibs/pcre_main.h
new file mode 100644
index 0000000000..ca6e7449df
--- /dev/null
+++ b/plugins/ClientChangeNotify/src/CommonLibs/pcre_main.h
@@ -0,0 +1,298 @@
+/*************************************************
+* Perl-Compatible Regular Expressions *
+*************************************************/
+
+/* This is the public header file for the PCRE library, to be #included by
+applications that call the PCRE functions.
+
+ Copyright (c) 1997-2006 University of Cambridge
+
+-----------------------------------------------------------------------------
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ * Neither the name of the University of Cambridge nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
+-----------------------------------------------------------------------------
+*/
+
+#ifndef _PCRE_H
+#define _PCRE_H
+
+/* The current PCRE version information. */
+
+/* NOTES FOR FUTURE MAINTAINERS: Do not use numbers with leading zeros, because
+they may be treated as octal constants. The PCRE_PRERELEASE feature is for
+identifying release candidates. It might be defined as -RC2, for example. In
+real releases, it should be defined empty. Do not change the alignment of these
+statments. The code in ./configure greps out the version numbers by using "cut"
+to get values from column 29 onwards. These are substituted into pcre-config
+and libpcre.pc. The values are not put into configure.ac and substituted here
+(which would simplify this issue) because that makes life harder for those who
+cannot run ./configure. As it now stands, this file need not be edited in that
+circumstance. */
+
+#define PCRE_MAJOR 7
+#define PCRE_MINOR 0
+#define PCRE_PRERELEASE
+#define PCRE_DATE 18-Dec-2006
+
+/* Win32 uses DLL by default; it needs special stuff for exported functions
+when building PCRE. */
+
+#ifdef _WIN32
+# ifdef PCRE_DEFINITION
+# ifdef DLL_EXPORT
+# define PCRE_DATA_SCOPE __declspec(dllexport)
+# endif
+# else
+# ifndef PCRE_STATIC
+# define PCRE_DATA_SCOPE extern __declspec(dllimport)
+# endif
+# endif
+#endif
+
+/* Otherwise, we use the standard "extern". */
+
+#ifndef PCRE_DATA_SCOPE
+# ifdef __cplusplus
+# define PCRE_DATA_SCOPE extern "C"
+# else
+# define PCRE_DATA_SCOPE extern
+# endif
+#endif
+
+/* Have to include stdlib.h in order to ensure that size_t is defined;
+it is needed here for malloc. */
+
+#include <stdlib.h>
+
+/* Allow for C++ users */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Options */
+
+#define PCRE_CASELESS 0x00000001
+#define PCRE_MULTILINE 0x00000002
+#define PCRE_DOTALL 0x00000004
+#define PCRE_EXTENDED 0x00000008
+#define PCRE_ANCHORED 0x00000010
+#define PCRE_DOLLAR_ENDONLY 0x00000020
+#define PCRE_EXTRA 0x00000040
+#define PCRE_NOTBOL 0x00000080
+#define PCRE_NOTEOL 0x00000100
+#define PCRE_UNGREEDY 0x00000200
+#define PCRE_NOTEMPTY 0x00000400
+#define PCRE_UTF8 0x00000800
+#define PCRE_NO_AUTO_CAPTURE 0x00001000
+#define PCRE_NO_UTF8_CHECK 0x00002000
+#define PCRE_AUTO_CALLOUT 0x00004000
+#define PCRE_PARTIAL 0x00008000
+#define PCRE_DFA_SHORTEST 0x00010000
+#define PCRE_DFA_RESTART 0x00020000
+#define PCRE_FIRSTLINE 0x00040000
+#define PCRE_DUPNAMES 0x00080000
+#define PCRE_NEWLINE_CR 0x00100000
+#define PCRE_NEWLINE_LF 0x00200000
+#define PCRE_NEWLINE_CRLF 0x00300000
+#define PCRE_NEWLINE_ANY 0x00400000
+
+/* Exec-time and get/set-time error codes */
+
+#define PCRE_ERROR_NOMATCH (-1)
+#define PCRE_ERROR_NULL (-2)
+#define PCRE_ERROR_BADOPTION (-3)
+#define PCRE_ERROR_BADMAGIC (-4)
+#define PCRE_ERROR_UNKNOWN_OPCODE (-5)
+#define PCRE_ERROR_UNKNOWN_NODE (-5) /* For backward compatibility */
+#define PCRE_ERROR_NOMEMORY (-6)
+#define PCRE_ERROR_NOSUBSTRING (-7)
+#define PCRE_ERROR_MATCHLIMIT (-8)
+#define PCRE_ERROR_CALLOUT (-9) /* Never used by PCRE itself */
+#define PCRE_ERROR_BADUTF8 (-10)
+#define PCRE_ERROR_BADUTF8_OFFSET (-11)
+#define PCRE_ERROR_PARTIAL (-12)
+#define PCRE_ERROR_BADPARTIAL (-13)
+#define PCRE_ERROR_INTERNAL (-14)
+#define PCRE_ERROR_BADCOUNT (-15)
+#define PCRE_ERROR_DFA_UITEM (-16)
+#define PCRE_ERROR_DFA_UCOND (-17)
+#define PCRE_ERROR_DFA_UMLIMIT (-18)
+#define PCRE_ERROR_DFA_WSSIZE (-19)
+#define PCRE_ERROR_DFA_RECURSE (-20)
+#define PCRE_ERROR_RECURSIONLIMIT (-21)
+#define PCRE_ERROR_NULLWSLIMIT (-22)
+#define PCRE_ERROR_BADNEWLINE (-23)
+
+/* Request types for pcre_fullinfo() */
+
+#define PCRE_INFO_OPTIONS 0
+#define PCRE_INFO_SIZE 1
+#define PCRE_INFO_CAPTURECOUNT 2
+#define PCRE_INFO_BACKREFMAX 3
+#define PCRE_INFO_FIRSTBYTE 4
+#define PCRE_INFO_FIRSTCHAR 4 /* For backwards compatibility */
+#define PCRE_INFO_FIRSTTABLE 5
+#define PCRE_INFO_LASTLITERAL 6
+#define PCRE_INFO_NAMEENTRYSIZE 7
+#define PCRE_INFO_NAMECOUNT 8
+#define PCRE_INFO_NAMETABLE 9
+#define PCRE_INFO_STUDYSIZE 10
+#define PCRE_INFO_DEFAULT_TABLES 11
+
+/* Request types for pcre_config(). Do not re-arrange, in order to remain
+compatible. */
+
+#define PCRE_CONFIG_UTF8 0
+#define PCRE_CONFIG_NEWLINE 1
+#define PCRE_CONFIG_LINK_SIZE 2
+#define PCRE_CONFIG_POSIX_MALLOC_THRESHOLD 3
+#define PCRE_CONFIG_MATCH_LIMIT 4
+#define PCRE_CONFIG_STACKRECURSE 5
+#define PCRE_CONFIG_UNICODE_PROPERTIES 6
+#define PCRE_CONFIG_MATCH_LIMIT_RECURSION 7
+
+/* Bit flags for the pcre_extra structure. Do not re-arrange or redefine
+these bits, just add new ones on the end, in order to remain compatible. */
+
+#define PCRE_EXTRA_STUDY_DATA 0x0001
+#define PCRE_EXTRA_MATCH_LIMIT 0x0002
+#define PCRE_EXTRA_CALLOUT_DATA 0x0004
+#define PCRE_EXTRA_TABLES 0x0008
+#define PCRE_EXTRA_MATCH_LIMIT_RECURSION 0x0010
+
+/* Types */
+
+struct real_pcre; /* declaration; the definition is private */
+typedef struct real_pcre pcre;
+
+/* When PCRE is compiled as a C++ library, the subject pointer type can be
+replaced with a custom type. For conventional use, the public interface is a
+const char *. */
+
+#ifndef PCRE_SPTR
+#define PCRE_SPTR const char *
+#endif
+
+/* The structure for passing additional data to pcre_exec(). This is defined in
+such as way as to be extensible. Always add new fields at the end, in order to
+remain compatible. */
+
+typedef struct pcre_extra {
+ unsigned long int flags; /* Bits for which fields are set */
+ void *study_data; /* Opaque data from pcre_study() */
+ unsigned long int match_limit; /* Maximum number of calls to match() */
+ void *callout_data; /* Data passed back in callouts */
+ const unsigned char *tables; /* Pointer to character tables */
+ unsigned long int match_limit_recursion; /* Max recursive calls to match() */
+} pcre_extra;
+
+/* The structure for passing out data via the pcre_callout_function. We use a
+structure so that new fields can be added on the end in future versions,
+without changing the API of the function, thereby allowing old clients to work
+without modification. */
+
+typedef struct pcre_callout_block {
+ int version; /* Identifies version of block */
+ /* ------------------------ Version 0 ------------------------------- */
+ int callout_number; /* Number compiled into pattern */
+ int *offset_vector; /* The offset vector */
+ PCRE_SPTR subject; /* The subject being matched */
+ int subject_length; /* The length of the subject */
+ int start_match; /* Offset to start of this match attempt */
+ int current_position; /* Where we currently are in the subject */
+ int capture_top; /* Max current capture */
+ int capture_last; /* Most recently closed capture */
+ void *callout_data; /* Data passed in with the call */
+ /* ------------------- Added for Version 1 -------------------------- */
+ int pattern_position; /* Offset to next item in the pattern */
+ int next_item_length; /* Length of next item in the pattern */
+ /* ------------------------------------------------------------------ */
+} pcre_callout_block;
+
+/* Indirection for store get and free functions. These can be set to
+alternative malloc/free functions if required. Special ones are used in the
+non-recursive case for "frames". There is also an optional callout function
+that is triggered by the (?) regex item. For Virtual Pascal, these definitions
+have to take another form. */
+
+#ifdef PCRE_EXPORTS
+
+#ifndef VPCOMPAT
+PCRE_DATA_SCOPE void *(*pcre_malloc)(size_t);
+PCRE_DATA_SCOPE void (*pcre_free)(void *);
+PCRE_DATA_SCOPE void *(*pcre_stack_malloc)(size_t);
+PCRE_DATA_SCOPE void (*pcre_stack_free)(void *);
+PCRE_DATA_SCOPE int (*pcre_callout)(pcre_callout_block *);
+#else /* VPCOMPAT */
+PCRE_DATA_SCOPE void *pcre_malloc(size_t);
+PCRE_DATA_SCOPE void pcre_free(void *);
+PCRE_DATA_SCOPE void *pcre_stack_malloc(size_t);
+PCRE_DATA_SCOPE void pcre_stack_free(void *);
+PCRE_DATA_SCOPE int pcre_callout(pcre_callout_block *);
+#endif /* VPCOMPAT */
+
+/* Exported PCRE functions */
+
+PCRE_DATA_SCOPE pcre *pcre_compile(const char *, int, const char **, int *,
+ const unsigned char *);
+PCRE_DATA_SCOPE pcre *pcre_compile2(const char *, int, int *, const char **,
+ int *, const unsigned char *);
+PCRE_DATA_SCOPE int pcre_config(int, void *);
+PCRE_DATA_SCOPE int pcre_copy_named_substring(const pcre *, const char *,
+ int *, int, const char *, char *, int);
+PCRE_DATA_SCOPE int pcre_copy_substring(const char *, int *, int, int, char *,
+ int);
+PCRE_DATA_SCOPE int pcre_dfa_exec(const pcre *, const pcre_extra *,
+ const char *, int, int, int, int *, int , int *, int);
+PCRE_DATA_SCOPE int pcre_exec(const pcre *, const pcre_extra *, PCRE_SPTR,
+ int, int, int, int *, int);
+PCRE_DATA_SCOPE void pcre_free_substring(const char *);
+PCRE_DATA_SCOPE void pcre_free_substring_list(const char **);
+PCRE_DATA_SCOPE int pcre_fullinfo(const pcre *, const pcre_extra *, int,
+ void *);
+PCRE_DATA_SCOPE int pcre_get_named_substring(const pcre *, const char *,
+ int *, int, const char *, const char **);
+PCRE_DATA_SCOPE int pcre_get_stringnumber(const pcre *, const char *);
+PCRE_DATA_SCOPE int pcre_get_stringtable_entries(const pcre *, const char *,
+ char **, char **);
+PCRE_DATA_SCOPE int pcre_get_substring(const char *, int *, int, int,
+ const char **);
+PCRE_DATA_SCOPE int pcre_get_substring_list(const char *, int *, int,
+ const char ***);
+PCRE_DATA_SCOPE int pcre_info(const pcre *, int *, int *);
+PCRE_DATA_SCOPE const unsigned char *pcre_maketables(void);
+PCRE_DATA_SCOPE int pcre_refcount(pcre *, int);
+PCRE_DATA_SCOPE pcre_extra *pcre_study(const pcre *, int, const char **);
+PCRE_DATA_SCOPE const char *pcre_version(void);
+
+#endif /* PCRE_EXPORTS */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* End of pcre.h */