/* (C) 2003-2007 Willem Jan Hengeveld * Web: http://www.xs4all.nl/~itsme/ * http://wiki.xda-developers.com/ * * $Id: $ */ #define EDB 1 #include #include "PoomInterface.h" #include "vectorutils.h" #include "PoomRecordManager.h" #include #include "ptrutils.h" const FieldInfo gfi; typedef BOOL (*FN_CeMountDBVolEx)( PCEGUID pGuid, LPWSTR lpwszDBVol, CEVOLUMEOPTIONS* pOptions, DWORD dwFlags); typedef HANDLE (*FN_CeOpenDatabaseInSession)( HANDLE hSession, PCEGUID pGuid, PCEOID poid, LPWSTR lpwszName, SORTORDERSPECEX* pSort, DWORD dwFlags, CENOTIFYREQUEST* pRequest); typedef BOOL (*FN_CeGetDatabaseProps)( IN HANDLE hHandle, INOUT WORD* pcPropId, IN CEPROPID* prgPropId, OUT CEPROPSPEC* prgProps); void DumpDatabaseInfo(CEOID oid, CEDBASEINFOEX *dbi) { debug("database %08lx: F%08lx T%08lx %4d %6d ... '%ls'\n", oid, dbi->dwFlags, dbi->dwDbaseType, dbi->dwNumRecords, dbi->dwSize, /* ftLastModified, wNumSortOrder, rgSortSpecs */ dbi->szDbaseName); if (dbi->wNumSortOrder) { debug(" ORDERING:"); for (int i=0 ; iwNumSortOrder ; i++) { debug(" %d:%x={", dbi->rgSortSpecs[i].wVersion, dbi->rgSortSpecs[i].wKeyFlags); for (int j=0 ; jrgSortSpecs[i].wNumProps ; j++) { if (j) debug(", "); debug("%08lx:%08lx", dbi->rgSortSpecs[i].rgPropID[j], dbi->rgSortSpecs[i].rgdwFlags[j]); } debug("}"); } debug("\n"); } } class CeDatabase { public: CeDatabase() : _bMounted(false), _hDb(NULL), _dboid(NULL), _hLib(NULL) { memset(&_mvolguid, 0, sizeof(CEGUID)); LoadEDBFunctions(); } ~CeDatabase() { close(); UnloadEDBFunctions(); } bool LoadEDBFunctions() { HINSTANCE _hLib; _hLib= LoadLibrary(_T("coredll.dll")); if (_hLib==NULL || _hLib==INVALID_HANDLE_VALUE) { error("LoadLibrary(coredll.dll)"); return false; } CeMountDBVolEx= (FN_CeMountDBVolEx)GetProcAddress(_hLib, L"CeMountDBVolEx"); if (CeMountDBVolEx==NULL) CeMountDBVolEx= &MyCeMountDBVolEx; CeOpenDatabaseInSession= (FN_CeOpenDatabaseInSession)GetProcAddress(_hLib, L"CeOpenDatabaseInSession"); if (CeOpenDatabaseInSession==NULL) CeOpenDatabaseInSession= &MyCeOpenDatabaseInSession; CeGetDatabaseProps= (FN_CeGetDatabaseProps)GetProcAddress(_hLib, L"CeGetDatabaseProps"); if (CeGetDatabaseProps==NULL) CeGetDatabaseProps= &MyCeGetDatabaseProps; return true; } static BOOL MyCeMountDBVolEx( PCEGUID pGuid, LPWSTR lpwszDBVol, CEVOLUMEOPTIONS* pOptions, DWORD dwFlags) { CREATE_INVALIDGUID(pGuid); return TRUE; } static HANDLE MyCeOpenDatabaseInSession( HANDLE hSession, PCEGUID pGuid, PCEOID poid, LPWSTR lpwszName, SORTORDERSPECEX* pSort, DWORD dwFlags, CENOTIFYREQUEST* pRequest) { return CeOpenDatabaseEx2(pGuid, poid, lpwszName, pSort, dwFlags, pRequest); } static BOOL MyCeGetDatabaseProps(IN HANDLE hHandle, INOUT WORD* pcPropId, IN CEPROPID* prgPropId, OUT CEPROPSPEC* prgProps) { SetLastError(0x57); return FALSE; } bool UnloadEDBFunctions() { FreeLibrary(_hLib); return true; } bool open(const std::Wstring& volname, const std::Wstring& dbname) { _bMounted= 0!=CeMountDBVolEx(&_mvolguid, const_cast(volname.c_str()), NULL, OPEN_EXISTING); if (!_bMounted) { error("CeMountDBVolEx(v:%ls)", const_cast(volname.c_str())); memset(&_mvolguid, 0, sizeof(CEGUID)); } _hDb= CeOpenDatabaseInSession(NULL, &_mvolguid, &_dboid, const_cast(dbname.c_str()), 0, CEDB_AUTOINCREMENT, NULL); if (_hDb==INVALID_HANDLE_VALUE || _hDb==NULL) { error("CeOpenDatabaseInSession(v:%ls, d:%ls)", volname.c_str(), const_cast(dbname.c_str())); return false; } return true; } bool close() { if (_hDb!=INVALID_HANDLE_VALUE && _hDb!=NULL) { CloseHandle(_hDb); _hDb= NULL; } if (_bMounted) CeUnmountDBVol(&_mvolguid); _bMounted= false; memset(&_mvolguid, 0, sizeof(CEGUID)); return true; } bool read(Record& rec) { BYTE *lpBuffer= NULL; DWORD nBufferSize= 0; WORD nProperties=0; CEOID oid= CeReadRecordPropsEx(_hDb, CEDB_ALLOWREALLOC, &nProperties, NULL, (BYTE**)&lpBuffer, &nBufferSize, NULL); if (oid==0) { error("CeReadRecordPropsEx"); return false; } if (nProperties*sizeof(CEPROPVAL)>nBufferSize) { debug("WARNING NOTE: np*sizeof(pv)= %d*%d > %d\n", nProperties, sizeof(CEPROPVAL), nBufferSize); debug("%s\n", hexdump(lpBuffer, nBufferSize).c_str()); } if (!rec.ParseFromPropval((const CEPROPVAL*)lpBuffer, nProperties)) return false; return true; } bool update(DWORD updoid, const Record& rec, DWORD *poid) { ByteVector propval; DWORD nProperties; if (!rec.EncodeAsPropval(propval, &nProperties)) { debug("error encoding as propval\n"); return false; } debug("update encoded as propval\n"); CEOID newoid= CeWriteRecordProps(_hDb, updoid, nProperties, (CEPROPVAL*)vectorptr(propval)); if (newoid==0) { error("CeWriteRecordProps(oid=%08lx, n=%d)", updoid, nProperties); return false; } *poid= newoid; return true; } bool seek(DWORD seekoid) { DWORD index=0; CEOID oid= CeSeekDatabaseEx(_hDb, CEDB_SEEK_CEOID, seekoid, 0, NULL/*&index*/); if (oid==0) { error("CeSeekDatabaseEx(oid=%08lx)", seekoid); return false; } debug("oid %08lx -> oid=%08lx, index=%08lx\n", seekoid, oid, index); return true; } bool del(CEOID recid) { if (!CeDeleteRecord(_hDb, recid)) { error("CeDeleteRecord"); return false; } return true; } bool query(DwordVector& oidlist) { CEOID oid= CeSeekDatabaseEx(_hDb, CEDB_SEEK_BEGINNING, 0, 0, NULL); while (oid) { oidlist.push_back(oid); oid= CeSeekDatabaseEx(_hDb, CEDB_SEEK_CURRENT, 1, 0, NULL); } if (oid==0) { if (GetLastError()==ERROR_SEEK) return true; error("CeSeekDatabaseEx(begin/current+1)- got %d items", oidlist.size()); return false; } return true; } bool dumpinfo() { BY_HANDLE_DB_INFORMATION dbhi; memset(&dbhi, 0, sizeof(dbhi)); dbhi.wVersion= BY_HANDLE_DB_INFORMATION_VERSION; if (!CeGetDBInformationByHandle(_hDb, &dbhi)) { dbhi.wVersion= BY_HANDLE_DB_INFORMATION_VERSION-1; if (!CeGetDBInformationByHandle(_hDb, &dbhi)) { dbhi.oidDbase= 0; error("CeGetDBInformationByHandle(%08lx)", _dboid); return false; } else { debug("!!! database version 1\n"); } } if (dbhi.oidDbase) DumpDatabaseInfo(_dboid, &dbhi.infDatabase); else debug("database %08lx\n", _dboid); return true; } bool dumpspec() { WORD propcount=0; if (!CeGetDatabaseProps(_hDb, &propcount, NULL, NULL)) { error("CeGetDatabaseProps(getcount)"); return false; } ByteVector bvProps; bvProps.resize(propcount*sizeof(CEPROPSPEC)); CEPROPSPEC *pspec= (CEPROPSPEC*)vectorptr(bvProps); int i; for (i=0 ; iwVersion= CEPROPSPEC_VERSION; if (!CeGetDatabaseProps(_hDb, &propcount, NULL, (CEPROPSPEC*)vectorptr(bvProps))) { error("CeGetDatabaseProps(getspec)"); return false; } pspec= (CEPROPSPEC*)vectorptr(bvProps); for (i=0 ; iwVersion, pspec->propid, pspec->dwFlags, pspec->pwszPropName); } return true; } private: bool _bMounted; CEGUID _mvolguid; CEOID _dboid; HANDLE _hDb; HINSTANCE _hLib; FN_CeMountDBVolEx CeMountDBVolEx; FN_CeOpenDatabaseInSession CeOpenDatabaseInSession; FN_CeGetDatabaseProps CeGetDatabaseProps; }; bool POOMAddRecord(DWORD dwDatabase, const Record& rec, DWORD *poid) { CeDatabase db; if (!db.open(L"\\pim.vol", L"Contacts Database")) return false; if (!db.update(0, rec, poid)) { debug("rec.add: error in db.update\n"); return false; } return true; } bool POOMGetRecord(DWORD dwDatabase, DWORD oid, Record& rec) { CeDatabase db; if (!db.open(L"\\pim.vol", L"Contacts Database")) return false; if (!db.seek(oid)) return false; if (!db.read(rec)) return false; return true; } bool POOMDelRecord(DWORD dwDatabase, DWORD oid) { CeDatabase db; if (!db.open(L"\\pim.vol", L"Contacts Database")) return false; if (!db.del(oid)) return false; return true; } bool POOMFindRecords(DWORD dwDatabase, const Query& query, DwordVector& oids) { CeDatabase db; if (!db.open(L"\\pim.vol", L"Contacts Database")) return false; //db.dumpinfo(); //db.dumpspec(); if (!db.query(oids)) return false; return true; } ITSUTILS_API HRESULT STDAPICALLTYPE IT_POOM_AddRecord( DWORD cbInput, AddRecordParams *pbInput, DWORD *pcbOutput, AddRecordResult **ppbOutput, IRAPIStream *pStream) { *pcbOutput= 0; *ppbOutput= NULL; DWORD res= 0; debug("poom-parsing\n"); Record rec; if (!rec.ParseFromByteVector(ByteVector(&pbInput->data[0], (BYTE*)pbInput+cbInput))) res= 1; else { DWORD oid; debug("poom-adding\n"); rec.dump(); if (!POOMAddRecord(pbInput->dwDatabase, rec, &oid)) res= 2; else { debug("poom-adding done->%08lx\n", oid); *pcbOutput= sizeof(AddRecordResult); AddRecordResult *pOut= *ppbOutput= (AddRecordResult*)LocalAlloc(LPTR, *pcbOutput); pOut->oid= oid; } } return res; } ITSUTILS_API HRESULT STDAPICALLTYPE IT_POOM_GetRecord( DWORD cbInput, GetRecordParams *pbInput, DWORD *pcbOutput, GetRecordResult **ppbOutput, IRAPIStream *pStream) { *pcbOutput= 0; *ppbOutput= NULL; DWORD res= 0; Record rec; if (!POOMGetRecord(pbInput->dwDatabase, pbInput->oid, rec)) res= 1; else { ByteVector brec; rec.EncodeAsByteVector(brec); *pcbOutput= brec.size(); GetRecordResult *pOut= *ppbOutput= (GetRecordResult*)LocalAlloc(LPTR, *pcbOutput); memcpy(pOut->data, vectorptr(brec), brec.size()); } return res; } ITSUTILS_API HRESULT STDAPICALLTYPE IT_POOM_FindRecords( DWORD cbInput, FindRecordsParams *pbInput, DWORD *pcbOutput, FindRecordsResult **ppbOutput, IRAPIStream *pStream) { *pcbOutput= 0; *ppbOutput= NULL; DWORD res= 0; Query query; if (!query.ParseFromByteVector(ByteVector(&pbInput->query[0], (BYTE*)pbInput+cbInput))) res= 1; else { DwordVector oids; if (!POOMFindRecords(pbInput->dwDatabase, query, oids)) res= 2; else { FindRecordsResult *pOut=NULL; *pcbOutput= PTR_DIFF(pOut, &(pOut->list[oids.size()])); debug("POOMFindRecords->%d -> %08lx\n", oids.size(), *pcbOutput); pOut= *ppbOutput= (FindRecordsResult*)LocalAlloc(LPTR, *pcbOutput); memcpy(pOut->list, vectorptr(oids), oids.size()*sizeof(DWORD)); } } return res; } ITSUTILS_API HRESULT STDAPICALLTYPE IT_POOM_DelRecord( DWORD cbInput, DelRecordParams *pbInput, DWORD *pcbOutput, DelRecordResult **ppbOutput, IRAPIStream *pStream) { *pcbOutput= 0; *ppbOutput= NULL; DWORD res= 0; if (!POOMDelRecord(pbInput->dwDatabase, pbInput->oid)) res= 1; return res; }