/* Miranda IM: the free IM client for Microsoft* Windows* Copyright 2000-12 Miranda IM, 2012-13 Miranda NG project, all portions of this codebase are copyrighted to the people listed in contributors.txt. 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 "..\..\core\commonheaders.h" #include "profilemanager.h" static bool bModuleInitialized = false; static HANDLE hIniChangeNotification; extern TCHAR mirandabootini[MAX_PATH]; static INT_PTR CALLBACK InstallIniDlgProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam) { switch(message) { case WM_INITDIALOG: TranslateDialogDefault(hwndDlg); SetDlgItemText(hwndDlg, IDC_ININAME, (TCHAR*)lParam); { TCHAR szSecurity[11]; const TCHAR *pszSecurityInfo; GetPrivateProfileString(_T("AutoExec"), _T("Warn"), _T("notsafe"), szSecurity, SIZEOF(szSecurity), mirandabootini); if ( !lstrcmpi(szSecurity, _T("all"))) pszSecurityInfo = LPGENT("Security systems to prevent malicious changes are in place and you will be warned before every change that is made."); else if ( !lstrcmpi(szSecurity, _T("onlyunsafe"))) pszSecurityInfo = LPGENT("Security systems to prevent malicious changes are in place and you will be warned before changes that are known to be unsafe."); else if ( !lstrcmpi(szSecurity, _T("none"))) pszSecurityInfo = LPGENT("Security systems to prevent malicious changes have been disabled. You will receive no further warnings."); else pszSecurityInfo = NULL; if (pszSecurityInfo) SetDlgItemText(hwndDlg, IDC_SECURITYINFO, TranslateTS(pszSecurityInfo)); } return TRUE; case WM_COMMAND: switch(LOWORD(wParam)) { case IDC_VIEWINI: { TCHAR szPath[MAX_PATH]; GetDlgItemText(hwndDlg, IDC_ININAME, szPath, SIZEOF(szPath)); ShellExecute(hwndDlg, _T("open"), szPath, NULL, NULL, SW_SHOW); break; } case IDOK: case IDCANCEL: case IDC_NOTOALL: EndDialog(hwndDlg, LOWORD(wParam)); break; } break; } return FALSE; } static bool IsInSpaceSeparatedList(const char *szWord, const char *szList) { const char *szItem, *szEnd; int wordLen = lstrlenA(szWord); for (szItem = szList;;) { szEnd = strchr(szItem, ' '); if (szEnd == NULL) return !lstrcmpA(szItem, szWord); if (szEnd - szItem == wordLen) { if ( !strncmp(szItem, szWord, wordLen)) return true; } szItem = szEnd+1; } } struct warnSettingChangeInfo_t { TCHAR *szIniPath; char *szSection; char *szSafeSections; char *szUnsafeSections; char *szName; char *szValue; int warnNoMore, cancel; }; static INT_PTR CALLBACK WarnIniChangeDlgProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam) { static struct warnSettingChangeInfo_t *warnInfo; switch(message) { case WM_INITDIALOG: { char szSettingName[256]; const TCHAR *pszSecurityInfo; warnInfo = (warnSettingChangeInfo_t*)lParam; TranslateDialogDefault(hwndDlg); SetDlgItemText(hwndDlg, IDC_ININAME, warnInfo->szIniPath); lstrcpyA(szSettingName, warnInfo->szSection); lstrcatA(szSettingName, " / "); lstrcatA(szSettingName, warnInfo->szName); SetDlgItemTextA(hwndDlg, IDC_SETTINGNAME, szSettingName); SetDlgItemTextA(hwndDlg, IDC_NEWVALUE, warnInfo->szValue); if (IsInSpaceSeparatedList(warnInfo->szSection, warnInfo->szSafeSections)) pszSecurityInfo = LPGENT("This change is known to be safe."); else if (IsInSpaceSeparatedList(warnInfo->szSection, warnInfo->szUnsafeSections)) pszSecurityInfo = LPGENT("This change is known to be potentially hazardous."); else pszSecurityInfo = LPGENT("This change is not known to be safe."); SetDlgItemText(hwndDlg, IDC_SECURITYINFO, TranslateTS(pszSecurityInfo)); return TRUE; } case WM_COMMAND: switch(LOWORD(wParam)) { case IDCANCEL: warnInfo->cancel = 1; case IDYES: case IDNO: warnInfo->warnNoMore = IsDlgButtonChecked(hwndDlg, IDC_WARNNOMORE); EndDialog(hwndDlg, LOWORD(wParam)); break; } break; } return FALSE; } static INT_PTR CALLBACK IniImportDoneDlgProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam) { switch(message) { case WM_INITDIALOG: TranslateDialogDefault(hwndDlg); SetDlgItemText(hwndDlg, IDC_ININAME, (TCHAR*)lParam); SetDlgItemText(hwndDlg, IDC_NEWNAME, (TCHAR*)lParam); return TRUE; case WM_COMMAND: { TCHAR szIniPath[MAX_PATH]; GetDlgItemText(hwndDlg, IDC_ININAME, szIniPath, SIZEOF(szIniPath)); switch(LOWORD(wParam)) { case IDC_DELETE: DeleteFile(szIniPath); case IDC_LEAVE: EndDialog(hwndDlg, LOWORD(wParam)); break; case IDC_RECYCLE: { SHFILEOPSTRUCT shfo = {0}; shfo.wFunc = FO_DELETE; shfo.pFrom = szIniPath; szIniPath[lstrlen(szIniPath)+1] = '\0'; shfo.fFlags = FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT | FOF_ALLOWUNDO; SHFileOperation(&shfo); } EndDialog(hwndDlg, LOWORD(wParam)); break; case IDC_MOVE: { TCHAR szNewPath[MAX_PATH]; GetDlgItemText(hwndDlg, IDC_NEWNAME, szNewPath, SIZEOF(szNewPath)); MoveFile(szIniPath, szNewPath); } EndDialog(hwndDlg, LOWORD(wParam)); break; } break; } } return FALSE; } // settings: struct SettingsList { char *name; SettingsList *next; } *setting_items = NULL; int SettingsEnumProc(const char *szSetting, LPARAM lParam) { SettingsList *newItem = (SettingsList *)mir_alloc(sizeof(SettingsList)); newItem->name = mir_strdup(szSetting); newItem->next = setting_items; setting_items = newItem; return 0; } static void ConvertBackslashes(char *str, UINT fileCp) { char *pstr; for (pstr = str; *pstr; pstr = CharNextExA(fileCp, pstr, 0)) { if (*pstr == '\\') { switch(pstr[1]) { case 'n': *pstr = '\n'; break; case 't': *pstr = '\t'; break; case 'r': *pstr = '\r'; break; default: *pstr = pstr[1]; break; } memmove(pstr+1, pstr+2, strlen(pstr+2) + 1); } } } static void ProcessIniFile(TCHAR* szIniPath, char *szSafeSections, char *szUnsafeSections, int secur, bool secFN) { FILE *fp = _tfopen(szIniPath, _T("rt")); if (fp == NULL) return; bool warnThisSection = false; char szSection[128]; szSection[0] = 0; while ( !feof(fp)) { char szLine[2048]; if (fgets(szLine, sizeof(szLine), fp) == NULL) break; int lineLength = lstrlenA(szLine); while (lineLength && (BYTE)(szLine[lineLength-1]) <= ' ') szLine[--lineLength] = '\0'; if (szLine[0] == ';' || szLine[0] <= ' ') continue; if (szLine[0] == '[') { char *szEnd = strchr(szLine+1, ']'); if (szEnd == NULL) continue; if (szLine[1] == '!') szSection[0] = '\0'; else { lstrcpynA(szSection, szLine+1, min(sizeof(szSection), (int)(szEnd-szLine))); switch (secur) { case 0: warnThisSection = false; break; case 1: warnThisSection = !IsInSpaceSeparatedList(szSection, szSafeSections); break; case 2: warnThisSection = IsInSpaceSeparatedList(szSection, szUnsafeSections); break; default: warnThisSection = true; break; } if (secFN) warnThisSection = 0; } if (szLine[1] == '?') { DBCONTACTENUMSETTINGS dbces; dbces.pfnEnumProc = SettingsEnumProc; lstrcpynA(szSection, szLine+2, min(sizeof(szSection), (int)(szEnd-szLine-1))); dbces.szModule = szSection; dbces.ofsSettings = 0; CallService(MS_DB_CONTACT_ENUMSETTINGS, 0, (LPARAM)&dbces); while (setting_items) { SettingsList *next = setting_items->next; db_unset(NULL, szSection, setting_items->name); mir_free(setting_items->name); mir_free(setting_items); setting_items = next; } } continue; } if (szSection[0] == '\0') continue; char *szValue = strchr(szLine, '='); if (szValue == NULL) continue; char szName[128]; lstrcpynA(szName, szLine, min(sizeof(szName), (int)(szValue-szLine+1))); szValue++; { warnSettingChangeInfo_t warnInfo; warnInfo.szIniPath = szIniPath; warnInfo.szName = szName; warnInfo.szSafeSections = szSafeSections; warnInfo.szSection = szSection; warnInfo.szUnsafeSections = szUnsafeSections; warnInfo.szValue = szValue; warnInfo.warnNoMore = 0; warnInfo.cancel = 0; if (warnThisSection && IDNO == DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_WARNINICHANGE), NULL, WarnIniChangeDlgProc, (LPARAM)&warnInfo)) continue; if (warnInfo.cancel) break; if (warnInfo.warnNoMore) warnThisSection = 0; } switch(szValue[0]) { case 'b': case 'B': db_set_b(NULL, szSection, szName, (BYTE)strtol(szValue+1, NULL, 0)); break; case 'w': case 'W': db_set_w(NULL, szSection, szName, (WORD)strtol(szValue+1, NULL, 0)); break; case 'd': case 'D': db_set_dw(NULL, szSection, szName, (DWORD)strtoul(szValue+1, NULL, 0)); break; case 'l': case 'L': case '-': db_unset(NULL, szSection, szName); break; case 'e': case 'E': ConvertBackslashes(szValue+1, Langpack_GetDefaultCodePage()); case 's': case 'S': db_set_s(NULL, szSection, szName, szValue+1); break; case 'g': case 'G': { char *pstr; for (pstr = szValue+1;*pstr;pstr++) { if (*pstr == '\\') { switch(pstr[1]) { case 'n': *pstr = '\n'; break; case 't': *pstr = '\t'; break; case 'r': *pstr = '\r'; break; default: *pstr = pstr[1]; break; } MoveMemory(pstr+1, pstr+2, lstrlenA(pstr+2)+1); } } } case 'u': case 'U': db_set_utf(NULL, szSection, szName, szValue+1); break; case 'n': case 'h': case 'N': case 'H': { int len; char *pszValue, *pszEnd; PBYTE buf = (PBYTE)mir_alloc(lstrlenA(szValue+1)); for (len = 0, pszValue = szValue+1;;len++) { buf[len] = (BYTE)strtol(pszValue, &pszEnd, 0x10); if (pszValue == pszEnd) break; pszValue = pszEnd; } db_set_blob(NULL, szSection, szName, buf, len); mir_free(buf); } break; default: TCHAR buf[ 250 ]; mir_sntprintf(buf, SIZEOF(buf), TranslateT("Invalid setting type for '%s'. The first character of every value must be b, w, d, l, s, e, u, g, h or n."), _A2T(szName)); MessageBox(NULL, buf, TranslateT("Install Database Settings"), MB_ICONWARNING | MB_OK); break; } } fclose(fp); } static void DoAutoExec(void) { TCHAR szUse[7], szIniPath[MAX_PATH], szFindPath[MAX_PATH]; TCHAR buf[2048], szSecurity[11], szOverrideSecurityFilename[MAX_PATH], szOnCreateFilename[MAX_PATH]; char *szSafeSections, *szUnsafeSections; int secur; GetPrivateProfileString(_T("AutoExec"), _T("Use"), _T("prompt"), szUse, SIZEOF(szUse), mirandabootini); if ( !lstrcmpi(szUse, _T("no"))) return; GetPrivateProfileString(_T("AutoExec"), _T("Safe"), _T("CLC Icons CLUI CList SkinSounds"), buf, SIZEOF(buf), mirandabootini); szSafeSections = mir_t2a(buf); GetPrivateProfileString(_T("AutoExec"), _T("Unsafe"), _T("ICQ MSN"), buf, SIZEOF(buf), mirandabootini); szUnsafeSections = mir_t2a(buf); GetPrivateProfileString(_T("AutoExec"), _T("Warn"), _T("notsafe"), szSecurity, SIZEOF(szSecurity), mirandabootini); if ( !lstrcmpi(szSecurity, _T("none"))) secur = 0; else if ( !lstrcmpi(szSecurity, _T("notsafe"))) secur = 1; else if ( !lstrcmpi(szSecurity, _T("onlyunsafe"))) secur = 2; GetPrivateProfileString(_T("AutoExec"), _T("OverrideSecurityFilename"), _T(""), szOverrideSecurityFilename, SIZEOF(szOverrideSecurityFilename), mirandabootini); GetPrivateProfileString(_T("AutoExec"), _T("OnCreateFilename"), _T(""), szOnCreateFilename, SIZEOF(szOnCreateFilename), mirandabootini); GetPrivateProfileString(_T("AutoExec"), _T("Glob"), _T("autoexec_*.ini"), szFindPath, SIZEOF(szFindPath), mirandabootini); if (g_bDbCreated && szOnCreateFilename[0]) { PathToAbsoluteT( VARST(szOnCreateFilename), szIniPath); ProcessIniFile(szIniPath, szSafeSections, szUnsafeSections, 0, 1); } PathToAbsoluteT( VARST(szFindPath), szFindPath); WIN32_FIND_DATA fd; HANDLE hFind = FindFirstFile(szFindPath, &fd); if (hFind == INVALID_HANDLE_VALUE) { mir_free(szSafeSections); mir_free(szUnsafeSections); return; } TCHAR *str2 = _tcsrchr(szFindPath, '\\'); if (str2 == NULL) szFindPath[0] = 0; else str2[1] = 0; do { bool secFN = lstrcmpi(fd.cFileName, szOverrideSecurityFilename) == 0; mir_sntprintf(szIniPath, SIZEOF(szIniPath), _T("%s%s"), szFindPath, fd.cFileName); if ( !lstrcmpi(szUse, _T("prompt")) && !secFN) { int result = DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_INSTALLINI), NULL, InstallIniDlgProc, (LPARAM)szIniPath); if (result == IDC_NOTOALL) break; if (result == IDCANCEL) continue; } ProcessIniFile(szIniPath, szSafeSections, szUnsafeSections, secur, secFN); if (secFN) DeleteFile(szIniPath); else { TCHAR szOnCompletion[8]; GetPrivateProfileString(_T("AutoExec"), _T("OnCompletion"), _T("recycle"), szOnCompletion, SIZEOF(szOnCompletion), mirandabootini); if ( !lstrcmpi(szOnCompletion, _T("delete"))) DeleteFile(szIniPath); else if ( !lstrcmpi(szOnCompletion, _T("recycle"))) { SHFILEOPSTRUCT shfo = {0}; shfo.wFunc = FO_DELETE; shfo.pFrom = szIniPath; szIniPath[lstrlen(szIniPath)+1] = 0; shfo.fFlags = FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT | FOF_ALLOWUNDO; SHFileOperation(&shfo); } else if ( !lstrcmpi(szOnCompletion, _T("rename"))) { TCHAR szRenamePrefix[MAX_PATH]; TCHAR szNewPath[MAX_PATH]; GetPrivateProfileString(_T("AutoExec"), _T("RenamePrefix"), _T("done_"), szRenamePrefix, SIZEOF(szRenamePrefix), mirandabootini); lstrcpy(szNewPath, szFindPath); lstrcat(szNewPath, szRenamePrefix); lstrcat(szNewPath, fd.cFileName); MoveFile(szIniPath, szNewPath); } else if ( !lstrcmpi(szOnCompletion, _T("ask"))) DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_INIIMPORTDONE), NULL, IniImportDoneDlgProc, (LPARAM)szIniPath); } } while (FindNextFile(hFind, &fd)); FindClose(hFind); mir_free(szSafeSections); mir_free(szUnsafeSections); } static INT_PTR CheckIniImportNow(WPARAM, LPARAM) { DoAutoExec(); FindNextChangeNotification(hIniChangeNotification); return 0; } int InitIni(void) { bModuleInitialized = true; DoAutoExec(); TCHAR szMirandaDir[MAX_PATH]; PathToAbsoluteT(_T("."), szMirandaDir); hIniChangeNotification = FindFirstChangeNotification(szMirandaDir, 0, FILE_NOTIFY_CHANGE_FILE_NAME); if (hIniChangeNotification != INVALID_HANDLE_VALUE) { CreateServiceFunction("DB/Ini/CheckImportNow", CheckIniImportNow); CallService(MS_SYSTEM_WAITONHANDLE, (WPARAM)hIniChangeNotification, (LPARAM)"DB/Ini/CheckImportNow"); } return 0; } void UninitIni(void) { if ( !bModuleInitialized) return; CallService(MS_SYSTEM_REMOVEWAIT, (WPARAM)hIniChangeNotification, 0); FindCloseChangeNotification(hIniChangeNotification); }