From cb4a46e7fbe62d788e66ed6121c717a2d22a4d7c Mon Sep 17 00:00:00 2001 From: watcherhd Date: Thu, 21 Apr 2011 14:14:52 +0000 Subject: svn.miranda.im is moving to a new home! git-svn-id: http://miranda-plugins.googlecode.com/svn/trunk@7 e753b5eb-9565-29b2-b5c5-2cc6f99dfbcb --- miranda-wine/src/modules/database/database.c | 377 +++++++++++++++++++++++++++ 1 file changed, 377 insertions(+) create mode 100644 miranda-wine/src/modules/database/database.c (limited to 'miranda-wine/src/modules/database/database.c') diff --git a/miranda-wine/src/modules/database/database.c b/miranda-wine/src/modules/database/database.c new file mode 100644 index 0000000..ead8acd --- /dev/null +++ b/miranda-wine/src/modules/database/database.c @@ -0,0 +1,377 @@ +/* + +Miranda IM: the free IM client for Microsoft* Windows* + +Copyright 2000-2006 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" + + +// from the plugin loader, hate extern but the db frontend is pretty much tied +extern PLUGINLINK pluginCoreLink; +// contains the location of mirandaboot.ini +extern char mirandabootini[MAX_PATH]; + +// returns 1 if the profile path was returned, without trailing slash +int getProfilePath(char * buf, size_t cch) +{ + char profiledir[MAX_PATH]; + char exprofiledir[MAX_PATH]; + char * p = 0; + // grab the base location now + GetModuleFileNameA(NULL, buf, cch); + p = strrchr(buf, '\\'); + if ( p != 0 ) *p=0; + // change to this location, or "." wont expand properly + _chdir(buf); + GetPrivateProfileStringA("Database", "ProfileDir", ".", profiledir, SIZEOF(profiledir), mirandabootini); + // get the string containing envars and maybe relative paths + // get rid of the vars + ExpandEnvironmentStringsA(profiledir, exprofiledir, SIZEOF(exprofiledir)); + if ( _fullpath(profiledir, exprofiledir, SIZEOF(profiledir)) != 0 ) { + /* XXX: really use CreateDirectory()? it only creates the last dir given a\b\c, SHCreateDirectory() + does what we want however thats 2000+ only */ + DWORD dw = INVALID_FILE_ATTRIBUTES; + CreateDirectoryA(profiledir, NULL); + dw=GetFileAttributesA(profiledir); + if ( dw != INVALID_FILE_ATTRIBUTES && dw&FILE_ATTRIBUTE_DIRECTORY ) { + strncpy(buf, profiledir, cch); + p = strrchr(buf, '\\'); + // if the char after '\' is null then change '\' to null + if ( p != 0 && *(++p)==0 ) *(--p)=0; + return 1; + } + } + // this never happens, usually C:\ is always returned + return 0; +} + +// returns 1 if *.dat spec is matched +int isValidProfileName(char * name) +{ + char * p = strrchr(name, '.'); + if ( p ) { + p++; + if ( lstrcmpiA( p, "dat" ) == 0 ) { + if ( p[3] == 0 ) return 1; + } + } + return 0; +} + +// returns 1 if a single profile (full path) is found within the profile dir +static int getProfile1(char * szProfile, size_t cch, char * profiledir, BOOL * noProfiles) +{ + int rc = 1; + char searchspec[MAX_PATH]; + WIN32_FIND_DATAA ffd; + HANDLE hFind = INVALID_HANDLE_VALUE; + unsigned int found=0; + mir_snprintf(searchspec,SIZEOF(searchspec),"%s\\*.dat", profiledir); + hFind = FindFirstFileA(searchspec, &ffd); + if ( hFind != INVALID_HANDLE_VALUE ) + { + // make sure the first hit is actually a *.dat file + if ( !(ffd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) && isValidProfileName(ffd.cFileName) ) + { + // copy the profile name early cos it might be the only one + mir_snprintf(szProfile, cch, "%s\\%s", profiledir, ffd.cFileName); + found++; + // this might be the only dat but there might be a few wrong things returned before another *.dat + while ( FindNextFileA(hFind,&ffd) ) { + // found another *.dat, but valid? + if ( !(ffd.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) && isValidProfileName(ffd.cFileName) ) { + rc=0; + found++; + break; + } //if + } // while + } //if + FindClose(hFind); + } + if ( found == 0 && noProfiles != 0 ) { + *noProfiles=TRUE; + rc=0; + } + return rc; +} + +// returns 1 if something that looks like a profile is there +static int getProfileCmdLineArgs(char * szProfile, size_t cch) +{ + char *szCmdLine=GetCommandLineA(); + char *szEndOfParam; + char szThisParam[1024]; + int firstParam=1; + + while(szCmdLine[0]) { + if(szCmdLine[0]=='"') { + szEndOfParam=strchr(szCmdLine+1,'"'); + if(szEndOfParam==NULL) break; + lstrcpynA(szThisParam,szCmdLine+1,min( SIZEOF(szThisParam),szEndOfParam-szCmdLine)); + szCmdLine=szEndOfParam+1; + } + else { + szEndOfParam=szCmdLine+strcspn(szCmdLine," \t"); + lstrcpynA(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 + ExpandEnvironmentStringsA(szThisParam,szProfile,cch); + return 1; + } + return 0; +} + +// returns 1 if a valid filename (incl. dat) is found, includes fully qualified path +static int getProfileCmdLine(char * szProfile, size_t cch, char * profiledir) +{ + char buf[MAX_PATH]; + HANDLE hFile; + int rc; + if ( getProfileCmdLineArgs(buf, SIZEOF(buf)) ) { + // have something that looks like a .dat, with or without .dat in the filename + if ( !isValidProfileName(buf) ) mir_snprintf(buf, SIZEOF(buf)-5,"%s.dat",buf); + // expand the relative to a full path , which might fail + if ( _fullpath(szProfile, buf, cch) != 0 ) { + hFile=CreateFileA(szProfile, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); + rc=hFile != INVALID_HANDLE_VALUE; + CloseHandle(hFile); + return rc; + } + return 0; + } + return 0; +} + +// returns 1 if the profile manager should be shown +static int showProfileManager(void) +{ + char Mgr[32]; + // is control pressed? + if (GetAsyncKeyState(VK_CONTROL)&0x8000) return 1; + // wanna show it? + GetPrivateProfileStringA("Database", "ShowProfileMgr", "never", Mgr, SIZEOF(Mgr), mirandabootini); + if ( _strcmpi(Mgr,"yes") == 0 ) return 1; + return 0; +} + +// returns 1 if a default profile should be selected instead of showing the manager. +static int getProfileAutoRun(char * szProfile, size_t cch, char * profiledir) +{ + char Mgr[32]; + char env_profile[MAX_PATH]; + char exp_profile[MAX_PATH]; + GetPrivateProfileStringA("Database", "ShowProfileMgr", "", Mgr, SIZEOF(Mgr), mirandabootini); + if ( lstrcmpiA(Mgr,"never") ) return 0; + GetPrivateProfileStringA("Database", "DefaultProfile", "", env_profile, SIZEOF(env_profile), mirandabootini); + if ( lstrlenA(env_profile) == 0 ) return 0; + ExpandEnvironmentStringsA(env_profile, exp_profile, SIZEOF(exp_profile)); + mir_snprintf(szProfile, cch, "%s\\%s.dat", profiledir, exp_profile); + return 1; +} + + + +// returns 1 if a profile was selected +static int getProfile(char * szProfile, size_t cch) +{ + char profiledir[MAX_PATH]; + PROFILEMANAGERDATA pd; + ZeroMemory(&pd,sizeof(pd)); + getProfilePath(profiledir,SIZEOF(profiledir)); + if ( getProfileCmdLine(szProfile, cch, profiledir) ) return 1; + if ( getProfileAutoRun(szProfile, cch, profiledir) ) return 1; + if ( !showProfileManager() && getProfile1(szProfile, cch, profiledir, &pd.noProfiles) ) return 1; + else { + pd.szProfile=szProfile; + pd.szProfileDir=profiledir; + return getProfileManager(&pd); + } +} + +// called by the UI, return 1 on success, use link to create profile, set error if any +int makeDatabase(char * profile, DATABASELINK * link, HWND hwndDlg) +{ + char buf[256]; + int err=0; + // check if the file already exists + HANDLE hFile=CreateFileA(profile, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + char * file = strrchr(profile,'\\'); + file++; + if ( hFile != INVALID_HANDLE_VALUE ) { + CloseHandle(hFile); + mir_snprintf(buf, SIZEOF(buf), Translate("The profile '%s' already exists. Do you want to move it to the " + "Recycle Bin? \n\nWARNING: The profile will be deleted if Recycle Bin is disabled.\nWARNING: A profile may contain confidential information and should be properly deleted."),file); + // file already exists! + if ( MessageBoxA(hwndDlg, buf, Translate("The profile already exists"), MB_ICONQUESTION|MB_YESNO|MB_DEFBUTTON2) != IDYES ) return 0; + // move the file + { + char szName[MAX_PATH]; // SHFileOperation needs a "double null" + SHFILEOPSTRUCTA sf; + ZeroMemory(&sf,sizeof(sf)); + sf.wFunc=FO_DELETE; + sf.pFrom=szName; + sf.fFlags=FOF_NOCONFIRMATION|FOF_NOERRORUI|FOF_SILENT; + mir_snprintf(szName, SIZEOF(szName),"%s\0",profile); + if ( SHFileOperationA(&sf) != 0 ) { + mir_snprintf(buf, SIZEOF(buf),Translate("Couldn't move '%s' to the Recycle Bin, Please select another profile name."),file); + MessageBoxA(0,buf,Translate("Problem moving profile"),MB_ICONINFORMATION|MB_OK); + return 0; + } + } + // now the file should be gone! + } + // ask the database to create the profile + if ( link->makeDatabase(profile,&err) ) { + mir_snprintf(buf, SIZEOF(buf),Translate("Unable to create the profile '%s', the error was %x"),file, err); + MessageBoxA(hwndDlg,buf,Translate("Problem creating profile"),MB_ICONERROR|MB_OK); + return 0; + } + // the profile has been created! woot + return 1; +} + +// enumerate all plugins that had valid DatabasePluginInfo() +static int FindDbPluginForProfile(char * pluginname, DATABASELINK * dblink, LPARAM lParam) +{ + char * szProfile = (char *) lParam; + if ( dblink && dblink->cbSize == sizeof(DATABASELINK) ) { + int err=0; + int rc=0; + // liked the profile? + rc=dblink->grokHeader(szProfile,&err); + if ( rc == 0 ) { + // added APIs? + if ( dblink->Load(szProfile, &pluginCoreLink) == 0 ) return DBPE_DONE; + return DBPE_HALT; + } else { + switch ( err ) { + case EGROKPRF_CANTREAD: + case EGROKPRF_UNKHEADER: + { + // just not supported. + return DBPE_CONT; + } + case EGROKPRF_VERNEWER: + case EGROKPRF_DAMAGED: + { + break; + } + } + return DBPE_HALT; + } //if + } + return DBPE_CONT; +} + +typedef struct { + char * profile; + UINT msg; + ATOM aPath; + int found; +} ENUMMIRANDAWINDOW; + +static BOOL CALLBACK EnumMirandaWindows(HWND hwnd, LPARAM lParam) +{ + TCHAR classname[256]; + ENUMMIRANDAWINDOW * x = (ENUMMIRANDAWINDOW *)lParam; + DWORD 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(char * szProfile) +{ + ENUMMIRANDAWINDOW x={0}; + x.profile=szProfile; + x.msg=RegisterWindowMessage( _T( "Miranda::ProcessProfile" )); + x.aPath=GlobalAddAtomA(szProfile); + EnumWindows(EnumMirandaWindows, (LPARAM)&x); + GlobalDeleteAtom(x.aPath); + return x.found; +} + +int LoadDatabaseModule(void) +{ + int iReturn = 0; + char szProfile[MAX_PATH]; + szProfile[0]=0; + + // load the older basic services of the db + InitTime(); + + // find out which profile to load + if ( getProfile(szProfile, SIZEOF(szProfile)) ) + { + int rc; + PLUGIN_DB_ENUM dbe; + + dbe.cbSize=sizeof(PLUGIN_DB_ENUM); + dbe.pfnEnumCallback=( int(*) (char*,void*,LPARAM) )FindDbPluginForProfile; + dbe.lParam=(LPARAM)szProfile; + + // find a driver to support the given profile + rc=CallService(MS_PLUGINS_ENUMDBPLUGINS, 0, (LPARAM)&dbe); + switch ( rc ) { + case -1: { + // no plugins at all + char buf[256]; + char * p = strrchr(szProfile,'\\'); + mir_snprintf(buf,SIZEOF(buf),Translate("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 ); + MessageBoxA(0,buf,Translate("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 + HANDLE hFile; + hFile=CreateFileA(szProfile,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL); + if ( hFile == INVALID_HANDLE_VALUE ) { + if ( !FindMirandaForProfile(szProfile) ) { + // file is locked, tried to find miranda window, but that failed too. + } + } else { + // file isn't locked, just no driver could open it. + char buf[256]; + char * p = strrchr(szProfile,'\\'); + mir_snprintf(buf,SIZEOF(buf),Translate("Miranda was unable to open '%s', its in an unknown format.\nThis profile might also be damaged, please run DB-tool which should be installed."), p ? ++p : szProfile); + MessageBoxA(0,buf,Translate("Miranda can't understand that profile"),MB_OK | MB_ICONERROR); + CloseHandle(hFile); + } + break; + } + } + iReturn = (rc != 0); + } + else + { + iReturn = 1; + } + + return iReturn; +} + -- cgit v1.2.3