diff options
author | Vadim Dashevskiy <watcherhd@gmail.com> | 2012-05-15 10:38:20 +0000 |
---|---|---|
committer | Vadim Dashevskiy <watcherhd@gmail.com> | 2012-05-15 10:38:20 +0000 |
commit | 48540940b6c28bb4378abfeb500ec45a625b37b6 (patch) | |
tree | 2ef294c0763e802f91d868bdef4229b6868527de /src/modules/database | |
parent | 5c350913f011e119127baeb32a6aedeb4f0d33bc (diff) |
initial commit
git-svn-id: http://svn.miranda-ng.org/main/trunk@2 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c
Diffstat (limited to 'src/modules/database')
-rw-r--r-- | src/modules/database/database.cpp | 563 | ||||
-rw-r--r-- | src/modules/database/dbini.cpp | 490 | ||||
-rw-r--r-- | src/modules/database/dblists.cpp | 282 | ||||
-rw-r--r-- | src/modules/database/dblists.h | 39 | ||||
-rw-r--r-- | src/modules/database/dbutils.cpp | 365 | ||||
-rw-r--r-- | src/modules/database/profilemanager.cpp | 850 | ||||
-rw-r--r-- | src/modules/database/profilemanager.h | 43 |
7 files changed, 2632 insertions, 0 deletions
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<DBEVENTTYPEDESCR> 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<char>* vars = ( LIST<char>* )lParam;
+ vars->insert( mir_strdup( szVarName ));
+ return 0;
+}
+
+static INT_PTR DbDeleteModule( WPARAM, LPARAM lParam )
+{
+ LIST<char> 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 <sys/stat.h>
+
+#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( "<In Use>" );
+ 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;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);
+ }
+ 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];
|