From 7fd9fe181150f166a098eaf4e006f878c28cb770 Mon Sep 17 00:00:00 2001 From: Gluzskiy Alexandr Date: Mon, 15 Feb 2010 05:51:01 +0300 Subject: sort --- path.c | 541 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 541 insertions(+) create mode 100644 path.c (limited to 'path.c') diff --git a/path.c b/path.c new file mode 100644 index 0000000..b829c68 --- /dev/null +++ b/path.c @@ -0,0 +1,541 @@ +/* + +"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); +} \ No newline at end of file -- cgit v1.2.3