/* "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" // ----------------------------------------- BOOL PPreparePathForWrite(HWND hwndDlg, const WCHAR* pszPath, BOOL bAskDirCreate, BOOL bContainsFileName) { // Using SHPathPrepareForWrite on Win2000+ (best, only if avail) { HRESULT (STDAPICALLTYPE *MySHPathPrepareForWrite)(HWND, IUnknown*, LPCTSTR, DWORD); #if defined(UNICODE) *(FARPROC*)&MySHPathPrepareForWrite = GetProcAddress(GetModuleHandle(_T("USER32")), "SHPathPrepareForWriteW"); #else *(FARPROC*)&MySHPathPrepareForWrite = GetProcAddress(GetModuleHandle(_T("USER32")), "SHPathPrepareForWriteA"); #endif if (MySHPathPrepareForWrite) { DWORD dwFlags = SHPPFW_NOWRITECHECK; // Not impl anyway if (bContainsFileName) dwFlags |= SHPPFW_IGNOREFILENAME; dwFlags |= bAskDirCreate ? SHPPFW_ASKDIRCREATE : SHPPFW_DIRCREATE; return SUCCEEDED(MySHPathPrepareForWrite(hwndDlg, NULL, (LPCTSTR)pszPath, dwFlags)); } } // Emulating SHPathPrepareForWrite: // Using SHCreateDirectoryEx on WinME // And: Using emulated version of SHCreateDirectoryEx on Win95/98 { WCHAR* pszDir; BOOL bReturn = FALSE; pszDir = mir_wstrdup(pszPath); if (!pszDir) return FALSE; if (bContainsFileName) PathRemoveFileSpec((LPWSTR)pszDir); // No dialog is emulated, instead always behave as // if "No" was clicked if (bAskDirCreate) return FALSE; // Create all sub directories { int (STDAPICALLTYPE *MySHCreateDirectoryEx)(HWND, LPCTSTR, SECURITY_ATTRIBUTES*); #if defined(UNICODE) *(FARPROC*)&MySHCreateDirectoryEx = (FARPROC)GetProcAddress(GetModuleHandle(_T("SHELL32")), "SHCreateDirectoryExW"); #else *(FARPROC*)&MySHCreateDirectoryEx = (FARPROC)GetProcAddress(GetModuleHandle(_T("SHELL32")), "SHCreateDirectoryExA"); #endif if (MySHCreateDirectoryEx) { int iRet = (SHCreateDirectoryEx(hwndDlg, pszDir, NULL) == ERROR_SUCCESS); bReturn = ((iRet == ERROR_SUCCESS) || (iRet == ERROR_ALREADY_EXISTS)); } else { int iSlashOcc; int iAbsSlashOcc; WCHAR* pszSlash; WCHAR szDirTemp[MAX_PATH]; WCHAR szDirOutput[MAX_PATH]; ZeroMemory(&szDirTemp, sizeof(szDirTemp)); ZeroMemory(&szDirOutput, sizeof(szDirOutput)); // Skip drive letter pszSlash = StrChr(pszDir, _T('\\')); // Search for the first :'\\' if (pszSlash != NULL) // does not contain any slashs { iSlashOcc = (int)(pszSlash-pszDir+1); // Pointer arithmetic StrCpyN(szDirTemp, pszDir+iSlashOcc, lstrlen(pszDir)-iSlashOcc); // Pointer arithmetic iAbsSlashOcc = iSlashOcc; bReturn = TRUE; pszSlash = szDirTemp; while (pszSlash) { pszSlash = StrChr(szDirTemp, _T('\\')); iSlashOcc = (int)(pszSlash-szDirTemp+1); // Pointer arithmetic iAbsSlashOcc = iAbsSlashOcc + iSlashOcc; StrCpyN(szDirOutput, pszPath, iAbsSlashOcc); // Pointer arithmetic StrCpyN(szDirTemp, szDirTemp+iSlashOcc, lstrlen(szDirTemp)-iSlashOcc); // Pointer arithmetic ZeroMemory((PBYTE)szDirTemp+((lstrlen(szDirTemp)-iSlashOcc)*sizeof(WCHAR)), iSlashOcc*sizeof(WCHAR)); bReturn = (CreateDirectory(szDirOutput, NULL) && bReturn); } } } } mir_free(pszDir); return bReturn; } } BOOL PIsValidFile(const WCHAR* pszFileName, const WCHAR* aszFileExtensions[], int nFileExtensions, const WCHAR* aszContentTypes[], int nContentTypes) { BOOL bIsOk = FALSE; int i; if (!pszFileName) return FALSE; // Check file extensions for (i=0; i=0; i--) if (PathGetCharType(pszPath[i])&GCT_WILD) RemoveSubStr(pszPath, i, 1); // Remove disallowed TCHARs for (i=lstrlen(pszPath); i>=0; i--) if (PathGetCharType(pszPath[i])&GCT_INVALID) RemoveSubStr(pszPath, i, 1); } */ PathRemoveBlanks(pszPath); PathUnquoteSpaces(pszPath); // Upper case drive TCHAR if (PathGetDriveNumber(pszPath) != -1) CharUpperBuff(pszPath, 1); // Make it use the long path name (Win98+/Win2000+) { DWORD (WINAPI *MyGetLongPathName)(LPCTSTR, LPCTSTR, DWORD); #if defined(UNICODE) *(FARPROC*)&MyGetLongPathName = GetProcAddress(GetModuleHandle(_T("KERNEL32")), "GetLongPathNameW"); #else *(FARPROC*)&MyGetLongPathName = GetProcAddress(GetModuleHandle(_T("KERNEL32")), "GetLongPathNameA"); #endif if (MyGetLongPathName) { if (MyGetLongPathName(pszPath, pszPath, MAX_PATH) == 0) { // Try to remove file name and see if it works then mir_sntprintf(szBuf, ARRAYSIZE(szBuf), _T("%s"), pszPath); if (PathRemoveFileSpec(szBuf) && (MyGetLongPathName(szBuf, szBuf, ARRAYSIZE(szBuf)) != 0)) { PathAppend(szBuf, PathFindFileName(pszPath)); mir_sntprintf(pszPath, MAX_PATH, _T("%s"), szBuf); } } } } // Lower case path if all upper case (only if user activated this feature for Windows-Explorer) { SHELLFLAGSTATE sfs; SHGetSettings(&sfs, SSF_DONTPRETTYPATH); if (!sfs.fDontPrettyPath) PathMakePretty(pszPath); } } // Make relative if (dwFlags&PC_ABSOLUTERELATIVE) { if (PathRelativePathTo(szBuf, szRelativeTo, FILE_ATTRIBUTE_DIRECTORY, pszPath, FILE_ATTRIBUTE_NORMAL)) { mir_sntprintf(pszPath, MAX_PATH, _T("%s"), szBuf); // Remove backslash in front -> does not belong there (causes by PathRelativePathTo) if ((pszPath[0] == _T('\\')) || (pszPath[0] == _T('/'))) MoveMemory(pszPath, CharNext(pszPath), (lstrlen(CharNext(pszPath))+1)*sizeof(WCHAR)); } // Miranda Utils contains a quite less featured implementation of relative paths // (not all cases are captured, does not support Unicode, too) //if (CallService(MS_UTILS_PATHTORELATIVE, (WPARAM)pszPath, (LPARAM)szBuf) == 0) // mir_sntprintf(pszPath, MAX_PATH, _T("%s"), szBuf); } // Environment strings if (dwFlags&PC_ENVIRONMENTSTRINGS) { BOOL (STDAPICALLTYPE *MyPathUnExpandEnvStrings)(LPCTSTR, LPTSTR, UINT); // PathUnExpandEnvStrings is Win98/2000+ #if defined(UNICODE) *(FARPROC*)&MyPathUnExpandEnvStrings = (FARPROC)GetProcAddress(GetModuleHandle(_T("SHLWAPI")), "PathUnExpandEnvStringsW"); #else *(FARPROC*)&MyPathUnExpandEnvStrings = (FARPROC)GetProcAddress(GetModuleHandle(_T("SHLWAPI")), "PathUnExpandEnvStringsA"); #endif if (MyPathUnExpandEnvStrings) if (MyPathUnExpandEnvStrings(pszPath, szBuf, MAX_PATH)) mir_sntprintf(pszPath, MAX_PATH, _T("%s"), szBuf); } } DWORD PMakePathUsable(WCHAR* pszPath) { WCHAR szBuf[MAX_PATH]; DWORD dwFlags = 0; if (!pszPath) return dwFlags; PathUnquoteSpaces(pszPath); // Environment strings { if (ExpandEnvironmentStrings(pszPath, szBuf, ARRAYSIZE(szBuf)) != 0) { // Success? if (StrCmp(pszPath, szBuf) != 0) dwFlags |= PC_ENVIRONMENTSTRINGS; mir_sntprintf(pszPath, MAX_PATH, _T("%s"), szBuf); } } // Absolute/relative path { WCHAR szRelativeTo[MAX_PATH]; PConstructLocalPath(szRelativeTo, CSIDL_EXT_EXECUTABLE, NULL, NULL, NULL); // Miranda Utils contains not a very good implementation of relative paths // (not all cases are captured) //(CallService(MS_UTILS_PATHTOABSOLUTE, (WPARAM)szBuf, (LPARAM)pszPath) != lstrlenA(szBuf)) // Create absolute path if path is relative if (PathIsRelative(pszPath)) { if (PathCombine(szBuf, szRelativeTo, pszPath)) { dwFlags |= PC_ABSOLUTERELATIVE; mir_sntprintf(pszPath, MAX_PATH, _T("%s"), szBuf); } } } return dwFlags; } BOOL PConstructLocalPath(WCHAR* pszReturn, int nMainFolder, const WCHAR* pszSubFolders, const WCHAR* pszFileName, const WCHAR* pszOptFileExtension) { // pszReturn muss MAX_PATH groß sein if (!pszReturn) return FALSE; pszReturn[0] = _T('\0'); switch (nMainFolder) { case CSIDL_EXT_MIRANDAPROFILE: { // Profile directory of Miranda's database WCHAR szBuf[MAX_PATH]; if (CallService(MS_DB_GETPROFILEPATH, (WPARAM)ARRAYSIZE(szBuf), (LPARAM)szBuf) != 0) return FALSE; #if defined(UNICODE) { WCHAR* pszBuf = (WCHAR*)mir_utf8encodeW(szBuf); if (!pszBuf) return FALSE; mir_sntprintf(pszReturn, MAX_PATH, _T("%s"), pszBuf); mir_free(pszBuf); } #else mir_sntprintf(pszReturn, MAX_PATH, _T("%s"), szBuf); #endif break; } case CSIDL_EXT_MODULE: { // Current DLL's directory if (GetModuleFileName(hInstance, pszReturn, MAX_PATH) == 0) return FALSE; PathRemoveFileSpec(pszReturn); break; } case CSIDL_EXT_EXECUTABLE: { // Current executable path if (GetModuleFileName(NULL, pszReturn, MAX_PATH) == 0) return FALSE; PathRemoveFileSpec(pszReturn); break; } case CSIDL_EXT_TEMP: { // Temp directory if (GetTempPath(MAX_PATH, pszReturn) == 0) return FALSE; break; } case CSIDL_EXT_CURRENT: { // Current directory if (GetCurrentDirectory(MAX_PATH, pszReturn) == 0) return FALSE; break; } default: { // CSIDL directory if (!SHGetSpecialFolderPath(NULL, pszReturn, nMainFolder, FALSE)) return FALSE; break; } } if (!PathAddBackslash(pszReturn)) return FALSE; if (pszSubFolders) { if (!PathAppend(pszReturn, pszSubFolders)) return FALSE; if (!PathAddBackslash(pszReturn)) return FALSE; } if (pszFileName) if (!PathAppend(pszReturn, pszFileName)) return FALSE; if (pszFileName && pszOptFileExtension) if (!PathAddExtension(pszReturn, pszOptFileExtension)) return FALSE; return TRUE; } // Move files or whole folder from module to destination directory BOOL PInstallFile(const WCHAR* pszFileName, const WCHAR* pszDestDir) { BOOL bReturn; WCHAR szFileFrom[MAX_PATH+1]; WCHAR szFileTo[MAX_PATH+1]; if (!pszFileName) return FALSE; PConstructLocalPath(szFileFrom, CSIDL_EXT_MODULE, NULL, pszFileName, NULL); if (!PathFileExists(szFileFrom)) return FALSE; mir_sntprintf(szFileTo, ARRAYSIZE(szFileTo), _T("%s"), pszDestDir); if (PathIsDirectory(szFileFrom)) { SHFILEOPSTRUCT sfo; ZeroMemory(&sfo, sizeof(sfo)); sfo.fFlags = FOF_MULTIDESTFILES|FOF_NOERRORUI|FOF_NOCONFIRMATION|FOF_NOCONFIRMMKDIR|FOF_SILENT; sfo.wFunc = FO_MOVE; szFileFrom[lstrlen(szFileFrom)+1] = _T('\0'); sfo.pFrom = szFileFrom; szFileTo[lstrlen(szFileTo)+1] = _T('\0'); sfo.pTo = szFileTo; bReturn = (SHFileOperation(&sfo) == 0); } else { PathAppend(szFileTo, pszFileName); DeleteFile(szFileTo); bReturn = MoveFile(szFileFrom, szFileTo); // MoveFile does only support directories limitedly } return bReturn; } BOOL PInstallDLLFile(const WCHAR* pszFileName, BOOL bIgnoreLanguage, BOOL bIgnoreOpSystem) { DWORD dwErr; WCHAR szSrcDir[MAX_PATH]; WCHAR szDestDir[MAX_PATH]; WCHAR szTmpFile[MAX_PATH]; UINT uTmpFileSize = ARRAYSIZE(szTmpFile); if (!pszFileName) return FALSE; // Test if file-to-be-installed exists PConstructLocalPath(szSrcDir, CSIDL_EXT_MODULE, NULL, pszFileName, NULL); if (!PathFileExists(szSrcDir)) return FALSE; // Source: module dir (Plugins directory) PConstructLocalPath(szSrcDir, CSIDL_EXT_MODULE, NULL, NULL, NULL); // Destination: app dir PConstructLocalPath(szDestDir, CSIDL_EXT_EXECUTABLE, NULL, NULL, NULL); // Install DLL using version verfication szTmpFile[0] = _T('\0'); // needs to be empty (docs) dwErr = VerInstallFile(0, (WCHAR*)pszFileName, (WCHAR*)pszFileName, szSrcDir, szDestDir, szDestDir, szTmpFile, &uTmpFileSize); if (!(dwErr&VIF_WRITEPROT) && !(dwErr&VIF_SRCOLD)) { // Ignore language/codepage of the DLL (install anyway) -> useful for DLLs without user interface if (bIgnoreLanguage) if ((dwErr&VIF_DIFFLANG) && (dwErr&VIF_DIFFCODEPG)) dwErr = VerInstallFile(VIFF_FORCEINSTALL, (WCHAR*)pszFileName, (WCHAR*)pszFileName, szSrcDir, szDestDir, szDestDir, szTmpFile, &uTmpFileSize); // Ignore operating system of the DLL (install anyway) -> useful for DLLs that work anyway if (bIgnoreOpSystem) if (dwErr&VIF_DIFFTYPE) dwErr = VerInstallFile(VIFF_FORCEINSTALL, (WCHAR*)pszFileName, (WCHAR*)pszFileName, szSrcDir, szDestDir, szDestDir, szTmpFile, &uTmpFileSize); } // Delete temp file if ((dwErr&VIF_TEMPFILE) && !(dwErr&VIF_BUFFTOOSMALL)) // buffer too small for temp file DeleteFile(szTmpFile); // Test for success PConstructLocalPath(szDestDir, CSIDL_EXT_EXECUTABLE, NULL, pszFileName, NULL); if (PathFileExists(szDestDir)) { PConstructLocalPath(szSrcDir, CSIDL_EXT_MODULE, NULL, pszFileName, NULL); DeleteFile(szSrcDir); return TRUE; } // Debug output OutputDebugString(_T("Spam Filter: VersionInfo DLL (VERSION.DLL) could not be used to install DLL file.\r\n")); // Source: module dir (Plugins directory) PConstructLocalPath(szSrcDir, CSIDL_EXT_MODULE, NULL, pszFileName, NULL); // Destination: app dir PConstructLocalPath(szDestDir, CSIDL_EXT_EXECUTABLE, NULL, pszFileName, NULL); // Copy without version checking [danger!] DeleteFile(szDestDir); return MoveFile(szSrcDir, szDestDir); }