From 48540940b6c28bb4378abfeb500ec45a625b37b6 Mon Sep 17 00:00:00 2001 From: Vadim Dashevskiy Date: Tue, 15 May 2012 10:38:20 +0000 Subject: initial commit git-svn-id: http://svn.miranda-ng.org/main/trunk@2 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- src/modules/database/database.cpp | 563 +++++++++++++++++++++ src/modules/database/dbini.cpp | 490 ++++++++++++++++++ src/modules/database/dblists.cpp | 282 +++++++++++ src/modules/database/dblists.h | 39 ++ src/modules/database/dbutils.cpp | 365 ++++++++++++++ src/modules/database/profilemanager.cpp | 850 ++++++++++++++++++++++++++++++++ src/modules/database/profilemanager.h | 43 ++ 7 files changed, 2632 insertions(+) create mode 100644 src/modules/database/database.cpp create mode 100644 src/modules/database/dbini.cpp create mode 100644 src/modules/database/dblists.cpp create mode 100644 src/modules/database/dblists.h create mode 100644 src/modules/database/dbutils.cpp create mode 100644 src/modules/database/profilemanager.cpp create mode 100644 src/modules/database/profilemanager.h (limited to 'src/modules/database') diff --git a/src/modules/database/database.cpp b/src/modules/database/database.cpp new file mode 100644 index 0000000000..9c9aab8146 --- /dev/null +++ b/src/modules/database/database.cpp @@ -0,0 +1,563 @@ +/* + +Miranda IM: the free IM client for Microsoft* Windows* + +Copyright 2000-2010 Miranda ICQ/IM 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 "commonheaders.h" +#include "profilemanager.h" +#include "../srfile/file.h" + +// from the plugin loader, hate extern but the db frontend is pretty much tied +extern PLUGINLINK pluginCoreLink; +// contains the location of mirandaboot.ini +extern TCHAR mirandabootini[MAX_PATH]; +bool dbCreated; +TCHAR g_profileDir[MAX_PATH], g_profileName[MAX_PATH]; + +bool fileExist(TCHAR* fname) +{ + if (fname[0] == 0) return false; + + FILE* fp = _tfopen(fname, _T("r+")); + bool res = fp != NULL; + if (res) fclose(fp); + return res; +} + +static void fillProfileName( const TCHAR* ptszFileName ) +{ + const TCHAR* p = _tcsrchr( ptszFileName, '\\' ); + if ( p == NULL ) + p = ptszFileName; + else + p++; + + _tcsncpy( g_profileName, p, SIZEOF(g_profileName)); +} + +bool IsInsideRootDir(TCHAR* profiledir, bool exact) +{ + int res; + TCHAR* pfd = Utils_ReplaceVarsT(_T("%miranda_path%")); + if (exact) + res = _tcsicmp(profiledir, pfd); + else + { + size_t len = _tcslen(pfd); + res = _tcsnicmp(profiledir, pfd, len); + } + mir_free(pfd); + return res == 0; +} + +// returns 1 if the profile path was returned, without trailing slash +int getProfilePath(TCHAR * buf, size_t cch) +{ + TCHAR profiledir[MAX_PATH]; + GetPrivateProfileString(_T("Database"), _T("ProfileDir"), _T(""), profiledir, SIZEOF(profiledir), mirandabootini); + + if (profiledir[0] == 0) + _tcscpy(profiledir, _T("%miranda_path%\\Profiles")); + + TCHAR* exprofiledir = Utils_ReplaceVarsT(profiledir); + size_t len = pathToAbsoluteT(exprofiledir, buf, NULL); + mir_free(exprofiledir); + + if (buf[len-1] == '/' || buf[len-1] == '\\') + buf[len-1] = 0; + + return 0; +} + +// returns 1 if *.dat spec is matched +int isValidProfileName(const TCHAR *name) +{ + size_t len = _tcslen(name) - 4; + return len > 0 && _tcsicmp(&name[len], _T(".dat")) == 0; +} + +// returns 1 if the profile manager should be shown +static bool showProfileManager(void) +{ + TCHAR Mgr[32]; + // is control pressed? + if (GetAsyncKeyState(VK_CONTROL)&0x8000) + return 1; + + // wanna show it? + GetPrivateProfileString(_T("Database"), _T("ShowProfileMgr"), _T("never"), Mgr, SIZEOF(Mgr), mirandabootini); + return ( _tcsicmp(Mgr, _T("yes")) == 0 ); +} + +bool shouldAutoCreate(TCHAR *szProfile) +{ + if (szProfile[0] == 0) + return false; + + TCHAR ac[32]; + GetPrivateProfileString(_T("Database"), _T("AutoCreate"), _T(""), ac, SIZEOF(ac), mirandabootini); + return _tcsicmp(ac, _T("yes")) == 0; +} + +static void getDefaultProfile(TCHAR * szProfile, size_t cch, TCHAR * profiledir) +{ + TCHAR defaultProfile[MAX_PATH]; + GetPrivateProfileString(_T("Database"), _T("DefaultProfile"), _T(""), defaultProfile, SIZEOF(defaultProfile), mirandabootini); + + if (defaultProfile[0] == 0) + return; + + TCHAR* res = Utils_ReplaceVarsT(defaultProfile); + if (res) { + mir_sntprintf(szProfile, cch, _T("%s\\%s\\%s%s"), profiledir, res, res, isValidProfileName(res) ? _T("") : _T(".dat")); + mir_free(res); + } + else szProfile[0] = 0; +} + +// returns 1 if something that looks like a profile is there +static int getProfileCmdLineArgs(TCHAR * szProfile, size_t cch) +{ + TCHAR *szCmdLine = GetCommandLine(); + TCHAR *szEndOfParam; + TCHAR szThisParam[1024]; + int firstParam=1; + + while(szCmdLine[0]) + { + if(szCmdLine[0]=='"') + { + szEndOfParam = _tcschr(szCmdLine+1, '"'); + if(szEndOfParam == NULL) break; + lstrcpyn(szThisParam, szCmdLine+1, min(SIZEOF(szThisParam), szEndOfParam - szCmdLine)); + szCmdLine = szEndOfParam + 1; + } + else + { + szEndOfParam = szCmdLine + _tcscspn(szCmdLine, _T(" \t")); + lstrcpyn(szThisParam, szCmdLine, min(SIZEOF(szThisParam), szEndOfParam - szCmdLine+1)); + szCmdLine = szEndOfParam; + } + while(*szCmdLine && *szCmdLine<=' ') szCmdLine++; + if (firstParam) { firstParam=0; continue; } //first param is executable name + if (szThisParam[0] == '/' || szThisParam[0] == '-') continue; //no switches supported + + TCHAR* res = Utils_ReplaceVarsT(szThisParam); + if (res == NULL) return 0; + _tcsncpy(szProfile, res, cch); szProfile[cch-1] = 0; + mir_free(res); + return 1; + } + return 0; +} + +void getProfileCmdLine(TCHAR * szProfile, size_t cch, TCHAR * profiledir) +{ + TCHAR buf[MAX_PATH]; + if (getProfileCmdLineArgs(buf, SIZEOF(buf))) + { + TCHAR *p, profileName[MAX_PATH], newProfileDir[MAX_PATH]; + + p = _tcsrchr(buf, '\\'); if (p) ++p; else p = buf; + + if (!isValidProfileName(buf) && *p) + _tcscat(buf, _T(".dat")); + + _tcscpy(profileName, p); + p = _tcsrchr(profileName, '.'); if (p) *p = 0; + + mir_sntprintf(newProfileDir, cch, _T("%s\\%s\\"), profiledir, profileName); + pathToAbsoluteT(buf, szProfile, newProfileDir); + + if (_tcschr(buf, '\\')) + { + _tcscpy(profiledir, szProfile); + if (profileName[0]) + { + p = _tcsrchr(profiledir, '\\'); *p = 0; + p = _tcsrchr(profiledir, '\\'); + if (p && _tcsicmp(p + 1, profileName) == 0) + *p = 0; + } + else + szProfile[0] = 0; + + } + } +} + +// move profile from profile subdir +static void moveProfileDirProfiles(TCHAR * profiledir, BOOL isRootDir = TRUE) +{ + TCHAR pfd[MAX_PATH]; + if (isRootDir) { + TCHAR *path = Utils_ReplaceVarsT(_T("%miranda_path%\\*.dat")); + mir_sntprintf(pfd, SIZEOF(pfd), _T("%s"), path); + mir_free(path); + } + else + mir_sntprintf(pfd, SIZEOF(pfd), _T("%s\\*.dat"), profiledir); + + WIN32_FIND_DATA ffd; + HANDLE hFind = FindFirstFile(pfd, &ffd); + if (hFind != INVALID_HANDLE_VALUE) + { + TCHAR *c =_tcsrchr(pfd, '\\'); if (c) *c = 0; + do + { + TCHAR path[MAX_PATH], path2[MAX_PATH]; + TCHAR* profile = mir_tstrdup(ffd.cFileName); + TCHAR *c =_tcsrchr(profile, '.'); if (c) *c = 0; + mir_sntprintf(path, SIZEOF(path), _T("%s\\%s"), pfd, ffd.cFileName); + mir_sntprintf(path2, SIZEOF(path2), _T("%s\\%s"), profiledir, profile); + CreateDirectoryTreeT(path2); + mir_sntprintf(path2, SIZEOF(path2), _T("%s\\%s\\%s"), profiledir, profile, ffd.cFileName); + if (_taccess(path2, 0) == 0) + { + const TCHAR tszMoveMsg[] = + _T("Miranda is trying upgrade your profile structure.\n") + _T("It cannot move profile %s to the new location %s\n") + _T("Because profile with this name already exist. Please resolve the issue manually."); + TCHAR buf[512]; + + mir_sntprintf(buf, SIZEOF(buf), TranslateTS(tszMoveMsg), path, path2); + MessageBox(NULL, buf, _T("Miranda IM"), MB_ICONERROR | MB_OK); + } + else if (MoveFile(path, path2) == 0) + { + const TCHAR tszMoveMsg[] = + _T("Miranda is trying upgrade your profile structure.\n") + _T("It cannot move profile %s to the new location %s automatically\n") + _T("Most likely due to insufficient privileges. Please move profile manually."); + TCHAR buf[512]; + + mir_sntprintf(buf, SIZEOF(buf), TranslateTS(tszMoveMsg), path, path2); + MessageBox(NULL, buf, _T("Miranda IM"), MB_ICONERROR | MB_OK); + break; + } + mir_free(profile); + } + while(FindNextFile(hFind, &ffd)); + } + FindClose(hFind); +} + +// returns 1 if a single profile (full path) is found within the profile dir +static int getProfile1(TCHAR * szProfile, size_t cch, TCHAR * profiledir, BOOL * noProfiles) +{ + unsigned int found = 0; + + if (IsInsideRootDir(profiledir, false)) + moveProfileDirProfiles(profiledir); + moveProfileDirProfiles(profiledir, FALSE); + + bool nodprof = szProfile[0] == 0; + bool reqfd = !nodprof && (_taccess(szProfile, 0) == 0 || shouldAutoCreate(szProfile)); + bool shpm = showProfileManager(); + + if (reqfd) + found++; + + if (shpm || !reqfd) { + TCHAR searchspec[MAX_PATH]; + mir_sntprintf(searchspec, SIZEOF(searchspec), _T("%s\\*.*"), profiledir); + + WIN32_FIND_DATA ffd; + HANDLE hFind = FindFirstFile(searchspec, &ffd); + if (hFind != INVALID_HANDLE_VALUE) { + do { + // make sure the first hit is actually a *.dat file + if ((ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && _tcscmp(ffd.cFileName, _T(".")) && _tcscmp(ffd.cFileName, _T(".."))) { + TCHAR newProfile[MAX_PATH]; + mir_sntprintf(newProfile, MAX_PATH, _T("%s\\%s\\%s.dat"), profiledir, ffd.cFileName, ffd.cFileName); + if (_taccess(newProfile, 0) == 0) + if (++found == 1 && nodprof) + _tcscpy(szProfile, newProfile); + } + } + while (FindNextFile(hFind, &ffd)); + + FindClose(hFind); + } + reqfd = !shpm && found == 1 && nodprof; + } + + if ( noProfiles ) + *noProfiles = found == 0; + + if ( nodprof && !reqfd ) + szProfile[0] = 0; + + return reqfd; +} + +// returns 1 if a default profile should be selected instead of showing the manager. +static int getProfileAutoRun(TCHAR * szProfile) +{ + TCHAR Mgr[32]; + GetPrivateProfileString(_T("Database"), _T("ShowProfileMgr"), _T(""), Mgr, SIZEOF(Mgr), mirandabootini); + if (_tcsicmp(Mgr, _T("never"))) + return 0; + + return fileExist(szProfile) || shouldAutoCreate(szProfile); +} + +// returns 1 if a profile was selected +static int getProfile(TCHAR * szProfile, size_t cch) +{ + getProfilePath(g_profileDir, SIZEOF(g_profileDir)); + if (IsInsideRootDir(g_profileDir, true)) + { + if (WritePrivateProfileString(_T("Database"), _T("ProfileDir"), _T(""), mirandabootini)) + getProfilePath(g_profileDir, SIZEOF(g_profileDir)); + } + + getDefaultProfile(szProfile, cch, g_profileDir); + getProfileCmdLine(szProfile, cch, g_profileDir); + if (IsInsideRootDir(g_profileDir, true)) + { + MessageBox(NULL, + _T("Profile cannot be placed into Miranda root folder.\n") + _T("Please move Miranda profile to some other location."), + _T("Miranda IM"), MB_ICONERROR | MB_OK); + return 0; + } + if (getProfileAutoRun(szProfile)) + return 1; + + PROFILEMANAGERDATA pd = {0}; + if (getProfile1(szProfile, cch, g_profileDir, &pd.noProfiles)) + return 1; + + pd.szProfile = szProfile; + pd.szProfileDir = g_profileDir; + return getProfileManager(&pd); +} + +// carefully converts a file name from TCHAR* to char* +char* makeFileName( const TCHAR* tszOriginalName ) +{ + char* szResult = NULL; + char* szFileName = mir_t2a( tszOriginalName ); + TCHAR* tszFileName = mir_a2t( szFileName ); + if ( _tcscmp( tszOriginalName, tszFileName )) { + TCHAR tszProfile[MAX_PATH]; + if ( GetShortPathName( tszOriginalName, tszProfile, MAX_PATH) != 0) + szResult = mir_t2a( tszProfile ); + } + + if ( !szResult ) + szResult = szFileName; + else + mir_free(szFileName); + mir_free(tszFileName); + + return szResult; +} + +// called by the UI, return 1 on success, use link to create profile, set error if any +int makeDatabase(TCHAR * profile, DATABASELINK * link, HWND hwndDlg) +{ + TCHAR buf[256]; + int err=0; + // check if the file already exists + TCHAR * file = _tcsrchr(profile, '\\'); + if (file) file++; + if (_taccess(profile, 0) == 0) { + // file already exists! + mir_sntprintf(buf, SIZEOF(buf), TranslateTS( _T("The profile '%s' already exists. Do you want to move it to the ") + _T("Recycle Bin? \n\nWARNING: The profile will be deleted if Recycle Bin is disabled.\n") + _T("WARNING: A profile may contain confidential information and should be properly deleted.")), file ); + if ( MessageBox(hwndDlg, buf, TranslateT("The profile already exists"), MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2) != IDYES ) + return 0; + + // move the file + SHFILEOPSTRUCT sf = {0}; + sf.wFunc = FO_DELETE; + sf.pFrom = buf; + sf.fFlags = FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT | FOF_ALLOWUNDO; + mir_sntprintf(buf, SIZEOF(buf), _T("%s\0"), profile); + if ( SHFileOperation(&sf) != 0 ) { + mir_sntprintf(buf, SIZEOF(buf),TranslateT("Couldn't move '%s' to the Recycle Bin, Please select another profile name."),file); + MessageBox(0,buf,TranslateT("Problem moving profile"),MB_ICONINFORMATION|MB_OK); + return 0; + } + // now the file should be gone! + } + // ask the database to create the profile + CreatePathToFileT(profile); + char *prf = makeFileName(profile); + if (link->makeDatabase(prf, &err)) { + mir_sntprintf(buf, SIZEOF(buf),TranslateT("Unable to create the profile '%s', the error was %x"),file, err); + MessageBox(hwndDlg,buf,TranslateT("Problem creating profile"),MB_ICONERROR|MB_OK); + mir_free(prf); + return 0; + } + dbCreated = true; + // the profile has been created! woot + mir_free(prf); + return 1; +} + +// enumerate all plugins that had valid DatabasePluginInfo() +static int FindDbPluginForProfile(const char*, DATABASELINK * dblink, LPARAM lParam) +{ + TCHAR* tszProfile = ( TCHAR* )lParam; + + int res = DBPE_CONT; + if ( dblink && dblink->cbSize == sizeof(DATABASELINK)) { + char* szProfile = makeFileName(tszProfile); + // liked the profile? + int err = 0; + if (dblink->grokHeader(szProfile, &err) == 0) { + // added APIs? + if ( !dblink->Load(szProfile, &pluginCoreLink)) { + fillProfileName( tszProfile ); + res = DBPE_DONE; + } + else res = DBPE_HALT; + } + else { + res = DBPE_HALT; + switch ( err ) { + case EGROKPRF_CANTREAD: + case EGROKPRF_UNKHEADER: + // just not supported. + res = DBPE_CONT; + + case EGROKPRF_VERNEWER: + case EGROKPRF_DAMAGED: + break; + } + } //if + mir_free(szProfile); + } + return res; +} + +// enumerate all plugins that had valid DatabasePluginInfo() +static int FindDbPluginAutoCreate(const char*, DATABASELINK * dblink, LPARAM lParam) +{ + TCHAR* tszProfile = ( TCHAR* )lParam; + + int res = DBPE_CONT; + if (dblink && dblink->cbSize == sizeof(DATABASELINK)) { + CreatePathToFileT( tszProfile ); + + int err; + char *szProfile = makeFileName( tszProfile ); + if (dblink->makeDatabase(szProfile, &err) == 0) { + dbCreated = true; + if ( !dblink->Load(szProfile, &pluginCoreLink)) { + fillProfileName( tszProfile ); + res = DBPE_DONE; + } + else res = DBPE_HALT; + } + mir_free(szProfile); + } + return res; +} + +typedef struct { + TCHAR * profile; + UINT msg; + ATOM aPath; + int found; +} ENUMMIRANDAWINDOW; + +static BOOL CALLBACK EnumMirandaWindows(HWND hwnd, LPARAM lParam) +{ + TCHAR classname[256]; + ENUMMIRANDAWINDOW * x = (ENUMMIRANDAWINDOW *)lParam; + DWORD_PTR res=0; + if ( GetClassName(hwnd,classname,SIZEOF(classname)) && lstrcmp( _T("Miranda"),classname)==0 ) { + if ( SendMessageTimeout(hwnd, x->msg, (WPARAM)x->aPath, 0, SMTO_ABORTIFHUNG, 100, &res) && res ) { + x->found++; + return FALSE; + } + } + return TRUE; +} + +static int FindMirandaForProfile(TCHAR * szProfile) +{ + ENUMMIRANDAWINDOW x={0}; + x.profile=szProfile; + x.msg=RegisterWindowMessage( _T( "Miranda::ProcessProfile" )); + x.aPath=GlobalAddAtom(szProfile); + EnumWindows(EnumMirandaWindows, (LPARAM)&x); + GlobalDeleteAtom(x.aPath); + return x.found; +} + +int LoadDatabaseModule(void) +{ + TCHAR szProfile[MAX_PATH]; + pathToAbsoluteT(_T("."), szProfile, NULL); + _tchdir(szProfile); + szProfile[0] = 0; + + // load the older basic services of the db + InitUtils(); + + // find out which profile to load + if ( !getProfile( szProfile, SIZEOF( szProfile ))) + return 1; + + PLUGIN_DB_ENUM dbe; + dbe.cbSize = sizeof(PLUGIN_DB_ENUM); + dbe.lParam = (LPARAM)szProfile; + + if ( _taccess(szProfile, 0) && shouldAutoCreate( szProfile )) + dbe.pfnEnumCallback=( int(*) (const char*,void*,LPARAM) )FindDbPluginAutoCreate; + else + dbe.pfnEnumCallback=( int(*) (const char*,void*,LPARAM) )FindDbPluginForProfile; + + // find a driver to support the given profile + int rc = CallService(MS_PLUGINS_ENUMDBPLUGINS, 0, (LPARAM)&dbe); + switch ( rc ) { + case -1: { + // no plugins at all + TCHAR buf[256]; + TCHAR* p = _tcsrchr(szProfile,'\\'); + mir_sntprintf(buf,SIZEOF(buf),TranslateT("Miranda is unable to open '%s' because you do not have any profile plugins installed.\nYou need to install dbx_3x.dll or equivalent."), p ? ++p : szProfile ); + MessageBox(0,buf,TranslateT("No profile support installed!"),MB_OK | MB_ICONERROR); + break; + } + case 1: + // if there were drivers but they all failed cos the file is locked, try and find the miranda which locked it + if (fileExist(szProfile)) { + // file isn't locked, just no driver could open it. + TCHAR buf[256]; + TCHAR* p = _tcsrchr(szProfile,'\\'); + mir_sntprintf(buf,SIZEOF(buf),TranslateT("Miranda was unable to open '%s', it's in an unknown format.\nThis profile might also be damaged, please run DB-tool which should be installed."), p ? ++p : szProfile); + MessageBox(0,buf,TranslateT("Miranda can't understand that profile"),MB_OK | MB_ICONERROR); + } + else if (!FindMirandaForProfile(szProfile)) { + TCHAR buf[256]; + TCHAR* p = _tcsrchr(szProfile,'\\'); + mir_sntprintf(buf,SIZEOF(buf),TranslateT("Miranda was unable to open '%s'\nIt's inaccessible or used by other application or Miranda instance"), p ? ++p : szProfile); + MessageBox(0,buf,TranslateT("Miranda can't open that profile"),MB_OK | MB_ICONERROR); + } + break; + } + return (rc != 0); +} diff --git a/src/modules/database/dbini.cpp b/src/modules/database/dbini.cpp new file mode 100644 index 0000000000..01e6645593 --- /dev/null +++ b/src/modules/database/dbini.cpp @@ -0,0 +1,490 @@ +/* + +Miranda IM: the free IM client for Microsoft* Windows* + +Copyright 2000-2009 Miranda ICQ/IM 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 "commonheaders.h" +#include "../srfile/file.h" + +static bool bModuleInitialized = false; +static HANDLE hIniChangeNotification; + +extern TCHAR mirandabootini[MAX_PATH]; +extern bool dbCreated; + +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; +} + +void ConvertBackslashes(char *, UINT); +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; + + DBCONTACTGETSETTING dbcgs; + dbcgs.szModule = szSection; + dbcgs.szSetting = setting_items->name; + CallService(MS_DB_CONTACT_DELETESETTING, 0, (LPARAM)&dbcgs); + + 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(hMirandaInst,MAKEINTRESOURCE(IDD_WARNINICHANGE),NULL,WarnIniChangeDlgProc,(LPARAM)&warnInfo)) + continue; + if(warnInfo.cancel) + break; + if(warnInfo.warnNoMore) + warnThisSection=0; + } + + switch(szValue[0]) { + case 'b': + case 'B': + DBWriteContactSettingByte(NULL,szSection,szName,(BYTE)strtol(szValue+1,NULL,0)); + break; + case 'w': + case 'W': + DBWriteContactSettingWord(NULL,szSection,szName,(WORD)strtol(szValue+1,NULL,0)); + break; + case 'd': + case 'D': + DBWriteContactSettingDword(NULL,szSection,szName,(DWORD)strtoul(szValue+1,NULL,0)); + break; + case 'l': + case 'L': + DBDeleteContactSetting(NULL,szSection,szName); + break; + case 'e': + case 'E': + ConvertBackslashes(szValue+1, LangPackGetDefaultCodePage()); + case 's': + case 'S': + DBWriteContactSettingString(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': + DBWriteContactSettingStringUtf(NULL,szSection,szName,szValue+1); + break; + case 'n': + case 'h': + case 'N': + case 'H': + { PBYTE buf; + int len; + char *pszValue,*pszEnd; + DBCONTACTWRITESETTING cws; + + 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; + } + cws.szModule=szSection; + cws.szSetting=szName; + cws.value.type=DBVT_BLOB; + cws.value.pbVal=buf; + cws.value.cpbVal=len; + CallService(MS_DB_CONTACT_WRITESETTING,(WPARAM)(HANDLE)NULL,(LPARAM)&cws); + mir_free(buf); + } + break; + default: + MessageBox(NULL,TranslateT("Invalid setting type. The first character of every value must be b, w, d, l, s, e, u, g, h or n."),TranslateT("Install Database Settings"),MB_OK); + break; + } + } + fclose(fp); +} + +static void DoAutoExec(void) +{ + TCHAR szUse[7], szIniPath[MAX_PATH], szFindPath[MAX_PATH]; + TCHAR *str2; + 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 (dbCreated && szOnCreateFilename[0]) { + str2 = Utils_ReplaceVarsT(szOnCreateFilename); + pathToAbsoluteT(str2, szIniPath, NULL); + mir_free(str2); + + ProcessIniFile(szIniPath, szSafeSections, szUnsafeSections, 0, 1); + } + + str2 = Utils_ReplaceVarsT(szFindPath); + pathToAbsoluteT(str2, szFindPath, NULL); + mir_free(str2); + + WIN32_FIND_DATA fd; + HANDLE hFind = FindFirstFile(szFindPath, &fd); + if (hFind == INVALID_HANDLE_VALUE) { + mir_free(szSafeSections); + mir_free(szUnsafeSections); + return; + } + + 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(hMirandaInst,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(hMirandaInst,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) +{ + TCHAR szMirandaDir[MAX_PATH]; + + bModuleInitialized = true; + + DoAutoExec(); + pathToAbsoluteT(_T("."), szMirandaDir, NULL); + 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); +} diff --git a/src/modules/database/dblists.cpp b/src/modules/database/dblists.cpp new file mode 100644 index 0000000000..02332ab283 --- /dev/null +++ b/src/modules/database/dblists.cpp @@ -0,0 +1,282 @@ +/* + +Miranda IM: the free IM client for Microsoft* Windows* + +Copyright 2000-2009 Miranda ICQ/IM 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 "commonheaders.h" + +/* a simple sorted list implementation */ + +SortedList* List_Create( int p_limit, int p_increment ) +{ + SortedList* result = ( SortedList* )mir_calloc( sizeof( SortedList )); + if ( result == NULL ) + return(NULL); + + result->increment = p_increment; + result->limit = p_limit; + return(result); +} + +void List_Destroy( SortedList* p_list ) +{ + if ( p_list == NULL ) + return; + + if ( p_list->items != NULL ) { + mir_free( p_list->items ); + p_list->items = NULL; + } + + p_list->realCount = p_list->limit = 0; +} + +void* List_Find( SortedList* p_list, void* p_value ) +{ + int index; + + if ( !List_GetIndex( p_list, p_value, &index )) + return(NULL); + + return(p_list->items[ index ]); +} + +#ifdef _DEBUG +#pragma optimize( "gt", on ) +#endif + +int List_GetIndex( SortedList* p_list, void* p_value, int* p_index ) +{ + if (p_value == NULL) + { + *p_index = -1; + return 0; + } + + switch ((INT_PTR)p_list->sortFunc) + { + case 0: + break; + + case HandleKeySort: +#ifdef _WIN64 + { + const unsigned __int64 val = *(unsigned __int64 *)p_value; + int low = 0; + int high = p_list->realCount - 1; + + while (low <= high) + { + int i = (low + high) / 2; + unsigned __int64 vali = *(unsigned __int64 *)p_list->items[i]; + if (vali == val) + { + *p_index = i; + return 1; + } + + if (vali < val) + low = i + 1; + else + high = i - 1; + } + + *p_index = low; + } + break; +#endif + + case NumericKeySort: + { + const unsigned val = *(unsigned *)p_value; + int low = 0; + int high = p_list->realCount - 1; + + while (low <= high) + { + int i = (low + high) / 2; + unsigned vali = *(unsigned *)p_list->items[i]; + if (vali == val) + { + *p_index = i; + return 1; + } + + if (vali < val) + low = i + 1; + else + high = i - 1; + } + + *p_index = low; + } + break; + + case PtrKeySort: + { + int low = 0; + int high = p_list->realCount - 1; + + while (low <= high) + { + int i = (low + high) / 2; + const void* vali = p_list->items[i]; + if (vali == p_value) + { + *p_index = i; + return 1; + } + + if (vali < p_value) + low = i + 1; + else + high = i - 1; + } + + *p_index = low; + } + break; + + default: + { + int low = 0; + int high = p_list->realCount - 1; + + while (low <= high) + { + int i = (low + high) / 2; + int result = p_list->sortFunc(p_list->items[i], p_value); + if (result == 0) + { + *p_index = i; + return 1; + } + + if (result < 0) + low = i + 1; + else + high = i - 1; + } + + *p_index = low; + } + break; + } + + return 0; +} + +int List_IndexOf( SortedList* p_list, void* p_value ) +{ + if ( p_value == NULL ) + return -1; + + int i; + for ( i=0; i < p_list->realCount; i++ ) + if ( p_list->items[i] == p_value ) + return i; + + return -1; +} + +#ifdef _DEBUG +#pragma optimize( "", on ) +#endif + +int List_Insert( SortedList* p_list, void* p_value, int p_index) +{ + if ( p_value == NULL || p_index > p_list->realCount ) + return 0; + + if ( p_list->realCount == p_list->limit ) + { + p_list->items = ( void** )mir_realloc( p_list->items, sizeof( void* )*(p_list->realCount + p_list->increment)); + p_list->limit += p_list->increment; + } + + if ( p_index < p_list->realCount ) + memmove( p_list->items+p_index+1, p_list->items+p_index, sizeof( void* )*( p_list->realCount-p_index )); + + p_list->realCount++; + + p_list->items[ p_index ] = p_value; + return 1; +} + +int List_InsertPtr( SortedList* list, void* p ) +{ + if ( p == NULL ) + return -1; + + int idx = list->realCount; + List_GetIndex( list, p, &idx ); + return List_Insert( list, p, idx ); +} + +int List_Remove( SortedList* p_list, int index ) +{ + if ( index < 0 || index > p_list->realCount ) + return(0); + + p_list->realCount--; + if ( p_list->realCount > index ) + { + memmove( p_list->items+index, p_list->items+index+1, sizeof( void* )*( p_list->realCount-index )); + p_list->items[ p_list->realCount ] = NULL; + } + + return 1; +} + +int List_RemovePtr( SortedList* list, void* p ) +{ + int idx = -1; + if ( List_GetIndex( list, p, &idx )) + List_Remove( list, idx ); + + return idx; +} + +void List_Copy( SortedList* s, SortedList* d, size_t itemSize ) +{ + int i; + + d->increment = s->increment; + d->sortFunc = s->sortFunc; + + for ( i = 0; i < s->realCount; i++ ) { + void* item = mir_alloc( itemSize ); + memcpy( item, s->items[i], itemSize ); + List_Insert( d, item, i ); +} } + +void List_ObjCopy( SortedList* s, SortedList* d, size_t itemSize ) +{ + int i; + + d->increment = s->increment; + d->sortFunc = s->sortFunc; + + for ( i = 0; i < s->realCount; i++ ) { + void* item = new char[ itemSize ]; + memcpy( item, s->items[i], itemSize ); + List_Insert( d, item, i ); +} } diff --git a/src/modules/database/dblists.h b/src/modules/database/dblists.h new file mode 100644 index 0000000000..30886973a4 --- /dev/null +++ b/src/modules/database/dblists.h @@ -0,0 +1,39 @@ +/* + +Miranda IM: the free IM client for Microsoft* Windows* + +Copyright 2000-2009 Miranda ICQ/IM 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. +*/ + +/* a simple sorted list implementation */ + +SortedList* List_Create( int, int ); +void List_Destroy( SortedList* ); + +void* List_Find( SortedList*, void* ); +int List_GetIndex( SortedList*, void*, int* ); +int List_Insert( SortedList*, void*, int ); +int List_Remove( SortedList*, int ); +int List_IndexOf( SortedList*, void* ); + +int List_InsertPtr( SortedList* list, void* p ); +int List_RemovePtr( SortedList* list, void* p ); + +void List_Copy( SortedList*, SortedList*, size_t ); +void List_ObjCopy( SortedList*, SortedList*, size_t ); \ No newline at end of file diff --git a/src/modules/database/dbutils.cpp b/src/modules/database/dbutils.cpp new file mode 100644 index 0000000000..1e73ddd18e --- /dev/null +++ b/src/modules/database/dbutils.cpp @@ -0,0 +1,365 @@ +/* + +Miranda IM: the free IM client for Microsoft* Windows* + +Copyright 2000-2009 Miranda ICQ/IM 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 "commonheaders.h" +#include "profilemanager.h" + +static int CompareEventTypes( const DBEVENTTYPEDESCR* p1, const DBEVENTTYPEDESCR* p2 ) +{ + int result = strcmp( p1->module, p2->module ); + if ( result ) + return result; + + return p1->eventType - p2->eventType; +} + +static LIST eventTypes( 10, CompareEventTypes ); + +static BOOL bModuleInitialized = FALSE; + +static INT_PTR DbEventTypeRegister(WPARAM, LPARAM lParam) +{ + DBEVENTTYPEDESCR* et = ( DBEVENTTYPEDESCR* )lParam; + if ( eventTypes.getIndex( et ) == -1 ) { + DBEVENTTYPEDESCR* p = ( DBEVENTTYPEDESCR* )mir_alloc( sizeof( DBEVENTTYPEDESCR )); + p->cbSize = DBEVENTTYPEDESCR_SIZE; + p->module = mir_strdup( et->module ); + p->eventType = et->eventType; + p->descr = mir_strdup( et->descr ); + p->textService = NULL; + p->iconService = NULL; + p->eventIcon = NULL; + p->flags = 0; + if ( et->cbSize == DBEVENTTYPEDESCR_SIZE ) { + if ( et->textService ) + p->textService = mir_strdup( et->textService ); + if ( et->iconService ) + p->iconService = mir_strdup( et->iconService ); + p->eventIcon = et->eventIcon; + p->flags = et->flags; + } + if ( !p->textService ) { + char szServiceName[100]; + mir_snprintf( szServiceName, sizeof(szServiceName), "%s/GetEventText%d", p->module, p->eventType ); + p->textService = mir_strdup( szServiceName ); + } + if ( !p->iconService ) { + char szServiceName[100]; + mir_snprintf( szServiceName, sizeof(szServiceName), "%s/GetEventIcon%d", p->module, p->eventType ); + p->iconService = mir_strdup( szServiceName ); + } + eventTypes.insert( p ); + } + + return 0; +} + +static INT_PTR DbEventTypeGet(WPARAM wParam, LPARAM lParam) +{ + DBEVENTTYPEDESCR tmp; + int idx; + + tmp.module = ( char* )wParam; + tmp.eventType = lParam; + if ( !List_GetIndex(( SortedList* )&eventTypes, &tmp, &idx )) + return 0; + + return ( INT_PTR )eventTypes[idx]; +} + +static INT_PTR DbEventGetText(WPARAM wParam, LPARAM lParam) +{ + DBEVENTGETTEXT* egt = (DBEVENTGETTEXT*)lParam; + BOOL bIsDenyUnicode = (egt->datatype & DBVTF_DENYUNICODE); + + DBEVENTINFO* dbei = egt->dbei; + DBEVENTTYPEDESCR* et = ( DBEVENTTYPEDESCR* )DbEventTypeGet( ( WPARAM )dbei->szModule, ( LPARAM )dbei->eventType ); + + if ( et && ServiceExists( et->textService )) + return CallService( et->textService, wParam, lParam ); + + if ( !dbei->pBlob ) return 0; + + if ( dbei->eventType == EVENTTYPE_FILE ) { + char* filename = ((char *)dbei->pBlob) + sizeof(DWORD); + char* descr = filename + lstrlenA( filename ) + 1; + char* str = (*descr == 0) ? filename : descr; + switch ( egt->datatype ) { + case DBVT_WCHAR: + return ( INT_PTR )(( dbei->flags & DBEF_UTF ) ? + Utf8DecodeT( str ) : mir_a2t( str )); + case DBVT_ASCIIZ: + return ( INT_PTR )(( dbei->flags & DBEF_UTF ) ? Utf8Decode( mir_strdup( str ), NULL ) : mir_strdup( str )); + } + return 0; + } + + // temporary fix for bug with event types conflict between jabber chat states notifications + // and srmm's status changes, must be commented out in future releases + if ( dbei->eventType == 25368 && dbei->cbBlob == 1 && dbei->pBlob[0] == 1 ) + return 0; + + egt->datatype &= ~DBVTF_DENYUNICODE; + if ( egt->datatype == DBVT_WCHAR ) + { + WCHAR* msg = NULL; + if ( dbei->flags & DBEF_UTF ) { + char* str = (char*)alloca(dbei->cbBlob + 1); + if (str == NULL) return NULL; + memcpy(str, dbei->pBlob, dbei->cbBlob); + str[dbei->cbBlob] = 0; + Utf8DecodeCP( str, egt->codepage, &msg ); + } + else { + size_t msglen = strlen(( char* )dbei->pBlob) + 1, msglenW = 0; + if ( msglen != dbei->cbBlob ) { + size_t i, count = (( dbei->cbBlob - msglen ) / sizeof( WCHAR )); + WCHAR* p = ( WCHAR* )&dbei->pBlob[ msglen ]; + for ( i=0; i < count; i++ ) { + if ( p[i] == 0 ) { + msglenW = i; + break; + } } } + + if ( msglenW > 0 && msglenW < msglen && !bIsDenyUnicode ) + msg = mir_wstrdup(( WCHAR* )&dbei->pBlob[ msglen ] ); + else { + msg = ( WCHAR* )mir_alloc( sizeof(WCHAR) * msglen ); + MultiByteToWideChar( egt->codepage, 0, (char *) dbei->pBlob, -1, msg, (int)msglen ); + } } + return ( INT_PTR )msg; + } + else if ( egt->datatype == DBVT_ASCIIZ ) { + char* msg = mir_strdup(( char* )dbei->pBlob ); + if (dbei->flags & DBEF_UTF) + Utf8DecodeCP( msg, egt->codepage, NULL ); + + return ( INT_PTR )msg; + } + return 0; +} + +static INT_PTR DbEventGetIcon( WPARAM wParam, LPARAM lParam ) +{ + DBEVENTINFO* dbei = ( DBEVENTINFO* )lParam; + HICON icon = NULL; + DBEVENTTYPEDESCR* et = ( DBEVENTTYPEDESCR* )DbEventTypeGet( ( WPARAM )dbei->szModule, ( LPARAM )dbei->eventType ); + + if ( et && ServiceExists( et->iconService )) { + icon = ( HICON )CallService( et->iconService, wParam, lParam ); + if ( icon ) + return ( INT_PTR )icon; + } + if ( et && et->eventIcon ) + icon = ( HICON )CallService( MS_SKIN2_GETICONBYHANDLE, 0, ( LPARAM )et->eventIcon ); + if ( !icon ) { + char szName[100]; + mir_snprintf( szName, sizeof( szName ), "eventicon_%s%d", dbei->szModule, dbei->eventType ); + icon = ( HICON )CallService( MS_SKIN2_GETICON, 0, ( LPARAM )szName ); + } + + if ( !icon ) + { + switch( dbei->eventType ) { + case EVENTTYPE_URL: + icon = LoadSkinIcon( SKINICON_EVENT_URL ); + break; + + case EVENTTYPE_FILE: + icon = LoadSkinIcon( SKINICON_EVENT_FILE ); + break; + + default: // EVENTTYPE_MESSAGE and unknown types + icon = LoadSkinIcon( SKINICON_EVENT_MESSAGE ); + break; + } + } + + if ( wParam & LR_SHARED ) + return ( INT_PTR )icon; + else + return ( INT_PTR )CopyIcon( icon ); +} + +static INT_PTR DbEventGetStringT( WPARAM wParam, LPARAM lParam ) +{ + DBEVENTINFO* dbei = ( DBEVENTINFO* )wParam; + char* string = ( char* )lParam; + + #if defined( _UNICODE ) + if ( dbei->flags & DBEF_UTF ) + return ( INT_PTR )Utf8DecodeUcs2( string ); + + return ( INT_PTR )mir_a2t( string ); + #else + char* res = mir_strdup( string ); + if ( dbei->flags & DBEF_UTF ) + Utf8Decode( res, NULL ); + return ( INT_PTR )res; + #endif +} + +///////////////////////////////////////////////////////////////////////////////////////// + +static int sttEnumVars( const char* szVarName, LPARAM lParam ) +{ + LIST* vars = ( LIST* )lParam; + vars->insert( mir_strdup( szVarName )); + return 0; +} + +static INT_PTR DbDeleteModule( WPARAM, LPARAM lParam ) +{ + LIST vars( 20 ); + + DBCONTACTENUMSETTINGS dbces = { 0 }; + dbces.pfnEnumProc = sttEnumVars; + dbces.lParam = ( LPARAM )&vars; + dbces.szModule = ( char* )lParam; + CallService( MS_DB_CONTACT_ENUMSETTINGS, NULL, (LPARAM)&dbces ); + + for ( int i=vars.getCount()-1; i >= 0; i-- ) { + DBDeleteContactSetting( NULL, ( char* )lParam, vars[i] ); + mir_free( vars[i] ); + } + vars.destroy(); + return 0; +} + +static INT_PTR GetProfilePath(WPARAM wParam, LPARAM lParam) +{ + if (!wParam || !lParam) + return 1; + + char* dst = (char*)lParam; + + #if defined( _UNICODE ) + char* tmp = mir_t2a( g_profileDir ); + strncpy( dst, tmp, wParam ); + mir_free( tmp ); + #else + strncpy( dst, g_profileDir, wParam ); + #endif + + if (wParam <= _tcslen(g_profileName)) + { + dst[wParam - 1] = 0; + return 1; + } + return 0; +} + +static INT_PTR GetProfileName(WPARAM wParam, LPARAM lParam) +{ + if (!wParam || !lParam) + return 1; + + char* dst = (char*)lParam; + + #if defined( _UNICODE ) + char* tmp = makeFileName( g_profileName ); + strncpy( dst, tmp, wParam ); + mir_free( tmp ); + #else + strncpy( dst, g_profileName, wParam ); + #endif + + if (wParam <= _tcslen(g_profileName)) + { + dst[wParam - 1] = 0; + return 1; + } + return 0; +} + +#if defined( _UNICODE ) + +static INT_PTR GetProfilePathW(WPARAM wParam, LPARAM lParam) +{ + if (!wParam || !lParam) + return 1; + + wchar_t* dst = (wchar_t*)lParam; + wcsncpy(dst, g_profileDir, wParam); + if (wParam <= wcslen(g_profileDir)) + { + dst[wParam - 1] = 0; + return 1; + } + return 0; +} + +static INT_PTR GetProfileNameW(WPARAM wParam, LPARAM lParam) +{ + wchar_t* dst = (wchar_t*)lParam; + wcsncpy(dst, g_profileName, wParam ); + if (wParam <= wcslen(g_profileName)) + { + dst[wParam - 1] = 0; + return 1; + } + return 0; +} + +#endif + +///////////////////////////////////////////////////////////////////////////////////////// + +int InitUtils() +{ + bModuleInitialized = TRUE; + + CreateServiceFunction(MS_DB_EVENT_REGISTERTYPE, DbEventTypeRegister); + CreateServiceFunction(MS_DB_EVENT_GETTYPE, DbEventTypeGet); + CreateServiceFunction(MS_DB_EVENT_GETTEXT, DbEventGetText); + CreateServiceFunction(MS_DB_EVENT_GETICON, DbEventGetIcon); + CreateServiceFunction(MS_DB_EVENT_GETSTRINGT, DbEventGetStringT); + + CreateServiceFunction(MS_DB_MODULE_DELETE, DbDeleteModule); + + CreateServiceFunction(MS_DB_GETPROFILEPATH,GetProfilePath); + CreateServiceFunction(MS_DB_GETPROFILENAME,GetProfileName); + #if defined( _UNICODE ) + CreateServiceFunction(MS_DB_GETPROFILEPATHW,GetProfilePathW); + CreateServiceFunction(MS_DB_GETPROFILENAMEW,GetProfileNameW); + #endif + return 0; +} + +void UnloadEventsModule() +{ + int i; + + if ( !bModuleInitialized ) return; + + for ( i=0; i < eventTypes.getCount(); i++ ) { + DBEVENTTYPEDESCR* p = eventTypes[i]; + mir_free( p->module ); + mir_free( p->descr ); + mir_free( p->textService ); + mir_free( p->iconService ); + mir_free( p ); + } + + eventTypes.destroy(); +} diff --git a/src/modules/database/profilemanager.cpp b/src/modules/database/profilemanager.cpp new file mode 100644 index 0000000000..06cd356d7c --- /dev/null +++ b/src/modules/database/profilemanager.cpp @@ -0,0 +1,850 @@ +/* + +Miranda IM: the free IM client for Microsoft* Windows* + +Copyright 2000-2009 Miranda ICQ/IM 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 "commonheaders.h" +#include "profilemanager.h" +#include + +#define WM_INPUTCHANGED (WM_USER + 0x3000) +#define WM_FOCUSTEXTBOX (WM_USER + 0x3001) + +typedef BOOL (__cdecl *ENUMPROFILECALLBACK) (TCHAR * fullpath, TCHAR * profile, LPARAM lParam); + +struct DetailsPageInit { + int pageCount; + OPTIONSDIALOGPAGE *odp; +}; + +struct DetailsPageData { + DLGTEMPLATE *pTemplate; + HINSTANCE hInst; + DLGPROC dlgProc; + HWND hwnd; + int changed; +}; + +struct DlgProfData { + PROPSHEETHEADER * psh; + HWND hwndOK; // handle to OK button + PROFILEMANAGERDATA * pd; + HANDLE hFileNotify; +}; + +struct DetailsData { + HINSTANCE hInstIcmp; + HFONT hBoldFont; + int pageCount; + int currentPage; + struct DetailsPageData *opd; + RECT rcDisplay; + struct DlgProfData * prof; +}; + +struct ProfileEnumData { + HWND hwnd; + TCHAR* szProfile; +}; + +extern TCHAR mirandabootini[MAX_PATH]; + +char **GetSeviceModePluginsList(void); +void SetServiceModePlugin( int idx ); + +static void ThemeDialogBackground(HWND hwnd) +{ + if (enableThemeDialogTexture) + enableThemeDialogTexture(hwnd, ETDT_ENABLETAB); +} + +static int findProfiles(TCHAR * szProfileDir, ENUMPROFILECALLBACK callback, LPARAM lParam) +{ + // find in Miranda IM profile subfolders + HANDLE hFind = INVALID_HANDLE_VALUE; + WIN32_FIND_DATA ffd; + TCHAR searchspec[MAX_PATH]; + mir_sntprintf(searchspec, SIZEOF(searchspec), _T("%s\\*.*"), szProfileDir); + hFind = FindFirstFile(searchspec, &ffd); + if ( hFind == INVALID_HANDLE_VALUE ) + return 0; + + do { + // find all subfolders except "." and ".." + if ( (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && _tcscmp(ffd.cFileName, _T(".")) && _tcscmp(ffd.cFileName, _T("..")) ) { + TCHAR buf[MAX_PATH], profile[MAX_PATH]; + mir_sntprintf(buf, SIZEOF(buf), _T("%s\\%s\\%s.dat"), szProfileDir, ffd.cFileName, ffd.cFileName); + if (_taccess(buf, 0) == 0) { + mir_sntprintf(profile, SIZEOF(profile), _T("%s.dat"), ffd.cFileName); + if ( !callback(buf, profile, lParam )) + break; + } + } + } + while ( FindNextFile(hFind, &ffd) ); + FindClose(hFind); + + return 1; +} + +static LRESULT CALLBACK ProfileNameValidate(HWND edit, UINT msg, WPARAM wParam, LPARAM lParam) +{ + if ( msg == WM_CHAR ) { + if ( _tcschr( _T(".?/\\#' "), (TCHAR)wParam) != 0 ) + return 0; + PostMessage(GetParent(edit),WM_INPUTCHANGED,0,0); + } + return CallWindowProc((WNDPROC)GetWindowLongPtr(edit,GWLP_USERDATA),edit,msg,wParam,lParam); +} + +static int FindDbProviders(const char*, DATABASELINK * dblink, LPARAM lParam) +{ + HWND hwndDlg = (HWND)lParam; + HWND hwndCombo = GetDlgItem(hwndDlg, IDC_PROFILEDRIVERS); + char szName[64]; + + if ( dblink->getFriendlyName(szName,SIZEOF(szName),1) == 0 ) { + // add to combo box + TCHAR* p = LangPackPcharToTchar( szName ); + LRESULT index = SendMessage( hwndCombo, CB_ADDSTRING, 0, (LPARAM)p ); + mir_free( p ); + SendMessage(hwndCombo, CB_SETITEMDATA, index, (LPARAM)dblink); + } + return DBPE_CONT; +} + +static INT_PTR CALLBACK DlgProfileNew(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + struct DlgProfData * dat = (struct DlgProfData *)GetWindowLongPtr(hwndDlg,GWLP_USERDATA); + switch (msg) { + case WM_INITDIALOG: + TranslateDialogDefault( hwndDlg ); + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam); + dat = (struct DlgProfData *)lParam; + { + // fill in the db plugins present + PLUGIN_DB_ENUM dbe; + dbe.cbSize = sizeof(dbe); + dbe.pfnEnumCallback = (int(*)(const char*,void*,LPARAM))FindDbProviders; + dbe.lParam = (LPARAM)hwndDlg; + if ( CallService( MS_PLUGINS_ENUMDBPLUGINS, 0, ( LPARAM )&dbe ) == -1 ) { + // no plugins?! + EnableWindow( GetDlgItem(hwndDlg, IDC_PROFILEDRIVERS ), FALSE ); + EnableWindow( GetDlgItem(hwndDlg, IDC_PROFILENAME ), FALSE ); + ShowWindow( GetDlgItem(hwndDlg, IDC_NODBDRIVERS ), TRUE ); + } + // default item + SendDlgItemMessage(hwndDlg, IDC_PROFILEDRIVERS, CB_SETCURSEL, 0, 0); + } + // subclass the profile name box + { + HWND hwndProfile = GetDlgItem(hwndDlg, IDC_PROFILENAME); + WNDPROC proc = (WNDPROC)GetWindowLongPtr(hwndProfile, GWLP_WNDPROC); + SetWindowLongPtr(hwndProfile,GWLP_USERDATA,(LONG_PTR)proc); + SetWindowLongPtr(hwndProfile,GWLP_WNDPROC,(LONG_PTR)ProfileNameValidate); + } + + // decide if there is a default profile name given in the INI and if it should be used + if (dat->pd->noProfiles || (shouldAutoCreate(dat->pd->szProfile) && _taccess(dat->pd->szProfile, 0))) + { + TCHAR* profile = _tcsrchr(dat->pd->szProfile, '\\'); + if (profile) ++profile; + else profile = dat->pd->szProfile; + + TCHAR *p = _tcsrchr(profile, '.'); + TCHAR c = 0; + if (p) { c = *p; *p = 0; } + + SetDlgItemText(hwndDlg, IDC_PROFILENAME, profile); + if (c) *p = c; + } + + // focus on the textbox + PostMessage( hwndDlg, WM_FOCUSTEXTBOX, 0, 0 ); + return TRUE; + + case WM_FOCUSTEXTBOX: + SetFocus( GetDlgItem( hwndDlg, IDC_PROFILENAME )); + break; + + case WM_INPUTCHANGED: // when input in the edit box changes + SendMessage( GetParent( hwndDlg ), PSM_CHANGED, 0, 0 ); + EnableWindow( dat->hwndOK, GetWindowTextLength( GetDlgItem( hwndDlg, IDC_PROFILENAME )) > 0 ); + break; + + case WM_SHOWWINDOW: + if ( wParam ) { + SetWindowText( dat->hwndOK, TranslateT("&Create")); + SendMessage( hwndDlg, WM_INPUTCHANGED, 0, 0 ); + } + break; + + case WM_NOTIFY: + { + NMHDR* hdr = ( NMHDR* )lParam; + if ( hdr && hdr->code == PSN_APPLY && dat && IsWindowVisible( hwndDlg )) { + TCHAR szName[MAX_PATH]; + LRESULT curSel = SendDlgItemMessage(hwndDlg,IDC_PROFILEDRIVERS,CB_GETCURSEL,0,0); + if ( curSel == CB_ERR ) break; // should never happen + GetDlgItemText(hwndDlg, IDC_PROFILENAME, szName, SIZEOF( szName )); + if ( szName[0] == 0 ) + break; + + // profile placed in "profile_name" subfolder + mir_sntprintf( dat->pd->szProfile, MAX_PATH, _T("%s\\%s\\%s.dat"), dat->pd->szProfileDir, szName, szName ); + dat->pd->newProfile = 1; + dat->pd->dblink = (DATABASELINK *)SendDlgItemMessage( hwndDlg, IDC_PROFILEDRIVERS, CB_GETITEMDATA, ( WPARAM )curSel, 0 ); + + if ( makeDatabase( dat->pd->szProfile, dat->pd->dblink, hwndDlg ) == 0 ) { + SetWindowLongPtr( hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE ); + } } } + break; + } + + return FALSE; +} + +static int DetectDbProvider(const char*, DATABASELINK * dblink, LPARAM lParam) +{ + int error; + +#ifdef _UNICODE + char* fullpath = makeFileName(( TCHAR* )lParam ); +#else + char* fullpath = (char*)lParam; +#endif + + int ret = dblink->grokHeader(fullpath, &error); +#ifdef _UNICODE + mir_free( fullpath ); +#endif + if ( ret == 0) { +#ifdef _UNICODE + char tmp[ MAX_PATH ]; + dblink->getFriendlyName(tmp, SIZEOF(tmp), 1); + MultiByteToWideChar(CP_ACP, 0, tmp, -1, (TCHAR*)lParam, MAX_PATH); +#else + dblink->getFriendlyName((TCHAR*)lParam, MAX_PATH, 1); +#endif + return DBPE_HALT; + } + + return DBPE_CONT; +} + +BOOL EnumProfilesForList(TCHAR * fullpath, TCHAR * profile, LPARAM lParam) +{ + ProfileEnumData *ped = (ProfileEnumData*)lParam; + HWND hwndList = GetDlgItem(ped->hwnd, IDC_PROFILELIST); + + TCHAR sizeBuf[64]; + int iItem=0; + struct _stat statbuf; + bool bFileExists = false, bFileLocked = true; + + TCHAR* p = _tcsrchr(profile, '.'); + _tcscpy(sizeBuf, _T("0 KB")); + if ( p != NULL ) *p=0; + + LVITEM item = { 0 }; + item.mask = LVIF_TEXT | LVIF_IMAGE; + item.pszText = profile; + item.iItem = 0; + + if ( _tstat(fullpath, &statbuf) == 0) { + if ( statbuf.st_size > 1000000 ) { + mir_sntprintf(sizeBuf,SIZEOF(sizeBuf), _T("%.3lf"), (double)statbuf.st_size / 1048576.0 ); + _tcscpy(sizeBuf+5, _T(" MB")); + } + else { + mir_sntprintf(sizeBuf,SIZEOF(sizeBuf), _T("%.3lf"), (double)statbuf.st_size / 1024.0 ); + _tcscpy(sizeBuf+5, _T(" KB")); + } + bFileExists = TRUE; + + bFileLocked = !fileExist(fullpath); + } + + item.iImage = bFileLocked; + + iItem = SendMessage( hwndList, LVM_INSERTITEM, 0, (LPARAM)&item ); + if ( lstrcmpi(ped->szProfile, fullpath) == 0 ) + ListView_SetItemState(hwndList, iItem, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED); + + item.iItem = iItem; + item.iSubItem = 2; + item.pszText = sizeBuf; + SendMessage( hwndList, LVM_SETITEMTEXT, iItem, (LPARAM)&item ); + + if ( bFileExists ) { + PLUGIN_DB_ENUM dbe; + TCHAR szPath[MAX_PATH]; + + LVITEM item2; + item2.mask = LVIF_TEXT; + item2.iItem = iItem; + + dbe.cbSize = sizeof(dbe); + dbe.pfnEnumCallback = (int(*)(const char*,void*,LPARAM))DetectDbProvider; + dbe.lParam = (LPARAM)szPath; + _tcscpy(szPath, fullpath); + if ( CallService( MS_PLUGINS_ENUMDBPLUGINS, 0, ( LPARAM )&dbe ) == 1 ) { + if (bFileLocked) { + // file locked + item2.pszText = TranslateT( "" ); + item2.iSubItem = 1; + SendMessage( hwndList, LVM_SETITEMTEXT, iItem, ( LPARAM )&item2 ); + } + else { + item.pszText = szPath; + item.iSubItem = 1; + SendMessage( hwndList, LVM_SETITEMTEXT, iItem, (LPARAM)&item ); + } } + + item2.iSubItem = 3; + item2.pszText = rtrim( _tctime( &statbuf.st_ctime )); + SendMessage( hwndList, LVM_SETITEMTEXT, iItem, (LPARAM)&item2 ); + + item2.iSubItem = 4; + item2.pszText = rtrim( _tctime( &statbuf.st_mtime )); + SendMessage( hwndList, LVM_SETITEMTEXT, iItem, (LPARAM)&item2 ); + } + return TRUE; +} + +void DeleteProfile(HWND hwndList, int iItem, DlgProfData* dat) +{ + if (iItem < 0) + return; + + TCHAR profile[MAX_PATH], profilef[MAX_PATH*2]; + + LVITEM item = {0}; + item.mask = LVIF_TEXT; + item.iItem = iItem; + item.pszText = profile; + item.cchTextMax = SIZEOF(profile); + if (!ListView_GetItem(hwndList, &item)) + return; + + mir_sntprintf(profilef, SIZEOF(profilef), TranslateT("Are you sure you want to remove profile \"%s\"?"), profile); + + if (IDYES != MessageBox(NULL, profilef, _T("Miranda IM"), MB_YESNO | MB_TASKMODAL | MB_ICONWARNING)) + return; + + mir_sntprintf(profilef, SIZEOF(profilef), _T("%s\\%s%c"), dat->pd->szProfileDir, profile, 0); + + SHFILEOPSTRUCT sf = {0}; + sf.wFunc = FO_DELETE; + sf.pFrom = profilef; + sf.fFlags = FOF_NOCONFIRMATION | FOF_SILENT | FOF_ALLOWUNDO; + SHFileOperation(&sf); + ListView_DeleteItem(hwndList, item.iItem); +} + +static INT_PTR CALLBACK DlgProfileSelect(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + DlgProfData* dat = (struct DlgProfData *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + HWND hwndList = GetDlgItem(hwndDlg, IDC_PROFILELIST); + + switch (msg) { + case WM_INITDIALOG: + { + HIMAGELIST hImgList; + LVCOLUMN col; + + TranslateDialogDefault( hwndDlg ); + + dat = (DlgProfData*) lParam; + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)dat); + + // set columns + col.mask = LVCF_TEXT | LVCF_WIDTH; + col.pszText = TranslateT("Profile"); + col.cx=122; + ListView_InsertColumn( hwndList, 0, &col ); + + col.pszText = TranslateT("Driver"); + col.cx=100; + ListView_InsertColumn( hwndList, 1, &col ); + + col.pszText = TranslateT("Size"); + col.cx=60; + ListView_InsertColumn( hwndList, 2, &col ); + + col.pszText = TranslateT("Created"); + col.cx=145; + ListView_InsertColumn( hwndList, 3, &col ); + + col.pszText = TranslateT("Modified"); + col.cx=145; + ListView_InsertColumn( hwndList, 4, &col ); + + // icons + hImgList = ImageList_Create(16, 16, ILC_MASK | (IsWinVerXPPlus() ? ILC_COLOR32 : ILC_COLOR16), 2, 1); + ImageList_AddIcon_NotShared(hImgList, MAKEINTRESOURCE(IDI_USERDETAILS)); + ImageList_AddIcon_NotShared(hImgList, MAKEINTRESOURCE(IDI_DELETE)); + + // LV will destroy the image list + SetWindowLongPtr(hwndList, GWL_STYLE, GetWindowLongPtr(hwndList, GWL_STYLE) | LVS_SORTASCENDING); + ListView_SetImageList(hwndList, hImgList, LVSIL_SMALL); + ListView_SetExtendedListViewStyle(hwndList, + ListView_GetExtendedListViewStyle(hwndList) | LVS_EX_DOUBLEBUFFER | LVS_EX_LABELTIP | LVS_EX_FULLROWSELECT); + + // find all the profiles + ProfileEnumData ped = { hwndDlg, dat->pd->szProfile }; + findProfiles(dat->pd->szProfileDir, EnumProfilesForList, (LPARAM)&ped); + PostMessage(hwndDlg, WM_FOCUSTEXTBOX, 0, 0); + + dat->hFileNotify = FindFirstChangeNotification(dat->pd->szProfileDir, TRUE, + FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE); + if (dat->hFileNotify != INVALID_HANDLE_VALUE) + SetTimer(hwndDlg, 0, 1200, NULL); + return TRUE; + } + + case WM_DESTROY: + KillTimer(hwndDlg, 0); + FindCloseChangeNotification(dat->hFileNotify); + break; + + case WM_TIMER: + if (WaitForSingleObject(dat->hFileNotify, 0) == WAIT_OBJECT_0) + { + ListView_DeleteAllItems(hwndList); + ProfileEnumData ped = { hwndDlg, dat->pd->szProfile }; + findProfiles(dat->pd->szProfileDir, EnumProfilesForList, (LPARAM)&ped); + FindNextChangeNotification(dat->hFileNotify); + } + break; + + case WM_FOCUSTEXTBOX: + SetFocus(hwndList); + if (dat->pd->szProfile[0] == 0 || ListView_GetSelectedCount(hwndList) == 0) + ListView_SetItemState(hwndList, 0, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED); + break; + + case WM_SHOWWINDOW: + if ( wParam ) + { + SetWindowText(dat->hwndOK, TranslateT("&Run")); + EnableWindow(dat->hwndOK, ListView_GetSelectedCount(hwndList)==1); + } + break; + + case WM_CONTEXTMENU: + { + LVHITTESTINFO lvht = {0}; + lvht.pt.x = GET_X_LPARAM(lParam); + lvht.pt.y = GET_Y_LPARAM(lParam); + ScreenToClient(hwndList, &lvht.pt); + if (ListView_HitTest(hwndList, &lvht) < 0) break; + + lvht.pt.x = GET_X_LPARAM(lParam); + lvht.pt.y = GET_Y_LPARAM(lParam); + + HMENU hMenu = CreatePopupMenu(); + AppendMenu(hMenu, MF_STRING, 1, TranslateT("Run")); + AppendMenu(hMenu, MF_SEPARATOR, 2, NULL); + AppendMenu(hMenu, MF_STRING, 3, TranslateT("Delete")); + int index = TrackPopupMenu(hMenu, TPM_RETURNCMD, lvht.pt.x, lvht.pt.y, 0, hwndDlg, NULL); + switch (index) { + case 1: + SendMessage(GetParent(hwndDlg), WM_COMMAND, IDOK, 0); + break; + + case 3: + DeleteProfile(hwndList, lvht.iItem, dat); + break; + } + DestroyMenu(hMenu); + break; + } + + + case WM_NOTIFY: + { + LPNMHDR hdr = (LPNMHDR) lParam; + if (hdr && hdr->code == PSN_INFOCHANGED) + break; + + if (hdr && hdr->idFrom == IDC_PROFILELIST) + { + switch (hdr->code) + { + case LVN_ITEMCHANGED: + EnableWindow(dat->hwndOK, ListView_GetSelectedCount(hwndList) == 1); + + case NM_DBLCLK: + { + LVITEM item = {0}; + TCHAR profile[MAX_PATH]; + + if (dat == NULL) break; + + item.mask = LVIF_TEXT; + item.iItem = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED | LVNI_ALL); + item.pszText = profile; + item.cchTextMax = SIZEOF(profile); + + if (ListView_GetItem(hwndList, &item)) { + // profile is placed in "profile_name" subfolder + TCHAR tmpPath[MAX_PATH]; + mir_sntprintf(tmpPath, SIZEOF(tmpPath), _T("%s\\%s.dat"), dat->pd->szProfileDir, profile); + HANDLE hFile = CreateFile(tmpPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); + if (hFile == INVALID_HANDLE_VALUE) + mir_sntprintf(dat->pd->szProfile, MAX_PATH, _T("%s\\%s\\%s.dat"), dat->pd->szProfileDir, profile, profile); + else + _tcscpy(dat->pd->szProfile, tmpPath); + CloseHandle(hFile); + if (hdr->code == NM_DBLCLK) EndDialog(GetParent(hwndDlg), 1); + } + return TRUE; + } + + case LVN_KEYDOWN: + { + LPNMLVKEYDOWN hdrk = (LPNMLVKEYDOWN) lParam; + if (hdrk->wVKey == VK_DELETE) + DeleteProfile(hwndList, ListView_GetNextItem(hwndList, -1, LVNI_SELECTED | LVNI_ALL), dat); + break; + } + } + } + break; + } } + + return FALSE; +} + +static INT_PTR CALLBACK DlgProfileManager(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + struct DetailsData* dat = ( struct DetailsData* )GetWindowLongPtr( hwndDlg, GWLP_USERDATA ); + + switch (msg) { + case WM_INITDIALOG: + { + struct DlgProfData * prof = (struct DlgProfData *)lParam; + PROPSHEETHEADER *psh = prof->psh; + TranslateDialogDefault(hwndDlg); + SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)LoadImage(hMirandaInst, MAKEINTRESOURCE(IDI_USERDETAILS),IMAGE_ICON,GetSystemMetrics(SM_CXSMICON),GetSystemMetrics(SM_CYSMICON),0)); + SendMessage(hwndDlg, WM_SETICON, ICON_BIG, (LPARAM)LoadImage(hMirandaInst, MAKEINTRESOURCE(IDI_USERDETAILS),IMAGE_ICON,GetSystemMetrics(SM_CXICON),GetSystemMetrics(SM_CYICON),0)); + dat = (struct DetailsData*)mir_alloc(sizeof(struct DetailsData)); + dat->prof = prof; + prof->hwndOK = GetDlgItem( hwndDlg, IDOK ); + EnableWindow( prof->hwndOK, FALSE ); + SetWindowLongPtr( hwndDlg, GWLP_USERDATA, (LONG_PTR)dat ); + + { + TCHAR buf[512]; + mir_sntprintf(buf, SIZEOF(buf), _T("%s: %s\n%s"), TranslateT("Miranda Profiles from"), prof->pd->szProfileDir, + TranslateT("Select or create your Miranda IM user profile")); + SetDlgItemText(hwndDlg, IDC_NAME, buf); + } + + { OPTIONSDIALOGPAGE *odp; + int i; + TCITEM tci; + + dat->currentPage = 0; + dat->pageCount = psh->nPages; + dat->opd = ( struct DetailsPageData* )mir_calloc( sizeof( struct DetailsPageData )*dat->pageCount ); + odp = ( OPTIONSDIALOGPAGE* )psh->ppsp; + + tci.mask = TCIF_TEXT; + for( i=0; i < dat->pageCount; i++ ) { + dat->opd[i].pTemplate = (DLGTEMPLATE *)LockResource(LoadResource(odp[i].hInstance,FindResourceA(odp[i].hInstance,odp[i].pszTemplate,MAKEINTRESOURCEA(5)))); + dat->opd[i].dlgProc = odp[i].pfnDlgProc; + dat->opd[i].hInst = odp[i].hInstance; + dat->opd[i].hwnd = NULL; + dat->opd[i].changed = 0; + tci.pszText = ( TCHAR* )odp[i].ptszTitle; + if (dat->prof->pd->noProfiles || shouldAutoCreate(dat->prof->pd->szProfile)) + dat->currentPage = 1; + TabCtrl_InsertItem( GetDlgItem(hwndDlg,IDC_TABS), i, &tci ); + } } + + GetWindowRect(GetDlgItem(hwndDlg,IDC_TABS),&dat->rcDisplay); + TabCtrl_AdjustRect(GetDlgItem(hwndDlg,IDC_TABS),FALSE,&dat->rcDisplay); + { + POINT pt = {0,0}; + ClientToScreen( hwndDlg, &pt ); + OffsetRect( &dat->rcDisplay, -pt.x, -pt.y ); + } + + TabCtrl_SetCurSel( GetDlgItem( hwndDlg, IDC_TABS ), dat->currentPage ); + dat->opd[dat->currentPage].hwnd = CreateDialogIndirectParam(dat->opd[dat->currentPage].hInst,dat->opd[dat->currentPage].pTemplate,hwndDlg,dat->opd[dat->currentPage].dlgProc,(LPARAM)dat->prof); + ThemeDialogBackground( dat->opd[dat->currentPage].hwnd ); + SetWindowPos( dat->opd[dat->currentPage].hwnd, HWND_TOP, dat->rcDisplay.left, dat->rcDisplay.top, 0, 0, SWP_NOSIZE ); + { PSHNOTIFY pshn; + pshn.hdr.code = PSN_INFOCHANGED; + pshn.hdr.hwndFrom = dat->opd[dat->currentPage].hwnd; + pshn.hdr.idFrom = 0; + pshn.lParam = ( LPARAM )0; + SendMessage( dat->opd[dat->currentPage].hwnd, WM_NOTIFY, 0, ( LPARAM )&pshn ); + } + // service mode combobox + { + char **list = GetSeviceModePluginsList(); + if ( !list ) { + ShowWindow( GetDlgItem(hwndDlg, IDC_SM_LABEL ), FALSE ); + ShowWindow( GetDlgItem(hwndDlg, IDC_SM_COMBO ), FALSE ); + } else { + int i = 0; + LRESULT index; + HWND hwndCombo = GetDlgItem(hwndDlg, IDC_SM_COMBO ); + index = SendMessage( hwndCombo, CB_ADDSTRING, 0, (LPARAM)_T("") ); + SendMessage( hwndCombo, CB_SETITEMDATA, index, (LPARAM)-1 ); + SendMessage( hwndCombo, CB_SETCURSEL, 0, 0); + while ( list[i] ) { + TCHAR *str = LangPackPcharToTchar( list[i] ); + index = SendMessage( hwndCombo, CB_ADDSTRING, 0, (LPARAM)str ); + mir_free(str); + SendMessage( hwndCombo, CB_SETITEMDATA, index, (LPARAM)i ); + i++; + } + mir_free(list); + } + } + ShowWindow( dat->opd[dat->currentPage].hwnd, SW_SHOW ); + return TRUE; + } + case WM_CTLCOLORSTATIC: + switch ( GetDlgCtrlID(( HWND )lParam )) { + case IDC_WHITERECT: + SetBkColor(( HDC )wParam, GetSysColor( COLOR_WINDOW )); + return ( INT_PTR )GetSysColorBrush( COLOR_WINDOW ); + } + break; + + case PSM_CHANGED: + dat->opd[dat->currentPage].changed=1; + return TRUE; + + case PSM_FORCECHANGED: + { PSHNOTIFY pshn; + int i; + + pshn.hdr.code = PSN_INFOCHANGED; + pshn.hdr.idFrom = 0; + pshn.lParam = (LPARAM)0; + for ( i=0; i < dat->pageCount; i++ ) { + pshn.hdr.hwndFrom = dat->opd[i].hwnd; + if ( dat->opd[i].hwnd != NULL ) + SendMessage(dat->opd[i].hwnd,WM_NOTIFY,0,(LPARAM)&pshn); + } + break; + } + case WM_NOTIFY: + switch(wParam) { + case IDC_TABS: + switch(((LPNMHDR)lParam)->code) { + case TCN_SELCHANGING: + { PSHNOTIFY pshn; + if ( dat->currentPage == -1 || dat->opd[dat->currentPage].hwnd == NULL ) + break; + pshn.hdr.code = PSN_KILLACTIVE; + pshn.hdr.hwndFrom = dat->opd[dat->currentPage].hwnd; + pshn.hdr.idFrom = 0; + pshn.lParam = 0; + if ( SendMessage( dat->opd[dat->currentPage].hwnd, WM_NOTIFY, 0, ( LPARAM )&pshn )) { + SetWindowLongPtr( hwndDlg, DWLP_MSGRESULT, TRUE ); + return TRUE; + } + break; + } + case TCN_SELCHANGE: + if ( dat->currentPage != -1 && dat->opd[dat->currentPage].hwnd != NULL ) + ShowWindow( dat->opd[ dat->currentPage ].hwnd, SW_HIDE ); + + dat->currentPage = TabCtrl_GetCurSel(GetDlgItem(hwndDlg,IDC_TABS)); + if ( dat->currentPage != -1 ) { + if ( dat->opd[dat->currentPage].hwnd == NULL ) { + PSHNOTIFY pshn; + dat->opd[dat->currentPage].hwnd=CreateDialogIndirectParam(dat->opd[dat->currentPage].hInst,dat->opd[dat->currentPage].pTemplate,hwndDlg,dat->opd[dat->currentPage].dlgProc,(LPARAM)dat->prof); + ThemeDialogBackground(dat->opd[dat->currentPage].hwnd); + SetWindowPos(dat->opd[dat->currentPage].hwnd,HWND_TOP,dat->rcDisplay.left,dat->rcDisplay.top,0,0,SWP_NOSIZE); + pshn.hdr.code=PSN_INFOCHANGED; + pshn.hdr.hwndFrom=dat->opd[dat->currentPage].hwnd; + pshn.hdr.idFrom=0; + pshn.lParam=(LPARAM)0; + SendMessage(dat->opd[dat->currentPage].hwnd,WM_NOTIFY,0,(LPARAM)&pshn); + } + ShowWindow(dat->opd[dat->currentPage].hwnd,SW_SHOW); + } + break; + } + break; + } + break; + + case WM_COMMAND: + switch(LOWORD(wParam)) { + case IDCANCEL: + { int i; + PSHNOTIFY pshn; + pshn.hdr.idFrom=0; + pshn.lParam=0; + pshn.hdr.code=PSN_RESET; + for(i=0;ipageCount;i++) { + if (dat->opd[i].hwnd==NULL || !dat->opd[i].changed) continue; + pshn.hdr.hwndFrom=dat->opd[i].hwnd; + SendMessage(dat->opd[i].hwnd,WM_NOTIFY,0,(LPARAM)&pshn); + } + EndDialog(hwndDlg,0); + } + break; + + case IDC_REMOVE: + if (!dat->prof->pd->noProfiles) { + HWND hwndList = GetDlgItem(dat->opd[0].hwnd, IDC_PROFILELIST); + DeleteProfile(hwndList, ListView_GetNextItem(hwndList, -1, LVNI_SELECTED | LVNI_ALL), dat->prof); + } + break; + + case IDOK: + { + int i; + PSHNOTIFY pshn; + pshn.hdr.idFrom=0; + pshn.lParam=(LPARAM)0; + if ( dat->currentPage != -1 ) { + pshn.hdr.code = PSN_KILLACTIVE; + pshn.hdr.hwndFrom = dat->opd[dat->currentPage].hwnd; + if ( SendMessage(dat->opd[dat->currentPage].hwnd, WM_NOTIFY, 0, ( LPARAM )&pshn )) + break; + } + + pshn.hdr.code=PSN_APPLY; + for ( i=0; i < dat->pageCount; i++ ) { + if ( dat->opd[i].hwnd == NULL || !dat->opd[i].changed ) + continue; + + pshn.hdr.hwndFrom = dat->opd[i].hwnd; + SendMessage( dat->opd[i].hwnd, WM_NOTIFY, 0, ( LPARAM )&pshn ); + if ( GetWindowLongPtr( dat->opd[i].hwnd, DWLP_MSGRESULT ) == PSNRET_INVALID_NOCHANGEPAGE) { + TabCtrl_SetCurSel( GetDlgItem( hwndDlg, IDC_TABS ), i ); + if ( dat->currentPage != -1 ) + ShowWindow( dat->opd[ dat->currentPage ].hwnd, SW_HIDE ); + dat->currentPage = i; + ShowWindow( dat->opd[dat->currentPage].hwnd, SW_SHOW ); + return 0; + } } + EndDialog(hwndDlg,1); + break; + } } + break; + + case WM_DESTROY: + { + LRESULT curSel = SendDlgItemMessage(hwndDlg,IDC_SM_COMBO,CB_GETCURSEL,0,0); + if ( curSel != CB_ERR ) { + int idx = SendDlgItemMessage( hwndDlg, IDC_SM_COMBO, CB_GETITEMDATA, ( WPARAM )curSel, 0 ); + SetServiceModePlugin(idx); + } + } + DestroyIcon(( HICON )SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, 0)); + DestroyIcon(( HICON )SendMessage(hwndDlg, WM_SETICON, ICON_BIG, 0)); + DeleteObject( dat->hBoldFont ); + { int i; + for ( i=0; i < dat->pageCount; i++ ) + if ( dat->opd[i].hwnd != NULL ) + DestroyWindow( dat->opd[i].hwnd ); + } + mir_free( dat->opd ); + mir_free( dat ); + break; + } + return FALSE; +} + +static int AddProfileManagerPage(struct DetailsPageInit * opi, OPTIONSDIALOGPAGE * odp) +{ + if ( odp->cbSize != sizeof( OPTIONSDIALOGPAGE )) + return 1; + + opi->odp = ( OPTIONSDIALOGPAGE* )mir_realloc( opi->odp, sizeof( OPTIONSDIALOGPAGE )*( opi->pageCount+1 )); + { + OPTIONSDIALOGPAGE* p = opi->odp + opi->pageCount++; + p->cbSize = sizeof(OPTIONSDIALOGPAGE); + p->hInstance = odp->hInstance; + p->pfnDlgProc = odp->pfnDlgProc; + p->position = odp->position; + p->ptszTitle = LangPackPcharToTchar(odp->pszTitle); + p->pszGroup = NULL; + p->groupPosition = odp->groupPosition; + p->hGroupIcon = odp->hGroupIcon; + p->hIcon = odp->hIcon; + if (( DWORD_PTR )odp->pszTemplate & 0xFFFF0000 ) + p->pszTemplate = mir_strdup( odp->pszTemplate ); + else + p->pszTemplate = odp->pszTemplate; + } + return 0; +} + +int getProfileManager(PROFILEMANAGERDATA * pd) +{ + DetailsPageInit opi; + opi.pageCount=0; + opi.odp=NULL; + + { + OPTIONSDIALOGPAGE odp = { 0 }; + odp.cbSize = sizeof(odp); + odp.pszTitle = LPGEN("My Profiles"); + odp.pfnDlgProc = DlgProfileSelect; + odp.pszTemplate = MAKEINTRESOURCEA(IDD_PROFILE_SELECTION); + odp.hInstance = hMirandaInst; + AddProfileManagerPage(&opi, &odp); + + odp.pszTitle = LPGEN("New Profile"); + odp.pszTemplate = MAKEINTRESOURCEA(IDD_PROFILE_NEW); + odp.pfnDlgProc = DlgProfileNew; + AddProfileManagerPage(&opi, &odp); + } + + PROPSHEETHEADER psh = { 0 }; + psh.dwSize = sizeof(psh); + psh.dwFlags = PSH_PROPSHEETPAGE|PSH_NOAPPLYNOW; + psh.hwndParent = NULL; + psh.nPages = opi.pageCount; + psh.pStartPage = 0; + psh.ppsp = (PROPSHEETPAGE*)opi.odp; + + DlgProfData prof; + prof.pd = pd; + prof.psh = &psh; + int rc = DialogBoxParam(hMirandaInst,MAKEINTRESOURCE(IDD_PROFILEMANAGER),NULL,DlgProfileManager,(LPARAM)&prof); + + if ( rc != -1 ) + for ( int i=0; i < opi.pageCount; i++ ) { + mir_free(( char* )opi.odp[i].pszTitle ); + mir_free( opi.odp[i].pszGroup ); + if (( DWORD_PTR )opi.odp[i].pszTemplate & 0xFFFF0000 ) + mir_free(( char* )opi.odp[i].pszTemplate ); + } + + if ( opi.odp != NULL ) + mir_free(opi.odp); + + return rc; +} diff --git a/src/modules/database/profilemanager.h b/src/modules/database/profilemanager.h new file mode 100644 index 0000000000..fc6bd56020 --- /dev/null +++ b/src/modules/database/profilemanager.h @@ -0,0 +1,43 @@ +/* + +Miranda IM: the free IM client for Microsoft* Windows* + +Copyright 2000-2009 Miranda ICQ/IM 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. +*/ + +typedef struct { + TCHAR * szProfile; // in/out + TCHAR * szProfileDir; // in/out + BOOL noProfiles; // in + BOOL newProfile; // out + DATABASELINK * dblink; // out +} PROFILEMANAGERDATA; + +int InitUtils(void); + +char* makeFileName( const TCHAR* tszOriginalName ); +int makeDatabase(TCHAR * profile, DATABASELINK * link, HWND hwndDlg); +int getProfileManager(PROFILEMANAGERDATA * pd); +int getProfilePath(TCHAR * buf, size_t cch); +int isValidProfileName(const TCHAR * name); +bool fileExist(TCHAR* fname); +bool shouldAutoCreate(TCHAR *szProfile); + +extern TCHAR g_profileDir[MAX_PATH]; +extern TCHAR g_profileName[MAX_PATH]; -- cgit v1.2.3