|
|
////////////////////////////////////////////////////////////////////////////////
///
///
/// MPSWAB.C
///
/// Microsoft Property Store - WAB Dll
///
/// Contains implementations of File managment functions
///
/// Exposed Functions:
/// OpenPropertyStore
/// ClosePropertyStore
/// BackupPropertyStore
/// LockPropertyStore
/// UnlockPropertyStore
/// ReadRecord
/// WriteRecord
/// FindRecords
/// DeleteRecords
/// ReadIndex
/// ReadPropArray
/// HrFindFuzzyRecordMatches
///
/// Private:
/// UnlockFileAccess
/// LockFileAccess
/// ReloadMPSWabFileInfoTmp
/// bTagWriteTransaction
/// bUntagWriteTransaction
///
/////////////////////////////////////////////////////////////////////////////////
#include "_apipch.h"
BOOL fTrace = TRUE; BOOL fDebugTrap = FALSE; TCHAR szDebugOutputFile[MAX_PATH] = TEXT("");
BOOL bUntagWriteTransaction(LPMPSWab_FILE_HEADER lpMPSWabFileHeader, HANDLE hMPSWabFile);
BOOL bTagWriteTransaction(LPMPSWab_FILE_HEADER lpMPSWabFileHeader, HANDLE hMPSWabFile);
HRESULT GetFolderEIDs(HANDLE hMPSWabFile, LPMPSWab_FILE_INFO lpMPSWabFileInfo, LPSBinary pmbinFold, ULONG * lpulFolderEIDs, LPDWORD * lppdwFolderEIDs);
BOOL bIsFolderMember(HANDLE hMPSWabFile, LPMPSWab_FILE_INFO lpMPSWabFileInfo, DWORD dwEntryID, ULONG * lpulObjType);
extern int nCountSubStrings(LPTSTR lpszSearchStr);
//$$//////////////////////////////////////////////////////////////
//
// OpenPropertyStore - searches for Property Store and or creates it
// based on flags.
//
// IN - lpszFileName - file name specified by client
// IN - ulFlags - AB_CREATE_NEW
// AB_CREATE_ALWAYS
// AB_OPEN_ALWAYS
// AB_OPEN_EXISTING
// AB_READ_ONLY
// AB_SET_DEFAULT (?)
// AB_DONT_RESTORE
// IN - hWnd - In the event of data corruption, use this hWnd for a message box
// if it exists, or show the message box on the desktop window
// OUT- lphPropertyStore - Handle to opened property store
//
// This routine also scans the file and attempts to fix errors if it finds any.
// including recovering from backup. When opening the file with OpenPropertyStore
// specify AB_DONT_RESTORE to prevent the restoration operation
// This should especially be done when opening files that are not the default
// property store.
//
// Return Value:
// HRESULT -
// S_OK Success
// E_FAIL Failure
//
////////////////////////////////////////////////////////////////
HRESULT OpenPropertyStore( IN LPTSTR lpszFileName, IN ULONG ulFlags, IN HWND hWnd, OUT LPHANDLE lphPropertyStore) { HRESULT hr = E_FAIL; HANDLE hMPSWabFile = NULL; ULONG i=0,j=0; DWORD dwNumofBytes = 0; WIN32_FIND_DATA FileData; DWORD dwIndexBlockSize = 0; LPTSTR lpszBuffer = NULL; BOOL bFileLocked = FALSE; ULONG cchSize;
//
// the following pointer will be returned back as the handle to the property store
//
LPMPSWab_FILE_INFO lpMPSWabFileInfo = NULL;
LPPTGDATA lpPTGData=GetThreadStoragePointer();
if(!lphPropertyStore) { hr = MAPI_E_INVALID_PARAMETER; goto out; }
// A file name overrides an outlook session
if(pt_bIsWABOpenExSession && !(ulFlags & AB_IGNORE_OUTLOOK)) { // This is a WABOpenEx session using outlooks storage provider
if(!lpfnWABOpenStorageProvider) return MAPI_E_NOT_INITIALIZED;
{ LPWABSTORAGEPROVIDER lpWSP = NULL;
hr = lpfnWABOpenStorageProvider(hWnd, pmsessOutlookWabSPI, lpfnAllocateBufferExternal ? lpfnAllocateBufferExternal : (LPALLOCATEBUFFER) (MAPIAllocateBuffer), lpfnAllocateMoreExternal ? lpfnAllocateMoreExternal : (LPALLOCATEMORE) (MAPIAllocateMore), lpfnFreeBufferExternal ? lpfnFreeBufferExternal : MAPIFreeBuffer, 0, &lpWSP);
DebugTrace(TEXT("Outlook WABOpenStorageProvider returned:%x\n"),hr);
if(HR_FAILED(hr)) return hr;
(*lphPropertyStore) = (HANDLE) lpWSP;
return(hr); } }
lpMPSWabFileInfo = LocalAlloc(LMEM_ZEROINIT,sizeof(MPSWab_FILE_INFO));
if (!lpMPSWabFileInfo) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; }
DebugTrace(( TEXT("-----------\nOpenPropertyStore: Entry\n")));
lpMPSWabFileInfo->hDataAccessMutex = CreateMutex(NULL,FALSE,TEXT("MPSWabDataAccessMutex"));
if(!LockFileAccess(lpMPSWabFileInfo)) { DebugTrace(TEXT("LockFileAccess Failed\n")); hr = MAPI_E_NO_ACCESS; goto out; } else { bFileLocked = TRUE; }
//
// Initialize
//
lpMPSWabFileInfo->lpMPSWabFileHeader = NULL; lpMPSWabFileInfo->lpszMPSWabFileName = NULL; lpMPSWabFileInfo->lpMPSWabIndexStr = NULL; lpMPSWabFileInfo->lpMPSWabIndexEID = NULL;
*lphPropertyStore = NULL;
//
// No file name ???
//
if (lpszFileName == NULL) goto out;
//
// Allocate space for the file header
//
lpMPSWabFileInfo->lpMPSWabFileHeader = LocalAlloc(LMEM_ZEROINIT,sizeof(MPSWab_FILE_HEADER));
if (!lpMPSWabFileInfo->lpMPSWabFileHeader) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; }
//
// retain file name for future use
//
cchSize = lstrlen(lpszFileName) + 1; lpMPSWabFileInfo->lpszMPSWabFileName = (LPTSTR) LocalAlloc(LMEM_ZEROINIT,sizeof(TCHAR)*cchSize);
if (!lpMPSWabFileInfo->lpszMPSWabFileName) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; }
StrCpyN(lpMPSWabFileInfo->lpszMPSWabFileName,lpszFileName,cchSize);
if(((ulFlags & AB_OPEN_ALWAYS)) || ((ulFlags & AB_OPEN_EXISTING))) { //
// If file exists, open it - if it doesnt exist, create a new one
//
hMPSWabFile = FindFirstFile(lpMPSWabFileInfo->lpszMPSWabFileName, &FileData); if (hMPSWabFile == INVALID_HANDLE_VALUE) { //
// File Not Found
//
if ((ulFlags & AB_OPEN_ALWAYS)) { //
// create a new one
//
if (!CreateMPSWabFile( IN lpMPSWabFileInfo->lpMPSWabFileHeader, IN lpMPSWabFileInfo->lpszMPSWabFileName, IN MAX_INITIAL_INDEX_ENTRIES, IN NAMEDPROP_STORE_SIZE)) { DebugTrace(TEXT("Could Not Create File %s!\n"),lpMPSWabFileInfo->lpszMPSWabFileName); goto out; } } else { //
// Nothing to do .. exit
//
goto out; } } else { // found the file ... just close the handle ...
FindClose(hMPSWabFile); hMPSWabFile = NULL; } } else if (((ulFlags & AB_CREATE_NEW)) || ((ulFlags & AB_CREATE_ALWAYS))) { //
// Create a new file - overwrite any existing file
//
if ((ulFlags & AB_CREATE_NEW)) { hMPSWabFile = FindFirstFile(lpMPSWabFileInfo->lpszMPSWabFileName, &FileData); if (hMPSWabFile != INVALID_HANDLE_VALUE) { //
// Dont overwrite if flag is CREATE_NEW
//
DebugTrace(TEXT("Specified file %s found\n"),lpMPSWabFileInfo->lpszMPSWabFileName); hr = MAPI_E_NOT_FOUND;
//Close the handle since we dont need it
FindClose(hMPSWabFile); hMPSWabFile = NULL;
goto out; } }
//
// Create a new one ... over-write if neccessary
//
if (!CreateMPSWabFile( IN lpMPSWabFileInfo->lpMPSWabFileHeader, IN lpMPSWabFileInfo->lpszMPSWabFileName, IN MAX_INITIAL_INDEX_ENTRIES, IN NAMEDPROP_STORE_SIZE)) { DebugTrace(TEXT("Could Not Create File %s!\n"),lpMPSWabFileInfo->lpszMPSWabFileName); goto out; } }
//
// Now we have a valid file, even though the file is new ... load the structures from the file
//
//
// check that we have a valid hWnd if we need to show message boxes
//
if (hWnd == NULL) hWnd = GetDesktopWindow();
// reentrancy point for bug 16681
TryOpeningWABFileOnceAgain:
//
// Open the file
//
hr = OpenWABFile(lpMPSWabFileInfo->lpszMPSWabFileName, NULL, &hMPSWabFile);
if ( (hMPSWabFile == INVALID_HANDLE_VALUE) || HR_FAILED(hr)) { DebugTrace(TEXT("Could not open file.\nExiting ...\n")); goto out; }
// Verify the WAB version, and migrate the file from an old version
// to a new version if required
hr = HrVerifyWABVersionAndUpdate( hWnd, hMPSWabFile, lpMPSWabFileInfo); if(HR_FAILED(hr)) { //
// Bug 16681:
// Check the special case error for the blank-wab problem
// If this error exists, then rename to file to *.w-b
// and try creating a new wab file or restoring from
// backup ...
if(hr == MAPI_E_VERSION) { TCHAR szSaveAsFileName[MAX_PATH]; ULONG nLen = lstrlen(lpMPSWabFileInfo->lpszMPSWabFileName); StrCpyN(szSaveAsFileName, lpMPSWabFileInfo->lpszMPSWabFileName, ARRAYSIZE(szSaveAsFileName));
szSaveAsFileName[nLen-2]='\0'; StrCatBuff(szSaveAsFileName, TEXT("~b"), ARRAYSIZE(szSaveAsFileName));
DeleteFile(szSaveAsFileName); //just in case it exists
DebugTrace(TEXT("Blank WAB file found. Being saved as %s\n"), szSaveAsFileName);
if (hMPSWabFile && INVALID_HANDLE_VALUE != hMPSWabFile) { IF_WIN32(CloseHandle(hMPSWabFile);) IF_WIN16(CloseFile(hMPSWabFile);) hMPSWabFile = NULL; }
if(!MoveFile(lpMPSWabFileInfo->lpszMPSWabFileName, szSaveAsFileName)) { // Just in case MoveFile failed,
if(!DeleteFile(lpMPSWabFileInfo->lpszMPSWabFileName)) { // and if delete file failed too, we dont want to get
// caught in a loop so exit ..
goto out; } } hr = E_FAIL;
goto TryOpeningWABFileOnceAgain; }
// There is a catch here that if the GUID of the file is mangled
// we will never be able to access the file with the WAB
DebugTrace(TEXT("hrVerifyWABVersionAndUpdate failed: %x\n"), hr); goto out; // else fall through
}
if(lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags == WAB_CLEAR) { // so it is a wab file - if there are no errors tagged to a quick check
hr = HrDoQuickWABIntegrityCheck(lpMPSWabFileInfo, hMPSWabFile); if (HR_FAILED(hr)) DebugTrace(TEXT("HrDoQuickWABIntegrityCheck failed:%x\n"),hr); else { // Reload whatever new info we added as a result of the above.
if(!ReloadMPSWabFileInfo( lpMPSWabFileInfo, hMPSWabFile)) { DebugTrace(TEXT("Reading file info failed.\n")); hr = E_FAIL; } } }
// if the quick check failed or some errors are tagged then rebuild the
// indexes
if( (HR_FAILED(hr)) || (lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags & WAB_ERROR_DETECTED) || (lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags & WAB_WRITE_IN_PROGRESS) ) { hr = HrDoDetailedWABIntegrityCheck(lpMPSWabFileInfo,hMPSWabFile); if(HR_FAILED(hr)) { DebugTrace(TEXT("HrDoDetailedWABIntegrityCheck failed:%x\n"),hr); if(hr == MAPI_E_CORRUPT_DATA) { if (ulFlags & AB_DONT_RESTORE) { goto out; } else { // Restore from Backup
ShowMessageBoxParam(hWnd, idsWABIntegrityError, MB_ICONHAND | MB_OK, lpMPSWabFileInfo->lpszMPSWabFileName);
hr = HrRestoreFromBackup(lpMPSWabFileInfo, hMPSWabFile); if(!HR_FAILED(hr)) ShowMessageBox(NULL, idsWABRestoreSucceeded, MB_OK | MB_ICONEXCLAMATION); else { ShowMessageBoxParam(NULL, idsWABUnableToRestoreBackup, MB_ICONHAND | MB_OK, lpMPSWabFileInfo->lpszMPSWabFileName); goto out; } } } else goto out; } }
lpMPSWabFileInfo->bReadOnlyAccess = ((ulFlags & AB_OPEN_READ_ONLY)) ? TRUE : FALSE;
hr = S_OK;
out:
//
// Cleanup
//
if (hMPSWabFile && INVALID_HANDLE_VALUE != hMPSWabFile) IF_WIN32(CloseHandle(hMPSWabFile);) IF_WIN16(CloseFile(hMPSWabFile);)
if (!(FAILED(hr))) { lpMPSWabFileInfo->bMPSWabInitialized = TRUE; *lphPropertyStore = (HANDLE) lpMPSWabFileInfo; } else { LocalFreeAndNull(&lpMPSWabFileInfo->lpMPSWabFileHeader);
LocalFreeAndNull(&lpMPSWabFileInfo->lpszMPSWabFileName);
LocalFreeAndNull(&lpMPSWabFileInfo->lpMPSWabIndexStr);
LocalFreeAndNull(&lpMPSWabFileInfo->lpMPSWabIndexEID);
//Close our handle on this mutex
CloseHandle(lpMPSWabFileInfo->hDataAccessMutex);
LocalFreeAndNull(&lpMPSWabFileInfo); }
if (bFileLocked) UnLockFileAccess(lpMPSWabFileInfo);
DebugTrace(( TEXT("OpenPropertyStore: Exit\n-----------\n")));
return(hr); }
//$$//////////////////////////////////////////////////////////////////////////////////
//
// ClosePropertyStore
//
// IN hPropertyStore - handle to property store
// IN ulFlags - AB_DONT_BACKUP prevents automatic backup. Should be called for
// for non-default property stores.
//
// Returns
// Success: S_OK
// Failure: E_FAIL
//
////////////////////////////////////////////////////////////////////////////////////
HRESULT ClosePropertyStore(HANDLE hPropertyStore, ULONG ulFlags) { HRESULT hr = E_FAIL; TCHAR szBackupFileName[MAX_PATH];
LPMPSWab_FILE_INFO lpMPSWabFileInfo = NULL;
LPPTGDATA lpPTGData=GetThreadStoragePointer();
DebugTrace(( TEXT("-----------\nClosePropertyStore: Entry\n")));
if(pt_bIsWABOpenExSession && !(ulFlags & AB_IGNORE_OUTLOOK)) { // This is a WABOpenEx session using outlooks storage provider
// Dont need to do anything in here ...
if(!hPropertyStore) return MAPI_E_NOT_INITIALIZED;
return S_OK; }
lpMPSWabFileInfo = hPropertyStore;
if (NULL == lpMPSWabFileInfo) goto out;
if(!(ulFlags & AB_DONT_BACKUP)) { szBackupFileName[0]='\0';
GetWABBackupFileName(lpMPSWabFileInfo->lpszMPSWabFileName,szBackupFileName,ARRAYSIZE(szBackupFileName));
if(lstrlen(szBackupFileName)) { //
// We do a backup operation here and some cleanup
//
hr = BackupPropertyStore( hPropertyStore, szBackupFileName); if(HR_FAILED(hr)) { DebugTrace(TEXT("BackupPropertyStore failed: %x\n"),hr); //ignore errors and keep going on with this shutdown ...
} } }
LocalFreeAndNull(&lpMPSWabFileInfo->lpMPSWabFileHeader);
LocalFreeAndNull(&lpMPSWabFileInfo->lpszMPSWabFileName);
LocalFreeAndNull(&lpMPSWabFileInfo->lpMPSWabIndexStr);
LocalFreeAndNull(&lpMPSWabFileInfo->lpMPSWabIndexEID);
//Close our handle on this mutex
CloseHandle(lpMPSWabFileInfo->hDataAccessMutex);
LocalFreeAndNull(&lpMPSWabFileInfo);
hr = S_OK;
out:
DebugTrace(( TEXT("ClosePropertyStore: Exit\n-----------\n")));
return(hr); }
//$$//////////////////////////////////////////////////////////////////////////////////
//
// SetContainerObjectType
//
// In this IE5 WAB, we are saving RECORD_CONTAINER type objects to the WAB store
// However, the previous IE4- wabs dont understand this object and will barf and
// fail. For purposes of backward compatibility, we need to make sure that they
// dont fail - to do this, we mark the object-type of record container objects
// from MAPI_ABCONT to MAPI_MAILUSER - that way a IE4- wab will treat the folder
// as a spurious mail user but wont exactly crash .. we'll let the RecordHeader.ulObjType
// remain as a RECORD_CONTAINER so we can still do quick searches for it
// When reading the object, we will reset the object type in IE5(this) WAB
//
//////////////////////////////////////////////////////////////////////////////////////
void SetContainerObjectType(ULONG ulcProps, LPSPropValue lpProps, BOOL bSetToMailUser) { ULONG i = 0; for(i=0;i<ulcProps;i++) { if(lpProps[i].ulPropTag == PR_OBJECT_TYPE) { lpProps[i].Value.l = bSetToMailUser ? MAPI_MAILUSER : MAPI_ABCONT; break; } } }
//$$//////////////////////////////////////////////////////////////////////////////////
//
// WriteRecord
//
// IN hPropertyStore - handle to property store
// IN pmbinFold - <Outlook> EntryID of folder to search in (NULL for default)
// IN lppsbEID - EntryId of record to write.
// *lppsbEID should be null to create and return new entryID
// IN ulRecordType - RECORD_CONTACT, RECORD_DISTLIST, RECORD_CONTAINER
// IN ulcPropCount - number of props in prop array
// IN lpPropArray - Array of LPSPropValues
// IN ulFlags - reserved - 0
//
// Two cases -
// writing a new record or
// modifying/editing an old record
//
// In the first case we create all the proper header structures and
// tack them onto the end of the file, updating the indexes and the
// file header structure.
//
// In the second case, when record is edited, it could become smaller or larger
// To avoid too much complication, we invalidate the old record header in the file and
// write the edited record to a new location. The accesscount in the file header
// is updated so that after too many edits we can re-write the file to a cleaner
// file. The original entryid is retained and the offset/data updated in the indexes.
//
// Returns
// Success: S_OK
// Failure: E_FAIL
//
////////////////////////////////////////////////////////////////////////////////////
HRESULT WriteRecord(IN HANDLE hPropertyStore, IN LPSBinary pmbinFold, IN LPSBinary * lppsbEID, IN ULONG ulFlags, IN ULONG ulRecordType, IN ULONG ulcPropCount, IN LPPROPERTY_ARRAY lpPropArray) { HRESULT hr = E_FAIL; LPULONG lpPropTagArray = NULL; TCHAR * lpRecordData = NULL; HANDLE hMPSWabFile = NULL; DWORD dwNumofBytes = 0; ULONG ulRecordDataSize = 0; BOOL bIsNewRecord = TRUE; ULONG nIndexPos; ULONG i=0,j=0,k=0; BOOL bFileLocked = FALSE; DWORD dwTempEID = 0; SBinary sbEIDSave = {0}; BOOL bEIDSave = FALSE; ULONG iEIDSave; // index of EID property in lpPropArray
ULONG ulcOldPropCount = 0; LPSPropValue lpOldPropArray = NULL; TCHAR lpszOldIndex[indexMax][MAX_INDEX_STRING]; DWORD dwEntryID = 0; SBinary sbEID = {0}; LPSBinary lpsbEID = NULL;
ULONG ulRecordHeaderOffset = 0; ULONG ulRecordPropTagOffset = 0; ULONG ulRecordDataOffset = 0;
BOOL bPropSet[indexMax]; DWORD dwErr = 0;
ULONG nLen = 0;
LPBYTE lp = NULL;
//
// These structures temporarily hold the new entry info for us
//
MPSWab_INDEX_ENTRY_DATA_STRING MPSWabIndexEntryDataString[indexMax]; MPSWab_INDEX_ENTRY_DATA_ENTRYID MPSWabIndexEntryDataEntryID; MPSWab_RECORD_HEADER MPSWabRecordHeader = {0};
LPMPSWab_FILE_INFO lpMPSWabFileInfo;
LPPTGDATA lpPTGData=GetThreadStoragePointer();
#ifdef DEBUG
// _DebugProperties(lpPropArray, ulcPropCount, TEXT("WriteRecord Properties"));
#endif
if(pt_bIsWABOpenExSession) { // This is a WABOpenEx session using outlooks storage provider
if(!hPropertyStore) return MAPI_E_NOT_INITIALIZED;
{ LPWABSTORAGEPROVIDER lpWSP = (LPWABSTORAGEPROVIDER) hPropertyStore; ULONG cb = 0; LPSPropValue lpNewPropArray = NULL; SCODE sc = 0;
if(!pt_bIsUnicodeOutlook) { // Need to convert these props back to ANSI for Outlook
// Since we don't know whether these props are localalloced or MapiAlloced,
// we can't convert them without leaking memory.
// Therefore, we need to create a copy of the props before we can save them ..
// what a waste of effort ..
// Allocate more for our return buffer
if (FAILED(sc = ScCountProps(ulcPropCount, lpPropArray, &cb))) { hr = ResultFromScode(sc); goto exit; }
if (FAILED(sc = MAPIAllocateBuffer(cb, &lpNewPropArray))) { hr = ResultFromScode(sc); goto exit; }
if (FAILED(sc = ScCopyProps(ulcPropCount, lpPropArray, lpNewPropArray, NULL))) { hr = ResultFromScode(sc); goto exit; }
// Now we thunk the data back to ANSI for Outlook
if (FAILED(sc = ScConvertWPropsToA((LPALLOCATEMORE) (&MAPIAllocateMore), lpNewPropArray, ulcPropCount, 0))) { hr = ResultFromScode(sc); goto exit; } }
hr = lpWSP->lpVtbl->WriteRecord(lpWSP, pmbinFold, lppsbEID, ulFlags, ulRecordType, ulcPropCount, lpNewPropArray ? lpNewPropArray : lpPropArray);
DebugTrace(TEXT("WABStorageProvider::WriteRecord returned:%x\n"),hr); exit: FreeBufferAndNull(&lpNewPropArray);
return hr; } }
lpMPSWabFileInfo = hPropertyStore;
if ( (NULL == lpMPSWabFileInfo) || (NULL == lpPropArray) || (0 == ulcPropCount) ) { DebugTrace(TEXT("Invalid Parameter!!\n")); hr = MAPI_E_INVALID_PARAMETER; goto out; }
if ((ulRecordType != RECORD_CONTACT) && (ulRecordType != RECORD_DISTLIST) && (ulRecordType != RECORD_CONTAINER)) goto out;
if(lppsbEID) { lpsbEID = *lppsbEID; if(lpsbEID && lpsbEID->cb != SIZEOF_WAB_ENTRYID) { // this may be a WAB container .. reset the entryid to a WAB entryid
if(WAB_CONTAINER == IsWABEntryID(lpsbEID->cb, (LPENTRYID)lpsbEID->lpb, NULL,NULL,NULL,NULL,NULL)) { IsWABEntryID(lpsbEID->cb, (LPENTRYID)lpsbEID->lpb, (LPVOID*)&sbEID.lpb,(LPVOID*)&sbEID.cb,NULL,NULL,NULL); if(sbEID.cb == SIZEOF_WAB_ENTRYID) lpsbEID = &sbEID; } } } if(!lppsbEID || (lpsbEID && lpsbEID->cb != SIZEOF_WAB_ENTRYID)) { DebugTrace(TEXT("Invalid Parameter!!\n")); hr = MAPI_E_INVALID_PARAMETER; goto out; }
if(lpsbEID && lpsbEID->cb && lpsbEID->lpb) CopyMemory(&dwEntryID, lpsbEID->lpb, min(lpsbEID->cb, sizeof(dwEntryID)));
DebugTrace(TEXT("--WriteRecord: dwEntryID=%d\n"), dwEntryID);
if (lpMPSWabFileInfo->bReadOnlyAccess) { DebugTrace(TEXT("Access Permissions are Read-Only\n")); hr = MAPI_E_NO_ACCESS; goto out; }
if(!LockFileAccess(lpMPSWabFileInfo)) { DebugTrace(TEXT("LockFileAccess Failed\n")); hr = MAPI_E_NO_ACCESS; goto out; } else { bFileLocked = TRUE; }
if(ulRecordType == RECORD_CONTAINER) SetContainerObjectType(ulcPropCount, lpPropArray, TRUE);
//
// Open the file
//
hr = OpenWABFile(lpMPSWabFileInfo->lpszMPSWabFileName, NULL, &hMPSWabFile);
if ( (hMPSWabFile == INVALID_HANDLE_VALUE) || HR_FAILED(hr)) { DebugTrace(TEXT("Could not open file.\nExiting ...\n")); goto out; }
//
// Check that we have enough disk space before trying any disk writing operations
//
if(!WABHasFreeDiskSpace(lpMPSWabFileInfo->lpszMPSWabFileName, hMPSWabFile)) { hr = MAPI_E_NOT_ENOUGH_DISK; goto out; }
hr = E_FAIL; //reset hr
//
// To ensure that file info is accurate,
// Any time we open a file, read the file info again ...
//
if(!ReloadMPSWabFileInfo( lpMPSWabFileInfo, hMPSWabFile)) { DebugTrace(TEXT("Reading file info failed.\n")); goto out; }
//
// Anytime we detect an error - try to fix it ...
//
if((lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags & WAB_ERROR_DETECTED) || (lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags & WAB_WRITE_IN_PROGRESS)) { if(HR_FAILED(HrDoQuickWABIntegrityCheck(lpMPSWabFileInfo,hMPSWabFile))) { hr = HrDoDetailedWABIntegrityCheck(lpMPSWabFileInfo,hMPSWabFile); if(HR_FAILED(hr)) { DebugTrace(TEXT("HrDoDetailedWABIntegrityCheck failed:%x\n"),hr); goto out; } } }
hr = E_FAIL; //reset hr
//
// If this is an old record, we want to get its old propertys so we can compare the
// indexes to see if any of their values changed ... if the valuse changed then we
// have to update the indexes for the old record too ..
//
if (dwEntryID != 0) { //get pointers to old displayname, firstname, lastname
for(j=indexDisplayName;j<indexMax;j++) { lpszOldIndex[j][0]='\0'; if (!LoadIndex( IN lpMPSWabFileInfo, IN j, IN hMPSWabFile) ) { DebugTrace(TEXT("Error Loading Index!\n")); goto out; } for(i=0;i<lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].ulcNumEntries;i++) { if(lpMPSWabFileInfo->lpMPSWabIndexStr[i].dwEntryID == dwEntryID) { // an old index exists for this entry
// get its value
StrCpyN(lpszOldIndex[j],lpMPSWabFileInfo->lpMPSWabIndexStr[i].szIndex,ARRAYSIZE(lpszOldIndex[j])); break; } } } }
// Tag this file as undergoing a write operation
if(!bTagWriteTransaction( lpMPSWabFileInfo->lpMPSWabFileHeader, hMPSWabFile) ) { DebugTrace(TEXT("Taggin file write failed\n")); goto out; }
//
// Irrespective of whether this is a new record or an old record, the
// data is going to the end of the file ... Get this new file position
//
ulRecordHeaderOffset = GetFileSize(hMPSWabFile, NULL);
if (dwEntryID != 0) { //
// we are not creating a new thing
// so we should first find the old header
// if the old entry doesnt exist then we
// should treat this as a new record and
// replace the entry id with a properly generated
// entryid
// if we find the existing record then we need to mark that as
// being defunct
//
//
// Search for given EntryID
// If not found, assign a new one
//
if (BinSearchEID( IN lpMPSWabFileInfo->lpMPSWabIndexEID, IN dwEntryID, IN lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries, OUT &nIndexPos)) { //
// this entryid exists in the index - we will need to invalidate this record
//
bIsNewRecord = FALSE;
if(!ReadDataFromWABFile(hMPSWabFile, lpMPSWabFileInfo->lpMPSWabIndexEID[nIndexPos].ulOffset, (LPVOID) &MPSWabRecordHeader, (DWORD) sizeof(MPSWab_RECORD_HEADER))) goto out;
//
// Set valid flag to false
//
MPSWabRecordHeader.bValidRecord = FALSE;
//
// Write it back
// Set File Pointer to this record
//
if(!WriteDataToWABFile( hMPSWabFile, lpMPSWabFileInfo->lpMPSWabIndexEID[nIndexPos].ulOffset, (LPVOID) &MPSWabRecordHeader, sizeof(MPSWab_RECORD_HEADER))) goto out;
//
// update the EntryID index so that it now points to the new offset
// instead of the old one
//
lpMPSWabFileInfo->lpMPSWabIndexEID[nIndexPos].ulOffset = ulRecordHeaderOffset;
//
// Increment this count so we know that we invalidated one more record ...
//
lpMPSWabFileInfo->lpMPSWabFileHeader->ulModificationCount++; } else { bIsNewRecord = TRUE; //This tags whether or not to create a new Index entry
//
// assign a new entryid
//
dwEntryID = lpMPSWabFileInfo->lpMPSWabFileHeader->dwNextEntryID++; } } else { //
// we are creating a new thing
//
bIsNewRecord = TRUE;
lpMPSWabFileInfo->lpMPSWabFileHeader->dwNextEntryID++; dwEntryID = lpMPSWabFileInfo->lpMPSWabFileHeader->dwNextEntryID; }
//
// Set the flag so we know when to backup
//
lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags |= WAB_BACKUP_NOW;
//
// if bIsNewRecord, then the PR_ENTRYID field of the record, as passed
// into this function, is 0 and we want to change it to the new Entry ID
// prior to saving so that we can include the new EntryID in the record on file
// Hence we scan the records and update PR_ENTRYID
//
if (bIsNewRecord) { for(i=0;i < ulcPropCount; i++) { if (lpPropArray[i].ulPropTag == PR_ENTRYID) { // Save the value of the property for restoration later
sbEIDSave = lpPropArray[i].Value.bin; iEIDSave = i; bEIDSave = TRUE;
// Assert(! lpPropArray[i].Value.bin.cb);
if (! lpPropArray[i].Value.bin.cb) { // No EntryID pointer... point to a temporary one.
lpPropArray[i].Value.bin.lpb = (LPVOID)&dwTempEID; } CopyMemory(lpPropArray[i].Value.bin.lpb,&dwEntryID,SIZEOF_WAB_ENTRYID); lpPropArray[i].Value.bin.cb = SIZEOF_WAB_ENTRYID; break; } }
}
//
// Now we create a new Record Header structure to write to the file
//
MPSWabRecordHeader.bValidRecord = TRUE; MPSWabRecordHeader.ulObjType = ulRecordType; MPSWabRecordHeader.dwEntryID = dwEntryID; MPSWabRecordHeader.ulcPropCount = ulcPropCount;
//
// write this empty record header to file so we can allocate file space now
// before filling in all the data
//
if(!WriteDataToWABFile( hMPSWabFile, ulRecordHeaderOffset, (LPVOID) &MPSWabRecordHeader, sizeof(MPSWabRecordHeader))) goto out;
//
// Now the File Pointer points to the end of the header which is the
// beginning of the PropTagArray
// ulRecordPropTagOffset is a relative offset from the start of the Record Header
//
ulRecordPropTagOffset = sizeof(MPSWab_RECORD_HEADER);
MPSWabRecordHeader.ulPropTagArraySize = sizeof(ULONG) * ulcPropCount;
//
// Allocate space for the prop tag array
//
lpPropTagArray = LocalAlloc(LMEM_ZEROINIT, MPSWabRecordHeader.ulPropTagArraySize);
if (!lpPropTagArray) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; }
//
// Fill in this array
//
for(i=0;i < ulcPropCount; i++) { lpPropTagArray[i] = lpPropArray[i].ulPropTag; }
//
// write it
//
if(!WriteFile( hMPSWabFile, (LPCVOID) lpPropTagArray, (DWORD) MPSWabRecordHeader.ulPropTagArraySize , &dwNumofBytes, NULL)) { DebugTrace(TEXT("Writing RecordPropArray failed.\n")); goto out; }
ulRecordDataOffset = sizeof(ULONG) * ulcPropCount;
if(HR_FAILED(hr = HrGetBufferFromPropArray(ulcPropCount, lpPropArray, &ulRecordDataSize, &lp))) { goto out; }
MPSWabRecordHeader.ulPropTagArrayOffset = ulRecordPropTagOffset; MPSWabRecordHeader.ulRecordDataOffset = ulRecordDataOffset; MPSWabRecordHeader.ulRecordDataSize = ulRecordDataSize;
//
// update the record header
// Write in the record header
// Set the filepointer to the RecordOffset
//
if(!WriteDataToWABFile( hMPSWabFile, ulRecordHeaderOffset, (LPVOID) &MPSWabRecordHeader, sizeof(MPSWab_RECORD_HEADER))) goto out;
//
// Write a data block
// Now we can write this block of data into the file
//
if (0xFFFFFFFF == SetFilePointer ( hMPSWabFile, ulRecordDataOffset, NULL, FILE_CURRENT)) { DebugTrace(TEXT("SetFilePointer Failed\n")); goto out; }
//
// Now write the RecordData
//
if(!WriteFile( hMPSWabFile, (LPCVOID) lp, (DWORD) ulRecordDataSize, &dwNumofBytes, NULL)) { DebugTrace(TEXT("Writing RecordHeader failed.\n")); goto out; }
LocalFreeAndNull(&lp);
//
// Update the indexes and write to file
// If this is a new record, we need to create and store new index
// entries in their proper place in the property store file
//
//// If this is not a new entry then we need to compare the index values to see if they
//// might have changed
//
// EntryID index in the file. Since we have already updated the actual
// offset in the Index in memory, all we really need to do is to
// store the index back into file. The string indexes are unchanged
// in this operation.
//
//
// Create the new index entries (only for new records)
//
MPSWabIndexEntryDataEntryID.dwEntryID = dwEntryID; MPSWabIndexEntryDataEntryID.ulOffset = ulRecordHeaderOffset;
for(j=indexDisplayName;j<indexMax;j++) { MPSWabIndexEntryDataString[j].dwEntryID = dwEntryID; MPSWabIndexEntryDataString[j].szIndex[0] = '\0'; bPropSet[j] = FALSE;
for(i=0;i<ulcPropCount;i++) { if(lpPropArray[i].ulPropTag == rgIndexArray[j]) { bPropSet[j] = TRUE; nLen = TruncatePos(lpPropArray[i].Value.LPSZ, MAX_INDEX_STRING-1); CopyMemory(MPSWabIndexEntryDataString[j].szIndex,lpPropArray[i].Value.LPSZ,sizeof(TCHAR)*nLen); MPSWabIndexEntryDataString[j].szIndex[nLen]='\0'; break; } } }
if (bIsNewRecord) {
DebugTrace(TEXT("Creating New Record: EntryID %d\n"), dwEntryID);
// Now write these indexes into file ...
// the indices in the file are already sorted so to add the new entry
// we will do the following:
//
// 1. Find out where in the index the entry would fit in
// 2. Write the entry into that position in the file
// 3. write the rest of the index from that point on into the file
// 4. reload the index
// do a bin search to find a match for the current index
// binsearch returns the matching position on match or it
// returns the position at which the match would exist were
// the match in the array. Thus whether
// there is a match or not we can assume ulPosition containts
// the index of the item at which the new entry should be entered
//
//
// do string indexes
//
for(j=indexDisplayName;j<indexMax;j++) //assumes a specific order defined in mpswab.h
{
if(!bPropSet[j]) continue;
//
// Get the index
//
if (!LoadIndex( IN lpMPSWabFileInfo, IN j, IN hMPSWabFile) ) { DebugTrace(TEXT("Error Loading Index!\n")); goto out; }
DebugTrace( TEXT("Index: %d Entry: %s\n"),j,MPSWabIndexEntryDataString[j].szIndex);
BinSearchStr( IN lpMPSWabFileInfo->lpMPSWabIndexStr, IN MPSWabIndexEntryDataString[j].szIndex, IN lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].ulcNumEntries, OUT &nIndexPos); // nIndexPos will contain the position at which we can insert this entry into the file
//Set the filepointer to point to the above found point
if(!WriteDataToWABFile( hMPSWabFile, lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].ulOffset + (nIndexPos) * sizeof(MPSWab_INDEX_ENTRY_DATA_STRING), (LPVOID) &MPSWabIndexEntryDataString[j], sizeof(MPSWab_INDEX_ENTRY_DATA_STRING))) goto out;
if (lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].ulcNumEntries != nIndexPos) //if not the last entry
{ //write the remaining entries in the array back to file
if(!WriteFile( hMPSWabFile, (LPCVOID) &lpMPSWabFileInfo->lpMPSWabIndexStr[nIndexPos], (DWORD) sizeof(MPSWab_INDEX_ENTRY_DATA_STRING)*(lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].ulcNumEntries - nIndexPos), &dwNumofBytes, NULL)) { DebugTrace(TEXT("Writing Index[%d] failed.\n"), j); goto out; } }
lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].ulcNumEntries++; lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].UtilizedBlockSize += sizeof(MPSWab_INDEX_ENTRY_DATA_STRING);
}
//Do the same for the EntryID index also
BinSearchEID( IN lpMPSWabFileInfo->lpMPSWabIndexEID, IN MPSWabIndexEntryDataEntryID.dwEntryID, IN lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries, OUT &nIndexPos); // nIndexPos will contain the position at which we can insert this entry into the file
if(!WriteDataToWABFile( hMPSWabFile, lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulOffset + (nIndexPos) * sizeof(MPSWab_INDEX_ENTRY_DATA_ENTRYID), (LPVOID) &MPSWabIndexEntryDataEntryID, sizeof(MPSWab_INDEX_ENTRY_DATA_ENTRYID))) goto out;
if (lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries != nIndexPos) //if not the last entry
{ //write the remaining entries in the array back to file
if(!WriteFile( hMPSWabFile, (LPCVOID) &lpMPSWabFileInfo->lpMPSWabIndexEID[nIndexPos], (DWORD) sizeof(MPSWab_INDEX_ENTRY_DATA_ENTRYID)*(lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries - nIndexPos), &dwNumofBytes, NULL)) { DebugTrace(TEXT("Writing Index[%d] failed.\n"), j); goto out; } }
lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries++; lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].UtilizedBlockSize += sizeof(MPSWab_INDEX_ENTRY_DATA_ENTRYID);
lpMPSWabFileInfo->lpMPSWabFileHeader->ulcNumEntries++; } else { DebugTrace(TEXT("Modifying Existing Record: EntryID %d\n"), dwEntryID);
// We have to compare the old props with the new props to see if we need to change any of the string
// indexes ...
for(j=indexDisplayName;j<indexMax;j++) {
BOOL bUpdateStringIndex = FALSE; BOOL bRemoveOldStringIndex = FALSE; BOOL bAddNewStringIndex = FALSE;
DebugTrace(TEXT("Index: %d Entry: %s\n"),j,MPSWabIndexEntryDataString[j].szIndex);
if (lstrlen(MPSWabIndexEntryDataString[j].szIndex)) bAddNewStringIndex = TRUE;
if (lstrlen(lpszOldIndex[j])) bRemoveOldStringIndex = TRUE;
// if there is no old index and there is a new index
// or there is an old index and there is a new index but they are different
// or there is an old index but no new index then
if( (!bRemoveOldStringIndex && bAddNewStringIndex) || (bRemoveOldStringIndex && bAddNewStringIndex && (lstrcmpi(lpszOldIndex[j],MPSWabIndexEntryDataString[j].szIndex)!=0)) || (bRemoveOldStringIndex && !bAddNewStringIndex) ) { bUpdateStringIndex = TRUE; }
if(!bUpdateStringIndex) continue;
if (bRemoveOldStringIndex) { ULONG nIndex =0; int nStartPos=0,nEndPos=0; LPTSTR lpsz = lpszOldIndex[j]; ULONG nTotal = 0;
if (!LoadIndex( IN lpMPSWabFileInfo, IN j, IN hMPSWabFile) ) { DebugTrace(TEXT("Error Loading Index!\n")); goto out; }
nTotal = lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].ulcNumEntries;
// Find the position of the old string index
// There is one problem where there are multiple entries with the same name
// BinSearch can potentially hand us back the wrong entry if we just
// search by name alone .. we need to look at both names and
// entry ids before accepting a position as the correct one
//
BinSearchStr( IN lpMPSWabFileInfo->lpMPSWabIndexStr, IN lpszOldIndex[j], IN nTotal, OUT &nIndexPos);
// nIndexPos contains the position of a particular entry matching the old index
// This may not necessarily be the correct entry if there are multiple identical
// display name entries ... Hence we look in out sorted Index array for the start
// of such names and the end of such names and then look at the entry ids
// of all such entries to get the right one
if(nTotal > 0) { nStartPos = (int) nIndexPos; nEndPos = (int) nIndexPos;
while((nStartPos>=0) && !lstrcmpi(lpsz,lpMPSWabFileInfo->lpMPSWabIndexStr[nStartPos].szIndex)) nStartPos--;
nStartPos++;
while((nEndPos<(int)nTotal) && !lstrcmpi(lpsz,lpMPSWabFileInfo->lpMPSWabIndexStr[nEndPos].szIndex)) nEndPos++;
nEndPos--;
if (nStartPos != nEndPos) { // there is more than one ...
for(nIndex=(ULONG)nStartPos;nIndex<=(ULONG)nEndPos;nIndex++) { if (lpMPSWabFileInfo->lpMPSWabIndexStr[nIndex].dwEntryID == dwEntryID) { nIndexPos = nIndex; break; } } }
} // At this point nIndexPos will contain the correctposition of this entry
//Set the filepointer to point to the above found point
if (0xFFFFFFFF == SetFilePointer ( hMPSWabFile, lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].ulOffset + (nIndexPos) * sizeof(MPSWab_INDEX_ENTRY_DATA_STRING), NULL, FILE_BEGIN)) { DebugTrace(TEXT("SetFilePointer Failed\n")); goto out; }
//remove the entry by overwriting it ...
if (lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].ulcNumEntries != nIndexPos) //if not the last entry
{ //write the remaining entries in the array back to file
if(!WriteFile( hMPSWabFile, (LPCVOID) &lpMPSWabFileInfo->lpMPSWabIndexStr[nIndexPos+1], (DWORD) sizeof(MPSWab_INDEX_ENTRY_DATA_STRING)*(lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].ulcNumEntries - nIndexPos-1), &dwNumofBytes, NULL)) { DebugTrace(TEXT("Writing Index[%d] failed.\n"), j); goto out; } }
if(lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].ulcNumEntries>0) lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].ulcNumEntries--; if(lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].UtilizedBlockSize>0) lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].UtilizedBlockSize -= sizeof(MPSWab_INDEX_ENTRY_DATA_STRING);
}
if (bAddNewStringIndex) { //Now find where the new entry would go ..
//
// Get the index
//
if (!LoadIndex( IN lpMPSWabFileInfo, IN j, IN hMPSWabFile) ) { DebugTrace(TEXT("Error Loading Index!\n")); goto out; }
BinSearchStr( IN lpMPSWabFileInfo->lpMPSWabIndexStr, IN MPSWabIndexEntryDataString[j].szIndex, IN lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].ulcNumEntries, OUT &nIndexPos); // nIndexPos will contain the position at which we can insert this entry into the file
if(!WriteDataToWABFile( hMPSWabFile, lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].ulOffset + (nIndexPos) * sizeof(MPSWab_INDEX_ENTRY_DATA_STRING), (LPVOID) &MPSWabIndexEntryDataString[j], sizeof(MPSWab_INDEX_ENTRY_DATA_STRING))) goto out;
if (lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].ulcNumEntries != nIndexPos) //if not the last entry
{ //write the remaining entries in the array back to file
if(!WriteFile( hMPSWabFile, (LPCVOID) &lpMPSWabFileInfo->lpMPSWabIndexStr[nIndexPos], (DWORD) sizeof(MPSWab_INDEX_ENTRY_DATA_STRING)*(lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].ulcNumEntries - nIndexPos), &dwNumofBytes, NULL)) { DebugTrace(TEXT("Writing Index[%d] failed.\n"), j); goto out; } }
lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].ulcNumEntries++; lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].UtilizedBlockSize += sizeof(MPSWab_INDEX_ENTRY_DATA_STRING);
} }
// Not a new item index-entry but just a modification of an old one
// in this case we just need to save the EntryID index back to file
if (!BinSearchEID( IN lpMPSWabFileInfo->lpMPSWabIndexEID, IN dwEntryID, IN lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries, OUT &nIndexPos)) { DebugTrace(TEXT("EntryID not found\n")); //No way should this ever happen
hr = MAPI_E_INVALID_ENTRYID; goto out; }
//Set the filepointer to point to the start of the entryid index
if(!WriteDataToWABFile( hMPSWabFile, lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulOffset + (nIndexPos) * sizeof(MPSWab_INDEX_ENTRY_DATA_ENTRYID), (LPVOID) &lpMPSWabFileInfo->lpMPSWabIndexEID[nIndexPos], sizeof(MPSWab_INDEX_ENTRY_DATA_ENTRYID))) goto out;
}
// update the file header
if (0xFFFFFFFF == SetFilePointer ( hMPSWabFile, 0, NULL, FILE_BEGIN)) { DebugTrace(TEXT("SetFilePointer Failed\n")); goto out; }
#ifdef DEBUG
DebugTrace(TEXT("ulcNum: %d\t"),lpMPSWabFileInfo->lpMPSWabFileHeader->ulcNumEntries); for(i=indexDisplayName;i<indexMax-2;i++) DebugTrace(TEXT("index %d: %d\t"),i, lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[i].ulcNumEntries); DebugTrace(TEXT("\n")); #endif
if(lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries != lpMPSWabFileInfo->lpMPSWabFileHeader->ulcNumEntries) lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags |= WAB_ERROR_DETECTED;
for(i=indexDisplayName+1;i<indexMax;i++) { if(lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[i].ulcNumEntries > lpMPSWabFileInfo->lpMPSWabFileHeader->ulcNumEntries) lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags |= WAB_ERROR_DETECTED; }
if(!WriteFile( hMPSWabFile, (LPCVOID) lpMPSWabFileInfo->lpMPSWabFileHeader, (DWORD) sizeof(MPSWab_FILE_HEADER), &dwNumofBytes, NULL)) { DebugTrace(TEXT("Writing FileHeader failed.\n")); goto out; }
if ((lpMPSWabFileInfo->lpMPSWabFileHeader->ulcMaxNumEntries - lpMPSWabFileInfo->lpMPSWabFileHeader->ulcNumEntries) < 10) { //
// if we are within 10 entries of exhausting the allocated space for the property
// store, its time to grow the store.
//
if (!CompressFile( lpMPSWabFileInfo, hMPSWabFile, NULL, TRUE, AB_GROW_INDEX)) { DebugTrace(TEXT("Growing the file failed\n")); goto out; } }
/*
// Notify other processes and our UI
{ NOTIFICATION Notification;
Notification.ulEventType = bIsNewRecord ? fnevObjectCreated : fnevObjectModified; Notification.info.obj.cbEntryID = SIZEOF_WAB_ENTRYID; Notification.info.obj.lpEntryID = (LPENTRYID)&dwEntryID; switch (ulRecordType) { case RECORD_CONTACT: Notification.info.obj.ulObjType = MAPI_MAILUSER; break; case RECORD_DISTLIST: Notification.info.obj.ulObjType = MAPI_DISTLIST; break; case RECORD_CONTAINER: Notification.info.obj.ulObjType = MAPI_ABCONT; break; default: Assert(FALSE); break; } Notification.info.obj.cbParentID = 0; Notification.info.obj.lpParentID = NULL; Notification.info.obj.cbOldID = 0; Notification.info.obj.lpOldID = NULL; Notification.info.obj.cbOldParentID = 0; Notification.info.obj.lpOldParentID = NULL; Notification.info.obj.lpPropTagArray = (LPSPropTagArray)lpPropArray;
HrFireNotification(&Notification); } */ //
// if we're still here it was all fun and games ...
//
if(!*lppsbEID) // if there was a null LPSBinary entryid provided, return one
{ LPSBinary lpsb = LocalAlloc(LMEM_ZEROINIT, sizeof(SBinary)); if(!lpsb) { hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; } lpsb->cb = SIZEOF_WAB_ENTRYID; lpsb->lpb = LocalAlloc(LMEM_ZEROINIT, SIZEOF_WAB_ENTRYID); if(!lpsb->lpb) { hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; } CopyMemory(lpsb->lpb, &dwEntryID, lpsb->cb); *lppsbEID = lpsb; }
hr = S_OK;
out: // UnTag this file as undergoing a write operation
// We only want the flag to stay there during crashes not during
// normal operations
//
if(lpMPSWabFileInfo) { if(!bUntagWriteTransaction( lpMPSWabFileInfo->lpMPSWabFileHeader, hMPSWabFile) ) { DebugTrace(TEXT("Untaggin file write failed\n")); } }
if (bEIDSave) { // Restore the original EID property in the input property array
lpPropArray[iEIDSave].Value.bin = sbEIDSave; }
LocalFreeAndNull(&lpPropTagArray);
LocalFreePropArray(hPropertyStore, ulcOldPropCount, &lpOldPropArray);
if (hMPSWabFile) IF_WIN32(CloseHandle(hMPSWabFile);) IF_WIN16(CloseFile(hMPSWabFile);)
if (bFileLocked) UnLockFileAccess(lpMPSWabFileInfo);
// Some special case error codes for generic fails
if(HR_FAILED(hr) && hr == E_FAIL) { dwErr = GetLastError(); switch(dwErr) { case ERROR_DISK_FULL: hr = MAPI_E_NOT_ENOUGH_DISK; break; } }
// in case we changed the object type here, reset it
if(ulRecordType == RECORD_CONTAINER) SetContainerObjectType(ulcPropCount, lpPropArray, FALSE);
DebugTrace(( TEXT("WriteRecord: Exit\n-----------\n")));
return(hr); }
/*
- - HrDupePropResWCtoA * * Dupes the PropRes passed into FindRecords and ReadPropArray * and converts it from WC to A in the process so we can feed * it to outlook * * Note the *lppPropResA->lpProp needs to be freed seperately from *lppPropResA */ HRESULT HrDupePropResWCtoA(ULONG ulFlags, LPSPropertyRestriction lpPropRes,LPSPropertyRestriction * lppPropResA) { SCODE sc = 0; HRESULT hr = S_OK; LPSPropValue lpNewPropArray = NULL;
LPSPropertyRestriction lpPropResA = NULL; ULONG cb = 0;
if(!(ulFlags & AB_MATCH_PROP_ONLY)) // means Restriction has some data part
{ if (FAILED(sc = ScCountProps(1, lpPropRes->lpProp, &cb))) { hr = ResultFromScode(sc); goto exit; }
if (FAILED(sc = MAPIAllocateBuffer(cb, &lpNewPropArray))) { hr = ResultFromScode(sc); goto exit; }
if (FAILED(sc = ScCopyProps(1, lpPropRes->lpProp, lpNewPropArray, NULL))) { hr = ResultFromScode(sc); goto exit; }
// Now we thunk the data back to ANSI for Outlook
if (FAILED(sc = ScConvertWPropsToA((LPALLOCATEMORE) (&MAPIAllocateMore), lpNewPropArray, 1, 0))) { hr = ResultFromScode(sc); goto exit; } } else { if (FAILED(sc = MAPIAllocateBuffer(sizeof(SPropValue), &lpNewPropArray))) { hr = ResultFromScode(sc); goto exit; } ZeroMemory(lpNewPropArray, sizeof(SPropValue)); if(PROP_TYPE(lpPropRes->ulPropTag)==PT_UNICODE) lpNewPropArray->ulPropTag = CHANGE_PROP_TYPE(lpPropRes->ulPropTag, PT_STRING8); else if(PROP_TYPE(lpPropRes->ulPropTag)==PT_MV_UNICODE) lpNewPropArray->ulPropTag = CHANGE_PROP_TYPE(lpPropRes->ulPropTag, PT_MV_STRING8); else lpNewPropArray->ulPropTag = lpPropRes->ulPropTag; }
if (FAILED(sc = MAPIAllocateBuffer(sizeof(SPropertyRestriction), &lpPropResA))) { hr = ResultFromScode(sc); goto exit; }
lpPropResA->relop = lpPropRes->relop; lpPropResA->ulPropTag = lpNewPropArray->ulPropTag; lpPropResA->lpProp = lpNewPropArray; *lppPropResA = lpPropResA;
exit: if(HR_FAILED(hr)) { FreeBufferAndNull(&lpPropResA); FreeBufferAndNull(&lpNewPropArray); }
return hr; }
//$$//////////////////////////////////////////////////////////////////////////////////
//
// FindRecords
//
// IN hPropertyStore - handle to property store
// IN pmbinFold - <Outlook> EntryID of folder to search in (NULL for default)
// IN ulFlags - AB_MATCH_PROP_ONLY - checks for existence of a certain prop only
// Does not check/compare the value of the Prop
// Used for unindexed properties only. Works only
// with RELOP_EQ and RELOP_NE
// e.g. caller says - give me a list of all entryids who have
// an email address - in this case we dont care what the
// email address is. Or he could say, give me a list of
// all entries who dont have URLs
//
// AB_IGNORE_OUTLOOK - works against WAB file even if OLK is running
//
// IN lpPropRes - pointer to SPropRes structure
// IN bLockFile - This function is also called internally in cases where we dont
// want to lock the file - In such cases we set the value to False. For
// external callers (outside MPSWAB.c) this value must always be TRUE
// IN OUT lpulcEIDCount - Count of how many to get and how many actually returned
// if Zero is specified, we have to get all matches.
//
//
// OUT rgsbEntryIDs - array of SBinary structures containing matching entryids
//
// lpPropRes will specify one of the following operators
// RELOP_GE (>=) RELOP_GT (>) RELOP_LE (<=)
// RELOP_LT (<) RELOP_NE (!=) RELOP_EQ (==)
//
// Implicit in this function is the fact that it should not be called for
// finding EntryIDs based on a given entryid value i.e. lpPropRes cannot
// contain an EntryID value, reason being that entryids aer unique and it doesnt
// make sense to find entryids. Hence if an entryid is specified, this
// function will just return the specified entryid back ...
//
// Returns
// Success: S_OK
// Failure: E_FAIL
//
////////////////////////////////////////////////////////////////////////////////////
HRESULT FindRecords(IN HANDLE hPropertyStore, IN LPSBinary pmbinFold, IN ULONG ulFlags, IN BOOL bLockFile, IN LPSPropertyRestriction lpPropRes, IN OUT LPULONG lpulcEIDCount, OUT LPSBinary * lprgsbEntryIDs) { HRESULT hr = E_FAIL; LPDWORD lprgdwTmp = NULL; HANDLE hMPSWabFile = NULL; ULONG nCurrentIndex =0; ULONG i=0,j=0,k=0,min=0,n=0; DWORD nCurrentEID = 0; ULONG ulMaxCount; DWORD dwNumofBytes = 0; ULONG ret; BOOL bMatchFound; TCHAR lpszValue[MAX_INDEX_STRING+1]; ULONG ulRangeStart = 0; ULONG ulRangeEnd = 0; ULONG ulRelOp = 0; ULONG ulcNumEntries =0; ULONG ulPreviousRecordOffset = 0,ulCurrentRecordOffset = 0; ULONG ulRecordCount = 0; LPULONG lpulPropTagArray = NULL; TCHAR * szBuf = NULL; TCHAR * lp = NULL; int nComp = 0; BOOL bFileLocked = 0; BOOL bErrorDetected = FALSE;
LPDWORD lpdwEntryIDs = NULL;
ULONG ulcEIDCount = 0; LPDWORD lpdwEID = NULL;
SPropValue TmpProp; ULONG ulcTmpValues; ULONG ulcTmpDataSize; ULONG ulFileSize = 0;
MPSWab_RECORD_HEADER MPSWabRecordHeader; LPMPSWab_FILE_INFO lpMPSWabFileInfo;
LPPTGDATA lpPTGData=GetThreadStoragePointer();
if(pt_bIsWABOpenExSession && !(ulFlags & AB_IGNORE_OUTLOOK)) { // This is a WABOpenEx session using outlooks storage provider
if(!hPropertyStore) return MAPI_E_NOT_INITIALIZED;
{ LPWABSTORAGEPROVIDER lpWSP = (LPWABSTORAGEPROVIDER) hPropertyStore; LPSPropertyRestriction lpPropResA = NULL;
if( !pt_bIsUnicodeOutlook) { // Need to thunk the restriction down to ANSI
HrDupePropResWCtoA(ulFlags, lpPropRes, &lpPropResA); }
hr = lpWSP->lpVtbl->FindRecords(lpWSP, (pmbinFold && pmbinFold->cb && pmbinFold->lpb) ? pmbinFold : NULL, ulFlags, lpPropResA ? lpPropResA : lpPropRes, lpulcEIDCount, lprgsbEntryIDs);
DebugTrace(TEXT("WABStorageProvider::FindRecords returned:%x\n"),hr);
if(lpPropResA) { FreeBufferAndNull(&lpPropResA->lpProp); FreeBufferAndNull(&lpPropResA); } return hr; } }
lpMPSWabFileInfo = hPropertyStore;
if (NULL==lpMPSWabFileInfo) goto out; if (NULL==lpPropRes) goto out;
//
// If we are looking for property matching only, the lpProp can be null
// Just remember not to reference it in this case...
//
if ( !((ulFlags & AB_MATCH_PROP_ONLY)) && (NULL==lpPropRes->lpProp)) { goto out; }
lpdwEntryIDs = NULL; ulMaxCount = *lpulcEIDCount; *lpulcEIDCount = 0;
ulRelOp = lpPropRes->relop;
if(bLockFile) { if(!LockFileAccess(lpMPSWabFileInfo)) { DebugTrace(TEXT("LockFileAccess Failed\n")); hr = MAPI_E_NO_ACCESS; goto out; } else { bFileLocked = TRUE; } }
//
// Open the file
//
hr = OpenWABFile(lpMPSWabFileInfo->lpszMPSWabFileName, NULL, &hMPSWabFile);
if ( (hMPSWabFile == INVALID_HANDLE_VALUE) || HR_FAILED(hr)) { DebugTrace(TEXT("Could not open file.\nExiting ...\n")); goto out; }
ulFileSize = GetFileSize(hMPSWabFile, NULL);
//
// To ensure that file info is accurate,
// Any time we open a file, read the file info again ...
//
if(!ReloadMPSWabFileInfo( lpMPSWabFileInfo, hMPSWabFile)) { DebugTrace(TEXT("Reading file info failed.\n")); goto out; }
//
// Anytime we detect an error - try to fix it ...
//
if((lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags & WAB_ERROR_DETECTED) || (lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags & WAB_WRITE_IN_PROGRESS)) { if(HR_FAILED(HrDoQuickWABIntegrityCheck(lpMPSWabFileInfo,hMPSWabFile))) { hr = HrDoDetailedWABIntegrityCheck(lpMPSWabFileInfo,hMPSWabFile); if(HR_FAILED(hr)) { DebugTrace(TEXT("HrDoDetailedWABIntegrityCheck failed:%x\n"),hr); goto out; } } }
//
//There are 2 main cases for this FindRecord function:
// 1. The specified property type to find is an index and we just
// need to search the indexes.
// 2. The specified property type is not an index, so we need to search
// the whole file.
// Each case is treated seperately.
//
//
// Of course, first we check if mistakenly an EntryID was sought. If
// so, just return the entry id itself.
//
if (rgIndexArray[indexEntryID] == lpPropRes->ulPropTag) { lpdwEntryIDs = LocalAlloc(LMEM_ZEROINIT,SIZEOF_WAB_ENTRYID);
if (!lpdwEntryIDs) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; }
*lpdwEntryIDs = lpPropRes->lpProp->Value.ul; *lpulcEIDCount = 1; hr = S_OK; goto out; }
//
// Now Check if the specified property type is indexed or not indexed
//
for (i = indexDisplayName; i<indexMax; i++) //assumes that indexEntryID = 0 and ignores it
{ //
// first check if the prop tag we are searching for is indexed or not
//
if (rgIndexArray[i] == lpPropRes->ulPropTag) { ulcNumEntries = lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[i].ulcNumEntries;
if (ulcNumEntries == 0) { //
// if nothing to search in, then report a success and return
//
hr = S_OK; goto out; }
if ((ulFlags & AB_MATCH_PROP_ONLY)) { //
// We dont need to look at the data
// We can assume that every single record has the indexed properties
// and therefore every record is eligible for returning
//
// So if RELOP_EQ is specified, we can just return a array of all
// the existing entryids .. if RELOP_NE is specified, then we cant
// return anything ...
//
if (lpPropRes->relop == RELOP_NE) { ulcEIDCount = 0;//*lpulcEIDCount = 0;
lpdwEID = NULL; //lpdwEntryIDs = NULL;
hr = S_OK; } else if(lpPropRes->relop == RELOP_EQ) {
//*lpulcEIDCount = ulcNumEntries;
ulcEIDCount = ulcNumEntries;
//Allocate enough memory for returned array
//lpdwEntryIDs = LocalAlloc(LMEM_ZEROINIT,SIZEOF_WAB_ENTRYID * (*lpulcEIDCount));
lpdwEID = LocalAlloc(LMEM_ZEROINIT,SIZEOF_WAB_ENTRYID * ulcEIDCount);
//if (!lpdwEntryIDs)
if (!lpdwEID) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; }
// Make sure this index is loaded into memory
if (!LoadIndex(lpMPSWabFileInfo,i,hMPSWabFile)) { DebugTrace(TEXT("Could not load index %x\n"),rgIndexArray[i]); goto out; }
for(j=0;j<ulcEIDCount;j++) { lpdwEID[j] = lpMPSWabFileInfo->lpMPSWabIndexStr[j].dwEntryID; }
hr = S_OK; } else { DebugTrace(TEXT("Unsupported find parameters\n")); hr = MAPI_E_INVALID_PARAMETER; } goto filterFolderMembers;
}
//
// We need to look at the Data
//
//
// The index strings are only MAX_INDEX_STRING long
// If the value to search for is longer we need to truncate it to
// MAX_INDEX_STRING length. There is a caveat that now we will
// return spurious matches but lets leave it here for now
// and tag it as TBD!!!
//
if (lstrlen(lpPropRes->lpProp->Value.LPSZ) >= MAX_INDEX_STRING-1) // >= 31 chars (so won't include trailing null)
{ ULONG nLen = TruncatePos(lpPropRes->lpProp->Value.LPSZ, MAX_INDEX_STRING-1); CopyMemory(lpszValue,lpPropRes->lpProp->Value.LPSZ,sizeof(TCHAR)*nLen); lpszValue[nLen]='\0'; } else { StrCpyN(lpszValue,lpPropRes->lpProp->Value.LPSZ,ARRAYSIZE(lpszValue)); }
//
// Load the appropriate index into memory
//
if (!LoadIndex(lpMPSWabFileInfo,i,hMPSWabFile)) { DebugTrace(TEXT("Could not load index %x\n"),rgIndexArray[i]); goto out; }
//
//if it is indexed, search this index for a match
//
bMatchFound = BinSearchStr( IN lpMPSWabFileInfo->lpMPSWabIndexStr, IN lpszValue, IN lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[i].ulcNumEntries, OUT &ret);
//
// 'ret' now contains the position at which this entry exists, if it exists
//
//
// Now we have to deal with all the relational operators
// There are several Permutations and Combinations of the operators and
// the success of the search.
//
// Rel_OP MatchFound=TRue MatchFound=False
//
// EQ == Find all that match Return Nothing
// NE != Find all that match and Return all
// exclude them
// LE <=, LT < Return Everything in index Return everything
// including and/or before including and before
// GT >, GE >= Return Everything in index Return Everything
// including and/or after including and after
//
// Since our sting arrays are sorted, the matched string could
// be one of many duplicates and we dont know where the duplicate lies
// so we have to find all the duplicates to the matched string
// This is easy - e.g.
// index array -> A,B,D,G,G,G,G,G,S,U,V,Y,Z and we matched G in the
// middle position ^
// we can just move forward and backward from there and find the range
// of indexes that match and treat that range as the matched range
// and then follow the above combinations ...
ulRangeStart = ret; ulRangeEnd = ret;
//
// If no match is found, then we can use the above values for ulRangeStart
// and ulRangeEnd otherwise if match was found we have to seek the
// borders of the duplicate list ...
//
if (bMatchFound) { for(;;) { ulRangeStart--; if ( (0xffffffff == ulRangeStart) || (lstrcmpi(lpMPSWabFileInfo->lpMPSWabIndexStr[ulRangeStart].szIndex,lpszValue) ) ) break; } for(;;) { ulRangeEnd++; if ( (ulRangeEnd == ulcNumEntries) || (lstrcmpi(lpMPSWabFileInfo->lpMPSWabIndexStr[ulRangeEnd].szIndex,lpszValue) ) ) break; }
// Fix off-by-one ..
ulRangeStart++; ulRangeEnd--;
}
//
// Now ulRangeStart points to start of the matched entries and
// ulRangeEnd to end of the matched entries.
// e.g. 0 1 ... ... ulcNumEntries-1
// A,B,C,D,G,G,G,G,G,G,H,J,J,K,L,Z
// ^ ^
// | |
// ulRangeStart ulRangeEnd
//
// Now we need to calculate the number of values we are returning in the array
//
if (bMatchFound) { switch(ulRelOp) { case RELOP_GT: //include everything from RangeEnd+1 to end
*lpulcEIDCount = ulcNumEntries - (ulRangeEnd + 1); break; case RELOP_GE: //include everything from RangeStart to end
*lpulcEIDCount = ulcNumEntries - ulRangeStart; break; case RELOP_LT: *lpulcEIDCount = ulRangeStart; break; case RELOP_LE: *lpulcEIDCount = ulRangeEnd + 1; break; case RELOP_NE: *lpulcEIDCount = ulcNumEntries - (ulRangeEnd+1 - ulRangeStart); break; case RELOP_EQ: *lpulcEIDCount = (ulRangeEnd+1 - ulRangeStart); break; } } else { //Assumes ulRangeStart = ulRangeEnd
switch(ulRelOp) { case RELOP_GT: case RELOP_GE: //include everything from RangeEnd/RangeStart to end
*lpulcEIDCount = ulcNumEntries - ulRangeEnd; break; case RELOP_LT: case RELOP_LE: *lpulcEIDCount = ulRangeStart; break; case RELOP_NE: *lpulcEIDCount = ulcNumEntries; break; case RELOP_EQ: *lpulcEIDCount = 0; break; }
}
if (*lpulcEIDCount == 0) { //
// nothing to return - goodbye
//
hr = S_OK; goto out; }
//
// dont return more than Max asked for (where Max != 0)...
//
if ( (*lpulcEIDCount > ulMaxCount) && (ulMaxCount != 0) ) *lpulcEIDCount = ulMaxCount;
//
// Allocate enough memory for returned array
//
lpdwEntryIDs = LocalAlloc(LMEM_ZEROINIT,SIZEOF_WAB_ENTRYID * (*lpulcEIDCount));
if (!lpdwEntryIDs) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; }
//
// Now copy over the EntryIDs from the index to the returned array
// Each operator needs different treatment
//
if (bMatchFound) { switch(ulRelOp) { case RELOP_GT: for(i=0;i<(*lpulcEIDCount);i++) { //include everything from RangeEnd+1 to end
lpdwEntryIDs[i] = lpMPSWabFileInfo->lpMPSWabIndexStr[i+ulRangeEnd+1].dwEntryID; } break; case RELOP_GE: for(i=0;i<(*lpulcEIDCount);i++) { //include everything from RangeStart to end
lpdwEntryIDs[i] = lpMPSWabFileInfo->lpMPSWabIndexStr[i+ulRangeStart].dwEntryID; } break; case RELOP_LT: case RELOP_LE: for(i=0;i<(*lpulcEIDCount);i++) { //include everything from before RangeEnd/RangeStart
lpdwEntryIDs[i] = lpMPSWabFileInfo->lpMPSWabIndexStr[i].dwEntryID; } break; case RELOP_NE: i = 0; if ( (ulcNumEntries > ulMaxCount) && (ulMaxCount != 0) ) ulcNumEntries = ulMaxCount; for(j=0;j<ulcNumEntries;j++) { //include everything from before RangeStart and after RangeEnd
if ( (j<ulRangeStart) || (j>ulRangeEnd) ) { lpdwEntryIDs[i] = lpMPSWabFileInfo->lpMPSWabIndexStr[j].dwEntryID; i++; } } break; case RELOP_EQ: i = 0; for(j=0;j<(*lpulcEIDCount);j++) { //include everything between RangeStart and RangeEnd
lpdwEntryIDs[i] = lpMPSWabFileInfo->lpMPSWabIndexStr[j+ulRangeStart].dwEntryID; i++; } break; } } else { //assumes that RangeStart = RangeEnd
switch(ulRelOp) { case RELOP_GT: case RELOP_GE: for(i=0;i<(*lpulcEIDCount);i++) { //include everything from RangeStart to end
lpdwEntryIDs[i] = lpMPSWabFileInfo->lpMPSWabIndexStr[i+ulRangeStart].dwEntryID; } break; case RELOP_LT: case RELOP_LE: case RELOP_NE: for(i=0;i<(*lpulcEIDCount);i++) { //include first 'n' entries
lpdwEntryIDs[i] = lpMPSWabFileInfo->lpMPSWabIndexStr[i].dwEntryID; } break; case RELOP_EQ: //This case should never happen cause we checked for it before (when total found=0)
DebugTrace(TEXT("Unexpected RELOP_EQ case\n")); break; } } //if we're here we've got our data
hr = S_OK; if(!pmbinFold) { goto out; } else { ulcEIDCount = *lpulcEIDCount; lpdwEID = lpdwEntryIDs; lpdwEntryIDs = NULL; *lpulcEIDCount = 0; goto filterFolderMembers; } } }
// If we're here then we didnt find anything in the indices ...
// Time to search the whole file
// Mechanism for this search is to go through all the entries in an index
// read in the record corresponding to that entry, read in the prop tag
// array, search in it for the specified property based on REL_OP and then if
// it meets our criteria, we can store the entryid of the record and return it
// For the time being lets also ignore Multivalued properties because they are too much of a headache
if ( ((lpPropRes->ulPropTag & MV_FLAG)) && (!((ulFlags & AB_MATCH_PROP_ONLY))) ) { DebugTrace(TEXT("Searching for MultiValued prop data not supported in this version\n")); goto out; }
// The maximum number of entryIDs we can return = maximum number of entries
// So we will allocate some working space for ourselves here
lpdwEID = LocalAlloc(LMEM_ZEROINIT, SIZEOF_WAB_ENTRYID*lpMPSWabFileInfo->lpMPSWabFileHeader->ulcNumEntries); if (!lpdwEID) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; }
ulcEIDCount = 0;
ulPreviousRecordOffset = 0; if (0xFFFFFFFF== SetFilePointer ( hMPSWabFile, ulPreviousRecordOffset, NULL, FILE_BEGIN)) { DebugTrace(TEXT("SetFilePointer Failed\n")); goto out; }
for(n=0;n<lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries;n++) { ulCurrentRecordOffset = lpMPSWabFileInfo->lpMPSWabIndexEID[n].ulOffset;
if (0xFFFFFFFF== SetFilePointer ( hMPSWabFile, ulCurrentRecordOffset - ulPreviousRecordOffset, NULL, FILE_CURRENT)) { DebugTrace(TEXT("SetFilePointer Failed\n")); goto out; }
ulPreviousRecordOffset = ulCurrentRecordOffset;
//Read in the record header
if(!ReadFile( hMPSWabFile, (LPVOID) &MPSWabRecordHeader, (DWORD) sizeof(MPSWab_RECORD_HEADER), &dwNumofBytes, NULL)) { DebugTrace(TEXT("Reading Record header failed.\n")); goto out; }
if(dwNumofBytes == 0) { DebugTrace(TEXT("Passed the end of file\n")); break; }
ulPreviousRecordOffset += dwNumofBytes;
if(!bIsValidRecord( MPSWabRecordHeader, lpMPSWabFileInfo->lpMPSWabFileHeader->dwNextEntryID, ulCurrentRecordOffset, ulFileSize)) // if (MPSWabRecordHeader.bValidRecord != TRUE)
{ //
// skip to next record
//
bErrorDetected = TRUE; continue; }
// Do a special case for PR_OBJECT_TYPE searches since these can be easily
// determined from the record header without having to read the entire record
//
if( (lpPropRes->ulPropTag == PR_OBJECT_TYPE) && (lpPropRes->relop == RELOP_EQ) ) { LONG ulObjType = 0; if(MPSWabRecordHeader.ulObjType == RECORD_DISTLIST) ulObjType = MAPI_DISTLIST; else if(MPSWabRecordHeader.ulObjType == RECORD_CONTAINER) ulObjType = MAPI_ABCONT; else ulObjType = MAPI_MAILUSER;
if(lpPropRes->lpProp->Value.l == ulObjType) { //save this entry id in our master list
lpdwEID[ulcEIDCount++] = MPSWabRecordHeader.dwEntryID; }
// goto next record - whether it was a match or not ...
continue; }
//
// Read in the PropTagArray
//
//
// Allocate space for the PropTagArray
//
LocalFreeAndNull(&lpulPropTagArray); lpulPropTagArray = LocalAlloc(LMEM_ZEROINIT, MPSWabRecordHeader.ulPropTagArraySize);
if (!lpulPropTagArray) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; }
//
// Read in the Prop tag array
//
if(!ReadFile( hMPSWabFile, (LPVOID) lpulPropTagArray, (DWORD) MPSWabRecordHeader.ulPropTagArraySize, &dwNumofBytes, NULL)) { DebugTrace(TEXT("Reading Record PropTagArray failed.\n")); goto out; }
ulPreviousRecordOffset += dwNumofBytes;
//
// if AB_MATCH_PROP_ONLY is specified, then we limit our search to determining whether or
// not the property exists. if AB_MATCH_PROP_ONLY is not specified, we first look
// for the prop tag and then we look at the data behind the tag.
//
// if AB_MATCH_PROP is specified, we only search for existence or non-existence of the
// prop. All other Relational Operators are defunct.
// As long as we are not searching for multi-valued properties, we can have realtional operator
// based searching.
if ((ulFlags & AB_MATCH_PROP_ONLY) && (ulRelOp != RELOP_EQ) && (ulRelOp != RELOP_NE)) { DebugTrace(TEXT("Unsupported relational operator for Property Matching\n")); hr = MAPI_E_INVALID_PARAMETER; goto out; }
if ((PROP_TYPE(lpPropRes->ulPropTag) == PT_CLSID) && (ulRelOp != RELOP_EQ) && (ulRelOp != RELOP_NE)) { DebugTrace(TEXT("Unsupported relational operator for finding GUIDs \n")); hr = MAPI_E_INVALID_PARAMETER; goto out; }
bMatchFound = FALSE;
//
// scan the existing props for our tag
//
for (j=0;j<MPSWabRecordHeader.ulcPropCount;j++) { if (lpulPropTagArray[j]==lpPropRes->ulPropTag) { bMatchFound = TRUE; break; } }
// At this point we know whether or not the record contains this property of interest
// Now we look at the flags and relational operators to see what to do.
if ((ulFlags & AB_MATCH_PROP_ONLY)) { // We are interested only in the presence or absence of this property
if ( ( (ulRelOp == RELOP_EQ) && (bMatchFound) ) || ( (ulRelOp == RELOP_NE) && (!bMatchFound) ) ) { //save this entry id in our master list
lpdwEID[ulcEIDCount++] = MPSWabRecordHeader.dwEntryID;
}
// goto next record
continue; } else { // want to compare the values ...
// if we are trying to compare value data and the property doesnt even exist in the record,
// bail out now ...
if (!bMatchFound) { //nothing of interest - go to next record
continue; }
LocalFreeAndNull(&szBuf);
szBuf = LocalAlloc(LMEM_ZEROINIT,MPSWabRecordHeader.ulRecordDataSize);
if (!szBuf) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; }
if(!ReadFile( hMPSWabFile, (LPVOID) szBuf, (DWORD) MPSWabRecordHeader.ulRecordDataSize, &dwNumofBytes, NULL)) { DebugTrace(TEXT("Reading Record Data failed.\n")); goto out; }
ulPreviousRecordOffset += dwNumofBytes;
lp = szBuf;
//reset bMatchFound - used again later in this routine
bMatchFound = FALSE;
//go through all the property values
for(i=0;i< MPSWabRecordHeader.ulcPropCount;i++) { //Read Property Tag
CopyMemory(&TmpProp.ulPropTag,lp,sizeof(ULONG)); lp+=sizeof(ULONG) / sizeof(TCHAR);
//Check if it is MultiValued
if ((TmpProp.ulPropTag & MV_FLAG)) { //Read cValues
CopyMemory(&ulcTmpValues,lp,sizeof(ULONG)); lp+=sizeof(ULONG) / sizeof(TCHAR); }
//read DataSize
CopyMemory(&ulcTmpDataSize,lp,sizeof(ULONG)); lp+=sizeof(ULONG) / sizeof(TCHAR);
if (TmpProp.ulPropTag != lpPropRes->ulPropTag) { //skip this prop
lp += ulcTmpDataSize; // go check next Prop Tag
continue; }
if ((TmpProp.ulPropTag & MV_FLAG)) { //skip this prop
lp += ulcTmpDataSize; //go check next prop tag
continue; }
// copy the requisite number of bytes into memory
switch(PROP_TYPE(TmpProp.ulPropTag)) { case(PT_I2): case(PT_LONG): case(PT_APPTIME): case(PT_SYSTIME): case(PT_R4): case(PT_BOOLEAN): case(PT_CURRENCY): case(PT_I8): CopyMemory(&TmpProp.Value.i,lp,min(ulcTmpDataSize,sizeof(TmpProp.Value.i))); break;
case(PT_CLSID): case(PT_TSTRING): TmpProp.Value.LPSZ = LocalAlloc(LMEM_ZEROINIT,ulcTmpDataSize); if (!TmpProp.Value.LPSZ) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; } CopyMemory(TmpProp.Value.LPSZ,lp,ulcTmpDataSize); break;
case(PT_BINARY): TmpProp.Value.bin.lpb = LocalAlloc(LMEM_ZEROINIT,ulcTmpDataSize); if (!TmpProp.Value.bin.lpb) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; } CopyMemory(TmpProp.Value.bin.lpb,lp,ulcTmpDataSize); TmpProp.Value.bin.cb = ulcTmpDataSize; break;
default: // something I dont understand .. skip
lp += ulcTmpDataSize; //go check next prop tag
continue; break; }
lp += ulcTmpDataSize;
// Do the comparison
switch(PROP_TYPE(TmpProp.ulPropTag)) { case(PT_I2): nComp = TmpProp.Value.i - lpPropRes->lpProp->Value.i; break; case(PT_LONG): nComp = TmpProp.Value.l - lpPropRes->lpProp->Value.l; break; case(PT_R4): if ((TmpProp.Value.flt - lpPropRes->lpProp->Value.flt) < 0) { nComp = -1; } else if ((TmpProp.Value.flt - lpPropRes->lpProp->Value.flt) == 0) { nComp = 0; } else { nComp = 1; } break; case(PT_DOUBLE): if ((TmpProp.Value.dbl - lpPropRes->lpProp->Value.dbl) < 0) { nComp = -1; } else if ((TmpProp.Value.dbl - lpPropRes->lpProp->Value.dbl) == 0) { nComp = 0; } else { nComp = 1; } break; case(PT_BOOLEAN): nComp = TmpProp.Value.b - lpPropRes->lpProp->Value.b; break; case(PT_CURRENCY): // ???TBD: nComp = TmpProp.Value.cur - lpPropRes->lpProp->Value.cur;
if((TmpProp.Value.cur.Hi - lpPropRes->lpProp->Value.cur.Hi) < 0) { nComp = -1; } else if((TmpProp.Value.cur.Hi - lpPropRes->lpProp->Value.cur.Hi) > 0) { nComp = +1; } else { if(TmpProp.Value.cur.Lo < lpPropRes->lpProp->Value.cur.Lo) { nComp = -1; } else if((TmpProp.Value.cur.Lo - lpPropRes->lpProp->Value.cur.Lo) > 0) { nComp = +1; } else { nComp = 0; } } break; case(PT_APPTIME): if ((TmpProp.Value.at - lpPropRes->lpProp->Value.at) < 0) { nComp = -1; } else if ((TmpProp.Value.at - lpPropRes->lpProp->Value.at) == 0) { nComp = 0; } else { nComp = 1; } break;
case(PT_SYSTIME): nComp = CompareFileTime(&(TmpProp.Value.ft), (FILETIME *) (&(lpPropRes->lpProp->Value.ft))); break;
case(PT_TSTRING): nComp = lstrcmpi(TmpProp.Value.LPSZ,lpPropRes->lpProp->Value.LPSZ); break;
case(PT_BINARY): min = (TmpProp.Value.bin.cb < lpPropRes->lpProp->Value.bin.cb) ? TmpProp.Value.bin.cb : lpPropRes->lpProp->Value.bin.cb; k=0; nComp=0; while((k<min) && ((int)TmpProp.Value.bin.lpb[k] == (int)lpPropRes->lpProp->Value.bin.lpb[k])) k++; //find first difference
if (k!=min) nComp = (int) TmpProp.Value.bin.lpb[k] - (int) lpPropRes->lpProp->Value.bin.lpb[k]; break;
case(PT_CLSID): nComp = IsEqualGUID(TmpProp.Value.lpguid,lpPropRes->lpProp->Value.lpguid); break;
case(PT_I8): // ??? TBD how to do this one ??
if((TmpProp.Value.li.HighPart - lpPropRes->lpProp->Value.li.HighPart) < 0) { nComp = -1; } else if((TmpProp.Value.li.HighPart - lpPropRes->lpProp->Value.li.HighPart) > 0) { nComp = +1; } else { if(TmpProp.Value.li.LowPart < lpPropRes->lpProp->Value.li.LowPart) { nComp = -1; } else if((TmpProp.Value.li.LowPart - lpPropRes->lpProp->Value.li.LowPart) > 0) { nComp = +1; } else { nComp = 0; } } break;
default: break; }
// If we get what we are looking for then there is no need to look at the
// rest of the record. In that case we go to the next record.
//
switch(ulRelOp) { case(RELOP_EQ): if (nComp == 0) { // We got atleast one match, so we can store this entryID and
// skip to next record
lpdwEID[ulcEIDCount++] = MPSWabRecordHeader.dwEntryID; bMatchFound = TRUE; } break; case(RELOP_NE): // We can only declare success for the != operator if and only if all values
// of this property in the record do not meet the given value.
// This means that we have to scan the whole record before we can declare success.
// Thus, instead of marking the flag on success, we actually mark it on
// failure. At the end of the 'for' loop, if there was even 1 failure in the
// test, we can mark the record as having failed our test.
if (nComp == 0) { bMatchFound = TRUE; } break; case(RELOP_GT): if (nComp > 0) { // We got atleast one match, so we can store this entryID and
// skip to next record
lpdwEID[ulcEIDCount++] = MPSWabRecordHeader.dwEntryID; bMatchFound = TRUE; } break; case(RELOP_GE): if (nComp >= 0) { // We got atleast one match, so we can store this entryID and
// skip to next record
lpdwEID[ulcEIDCount++] = MPSWabRecordHeader.dwEntryID; bMatchFound = TRUE; } break; case(RELOP_LT): if (nComp < 0) { // We got atleast one match, so we can store this entryID and
// skip to next record
lpdwEID[ulcEIDCount++] = MPSWabRecordHeader.dwEntryID; bMatchFound = TRUE; } break; case(RELOP_LE): if (nComp <= 0) { // We got atleast one match, so we can store this entryID and
// skip to next record
lpdwEID[ulcEIDCount++] = MPSWabRecordHeader.dwEntryID; bMatchFound = TRUE; } break; default: break; }
switch(PROP_TYPE(TmpProp.ulPropTag)) { case(PT_CLSID): case(PT_TSTRING): LocalFreeAndNull((LPVOID *) (&TmpProp.Value.LPSZ)); break; case(PT_BINARY): LocalFreeAndNull((LPVOID *) (&TmpProp.Value.bin.lpb)); break; }
// if we got a match above, we dont look in this record anymore
if (bMatchFound) break;
} //(for i= ...
if ((ulRelOp == RELOP_NE) && (bMatchFound == FALSE)) { //We exited the for loop legitimately and still didnt find a match
//so we can finally declare a success for this one relop
lpdwEID[ulcEIDCount++] = MPSWabRecordHeader.dwEntryID; }
} //else
if ((ulcEIDCount == ulMaxCount) && (ulMaxCount != 0)) { // got enough records to return
// break out of do loop
break; }
LocalFreeAndNull(&szBuf);
LocalFreeAndNull(&lpulPropTagArray);
}//for loop
filterFolderMembers: #define WAB_IGNORE_ENTRY 0xFFFFFFFF
// if a folder was specified, only return the entries that are part of this folder
// pmbinFold will be NULL when there is no Outlook and no profiles
// otherwise it will have something in it
// If pmbinFold->cb and ->lpb are empty, then this is the virtual PAB folder and
// we want to return EVERYTHING in it
if(pmbinFold)// && pmbinFold->cb && pmbinFold->lpb)
{ // if it is the virtual root folder, only accept entries that dont have
// PR_WAB_FOLDER_PARENT set on it
// if it is not the root virtual folder, only return this entry if it is
// a member of the folder
/***/ if(!pmbinFold->cb && !pmbinFold->lpb) { // only accept entries that dont have PR_WAB_FOLDER_PARENT
for(i=0;i<ulcEIDCount;i++) { ULONG ulObjType = 0; if(bIsFolderMember(hMPSWabFile, lpMPSWabFileInfo, lpdwEID[i], &ulObjType)) lpdwEID[i] = WAB_IGNORE_ENTRY; //if(ulObjType == RECORD_CONTAINER)
// lpdwEID[i] = WAB_IGNORE_ENTRY;
} } else if(pmbinFold->cb && pmbinFold->lpb) /****/ { LPDWORD lpdwFolderEIDs = NULL; ULONG ulFolderEIDs = 0; if(!HR_FAILED(GetFolderEIDs( hMPSWabFile, lpMPSWabFileInfo, pmbinFold, &ulFolderEIDs, &lpdwFolderEIDs))) { if(ulFolderEIDs && lpdwFolderEIDs) { for(i=0;i<ulcEIDCount;i++) { BOOL bFound = FALSE; for(j=0;j<ulFolderEIDs;j++) { if(lpdwEID[i] == lpdwFolderEIDs[j]) { bFound = TRUE; break; } } if(!bFound) lpdwEID[i] = WAB_IGNORE_ENTRY; } } else { // empty folder so dont return anything
ulcEIDCount = 0; if(lpdwEID) { LocalFree(lpdwEID); lpdwEID = NULL; } } } if(lpdwFolderEIDs) LocalFree(lpdwFolderEIDs); } }
*lpulcEIDCount = 0; if(lpdwEID && ulcEIDCount) { //So now if we got here, we can return the array
lpdwEntryIDs = LocalAlloc(LMEM_ZEROINIT, ulcEIDCount * SIZEOF_WAB_ENTRYID); if (!lpdwEntryIDs) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; }
for(i=0;i<ulcEIDCount;i++) { if(lpdwEID[i]!=WAB_IGNORE_ENTRY) { lpdwEntryIDs[*lpulcEIDCount]=lpdwEID[i]; (*lpulcEIDCount)++; } } }
hr = S_OK;
out:
if(!HR_FAILED(hr) && lpdwEntryIDs && *lpulcEIDCount) { // Convert to the array of SBinarys we will return
(*lprgsbEntryIDs) = LocalAlloc(LMEM_ZEROINIT, sizeof(SBinary) * (*lpulcEIDCount)); if(*lprgsbEntryIDs) { for(i=0;i<*lpulcEIDCount;i++) { (*lprgsbEntryIDs)[i].lpb = LocalAlloc(LMEM_ZEROINIT, SIZEOF_WAB_ENTRYID); if((*lprgsbEntryIDs)[i].lpb) { (*lprgsbEntryIDs)[i].cb = SIZEOF_WAB_ENTRYID; CopyMemory((*lprgsbEntryIDs)[i].lpb, &(lpdwEntryIDs[i]), SIZEOF_WAB_ENTRYID); } } } else *lpulcEIDCount = 0; // out of memory
}
if(lpdwEntryIDs) LocalFree(lpdwEntryIDs);
LocalFreeAndNull(&szBuf);
LocalFreeAndNull(&lpulPropTagArray);
LocalFreeAndNull(&lpdwEID);
if(bErrorDetected) TagWABFileError(lpMPSWabFileInfo->lpMPSWabFileHeader, hMPSWabFile);
if (hMPSWabFile) IF_WIN32(CloseHandle(hMPSWabFile);) IF_WIN16(CloseFile(hMPSWabFile);)
if(bLockFile) { if (bFileLocked) UnLockFileAccess(lpMPSWabFileInfo); }
return(hr); }
//$$//////////////////////////////////////////////////////////////////////////////////
//
// DeleteRecord
//
// IN hPropertyStore - handle to property store
// IN dwEntryID - EntryID of record to delete
//
// Basically, we invalidate the existing record specified by the EntryID
// and we also reduce the total count, update the modification count,
// and remove the corresponding indexes from all the 4 indexes
//
// Returns
// Success: S_OK
// Failure: E_FAIL
//
////////////////////////////////////////////////////////////////////////////////////
HRESULT DeleteRecord( IN HANDLE hPropertyStore, IN LPSBinary lpsbEID) { HRESULT hr = E_FAIL; ULONG nIndexPos = 0, j = 0, i = 0; HANDLE hMPSWabFile = NULL; DWORD dwNumofBytes = 0; ULONG index = 0; BOOL bFileLocked = FALSE; BOOL bEntryAlreadyDeleted = FALSE; DWORD dwEntryID = 0; MPSWab_RECORD_HEADER MPSWabRecordHeader; LPMPSWab_FILE_INFO lpMPSWabFileInfo; SBinary sbEID = {0};
LPPTGDATA lpPTGData=GetThreadStoragePointer();
if(pt_bIsWABOpenExSession) { // This is a WABOpenEx session using outlooks storage provider
if(!hPropertyStore) return MAPI_E_NOT_INITIALIZED;
{ LPWABSTORAGEPROVIDER lpWSP = (LPWABSTORAGEPROVIDER) hPropertyStore;
hr = lpWSP->lpVtbl->DeleteRecord(lpWSP, lpsbEID);
DebugTrace(TEXT("WABStorageProvider::DeleteRecord returned:%x\n"),hr);
return hr; } }
lpMPSWabFileInfo = hPropertyStore;
if(lpsbEID && lpsbEID->cb != SIZEOF_WAB_ENTRYID) { // this may be a WAB container .. reset the entryid to a WAB entryid
if(WAB_CONTAINER == IsWABEntryID(lpsbEID->cb, (LPENTRYID)lpsbEID->lpb, NULL,NULL,NULL,NULL,NULL)) { IsWABEntryID(lpsbEID->cb, (LPENTRYID)lpsbEID->lpb, (LPVOID*)&sbEID.lpb,(LPVOID*)&sbEID.cb,NULL,NULL,NULL); if(sbEID.cb == SIZEOF_WAB_ENTRYID) lpsbEID = &sbEID; } } if(!lpsbEID || lpsbEID->cb != SIZEOF_WAB_ENTRYID) { hr = MAPI_E_INVALID_PARAMETER; goto out; }
CopyMemory(&dwEntryID, lpsbEID->lpb, min(lpsbEID->cb, sizeof(dwEntryID)));
DebugTrace(TEXT("----Thread:%x\tDeleteRecord: Entry\n----EntryID:%d\n"),GetCurrentThreadId(),dwEntryID);
//
// If we had started this whole session requesting read-only access
// make sure we dont mistakenly try to violate it ...
//
if (lpMPSWabFileInfo->bReadOnlyAccess) { DebugTrace(TEXT("Access Permissions are Read-Only")); hr = MAPI_E_NO_ACCESS; goto out; }
if(!LockFileAccess(lpMPSWabFileInfo)) { DebugTrace(TEXT("LockFileAccess Failed\n")); hr = MAPI_E_NO_ACCESS; goto out; } else { bFileLocked = TRUE; }
//Open the file
hr = OpenWABFile(lpMPSWabFileInfo->lpszMPSWabFileName, NULL, &hMPSWabFile);
if ( (hMPSWabFile == INVALID_HANDLE_VALUE) || HR_FAILED(hr)) { DebugTrace(TEXT("Could not open file.\nExiting ...\n")); goto out; }
//
// To ensure that file info is accurate,
// Any time we open a file, read the file info again ...
//
if(!ReloadMPSWabFileInfo( lpMPSWabFileInfo, hMPSWabFile)) { DebugTrace(TEXT("Reading file info failed.\n")); goto out; }
//
// Anytime we detect an error - try to fix it ...
//
if((lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags & WAB_ERROR_DETECTED) || (lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags & WAB_WRITE_IN_PROGRESS)) { if(HR_FAILED(HrDoQuickWABIntegrityCheck(lpMPSWabFileInfo,hMPSWabFile))) { hr = HrDoDetailedWABIntegrityCheck(lpMPSWabFileInfo,hMPSWabFile); if(HR_FAILED(hr)) { DebugTrace(TEXT("HrDoDetailedWABIntegrityCheck failed:%x\n"),hr); goto out; } } }
// Tag this file as undergoing a write operation
if(!bTagWriteTransaction( lpMPSWabFileInfo->lpMPSWabFileHeader, hMPSWabFile) ) { DebugTrace(TEXT("Taggin file write failed\n")); goto out; }
//
// First check if this is a valid entryID
//
if (!BinSearchEID( IN lpMPSWabFileInfo->lpMPSWabIndexEID, IN dwEntryID, IN lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries, OUT &nIndexPos)) { DebugTrace(TEXT("Specified EntryID: %d doesnt exist!"),dwEntryID); hr = MAPI_E_INVALID_ENTRYID; goto out; }
//
// Yes it's valid. Go to this record and invalidate the record.
//
if(!ReadDataFromWABFile(hMPSWabFile, lpMPSWabFileInfo->lpMPSWabIndexEID[nIndexPos].ulOffset, (LPVOID) &MPSWabRecordHeader, (DWORD) sizeof(MPSWab_RECORD_HEADER))) goto out;
if ((MPSWabRecordHeader.bValidRecord == FALSE) && (MPSWabRecordHeader.bValidRecord != TRUE)) { //
// this should never happen but who knows
//
DebugTrace(TEXT("Specified entry has already been invalidated ...\n")); // hr = S_OK;
// goto out;
// if we hit an invalid entryid through the index, then we need to remove that link from the index
// so we'll go ahead and pretend that its all fine and continue like nothing happened.
// This will ensure that the entryid reference is also removed ...
bEntryAlreadyDeleted = TRUE; }
//
// Set valid flag to false
//
MPSWabRecordHeader.bValidRecord = FALSE;
//
// Write it back
// Set File Pointer to this record
//
if(!WriteDataToWABFile( hMPSWabFile, lpMPSWabFileInfo->lpMPSWabIndexEID[nIndexPos].ulOffset, (LPVOID) &MPSWabRecordHeader, sizeof(MPSWab_RECORD_HEADER))) goto out;
//
// Now we need to remove this entry from the EntryID index and also remove this
// entry from the other indexes
//
// Set File Pointer to the Pt. in the EntryID index on file
// at which this record appears
//
if (0xFFFFFFFF == SetFilePointer ( hMPSWabFile, lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulOffset + (nIndexPos)*sizeof(MPSWab_INDEX_ENTRY_DATA_ENTRYID), NULL, FILE_BEGIN)) { DebugTrace(TEXT("SetFilePointer Failed\n")); goto out; }
// Write the remainder of the array back to disk to overwrite this entry
if (lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries > (nIndexPos+1)) { if(!WriteFile( hMPSWabFile, (LPVOID) &lpMPSWabFileInfo->lpMPSWabIndexEID[nIndexPos+1], (DWORD) sizeof(MPSWab_INDEX_ENTRY_DATA_ENTRYID)*(lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries - nIndexPos - 1), &dwNumofBytes, NULL)) { DebugTrace(TEXT("Writing Index failed.\n")); goto out; } }
if(lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries>0) lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries--; if(lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].UtilizedBlockSize>0) lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].UtilizedBlockSize -= sizeof(MPSWab_INDEX_ENTRY_DATA_ENTRYID);
// DebugTrace(TEXT("Thread:%x\tIndex: %d\tulNumEntries: %d\n"),GetCurrentThreadId(),indexEntryID,lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries);
//
// Similarly scan the str index arrays
//
for (index = indexDisplayName; index < indexMax; index++) { if (!LoadIndex( IN lpMPSWabFileInfo, IN index, IN hMPSWabFile) ) { DebugTrace(TEXT("Error Loading Index!")); goto out; }
nIndexPos = 0xFFFFFFFF;
for(j=0;j<lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[index].ulcNumEntries;j++) { if (lpMPSWabFileInfo->lpMPSWabIndexStr[j].dwEntryID == dwEntryID) { nIndexPos = j; break; } }
// if the entry doesnt exist .. no problem
// if it does - delete it ...
if (index == indexDisplayName) Assert(nIndexPos != 0xFFFFFFFF);
if (nIndexPos != 0xFFFFFFFF) {
if (0xFFFFFFFF == SetFilePointer ( hMPSWabFile, lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[index].ulOffset + (nIndexPos)*sizeof(MPSWab_INDEX_ENTRY_DATA_STRING), NULL, FILE_BEGIN)) { DebugTrace(TEXT("SetFilePointer Failed\n")); goto out; }
// Write the remainder of the array back to disk to overwrite this entry
if (lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[index].ulcNumEntries > (nIndexPos+1)) { if(!WriteFile( hMPSWabFile, (LPVOID) &lpMPSWabFileInfo->lpMPSWabIndexStr[nIndexPos+1], (DWORD) sizeof(MPSWab_INDEX_ENTRY_DATA_STRING)*(lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[index].ulcNumEntries - nIndexPos - 1), &dwNumofBytes, NULL)) { DebugTrace(TEXT("Writing Index failed.\n")); goto out; } }
if(lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[index].ulcNumEntries>0) lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[index].ulcNumEntries--; if(lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[index].UtilizedBlockSize>0) lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[index].UtilizedBlockSize -= sizeof(MPSWab_INDEX_ENTRY_DATA_STRING);
//DebugTrace(TEXT("Thread:%x\tIndex: %d\tulNumEntries: %d\n"),GetCurrentThreadId(),index,lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[index].ulcNumEntries);
} }
// Save the fileheader back to the file
if(!bEntryAlreadyDeleted) { if(lpMPSWabFileInfo->lpMPSWabFileHeader->ulcNumEntries>0) lpMPSWabFileInfo->lpMPSWabFileHeader->ulcNumEntries--; lpMPSWabFileInfo->lpMPSWabFileHeader->ulModificationCount++; lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags |= WAB_BACKUP_NOW; }
if (0xFFFFFFFF == SetFilePointer ( hMPSWabFile, 0, NULL, FILE_BEGIN)) { DebugTrace(TEXT("SetFilePointer Failed\n")); goto out; }
if(lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries != lpMPSWabFileInfo->lpMPSWabFileHeader->ulcNumEntries) lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags |= WAB_ERROR_DETECTED;
for(i=indexDisplayName;i<indexMax;i++) { if(lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[i].ulcNumEntries > lpMPSWabFileInfo->lpMPSWabFileHeader->ulcNumEntries) lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags |= WAB_ERROR_DETECTED; }
if(!WriteFile( hMPSWabFile, (LPVOID) lpMPSWabFileInfo->lpMPSWabFileHeader, (DWORD) sizeof(MPSWab_FILE_HEADER), &dwNumofBytes, NULL)) { DebugTrace(TEXT("Writing FileHeader Failed failed.\n")); goto out; }
if ( (lpMPSWabFileInfo->lpMPSWabFileHeader->ulModificationCount > MAX_ALLOWABLE_WASTED_SPACE_ENTRIES) ) // ||
{ // above condition means that if more than space for 50 entries is wasted
// of if number of modifications are more than the number of entries
// we should clean up the file
if (!CompressFile( lpMPSWabFileInfo, hMPSWabFile, NULL, FALSE, 0)) { DebugTrace(TEXT("Thread:%x\tCompress file failed\n"),GetCurrentThreadId()); hr = E_FAIL; goto out; } }
hr = S_OK;
out:
// UnTag this file as undergoing a write operation
// We only want the flag to stay there during crashes not during
// normal operations
//
if(lpMPSWabFileInfo) { if(!bUntagWriteTransaction( lpMPSWabFileInfo->lpMPSWabFileHeader, hMPSWabFile) ) { DebugTrace(TEXT("Untaggin file write failed\n")); } }
if (hMPSWabFile) IF_WIN32(CloseHandle(hMPSWabFile);) IF_WIN16(CloseFile(hMPSWabFile);)
if (bFileLocked) UnLockFileAccess(lpMPSWabFileInfo);
//DebugTrace(TEXT("----Thread:%x\tDeleteRecords: Exit\n"),GetCurrentThreadId());
return(hr); }
/*
- - ReadRecordFreePropArray * * Memory from ReadRecord can be obtained through a convoluted plethora of different * allocation types .. we therefore need to free it much more safely than other memory types * */ void ReadRecordFreePropArray(HANDLE hPropertyStore, ULONG ulcPropCount, LPSPropValue * lppPropArray) { LPPTGDATA lpPTGData=GetThreadStoragePointer();
if( pt_bIsWABOpenExSession && //outlook session
!pt_bIsUnicodeOutlook && //outlook doesn't support Unicode
!lpfnAllocateMoreExternal ) //don't have an outlook allocator
{ // this is special case MAPI Allocated memory
FreeBufferAndNull(lppPropArray); } else LocalFreePropArray(hPropertyStore, ulcPropCount, lppPropArray); }
/*
- - HrDupeOlkPropsAtoWC * * Outlook properties are unmungable without having the outlook allocators * In an independent WAB session, the Outlook allocators are not available, hence * we have to recreate the property arrays with the WAB allocators so we can modify * them and turn them from Outlooks non-unicode to the WAB's needed unicode format. */ HRESULT HrDupeOlkPropsAtoWC(ULONG ulCount, LPSPropValue lpPropArray, LPSPropValue * lppSPVNew) { HRESULT hr = S_OK; SCODE sc = 0; LPSPropValue lpSPVNew = NULL; ULONG cb = 0; if (FAILED(sc = ScCountProps(ulCount, lpPropArray, &cb))) { hr = ResultFromScode(sc); goto exit; }
if (FAILED(sc = MAPIAllocateBuffer(cb, &lpSPVNew))) { hr = ResultFromScode(sc); goto exit; }
if (FAILED(sc = ScCopyProps(ulCount, lpPropArray, lpSPVNew, NULL))) { hr = ResultFromScode(sc); goto exit; }
// [PaulHi] Raid 73237 @hack
// Outlook marks the contact as mail or DL (group) through the PR_DISPLAY_TYPE
// property tag. However, the WAB relies on the PR_OBJECT_TYPE tag to determine
// how the contact appears in the listview. If there is no PR_OBJECT_TYPE tag
// but there is a PR_DISPLAY_TYPE tag then convert it to PR_OBJECT_TYPE.
{ ULONG ul; ULONG ulDpType = (ULONG)(-1); BOOL bConvert = TRUE;
for (ul=0; ul<ulCount; ul++) { if (lpSPVNew[ul].ulPropTag == PR_OBJECT_TYPE) { bConvert = FALSE; break; } else if (lpSPVNew[ul].ulPropTag == PR_DISPLAY_TYPE) ulDpType = ul; } if ( bConvert && (ulDpType != (ULONG)(-1)) ) { // Convert PR_DISPLAY_TYPE to PR_OBJECT_TYPE
lpSPVNew[ulDpType].ulPropTag = PR_OBJECT_TYPE; if ( (lpSPVNew[ulDpType].Value.ul == DT_PRIVATE_DISTLIST) || (lpSPVNew[ulDpType].Value.ul == DT_DISTLIST) ) { lpSPVNew[ulDpType].Value.ul = MAPI_DISTLIST; } else { lpSPVNew[ulDpType].Value.ul = MAPI_MAILUSER; } } }
if(FAILED(sc = ScConvertAPropsToW((LPALLOCATEMORE)(&MAPIAllocateMore), lpSPVNew, ulCount, 0))) { hr = ResultFromScode(sc); goto exit; }
*lppSPVNew = lpSPVNew;
exit: if(HR_FAILED(hr)) { FreeBufferAndNull(&lpSPVNew); *lppSPVNew = NULL; }
return hr; }
//$$//////////////////////////////////////////////////////////////////////////////////
//
// ReadRecord
//
// IN hPropertyStore - handle to property store
// IN dwEntryID - EntryID of record to read
// IN ulFlags
// OUT ulcPropCount - number of props returned
// OUT lpPropArray - Array of Property values
//
// Basically, we find the record offset, read in the record, copy the data
// into SPropValue arrays and return the arrays
//
// IMPORTANT NOTE: To free memory allocated from here call ReadRecordFreePropArray
// Returns
// Success: S_OK
// Failure: E_FAIL
//
////////////////////////////////////////////////////////////////////////////////////
HRESULT ReadRecord( IN HANDLE hPropertyStore, IN LPSBinary lpsbEntryID, IN ULONG ulFlags, OUT LPULONG lpulcPropCount, OUT LPPROPERTY_ARRAY * lppPropArray) { HRESULT hr = E_FAIL; HANDLE hMPSWabFile = NULL; BOOL bFileLocked = FALSE; DWORD dwEntryID = 0; MPSWab_RECORD_HEADER MPSWabRecordHeader = {0}; LPMPSWab_FILE_INFO lpMPSWabFileInfo = hPropertyStore; SBinary sbEID = {0};
LPPTGDATA lpPTGData=GetThreadStoragePointer();
if(pt_bIsWABOpenExSession && !(ulFlags & AB_IGNORE_OUTLOOK)) { // This is a WABOpenEx session using outlooks storage provider
if(!hPropertyStore) return MAPI_E_NOT_INITIALIZED;
{ LPWABSTORAGEPROVIDER lpWSP = (LPWABSTORAGEPROVIDER) hPropertyStore;
hr = lpWSP->lpVtbl->ReadRecord( lpWSP, lpsbEntryID, ulFlags, lpulcPropCount, lppPropArray);
DebugTrace(TEXT("WABStorageProvider::ReadRecord returned:%x\n"),hr);
if(!HR_FAILED(hr) && *lpulcPropCount && *lppPropArray && !pt_bIsUnicodeOutlook) { // Map all the contacts props to Unicode if needed since Outlook9 and older don't
// support unicode
SCODE sc = 0; if(lpfnAllocateMoreExternal) { // the memory that comes from outlook is allocated using outlooks allocators
// and we can't mess with it .. unless we have the allocators passed in through
// wabopenex
if(sc = ScConvertAPropsToW(lpfnAllocateMoreExternal, *lppPropArray, *lpulcPropCount, 0)) hr = ResultFromScode(sc); } else { // we don't have external allocators, which means we need to muck with reallocating memory etc
// therefore we'll need to duplicate the prop array and then convert it
//
// Because of this mess, we need to have a special way of releasing this memory so
// we don't leak all over the place
ULONG ulCount = *lpulcPropCount; LPSPropValue lpSPVNew = NULL;
if(HR_FAILED(hr = HrDupeOlkPropsAtoWC(ulCount, *lppPropArray, &lpSPVNew))) goto exit;
// Free the old props
LocalFreePropArray(hPropertyStore, *lpulcPropCount, lppPropArray); *lppPropArray = lpSPVNew; *lpulcPropCount = ulCount; } } exit: return hr; } }
if(lpsbEntryID && lpsbEntryID->cb != SIZEOF_WAB_ENTRYID) { // this may be a WAB container .. reset the entryid to a WAB entryid
if(WAB_CONTAINER == IsWABEntryID(lpsbEntryID->cb, (LPENTRYID)lpsbEntryID->lpb, NULL,NULL,NULL,NULL,NULL)) { IsWABEntryID(lpsbEntryID->cb, (LPENTRYID)lpsbEntryID->lpb, (LPVOID*)&sbEID.lpb, (LPVOID*)&sbEID.cb, NULL,NULL,NULL); if(sbEID.cb == SIZEOF_WAB_ENTRYID) lpsbEntryID = &sbEID; } } if(!lpsbEntryID || lpsbEntryID->cb != SIZEOF_WAB_ENTRYID) { hr = MAPI_E_INVALID_PARAMETER; goto out; }
CopyMemory(&dwEntryID, lpsbEntryID->lpb, min(lpsbEntryID->cb, sizeof(dwEntryID)));
//DebugTrace(TEXT("--ReadRecord: dwEntryID=%d\n"), dwEntryID);
*lpulcPropCount = 0; *lppPropArray = NULL;
if(!LockFileAccess(lpMPSWabFileInfo)) { DebugTrace(TEXT("LockFileAccess Failed\n")); hr = MAPI_E_NO_ACCESS; goto out; } else { bFileLocked = TRUE; }
//Open the file
hr = OpenWABFile(lpMPSWabFileInfo->lpszMPSWabFileName, NULL, &hMPSWabFile);
if ( (hMPSWabFile == INVALID_HANDLE_VALUE) || HR_FAILED(hr)) { DebugTrace(TEXT("Could not open file.\nExiting ...\n")); goto out; }
//
// To ensure that file info is accurate,
// Any time we open a file, read the file info again ...
//
if(!ReloadMPSWabFileInfo( lpMPSWabFileInfo, hMPSWabFile)) { DebugTrace(TEXT("Reading file info failed.\n")); goto out; }
//
// Anytime we detect an error - try to fix it ...
//
if((lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags & WAB_ERROR_DETECTED) || (lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags & WAB_WRITE_IN_PROGRESS)) { if(HR_FAILED(HrDoQuickWABIntegrityCheck(lpMPSWabFileInfo,hMPSWabFile))) { hr = HrDoDetailedWABIntegrityCheck(lpMPSWabFileInfo,hMPSWabFile); if(HR_FAILED(hr)) { DebugTrace(TEXT("HrDoDetailedWABIntegrityCheck failed:%x\n"),hr); goto out; } } }
hr = ReadRecordWithoutLocking( hMPSWabFile, lpMPSWabFileInfo, dwEntryID, lpulcPropCount, lppPropArray);
out:
//a little cleanup on failure
if (FAILED(hr)) { if ((*lppPropArray) && (MPSWabRecordHeader.ulcPropCount > 0)) { LocalFreePropArray(hPropertyStore, MPSWabRecordHeader.ulcPropCount, lppPropArray); *lppPropArray = NULL; } }
if(hMPSWabFile) IF_WIN32(CloseHandle(hMPSWabFile);) IF_WIN16(CloseFile(hMPSWabFile);)
if (bFileLocked) UnLockFileAccess(lpMPSWabFileInfo);
//DebugTrace(( TEXT("ReadRecord: Exit\n-----------\n")));
return(hr); }
#ifdef OLD_STUFF /*
//$$//////////////////////////////////////////////////////////////////////////////////
//
// ReadIndex - Given a specified proptag, returns an array containing all the
// data in the addressbook that corresponds to the supplied proptag
//
// IN hPropertyStore - handle to property store
// IN ulPropTag - EntryID of record to read
// OUT lpulEIDCount - number of props returned
// OUT lppdwIndex - Array of Property values
//
// Basically, we find the record offset, read in the record, copy the data
// into SPropValue arrays and return the arrays.
//
// Each SPropValue within the array corresponds to data for that prop in
// the property store. The SPropVal.Value holds the data and the
// SPropVal.ulPropTag holds the **ENTRY-ID** of the record containing
// the data and not any prop tag value
//
// Returns
// Success: S_OK
// Failure: E_FAIL
//
////////////////////////////////////////////////////////////////////////////////////
HRESULT ReadIndex( IN HANDLE hPropertyStore, IN PROPERTY_TAG ulPropTag, OUT LPULONG lpulEIDCount, OUT LPPROPERTY_ARRAY * lppdwIndex) { HRESULT hr = E_FAIL; SPropertyRestriction PropRes; ULONG ulPropCount = 0; ULONG ulEIDCount = 0; //ULONG ulArraySize = 0;
LPDWORD lpdwEntryIDs = NULL; HANDLE hMPSWabFile = NULL; DWORD dwNumofBytes = 0; LPPROPERTY_ARRAY lpPropArray = NULL; TCHAR * szBuf = NULL; TCHAR * lp = NULL; ULONG i=0,j=0,k=0; ULONG nIndexPos=0,ulRecordOffset = 0; BOOL bFileLocked = FALSE; BOOL bMatchFound = FALSE; ULONG ulDataSize = 0; ULONG ulcValues = 0; ULONG ulTmpPropTag = 0; ULONG ulFileSize = 0; BOOL bErrorDetected = FALSE;
MPSWab_RECORD_HEADER MPSWabRecordHeader = {0}; LPMPSWab_FILE_INFO lpMPSWabFileInfo = hPropertyStore;
DebugTrace(( TEXT("-----------\nReadIndex: Entry\n")));
*lpulEIDCount = 0; *lppdwIndex = NULL;
if(!LockFileAccess(lpMPSWabFileInfo)) { DebugTrace(TEXT("LockFileAccess Failed\n")); hr = MAPI_E_NO_ACCESS; goto out; } else { bFileLocked = TRUE; }
PropRes.ulPropTag = ulPropTag; PropRes.relop = RELOP_EQ; PropRes.lpProp = NULL;
hr = FindRecords( IN hPropertyStore, IN AB_MATCH_PROP_ONLY, FALSE, &PropRes, &ulEIDCount, &lpdwEntryIDs);
if (FAILED(hr)) goto out;
//reset hr
hr = E_FAIL;
if (ulEIDCount == 0) { DebugTrace(TEXT("No Records Found\n")); hr = MAPI_E_NOT_FOUND; goto out; }
// We now know that we are going to get ulEIDCount records
// We will assume that each record has only 1 property which we are interested in
lpPropArray = LocalAlloc(LMEM_ZEROINIT, ulEIDCount * sizeof(SPropValue)); if (!lpPropArray) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; }
//Open the file
hr = OpenWABFile(lpMPSWabFileInfo->lpszMPSWabFileName, NULL, &hMPSWabFile);
if ( (hMPSWabFile == INVALID_HANDLE_VALUE) || HR_FAILED(hr)) { DebugTrace(TEXT("Could not open file.\nExiting ...\n")); goto out; }
ulFileSize = GetFileSize(hMPSWabFile, NULL);
//
// To ensure that file info is accurate,
// Any time we open a file, read the file info again ...
//
if(!ReloadMPSWabFileInfo( lpMPSWabFileInfo, hMPSWabFile)) { DebugTrace(TEXT("Reading file info failed.\n")); goto out; }
//
// Anytime we detect an error - try to fix it ...
//
if((lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags & WAB_ERROR_DETECTED) || (lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags & WAB_WRITE_IN_PROGRESS)) { if(HR_FAILED(HrDoQuickWABIntegrityCheck(lpMPSWabFileInfo,hMPSWabFile))) { hr = HrDoDetailedWABIntegrityCheck(lpMPSWabFileInfo,hMPSWabFile); if(HR_FAILED(hr)) { DebugTrace(TEXT("HrDoDetailedWABIntegrityCheck failed:%x\n"),hr); goto out; } } }
// ulArraySize = 0;
*lpulEIDCount = 0;
ulPropCount = 0; for(i = 0; i < ulEIDCount; i++) {
//Get offset for this entryid
if (!BinSearchEID( IN lpMPSWabFileInfo->lpMPSWabIndexEID, IN lpdwEntryIDs[i], IN lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries, OUT &nIndexPos)) { DebugTrace(TEXT("Specified EntryID doesnt exist!\n")); continue; //goto out;
}
ulRecordOffset = lpMPSWabFileInfo->lpMPSWabIndexEID[nIndexPos].ulOffset;
if(!ReadDataFromWABFile(hMPSWabFile, ulRecordOffset, (LPVOID) &MPSWabRecordHeader, (DWORD) sizeof(MPSWab_RECORD_HEADER))) goto out;
if(!bIsValidRecord( MPSWabRecordHeader, lpMPSWabFileInfo->lpMPSWabFileHeader->dwNextEntryID, ulRecordOffset, ulFileSize)) // if ((MPSWabRecordHeader.bValidRecord == FALSE) && (MPSWabRecordHeader.bValidRecord != TRUE))
{ //this should never happen but who knows
DebugTrace(TEXT("Error: Obtained an invalid record ...\n")); bErrorDetected = TRUE; //hr = MAPI_E_INVALID_OBJECT;
//goto out;
//ignore it and continue
continue; }
//ReadData
LocalFreeAndNull(&szBuf);
szBuf = LocalAlloc(LMEM_ZEROINIT, MPSWabRecordHeader.ulRecordDataSize); if (!szBuf) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; }
// Set File Pointer to beginning of Data Section
if (0xFFFFFFFF == SetFilePointer ( hMPSWabFile, MPSWabRecordHeader.ulPropTagArraySize, NULL, FILE_CURRENT)) { DebugTrace(TEXT("SetFilePointer Failed\n")); goto out; }
//Read in the data
// Read record header
if(!ReadFile( hMPSWabFile, (LPVOID) szBuf, (DWORD) MPSWabRecordHeader.ulRecordDataSize, &dwNumofBytes, NULL)) { DebugTrace(TEXT("Reading Record Header failed.\n")); goto out; }
lp = szBuf;
// Go through all the properties in this record searching for the
// desired one ...
bMatchFound = FALSE; ulDataSize = 0; ulcValues = 0; ulTmpPropTag = 0;
for (j = 0; j< MPSWabRecordHeader.ulcPropCount; j++) {
CopyMemory(&ulTmpPropTag,lp,sizeof(ULONG)); lp+=sizeof(ULONG);
if ((ulTmpPropTag & MV_FLAG)) { CopyMemory(&ulcValues,lp,sizeof(ULONG)); lp += sizeof(ULONG); //skip cValues
} CopyMemory(&ulDataSize,lp,sizeof(ULONG)); lp+=sizeof(ULONG);
// if the tag doesnt match, skip this property
if (ulTmpPropTag != ulPropTag) //skip
{ lp += ulDataSize; //skip over data
continue; } else { bMatchFound = TRUE; break; } } // for j ...
if (bMatchFound) {
//
// if we are here, the property matched and we want its data
//
//
// **** note: ***** we store the entryid in the proptag variable
//
lpPropArray[ulPropCount].ulPropTag = lpdwEntryIDs[i];
if ((ulPropTag & MV_FLAG)) { //now get the data
switch(PROP_TYPE(ulPropTag)) { case(PT_MV_I2): case(PT_MV_LONG): case(PT_MV_R4): case(PT_MV_DOUBLE): case(PT_MV_CURRENCY): case(PT_MV_APPTIME): case(PT_MV_SYSTIME): case(PT_MV_CLSID): case(PT_MV_I8): lpPropArray[ulPropCount].Value.MVi.lpi = LocalAlloc(LMEM_ZEROINIT,ulDataSize); if (!(lpPropArray[ulPropCount].Value.MVi.lpi)) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; } lpPropArray[ulPropCount].Value.MVi.cValues = ulcValues; CopyMemory(lpPropArray[ulPropCount].Value.MVi.lpi, lp, ulDataSize); lp += ulDataSize; break;
case(PT_MV_BINARY): lpPropArray[ulPropCount].Value.MVbin.lpbin = LocalAlloc(LMEM_ZEROINIT, ulcValues * sizeof(SBinary)); if (!(lpPropArray[ulPropCount].Value.MVbin.lpbin)) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; } lpPropArray[ulPropCount].Value.MVbin.cValues = ulcValues; for (k=0;k<ulcValues;k++) { ULONG nLen; // copy cBytes
CopyMemory(&nLen, lp, sizeof(ULONG)); lp += sizeof(ULONG); lpPropArray[ulPropCount].Value.MVbin.lpbin[k].cb = nLen; lpPropArray[ulPropCount].Value.MVbin.lpbin[k].lpb = LocalAlloc(LMEM_ZEROINIT, nLen); if (!(lpPropArray[ulPropCount].Value.MVbin.lpbin[k].lpb)) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; } CopyMemory(lpPropArray[ulPropCount].Value.MVbin.lpbin[k].lpb, lp, nLen); lp += nLen; } lpPropArray[ulPropCount].Value.MVbin.cValues = ulcValues; break;
case(PT_MV_TSTRING): lpPropArray[ulPropCount].Value.MVSZ.LPPSZ = LocalAlloc(LMEM_ZEROINIT, ulcValues * sizeof(LPTSTR)); if (!(lpPropArray[ulPropCount].Value.MVSZ.LPPSZ)) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; } for (k=0;k<ulcValues;k++) { ULONG nLen; // get string length (includes terminating zero)
CopyMemory(&nLen, lp, sizeof(ULONG)); lp += sizeof(ULONG); lpPropArray[ulPropCount].Value.MVSZ.LPPSZ[k] = LocalAlloc(LMEM_ZEROINIT, nLen); if (!(lpPropArray[ulPropCount].Value.MVSZ.LPPSZ[k])) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; } CopyMemory(lpPropArray[ulPropCount].Value.MVSZ.LPPSZ[k], lp, nLen); lp += nLen; } lpPropArray[ulPropCount].Value.MVSZ.cValues = ulcValues; break;
} //switch
} else { //Single Valued
switch(PROP_TYPE(ulPropTag)) { case(PT_I2): case(PT_LONG): case(PT_APPTIME): case(PT_SYSTIME): case(PT_R4): case(PT_BOOLEAN): case(PT_CURRENCY): case(PT_I8): CopyMemory(&(lpPropArray[ulPropCount].Value.i),lp,ulDataSize); lp+=ulDataSize; break; case(PT_CLSID): case(PT_TSTRING): lpPropArray[ulPropCount].Value.LPSZ = LocalAlloc(LMEM_ZEROINIT,ulDataSize); if (!(lpPropArray[ulPropCount].Value.LPSZ)) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; } CopyMemory(lpPropArray[ulPropCount].Value.LPSZ,lp,ulDataSize); lp+=ulDataSize; break; case(PT_BINARY): lpPropArray[ulPropCount].Value.bin.lpb = LocalAlloc(LMEM_ZEROINIT,ulDataSize); if (!(lpPropArray[ulPropCount].Value.bin.lpb)) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; } CopyMemory(lpPropArray[ulPropCount].Value.bin.lpb,lp,ulDataSize); lpPropArray[ulPropCount].Value.bin.cb = ulDataSize; lp+=ulDataSize; break;
} //switch
} // if MV_PROP
ulPropCount++;
} // if bMatchFound
} //for i=
DebugTrace(( TEXT("ulPropCount: %d\tulEIDCount: %d\n"),ulPropCount, ulEIDCount));
//Got all the prop tags
if (lpPropArray) { *lpulEIDCount = ulPropCount; *lppdwIndex = lpPropArray; }
hr = S_OK;
out:
LocalFreeAndNull(&lpdwEntryIDs);
if (FAILED(hr)) { if((lpPropArray) && (ulEIDCount > 0)) LocalFreePropArray(hPropertyStore, ulEIDCount,&lpPropArray); *lppdwIndex = NULL; *lpulEIDCount = 0; }
if(bErrorDetected) TagWABFileError(lpMPSWabFileInfo->lpMPSWabFileHeader, hMPSWabFile);
if(hMPSWabFile) IF_WIN32(CloseHandle(hMPSWabFile);) IF_WIN16(CloseFile(hMPSWabFile);)
if (bFileLocked) UnLockFileAccess(lpMPSWabFileInfo);
DebugTrace(( TEXT("ReadIndex: Exit\n-----------\n")));
return(hr); } */ #endif // OLD_STUFF
//$$//////////////////////////////////////////////////////////////////////////////////
//
// BackupPropertyStore - Creates a clean, backup version of the property store
//
// IN hPropertyStore - handle to property store
// IN lpszBackupFileName - name to back up in ...
//
// Returns
// Success: S_OK
// Failure: E_FAIL
//
////////////////////////////////////////////////////////////////////////////////////
HRESULT BackupPropertyStore(HANDLE hPropertyStore, LPTSTR lpszBackupFileName) { HRESULT hr = E_FAIL; HANDLE hMPSWabFile = NULL; BOOL bWFileLocked = FALSE; DWORD dwNumofBytes = 0;
LPMPSWab_FILE_INFO lpMPSWabFileInfo = hPropertyStore;
HCURSOR hOldCur = SetCursor(LoadCursor(NULL,IDC_WAIT));
DebugTrace(( TEXT("BackupPropertyStore: Entry\n")));
if (lpszBackupFileName == NULL) { DebugTrace(TEXT("Invalid backup file name\n")); hr = MAPI_E_INVALID_PARAMETER; goto out; }
if(!LockFileAccess(lpMPSWabFileInfo)) { DebugTrace(TEXT("LockFileAccess Failed\n")); goto out; } else { bWFileLocked = TRUE; }
hMPSWabFile = CreateFile( lpMPSWabFileInfo->lpszMPSWabFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, (LPSECURITY_ATTRIBUTES) NULL, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, (HANDLE) NULL); if (hMPSWabFile == INVALID_HANDLE_VALUE) { DebugTrace(TEXT("Could not open file.\nExiting ...\n")); goto out; }
//
// We dont want to back up this file if it has errors in it so first
// check for errors
//
if(!ReloadMPSWabFileInfo( lpMPSWabFileInfo, hMPSWabFile)) { DebugTrace(TEXT("Reading file info failed.\n")); goto out; }
if(!(lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags & WAB_BACKUP_NOW)) { DebugTrace(( TEXT("No need to backup!\n"))); hr = S_OK; goto out; }
if(lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags & (WAB_ERROR_DETECTED | WAB_WRITE_IN_PROGRESS)) { DebugTrace(TEXT("Errors in file - Won't backup!\n")); goto out; }
DebugTrace( TEXT("Backing up to %s\n"),lpszBackupFileName);
//
// reset the backup flag before backing up
//
lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags &= ~WAB_BACKUP_NOW;
if(!WriteDataToWABFile( hMPSWabFile, 0, (LPVOID) lpMPSWabFileInfo->lpMPSWabFileHeader, sizeof(MPSWab_FILE_HEADER))) goto out;
if (!CompressFile( lpMPSWabFileInfo, hMPSWabFile, lpszBackupFileName, FALSE, 0)) { DebugTrace(TEXT("Compress file failed\n")); goto out; }
//SetFileAttributes(lpszBackupFileName, FILE_ATTRIBUTE_HIDDEN);
hr = S_OK;
out:
if (hMPSWabFile) IF_WIN32(CloseHandle(hMPSWabFile);) IF_WIN16(CloseFile(hMPSWabFile);)
if(bWFileLocked) UnLockFileAccess(lpMPSWabFileInfo);
SetCursor(hOldCur);
DebugTrace(( TEXT("BackupPropertyStore: Exit\n")));
return hr; }
//$$//////////////////////////////////////////////////////////////////////////////////
//
// UnlockFileAccess - UnLocks Exclusive Access to the property store
//
////////////////////////////////////////////////////////////////////////////////////
BOOL UnLockFileAccessTmp(LPMPSWab_FILE_INFO lpMPSWabFileInfo) { BOOL bRet = FALSE;
DebugTrace(( TEXT("\t\tUnlockFileAccess: Entry\n")));
if(lpMPSWabFileInfo) bRet = ReleaseMutex(lpMPSWabFileInfo->hDataAccessMutex);
return bRet; }
//$$//////////////////////////////////////////////////////////////////////////////////
//
// LockFileAccess - Gives exclusive access to the Property Store
//
////////////////////////////////////////////////////////////////////////////////////
BOOL LockFileAccessTmp(LPMPSWab_FILE_INFO lpMPSWabFileInfo) { BOOL bRet = FALSE; DWORD dwWait = 0;
DebugTrace(( TEXT("\t\tLockFileAccess: Entry\n")));
if(lpMPSWabFileInfo) { dwWait = WaitForSingleObject(lpMPSWabFileInfo->hDataAccessMutex,MAX_LOCK_FILE_TIMEOUT);
if ((dwWait == WAIT_TIMEOUT) || (dwWait == WAIT_FAILED)) { DebugTrace(TEXT("Thread:%x\tWaitFOrSingleObject failed.\n"),GetCurrentThreadId()); bRet = FALSE; }
}
return(bRet);
}
//$$//////////////////////////////////////////////////////////////////////////////////
//
// ReloadMPSWabFileInfo - Reloads the MPSWabFileHeader and reloads the
// memory indexes. This is a performance hit but cant be helped since it
// is the most reliable way to ensure we are working with the latest
// valid information
//
// Thus a write by one program cannot mess up the read by another program
//
////////////////////////////////////////////////////////////////////////////////////
BOOL ReloadMPSWabFileInfoTmp(HANDLE hPropertyStore) { HANDLE hMPSWabFile = NULL; LPMPSWab_FILE_INFO lpMPSWabFileInfo = hPropertyStore;
BOOL bRet = FALSE; DWORD dwNumofBytes = 0; HRESULT hr = E_FAIL;
hr = OpenWABFile(lpMPSWabFileInfo->lpszMPSWabFileName, NULL, &hMPSWabFile);
if ( (hMPSWabFile == INVALID_HANDLE_VALUE) || HR_FAILED(hr)) { goto out; }
if(0xFFFFFFFF == SetFilePointer ( hMPSWabFile, 0, NULL, FILE_BEGIN)) { DebugTrace(TEXT("SetFilePointer Failed\n")); goto out; }
bRet = ReloadMPSWabFileInfo(lpMPSWabFileInfo,hMPSWabFile);
out:
if (hMPSWabFile) IF_WIN32(CloseHandle(hMPSWabFile);) IF_WIN16(CloseFile(hMPSWabFile);)
return bRet;
}
//$$//////////////////////////////////////////////////////////////////////////////////
//
// LockPropertyStore - Locks the property store and reloads the indexes so we have
// the most current ones ...
//
// IN hPropertyStore - handle to property store
//
// Returns
// Success: S_OK
// Failure: E_FAIL
//
////////////////////////////////////////////////////////////////////////////////////
HRESULT LockPropertyStore(IN HANDLE hPropertyStore) { HRESULT hr = E_FAIL; LPMPSWab_FILE_INFO lpMPSWabFileInfo = (LPMPSWab_FILE_INFO) hPropertyStore;
if (!LockFileAccessTmp(lpMPSWabFileInfo)) { goto out; }
// reload the indexes
if(!ReloadMPSWabFileInfoTmp(hPropertyStore)) { goto out; }
hr = hrSuccess;
out: return hr; }
//$$//////////////////////////////////////////////////////////////////////////////////
//
// UnLockPropertyStore -
//
// IN hPropertyStore - handle to property store
//
// Returns
// Success: S_OK
// Failure: E_FAIL
//
////////////////////////////////////////////////////////////////////////////////////
HRESULT UnlockPropertyStore(IN HANDLE hPropertyStore) { HRESULT hr = E_FAIL;
LPMPSWab_FILE_INFO lpMPSWabFileInfo = (LPMPSWab_FILE_INFO) hPropertyStore;
if (!UnLockFileAccessTmp(lpMPSWabFileInfo)) { goto out; }
hr = hrSuccess;
out: return hr; }
//$$//////////////////////////////////////////////////////////////////////////////////
//
// ReadPropArray - Given a specified array of proptags and a search key,
// finds all records with that search key, and reads the records for
// all the props specified in the proptagarray.
//
// IN hPropertyStore - handle to property store
// IN pmbinFold - <Outlook> EntryID of folder to search in (NULL for default)
// IN SPropRes - property restriction set specifying what we're searching for
// IN ulFlags - search flags - only acceptable one is AB_MATCH_PROP_ONLY
// IN ulcPropTagCount - number of props per record requested
// IN lpPropTagArray - array of ulPropTags to return
// OUT lpContentList - List of AdrEntry structures corresponding to each matched record.
// SPropValue of each structure contains the requested props.
//
// Returns
// Success: S_OK
// Failure: E_FAIL
//
////////////////////////////////////////////////////////////////////////////////////
HRESULT ReadPropArray( IN HANDLE hPropertyStore, IN LPSBinary pmbinFold, IN SPropertyRestriction * lpPropRes, IN ULONG ulSearchFlags, IN ULONG ulcPropTagCount, IN LPULONG lpPTArray, OUT LPCONTENTLIST * lppContentList) { LPULONG lpPropTagArray = NULL; HRESULT hr = E_FAIL; SCODE sc = SUCCESS_SUCCESS; ULONG ulcEIDCount = 0; LPSBinary rgsbEntryIDs = NULL; HANDLE hMPSWabFile = NULL; DWORD dwNumofBytes = 0; LPBYTE szBuf = NULL; LPBYTE lp = NULL; LPCONTENTLIST lpContentList = NULL; ULONG i=0,j=0,k=0; ULONG nIndexPos=0,ulRecordOffset = 0; BOOL bFileLocked = FALSE; LPSPropValue lpPropArray = NULL; ULONG ulcFoundPropCount = 0; //Counts the number of finds so it can exit early
BOOL * lpbFoundProp = NULL; ULONG ulFileSize = 0; int nCount=0; BOOL bErrorDetected = FALSE;
MPSWab_RECORD_HEADER MPSWabRecordHeader = {0}; LPMPSWab_FILE_INFO lpMPSWabFileInfo;
//DebugTrace(("-----------\nReadPropArray: Entry\n"));
LPPTGDATA lpPTGData=GetThreadStoragePointer();
// Check arguments
if(ulcPropTagCount < 1) return(MAPI_E_INVALID_PARAMETER);
if(pt_bIsWABOpenExSession) { // This is a WABOpenEx session using outlooks storage provider
ULONG ulFlags = ulSearchFlags;
if(!hPropertyStore) return MAPI_E_NOT_INITIALIZED;
if(ulFlags & AB_UNICODE && !pt_bIsUnicodeOutlook) ulFlags &= ~AB_UNICODE;
{ LPWABSTORAGEPROVIDER lpWSP = (LPWABSTORAGEPROVIDER) hPropertyStore; LPSPropertyRestriction lpPropResA = NULL;
if( !pt_bIsUnicodeOutlook) { // Need to thunk the restriction down to ANSI
HrDupePropResWCtoA(ulFlags, lpPropRes, &lpPropResA);
// Since the native Outlook properties are all non-UNICODE, if someone is requesting
// Unicode data, we need to convert requsted Unicode props in the PropTagArray into ANSI props
//
if(ulSearchFlags & AB_UNICODE) { if(!(lpPropTagArray = LocalAlloc(LMEM_ZEROINIT, sizeof(ULONG)*ulcPropTagCount))) return MAPI_E_NOT_ENOUGH_MEMORY; for(i=0;i<ulcPropTagCount;i++) { if(PROP_TYPE(lpPTArray[i]) == PT_UNICODE) lpPropTagArray[i] = CHANGE_PROP_TYPE(lpPTArray[i], PT_STRING8); else if(PROP_TYPE(lpPTArray[i]) == PT_MV_UNICODE) lpPropTagArray[i] = CHANGE_PROP_TYPE(lpPTArray[i], PT_MV_STRING8); else lpPropTagArray[i] = lpPTArray[i]; } } else { lpPropTagArray = lpPTArray; }
}
hr = lpWSP->lpVtbl->ReadPropArray(lpWSP, (pmbinFold && pmbinFold->cb && pmbinFold->lpb) ? pmbinFold : NULL, lpPropResA ? lpPropResA : lpPropRes, ulFlags, ulcPropTagCount, lpPTArray, lppContentList);
DebugTrace(TEXT("WABStorageProvider::ReadPropArray returned:%x\n"),hr);
if(lpPropResA) { FreeBufferAndNull(&lpPropResA->lpProp); FreeBufferAndNull(&lpPropResA); }
if(ulSearchFlags & AB_UNICODE && !pt_bIsUnicodeOutlook) { // Sender specifically requested Unicode data which Outlook doesn't return
// so need to modify the returned data list ..
if(!HR_FAILED(hr) && *lppContentList) { LPCONTENTLIST lpAdrList = *lppContentList; for(i=0;lpAdrList->cEntries;i++) { // Now we thunk the data back to ANSI for Outlook
// ignore errors for now
if(lpAdrList->aEntries[i].rgPropVals) ScConvertWPropsToA((LPALLOCATEMORE) (&MAPIAllocateMore), lpAdrList->aEntries[i].rgPropVals, lpAdrList->aEntries[i].cValues, 0); } } }
if(lpPropTagArray != lpPTArray) LocalFreeAndNull(&lpPropTagArray);
return hr; } }
lpMPSWabFileInfo = hPropertyStore;
if ((ulSearchFlags & ~(AB_MATCH_PROP_ONLY|AB_UNICODE) ) || (!(lpPTArray)) || (!(lpPropRes)) || ( ulcPropTagCount == 0 ) || ( hPropertyStore == NULL)) { hr = MAPI_E_INVALID_PARAMETER; goto out; }
// Since the native properties are all UNICODE, if someone is NOT requesting
// Unicode data, we need to convert ANSI props in the PropTagArray into UNICODE props
//
if(!(ulSearchFlags & AB_UNICODE)) { if(!(lpPropTagArray = LocalAlloc(LMEM_ZEROINIT, sizeof(ULONG)*ulcPropTagCount))) { hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; } for(i=0;i<ulcPropTagCount;i++) { if(PROP_TYPE(lpPTArray[i]) == PT_STRING8) lpPropTagArray[i] = CHANGE_PROP_TYPE(lpPTArray[i], PT_UNICODE); else if(PROP_TYPE(lpPTArray[i]) == PT_MV_STRING8) lpPropTagArray[i] = CHANGE_PROP_TYPE(lpPTArray[i], PT_MV_UNICODE); else lpPropTagArray[i] = lpPTArray[i]; } } else { lpPropTagArray = lpPTArray; }
if(!LockFileAccess(lpMPSWabFileInfo)) { DebugTrace(TEXT("LockFileAccess Failed\n")); hr = MAPI_E_NO_ACCESS; goto out; } else { bFileLocked = TRUE; }
hr = FindRecords( IN hPropertyStore, pmbinFold, IN ulSearchFlags, FALSE, lpPropRes, &ulcEIDCount, &rgsbEntryIDs);
if (FAILED(hr)) goto out;
if (ulcEIDCount == 0) { DebugTrace(TEXT("No Records Found\n")); hr = MAPI_E_NOT_FOUND; goto out; }
//reset hr
hr = E_FAIL;
//Open the file
hr = OpenWABFile(lpMPSWabFileInfo->lpszMPSWabFileName, NULL, &hMPSWabFile);
if ( (hMPSWabFile == INVALID_HANDLE_VALUE) || HR_FAILED(hr)) { DebugTrace(TEXT("Could not open file.\nExiting ...\n")); goto out; }
ulFileSize = GetFileSize(hMPSWabFile, NULL);
//
// To ensure that file info is accurate,
// Any time we open a file, read the file info again ...
//
if(!ReloadMPSWabFileInfo( lpMPSWabFileInfo, hMPSWabFile)) { DebugTrace(TEXT("Reading file info failed.\n")); goto out; }
//
// Anytime we detect an error - try to fix it ...
//
if((lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags & WAB_ERROR_DETECTED) || (lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags & WAB_WRITE_IN_PROGRESS)) { if(HR_FAILED(HrDoQuickWABIntegrityCheck(lpMPSWabFileInfo,hMPSWabFile))) { hr = HrDoDetailedWABIntegrityCheck(lpMPSWabFileInfo,hMPSWabFile); if(HR_FAILED(hr)) { DebugTrace(TEXT("HrDoDetailedWABIntegrityCheck failed:%x\n"),hr); goto out; } } }
*lppContentList = NULL;
// we know we matched ulcEIDCount records so
// pre-create an array of that many records
*lppContentList = LocalAlloc(LMEM_ZEROINIT, sizeof(CONTENTLIST) + ulcEIDCount * sizeof(ADRENTRY)); if(!(*lppContentList)) { DebugTrace(TEXT("LocalAlloc failed to allocate memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; }
lpContentList = (*lppContentList); lpContentList->cEntries = ulcEIDCount; nCount = 0;
for (i = 0; i < ulcEIDCount; i++) { DWORD dwEID = 0; LPADRENTRY lpAdrEntry = &(lpContentList->aEntries[nCount]);
CopyMemory(&dwEID, rgsbEntryIDs[i].lpb, min(rgsbEntryIDs[i].cb, sizeof(dwEID)));
//Get offset for this entryid
if (!BinSearchEID( IN lpMPSWabFileInfo->lpMPSWabIndexEID, IN dwEID, IN lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries, OUT &nIndexPos)) { DebugTrace(TEXT("Specified EntryID doesnt exist!\n")); // skip this entry ... we'd rather ignore than fail ...
continue; //goto out;
}
ulRecordOffset = lpMPSWabFileInfo->lpMPSWabIndexEID[nIndexPos].ulOffset;
if(!ReadDataFromWABFile(hMPSWabFile, ulRecordOffset, (LPVOID) &MPSWabRecordHeader, (DWORD) sizeof(MPSWab_RECORD_HEADER))) goto out;
if(!bIsValidRecord( MPSWabRecordHeader, lpMPSWabFileInfo->lpMPSWabFileHeader->dwNextEntryID, ulRecordOffset, ulFileSize)) { //this should never happen but who knows
DebugTrace(TEXT("Error: Obtained an invalid record ...\n")); bErrorDetected = TRUE; // skip rather than fail
continue; }
if(MPSWabRecordHeader.ulObjType == RECORD_CONTAINER) continue; //skip the container records - dont want them in our contents tables
//Allocate each AdrEntry Structure
lpAdrEntry->cValues = ulcPropTagCount;
lpAdrEntry->rgPropVals = LocalAlloc(LMEM_ZEROINIT, ulcPropTagCount * sizeof(SPropValue)); if(!(lpAdrEntry->rgPropVals)) { DebugTrace(TEXT("LocalAlloc failed to allocate memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; }
// Initialize this rgPropVals empty array.
// We set all the proptypes to PT_ERROR so that if any property
// could not be found in the record, its corresponding property is already
// initialized to an Error
for(j=0;j<ulcPropTagCount;j++) { lpAdrEntry->rgPropVals[j].ulPropTag = PROP_TAG(PT_ERROR,0x0000); }
//ReadData
LocalFreeAndNull(&szBuf); szBuf = LocalAlloc(LMEM_ZEROINIT, MPSWabRecordHeader.ulRecordDataSize); if (!szBuf) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; }
// Set File Pointer to beginning of Data Section
if (0xFFFFFFFF == SetFilePointer ( hMPSWabFile, MPSWabRecordHeader.ulPropTagArraySize, NULL, FILE_CURRENT)) { DebugTrace(TEXT("SetFilePointer Failed\n")); goto out; }
//Read in the data
// Read record header
if(!ReadFile( hMPSWabFile, (LPVOID) szBuf, (DWORD) MPSWabRecordHeader.ulRecordDataSize, &dwNumofBytes, NULL)) { DebugTrace(TEXT("Reading Record Header failed.\n")); goto out; }
lp = szBuf;
// Go through all the properties in this record searching for the
// desired ones ...
// We also initialize a bool array that tracks if each individual
// property has been set ... this prevents us from overwriting a prop
// once it has been found
LocalFreeAndNull(&lpbFoundProp);
lpbFoundProp = LocalAlloc(LMEM_ZEROINIT, sizeof(BOOL) * ulcPropTagCount); if(!lpbFoundProp) { DebugTrace(TEXT("LocalAlloc failed to allocate memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; }
for(j=0;j<ulcPropTagCount;j++) lpbFoundProp[j]=FALSE;
ulcFoundPropCount = 0;
for (j = 0; j< MPSWabRecordHeader.ulcPropCount; j++) { LPSPropValue lpSPropVal=NULL; ULONG ulDataSize = 0; ULONG ulcValues = 0; ULONG ulTmpPropTag = 0; BOOL bPropMatch = FALSE; ULONG ulPropMatchIndex = 0;
// Did we find as many props as we were looking for?
// if yes, then dont look for any more
if (ulcFoundPropCount == ulcPropTagCount) break;
// Get the fresh property tag
CopyMemory(&ulTmpPropTag,lp,sizeof(ULONG)); lp+=sizeof(ULONG);
if ((ulTmpPropTag & MV_FLAG)) // MVProps have an additional cValues thrown in
{ CopyMemory(&ulcValues,lp,sizeof(ULONG)); lp += sizeof(ULONG); }
//Get the prop data size
CopyMemory(&ulDataSize,lp,sizeof(ULONG)); lp+=sizeof(ULONG);
// Check if we want this property
for(k=0;k<ulcPropTagCount;k++) { if (ulTmpPropTag == lpPropTagArray[k]) { bPropMatch = TRUE; ulPropMatchIndex = k; break; } }
//skip if no match
if ((!bPropMatch)) { lp += ulDataSize; //skip over data
continue; }
//if we already found this property and filled it, skip
if (lpbFoundProp[ulPropMatchIndex] == TRUE) { lp += ulDataSize; //skip over data
continue; }
//Set this prop in the array we will return
lpSPropVal = &(lpAdrEntry->rgPropVals[ulPropMatchIndex]);
lpSPropVal->ulPropTag = ulTmpPropTag;
//Single Valued
switch(PROP_TYPE(ulTmpPropTag)) { case(PT_I2): case(PT_LONG): case(PT_APPTIME): case(PT_SYSTIME): case(PT_R4): case(PT_BOOLEAN): case(PT_CURRENCY): case(PT_I8): CopyMemory(&(lpSPropVal->Value.i),lp,min(ulDataSize,sizeof(lpSPropVal->Value.i))); lp+=ulDataSize; break;
case(PT_CLSID): case(PT_TSTRING): lpSPropVal->Value.LPSZ = LocalAlloc(LMEM_ZEROINIT,ulDataSize); if (!(lpSPropVal->Value.LPSZ)) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; } CopyMemory(lpSPropVal->Value.LPSZ,lp,ulDataSize); lp+=ulDataSize; break;
case(PT_BINARY): lpSPropVal->Value.bin.lpb = LocalAlloc(LMEM_ZEROINIT,ulDataSize); if (!(lpSPropVal->Value.bin.lpb)) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; } CopyMemory(lpSPropVal->Value.bin.lpb,lp,ulDataSize); lpSPropVal->Value.bin.cb = ulDataSize; lp+=ulDataSize; break;
// Multi-valued
case PT_MV_TSTRING: lpSPropVal->Value.MVSZ.LPPSZ = LocalAlloc(LMEM_ZEROINIT, ulcValues * sizeof(LPTSTR)); if (!lpSPropVal->Value.MVSZ.LPPSZ) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; } lpSPropVal->Value.MVSZ.cValues = ulcValues; for (k=0;k<ulcValues;k++) { ULONG nLen; // get string length (includes terminating zero)
CopyMemory(&nLen, lp, sizeof(ULONG)); lp += sizeof(ULONG); lpSPropVal->Value.MVSZ.LPPSZ[k] = LocalAlloc(LMEM_ZEROINIT, nLen); if (!lpSPropVal->Value.MVSZ.LPPSZ[k]) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; } CopyMemory(lpSPropVal->Value.MVSZ.LPPSZ[k], lp, nLen); lp += nLen; } break;
case PT_MV_BINARY: lpSPropVal->Value.MVbin.lpbin = LocalAlloc(LMEM_ZEROINIT, ulcValues * sizeof(SBinary)); if (!lpSPropVal->Value.MVbin.lpbin) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; } lpSPropVal->Value.MVbin.cValues = ulcValues; for (k=0;k<ulcValues;k++) { ULONG nLen; CopyMemory(&nLen, lp, sizeof(ULONG)); lp += sizeof(ULONG); lpSPropVal->Value.MVbin.lpbin[k].cb = nLen; lpSPropVal->Value.MVbin.lpbin[k].lpb = LocalAlloc(LMEM_ZEROINIT, nLen); if (!lpSPropVal->Value.MVbin.lpbin[k].lpb) { DebugTrace(TEXT("Error allocating memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; } CopyMemory(lpSPropVal->Value.MVbin.lpbin[k].lpb, lp, nLen); lp += nLen; } break;
} //switch
ulcFoundPropCount++; lpbFoundProp[ulPropMatchIndex]=TRUE;
}// for j
if(!(ulSearchFlags & AB_UNICODE)) //default DATA is in UNICODE, switch it to ANSI
ConvertWCPropsToALocalAlloc(lpAdrEntry->rgPropVals, lpAdrEntry->cValues);
LocalFreeAndNull(&szBuf);
LocalFreeAndNull(&lpbFoundProp);
nCount++;
}//for i
lpContentList->cEntries = nCount;
hr = S_OK;
out:
if(lpPropTagArray && lpPropTagArray!=lpPTArray) LocalFree(lpPropTagArray);
LocalFreeAndNull(&szBuf);
LocalFreeAndNull(&lpbFoundProp);
FreeEntryIDs(hPropertyStore, ulcEIDCount, rgsbEntryIDs);
if(bErrorDetected) TagWABFileError(lpMPSWabFileInfo->lpMPSWabFileHeader, hMPSWabFile);
if(hMPSWabFile) IF_WIN32(CloseHandle(hMPSWabFile);) IF_WIN16(CloseFile(hMPSWabFile);)
if (HR_FAILED(hr)) { if (*lppContentList) { FreePcontentlist(hPropertyStore, *lppContentList); (*lppContentList) = NULL; } }
if (bFileLocked) UnLockFileAccess(lpMPSWabFileInfo);
//DebugTrace(("ReadPropArray: Exit\n-----------\n"));
return(hr); }
typedef struct _tagWabEIDList { WAB_ENTRYID dwEntryID; struct _tagWabEIDList * lpNext; } WAB_EID_LIST, * LPWAB_EID_LIST;
//$$private swap routine
void my_swap(LPWAB_ENTRYID lpdwEID, int left, int right) { WAB_ENTRYID temp; temp = lpdwEID[left]; lpdwEID[left] = lpdwEID[right]; lpdwEID[right] = temp; return; } //$$ private quick sort routine
// copied from Kernighan and Ritchie p.87
void my_qsort(LPWAB_ENTRYID lpdwEID, int left, int right) { int i, last;
if(left >= right) return;
my_swap(lpdwEID, left, (left+right)/2);
last = left; for(i=left+1;i<=right;i++) if(lpdwEID[i]<lpdwEID[left]) my_swap(lpdwEID, ++last, i);
my_swap(lpdwEID, left, last); my_qsort(lpdwEID, left, last-1); my_qsort(lpdwEID, last+1, right);
return; }
//$$//////////////////////////////////////////////////////////////////////////////////
//
// HrFindFuzzyRecordMatches - given a str to search for, goes throught the
// indexes and looks for partial matches. Returns a DWORD array of entry ids
// of all records that met the criteria ... if the flag AB_FAIL_AMBIGUOUS is
// supplied the function bails out if it finds more than 1 result (this
// is advantageous for ResolveNames since we have to call the function
// again and this way we avoid duplicate work
// If the search string contains spaces - we break it down into substrings
// and find only those targets that have all the sub strings. Reason for
// doing this is that if we have a Display Name of Thomas A. Edison, we should
// be able to search for Tom Edison and succeed. Caveat: we will also succeed
// for Ed Mas.<TBD> fix it
//
// One final addendum - if we get 1 exact match and multiple fuzzy matches and
// AB_FAIL_AMBIGUOUS is set then we give the 1 exact match precedence
// over the rest and declare it the unique result
//
// IN hPropertyStore - handle to property store
// IN pmbinFold - <Outlook> EntryID of folder to search in (NULL for default)
// IN lpszSearchStr - String to search for ...
// IN ulFlags - 0
// AB_FAIL_AMBIGUOUS // Means fail if no exact match
// And any combination of
// AB_FUZZY_FIND_NAME // search display name index
// AB_FUZZY_FIND_EMAIL // search email address index
// AB_FUZZY_FIND_ALIAS // search nickname index
// AB_FUZZY_FIND_ALL // search all three indexes
//
// OUT lpcValues - number of records matched
// OUT rgsbEntryIDs - array of SBinary EntryIDs of matching records
//
// TBD: This implementation Doesnt support Multi Valued propertys right now
//
//
//
// Returns
// Success: S_OK
// Failure: E_FAIL, MAPI_E_AMBIGUOUS_RECIP if AB_FUZZY_FAIL_AMBIGUOUS specified
//
////////////////////////////////////////////////////////////////////////////////////
HRESULT HrFindFuzzyRecordMatches( HANDLE hPropertyStore, LPSBinary pmbinFold, LPTSTR lpszSearchForThisString, ULONG ulFlags, ULONG * lpcValues, LPSBinary * lprgsbEntryIDs) { HRESULT hr= E_FAIL; HANDLE hMPSWabFile = NULL; BOOL bFileLocked = FALSE; ULONG j = 0; ULONG i = 0,k=0; ULONG cValues = 0; LPWAB_EID_LIST lpHead = NULL,lpCurrent = NULL; ULONG ulNumIndexesToSearch = 0; LPMPSWab_FILE_INFO lpMPSWabFileInfo; LPWAB_ENTRYID lpdwEntryIDs = NULL; LPTSTR * lppszSubStr = NULL; ULONG ulSubStrCount = 0; LPTSTR lpszSearchStr = NULL; ULONG ulUniqueMatchCount = 0; DWORD dwUniqueEID = 0; LPDWORD lpdwFolderEIDs = NULL; ULONG ulFolderEIDs = 0; BOOL bSearchVirtualRootFolder = FALSE; ULONG cchSize;
LPPTGDATA lpPTGData=GetThreadStoragePointer();
if(pt_bIsWABOpenExSession) { // This is a WABOpenEx session using outlooks storage provider
if(!hPropertyStore) return MAPI_E_NOT_INITIALIZED;
{ LPWABSTORAGEPROVIDER lpWSP = (LPWABSTORAGEPROVIDER) hPropertyStore; LPSTR lpSearchString = ConvertWtoA(lpszSearchForThisString); hr = lpWSP->lpVtbl->FindFuzzyRecordMatches( lpWSP, pmbinFold, lpSearchString, ulFlags, lpcValues, lprgsbEntryIDs); LocalFreeAndNull(&lpSearchString); DebugTrace(TEXT("WABStorageProvider::FindFuzzyRecordMatches returned:%x\n"),hr); return hr; } }
lpMPSWabFileInfo = hPropertyStore;
//DebugTrace(("//////////\nHrFindFuzzyRecordMatches: Entry\n"));
if ((!lpszSearchForThisString) || (!lprgsbEntryIDs) || ( hPropertyStore == NULL) ) { hr = MAPI_E_INVALID_PARAMETER; DebugTrace(TEXT("Invalid Parameters\n")); goto out; }
*lprgsbEntryIDs = NULL; *lpcValues = 0;
if(!LockFileAccess(lpMPSWabFileInfo)) { DebugTrace(TEXT("LockFileAccess Failed\n")); hr = MAPI_E_NO_ACCESS; goto out; } else { bFileLocked = TRUE; }
// Parse the search string for spaces and break it down into substrings
cchSize = lstrlen(lpszSearchForThisString)+1; lpszSearchStr = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize); if(!lpszSearchStr) { hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; } StrCpyN(lpszSearchStr, lpszSearchForThisString, cchSize);
TrimSpaces(lpszSearchStr); ulSubStrCount = 0;
{ // Count the spaces
LPTSTR lpTemp = lpszSearchStr; LPTSTR lpStart = lpszSearchStr;
ulSubStrCount = nCountSubStrings(lpszSearchStr);
lppszSubStr = LocalAlloc(LMEM_ZEROINIT, sizeof(LPTSTR) * ulSubStrCount); if(!lppszSubStr) { hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; }
// Fill in the substrings
i=0; lpTemp = lpszSearchStr; while(*lpTemp) { if (IsSpace(lpTemp) && ! IsSpace(CharNext(lpTemp))) { LPTSTR lpNextString = CharNext(lpTemp); *lpTemp = '\0'; lpTemp = lpNextString; cchSize = lstrlen(lpStart)+1; lppszSubStr[i] = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize); if(!lppszSubStr[i]) { hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; } StrCpyN(lppszSubStr[i], lpStart, cchSize); lpStart = lpTemp; i++; } else lpTemp = CharNext(lpTemp); }
if(i==ulSubStrCount-1) { //we're off by one
cchSize = lstrlen(lpStart)+1; lppszSubStr[i] = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize); if(!lppszSubStr[i]) { hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; } StrCpyN(lppszSubStr[i], lpStart, cchSize); }
for(i=0;i<ulSubStrCount;i++) TrimSpaces(lppszSubStr[i]); }
//Open the file
hr = OpenWABFile(lpMPSWabFileInfo->lpszMPSWabFileName, NULL, &hMPSWabFile);
if ( (hMPSWabFile == INVALID_HANDLE_VALUE) || HR_FAILED(hr)) { DebugTrace(TEXT("Could not open file.\nExiting ...\n")); goto out; }
//
// To ensure that file info is accurate,
// Any time we open a file, read the file info again ...
//
if(!ReloadMPSWabFileInfo( lpMPSWabFileInfo, hMPSWabFile)) { DebugTrace(TEXT("Reading file info failed.\n")); goto out; }
//
// Anytime we detect an error - try to fix it ...
//
if((lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags & WAB_ERROR_DETECTED) || (lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags & WAB_WRITE_IN_PROGRESS)) { if(HR_FAILED(HrDoQuickWABIntegrityCheck(lpMPSWabFileInfo,hMPSWabFile))) { hr = HrDoDetailedWABIntegrityCheck(lpMPSWabFileInfo,hMPSWabFile); if(HR_FAILED(hr)) { DebugTrace(TEXT("HrDoDetailedWABIntegrityCheck failed:%x\n"),hr); goto out; } } }
// If a WAB folder EID is specified, then we only want to search within the contents
// of that particular WAB folder .. that way we don't have to search through the whole WAB
// So we will open the WAB folder and get a list of it's member EIDs and check that a entryid
// is a member of that folder before we search through it
if(ulFlags & AB_FUZZY_FIND_PROFILEFOLDERONLY) { if(pmbinFold && pmbinFold->cb && pmbinFold->lpb) { // We need to look through the specified folder only
hr = GetFolderEIDs(hMPSWabFile, lpMPSWabFileInfo, pmbinFold, &ulFolderEIDs, &lpdwFolderEIDs); if(!HR_FAILED(hr) && !ulFolderEIDs && !lpdwFolderEIDs) goto out; //empty container - nothing to search
} else { // we need to look through the virtual folder
// It's harder to assemble a list of virtual folder contents
// without looking at each entry .. so instead we will just look
// at the entry prior to searching through it and if it's not in th
// virtual folder, we will ignore it ..
bSearchVirtualRootFolder = TRUE; } } // If we can always assume that the Display Name is made up of
// First and Last name .. then by searching only the display name
// we dont need to search the other indexes.
// later when we have email implemented as an index - we can think about searching
// the email also ...
if (ulFlags & AB_FUZZY_FIND_NAME) ulNumIndexesToSearch++; if (ulFlags & AB_FUZZY_FIND_EMAIL) ulNumIndexesToSearch++; if (ulFlags & AB_FUZZY_FIND_ALIAS) ulNumIndexesToSearch++;
for(k=0;k<ulNumIndexesToSearch;k++) { if(ulFlags & AB_FUZZY_FIND_NAME) { ulFlags &= ~AB_FUZZY_FIND_NAME; j = indexDisplayName; } else if(ulFlags & AB_FUZZY_FIND_EMAIL) { ulFlags &= ~AB_FUZZY_FIND_EMAIL; j = indexEmailAddress; } else if(ulFlags & AB_FUZZY_FIND_ALIAS) { ulFlags &= ~AB_FUZZY_FIND_ALIAS; j = indexAlias; }
//
// Get the index
//
if (!LoadIndex( IN lpMPSWabFileInfo, IN j, IN hMPSWabFile) ) { DebugTrace(TEXT("Error Loading Index!\n")); goto out; }
for(i=0;i<lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].ulcNumEntries;i++) { // if there is a match we will store it in a linked list for now
// since that is simpler to implement ...
// later on we can clean up the action .. TBD
LPTSTR lpszTarget = lpMPSWabFileInfo->lpMPSWabIndexStr[i].szIndex; ULONG n = 0;
// Before looking at any particular entry, check that it is part of the
// current folder
if(ulFolderEIDs && lpdwFolderEIDs) { BOOL bFound = FALSE; for(n=0;n<ulFolderEIDs;n++) { if(lpMPSWabFileInfo->lpMPSWabIndexStr[i].dwEntryID == lpdwFolderEIDs[n]) { bFound = TRUE; break; } } if(!bFound) continue; } else if(bSearchVirtualRootFolder) { // Discard this entry if it belongs to any folder .. we only want to
// consider entries that don't belong to any folder ..
ULONG ulObjType = 0; if(bIsFolderMember( hMPSWabFile, lpMPSWabFileInfo, lpMPSWabFileInfo->lpMPSWabIndexStr[i].dwEntryID, &ulObjType) || (ulObjType == RECORD_CONTAINER) ) continue; }
for(n=0;n<ulSubStrCount;n++) { if(j == indexEmailAddress && IsInternetAddress(lppszSubStr[n], NULL)) { // Bug 33422 - we are resolving correct email addresses to incorrect email addresses
// If the address looks like a valid internet address, we should do a starts with search
// This way [email protected] doesnt resolve to [email protected]
if(lstrlen(lppszSubStr[n]) > lstrlen(lpszTarget)) break;
// Bug 7881: need to do a caseinsensitive search here ..
{ LPTSTR lp = lppszSubStr[n], lpT = lpszTarget; while(lp && *lp && lpT && *lpT && ( ( (TCHAR)CharLower( (LPTSTR)(DWORD_PTR)MAKELONG(*lp, 0)) == *lpT) || ( (TCHAR)CharUpper( (LPTSTR)(DWORD_PTR)MAKELONG(*lp, 0)) == *lpT) ) ) { lp++; lpT++; } if(*lp) // which means didnt reach the end of the string
break; } } else if (!SubstringSearch(lpszTarget, lppszSubStr[n])) break; }
{ BOOL bExactMatch = FALSE;
// look for exact matches too
if(lstrlen(lpszSearchForThisString) > MAX_INDEX_STRING-1) { // this is a really long string so we can't really compare it correctly
// so for starters we will compare the first 32 chars
TCHAR sz[MAX_INDEX_STRING]; CopyMemory(sz, lpszSearchForThisString, min(sizeof(TCHAR)*lstrlen(lpszTarget),sizeof(sz))); sz[min(lstrlen(lpszTarget),ARRAYSIZE(sz)-1)] = '\0'; // depending on the language target string may or maynot be 32 chars - might be less
if(!lstrcmpi(sz, lpszTarget)) { // Match .. now to check the whole string ...
ULONG ulcProps = 0; LPSPropValue lpProps = NULL; if(!HR_FAILED(ReadRecordWithoutLocking(hMPSWabFile, lpMPSWabFileInfo, lpMPSWabFileInfo->lpMPSWabIndexStr[i].dwEntryID, &ulcProps, &lpProps))) { ULONG k = 0; ULONG ulProp = (j==indexDisplayName) ? PR_DISPLAY_NAME : ((j==indexEmailAddress) ? PR_EMAIL_ADDRESS : PR_NICKNAME); for(k=0;k<ulcProps;k++) { if(lpProps[k].ulPropTag == ulProp) { if(!lstrcmpi(lpszSearchForThisString, lpProps[k].Value.LPSZ)) { bExactMatch = TRUE; break; } } } LocalFreePropArray(hMPSWabFile, ulcProps, &lpProps); } } } else if(!lstrcmpi(lpszSearchForThisString, lpszTarget)) bExactMatch = TRUE;
if(bExactMatch) { //exact match
ulUniqueMatchCount++; dwUniqueEID = lpMPSWabFileInfo->lpMPSWabIndexStr[i].dwEntryID; if( ulFlags == AB_FUZZY_FAIL_AMBIGUOUS && ulUniqueMatchCount > 1 ) { // more than two - genuine fail
hr = MAPI_E_AMBIGUOUS_RECIP; DebugTrace(TEXT("Found multiple exact matches: Ambiguous search\n")); goto out; } //if
} else // not an exact match - revert back to regular error check
if(n != ulSubStrCount) // something didnt match
continue; }
// if (SubstringSearch(lpszTarget, lpszSearchStr))
{ // Yes a partial match ...
LPWAB_EID_LIST lpTemp = NULL; BOOL bDupe = FALSE;
// before adding this to the list, make sure it is not a FOLDER .. if it is a folder,
// we need to ignore it ..
{ ULONG ulObjType = 0; bIsFolderMember( hMPSWabFile, lpMPSWabFileInfo, lpMPSWabFileInfo->lpMPSWabIndexStr[i].dwEntryID, &ulObjType); if(ulObjType == RECORD_CONTAINER) continue; } // before adding this entryid to the list, make sure that it isnt already in the list
if(lpHead) { lpTemp = lpHead; while(lpTemp) { if(lpTemp->dwEntryID == lpMPSWabFileInfo->lpMPSWabIndexStr[i].dwEntryID) { bDupe = TRUE; break; } lpTemp = lpTemp->lpNext; } }
if(bDupe) continue;
lpTemp = LocalAlloc(LMEM_ZEROINIT,sizeof(WAB_EID_LIST));
if(!lpTemp) { DebugTrace(TEXT("Local Alloc Failed\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; }
lpTemp->lpNext = NULL; lpTemp->dwEntryID = lpMPSWabFileInfo->lpMPSWabIndexStr[i].dwEntryID;
if (lpCurrent) { lpCurrent->lpNext = lpTemp; lpCurrent = lpTemp; } else lpCurrent = lpTemp;
if(!lpHead) lpHead = lpCurrent;
cValues++;
// if we have to give exact match precedence over fuzzy match then
// this means that we have to search everything and can't bail just yet
//
/*
if( (ulFlags == AB_FUZZY_FAIL_AMBIGUOUS) && (cValues > 1) ) { // There is always the possibility that the same element
// has been found twice, once under display name and once
// under e-mail (e.g. Joe Smith, [email protected], searching for Joe)
// So if we have two elements and the entryids are the same,
// this is no cause for failure
if(cValues==2) { if(lpHead && lpCurrent) { if(lpHead->dwEntryID == lpCurrent->dwEntryID) continue; } }
// more than two - genuine fail
hr = MAPI_E_AMBIGUOUS_RECIP; DebugTrace(TEXT("Found multiple matches: Ambiguous search\n")); goto out;
} //if
*/ }//if Substring search
}//for(i= ..
}//for k=..
lpCurrent = lpHead;
if (lpCurrent == NULL) { // nothing found
hr = hrSuccess; *lpcValues = 0; DebugTrace(( TEXT("No matches found\n"))); goto out; }
//
// if we want this search to fail when it's ambiguous, this means
// we give preference to exact matches. Hence if we have a single exact match,
// then we should return only that single exact match..
if( ulFlags==AB_FUZZY_FAIL_AMBIGUOUS && ulUniqueMatchCount==1 ) { *lpcValues = 1; *lprgsbEntryIDs = LocalAlloc(LMEM_ZEROINIT, sizeof(SBinary)); if(!(*lprgsbEntryIDs)) { hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; } (*lprgsbEntryIDs)[0].lpb = LocalAlloc(LMEM_ZEROINIT, SIZEOF_WAB_ENTRYID); if((*lprgsbEntryIDs)[0].lpb) { (*lprgsbEntryIDs)[0].cb = SIZEOF_WAB_ENTRYID; CopyMemory((*lprgsbEntryIDs)[0].lpb,&dwUniqueEID, SIZEOF_WAB_ENTRYID); } } else {
// At the end of the above loops, we should have a linked list of
// entry ids - if we are searching through more than one index, then
// chances are that we have duplicates in this above list or entryids.
// We need to weed out the duplicates before we return this array
// First we turn the linked list into an array, freeing the linked list in the
// process. Then we quick sort the array of entryids
// Then we remove the duplicates and return another cleaned up array
lpdwEntryIDs = LocalAlloc(LMEM_ZEROINIT,cValues * SIZEOF_WAB_ENTRYID); if(!lpdwEntryIDs) { DebugTrace(TEXT("LocalAlloc failed to allocate memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; }
for(j=0;j<cValues;j++) { if(lpCurrent) { lpdwEntryIDs[j]=lpCurrent->dwEntryID; lpHead = lpCurrent->lpNext; LocalFreeAndNull(&lpCurrent); lpCurrent = lpHead; } }
lpCurrent = NULL;
// Now quicksort this array
my_qsort(lpdwEntryIDs, 0, cValues-1);
// Now we have a quicksorted array - scan it and remove duplicates
*lpcValues = 1; for(i=0;i<cValues-1;i++) { if(lpdwEntryIDs[i] == lpdwEntryIDs[i+1]) lpdwEntryIDs[i] = 0; else (*lpcValues)++;
}
*lprgsbEntryIDs = LocalAlloc(LMEM_ZEROINIT,(*lpcValues) * sizeof(SBinary)); if(!(*lprgsbEntryIDs)) { DebugTrace(TEXT("LocalAlloc failed to allocate memory\n")); hr = MAPI_E_NOT_ENOUGH_MEMORY; goto out; }
*lpcValues = 0;
for(j=0;j<cValues;j++) { if(lpdwEntryIDs[j] > 0) { int index = *lpcValues; (*lprgsbEntryIDs)[index].lpb = LocalAlloc(LMEM_ZEROINIT, SIZEOF_WAB_ENTRYID); if((*lprgsbEntryIDs)[index].lpb) { (*lprgsbEntryIDs)[index].cb = SIZEOF_WAB_ENTRYID; CopyMemory((*lprgsbEntryIDs)[index].lpb,&(lpdwEntryIDs[j]), SIZEOF_WAB_ENTRYID); (*lpcValues)++; } } } }
hr = hrSuccess;
out:
if(lpdwFolderEIDs) LocalFree(lpdwFolderEIDs);
if(lpCurrent) { while(lpCurrent) { lpHead = lpCurrent->lpNext; LocalFreeAndNull(&lpCurrent); lpCurrent = lpHead; } }
if(lppszSubStr) { for(i=0;i<ulSubStrCount;i++) LocalFreeAndNull(&lppszSubStr[i]); LocalFree(lppszSubStr); }
LocalFreeAndNull(&lpszSearchStr);
LocalFreeAndNull(&lpdwEntryIDs);
if(hMPSWabFile) IF_WIN32(CloseHandle(hMPSWabFile);) IF_WIN16(CloseFile(hMPSWabFile);)
if (bFileLocked) UnLockFileAccess(lpMPSWabFileInfo);
DebugTrace(TEXT("HrFindFuzzyRecordMatches: Exit: %x cValues: %d\n"),hr,*lpcValues);
return hr; }
//$$////////////////////////////////////////////////////////////////////////
//
// bTagWriteTransaction -
//
// During a write transaction, we tag the header as write-in-progress so that
// if the transaction shuts down in the middle we dont get messed up the next
// time we open up and so we can attepmt a repair the next time we open up
//
////////////////////////////////////////////////////////////////////////////
BOOL bTagWriteTransaction(LPMPSWab_FILE_HEADER lpMPSWabFileHeader, HANDLE hMPSWabFile) { BOOL bRet = FALSE; DWORD dwNumofBytes = 0;
if(!lpMPSWabFileHeader || !hMPSWabFile) { DebugTrace(TEXT("Invalid Parameter\n")); goto out; }
lpMPSWabFileHeader->ulFlags |= WAB_WRITE_IN_PROGRESS;
if(!WriteDataToWABFile( hMPSWabFile, 0, (LPVOID) lpMPSWabFileHeader, sizeof(MPSWab_FILE_HEADER))) goto out;
bRet = TRUE;
out: return bRet; }
//$$////////////////////////////////////////////////////////////////////////
//
// bUntagWriteTransaction -
//
// During a write transaction, we tag the header as write-in-progress so that
// if the transaction shuts down in the middle we dont get messed up the next
// time we open up and so we can attepmt a repair the next time we open up
//
////////////////////////////////////////////////////////////////////////////
BOOL bUntagWriteTransaction(LPMPSWab_FILE_HEADER lpMPSWabFileHeader, HANDLE hMPSWabFile) { BOOL bRet = FALSE; DWORD dwNumofBytes = 0;
if(!lpMPSWabFileHeader || !hMPSWabFile) { DebugTrace(TEXT("Invalid Parameter\n")); goto out; }
lpMPSWabFileHeader->ulFlags &= ~WAB_WRITE_IN_PROGRESS;
// update the file header
if(!WriteDataToWABFile( hMPSWabFile, 0, (LPVOID) lpMPSWabFileHeader, sizeof(MPSWab_FILE_HEADER))) goto out;
bRet = TRUE;
out: return bRet; }
/*
- GetNamedPropsFromBuffer - * bDoAtoWConversion - when importing from an old-non-unicode WAB file, we need to * update the 'name' strings from ASCII to Unicode .. this flag tells us to do so * */ BOOL GetNamedPropsFromBuffer(LPBYTE szBuf, ULONG ulcGUIDCount, BOOL bDoAtoWConversion, OUT LPGUID_NAMED_PROPS * lppgnp) { LPBYTE lp = szBuf; LPGUID_NAMED_PROPS lpgnp = NULL; ULONG i = 0,j=0;
lpgnp = LocalAlloc(LMEM_ZEROINIT, ulcGUIDCount * sizeof(GUID_NAMED_PROPS)); if(!lpgnp) { DebugTrace(TEXT("LocalAlloc failed\n")); goto out; }
for(i=0;i<ulcGUIDCount;i++) { lpgnp[i].lpGUID = LocalAlloc(LMEM_ZEROINIT, sizeof(GUID)); if(!lpgnp[i].lpGUID) { DebugTrace(TEXT("LocalAlloc failed\n")); goto out; }
CopyMemory(lpgnp[i].lpGUID, lp, sizeof(GUID)); lp += sizeof(GUID); // for GUID
CopyMemory(&(lpgnp[i].cValues), lp, sizeof(ULONG)); lp += sizeof(ULONG); // for cValues
lpgnp[i].lpnm = LocalAlloc(LMEM_ZEROINIT, (lpgnp[i].cValues)*sizeof(NAMED_PROP)); if(!lpgnp[i].lpnm) { DebugTrace(TEXT("LocalAlloc failed\n")); goto out; }
for(j=0;j<lpgnp[i].cValues;j++) { ULONG nLen; LPWSTR lpW = NULL;
CopyMemory(&(lpgnp[i].lpnm[j].ulPropTag), lp, sizeof(ULONG)); lp += sizeof(ULONG); //saves PropTag
// nLen includes trailing zero
CopyMemory(&nLen, lp, sizeof(ULONG)); lp += sizeof(ULONG); //saves lstrlen
if(!bDoAtoWConversion) { if(!(lpW = LocalAlloc(LMEM_ZEROINIT, nLen))) { DebugTrace(TEXT("LocalAlloc failed\n")); goto out; } CopyMemory(lpW, lp, nLen); } else { LPSTR lpA = NULL; if(!(lpA = LocalAlloc(LMEM_ZEROINIT, nLen))) { DebugTrace(TEXT("LocalAlloc failed\n")); goto out; } CopyMemory(lpA, lp, nLen); lpW = ConvertAtoW(lpA); LocalFreeAndNull(&lpA); } lpgnp[i].lpnm[j].lpsz = lpW;
// [PaulHi] HACK 3/25/99 The wabimprt.c code expects lpW to ALWAYS be at least
// two characters in length, and skips the first character. If this is
// less than or equal to one character then create a two character buffer filled
// with zeros.
if (nLen <= 2) // Length is in bytes
{ LocalFreeAndNull(&(lpgnp[i].lpnm[j].lpsz)); lpgnp[i].lpnm[j].lpsz = LocalAlloc(LMEM_ZEROINIT, (2 * sizeof(WCHAR))); if (!lpgnp[i].lpnm[j].lpsz) { DebugTrace(TEXT("LocalAlloc failed\n")); goto out; } }
lp += nLen; } }
*lppgnp = lpgnp;
return TRUE;
out: if(lpgnp) FreeGuidnamedprops(ulcGUIDCount, lpgnp);
return FALSE; }
//$$////////////////////////////////////////////////////////////////////////
////
//// GetNamedPropsFromPropStore -
////
//// Used for retreiving the named props to the property store
//// The supplied lppgn pointer is filled with GUID_NAMED_PROP array
////
//// IN hPropertyStore - handle to the property store
//// OUT lpulcGUIDCount - number of different GUIDs in the lpgnp array
//// OUT lppgnp - returned LPGUID_NAMED_PROP structure array
////
//// The lppgnp Structure is LocalAlloced. Caller should calle
//// FreeGuidnamedprop to free this structure
////
////////////////////////////////////////////////////////////////////////////
HRESULT GetNamedPropsFromPropStore( IN HANDLE hPropertyStore, OUT LPULONG lpulcGUIDCount, OUT LPGUID_NAMED_PROPS * lppgnp) { HRESULT hr= E_FAIL; HANDLE hMPSWabFile = NULL; BOOL bFileLocked = FALSE; ULONG j = 0; ULONG i = 0,k=0; LPMPSWab_FILE_INFO lpMPSWabFileInfo = (LPMPSWab_FILE_INFO) hPropertyStore; DWORD dwNumofBytes = 0; ULONG ulSize = 0; LPGUID_NAMED_PROPS lpgnp = NULL; ULONG ulcGUIDCount = 0; LPBYTE szBuf = NULL; LPBYTE lp = NULL;
if ((!lppgnp) || ( hPropertyStore == NULL) ) { hr = MAPI_E_INVALID_PARAMETER; DebugTrace(TEXT("Invalid Parameters\n")); goto out; }
*lppgnp = NULL; *lpulcGUIDCount = 0;
if(!LockFileAccess(lpMPSWabFileInfo)) { DebugTrace(TEXT("LockFileAccess Failed\n")); hr = MAPI_E_NO_ACCESS; goto out; } else { bFileLocked = TRUE; }
//Open the file
hr = OpenWABFile(lpMPSWabFileInfo->lpszMPSWabFileName, NULL, &hMPSWabFile);
if ( (hMPSWabFile == INVALID_HANDLE_VALUE) || HR_FAILED(hr)) { DebugTrace(TEXT("Could not open file.\nExiting ...\n")); goto out; }
//
// To ensure that file info is accurate,
// Any time we open a file, read the file info again ...
//
if(!ReloadMPSWabFileInfo( lpMPSWabFileInfo, hMPSWabFile)) { DebugTrace(TEXT("Reading file info failed.\n")); goto out; }
//
// First we need to figure out how much space we need to save the named
// properties structure
//
ulSize = lpMPSWabFileInfo->lpMPSWabFileHeader->NamedPropData.AllocatedBlockSize; ulcGUIDCount = lpMPSWabFileInfo->lpMPSWabFileHeader->NamedPropData.ulcNumEntries;
// Now the file is big enough, create the memory block for the named props
// and fill the block with the given Data
szBuf = LocalAlloc(LMEM_ZEROINIT, ulSize); if(!szBuf) { DebugTrace(TEXT("LocalAlloc failed\n")); goto out; }
if(!ReadDataFromWABFile(hMPSWabFile, lpMPSWabFileInfo->lpMPSWabFileHeader->NamedPropData.ulOffset, (LPVOID) szBuf, ulSize)) goto out;
if(!GetNamedPropsFromBuffer(szBuf, ulcGUIDCount, FALSE, lppgnp)) goto out;
*lpulcGUIDCount = ulcGUIDCount;
// done
hr = S_OK;
out:
if(HR_FAILED(hr)) { FreeGuidnamedprops(ulcGUIDCount, lpgnp); }
LocalFreeAndNull(&szBuf);
if(hMPSWabFile) IF_WIN32(CloseHandle(hMPSWabFile);) IF_WIN16(CloseFile(hMPSWabFile);)
if (bFileLocked) UnLockFileAccess(lpMPSWabFileInfo);
return hr; }
/*
- SetNamedPropsToBuffer - * */ BOOL SetNamedPropsToBuffer( ULONG ulcGUIDCount, LPGUID_NAMED_PROPS lpgnp, ULONG * lpulSize, LPBYTE * lpp) { ULONG ulSize = 0, i =0, j=0; LPBYTE szBuf = NULL, lp = NULL;
//
// First we need to figure out how much space we need to save the named
// properties structure
//
ulSize = 0; for(i=0;i<ulcGUIDCount;i++) { if(lpgnp[i].lpGUID) { ulSize += sizeof(GUID); // for GUID
ulSize += sizeof(ULONG); // for cValues
for(j=0;j<lpgnp[i].cValues;j++) { ulSize += sizeof(ULONG); //saves PropTag
if(lpgnp[i].lpnm[j].lpsz) { ulSize += sizeof(ULONG); //saves lstrlen
ulSize += sizeof(TCHAR)*(lstrlen(lpgnp[i].lpnm[j].lpsz)+1); } } } }
// Now the file is big enough, create the memory block for the named props
// and fill the block with the given Data
szBuf = LocalAlloc(LMEM_ZEROINIT, ulSize); if(!szBuf) { DebugTrace(TEXT("LocalAlloc failed\n")); goto out; }
lp = szBuf; for(i=0;i<ulcGUIDCount;i++) { if(lpgnp[i].lpGUID) { CopyMemory(lp, lpgnp[i].lpGUID, sizeof(GUID)); lp += sizeof(GUID); // for GUID
CopyMemory(lp, &(lpgnp[i].cValues), sizeof(ULONG)); lp += sizeof(ULONG); // for cValues
for(j=0;j<lpgnp[i].cValues;j++) { ULONG nLen; CopyMemory(lp, &(lpgnp[i].lpnm[j].ulPropTag), sizeof(ULONG)); lp += sizeof(ULONG); //saves PropTag
// This assumes that there is always a string to save
nLen = sizeof(TCHAR)*(lstrlen(lpgnp[i].lpnm[j].lpsz)+1); CopyMemory(lp, &nLen, sizeof(ULONG)); lp += sizeof(ULONG); //saves lstrlen
CopyMemory(lp, lpgnp[i].lpnm[j].lpsz, nLen); lp += nLen; } } }
*lpp = szBuf; *lpulSize = ulSize; return TRUE; out: if(szBuf) LocalFree(szBuf); return FALSE; }
//$$////////////////////////////////////////////////////////////////////////
////
//// SetNamedPropsToPropStore -
////
//// Used for writing the named props to the property store
//// The input lpgnp pointer contents will overwrite whatever exists in the
//// property store hence this should be used to replace not to add.
//// For each application GUID, there can be any number of properties
//// The number of application GUIDs is stored in the
//// FileHeader.NamedPropData.ulcNumEntries field. The actual data is of the
//// form:
//// GUID.#-of-Named-Prop-Tags.proptag.strlen.string.proptag.strlen.string etc.
////
//// This function will grow the property store as needed to fit the given
//// data.
////
//// IN hPropertyStore - handle to the property store
//// IN ulcGUIDCount - number of different GUIDs in the lpgnp array
//// IN lpgnp - LPGUID_NAMED_PROP structure array
////////////////////////////////////////////////////////////////////////////
HRESULT SetNamedPropsToPropStore( IN HANDLE hPropertyStore, IN ULONG ulcGUIDCount, OUT LPGUID_NAMED_PROPS lpgnp) { HRESULT hr= E_FAIL; HANDLE hMPSWabFile = NULL; BOOL bFileLocked = FALSE; ULONG j = 0; ULONG i = 0,k=0; LPMPSWab_FILE_INFO lpMPSWabFileInfo = (LPMPSWab_FILE_INFO) hPropertyStore; DWORD dwNumofBytes = 0; ULONG ulSize = 0; LPBYTE szBuf = NULL; LPBYTE lp = NULL;
DebugTrace(TEXT("\tSetNamedPropsToPropStore: Entry\n"));
if ((!lpgnp) || (lpgnp && !ulcGUIDCount) || ( hPropertyStore == NULL) ) { hr = MAPI_E_INVALID_PARAMETER; DebugTrace(TEXT("Invalid Parameters\n")); goto out; }
if(!LockFileAccess(lpMPSWabFileInfo)) { DebugTrace(TEXT("LockFileAccess Failed\n")); hr = MAPI_E_NO_ACCESS; goto out; } else { bFileLocked = TRUE; }
//Open the file
hr = OpenWABFile(lpMPSWabFileInfo->lpszMPSWabFileName, NULL, &hMPSWabFile);
if ( (hMPSWabFile == INVALID_HANDLE_VALUE) || HR_FAILED(hr)) { DebugTrace(TEXT("Could not open file.\nExiting ...\n")); goto out; }
//
// To ensure that file info is accurate,
// Any time we open a file, read the file info again ...
//
if(!ReloadMPSWabFileInfo( lpMPSWabFileInfo, hMPSWabFile)) { DebugTrace(TEXT("Reading file info failed.\n")); goto out; }
if(!SetNamedPropsToBuffer(ulcGUIDCount, lpgnp, &ulSize, &szBuf)) goto out;
// We now know we need ulSize bytes of space.
// Do we have this much space in the store ? if not, grow the store
while(lpMPSWabFileInfo->lpMPSWabFileHeader->NamedPropData.AllocatedBlockSize < ulSize) { if (!CompressFile( lpMPSWabFileInfo, hMPSWabFile, NULL, TRUE, AB_GROW_NAMEDPROP)) { DebugTrace(TEXT("Growing the file failed\n")); goto out; }
if(!ReloadMPSWabFileInfo( lpMPSWabFileInfo, hMPSWabFile)) { DebugTrace(TEXT("Reading file info failed.\n")); goto out; }
}
//
// Write this buffer into the file
//
if(!WriteDataToWABFile( hMPSWabFile, lpMPSWabFileInfo->lpMPSWabFileHeader->NamedPropData.ulOffset, (LPVOID) szBuf, ulSize)) goto out;
//
// Update the file header and write it
//
lpMPSWabFileInfo->lpMPSWabFileHeader->NamedPropData.UtilizedBlockSize = ulSize; lpMPSWabFileInfo->lpMPSWabFileHeader->NamedPropData.ulcNumEntries = ulcGUIDCount;
if(!WriteDataToWABFile( hMPSWabFile, 0, (LPVOID) lpMPSWabFileInfo->lpMPSWabFileHeader, sizeof(MPSWab_FILE_HEADER))) goto out;
// done
hr = S_OK;
out:
LocalFreeAndNull(&szBuf);
if(hMPSWabFile) IF_WIN32(CloseHandle(hMPSWabFile);) IF_WIN16(CloseFile(hMPSWabFile);)
if (bFileLocked) UnLockFileAccess(lpMPSWabFileInfo);
//DebugTrace(TEXT("//////////\nSetNamedPropsToPropStore: Exit\n"));
return hr; }
/*
- - GetOutlookRefreshCountData * * Outlook notifications are a bit funky in that Outlook sets an event and the first * WAB process to get that event resets it to the mutual exclusion of all other WAB * processes ... so we do an event count through the registry .. each process will make * a registry check of the latest event count and fire a refresh if their copy is older * than the count in the registry */ static const LPTSTR lpOlkContactRefresh = TEXT("OlkContactRefresh"); static const LPTSTR lpOlkFolderRefresh = TEXT("OlkFolderRefresh"); void GetOutlookRefreshCountData(LPDWORD lpdwOlkRefreshCount,LPDWORD lpdwOlkFolderRefreshCount) { HKEY hKey = NULL; DWORD dwDisposition = 0,dwSize = 0,dwType = 0; // begin registry stuff
if (ERROR_SUCCESS != RegCreateKeyEx(HKEY_CURRENT_USER, lpNewWABRegKey, 0, //reserved
NULL, REG_OPTION_NON_VOLATILE, KEY_READ, NULL, &hKey, &dwDisposition)) { goto exit; } dwSize = sizeof(DWORD); dwType = REG_DWORD; RegQueryValueEx(hKey,lpOlkContactRefresh,NULL,&dwType,(LPBYTE)lpdwOlkRefreshCount, &dwSize); dwSize = sizeof(DWORD); dwType = REG_DWORD; RegQueryValueEx(hKey,lpOlkFolderRefresh,NULL,&dwType,(LPBYTE)lpdwOlkFolderRefreshCount, &dwSize); exit: if(hKey) RegCloseKey(hKey); }
/*
- - SetOutlookRefreshCountData * */ void SetOutlookRefreshCountData(DWORD dwOlkRefreshCount,DWORD dwOlkFolderRefreshCount) { HKEY hKey = NULL; DWORD dwDisposition = 0,dwSize = 0; // begin registry stuff
if (ERROR_SUCCESS != RegCreateKeyEx(HKEY_CURRENT_USER, lpNewWABRegKey, 0, //reserved
NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwDisposition)) { goto exit; } dwSize = sizeof(DWORD); RegSetValueEx(hKey,lpOlkContactRefresh, 0, REG_DWORD, (LPBYTE)&dwOlkRefreshCount, dwSize); RegSetValueEx(hKey,lpOlkFolderRefresh, 0, REG_DWORD, (LPBYTE)&dwOlkFolderRefreshCount, dwSize); exit: if(hKey) RegCloseKey(hKey); }
/*
- - Copies a set of container info from Outlook to the WAB * * The difference is that Outlook always returns ANSI while WAB may * want Unicode in some cases * */ void ConvertOlkConttoWABCont(ULONG * lpcolk, OutlookContInfo ** lprgolk, ULONG * lpcolkci, OlkContInfo ** lprgolkci) { ULONG i = 0; SCODE sc = S_OK; ULONG cVal = *lpcolk; OlkContInfo * rgolkci = NULL; if(!(sc = MAPIAllocateBuffer(sizeof(OlkContInfo)*(cVal), &rgolkci))) { for(i = 0; i < *lpcolk ; i++) { if(!(sc = MAPIAllocateMore(sizeof(SBinary), rgolkci, (LPVOID*)(&rgolkci[i].lpEntryID)))) { rgolkci[i].lpEntryID->cb = ((*lprgolk)[i]).lpEntryID->cb; if(!(sc = MAPIAllocateMore(rgolkci[i].lpEntryID->cb, rgolkci, (LPVOID*)(&(rgolkci[i].lpEntryID->lpb))))) { CopyMemory(rgolkci[i].lpEntryID->lpb, ((*lprgolk)[i]).lpEntryID->lpb, rgolkci[i].lpEntryID->cb); } } sc = ScAnsiToWCMore((LPALLOCATEMORE) (&MAPIAllocateMore), rgolkci,((*lprgolk)[i]).lpszName, &rgolkci[i].lpszName); } } *lpcolkci = *lpcolk; *lprgolkci = rgolkci; }
/***************************************************************************
Name : CheckChangedWAB
Purpose : Has the file been written since we last checked?
Parameters: hPropertyStore = open property store handle lpftLast -> Last file time for this dialog
Returns : TRUE if property store has changed since last check
Comment : The first time this function is called is regarded as initialization and will always return FALSE.
***************************************************************************/ BOOL CheckChangedWAB(LPPROPERTY_STORE lpPropertyStore, HANDLE hMutex, LPDWORD lpdwContact, LPDWORD lpdwFolder, LPFILETIME lpftLast) { LPPTGDATA lpPTGData=GetThreadStoragePointer(); BOOL fChanged = FALSE; HANDLE hPropertyStore = lpPropertyStore->hPropertyStore;
if(!pt_bIsWABOpenExSession) { LPMPSWab_FILE_INFO lpMPSWabFileInfo = (LPMPSWab_FILE_INFO)hPropertyStore; HANDLE hFind = INVALID_HANDLE_VALUE; WIN32_FIND_DATA FindData;
if (lpMPSWabFileInfo) { if (INVALID_HANDLE_VALUE == (hFind = FindFirstFile( lpMPSWabFileInfo->lpszMPSWabFileName, // pointer to name of file to search for
&FindData))) { DebugTrace(TEXT("CheckWABRefresh:FindFirstFile -> %u\n"), GetLastError()); } else { if (lpftLast->dwHighDateTime < FindData.ftLastWriteTime.dwHighDateTime || (lpftLast->dwHighDateTime == FindData.ftLastWriteTime.dwHighDateTime && lpftLast->dwLowDateTime < FindData.ftLastWriteTime.dwLowDateTime)) { fChanged = TRUE; if (lpftLast->dwLowDateTime == 0 && lpftLast->dwHighDateTime == 0) { fChanged = FALSE; } *lpftLast = FindData.ftLastWriteTime; }
FindClose(hFind); } } } else { // WABOpenEx Session (ie Outlook session)
// Check our 2 events to see if anything needs updating
BOOL fContact = FALSE, fFolders = FALSE; DWORD dwContact = 0, dwFolder = 0;
if(WAIT_OBJECT_0 == WaitForSingleObject(hMutex,0)) {
if(WAIT_OBJECT_0 == WaitForSingleObject(ghEventOlkRefreshContacts, 0)) fContact = TRUE;
if(WAIT_OBJECT_0 == WaitForSingleObject(ghEventOlkRefreshFolders, 0)) fFolders = TRUE;
if(!fContact && !fFolders) { // Didn't catch an event .. check if we missed any in the past by looking at the registry settings
GetOutlookRefreshCountData(&dwContact,&dwFolder); if(*lpdwContact < dwContact) { fContact = TRUE; *lpdwContact = dwContact; } if(*lpdwFolder < dwFolder) { fFolders = TRUE; *lpdwFolder = dwFolder; } } else { //Caught an event .. update the registry
if(fContact) { DebugTrace(TEXT("####>> Got Outlook Contact Refresh Event\n")); ResetEvent(ghEventOlkRefreshContacts); } if(fFolders) { DebugTrace(TEXT("####>> Got Outlook Folder Refresh Event\n")); ResetEvent(ghEventOlkRefreshFolders); }
GetOutlookRefreshCountData(&dwContact,&dwFolder); *lpdwContact = dwContact + (fContact ? 1 : 0); *lpdwFolder = dwFolder + (fFolders ? 1 : 0); SetOutlookRefreshCountData(*lpdwContact, *lpdwFolder); }
if(fContact) { SYSTEMTIME st = {0}; GetSystemTime(&st); SystemTimeToFileTime(&st, lpftLast); } if(fFolders) { // Need to specifically update the folders list in the rgolkci ..
LPWABSTORAGEPROVIDER lpWSP = (LPWABSTORAGEPROVIDER) hPropertyStore; HRESULT hr = E_FAIL; ULONG colk = 0; OutlookContInfo * rgolk = NULL;
FreeBufferAndNull(&(lpPropertyStore->rgolkci)); hr = lpWSP->lpVtbl->GetContainerList(lpWSP, &colk, &rgolk); if(!HR_FAILED(hr)) { DebugTrace(TEXT("WABStorageProvider::GetContainerList returns:%x\n"),hr); ConvertOlkConttoWABCont(&colk, &rgolk, &lpPropertyStore->colkci, &lpPropertyStore->rgolkci); FreeBufferAndNull(&rgolk); } } fChanged = fContact | fFolders;
ReleaseMutex(hMutex); } } return(fChanged); }
/***************************************************************************
Name : FreeEntryIDs
Purpose : Frees any LPSBinary structures allocated and returned by funtions in thie file (e.g. WriteRecord, etc)
Parameters: lpsbEID - SBinary structure containing an entryid
Returns : void
***************************************************************************/ HRESULT FreeEntryIDs(IN HANDLE hPropertyStore, IN ULONG ulCount, IN LPSBinary rgsbEIDs) { ULONG i = 0;
LPPTGDATA lpPTGData=GetThreadStoragePointer();
if(pt_bIsWABOpenExSession) { // This is a WABOpenEx session using outlooks storage provider
if(!hPropertyStore) return MAPI_E_NOT_INITIALIZED;
{ LPWABSTORAGEPROVIDER lpWSP = (LPWABSTORAGEPROVIDER) hPropertyStore; HRESULT hr = E_FAIL;
hr = lpWSP->lpVtbl->FreeEntryIDs( lpWSP, ulCount, rgsbEIDs);
DebugTrace(TEXT("WABStorageProvider::FreeEntryIDs returned:%x\n"),hr);
return hr; } }
if(ulCount && rgsbEIDs) { for(i=0;i<ulCount;i++) LocalFree(rgsbEIDs[i].lpb); LocalFree(rgsbEIDs); }
return S_OK; }
const LPTSTR szOutlook = TEXT("Outlook Contact Store"); //$$////////////////////////////////////////////////////////////////////////
////
//// GetWABFileName()
////
//// If this is a WAB File then returns a pointer to the file name
//// If running against outlook, returns szEmpty
//// Caller should not free this
////////////////////////////////////////////////////////////////////////////
LPTSTR GetWABFileName(IN HANDLE hPropertyStore, BOOL bRetOutlookStr) { LPPTGDATA lpPTGData=GetThreadStoragePointer(); LPMPSWab_FILE_INFO lpMPSWabFileInfo = (LPMPSWab_FILE_INFO) hPropertyStore;
if(pt_bIsWABOpenExSession) { return (bRetOutlookStr ? szOutlook : szEmpty); }
return lpMPSWabFileInfo->lpszMPSWabFileName; }
//$$////////////////////////////////////////////////////////////////////////
////
//// GetWABFileEntryCount() - returns actual number of entries in a WAB
/// This number includes all contacts, groups, and foldesr
////
////////////////////////////////////////////////////////////////////////////
DWORD GetWABFileEntryCount(IN HANDLE hPropertyStore) { LPMPSWab_FILE_INFO lpMPSWabFileInfo = (LPMPSWab_FILE_INFO) hPropertyStore;
return lpMPSWabFileInfo->lpMPSWabFileHeader->ulcNumEntries; }
//$$////////////////////////////////////////////////////////////////////////////
//
// LocalFreePropArray - Frees an SPropValue structure allocated using LocalAlloc
// instead of MAPIAllocateBuffer.
//
// When called internally from property store functions, hPropertyStore can be
// NULL ...
// If this is a Outlook session and there is a hPropertyStore then we release through
// Outlook.
// If there is no hPropertyStore then this was locally allocated memory when we
// LocalFree ...
//
////////////////////////////////////////////////////////////////////////////////
void LocalFreePropArray(HANDLE hPropertyStore, ULONG ulcPropCount, LPPROPERTY_ARRAY * lppPropArray) { ULONG i=0,j=0,k=0; LPSPropValue lpPropArray = *lppPropArray;
LPPTGDATA lpPTGData=GetThreadStoragePointer();
if(!lpPropArray || !ulcPropCount) goto out;
if(pt_bIsWABOpenExSession && hPropertyStore) { // This is a WABOpenEx session using outlooks storage provider
{ LPWABSTORAGEPROVIDER lpWSP = (LPWABSTORAGEPROVIDER) hPropertyStore; HRESULT hr = E_FAIL;
hr = lpWSP->lpVtbl->FreePropArray( lpWSP, ulcPropCount, *lppPropArray);
DebugTrace(TEXT("WABStorageProvider::FreePropArray returned:%x\n"),hr);
*lppPropArray = NULL;
return; } }
for(i = 0; i<ulcPropCount;i++) { // we only care to free the sub-level pointers which we
// might have allocated
switch(PROP_TYPE(lpPropArray[i].ulPropTag)) { case PT_CLSID: LocalFreeAndNull((LPVOID *) (&(lpPropArray[i].Value.lpguid))); break;
case PT_STRING8: if (lpPropArray[i].Value.lpszA)// && lpPropArray[i].Value.lpszA != szEmpty)
LocalFreeAndNull((LPVOID *) (&(lpPropArray[i].Value.lpszA))); break;
case PT_UNICODE: if (lpPropArray[i].Value.lpszW && lpPropArray[i].Value.lpszW != szEmpty) LocalFreeAndNull((LPVOID *) (&(lpPropArray[i].Value.lpszW))); break;
case PT_BINARY: if (lpPropArray[i].Value.bin.cb) LocalFreeAndNull((LPVOID *) (&(lpPropArray[i].Value.bin.lpb))); break;
case PT_MV_STRING8: j = lpPropArray[i].Value.MVszA.cValues; for(k = 0; k < j; k++) { if (lpPropArray[i].Value.MVszA.lppszA[k])// && lpPropArray[i].Value.MVszA.lppszA[k] != szEmpty)
LocalFreeAndNull((LPVOID *) (&(lpPropArray[i].Value.MVszA.lppszA[k]))); } LocalFree(lpPropArray[i].Value.MVszA.lppszA); break;
case PT_MV_UNICODE: j = lpPropArray[i].Value.MVszW.cValues; for(k = 0; k < j; k++) { if (lpPropArray[i].Value.MVszW.lppszW[k] && lpPropArray[i].Value.MVszW.lppszW[k] != szEmpty) LocalFreeAndNull((LPVOID *) (&(lpPropArray[i].Value.MVszW.lppszW[k]))); } LocalFree(lpPropArray[i].Value.MVszW.lppszW); break;
case PT_MV_BINARY: j = lpPropArray[i].Value.MVbin.cValues; for(k = 0; k < j; k++) { LocalFreeAndNull((LPVOID *) (&(lpPropArray[i].Value.MVbin.lpbin[k].lpb))); } LocalFree(lpPropArray[i].Value.MVbin.lpbin); break;
case(PT_MV_I2): case(PT_MV_LONG): case(PT_MV_R4): case(PT_MV_DOUBLE): case(PT_MV_CURRENCY): case(PT_MV_APPTIME): case(PT_MV_SYSTIME): case(PT_MV_CLSID): case(PT_MV_I8): LocalFree(lpPropArray[i].Value.MVi.lpi); break;
default: break; } }
LocalFreeAndNull((LPVOID *) (lppPropArray)); // yes, no &
out: return; }
//$$///////////////////////////////////////////////////////////////////////////
//
//
// FreePcontentlist is used to free LPCONTENTLIST structures
// Even though the LPCONTENTLIST is exactly the same as LPADRLIST
// there is a difference in how the 2 are created with the former
// being created using LocalAlloc and the latter thru MAPIAllocateBuffer
//
//
/////////////////////////////////////////////////////////////////////////////
void FreePcontentlist(HANDLE hPropertyStore, IN OUT LPCONTENTLIST lpContentList) { ULONG i=0;
LPPTGDATA lpPTGData=GetThreadStoragePointer();
if(pt_bIsWABOpenExSession) { // This is a WABOpenEx session using outlooks storage provider
if(!hPropertyStore) return;// MAPI_E_NOT_INITIALIZED;
{ LPWABSTORAGEPROVIDER lpWSP = (LPWABSTORAGEPROVIDER) hPropertyStore; HRESULT hr = E_FAIL;
hr = lpWSP->lpVtbl->FreeContentList(lpWSP, lpContentList);
DebugTrace(TEXT("WABStorageProvider::FreeContentList returned:%x\n"),hr);
return; } }
if (!lpContentList) goto out;
for (i=0;i<lpContentList->cEntries;i++) { if (lpContentList->aEntries[i].rgPropVals) LocalFreePropArray(hPropertyStore, lpContentList->aEntries[i].cValues, (LPPROPERTY_ARRAY *) (&(lpContentList->aEntries[i].rgPropVals))); }
LocalFreeAndNull(&lpContentList);
out: return; }
/*
- - GetFolderEIDs - * Returns a list of EIDs that are a member of a given folder * */ HRESULT GetFolderEIDs(HANDLE hMPSWabFile, LPMPSWab_FILE_INFO lpMPSWabFileInfo, LPSBinary pmbinFold, ULONG * lpulFolderEIDs, LPDWORD * lppdwFolderEIDs) { HRESULT hr = S_OK; ULONG ulcPropCount = 0; LPSPropValue lpPropArray = NULL; DWORD dwEntryID = 0; ULONG i = 0,j=0; LPDWORD lpdwFolderEIDs = NULL; SBinary sbEID = {0};
if(pmbinFold && pmbinFold->cb != SIZEOF_WAB_ENTRYID) { // this may be a WAB container .. reset the entryid to a WAB entryid
if(WAB_CONTAINER == IsWABEntryID(pmbinFold->cb, (LPENTRYID)pmbinFold->lpb, NULL,NULL,NULL,NULL,NULL)) { IsWABEntryID(pmbinFold->cb, (LPENTRYID)pmbinFold->lpb, (LPVOID*)&sbEID.lpb,(LPVOID*)&sbEID.cb,NULL,NULL,NULL); if(sbEID.cb == SIZEOF_WAB_ENTRYID) pmbinFold = &sbEID; } } if(!pmbinFold || pmbinFold->cb != SIZEOF_WAB_ENTRYID) { return MAPI_E_INVALID_PARAMETER; }
CopyMemory(&dwEntryID, pmbinFold->lpb, min(pmbinFold->cb,sizeof(dwEntryID)));
if(HR_FAILED(hr = ReadRecordWithoutLocking( hMPSWabFile, lpMPSWabFileInfo, dwEntryID, &ulcPropCount, &lpPropArray))) return hr;
for(i=0;i<ulcPropCount;i++) { if(lpPropArray[i].ulPropTag == PR_WAB_FOLDER_ENTRIES) { *lpulFolderEIDs = lpPropArray[i].Value.MVbin.cValues; if(*lpulFolderEIDs) { lpdwFolderEIDs = LocalAlloc(LMEM_ZEROINIT, *lpulFolderEIDs * sizeof(DWORD)); if(lpdwFolderEIDs) { for(j=0;j<*lpulFolderEIDs;j++) { CopyMemory(&(lpdwFolderEIDs[j]), lpPropArray[i].Value.MVbin.lpbin[j].lpb, min(lpPropArray[i].Value.MVbin.lpbin[j].cb, sizeof(lpdwFolderEIDs[0]))); } } } break; } }
if(*lpulFolderEIDs && lpdwFolderEIDs) *lppdwFolderEIDs = lpdwFolderEIDs;
LocalFreePropArray(NULL, ulcPropCount, &lpPropArray);
return S_OK; }
/*
- - bIsFolderMember - * Returns TRUE if specified entry is a member of a folder * */ BOOL bIsFolderMember(HANDLE hMPSWabFile, LPMPSWab_FILE_INFO lpMPSWabFileInfo, DWORD dwEntryID, ULONG * lpulObjType) { BOOL bRet = FALSE; ULONG ulRecordOffset = 0; ULONG nIndexPos = 0; ULONG * lpulPropTags = NULL;
//
// First check if this is a valid entryID
//
if (!BinSearchEID( IN lpMPSWabFileInfo->lpMPSWabIndexEID, IN dwEntryID, IN lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries, OUT &nIndexPos)) { DebugTrace(TEXT("Specified EntryID doesnt exist!\n")); goto out; }
//if entryid exists, we can start reading the record
ulRecordOffset = lpMPSWabFileInfo->lpMPSWabIndexEID[nIndexPos].ulOffset;
{ MPSWab_RECORD_HEADER MPSWabRecordHeader = {0}; DWORD dwNumofBytes = 0; ULONG i = 0;
if(!ReadDataFromWABFile(hMPSWabFile, ulRecordOffset, (LPVOID) &MPSWabRecordHeader, (DWORD) sizeof(MPSWab_RECORD_HEADER))) goto out;
if(lpulObjType) *lpulObjType = MPSWabRecordHeader.ulObjType;
lpulPropTags = LocalAlloc(LMEM_ZEROINIT, MPSWabRecordHeader.ulcPropCount * sizeof(ULONG)); if(!lpulPropTags) { DebugTrace(TEXT("Error allocating memory\n")); goto out; }
//Read in the data
if(!ReadFile( hMPSWabFile, (LPVOID) lpulPropTags, (DWORD) MPSWabRecordHeader.ulPropTagArraySize, &dwNumofBytes, NULL)) { DebugTrace(TEXT("Reading Record Header failed.\n")); goto out; }
for(i=0;i<MPSWabRecordHeader.ulcPropCount;i++) { if(lpulPropTags[i] == PR_WAB_FOLDER_PARENT || lpulPropTags[i] == PR_WAB_FOLDER_PARENT_OLDPROP) { bRet = TRUE; break; } } }
out:
if(lpulPropTags) LocalFree(lpulPropTags); return bRet; }
/*
- - ConvertWCPropsToALocalAlloc() - * Takes a SPropValue array and converts Unicode strings to ANSI equivalents * Uses LocalAlloc for the new strings .. unlike the ScWCtoAnsiMore which uses the * internal memory allocators */ void ConvertWCPropsToALocalAlloc(LPSPropValue lpProps, ULONG ulcValues) { ULONG i = 0, j = 0, ulCount = 0; LPSTR * lppszA = NULL; LPSTR lpszA = NULL;
for(i=0;i<ulcValues;i++) { switch(PROP_TYPE(lpProps[i].ulPropTag)) { case PT_UNICODE: lpszA = ConvertWtoA(lpProps[i].Value.lpszW); LocalFreeAndNull((LPVOID *) (&lpProps[i].Value.lpszW)); lpProps[i].Value.lpszA = lpszA; lpProps[i].ulPropTag = CHANGE_PROP_TYPE( lpProps[i].ulPropTag, PT_STRING8); break; case PT_MV_UNICODE: ulCount = lpProps[i].Value.MVszW.cValues; if(lppszA = LocalAlloc(LMEM_ZEROINIT, sizeof(LPSTR)*ulCount)) { for(j=0;j<ulCount;j++) { lppszA[j] = ConvertWtoA(lpProps[i].Value.MVszW.lppszW[j]); LocalFreeAndNull((LPVOID*)&(lpProps[i].Value.MVszW.lppszW[j])); } LocalFreeAndNull((LPVOID*)(&lpProps[i].Value.MVszW.lppszW)); lpProps[i].Value.MVszW.cValues = 0; lpProps[i].Value.MVszA.cValues = ulCount; lpProps[i].Value.MVszA.lppszA = lppszA; lppszA = NULL; lpProps[i].ulPropTag = CHANGE_PROP_TYPE( lpProps[i].ulPropTag, PT_MV_STRING8); } break; } } }
/*
- - ConvertAPropsToWCLocalAlloc() - * Takes a SPropValue array and converts Unicode strings to ANSI equivalents * Uses LocalAlloc for the new strings .. unlike the ScWCtoAnsiMore which uses the * internal memory allocators */ void ConvertAPropsToWCLocalAlloc(LPSPropValue lpProps, ULONG ulcValues) { ULONG i = 0, j = 0, ulCount = 0; LPWSTR * lppszW = NULL; LPWSTR lpszW = NULL;
for(i=0;i<ulcValues;i++) { switch(PROP_TYPE(lpProps[i].ulPropTag)) { case PT_STRING8: lpszW = ConvertAtoW(lpProps[i].Value.lpszA); LocalFreeAndNull((LPVOID *) (&lpProps[i].Value.lpszA)); lpProps[i].Value.lpszW = lpszW; lpProps[i].ulPropTag = CHANGE_PROP_TYPE( lpProps[i].ulPropTag, PT_UNICODE); break; case PT_MV_STRING8: ulCount = lpProps[i].Value.MVszA.cValues; if(lppszW = LocalAlloc(LMEM_ZEROINIT, sizeof(LPWSTR)*ulCount)) { for(j=0;j<ulCount;j++) { lppszW[j] = ConvertAtoW(lpProps[i].Value.MVszA.lppszA[j]); LocalFreeAndNull((LPVOID *) (&lpProps[i].Value.MVszA.lppszA[j])); } LocalFreeAndNull((LPVOID *)&(lpProps[i].Value.MVszW.lppszW)); lpProps[i].Value.MVszA.cValues = 0; lpProps[i].Value.MVszW.cValues = ulCount; lpProps[i].Value.MVszW.lppszW = lppszW; lppszW = NULL; lpProps[i].ulPropTag = CHANGE_PROP_TYPE( lpProps[i].ulPropTag, PT_MV_UNICODE); } break; } } }
|