/* "Spam Filter"-Plugin for Miranda IM Copyright 2003-2006 Heiko Herkenrath 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 ("SpamFilter-License.txt"); if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ // -- Includes #include "common.h" // -- Macros #define SLAlloc(s) mir_alloc(s) #define SLReAlloc(p, s) mir_realloc((p), (s)) #define SLFree(p) mir_free(p) //#define SLAlloc(s) HeapAlloc(GetProcessHeap(), 0, (s)) //#define SLReAlloc(p, s) HeapReAlloc(GetProcessHeap(), 0, (p), (s)) //#define SLFree(p) HeapFree(GetProcessHeap(), 0, (p)) // ----------------------------------------- BOOL SLAssignToListBoxCtrl(LPSTRINGLIST psl, HWND hwndListBox) { BOOL bReturn = FALSE; int i; if (!psl || !hwndListBox) return FALSE; SendMessage(hwndListBox, LB_RESETCONTENT, 0, 0); SendMessage(hwndListBox, LB_INITSTORAGE, (WPARAM)psl->uCount, (LPARAM)(SLGetSize(psl, TRUE)*sizeof(WCHAR))); EnterCriticalSection(&psl->csListAccess); for (i=SL_MIN_POS; i<(int)psl->uCount; i++) if (SendMessage(hwndListBox, LB_ADDSTRING, 0, (LPARAM)psl->papszList[i]) >= 0) bReturn = TRUE; LeaveCriticalSection(&psl->csListAccess); return bReturn; } BOOL SLRetrieveFromListBoxCtrl(LPSTRINGLIST psl, HWND hwndListBox) { int iCount, i, iPos; BOOL bReturn; if (!psl || !hwndListBox) return FALSE; bReturn = FALSE; EnterCriticalSection(&psl->csListAccess); iCount = SendMessage(hwndListBox, LB_GETCOUNT, 0, 0); for (i=0; ipapszList[iPos]) != LB_ERR) bReturn = TRUE; else SLDeleteItem(psl, iPos); } } LeaveCriticalSection(&psl->csListAccess); return bReturn; } /* BOOL SLLoadFromIniFile(LPSTRINGLIST psl, const TCHAR* pszSearchPath, const TCHAR* pszSection, const TCHAR* pszSettingPrefix) { TCHAR szFile[MAX_PATH]; BOOL bFileFound; BOOL bReturn = FALSE; int i, iLen, iSize; TCHAR* pszItem; TCHAR* pszBuf; WIN32_FIND_DATA wfd; HANDLE hFind; if (!psl || !pszSection || !pszSearchPath) return FALSE; ZeroMemory(&wfd, sizeof(wfd)); EnterCriticalSection(&psl->csListAccess); // Enum all files in the directory hFind = FindFirstFile(pszSearchPath, &wfd); for (bFileFound=(hFind!=INVALID_HANDLE_VALUE); bFileFound; bFileFound=FindNextFile(hFind, &wfd)) { if (wfd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) continue; // Construct the file name mir_sntprintf(szFile, ARRAYSIZE(szFile), _T("%s"), pszSearchPath); PathRemoveFileSpec(szFile); PathAppend(szFile, wfd.cFileName); // Load the data from ini file iSize = (pszSettingPrefix?(lstrlen(pszSettingPrefix)+1):0)+MAX_INT_LENGTH+1); pszItem = (TCHAR*)mir_alloc(iSize*sizeof(TCHAR)); if (!pszItem) continue; for (i=SL_MIN_POS;;i++) // no break condition { mir_sntprintf(pszItem, _T("%s%s%i"), iSize, pszSettingPrefix?pszSettingPrefix:_T(""), pszSettingPrefix?_T("|"):_T(""), i); iLen = GetPrivateProfileString(pszSection, pszItem, NULL, NULL, 0, szFile); if (iLen < 0) break; pszBuf = (TCHAR*)mir_alloc((iLen+1)*sizeof(TCHAR)); if (!pszBuf) continue; GetPrivateProfileString(pszSection, pszItem, NULL, pszBuf, iLen, szFile); if (lstrlen(pszBuf) <= 0) break; if (SLAddItem(psl, pszBuf) != SL_INVALID_POS) if (!bReturn) bReturn = TRUE; mir_free(pszBuf); } mir_free(pszItem); } LeaveCriticalSection(&psl->csListAccess); if (hFind) FindClose(hFind); return bReturn; } BOOL SLSaveToIniFile(LPSTRINGLIST psl, const TCHAR* pszFileName, const TCHAR* pszSection, const TCHAR* pszSettingPrefix) { int i; char* pszItem; int iSize; BOOL bReturn = FALSE; if (!psl || !pszSection || !pszFileName) return FALSE; iSize = (pszSettingPrefix?(lstrlen(pszSettingPrefix)+1):0)+MAX_INT_LENGTH+1; pszItem = (TCHAR*)mir_alloc(iSize*sizeof(TCHAR)); if (pszItem) { EnterCriticalSection(&psl->csListAccess); // Delete old items (empty section) WritePrivateProfileString(pszSection, NULL, NULL, pszFileName); for (i=SL_MIN_POS; i<(int)psl->uCount; i++) { mir_sntprintf(pszItem, iSize, _T("%s%s%i"), pszSettingPrefix?pszSettingPrefix:_T(""), pszSettingPrefix?_T("|"):_T(""), i); if (WritePrivateProfileString(pszSection, pszItem, psl->papszList[i], pszFileName)) bReturn = TRUE; } LeaveCriticalSection(&psl->csListAccess); mir_free(pszItem); } return bReturn; } */ BOOL SLLoadFromFile(LPSTRINGLIST psl, const WCHAR* pszSearchPath) { BOOL bReturn; WIN32_FIND_DATA wfd; HANDLE hFind; BOOL bFileFound; WCHAR szFile[MAX_PATH]; HANDLE hFile; DWORD dwRead; int iAllocBufSize; int iAllocBufStep; char* pszAllocBuf; char* pszAllocBufTmp; const char szBOM[3] = {0xEF, 0xBB, 0xBF}; BOOL bWatchBOM; BOOL bEndOfFile; WCHAR* pszContentConv; WCHAR* pszBuf; if (!psl || !pszSearchPath) return FALSE; EnterCriticalSection(&psl->csListAccess); // Initial buffer size (gets auto-enlarged if needed) iAllocBufSize = 128; // read-in chars buffer pszAllocBuf = NULL; // Enum all files in the directory bReturn = FALSE; hFind = FindFirstFile(pszSearchPath, &wfd); for (bFileFound=(hFind!=INVALID_HANDLE_VALUE); bFileFound; bFileFound=FindNextFile(hFind, &wfd)) { if (wfd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) continue; mir_sntprintf(szFile, ARRAYSIZE(szFile), _T("%s"), pszSearchPath); PathRemoveFileSpec(szFile); PathAppend(szFile, wfd.cFileName); hFile = CreateFile(szFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if (hFile == INVALID_HANDLE_VALUE) continue; bWatchBOM = TRUE; bEndOfFile = FALSE; iAllocBufStep = 0; while (!bEndOfFile) { // Enlarge buffer if needed if (!pszAllocBuf || (iAllocBufStep >= iAllocBufSize)) { pszAllocBufTmp = (char*)mir_realloc(pszAllocBuf, (iAllocBufSize*2)*sizeof(char)); if (pszAllocBufTmp) { if (pszAllocBuf) iAllocBufSize *= 2; pszAllocBuf = pszAllocBufTmp; } else { bEndOfFile = TRUE; // out of memory } } if (!bEndOfFile) { if (!ReadFile(hFile, &pszAllocBuf[iAllocBufStep], sizeof(char), &dwRead, NULL)) bEndOfFile = TRUE; if (dwRead < sizeof(char)) bEndOfFile = TRUE; } if ((pszAllocBuf[iAllocBufStep] == '\n') || bEndOfFile) { if (!bEndOfFile && (iAllocBufStep>0) && (pszAllocBuf[iAllocBufStep-1] == '\r')) pszAllocBuf[iAllocBufStep-1] = '\0'; else pszAllocBuf[iAllocBufStep] = '\0'; if (lstrlenA(pszAllocBuf) > 0) { // Test UTF-8 BOM // EF BB BF = UTF-8 // -> indicating UTF-8 Unicode text file (check only once) if (bWatchBOM) { if (StrCmpNA(pszAllocBuf, szBOM, ARRAYSIZE(szBOM)) == 0) MoveMemory(pszAllocBuf, (PBYTE)pszAllocBuf+sizeof(szBOM), ((lstrlenA(pszAllocBuf)+1)*sizeof(char))-sizeof(szBOM)); bWatchBOM = FALSE; } // Decode Utf8 mir_utf8decode(pszAllocBuf,&pszContentConv); if (pszContentConv) { pszBuf = pszContentConv; while (pszBuf) { // Find comment indicator pszBuf = StrChr(pszBuf, _T(';')); // find ";" comment indicator if (pszBuf && (*CharPrev(pszContentConv, pszBuf) != _T('\\'))) // ignore "\;" chars { *pszBuf = _T('\0'); break; } } // Replace no-comment indicators pszBuf = ReplaceSubStringWithString(pszContentConv, _T("\\;"), _T(";"), TRUE, FALSE, NULL); // Add item to list (disallow empty items) if (lstrlen(pszContentConv) > 0) if (SLAddItem(psl, pszBuf?pszBuf:pszContentConv) >= 0) bReturn = TRUE; mir_free(pszContentConv); if (pszBuf) mir_free(pszBuf); } } // Reset step count iAllocBufStep = 0; } else { // Step up in string iAllocBufStep++; } } // while (!bEndOfFile) CloseHandle(hFile); } if (hFind) FindClose(hFind); if (pszAllocBuf) mir_free(pszAllocBuf); LeaveCriticalSection(&psl->csListAccess); return bReturn; } BOOL SLSaveToFile(LPSTRINGLIST psl, const WCHAR* pszFileName) { BOOL bReturn; int i; const char szBOM[3] = {0xEF, 0xBB, 0xBF}; HANDLE hFile; DWORD dwWritten; // Win98 compatibility WCHAR* pszBuf; char* pszContentUtf8; if (!psl || !pszFileName) return FALSE; hFile = CreateFile(pszFileName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, 0, NULL); if (hFile == INVALID_HANDLE_VALUE) return FALSE; bReturn = FALSE; EnterCriticalSection(&psl->csListAccess); // Write UTF-8 BOM // EF BB BF = UTF-8 // -> indicating UTF-8 Unicode text file if (WriteFile(hFile, &szBOM, sizeof(szBOM), &dwWritten, NULL)) for (i=SL_MIN_POS; i<(int)psl->uCount; i++) { // Replace comment indicators pszBuf = ReplaceSubStringWithString(psl->papszList[i], _T(";"), _T("\\;"), TRUE, FALSE, NULL); if (!pszBuf) continue; pszContentUtf8 = mir_utf8encodeW(pszBuf); if (pszContentUtf8) { if (WriteFile(hFile, pszContentUtf8, lstrlenA(pszContentUtf8)*sizeof(char), &dwWritten, NULL)) if (WriteFile(hFile, "\r\n", 2*sizeof(char), &dwWritten, NULL)) bReturn = TRUE; mir_free(pszContentUtf8); } mir_free(pszBuf); } LeaveCriticalSection(&psl->csListAccess); SetEndOfFile(hFile); // if it was longer before FlushFileBuffers(hFile); // just to be sure CloseHandle(hFile); return bReturn; } /* BOOL SLConvertFromString(LPSTRINGLIST psl, const TCHAR* pszString, int cchSize, const TCHAR* pszSeparator, BOOL bIgnoreEmptyItems) { // If pszSeparator is NULL a _T('\0') is taken as separator BOOL bReturn; int cchSepLen; BOOL bReachedEnd; TCHAR* pszAfterPrev; TCHAR* pszNext; int iPos; if (!pszString || !psl) return 0; if (cchSize < 0) cchSize = lstrlen(pszString)+1; cchSepLen = pszSeparator?lstrlen(pszSeparator):1; EnterCriticalSection(&psl->csListAccess); // Loop through string bReturn = 0; pszAfterPrev = (TCHAR*)pszString; bReachedEnd = FALSE; while (!bReachedEnd) { // Find first/next occurence if (pszSeparator) { pszNext = StrStr(pszAfterPrev, pszSeparator); if (!pszNext) { bReachedEnd = TRUE; pszNext = (TCHAR*)pszString+(cchSize*sizeof(TCHAR)); } } else { // Find NULL separator pszNext = pszAfterPrev; while (*pszNext != _T('\0')); { pszNext = CharNext(pszNext); if ( pszNext >= (szString+((cchSize-1)*sizeof(TCHAR)) ) { bReachedEnd = TRUE; break; } } } // Add item if (!bIgnoreEmptyItems || (pszNext != pszAfterPrev)) { i2 if (iPos < 0) continue; CopyMemory((PBYTE)psl->papszList[iPos], pszAfterPrev, ((PBYTE)pszNext-(PBYTE)pszAfterPrev)); bReturn = TRUE; } // Step up one separated item pszAfterPrev = pszNext+(cchSepLen*sizeof(TCHAR)); if ( pszAfterPrev >= pszString+((cchSize-1)*sizeof(TCHAR)) ) bReachedEnd = TRUE; } LeaveCriticalSection(&psl->csListAccess); return bReturn; } */ WCHAR* SLConvertToString(LPSTRINGLIST psl, const WCHAR* pszSeparator, BOOL bAlsoDoFirst, BOOL bAlsoDoLast, int* piSize) { // Returned string needs to be freed with SLFreeReturn() // If pszSeparator is NULL a _T('\0') is taken as separator int i; int iSepLen; int iSize; WCHAR* pszReturn; WCHAR* pszStep; if (piSize) *piSize = 0; if (!psl) return NULL; EnterCriticalSection(&psl->csListAccess); // Get needed size iSepLen = pszSeparator?lstrlen(pszSeparator):1; iSize = SLGetSize(psl, FALSE)+1; // character count in string list if (psl->uCount > 0) iSize += (psl->uCount-1)*iSepLen; if ((psl->uCount > 0) && bAlsoDoFirst) iSize += iSepLen; if (bAlsoDoLast) iSize += iSepLen; pszReturn = (WCHAR*)SLAlloc(iSize*sizeof(WCHAR)); if (!pszReturn) { LeaveCriticalSection(&psl->csListAccess); return NULL; } if (piSize) *piSize = iSize; // Add items to memory pszStep = pszReturn; for (i=SL_MIN_POS; i<(int)psl->uCount; i++) { if ((i>SL_MIN_POS) || bAlsoDoFirst) { if (pszSeparator) CopyMemory(pszStep, pszSeparator, iSepLen*sizeof(WCHAR)); // no terminating zero else ZeroMemory(pszStep, sizeof(WCHAR)); pszStep = &pszStep[iSepLen]; } // Add item CopyMemory(pszStep, psl->papszList[i], lstrlen(psl->papszList[i])*sizeof(WCHAR)); // no terminating zero pszStep = &pszStep[lstrlen(psl->papszList[i])]; } LeaveCriticalSection(&psl->csListAccess); if (bAlsoDoLast) { if (pszSeparator) CopyMemory(pszStep, pszSeparator, iSepLen*sizeof(WCHAR)); // no terminating zero else ZeroMemory(pszStep, sizeof(WCHAR)); pszStep = &pszStep[iSepLen]; } ZeroMemory(pszStep, sizeof(WCHAR)); return pszReturn; } void SLFreeReturn(void* pPntr) { if (pPntr) SLFree(pPntr); } BOOL SLConvertToStringBuf(LPSTRINGLIST psl, WCHAR* pszOutput, int cchMaxSize, const WCHAR* pszSeparator, BOOL bAlsoDoFirst, BOOL bAlsoDoLast) { BOOL bReturn; int iSize; WCHAR* pszBuf; if (!psl || !pszOutput || (cchMaxSize <= 0)) return FALSE; pszBuf = SLConvertToString(psl, pszSeparator, bAlsoDoFirst, bAlsoDoLast, &iSize); if (pszBuf) { if (cchMaxSize < iSize) iSize = cchMaxSize; CopyMemory(pszOutput, pszBuf, iSize*sizeof(WCHAR)); SLFreeReturn(pszBuf); bReturn = TRUE; } else { iSize = 1; bReturn = FALSE; } if (cchMaxSize > 1) ZeroMemory(&pszOutput[iSize-1], sizeof(WCHAR)); if (!pszSeparator && bAlsoDoLast && (cchMaxSize > 2)) ZeroMemory(&pszOutput[iSize], sizeof(WCHAR)); return bReturn; } BOOL SLMergeList(LPSTRINGLIST pslDest, LPSTRINGLIST pslFrom) { BOOL bReturn; int i; if (!pslDest || !pslFrom || (pslDest == pslFrom)) return FALSE; EnterCriticalSection(&pslFrom->csListAccess); // first list if (pslFrom->uCount == 0) { LeaveCriticalSection(&pslFrom->csListAccess); return TRUE; } EnterCriticalSection(&pslDest->csListAccess); // second list bReturn = FALSE; for (i=SL_MIN_POS; i<(int)(pslFrom->uCount); i++) if (SLAddItem(pslDest, pslFrom->papszList[i]) != SL_INVALID_POS) bReturn = TRUE; LeaveCriticalSection(&pslFrom->csListAccess); // first list LeaveCriticalSection(&pslDest->csListAccess); // second list return bReturn; } int SLFindItem(LPSTRINGLIST psl, const WCHAR* pszItem, BOOL bCaseSensitive, int iStartPos) { int i, iReturn; if (!psl || !pszItem) return SL_INVALID_POS; EnterCriticalSection(&psl->csListAccess); if (!SLIsValid(psl, iStartPos)) { LeaveCriticalSection(&psl->csListAccess); return SL_INVALID_POS; } iReturn = SL_INVALID_POS; for (i=iStartPos; i<(int)psl->uCount; i++) if ((bCaseSensitive?StrCmp(psl->papszList[i], pszItem):StrCmpI(psl->papszList[i], pszItem)) == 0) { iReturn = i; break; } LeaveCriticalSection(&psl->csListAccess); return iReturn; } BOOL SLIsItem(LPSTRINGLIST psl, const WCHAR* pszItem, BOOL bCaseSensitive) { return (SLFindItem(psl, pszItem, bCaseSensitive, SL_MIN_POS) != SL_INVALID_POS); } int SLAddItem(LPSTRINGLIST psl, const WCHAR* pszNewItem) { WCHAR** apszBuf; WCHAR* pszBuf; int i; if (!psl) return SL_INVALID_POS; EnterCriticalSection(&psl->csListAccess); if (((int)(psl->uCount+1) <= 0) || ((int)(psl->uCount+1) == psl->uCount)) { #if defined(_DEBUG) OutputDebugString(_T("Spam Filter: Stringlist overflow.\r\n")); DebugBreak(); #endif LeaveCriticalSection(&psl->csListAccess); return SL_INVALID_POS; } // Create/Resize the array if (!psl->papszList) { apszBuf = (WCHAR**)SLAlloc(sizeof(WCHAR*)); psl->uCount = 0; } else { apszBuf = (WCHAR**)SLReAlloc(psl->papszList, (psl->uCount+1)*sizeof(WCHAR*)); } if (apszBuf) { psl->papszList = apszBuf; } else { LeaveCriticalSection(&psl->csListAccess); return SL_INVALID_POS; } // Prepare new string memory pszBuf = (WCHAR*)SLAlloc(((pszNewItem?lstrlen(pszNewItem):0)+1)*sizeof(WCHAR)); if (!pszBuf) { LeaveCriticalSection(&psl->csListAccess); return SL_INVALID_POS; } // Prepare new string if (pszNewItem) CopyMemory(pszBuf, pszNewItem, (lstrlen(pszNewItem)+1)*sizeof(WCHAR)); else ZeroMemory(pszBuf, sizeof(WCHAR)); // Insert the new string i = psl->uCount; psl->papszList[i] = pszBuf; psl->uCount++; LeaveCriticalSection(&psl->csListAccess); return i; } int SLAddItemPair(LPSTRINGLIST psl, const WCHAR* pszNewItem1, const WCHAR* pszNewItem2) { int iPos; if (!psl) return SL_INVALID_POS; EnterCriticalSection(&psl->csListAccess); iPos = SLAddItem(psl, pszNewItem1); if (iPos != SL_INVALID_POS) if (SLAddItem(psl, pszNewItem2) == SL_INVALID_POS) SLDeleteItem(psl, iPos); LeaveCriticalSection(&psl->csListAccess); return iPos; } int SLPrepareItem(LPSTRINGLIST psl, int cchLength) { int iPos; if (!psl) return SL_INVALID_POS; EnterCriticalSection(&psl->csListAccess); iPos = SLAddItem(psl, NULL); // empty item if (iPos != SL_INVALID_POS) if (!SLSetItemLength(psl, iPos, cchLength)) { SLDeleteItem(psl, iPos); iPos = SL_INVALID_POS; } LeaveCriticalSection(&psl->csListAccess); return iPos; } /* BOOL SLAddItems(LPSTRINGLIST psl, const TCHAR* apszNewItems[], UINT uNewItemsCount) { int i; TCHAR** apszBuf; if (!psl || !apszNewItems || (uNewItemsCount <= 0)) return FALSE; EnterCriticalSection(&psl->csListAccess); // Create/Resize the array if (!psl->papszList) { apszBuf = (TCHAR**)SLAlloc(uNewItemCount*sizeof(TCHAR*)); psl->uCount = 0; // just to be sure } else { apszBuf = (TCHAR**)SLReAlloc(psl->papszList, (psl->uCount+uNewItemCount)*sizeof(TCHAR*)); } if (apszBuf) { psl->papszList = apszBuf; } else { LeaveCriticalSection(&psl->csListAccess); return FALSE; } // Insert the new string for (i=SL_MIN_POS; i<=iNewItemCount; i++) { psl->papszList[psl->uCount+i] = (TCHAR*)SLAlloc((lstrlen(apszNewItems[i])+1)*sizeof(TCHAR)); if (psl->papszList[psl->uCount+i]) { CopyMemory((PBYTE)psl->papszList[psl->uCount+i], apszNewItems[i], (lstrlen(apszNewItems[i])+1)*sizeof(TCHAR)); // Increase list count psl->uCount++; } else { LeaveCriticalSection(&psl->csListAccess); return FALSE; } } LeaveCriticalSection(&psl->csListAccess); return TRUE; } */ BOOL SLDeleteItems(LPSTRINGLIST psl, int iPosFirst, int iPosLast) { int i; WCHAR** apszBuf; if (!psl) return FALSE; if (iPosLast < iPosFirst) { i = iPosLast; iPosLast = iPosFirst; iPosFirst = i; } EnterCriticalSection(&psl->csListAccess); if (!SLIsValid(psl, iPosFirst) || !SLIsValid(psl, iPosLast)) { LeaveCriticalSection(&psl->csListAccess); return FALSE; } for (i=iPosFirst; i<=iPosLast; i++) SLFree(psl->papszList[i]); if ((iPosLast+1) < (int)uMsgTypesCount) MoveMemory(&pamtdMsgTypes[iPosFirst], &pamtdMsgTypes[iPosLast+1], (iPosLast-iPosFirst+1)*sizeof(WCHAR)); psl->uCount -= (iPosLast-iPosFirst+1); if (psl->papszList && (psl->uCount > 0)) { apszBuf = (WCHAR**)SLReAlloc(psl->papszList, psl->uCount*sizeof(WCHAR*)); if (apszBuf) psl->papszList = apszBuf; } else { if (psl->papszList) SLFree(psl->papszList); psl->papszList = NULL; psl->uCount = 0; } LeaveCriticalSection(&psl->csListAccess); return TRUE; } BOOL SLDeleteItem(LPSTRINGLIST psl, int iPos) { return SLDeleteItems(psl, iPos, iPos); } BOOL SLSetItemLength(LPSTRINGLIST psl, int iPos, int cchLength) { WCHAR* pszBuf; int iOldLen; BOOL bReturn; if (!psl) return FALSE; if (cchLength < 0) cchLength = 0; EnterCriticalSection(&psl->csListAccess); if (!SLIsValid(psl, iPos)) { LeaveCriticalSection(&psl->csListAccess); return FALSE; } iOldLen = lstrlen(psl->papszList[iPos]); pszBuf = (WCHAR*)SLReAlloc(psl->papszList[iPos], (cchLength+1)*sizeof(WCHAR)); if (pszBuf) { psl->papszList[iPos] = pszBuf; if (cchLength <= iOldLen) ZeroMemory(&pszBuf[cchLength], sizeof(WCHAR)); else ZeroMemory(&pszBuf[iOldLen], (cchLength-iOldLen+1)*sizeof(WCHAR)); bReturn = TRUE; } else { bReturn = FALSE; } LeaveCriticalSection(&psl->csListAccess); return bReturn; } BOOL SLChangeItem(LPSTRINGLIST psl, int iPos, WCHAR* pszNewStr, BOOL bDoAppend) { BOOL bReturn; WCHAR* pszBuf; if (!psl) return FALSE; EnterCriticalSection(&psl->csListAccess); if (!SLIsValid(psl, iPos)) { LeaveCriticalSection(&psl->csListAccess); return FALSE; } pszBuf = (WCHAR*)SLReAlloc(psl->papszList[iPos], ((pszNewStr?lstrlen(pszNewStr):0) + (bDoAppend?lstrlen(psl->papszList[iPos]):0) + 1)*sizeof(WCHAR)); if (pszBuf) { psl->papszList[iPos] = pszBuf; if (bDoAppend && pszNewStr) CopyMemory(&pszBuf[lstrlen(pszBuf)], pszNewStr, (lstrlen(pszNewStr)+1)*sizeof(WCHAR)); else if (pszNewStr) CopyMemory(pszBuf, pszNewStr, (lstrlen(pszNewStr)+1)*sizeof(WCHAR)); else if (!bDoAppend) ZeroMemory(psl->papszList[iPos], sizeof(WCHAR)); bReturn = TRUE; } else { if (!bDoAppend) ZeroMemory(psl->papszList[iPos], sizeof(WCHAR)); bReturn = FALSE; } LeaveCriticalSection(&psl->csListAccess); return bReturn; } BOOL SLItemPrintf(LPSTRINGLIST psl, int iPos, int cchArgMaxLen, ...) { BOOL bReturn = FALSE; WCHAR* pszBuf; WCHAR* pszFmt; va_list arglist; if (!psl) return FALSE; if (cchArgMaxLen < 0) cchArgMaxLen = 0; EnterCriticalSection(&psl->csListAccess); if (SLIsValid(psl, iPos)) { pszFmt = (WCHAR*)SLAlloc((lstrlen(psl->papszList[iPos])+1)*sizeof(WCHAR)); if (pszFmt) { CopyMemory(pszFmt, psl->papszList[iPos], (lstrlen(psl->papszList[iPos])+1)*sizeof(WCHAR)); pszBuf = (WCHAR*)SLReAlloc(psl->papszList[iPos], (lstrlen(psl->papszList[iPos])+cchArgMaxLen+1)*sizeof(WCHAR)); if (pszBuf) { psl->papszList[iPos] = pszBuf; va_start(arglist, cchArgMaxLen); mir_vsntprintf(pszBuf, lstrlen(pszBuf)+cchArgMaxLen+1, pszFmt, arglist); va_end(arglist); bReturn = TRUE; mir_free(pszFmt); } } } LeaveCriticalSection(&psl->csListAccess); return bReturn; } /* BOOL SLMoveItem(LPSTRINGLIST psl, int iOldPos, int iNewPos, BOOL bOnlySwitch) { TCHAR* pszBuf; if (!psl) return FALSE; EnterCriticalSection(&psl->csListAccess); if (!SLIsValid(psl, iOldPos) || !SLIsValid(psl, iNewPos)) { LeaveCriticalSection(&psl->csListAccess); return FALSE; } if (iNewPos == iOldPos) { LeaveCriticalSection(&psl->csListAccess); return TRUE; } if (bOnlySwitch) { // Switch the items pszBuf = psl->papszList[iOldPos]; psl->papszList[iOldPos] = psl->papszList[iNewPos]; psl->papszList[iOldPos] = pszBuf; } else { int i; // Cache the old item pszBuf = psl->papszList[iOldPos]; if (iNewPos > iOldPos) { // Move items in between one down for (i=iNewPos; ipapszList[i+1] = psl->papszList[i]; } else { // Move items in between one up for (i=(iOldPos+1); i<=iNewPos; i++) psl->papszList[i] = psl->papszList[i+1]; } psl->papszList[iNewPos] = pszBuf; } LeaveCriticalSection(&psl->csListAccess); return TRUE; } */ BOOL SLIsValid(LPSTRINGLIST psl, int iPos) { BOOL bReturn; if (!psl) return FALSE; EnterCriticalSection(&psl->csListAccess); bReturn = (psl->papszList && (iPos>=SL_MIN_POS) && (iPos<(int)psl->uCount)); LeaveCriticalSection(&psl->csListAccess); return bReturn; } WCHAR* SLGetItem(LPSTRINGLIST psl, int iPos) { WCHAR* pszReturn; EnterCriticalSection(&psl->csListAccess); // other operations finished pszReturn = SLIsValid(psl, iPos) ? psl->papszList[iPos] : NULL; LeaveCriticalSection(&psl->csListAccess); return pszReturn; } int SLGetMaxPos(LPSTRINGLIST psl) { int iReturn; if (!psl) return SL_INVALID_POS; EnterCriticalSection(&psl->csListAccess); // other operations finished iReturn = (psl->uCount > 0) ? (int)(psl->uCount-1) : SL_INVALID_POS; LeaveCriticalSection(&psl->csListAccess); return iReturn; } int SLGetItemCount(LPSTRINGLIST psl) { int iReturn; if (!psl) return 0; EnterCriticalSection(&psl->csListAccess); // other operations finished iReturn = (int)psl->uCount; LeaveCriticalSection(&psl->csListAccess); return iReturn; } int SLGetSize(LPSTRINGLIST psl, BOOL bAlsoTerminatingZeros) // character count size { int i, iReturn; if (!psl) return 0; EnterCriticalSection(&psl->csListAccess); iReturn = 0; for (i=SL_MIN_POS; i<(int)psl->uCount; i++) iReturn += lstrlen(psl->papszList[i]); if (bAlsoTerminatingZeros) iReturn += (int)psl->uCount; LeaveCriticalSection(&psl->csListAccess); return iReturn; } BOOL SLClearList(LPSTRINGLIST psl) { int i; if (!psl) return FALSE; EnterCriticalSection(&psl->csListAccess); // Free string memory for (i=SL_MIN_POS; i<(int)psl->uCount; i++) SLFree(psl->papszList[i]); // Free the array psl->uCount = 0; if (psl->papszList) SLFree(psl->papszList); psl->papszList = NULL; LeaveCriticalSection(&psl->csListAccess); return TRUE; } /* BOOL SLBlockList(LPSTRINGLIST psl) { if (!psl) return FALSE; EnterCriticalSection(&psl->csListAccess); return TRUE; } BOOL SLUnBlockList(LPSTRINGLIST psl) { if (!psl) return FALSE; LeaveCriticalSection(&psl->csListAccess); return TRUE; } */ LPSTRINGLIST SLNewList(void) { LPSTRINGLIST psl = (LPSTRINGLIST)SLAlloc(sizeof(STRINGLIST)); psl->papszList = NULL; psl->uCount = 0; InitializeCriticalSection(&psl->csListAccess); return psl; } void SLFreeList(LPSTRINGLIST psl) { if (!psl) return; SLClearList(psl); DeleteCriticalSection(&psl->csListAccess); SLFree(psl); }