Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

7090 lines
238 KiB

  1. ////////////////////////////////////////////////////////////////////////////////
  2. ///
  3. ///
  4. /// MPSWAB.C
  5. ///
  6. /// Microsoft Property Store - WAB Dll
  7. ///
  8. /// Contains implementations of File managment functions
  9. ///
  10. /// Exposed Functions:
  11. /// OpenPropertyStore
  12. /// ClosePropertyStore
  13. /// BackupPropertyStore
  14. /// LockPropertyStore
  15. /// UnlockPropertyStore
  16. /// ReadRecord
  17. /// WriteRecord
  18. /// FindRecords
  19. /// DeleteRecords
  20. /// ReadIndex
  21. /// ReadPropArray
  22. /// HrFindFuzzyRecordMatches
  23. ///
  24. /// Private:
  25. /// UnlockFileAccess
  26. /// LockFileAccess
  27. /// ReloadMPSWabFileInfoTmp
  28. /// bTagWriteTransaction
  29. /// bUntagWriteTransaction
  30. ///
  31. /////////////////////////////////////////////////////////////////////////////////
  32. #include "_apipch.h"
  33. BOOL fTrace = TRUE;
  34. BOOL fDebugTrap = FALSE;
  35. TCHAR szDebugOutputFile[MAX_PATH] = TEXT("");
  36. BOOL bUntagWriteTransaction(LPMPSWab_FILE_HEADER lpMPSWabFileHeader,
  37. HANDLE hMPSWabFile);
  38. BOOL bTagWriteTransaction(LPMPSWab_FILE_HEADER lpMPSWabFileHeader,
  39. HANDLE hMPSWabFile);
  40. HRESULT GetFolderEIDs(HANDLE hMPSWabFile,
  41. LPMPSWab_FILE_INFO lpMPSWabFileInfo,
  42. LPSBinary pmbinFold,
  43. ULONG * lpulFolderEIDs,
  44. LPDWORD * lppdwFolderEIDs);
  45. BOOL bIsFolderMember(HANDLE hMPSWabFile,
  46. LPMPSWab_FILE_INFO lpMPSWabFileInfo,
  47. DWORD dwEntryID, ULONG * lpulObjType);
  48. extern int nCountSubStrings(LPTSTR lpszSearchStr);
  49. //$$//////////////////////////////////////////////////////////////
  50. //
  51. // OpenPropertyStore - searches for Property Store and or creates it
  52. // based on flags.
  53. //
  54. // IN - lpszFileName - file name specified by client
  55. // IN - ulFlags - AB_CREATE_NEW
  56. // AB_CREATE_ALWAYS
  57. // AB_OPEN_ALWAYS
  58. // AB_OPEN_EXISTING
  59. // AB_READ_ONLY
  60. // AB_SET_DEFAULT (?)
  61. // AB_DONT_RESTORE
  62. // IN - hWnd - In the event of data corruption, use this hWnd for a message box
  63. // if it exists, or show the message box on the desktop window
  64. // OUT- lphPropertyStore - Handle to opened property store
  65. //
  66. // This routine also scans the file and attempts to fix errors if it finds any.
  67. // including recovering from backup. When opening the file with OpenPropertyStore
  68. // specify AB_DONT_RESTORE to prevent the restoration operation
  69. // This should especially be done when opening files that are not the default
  70. // property store.
  71. //
  72. // Return Value:
  73. // HRESULT -
  74. // S_OK Success
  75. // E_FAIL Failure
  76. //
  77. ////////////////////////////////////////////////////////////////
  78. HRESULT OpenPropertyStore( IN LPTSTR lpszFileName,
  79. IN ULONG ulFlags,
  80. IN HWND hWnd,
  81. OUT LPHANDLE lphPropertyStore)
  82. {
  83. HRESULT hr = E_FAIL;
  84. HANDLE hMPSWabFile = NULL;
  85. ULONG i=0,j=0;
  86. DWORD dwNumofBytes = 0;
  87. WIN32_FIND_DATA FileData;
  88. DWORD dwIndexBlockSize = 0;
  89. LPTSTR lpszBuffer = NULL;
  90. BOOL bFileLocked = FALSE;
  91. ULONG cchSize;
  92. //
  93. // the following pointer will be returned back as the handle to the property store
  94. //
  95. LPMPSWab_FILE_INFO lpMPSWabFileInfo = NULL;
  96. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  97. if(!lphPropertyStore)
  98. {
  99. hr = MAPI_E_INVALID_PARAMETER;
  100. goto out;
  101. }
  102. // A file name overrides an outlook session
  103. if(pt_bIsWABOpenExSession && !(ulFlags & AB_IGNORE_OUTLOOK))
  104. {
  105. // This is a WABOpenEx session using outlooks storage provider
  106. if(!lpfnWABOpenStorageProvider)
  107. return MAPI_E_NOT_INITIALIZED;
  108. {
  109. LPWABSTORAGEPROVIDER lpWSP = NULL;
  110. hr = lpfnWABOpenStorageProvider(hWnd, pmsessOutlookWabSPI,
  111. lpfnAllocateBufferExternal ? lpfnAllocateBufferExternal : (LPALLOCATEBUFFER) (MAPIAllocateBuffer),
  112. lpfnAllocateMoreExternal ? lpfnAllocateMoreExternal : (LPALLOCATEMORE) (MAPIAllocateMore),
  113. lpfnFreeBufferExternal ? lpfnFreeBufferExternal : MAPIFreeBuffer,
  114. 0,
  115. &lpWSP);
  116. DebugTrace(TEXT("Outlook WABOpenStorageProvider returned:%x\n"),hr);
  117. if(HR_FAILED(hr))
  118. return hr;
  119. (*lphPropertyStore) = (HANDLE) lpWSP;
  120. return(hr);
  121. }
  122. }
  123. lpMPSWabFileInfo = LocalAlloc(LMEM_ZEROINIT,sizeof(MPSWab_FILE_INFO));
  124. if (!lpMPSWabFileInfo)
  125. {
  126. DebugTrace(TEXT("Error allocating memory\n"));
  127. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  128. goto out;
  129. }
  130. DebugTrace(( TEXT("-----------\nOpenPropertyStore: Entry\n")));
  131. lpMPSWabFileInfo->hDataAccessMutex = CreateMutex(NULL,FALSE,TEXT("MPSWabDataAccessMutex"));
  132. if(!LockFileAccess(lpMPSWabFileInfo))
  133. {
  134. DebugTrace(TEXT("LockFileAccess Failed\n"));
  135. hr = MAPI_E_NO_ACCESS;
  136. goto out;
  137. }
  138. else
  139. {
  140. bFileLocked = TRUE;
  141. }
  142. //
  143. // Initialize
  144. //
  145. lpMPSWabFileInfo->lpMPSWabFileHeader = NULL;
  146. lpMPSWabFileInfo->lpszMPSWabFileName = NULL;
  147. lpMPSWabFileInfo->lpMPSWabIndexStr = NULL;
  148. lpMPSWabFileInfo->lpMPSWabIndexEID = NULL;
  149. *lphPropertyStore = NULL;
  150. //
  151. // No file name ???
  152. //
  153. if (lpszFileName == NULL) goto out;
  154. //
  155. // Allocate space for the file header
  156. //
  157. lpMPSWabFileInfo->lpMPSWabFileHeader = LocalAlloc(LMEM_ZEROINIT,sizeof(MPSWab_FILE_HEADER));
  158. if (!lpMPSWabFileInfo->lpMPSWabFileHeader)
  159. {
  160. DebugTrace(TEXT("Error allocating memory\n"));
  161. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  162. goto out;
  163. }
  164. //
  165. // retain file name for future use
  166. //
  167. cchSize = lstrlen(lpszFileName) + 1;
  168. lpMPSWabFileInfo->lpszMPSWabFileName = (LPTSTR) LocalAlloc(LMEM_ZEROINIT,sizeof(TCHAR)*cchSize);
  169. if (!lpMPSWabFileInfo->lpszMPSWabFileName)
  170. {
  171. DebugTrace(TEXT("Error allocating memory\n"));
  172. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  173. goto out;
  174. }
  175. StrCpyN(lpMPSWabFileInfo->lpszMPSWabFileName,lpszFileName,cchSize);
  176. if(((ulFlags & AB_OPEN_ALWAYS)) || ((ulFlags & AB_OPEN_EXISTING)))
  177. {
  178. //
  179. // If file exists, open it - if it doesnt exist, create a new one
  180. //
  181. hMPSWabFile = FindFirstFile(lpMPSWabFileInfo->lpszMPSWabFileName, &FileData);
  182. if (hMPSWabFile == INVALID_HANDLE_VALUE)
  183. {
  184. //
  185. // File Not Found
  186. //
  187. if ((ulFlags & AB_OPEN_ALWAYS))
  188. {
  189. //
  190. // create a new one
  191. //
  192. if (!CreateMPSWabFile( IN lpMPSWabFileInfo->lpMPSWabFileHeader,
  193. IN lpMPSWabFileInfo->lpszMPSWabFileName,
  194. IN MAX_INITIAL_INDEX_ENTRIES,
  195. IN NAMEDPROP_STORE_SIZE))
  196. {
  197. DebugTrace(TEXT("Could Not Create File %s!\n"),lpMPSWabFileInfo->lpszMPSWabFileName);
  198. goto out;
  199. }
  200. }
  201. else
  202. {
  203. //
  204. // Nothing to do .. exit
  205. //
  206. goto out;
  207. }
  208. }
  209. else
  210. {
  211. // found the file ... just close the handle ...
  212. FindClose(hMPSWabFile);
  213. hMPSWabFile = NULL;
  214. }
  215. }
  216. else if (((ulFlags & AB_CREATE_NEW)) || ((ulFlags & AB_CREATE_ALWAYS)))
  217. {
  218. //
  219. // Create a new file - overwrite any existing file
  220. //
  221. if ((ulFlags & AB_CREATE_NEW))
  222. {
  223. hMPSWabFile = FindFirstFile(lpMPSWabFileInfo->lpszMPSWabFileName, &FileData);
  224. if (hMPSWabFile != INVALID_HANDLE_VALUE)
  225. {
  226. //
  227. // Dont overwrite if flag is CREATE_NEW
  228. //
  229. DebugTrace(TEXT("Specified file %s found\n"),lpMPSWabFileInfo->lpszMPSWabFileName);
  230. hr = MAPI_E_NOT_FOUND;
  231. //Close the handle since we dont need it
  232. FindClose(hMPSWabFile);
  233. hMPSWabFile = NULL;
  234. goto out;
  235. }
  236. }
  237. //
  238. // Create a new one ... over-write if neccessary
  239. //
  240. if (!CreateMPSWabFile( IN lpMPSWabFileInfo->lpMPSWabFileHeader,
  241. IN lpMPSWabFileInfo->lpszMPSWabFileName,
  242. IN MAX_INITIAL_INDEX_ENTRIES,
  243. IN NAMEDPROP_STORE_SIZE))
  244. {
  245. DebugTrace(TEXT("Could Not Create File %s!\n"),lpMPSWabFileInfo->lpszMPSWabFileName);
  246. goto out;
  247. }
  248. }
  249. //
  250. // Now we have a valid file, even though the file is new ... load the structures from the file
  251. //
  252. //
  253. // check that we have a valid hWnd if we need to show message boxes
  254. //
  255. if (hWnd == NULL)
  256. hWnd = GetDesktopWindow();
  257. // reentrancy point for bug 16681
  258. TryOpeningWABFileOnceAgain:
  259. //
  260. // Open the file
  261. //
  262. hr = OpenWABFile(lpMPSWabFileInfo->lpszMPSWabFileName, NULL, &hMPSWabFile);
  263. if ( (hMPSWabFile == INVALID_HANDLE_VALUE) ||
  264. HR_FAILED(hr))
  265. {
  266. DebugTrace(TEXT("Could not open file.\nExiting ...\n"));
  267. goto out;
  268. }
  269. // Verify the WAB version, and migrate the file from an old version
  270. // to a new version if required
  271. hr = HrVerifyWABVersionAndUpdate( hWnd,
  272. hMPSWabFile,
  273. lpMPSWabFileInfo);
  274. if(HR_FAILED(hr))
  275. {
  276. //
  277. // Bug 16681:
  278. // Check the special case error for the blank-wab problem
  279. // If this error exists, then rename to file to *.w-b
  280. // and try creating a new wab file or restoring from
  281. // backup ...
  282. if(hr == MAPI_E_VERSION)
  283. {
  284. TCHAR szSaveAsFileName[MAX_PATH];
  285. ULONG nLen = lstrlen(lpMPSWabFileInfo->lpszMPSWabFileName);
  286. StrCpyN(szSaveAsFileName, lpMPSWabFileInfo->lpszMPSWabFileName, ARRAYSIZE(szSaveAsFileName));
  287. szSaveAsFileName[nLen-2]='\0';
  288. StrCatBuff(szSaveAsFileName, TEXT("~b"), ARRAYSIZE(szSaveAsFileName));
  289. DeleteFile(szSaveAsFileName); //just in case it exists
  290. DebugTrace(TEXT("Blank WAB file found. Being saved as %s\n"), szSaveAsFileName);
  291. if (hMPSWabFile && INVALID_HANDLE_VALUE != hMPSWabFile)
  292. {
  293. IF_WIN32(CloseHandle(hMPSWabFile);)
  294. IF_WIN16(CloseFile(hMPSWabFile);)
  295. hMPSWabFile = NULL;
  296. }
  297. if(!MoveFile(lpMPSWabFileInfo->lpszMPSWabFileName, szSaveAsFileName))
  298. {
  299. // Just in case MoveFile failed,
  300. if(!DeleteFile(lpMPSWabFileInfo->lpszMPSWabFileName))
  301. {
  302. // and if delete file failed too, we dont want to get
  303. // caught in a loop so exit ..
  304. goto out;
  305. }
  306. }
  307. hr = E_FAIL;
  308. goto TryOpeningWABFileOnceAgain;
  309. }
  310. // There is a catch here that if the GUID of the file is mangled
  311. // we will never be able to access the file with the WAB
  312. DebugTrace(TEXT("hrVerifyWABVersionAndUpdate failed: %x\n"), hr);
  313. goto out;
  314. // else fall through
  315. }
  316. if(lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags == WAB_CLEAR)
  317. {
  318. // so it is a wab file - if there are no errors tagged to a quick check
  319. hr = HrDoQuickWABIntegrityCheck(lpMPSWabFileInfo, hMPSWabFile);
  320. if (HR_FAILED(hr))
  321. DebugTrace(TEXT("HrDoQuickWABIntegrityCheck failed:%x\n"),hr);
  322. else
  323. {
  324. // Reload whatever new info we added as a result of the above.
  325. if(!ReloadMPSWabFileInfo(
  326. lpMPSWabFileInfo,
  327. hMPSWabFile))
  328. {
  329. DebugTrace(TEXT("Reading file info failed.\n"));
  330. hr = E_FAIL;
  331. }
  332. }
  333. }
  334. // if the quick check failed or some errors are tagged then rebuild the
  335. // indexes
  336. if( (HR_FAILED(hr)) ||
  337. (lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags & WAB_ERROR_DETECTED) ||
  338. (lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags & WAB_WRITE_IN_PROGRESS) )
  339. {
  340. hr = HrDoDetailedWABIntegrityCheck(lpMPSWabFileInfo,hMPSWabFile);
  341. if(HR_FAILED(hr))
  342. {
  343. DebugTrace(TEXT("HrDoDetailedWABIntegrityCheck failed:%x\n"),hr);
  344. if(hr == MAPI_E_CORRUPT_DATA)
  345. {
  346. if (ulFlags & AB_DONT_RESTORE)
  347. {
  348. goto out;
  349. }
  350. else
  351. {
  352. // Restore from Backup
  353. ShowMessageBoxParam(hWnd, idsWABIntegrityError, MB_ICONHAND | MB_OK, lpMPSWabFileInfo->lpszMPSWabFileName);
  354. hr = HrRestoreFromBackup(lpMPSWabFileInfo, hMPSWabFile);
  355. if(!HR_FAILED(hr))
  356. ShowMessageBox(NULL, idsWABRestoreSucceeded, MB_OK | MB_ICONEXCLAMATION);
  357. else
  358. {
  359. ShowMessageBoxParam(NULL, idsWABUnableToRestoreBackup, MB_ICONHAND | MB_OK, lpMPSWabFileInfo->lpszMPSWabFileName);
  360. goto out;
  361. }
  362. }
  363. }
  364. else
  365. goto out;
  366. }
  367. }
  368. lpMPSWabFileInfo->bReadOnlyAccess = ((ulFlags & AB_OPEN_READ_ONLY)) ? TRUE : FALSE;
  369. hr = S_OK;
  370. out:
  371. //
  372. // Cleanup
  373. //
  374. if (hMPSWabFile && INVALID_HANDLE_VALUE != hMPSWabFile)
  375. IF_WIN32(CloseHandle(hMPSWabFile);) IF_WIN16(CloseFile(hMPSWabFile);)
  376. if (!(FAILED(hr)))
  377. {
  378. lpMPSWabFileInfo->bMPSWabInitialized = TRUE;
  379. *lphPropertyStore = (HANDLE) lpMPSWabFileInfo;
  380. }
  381. else
  382. {
  383. LocalFreeAndNull(&lpMPSWabFileInfo->lpMPSWabFileHeader);
  384. LocalFreeAndNull(&lpMPSWabFileInfo->lpszMPSWabFileName);
  385. LocalFreeAndNull(&lpMPSWabFileInfo->lpMPSWabIndexStr);
  386. LocalFreeAndNull(&lpMPSWabFileInfo->lpMPSWabIndexEID);
  387. //Close our handle on this mutex
  388. CloseHandle(lpMPSWabFileInfo->hDataAccessMutex);
  389. LocalFreeAndNull(&lpMPSWabFileInfo);
  390. }
  391. if (bFileLocked)
  392. UnLockFileAccess(lpMPSWabFileInfo);
  393. DebugTrace(( TEXT("OpenPropertyStore: Exit\n-----------\n")));
  394. return(hr);
  395. }
  396. //$$//////////////////////////////////////////////////////////////////////////////////
  397. //
  398. // ClosePropertyStore
  399. //
  400. // IN hPropertyStore - handle to property store
  401. // IN ulFlags - AB_DONT_BACKUP prevents automatic backup. Should be called for
  402. // for non-default property stores.
  403. //
  404. // Returns
  405. // Success: S_OK
  406. // Failure: E_FAIL
  407. //
  408. ////////////////////////////////////////////////////////////////////////////////////
  409. HRESULT ClosePropertyStore(HANDLE hPropertyStore, ULONG ulFlags)
  410. {
  411. HRESULT hr = E_FAIL;
  412. TCHAR szBackupFileName[MAX_PATH];
  413. LPMPSWab_FILE_INFO lpMPSWabFileInfo = NULL;
  414. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  415. DebugTrace(( TEXT("-----------\nClosePropertyStore: Entry\n")));
  416. if(pt_bIsWABOpenExSession && !(ulFlags & AB_IGNORE_OUTLOOK))
  417. {
  418. // This is a WABOpenEx session using outlooks storage provider
  419. // Dont need to do anything in here ...
  420. if(!hPropertyStore)
  421. return MAPI_E_NOT_INITIALIZED;
  422. return S_OK;
  423. }
  424. lpMPSWabFileInfo = hPropertyStore;
  425. if (NULL == lpMPSWabFileInfo) goto out;
  426. if(!(ulFlags & AB_DONT_BACKUP))
  427. {
  428. szBackupFileName[0]='\0';
  429. GetWABBackupFileName(lpMPSWabFileInfo->lpszMPSWabFileName,szBackupFileName,ARRAYSIZE(szBackupFileName));
  430. if(lstrlen(szBackupFileName))
  431. {
  432. //
  433. // We do a backup operation here and some cleanup
  434. //
  435. hr = BackupPropertyStore( hPropertyStore,
  436. szBackupFileName);
  437. if(HR_FAILED(hr))
  438. {
  439. DebugTrace(TEXT("BackupPropertyStore failed: %x\n"),hr);
  440. //ignore errors and keep going on with this shutdown ...
  441. }
  442. }
  443. }
  444. LocalFreeAndNull(&lpMPSWabFileInfo->lpMPSWabFileHeader);
  445. LocalFreeAndNull(&lpMPSWabFileInfo->lpszMPSWabFileName);
  446. LocalFreeAndNull(&lpMPSWabFileInfo->lpMPSWabIndexStr);
  447. LocalFreeAndNull(&lpMPSWabFileInfo->lpMPSWabIndexEID);
  448. //Close our handle on this mutex
  449. CloseHandle(lpMPSWabFileInfo->hDataAccessMutex);
  450. LocalFreeAndNull(&lpMPSWabFileInfo);
  451. hr = S_OK;
  452. out:
  453. DebugTrace(( TEXT("ClosePropertyStore: Exit\n-----------\n")));
  454. return(hr);
  455. }
  456. //$$//////////////////////////////////////////////////////////////////////////////////
  457. //
  458. // SetContainerObjectType
  459. //
  460. // In this IE5 WAB, we are saving RECORD_CONTAINER type objects to the WAB store
  461. // However, the previous IE4- wabs dont understand this object and will barf and
  462. // fail. For purposes of backward compatibility, we need to make sure that they
  463. // dont fail - to do this, we mark the object-type of record container objects
  464. // from MAPI_ABCONT to MAPI_MAILUSER - that way a IE4- wab will treat the folder
  465. // as a spurious mail user but wont exactly crash .. we'll let the RecordHeader.ulObjType
  466. // remain as a RECORD_CONTAINER so we can still do quick searches for it
  467. // When reading the object, we will reset the object type in IE5(this) WAB
  468. //
  469. //////////////////////////////////////////////////////////////////////////////////////
  470. void SetContainerObjectType(ULONG ulcProps, LPSPropValue lpProps, BOOL bSetToMailUser)
  471. {
  472. ULONG i = 0;
  473. for(i=0;i<ulcProps;i++)
  474. {
  475. if(lpProps[i].ulPropTag == PR_OBJECT_TYPE)
  476. {
  477. lpProps[i].Value.l = bSetToMailUser ? MAPI_MAILUSER : MAPI_ABCONT;
  478. break;
  479. }
  480. }
  481. }
  482. //$$//////////////////////////////////////////////////////////////////////////////////
  483. //
  484. // WriteRecord
  485. //
  486. // IN hPropertyStore - handle to property store
  487. // IN pmbinFold - <Outlook> EntryID of folder to search in (NULL for default)
  488. // IN lppsbEID - EntryId of record to write.
  489. // *lppsbEID should be null to create and return new entryID
  490. // IN ulRecordType - RECORD_CONTACT, RECORD_DISTLIST, RECORD_CONTAINER
  491. // IN ulcPropCount - number of props in prop array
  492. // IN lpPropArray - Array of LPSPropValues
  493. // IN ulFlags - reserved - 0
  494. //
  495. // Two cases -
  496. // writing a new record or
  497. // modifying/editing an old record
  498. //
  499. // In the first case we create all the proper header structures and
  500. // tack them onto the end of the file, updating the indexes and the
  501. // file header structure.
  502. //
  503. // In the second case, when record is edited, it could become smaller or larger
  504. // To avoid too much complication, we invalidate the old record header in the file and
  505. // write the edited record to a new location. The accesscount in the file header
  506. // is updated so that after too many edits we can re-write the file to a cleaner
  507. // file. The original entryid is retained and the offset/data updated in the indexes.
  508. //
  509. // Returns
  510. // Success: S_OK
  511. // Failure: E_FAIL
  512. //
  513. ////////////////////////////////////////////////////////////////////////////////////
  514. HRESULT WriteRecord(IN HANDLE hPropertyStore,
  515. IN LPSBinary pmbinFold,
  516. IN LPSBinary * lppsbEID,
  517. IN ULONG ulFlags,
  518. IN ULONG ulRecordType,
  519. IN ULONG ulcPropCount,
  520. IN LPPROPERTY_ARRAY lpPropArray)
  521. {
  522. HRESULT hr = E_FAIL;
  523. LPULONG lpPropTagArray = NULL;
  524. TCHAR * lpRecordData = NULL;
  525. HANDLE hMPSWabFile = NULL;
  526. DWORD dwNumofBytes = 0;
  527. ULONG ulRecordDataSize = 0;
  528. BOOL bIsNewRecord = TRUE;
  529. ULONG nIndexPos;
  530. ULONG i=0,j=0,k=0;
  531. BOOL bFileLocked = FALSE;
  532. DWORD dwTempEID = 0;
  533. SBinary sbEIDSave = {0};
  534. BOOL bEIDSave = FALSE;
  535. ULONG iEIDSave; // index of EID property in lpPropArray
  536. ULONG ulcOldPropCount = 0;
  537. LPSPropValue lpOldPropArray = NULL;
  538. TCHAR lpszOldIndex[indexMax][MAX_INDEX_STRING];
  539. DWORD dwEntryID = 0;
  540. SBinary sbEID = {0};
  541. LPSBinary lpsbEID = NULL;
  542. ULONG ulRecordHeaderOffset = 0;
  543. ULONG ulRecordPropTagOffset = 0;
  544. ULONG ulRecordDataOffset = 0;
  545. BOOL bPropSet[indexMax];
  546. DWORD dwErr = 0;
  547. ULONG nLen = 0;
  548. LPBYTE lp = NULL;
  549. //
  550. // These structures temporarily hold the new entry info for us
  551. //
  552. MPSWab_INDEX_ENTRY_DATA_STRING MPSWabIndexEntryDataString[indexMax];
  553. MPSWab_INDEX_ENTRY_DATA_ENTRYID MPSWabIndexEntryDataEntryID;
  554. MPSWab_RECORD_HEADER MPSWabRecordHeader = {0};
  555. LPMPSWab_FILE_INFO lpMPSWabFileInfo;
  556. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  557. #ifdef DEBUG
  558. // _DebugProperties(lpPropArray, ulcPropCount, TEXT("WriteRecord Properties"));
  559. #endif
  560. if(pt_bIsWABOpenExSession)
  561. {
  562. // This is a WABOpenEx session using outlooks storage provider
  563. if(!hPropertyStore)
  564. return MAPI_E_NOT_INITIALIZED;
  565. {
  566. LPWABSTORAGEPROVIDER lpWSP = (LPWABSTORAGEPROVIDER) hPropertyStore;
  567. ULONG cb = 0;
  568. LPSPropValue lpNewPropArray = NULL;
  569. SCODE sc = 0;
  570. if(!pt_bIsUnicodeOutlook)
  571. {
  572. // Need to convert these props back to ANSI for Outlook
  573. // Since we don't know whether these props are localalloced or MapiAlloced,
  574. // we can't convert them without leaking memory.
  575. // Therefore, we need to create a copy of the props before we can save them ..
  576. // what a waste of effort ..
  577. // Allocate more for our return buffer
  578. if (FAILED(sc = ScCountProps(ulcPropCount, lpPropArray, &cb)))
  579. {
  580. hr = ResultFromScode(sc);
  581. goto exit;
  582. }
  583. if (FAILED(sc = MAPIAllocateBuffer(cb, &lpNewPropArray)))
  584. {
  585. hr = ResultFromScode(sc);
  586. goto exit;
  587. }
  588. if (FAILED(sc = ScCopyProps(ulcPropCount, lpPropArray, lpNewPropArray, NULL)))
  589. {
  590. hr = ResultFromScode(sc);
  591. goto exit;
  592. }
  593. // Now we thunk the data back to ANSI for Outlook
  594. if (FAILED(sc = ScConvertWPropsToA((LPALLOCATEMORE) (&MAPIAllocateMore), lpNewPropArray, ulcPropCount, 0)))
  595. {
  596. hr = ResultFromScode(sc);
  597. goto exit;
  598. }
  599. }
  600. hr = lpWSP->lpVtbl->WriteRecord(lpWSP,
  601. pmbinFold,
  602. lppsbEID,
  603. ulFlags,
  604. ulRecordType,
  605. ulcPropCount,
  606. lpNewPropArray ? lpNewPropArray : lpPropArray);
  607. DebugTrace(TEXT("WABStorageProvider::WriteRecord returned:%x\n"),hr);
  608. exit:
  609. FreeBufferAndNull(&lpNewPropArray);
  610. return hr;
  611. }
  612. }
  613. lpMPSWabFileInfo = hPropertyStore;
  614. if ( (NULL == lpMPSWabFileInfo) ||
  615. (NULL == lpPropArray) ||
  616. (0 == ulcPropCount) )
  617. {
  618. DebugTrace(TEXT("Invalid Parameter!!\n"));
  619. hr = MAPI_E_INVALID_PARAMETER;
  620. goto out;
  621. }
  622. if ((ulRecordType != RECORD_CONTACT) &&
  623. (ulRecordType != RECORD_DISTLIST) &&
  624. (ulRecordType != RECORD_CONTAINER))
  625. goto out;
  626. if(lppsbEID)
  627. {
  628. lpsbEID = *lppsbEID;
  629. if(lpsbEID && lpsbEID->cb != SIZEOF_WAB_ENTRYID)
  630. {
  631. // this may be a WAB container .. reset the entryid to a WAB entryid
  632. if(WAB_CONTAINER == IsWABEntryID(lpsbEID->cb, (LPENTRYID)lpsbEID->lpb,
  633. NULL,NULL,NULL,NULL,NULL))
  634. {
  635. IsWABEntryID(lpsbEID->cb, (LPENTRYID)lpsbEID->lpb,
  636. (LPVOID*)&sbEID.lpb,(LPVOID*)&sbEID.cb,NULL,NULL,NULL);
  637. if(sbEID.cb == SIZEOF_WAB_ENTRYID)
  638. lpsbEID = &sbEID;
  639. }
  640. }
  641. }
  642. if(!lppsbEID || (lpsbEID && lpsbEID->cb != SIZEOF_WAB_ENTRYID))
  643. {
  644. DebugTrace(TEXT("Invalid Parameter!!\n"));
  645. hr = MAPI_E_INVALID_PARAMETER;
  646. goto out;
  647. }
  648. if(lpsbEID && lpsbEID->cb && lpsbEID->lpb)
  649. CopyMemory(&dwEntryID, lpsbEID->lpb, min(lpsbEID->cb, sizeof(dwEntryID)));
  650. DebugTrace(TEXT("--WriteRecord: dwEntryID=%d\n"), dwEntryID);
  651. if (lpMPSWabFileInfo->bReadOnlyAccess)
  652. {
  653. DebugTrace(TEXT("Access Permissions are Read-Only\n"));
  654. hr = MAPI_E_NO_ACCESS;
  655. goto out;
  656. }
  657. if(!LockFileAccess(lpMPSWabFileInfo))
  658. {
  659. DebugTrace(TEXT("LockFileAccess Failed\n"));
  660. hr = MAPI_E_NO_ACCESS;
  661. goto out;
  662. }
  663. else
  664. {
  665. bFileLocked = TRUE;
  666. }
  667. if(ulRecordType == RECORD_CONTAINER)
  668. SetContainerObjectType(ulcPropCount, lpPropArray, TRUE);
  669. //
  670. // Open the file
  671. //
  672. hr = OpenWABFile(lpMPSWabFileInfo->lpszMPSWabFileName, NULL, &hMPSWabFile);
  673. if ( (hMPSWabFile == INVALID_HANDLE_VALUE) ||
  674. HR_FAILED(hr))
  675. {
  676. DebugTrace(TEXT("Could not open file.\nExiting ...\n"));
  677. goto out;
  678. }
  679. //
  680. // Check that we have enough disk space before trying any disk writing operations
  681. //
  682. if(!WABHasFreeDiskSpace(lpMPSWabFileInfo->lpszMPSWabFileName, hMPSWabFile))
  683. {
  684. hr = MAPI_E_NOT_ENOUGH_DISK;
  685. goto out;
  686. }
  687. hr = E_FAIL; //reset hr
  688. //
  689. // To ensure that file info is accurate,
  690. // Any time we open a file, read the file info again ...
  691. //
  692. if(!ReloadMPSWabFileInfo(
  693. lpMPSWabFileInfo,
  694. hMPSWabFile))
  695. {
  696. DebugTrace(TEXT("Reading file info failed.\n"));
  697. goto out;
  698. }
  699. //
  700. // Anytime we detect an error - try to fix it ...
  701. //
  702. if((lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags & WAB_ERROR_DETECTED) ||
  703. (lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags & WAB_WRITE_IN_PROGRESS))
  704. {
  705. if(HR_FAILED(HrDoQuickWABIntegrityCheck(lpMPSWabFileInfo,hMPSWabFile)))
  706. {
  707. hr = HrDoDetailedWABIntegrityCheck(lpMPSWabFileInfo,hMPSWabFile);
  708. if(HR_FAILED(hr))
  709. {
  710. DebugTrace(TEXT("HrDoDetailedWABIntegrityCheck failed:%x\n"),hr);
  711. goto out;
  712. }
  713. }
  714. }
  715. hr = E_FAIL; //reset hr
  716. //
  717. // If this is an old record, we want to get its old propertys so we can compare the
  718. // indexes to see if any of their values changed ... if the valuse changed then we
  719. // have to update the indexes for the old record too ..
  720. //
  721. if (dwEntryID != 0)
  722. {
  723. //get pointers to old displayname, firstname, lastname
  724. for(j=indexDisplayName;j<indexMax;j++)
  725. {
  726. lpszOldIndex[j][0]='\0';
  727. if (!LoadIndex( IN lpMPSWabFileInfo,
  728. IN j,
  729. IN hMPSWabFile) )
  730. {
  731. DebugTrace(TEXT("Error Loading Index!\n"));
  732. goto out;
  733. }
  734. for(i=0;i<lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].ulcNumEntries;i++)
  735. {
  736. if(lpMPSWabFileInfo->lpMPSWabIndexStr[i].dwEntryID == dwEntryID)
  737. {
  738. // an old index exists for this entry
  739. // get its value
  740. StrCpyN(lpszOldIndex[j],lpMPSWabFileInfo->lpMPSWabIndexStr[i].szIndex,ARRAYSIZE(lpszOldIndex[j]));
  741. break;
  742. }
  743. }
  744. }
  745. }
  746. // Tag this file as undergoing a write operation
  747. if(!bTagWriteTransaction( lpMPSWabFileInfo->lpMPSWabFileHeader,
  748. hMPSWabFile) )
  749. {
  750. DebugTrace(TEXT("Taggin file write failed\n"));
  751. goto out;
  752. }
  753. //
  754. // Irrespective of whether this is a new record or an old record, the
  755. // data is going to the end of the file ... Get this new file position
  756. //
  757. ulRecordHeaderOffset = GetFileSize(hMPSWabFile, NULL);
  758. if (dwEntryID != 0)
  759. {
  760. //
  761. // we are not creating a new thing
  762. // so we should first find the old header
  763. // if the old entry doesnt exist then we
  764. // should treat this as a new record and
  765. // replace the entry id with a properly generated
  766. // entryid
  767. // if we find the existing record then we need to mark that as
  768. // being defunct
  769. //
  770. //
  771. // Search for given EntryID
  772. // If not found, assign a new one
  773. //
  774. if (BinSearchEID( IN lpMPSWabFileInfo->lpMPSWabIndexEID,
  775. IN dwEntryID,
  776. IN lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries,
  777. OUT &nIndexPos))
  778. {
  779. //
  780. // this entryid exists in the index - we will need to invalidate this record
  781. //
  782. bIsNewRecord = FALSE;
  783. if(!ReadDataFromWABFile(hMPSWabFile,
  784. lpMPSWabFileInfo->lpMPSWabIndexEID[nIndexPos].ulOffset,
  785. (LPVOID) &MPSWabRecordHeader,
  786. (DWORD) sizeof(MPSWab_RECORD_HEADER)))
  787. goto out;
  788. //
  789. // Set valid flag to false
  790. //
  791. MPSWabRecordHeader.bValidRecord = FALSE;
  792. //
  793. // Write it back
  794. // Set File Pointer to this record
  795. //
  796. if(!WriteDataToWABFile( hMPSWabFile,
  797. lpMPSWabFileInfo->lpMPSWabIndexEID[nIndexPos].ulOffset,
  798. (LPVOID) &MPSWabRecordHeader,
  799. sizeof(MPSWab_RECORD_HEADER)))
  800. goto out;
  801. //
  802. // update the EntryID index so that it now points to the new offset
  803. // instead of the old one
  804. //
  805. lpMPSWabFileInfo->lpMPSWabIndexEID[nIndexPos].ulOffset = ulRecordHeaderOffset;
  806. //
  807. // Increment this count so we know that we invalidated one more record ...
  808. //
  809. lpMPSWabFileInfo->lpMPSWabFileHeader->ulModificationCount++;
  810. }
  811. else
  812. {
  813. bIsNewRecord = TRUE; //This tags whether or not to create a new Index entry
  814. //
  815. // assign a new entryid
  816. //
  817. dwEntryID = lpMPSWabFileInfo->lpMPSWabFileHeader->dwNextEntryID++;
  818. }
  819. }
  820. else
  821. {
  822. //
  823. // we are creating a new thing
  824. //
  825. bIsNewRecord = TRUE;
  826. lpMPSWabFileInfo->lpMPSWabFileHeader->dwNextEntryID++;
  827. dwEntryID = lpMPSWabFileInfo->lpMPSWabFileHeader->dwNextEntryID;
  828. }
  829. //
  830. // Set the flag so we know when to backup
  831. //
  832. lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags |= WAB_BACKUP_NOW;
  833. //
  834. // if bIsNewRecord, then the PR_ENTRYID field of the record, as passed
  835. // into this function, is 0 and we want to change it to the new Entry ID
  836. // prior to saving so that we can include the new EntryID in the record on file
  837. // Hence we scan the records and update PR_ENTRYID
  838. //
  839. if (bIsNewRecord)
  840. {
  841. for(i=0;i < ulcPropCount; i++)
  842. {
  843. if (lpPropArray[i].ulPropTag == PR_ENTRYID)
  844. {
  845. // Save the value of the property for restoration later
  846. sbEIDSave = lpPropArray[i].Value.bin;
  847. iEIDSave = i;
  848. bEIDSave = TRUE;
  849. // Assert(! lpPropArray[i].Value.bin.cb);
  850. if (! lpPropArray[i].Value.bin.cb) {
  851. // No EntryID pointer... point to a temporary one.
  852. lpPropArray[i].Value.bin.lpb = (LPVOID)&dwTempEID;
  853. }
  854. CopyMemory(lpPropArray[i].Value.bin.lpb,&dwEntryID,SIZEOF_WAB_ENTRYID);
  855. lpPropArray[i].Value.bin.cb = SIZEOF_WAB_ENTRYID;
  856. break;
  857. }
  858. }
  859. }
  860. //
  861. // Now we create a new Record Header structure to write to the file
  862. //
  863. MPSWabRecordHeader.bValidRecord = TRUE;
  864. MPSWabRecordHeader.ulObjType = ulRecordType;
  865. MPSWabRecordHeader.dwEntryID = dwEntryID;
  866. MPSWabRecordHeader.ulcPropCount = ulcPropCount;
  867. //
  868. // write this empty record header to file so we can allocate file space now
  869. // before filling in all the data
  870. //
  871. if(!WriteDataToWABFile( hMPSWabFile,
  872. ulRecordHeaderOffset,
  873. (LPVOID) &MPSWabRecordHeader,
  874. sizeof(MPSWabRecordHeader)))
  875. goto out;
  876. //
  877. // Now the File Pointer points to the end of the header which is the
  878. // beginning of the PropTagArray
  879. // ulRecordPropTagOffset is a relative offset from the start of the Record Header
  880. //
  881. ulRecordPropTagOffset = sizeof(MPSWab_RECORD_HEADER);
  882. MPSWabRecordHeader.ulPropTagArraySize = sizeof(ULONG) * ulcPropCount;
  883. //
  884. // Allocate space for the prop tag array
  885. //
  886. lpPropTagArray = LocalAlloc(LMEM_ZEROINIT, MPSWabRecordHeader.ulPropTagArraySize);
  887. if (!lpPropTagArray)
  888. {
  889. DebugTrace(TEXT("Error allocating memory\n"));
  890. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  891. goto out;
  892. }
  893. //
  894. // Fill in this array
  895. //
  896. for(i=0;i < ulcPropCount; i++)
  897. {
  898. lpPropTagArray[i] = lpPropArray[i].ulPropTag;
  899. }
  900. //
  901. // write it
  902. //
  903. if(!WriteFile( hMPSWabFile,
  904. (LPCVOID) lpPropTagArray,
  905. (DWORD) MPSWabRecordHeader.ulPropTagArraySize ,
  906. &dwNumofBytes,
  907. NULL))
  908. {
  909. DebugTrace(TEXT("Writing RecordPropArray failed.\n"));
  910. goto out;
  911. }
  912. ulRecordDataOffset = sizeof(ULONG) * ulcPropCount;
  913. if(HR_FAILED(hr = HrGetBufferFromPropArray(ulcPropCount,
  914. lpPropArray,
  915. &ulRecordDataSize,
  916. &lp)))
  917. {
  918. goto out;
  919. }
  920. MPSWabRecordHeader.ulPropTagArrayOffset = ulRecordPropTagOffset;
  921. MPSWabRecordHeader.ulRecordDataOffset = ulRecordDataOffset;
  922. MPSWabRecordHeader.ulRecordDataSize = ulRecordDataSize;
  923. //
  924. // update the record header
  925. // Write in the record header
  926. // Set the filepointer to the RecordOffset
  927. //
  928. if(!WriteDataToWABFile( hMPSWabFile,
  929. ulRecordHeaderOffset,
  930. (LPVOID) &MPSWabRecordHeader,
  931. sizeof(MPSWab_RECORD_HEADER)))
  932. goto out;
  933. //
  934. // Write a data block
  935. // Now we can write this block of data into the file
  936. //
  937. if (0xFFFFFFFF == SetFilePointer ( hMPSWabFile,
  938. ulRecordDataOffset,
  939. NULL,
  940. FILE_CURRENT))
  941. {
  942. DebugTrace(TEXT("SetFilePointer Failed\n"));
  943. goto out;
  944. }
  945. //
  946. // Now write the RecordData
  947. //
  948. if(!WriteFile( hMPSWabFile,
  949. (LPCVOID) lp,
  950. (DWORD) ulRecordDataSize,
  951. &dwNumofBytes,
  952. NULL))
  953. {
  954. DebugTrace(TEXT("Writing RecordHeader failed.\n"));
  955. goto out;
  956. }
  957. LocalFreeAndNull(&lp);
  958. //
  959. // Update the indexes and write to file
  960. // If this is a new record, we need to create and store new index
  961. // entries in their proper place in the property store file
  962. //
  963. //// If this is not a new entry then we need to compare the index values to see if they
  964. //// might have changed
  965. //
  966. // EntryID index in the file. Since we have already updated the actual
  967. // offset in the Index in memory, all we really need to do is to
  968. // store the index back into file. The string indexes are unchanged
  969. // in this operation.
  970. //
  971. //
  972. // Create the new index entries (only for new records)
  973. //
  974. MPSWabIndexEntryDataEntryID.dwEntryID = dwEntryID;
  975. MPSWabIndexEntryDataEntryID.ulOffset = ulRecordHeaderOffset;
  976. for(j=indexDisplayName;j<indexMax;j++)
  977. {
  978. MPSWabIndexEntryDataString[j].dwEntryID = dwEntryID;
  979. MPSWabIndexEntryDataString[j].szIndex[0] = '\0';
  980. bPropSet[j] = FALSE;
  981. for(i=0;i<ulcPropCount;i++)
  982. {
  983. if(lpPropArray[i].ulPropTag == rgIndexArray[j])
  984. {
  985. bPropSet[j] = TRUE;
  986. nLen = TruncatePos(lpPropArray[i].Value.LPSZ, MAX_INDEX_STRING-1);
  987. CopyMemory(MPSWabIndexEntryDataString[j].szIndex,lpPropArray[i].Value.LPSZ,sizeof(TCHAR)*nLen);
  988. MPSWabIndexEntryDataString[j].szIndex[nLen]='\0';
  989. break;
  990. }
  991. }
  992. }
  993. if (bIsNewRecord)
  994. {
  995. DebugTrace(TEXT("Creating New Record: EntryID %d\n"), dwEntryID);
  996. // Now write these indexes into file ...
  997. // the indices in the file are already sorted so to add the new entry
  998. // we will do the following:
  999. //
  1000. // 1. Find out where in the index the entry would fit in
  1001. // 2. Write the entry into that position in the file
  1002. // 3. write the rest of the index from that point on into the file
  1003. // 4. reload the index
  1004. // do a bin search to find a match for the current index
  1005. // binsearch returns the matching position on match or it
  1006. // returns the position at which the match would exist were
  1007. // the match in the array. Thus whether
  1008. // there is a match or not we can assume ulPosition containts
  1009. // the index of the item at which the new entry should be entered
  1010. //
  1011. //
  1012. // do string indexes
  1013. //
  1014. for(j=indexDisplayName;j<indexMax;j++) //assumes a specific order defined in mpswab.h
  1015. {
  1016. if(!bPropSet[j])
  1017. continue;
  1018. //
  1019. // Get the index
  1020. //
  1021. if (!LoadIndex( IN lpMPSWabFileInfo,
  1022. IN j,
  1023. IN hMPSWabFile) )
  1024. {
  1025. DebugTrace(TEXT("Error Loading Index!\n"));
  1026. goto out;
  1027. }
  1028. DebugTrace( TEXT("Index: %d Entry: %s\n"),j,MPSWabIndexEntryDataString[j].szIndex);
  1029. BinSearchStr( IN lpMPSWabFileInfo->lpMPSWabIndexStr,
  1030. IN MPSWabIndexEntryDataString[j].szIndex,
  1031. IN lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].ulcNumEntries,
  1032. OUT &nIndexPos);
  1033. // nIndexPos will contain the position at which we can insert this entry into the file
  1034. //Set the filepointer to point to the above found point
  1035. if(!WriteDataToWABFile( hMPSWabFile,
  1036. lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].ulOffset + (nIndexPos) * sizeof(MPSWab_INDEX_ENTRY_DATA_STRING),
  1037. (LPVOID) &MPSWabIndexEntryDataString[j],
  1038. sizeof(MPSWab_INDEX_ENTRY_DATA_STRING)))
  1039. goto out;
  1040. if (lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].ulcNumEntries != nIndexPos) //if not the last entry
  1041. {
  1042. //write the remaining entries in the array back to file
  1043. if(!WriteFile( hMPSWabFile,
  1044. (LPCVOID) &lpMPSWabFileInfo->lpMPSWabIndexStr[nIndexPos],
  1045. (DWORD) sizeof(MPSWab_INDEX_ENTRY_DATA_STRING)*(lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].ulcNumEntries - nIndexPos),
  1046. &dwNumofBytes,
  1047. NULL))
  1048. {
  1049. DebugTrace(TEXT("Writing Index[%d] failed.\n"), j);
  1050. goto out;
  1051. }
  1052. }
  1053. lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].ulcNumEntries++;
  1054. lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].UtilizedBlockSize += sizeof(MPSWab_INDEX_ENTRY_DATA_STRING);
  1055. }
  1056. //Do the same for the EntryID index also
  1057. BinSearchEID( IN lpMPSWabFileInfo->lpMPSWabIndexEID,
  1058. IN MPSWabIndexEntryDataEntryID.dwEntryID,
  1059. IN lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries,
  1060. OUT &nIndexPos);
  1061. // nIndexPos will contain the position at which we can insert this entry into the file
  1062. if(!WriteDataToWABFile( hMPSWabFile,
  1063. lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulOffset + (nIndexPos) * sizeof(MPSWab_INDEX_ENTRY_DATA_ENTRYID),
  1064. (LPVOID) &MPSWabIndexEntryDataEntryID,
  1065. sizeof(MPSWab_INDEX_ENTRY_DATA_ENTRYID)))
  1066. goto out;
  1067. if (lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries != nIndexPos) //if not the last entry
  1068. {
  1069. //write the remaining entries in the array back to file
  1070. if(!WriteFile( hMPSWabFile,
  1071. (LPCVOID) &lpMPSWabFileInfo->lpMPSWabIndexEID[nIndexPos],
  1072. (DWORD) sizeof(MPSWab_INDEX_ENTRY_DATA_ENTRYID)*(lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries - nIndexPos),
  1073. &dwNumofBytes,
  1074. NULL))
  1075. {
  1076. DebugTrace(TEXT("Writing Index[%d] failed.\n"), j);
  1077. goto out;
  1078. }
  1079. }
  1080. lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries++;
  1081. lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].UtilizedBlockSize += sizeof(MPSWab_INDEX_ENTRY_DATA_ENTRYID);
  1082. lpMPSWabFileInfo->lpMPSWabFileHeader->ulcNumEntries++;
  1083. }
  1084. else
  1085. {
  1086. DebugTrace(TEXT("Modifying Existing Record: EntryID %d\n"), dwEntryID);
  1087. // We have to compare the old props with the new props to see if we need to change any of the string
  1088. // indexes ...
  1089. for(j=indexDisplayName;j<indexMax;j++)
  1090. {
  1091. BOOL bUpdateStringIndex = FALSE;
  1092. BOOL bRemoveOldStringIndex = FALSE;
  1093. BOOL bAddNewStringIndex = FALSE;
  1094. DebugTrace(TEXT("Index: %d Entry: %s\n"),j,MPSWabIndexEntryDataString[j].szIndex);
  1095. if (lstrlen(MPSWabIndexEntryDataString[j].szIndex))
  1096. bAddNewStringIndex = TRUE;
  1097. if (lstrlen(lpszOldIndex[j]))
  1098. bRemoveOldStringIndex = TRUE;
  1099. // if there is no old index and there is a new index
  1100. // or there is an old index and there is a new index but they are different
  1101. // or there is an old index but no new index then
  1102. if( (!bRemoveOldStringIndex && bAddNewStringIndex)
  1103. || (bRemoveOldStringIndex && bAddNewStringIndex && (lstrcmpi(lpszOldIndex[j],MPSWabIndexEntryDataString[j].szIndex)!=0))
  1104. || (bRemoveOldStringIndex && !bAddNewStringIndex) )
  1105. {
  1106. bUpdateStringIndex = TRUE;
  1107. }
  1108. if(!bUpdateStringIndex)
  1109. continue;
  1110. if (bRemoveOldStringIndex)
  1111. {
  1112. ULONG nIndex =0;
  1113. int nStartPos=0,nEndPos=0;
  1114. LPTSTR lpsz = lpszOldIndex[j];
  1115. ULONG nTotal = 0;
  1116. if (!LoadIndex( IN lpMPSWabFileInfo,
  1117. IN j,
  1118. IN hMPSWabFile) )
  1119. {
  1120. DebugTrace(TEXT("Error Loading Index!\n"));
  1121. goto out;
  1122. }
  1123. nTotal = lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].ulcNumEntries;
  1124. // Find the position of the old string index
  1125. // There is one problem where there are multiple entries with the same name
  1126. // BinSearch can potentially hand us back the wrong entry if we just
  1127. // search by name alone .. we need to look at both names and
  1128. // entry ids before accepting a position as the correct one
  1129. //
  1130. BinSearchStr( IN lpMPSWabFileInfo->lpMPSWabIndexStr,
  1131. IN lpszOldIndex[j],
  1132. IN nTotal,
  1133. OUT &nIndexPos);
  1134. // nIndexPos contains the position of a particular entry matching the old index
  1135. // This may not necessarily be the correct entry if there are multiple identical
  1136. // display name entries ... Hence we look in out sorted Index array for the start
  1137. // of such names and the end of such names and then look at the entry ids
  1138. // of all such entries to get the right one
  1139. if(nTotal > 0)
  1140. {
  1141. nStartPos = (int) nIndexPos;
  1142. nEndPos = (int) nIndexPos;
  1143. while((nStartPos>=0) && !lstrcmpi(lpsz,lpMPSWabFileInfo->lpMPSWabIndexStr[nStartPos].szIndex))
  1144. nStartPos--;
  1145. nStartPos++;
  1146. while((nEndPos<(int)nTotal) && !lstrcmpi(lpsz,lpMPSWabFileInfo->lpMPSWabIndexStr[nEndPos].szIndex))
  1147. nEndPos++;
  1148. nEndPos--;
  1149. if (nStartPos != nEndPos)
  1150. {
  1151. // there is more than one ...
  1152. for(nIndex=(ULONG)nStartPos;nIndex<=(ULONG)nEndPos;nIndex++)
  1153. {
  1154. if (lpMPSWabFileInfo->lpMPSWabIndexStr[nIndex].dwEntryID == dwEntryID)
  1155. {
  1156. nIndexPos = nIndex;
  1157. break;
  1158. }
  1159. }
  1160. }
  1161. }
  1162. // At this point nIndexPos will contain the correctposition of this entry
  1163. //Set the filepointer to point to the above found point
  1164. if (0xFFFFFFFF == SetFilePointer ( hMPSWabFile,
  1165. lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].ulOffset + (nIndexPos) * sizeof(MPSWab_INDEX_ENTRY_DATA_STRING),
  1166. NULL,
  1167. FILE_BEGIN))
  1168. {
  1169. DebugTrace(TEXT("SetFilePointer Failed\n"));
  1170. goto out;
  1171. }
  1172. //remove the entry by overwriting it ...
  1173. if (lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].ulcNumEntries != nIndexPos) //if not the last entry
  1174. {
  1175. //write the remaining entries in the array back to file
  1176. if(!WriteFile( hMPSWabFile,
  1177. (LPCVOID) &lpMPSWabFileInfo->lpMPSWabIndexStr[nIndexPos+1],
  1178. (DWORD) sizeof(MPSWab_INDEX_ENTRY_DATA_STRING)*(lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].ulcNumEntries - nIndexPos-1),
  1179. &dwNumofBytes,
  1180. NULL))
  1181. {
  1182. DebugTrace(TEXT("Writing Index[%d] failed.\n"), j);
  1183. goto out;
  1184. }
  1185. }
  1186. if(lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].ulcNumEntries>0)
  1187. lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].ulcNumEntries--;
  1188. if(lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].UtilizedBlockSize>0)
  1189. lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].UtilizedBlockSize -= sizeof(MPSWab_INDEX_ENTRY_DATA_STRING);
  1190. }
  1191. if (bAddNewStringIndex)
  1192. {
  1193. //Now find where the new entry would go ..
  1194. //
  1195. // Get the index
  1196. //
  1197. if (!LoadIndex( IN lpMPSWabFileInfo,
  1198. IN j,
  1199. IN hMPSWabFile) )
  1200. {
  1201. DebugTrace(TEXT("Error Loading Index!\n"));
  1202. goto out;
  1203. }
  1204. BinSearchStr( IN lpMPSWabFileInfo->lpMPSWabIndexStr,
  1205. IN MPSWabIndexEntryDataString[j].szIndex,
  1206. IN lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].ulcNumEntries,
  1207. OUT &nIndexPos);
  1208. // nIndexPos will contain the position at which we can insert this entry into the file
  1209. if(!WriteDataToWABFile( hMPSWabFile,
  1210. lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].ulOffset + (nIndexPos) * sizeof(MPSWab_INDEX_ENTRY_DATA_STRING),
  1211. (LPVOID) &MPSWabIndexEntryDataString[j],
  1212. sizeof(MPSWab_INDEX_ENTRY_DATA_STRING)))
  1213. goto out;
  1214. if (lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].ulcNumEntries != nIndexPos) //if not the last entry
  1215. {
  1216. //write the remaining entries in the array back to file
  1217. if(!WriteFile( hMPSWabFile,
  1218. (LPCVOID) &lpMPSWabFileInfo->lpMPSWabIndexStr[nIndexPos],
  1219. (DWORD) sizeof(MPSWab_INDEX_ENTRY_DATA_STRING)*(lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].ulcNumEntries - nIndexPos),
  1220. &dwNumofBytes,
  1221. NULL))
  1222. {
  1223. DebugTrace(TEXT("Writing Index[%d] failed.\n"), j);
  1224. goto out;
  1225. }
  1226. }
  1227. lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].ulcNumEntries++;
  1228. lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].UtilizedBlockSize += sizeof(MPSWab_INDEX_ENTRY_DATA_STRING);
  1229. }
  1230. }
  1231. // Not a new item index-entry but just a modification of an old one
  1232. // in this case we just need to save the EntryID index back to file
  1233. if (!BinSearchEID( IN lpMPSWabFileInfo->lpMPSWabIndexEID,
  1234. IN dwEntryID,
  1235. IN lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries,
  1236. OUT &nIndexPos))
  1237. {
  1238. DebugTrace(TEXT("EntryID not found\n")); //No way should this ever happen
  1239. hr = MAPI_E_INVALID_ENTRYID;
  1240. goto out;
  1241. }
  1242. //Set the filepointer to point to the start of the entryid index
  1243. if(!WriteDataToWABFile( hMPSWabFile,
  1244. lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulOffset + (nIndexPos) * sizeof(MPSWab_INDEX_ENTRY_DATA_ENTRYID),
  1245. (LPVOID) &lpMPSWabFileInfo->lpMPSWabIndexEID[nIndexPos],
  1246. sizeof(MPSWab_INDEX_ENTRY_DATA_ENTRYID)))
  1247. goto out;
  1248. }
  1249. // update the file header
  1250. if (0xFFFFFFFF == SetFilePointer ( hMPSWabFile,
  1251. 0,
  1252. NULL,
  1253. FILE_BEGIN))
  1254. {
  1255. DebugTrace(TEXT("SetFilePointer Failed\n"));
  1256. goto out;
  1257. }
  1258. #ifdef DEBUG
  1259. DebugTrace(TEXT("ulcNum: %d\t"),lpMPSWabFileInfo->lpMPSWabFileHeader->ulcNumEntries);
  1260. for(i=indexDisplayName;i<indexMax-2;i++)
  1261. DebugTrace(TEXT("index %d: %d\t"),i, lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[i].ulcNumEntries);
  1262. DebugTrace(TEXT("\n"));
  1263. #endif
  1264. if(lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries != lpMPSWabFileInfo->lpMPSWabFileHeader->ulcNumEntries)
  1265. lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags |= WAB_ERROR_DETECTED;
  1266. for(i=indexDisplayName+1;i<indexMax;i++)
  1267. {
  1268. if(lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[i].ulcNumEntries > lpMPSWabFileInfo->lpMPSWabFileHeader->ulcNumEntries)
  1269. lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags |= WAB_ERROR_DETECTED;
  1270. }
  1271. if(!WriteFile( hMPSWabFile,
  1272. (LPCVOID) lpMPSWabFileInfo->lpMPSWabFileHeader,
  1273. (DWORD) sizeof(MPSWab_FILE_HEADER),
  1274. &dwNumofBytes,
  1275. NULL))
  1276. {
  1277. DebugTrace(TEXT("Writing FileHeader failed.\n"));
  1278. goto out;
  1279. }
  1280. if ((lpMPSWabFileInfo->lpMPSWabFileHeader->ulcMaxNumEntries - lpMPSWabFileInfo->lpMPSWabFileHeader->ulcNumEntries) < 10)
  1281. {
  1282. //
  1283. // if we are within 10 entries of exhausting the allocated space for the property
  1284. // store, its time to grow the store.
  1285. //
  1286. if (!CompressFile( lpMPSWabFileInfo,
  1287. hMPSWabFile,
  1288. NULL,
  1289. TRUE,
  1290. AB_GROW_INDEX))
  1291. {
  1292. DebugTrace(TEXT("Growing the file failed\n"));
  1293. goto out;
  1294. }
  1295. }
  1296. /*
  1297. // Notify other processes and our UI
  1298. {
  1299. NOTIFICATION Notification;
  1300. Notification.ulEventType = bIsNewRecord ? fnevObjectCreated : fnevObjectModified;
  1301. Notification.info.obj.cbEntryID = SIZEOF_WAB_ENTRYID;
  1302. Notification.info.obj.lpEntryID = (LPENTRYID)&dwEntryID;
  1303. switch (ulRecordType) {
  1304. case RECORD_CONTACT:
  1305. Notification.info.obj.ulObjType = MAPI_MAILUSER;
  1306. break;
  1307. case RECORD_DISTLIST:
  1308. Notification.info.obj.ulObjType = MAPI_DISTLIST;
  1309. break;
  1310. case RECORD_CONTAINER:
  1311. Notification.info.obj.ulObjType = MAPI_ABCONT;
  1312. break;
  1313. default:
  1314. Assert(FALSE);
  1315. break;
  1316. }
  1317. Notification.info.obj.cbParentID = 0;
  1318. Notification.info.obj.lpParentID = NULL;
  1319. Notification.info.obj.cbOldID = 0;
  1320. Notification.info.obj.lpOldID = NULL;
  1321. Notification.info.obj.cbOldParentID = 0;
  1322. Notification.info.obj.lpOldParentID = NULL;
  1323. Notification.info.obj.lpPropTagArray = (LPSPropTagArray)lpPropArray;
  1324. HrFireNotification(&Notification);
  1325. }
  1326. */
  1327. //
  1328. // if we're still here it was all fun and games ...
  1329. //
  1330. if(!*lppsbEID) // if there was a null LPSBinary entryid provided, return one
  1331. {
  1332. LPSBinary lpsb = LocalAlloc(LMEM_ZEROINIT, sizeof(SBinary));
  1333. if(!lpsb)
  1334. {
  1335. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  1336. goto out;
  1337. }
  1338. lpsb->cb = SIZEOF_WAB_ENTRYID;
  1339. lpsb->lpb = LocalAlloc(LMEM_ZEROINIT, SIZEOF_WAB_ENTRYID);
  1340. if(!lpsb->lpb)
  1341. {
  1342. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  1343. goto out;
  1344. }
  1345. CopyMemory(lpsb->lpb, &dwEntryID, lpsb->cb);
  1346. *lppsbEID = lpsb;
  1347. }
  1348. hr = S_OK;
  1349. out:
  1350. // UnTag this file as undergoing a write operation
  1351. // We only want the flag to stay there during crashes not during
  1352. // normal operations
  1353. //
  1354. if(lpMPSWabFileInfo)
  1355. {
  1356. if(!bUntagWriteTransaction( lpMPSWabFileInfo->lpMPSWabFileHeader,
  1357. hMPSWabFile) )
  1358. {
  1359. DebugTrace(TEXT("Untaggin file write failed\n"));
  1360. }
  1361. }
  1362. if (bEIDSave) {
  1363. // Restore the original EID property in the input property array
  1364. lpPropArray[iEIDSave].Value.bin = sbEIDSave;
  1365. }
  1366. LocalFreeAndNull(&lpPropTagArray);
  1367. LocalFreePropArray(hPropertyStore, ulcOldPropCount, &lpOldPropArray);
  1368. if (hMPSWabFile)
  1369. IF_WIN32(CloseHandle(hMPSWabFile);) IF_WIN16(CloseFile(hMPSWabFile);)
  1370. if (bFileLocked)
  1371. UnLockFileAccess(lpMPSWabFileInfo);
  1372. // Some special case error codes for generic fails
  1373. if(HR_FAILED(hr) && hr == E_FAIL)
  1374. {
  1375. dwErr = GetLastError();
  1376. switch(dwErr)
  1377. {
  1378. case ERROR_DISK_FULL:
  1379. hr = MAPI_E_NOT_ENOUGH_DISK;
  1380. break;
  1381. }
  1382. }
  1383. // in case we changed the object type here, reset it
  1384. if(ulRecordType == RECORD_CONTAINER)
  1385. SetContainerObjectType(ulcPropCount, lpPropArray, FALSE);
  1386. DebugTrace(( TEXT("WriteRecord: Exit\n-----------\n")));
  1387. return(hr);
  1388. }
  1389. /*
  1390. -
  1391. - HrDupePropResWCtoA
  1392. *
  1393. * Dupes the PropRes passed into FindRecords and ReadPropArray
  1394. * and converts it from WC to A in the process so we can feed
  1395. * it to outlook
  1396. *
  1397. * Note the *lppPropResA->lpProp needs to be freed seperately from *lppPropResA
  1398. */
  1399. HRESULT HrDupePropResWCtoA(ULONG ulFlags, LPSPropertyRestriction lpPropRes,LPSPropertyRestriction * lppPropResA)
  1400. {
  1401. SCODE sc = 0;
  1402. HRESULT hr = S_OK;
  1403. LPSPropValue lpNewPropArray = NULL;
  1404. LPSPropertyRestriction lpPropResA = NULL;
  1405. ULONG cb = 0;
  1406. if(!(ulFlags & AB_MATCH_PROP_ONLY)) // means Restriction has some data part
  1407. {
  1408. if (FAILED(sc = ScCountProps(1, lpPropRes->lpProp, &cb)))
  1409. {
  1410. hr = ResultFromScode(sc);
  1411. goto exit;
  1412. }
  1413. if (FAILED(sc = MAPIAllocateBuffer(cb, &lpNewPropArray)))
  1414. {
  1415. hr = ResultFromScode(sc);
  1416. goto exit;
  1417. }
  1418. if (FAILED(sc = ScCopyProps(1, lpPropRes->lpProp, lpNewPropArray, NULL)))
  1419. {
  1420. hr = ResultFromScode(sc);
  1421. goto exit;
  1422. }
  1423. // Now we thunk the data back to ANSI for Outlook
  1424. if (FAILED(sc = ScConvertWPropsToA((LPALLOCATEMORE) (&MAPIAllocateMore), lpNewPropArray, 1, 0)))
  1425. {
  1426. hr = ResultFromScode(sc);
  1427. goto exit;
  1428. }
  1429. }
  1430. else
  1431. {
  1432. if (FAILED(sc = MAPIAllocateBuffer(sizeof(SPropValue), &lpNewPropArray)))
  1433. {
  1434. hr = ResultFromScode(sc);
  1435. goto exit;
  1436. }
  1437. ZeroMemory(lpNewPropArray, sizeof(SPropValue));
  1438. if(PROP_TYPE(lpPropRes->ulPropTag)==PT_UNICODE)
  1439. lpNewPropArray->ulPropTag = CHANGE_PROP_TYPE(lpPropRes->ulPropTag, PT_STRING8);
  1440. else if(PROP_TYPE(lpPropRes->ulPropTag)==PT_MV_UNICODE)
  1441. lpNewPropArray->ulPropTag = CHANGE_PROP_TYPE(lpPropRes->ulPropTag, PT_MV_STRING8);
  1442. else
  1443. lpNewPropArray->ulPropTag = lpPropRes->ulPropTag;
  1444. }
  1445. if (FAILED(sc = MAPIAllocateBuffer(sizeof(SPropertyRestriction), &lpPropResA)))
  1446. {
  1447. hr = ResultFromScode(sc);
  1448. goto exit;
  1449. }
  1450. lpPropResA->relop = lpPropRes->relop;
  1451. lpPropResA->ulPropTag = lpNewPropArray->ulPropTag;
  1452. lpPropResA->lpProp = lpNewPropArray;
  1453. *lppPropResA = lpPropResA;
  1454. exit:
  1455. if(HR_FAILED(hr))
  1456. {
  1457. FreeBufferAndNull(&lpPropResA);
  1458. FreeBufferAndNull(&lpNewPropArray);
  1459. }
  1460. return hr;
  1461. }
  1462. //$$//////////////////////////////////////////////////////////////////////////////////
  1463. //
  1464. // FindRecords
  1465. //
  1466. // IN hPropertyStore - handle to property store
  1467. // IN pmbinFold - <Outlook> EntryID of folder to search in (NULL for default)
  1468. // IN ulFlags - AB_MATCH_PROP_ONLY - checks for existence of a certain prop only
  1469. // Does not check/compare the value of the Prop
  1470. // Used for unindexed properties only. Works only
  1471. // with RELOP_EQ and RELOP_NE
  1472. // e.g. caller says - give me a list of all entryids who have
  1473. // an email address - in this case we dont care what the
  1474. // email address is. Or he could say, give me a list of
  1475. // all entries who dont have URLs
  1476. //
  1477. // AB_IGNORE_OUTLOOK - works against WAB file even if OLK is running
  1478. //
  1479. // IN lpPropRes - pointer to SPropRes structure
  1480. // IN bLockFile - This function is also called internally in cases where we dont
  1481. // want to lock the file - In such cases we set the value to False. For
  1482. // external callers (outside MPSWAB.c) this value must always be TRUE
  1483. // IN OUT lpulcEIDCount - Count of how many to get and how many actually returned
  1484. // if Zero is specified, we have to get all matches.
  1485. //
  1486. //
  1487. // OUT rgsbEntryIDs - array of SBinary structures containing matching entryids
  1488. //
  1489. // lpPropRes will specify one of the following operators
  1490. // RELOP_GE (>=) RELOP_GT (>) RELOP_LE (<=)
  1491. // RELOP_LT (<) RELOP_NE (!=) RELOP_EQ (==)
  1492. //
  1493. // Implicit in this function is the fact that it should not be called for
  1494. // finding EntryIDs based on a given entryid value i.e. lpPropRes cannot
  1495. // contain an EntryID value, reason being that entryids aer unique and it doesnt
  1496. // make sense to find entryids. Hence if an entryid is specified, this
  1497. // function will just return the specified entryid back ...
  1498. //
  1499. // Returns
  1500. // Success: S_OK
  1501. // Failure: E_FAIL
  1502. //
  1503. ////////////////////////////////////////////////////////////////////////////////////
  1504. HRESULT FindRecords(IN HANDLE hPropertyStore,
  1505. IN LPSBinary pmbinFold,
  1506. IN ULONG ulFlags,
  1507. IN BOOL bLockFile,
  1508. IN LPSPropertyRestriction lpPropRes,
  1509. IN OUT LPULONG lpulcEIDCount,
  1510. OUT LPSBinary * lprgsbEntryIDs)
  1511. {
  1512. HRESULT hr = E_FAIL;
  1513. LPDWORD lprgdwTmp = NULL;
  1514. HANDLE hMPSWabFile = NULL;
  1515. ULONG nCurrentIndex =0;
  1516. ULONG i=0,j=0,k=0,min=0,n=0;
  1517. DWORD nCurrentEID = 0;
  1518. ULONG ulMaxCount;
  1519. DWORD dwNumofBytes = 0;
  1520. ULONG ret;
  1521. BOOL bMatchFound;
  1522. TCHAR lpszValue[MAX_INDEX_STRING+1];
  1523. ULONG ulRangeStart = 0;
  1524. ULONG ulRangeEnd = 0;
  1525. ULONG ulRelOp = 0;
  1526. ULONG ulcNumEntries =0;
  1527. ULONG ulPreviousRecordOffset = 0,ulCurrentRecordOffset = 0;
  1528. ULONG ulRecordCount = 0;
  1529. LPULONG lpulPropTagArray = NULL;
  1530. TCHAR * szBuf = NULL;
  1531. TCHAR * lp = NULL;
  1532. int nComp = 0;
  1533. BOOL bFileLocked = 0;
  1534. BOOL bErrorDetected = FALSE;
  1535. LPDWORD lpdwEntryIDs = NULL;
  1536. ULONG ulcEIDCount = 0;
  1537. LPDWORD lpdwEID = NULL;
  1538. SPropValue TmpProp;
  1539. ULONG ulcTmpValues;
  1540. ULONG ulcTmpDataSize;
  1541. ULONG ulFileSize = 0;
  1542. MPSWab_RECORD_HEADER MPSWabRecordHeader;
  1543. LPMPSWab_FILE_INFO lpMPSWabFileInfo;
  1544. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  1545. if(pt_bIsWABOpenExSession && !(ulFlags & AB_IGNORE_OUTLOOK))
  1546. {
  1547. // This is a WABOpenEx session using outlooks storage provider
  1548. if(!hPropertyStore)
  1549. return MAPI_E_NOT_INITIALIZED;
  1550. {
  1551. LPWABSTORAGEPROVIDER lpWSP = (LPWABSTORAGEPROVIDER) hPropertyStore;
  1552. LPSPropertyRestriction lpPropResA = NULL;
  1553. if( !pt_bIsUnicodeOutlook)
  1554. {
  1555. // Need to thunk the restriction down to ANSI
  1556. HrDupePropResWCtoA(ulFlags, lpPropRes, &lpPropResA);
  1557. }
  1558. hr = lpWSP->lpVtbl->FindRecords(lpWSP,
  1559. (pmbinFold && pmbinFold->cb && pmbinFold->lpb) ? pmbinFold : NULL,
  1560. ulFlags,
  1561. lpPropResA ? lpPropResA : lpPropRes,
  1562. lpulcEIDCount,
  1563. lprgsbEntryIDs);
  1564. DebugTrace(TEXT("WABStorageProvider::FindRecords returned:%x\n"),hr);
  1565. if(lpPropResA)
  1566. {
  1567. FreeBufferAndNull(&lpPropResA->lpProp);
  1568. FreeBufferAndNull(&lpPropResA);
  1569. }
  1570. return hr;
  1571. }
  1572. }
  1573. lpMPSWabFileInfo = hPropertyStore;
  1574. if (NULL==lpMPSWabFileInfo) goto out;
  1575. if (NULL==lpPropRes) goto out;
  1576. //
  1577. // If we are looking for property matching only, the lpProp can be null
  1578. // Just remember not to reference it in this case...
  1579. //
  1580. if ( !((ulFlags & AB_MATCH_PROP_ONLY)) && (NULL==lpPropRes->lpProp))
  1581. {
  1582. goto out;
  1583. }
  1584. lpdwEntryIDs = NULL;
  1585. ulMaxCount = *lpulcEIDCount;
  1586. *lpulcEIDCount = 0;
  1587. ulRelOp = lpPropRes->relop;
  1588. if(bLockFile)
  1589. {
  1590. if(!LockFileAccess(lpMPSWabFileInfo))
  1591. {
  1592. DebugTrace(TEXT("LockFileAccess Failed\n"));
  1593. hr = MAPI_E_NO_ACCESS;
  1594. goto out;
  1595. }
  1596. else
  1597. {
  1598. bFileLocked = TRUE;
  1599. }
  1600. }
  1601. //
  1602. // Open the file
  1603. //
  1604. hr = OpenWABFile(lpMPSWabFileInfo->lpszMPSWabFileName, NULL, &hMPSWabFile);
  1605. if ( (hMPSWabFile == INVALID_HANDLE_VALUE) ||
  1606. HR_FAILED(hr))
  1607. {
  1608. DebugTrace(TEXT("Could not open file.\nExiting ...\n"));
  1609. goto out;
  1610. }
  1611. ulFileSize = GetFileSize(hMPSWabFile, NULL);
  1612. //
  1613. // To ensure that file info is accurate,
  1614. // Any time we open a file, read the file info again ...
  1615. //
  1616. if(!ReloadMPSWabFileInfo(
  1617. lpMPSWabFileInfo,
  1618. hMPSWabFile))
  1619. {
  1620. DebugTrace(TEXT("Reading file info failed.\n"));
  1621. goto out;
  1622. }
  1623. //
  1624. // Anytime we detect an error - try to fix it ...
  1625. //
  1626. if((lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags & WAB_ERROR_DETECTED) ||
  1627. (lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags & WAB_WRITE_IN_PROGRESS))
  1628. {
  1629. if(HR_FAILED(HrDoQuickWABIntegrityCheck(lpMPSWabFileInfo,hMPSWabFile)))
  1630. {
  1631. hr = HrDoDetailedWABIntegrityCheck(lpMPSWabFileInfo,hMPSWabFile);
  1632. if(HR_FAILED(hr))
  1633. {
  1634. DebugTrace(TEXT("HrDoDetailedWABIntegrityCheck failed:%x\n"),hr);
  1635. goto out;
  1636. }
  1637. }
  1638. }
  1639. //
  1640. //There are 2 main cases for this FindRecord function:
  1641. // 1. The specified property type to find is an index and we just
  1642. // need to search the indexes.
  1643. // 2. The specified property type is not an index, so we need to search
  1644. // the whole file.
  1645. // Each case is treated seperately.
  1646. //
  1647. //
  1648. // Of course, first we check if mistakenly an EntryID was sought. If
  1649. // so, just return the entry id itself.
  1650. //
  1651. if (rgIndexArray[indexEntryID] == lpPropRes->ulPropTag)
  1652. {
  1653. lpdwEntryIDs = LocalAlloc(LMEM_ZEROINIT,SIZEOF_WAB_ENTRYID);
  1654. if (!lpdwEntryIDs)
  1655. {
  1656. DebugTrace(TEXT("Error allocating memory\n"));
  1657. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  1658. goto out;
  1659. }
  1660. *lpdwEntryIDs = lpPropRes->lpProp->Value.ul;
  1661. *lpulcEIDCount = 1;
  1662. hr = S_OK;
  1663. goto out;
  1664. }
  1665. //
  1666. // Now Check if the specified property type is indexed or not indexed
  1667. //
  1668. for (i = indexDisplayName; i<indexMax; i++) //assumes that indexEntryID = 0 and ignores it
  1669. {
  1670. //
  1671. // first check if the prop tag we are searching for is indexed or not
  1672. //
  1673. if (rgIndexArray[i] == lpPropRes->ulPropTag)
  1674. {
  1675. ulcNumEntries = lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[i].ulcNumEntries;
  1676. if (ulcNumEntries == 0)
  1677. {
  1678. //
  1679. // if nothing to search in, then report a success and return
  1680. //
  1681. hr = S_OK;
  1682. goto out;
  1683. }
  1684. if ((ulFlags & AB_MATCH_PROP_ONLY))
  1685. {
  1686. //
  1687. // We dont need to look at the data
  1688. // We can assume that every single record has the indexed properties
  1689. // and therefore every record is eligible for returning
  1690. //
  1691. // So if RELOP_EQ is specified, we can just return a array of all
  1692. // the existing entryids .. if RELOP_NE is specified, then we cant
  1693. // return anything ...
  1694. //
  1695. if (lpPropRes->relop == RELOP_NE)
  1696. {
  1697. ulcEIDCount = 0;//*lpulcEIDCount = 0;
  1698. lpdwEID = NULL; //lpdwEntryIDs = NULL;
  1699. hr = S_OK;
  1700. }
  1701. else if(lpPropRes->relop == RELOP_EQ)
  1702. {
  1703. //*lpulcEIDCount = ulcNumEntries;
  1704. ulcEIDCount = ulcNumEntries;
  1705. //Allocate enough memory for returned array
  1706. //lpdwEntryIDs = LocalAlloc(LMEM_ZEROINIT,SIZEOF_WAB_ENTRYID * (*lpulcEIDCount));
  1707. lpdwEID = LocalAlloc(LMEM_ZEROINIT,SIZEOF_WAB_ENTRYID * ulcEIDCount);
  1708. //if (!lpdwEntryIDs)
  1709. if (!lpdwEID)
  1710. {
  1711. DebugTrace(TEXT("Error allocating memory\n"));
  1712. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  1713. goto out;
  1714. }
  1715. // Make sure this index is loaded into memory
  1716. if (!LoadIndex(lpMPSWabFileInfo,i,hMPSWabFile))
  1717. {
  1718. DebugTrace(TEXT("Could not load index %x\n"),rgIndexArray[i]);
  1719. goto out;
  1720. }
  1721. for(j=0;j<ulcEIDCount;j++)
  1722. {
  1723. lpdwEID[j] = lpMPSWabFileInfo->lpMPSWabIndexStr[j].dwEntryID;
  1724. }
  1725. hr = S_OK;
  1726. }
  1727. else
  1728. {
  1729. DebugTrace(TEXT("Unsupported find parameters\n"));
  1730. hr = MAPI_E_INVALID_PARAMETER;
  1731. }
  1732. goto filterFolderMembers;
  1733. }
  1734. //
  1735. // We need to look at the Data
  1736. //
  1737. //
  1738. // The index strings are only MAX_INDEX_STRING long
  1739. // If the value to search for is longer we need to truncate it to
  1740. // MAX_INDEX_STRING length. There is a caveat that now we will
  1741. // return spurious matches but lets leave it here for now
  1742. // and tag it as TBD!!!
  1743. //
  1744. if (lstrlen(lpPropRes->lpProp->Value.LPSZ) >= MAX_INDEX_STRING-1) // >= 31 chars (so won't include trailing null)
  1745. {
  1746. ULONG nLen = TruncatePos(lpPropRes->lpProp->Value.LPSZ, MAX_INDEX_STRING-1);
  1747. CopyMemory(lpszValue,lpPropRes->lpProp->Value.LPSZ,sizeof(TCHAR)*nLen);
  1748. lpszValue[nLen]='\0';
  1749. }
  1750. else
  1751. {
  1752. StrCpyN(lpszValue,lpPropRes->lpProp->Value.LPSZ,ARRAYSIZE(lpszValue));
  1753. }
  1754. //
  1755. // Load the appropriate index into memory
  1756. //
  1757. if (!LoadIndex(lpMPSWabFileInfo,i,hMPSWabFile))
  1758. {
  1759. DebugTrace(TEXT("Could not load index %x\n"),rgIndexArray[i]);
  1760. goto out;
  1761. }
  1762. //
  1763. //if it is indexed, search this index for a match
  1764. //
  1765. bMatchFound = BinSearchStr( IN lpMPSWabFileInfo->lpMPSWabIndexStr,
  1766. IN lpszValue,
  1767. IN lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[i].ulcNumEntries,
  1768. OUT &ret);
  1769. //
  1770. // 'ret' now contains the position at which this entry exists, if it exists
  1771. //
  1772. //
  1773. // Now we have to deal with all the relational operators
  1774. // There are several Permutations and Combinations of the operators and
  1775. // the success of the search.
  1776. //
  1777. // Rel_OP MatchFound=TRue MatchFound=False
  1778. //
  1779. // EQ == Find all that match Return Nothing
  1780. // NE != Find all that match and Return all
  1781. // exclude them
  1782. // LE <=, LT < Return Everything in index Return everything
  1783. // including and/or before including and before
  1784. // GT >, GE >= Return Everything in index Return Everything
  1785. // including and/or after including and after
  1786. //
  1787. // Since our sting arrays are sorted, the matched string could
  1788. // be one of many duplicates and we dont know where the duplicate lies
  1789. // so we have to find all the duplicates to the matched string
  1790. // This is easy - e.g.
  1791. // index array -> A,B,D,G,G,G,G,G,S,U,V,Y,Z and we matched G in the
  1792. // middle position ^
  1793. // we can just move forward and backward from there and find the range
  1794. // of indexes that match and treat that range as the matched range
  1795. // and then follow the above combinations ...
  1796. ulRangeStart = ret;
  1797. ulRangeEnd = ret;
  1798. //
  1799. // If no match is found, then we can use the above values for ulRangeStart
  1800. // and ulRangeEnd otherwise if match was found we have to seek the
  1801. // borders of the duplicate list ...
  1802. //
  1803. if (bMatchFound)
  1804. {
  1805. for(;;)
  1806. {
  1807. ulRangeStart--;
  1808. if ( (0xffffffff == ulRangeStart) ||
  1809. (lstrcmpi(lpMPSWabFileInfo->lpMPSWabIndexStr[ulRangeStart].szIndex,lpszValue) ) )
  1810. break;
  1811. }
  1812. for(;;)
  1813. {
  1814. ulRangeEnd++;
  1815. if ( (ulRangeEnd == ulcNumEntries) ||
  1816. (lstrcmpi(lpMPSWabFileInfo->lpMPSWabIndexStr[ulRangeEnd].szIndex,lpszValue) ) )
  1817. break;
  1818. }
  1819. // Fix off-by-one ..
  1820. ulRangeStart++;
  1821. ulRangeEnd--;
  1822. }
  1823. //
  1824. // Now ulRangeStart points to start of the matched entries and
  1825. // ulRangeEnd to end of the matched entries.
  1826. // e.g. 0 1 ... ... ulcNumEntries-1
  1827. // A,B,C,D,G,G,G,G,G,G,H,J,J,K,L,Z
  1828. // ^ ^
  1829. // | |
  1830. // ulRangeStart ulRangeEnd
  1831. //
  1832. // Now we need to calculate the number of values we are returning in the array
  1833. //
  1834. if (bMatchFound)
  1835. {
  1836. switch(ulRelOp)
  1837. {
  1838. case RELOP_GT:
  1839. //include everything from RangeEnd+1 to end
  1840. *lpulcEIDCount = ulcNumEntries - (ulRangeEnd + 1);
  1841. break;
  1842. case RELOP_GE:
  1843. //include everything from RangeStart to end
  1844. *lpulcEIDCount = ulcNumEntries - ulRangeStart;
  1845. break;
  1846. case RELOP_LT:
  1847. *lpulcEIDCount = ulRangeStart;
  1848. break;
  1849. case RELOP_LE:
  1850. *lpulcEIDCount = ulRangeEnd + 1;
  1851. break;
  1852. case RELOP_NE:
  1853. *lpulcEIDCount = ulcNumEntries - (ulRangeEnd+1 - ulRangeStart);
  1854. break;
  1855. case RELOP_EQ:
  1856. *lpulcEIDCount = (ulRangeEnd+1 - ulRangeStart);
  1857. break;
  1858. }
  1859. }
  1860. else
  1861. {
  1862. //Assumes ulRangeStart = ulRangeEnd
  1863. switch(ulRelOp)
  1864. {
  1865. case RELOP_GT:
  1866. case RELOP_GE:
  1867. //include everything from RangeEnd/RangeStart to end
  1868. *lpulcEIDCount = ulcNumEntries - ulRangeEnd;
  1869. break;
  1870. case RELOP_LT:
  1871. case RELOP_LE:
  1872. *lpulcEIDCount = ulRangeStart;
  1873. break;
  1874. case RELOP_NE:
  1875. *lpulcEIDCount = ulcNumEntries;
  1876. break;
  1877. case RELOP_EQ:
  1878. *lpulcEIDCount = 0;
  1879. break;
  1880. }
  1881. }
  1882. if (*lpulcEIDCount == 0)
  1883. {
  1884. //
  1885. // nothing to return - goodbye
  1886. //
  1887. hr = S_OK;
  1888. goto out;
  1889. }
  1890. //
  1891. // dont return more than Max asked for (where Max != 0)...
  1892. //
  1893. if ( (*lpulcEIDCount > ulMaxCount) && (ulMaxCount != 0) )
  1894. *lpulcEIDCount = ulMaxCount;
  1895. //
  1896. // Allocate enough memory for returned array
  1897. //
  1898. lpdwEntryIDs = LocalAlloc(LMEM_ZEROINIT,SIZEOF_WAB_ENTRYID * (*lpulcEIDCount));
  1899. if (!lpdwEntryIDs)
  1900. {
  1901. DebugTrace(TEXT("Error allocating memory\n"));
  1902. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  1903. goto out;
  1904. }
  1905. //
  1906. // Now copy over the EntryIDs from the index to the returned array
  1907. // Each operator needs different treatment
  1908. //
  1909. if (bMatchFound)
  1910. {
  1911. switch(ulRelOp)
  1912. {
  1913. case RELOP_GT:
  1914. for(i=0;i<(*lpulcEIDCount);i++)
  1915. {
  1916. //include everything from RangeEnd+1 to end
  1917. lpdwEntryIDs[i] = lpMPSWabFileInfo->lpMPSWabIndexStr[i+ulRangeEnd+1].dwEntryID;
  1918. }
  1919. break;
  1920. case RELOP_GE:
  1921. for(i=0;i<(*lpulcEIDCount);i++)
  1922. {
  1923. //include everything from RangeStart to end
  1924. lpdwEntryIDs[i] = lpMPSWabFileInfo->lpMPSWabIndexStr[i+ulRangeStart].dwEntryID;
  1925. }
  1926. break;
  1927. case RELOP_LT:
  1928. case RELOP_LE:
  1929. for(i=0;i<(*lpulcEIDCount);i++)
  1930. {
  1931. //include everything from before RangeEnd/RangeStart
  1932. lpdwEntryIDs[i] = lpMPSWabFileInfo->lpMPSWabIndexStr[i].dwEntryID;
  1933. }
  1934. break;
  1935. case RELOP_NE:
  1936. i = 0;
  1937. if ( (ulcNumEntries > ulMaxCount) && (ulMaxCount != 0) )
  1938. ulcNumEntries = ulMaxCount;
  1939. for(j=0;j<ulcNumEntries;j++)
  1940. {
  1941. //include everything from before RangeStart and after RangeEnd
  1942. if ( (j<ulRangeStart) || (j>ulRangeEnd) )
  1943. {
  1944. lpdwEntryIDs[i] = lpMPSWabFileInfo->lpMPSWabIndexStr[j].dwEntryID;
  1945. i++;
  1946. }
  1947. }
  1948. break;
  1949. case RELOP_EQ:
  1950. i = 0;
  1951. for(j=0;j<(*lpulcEIDCount);j++)
  1952. {
  1953. //include everything between RangeStart and RangeEnd
  1954. lpdwEntryIDs[i] = lpMPSWabFileInfo->lpMPSWabIndexStr[j+ulRangeStart].dwEntryID;
  1955. i++;
  1956. }
  1957. break;
  1958. }
  1959. }
  1960. else
  1961. {
  1962. //assumes that RangeStart = RangeEnd
  1963. switch(ulRelOp)
  1964. {
  1965. case RELOP_GT:
  1966. case RELOP_GE:
  1967. for(i=0;i<(*lpulcEIDCount);i++)
  1968. {
  1969. //include everything from RangeStart to end
  1970. lpdwEntryIDs[i] = lpMPSWabFileInfo->lpMPSWabIndexStr[i+ulRangeStart].dwEntryID;
  1971. }
  1972. break;
  1973. case RELOP_LT:
  1974. case RELOP_LE:
  1975. case RELOP_NE:
  1976. for(i=0;i<(*lpulcEIDCount);i++)
  1977. {
  1978. //include first 'n' entries
  1979. lpdwEntryIDs[i] = lpMPSWabFileInfo->lpMPSWabIndexStr[i].dwEntryID;
  1980. }
  1981. break;
  1982. case RELOP_EQ:
  1983. //This case should never happen cause we checked for it before (when total found=0)
  1984. DebugTrace(TEXT("Unexpected RELOP_EQ case\n"));
  1985. break;
  1986. }
  1987. }
  1988. //if we're here we've got our data
  1989. hr = S_OK;
  1990. if(!pmbinFold)
  1991. {
  1992. goto out;
  1993. }
  1994. else
  1995. {
  1996. ulcEIDCount = *lpulcEIDCount;
  1997. lpdwEID = lpdwEntryIDs;
  1998. lpdwEntryIDs = NULL;
  1999. *lpulcEIDCount = 0;
  2000. goto filterFolderMembers;
  2001. }
  2002. }
  2003. }
  2004. // If we're here then we didnt find anything in the indices ...
  2005. // Time to search the whole file
  2006. // Mechanism for this search is to go through all the entries in an index
  2007. // read in the record corresponding to that entry, read in the prop tag
  2008. // array, search in it for the specified property based on REL_OP and then if
  2009. // it meets our criteria, we can store the entryid of the record and return it
  2010. // For the time being lets also ignore Multivalued properties because they are too much of a headache
  2011. if ( ((lpPropRes->ulPropTag & MV_FLAG)) && (!((ulFlags & AB_MATCH_PROP_ONLY))) )
  2012. {
  2013. DebugTrace(TEXT("Searching for MultiValued prop data not supported in this version\n"));
  2014. goto out;
  2015. }
  2016. // The maximum number of entryIDs we can return = maximum number of entries
  2017. // So we will allocate some working space for ourselves here
  2018. lpdwEID = LocalAlloc(LMEM_ZEROINIT, SIZEOF_WAB_ENTRYID*lpMPSWabFileInfo->lpMPSWabFileHeader->ulcNumEntries);
  2019. if (!lpdwEID)
  2020. {
  2021. DebugTrace(TEXT("Error allocating memory\n"));
  2022. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  2023. goto out;
  2024. }
  2025. ulcEIDCount = 0;
  2026. ulPreviousRecordOffset = 0;
  2027. if (0xFFFFFFFF== SetFilePointer ( hMPSWabFile,
  2028. ulPreviousRecordOffset,
  2029. NULL,
  2030. FILE_BEGIN))
  2031. {
  2032. DebugTrace(TEXT("SetFilePointer Failed\n"));
  2033. goto out;
  2034. }
  2035. for(n=0;n<lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries;n++)
  2036. {
  2037. ulCurrentRecordOffset = lpMPSWabFileInfo->lpMPSWabIndexEID[n].ulOffset;
  2038. if (0xFFFFFFFF== SetFilePointer ( hMPSWabFile,
  2039. ulCurrentRecordOffset - ulPreviousRecordOffset,
  2040. NULL,
  2041. FILE_CURRENT))
  2042. {
  2043. DebugTrace(TEXT("SetFilePointer Failed\n"));
  2044. goto out;
  2045. }
  2046. ulPreviousRecordOffset = ulCurrentRecordOffset;
  2047. //Read in the record header
  2048. if(!ReadFile( hMPSWabFile,
  2049. (LPVOID) &MPSWabRecordHeader,
  2050. (DWORD) sizeof(MPSWab_RECORD_HEADER),
  2051. &dwNumofBytes,
  2052. NULL))
  2053. {
  2054. DebugTrace(TEXT("Reading Record header failed.\n"));
  2055. goto out;
  2056. }
  2057. if(dwNumofBytes == 0)
  2058. {
  2059. DebugTrace(TEXT("Passed the end of file\n"));
  2060. break;
  2061. }
  2062. ulPreviousRecordOffset += dwNumofBytes;
  2063. if(!bIsValidRecord( MPSWabRecordHeader,
  2064. lpMPSWabFileInfo->lpMPSWabFileHeader->dwNextEntryID,
  2065. ulCurrentRecordOffset,
  2066. ulFileSize))
  2067. // if (MPSWabRecordHeader.bValidRecord != TRUE)
  2068. {
  2069. //
  2070. // skip to next record
  2071. //
  2072. bErrorDetected = TRUE;
  2073. continue;
  2074. }
  2075. // Do a special case for PR_OBJECT_TYPE searches since these can be easily
  2076. // determined from the record header without having to read the entire record
  2077. //
  2078. if( (lpPropRes->ulPropTag == PR_OBJECT_TYPE) &&
  2079. (lpPropRes->relop == RELOP_EQ) )
  2080. {
  2081. LONG ulObjType = 0;
  2082. if(MPSWabRecordHeader.ulObjType == RECORD_DISTLIST)
  2083. ulObjType = MAPI_DISTLIST;
  2084. else if(MPSWabRecordHeader.ulObjType == RECORD_CONTAINER)
  2085. ulObjType = MAPI_ABCONT;
  2086. else
  2087. ulObjType = MAPI_MAILUSER;
  2088. if(lpPropRes->lpProp->Value.l == ulObjType)
  2089. {
  2090. //save this entry id in our master list
  2091. lpdwEID[ulcEIDCount++] = MPSWabRecordHeader.dwEntryID;
  2092. }
  2093. // goto next record - whether it was a match or not ...
  2094. continue;
  2095. }
  2096. //
  2097. // Read in the PropTagArray
  2098. //
  2099. //
  2100. // Allocate space for the PropTagArray
  2101. //
  2102. LocalFreeAndNull(&lpulPropTagArray);
  2103. lpulPropTagArray = LocalAlloc(LMEM_ZEROINIT, MPSWabRecordHeader.ulPropTagArraySize);
  2104. if (!lpulPropTagArray)
  2105. {
  2106. DebugTrace(TEXT("Error allocating memory\n"));
  2107. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  2108. goto out;
  2109. }
  2110. //
  2111. // Read in the Prop tag array
  2112. //
  2113. if(!ReadFile( hMPSWabFile,
  2114. (LPVOID) lpulPropTagArray,
  2115. (DWORD) MPSWabRecordHeader.ulPropTagArraySize,
  2116. &dwNumofBytes,
  2117. NULL))
  2118. {
  2119. DebugTrace(TEXT("Reading Record PropTagArray failed.\n"));
  2120. goto out;
  2121. }
  2122. ulPreviousRecordOffset += dwNumofBytes;
  2123. //
  2124. // if AB_MATCH_PROP_ONLY is specified, then we limit our search to determining whether or
  2125. // not the property exists. if AB_MATCH_PROP_ONLY is not specified, we first look
  2126. // for the prop tag and then we look at the data behind the tag.
  2127. //
  2128. // if AB_MATCH_PROP is specified, we only search for existence or non-existence of the
  2129. // prop. All other Relational Operators are defunct.
  2130. // As long as we are not searching for multi-valued properties, we can have realtional operator
  2131. // based searching.
  2132. if ((ulFlags & AB_MATCH_PROP_ONLY) && (ulRelOp != RELOP_EQ) && (ulRelOp != RELOP_NE))
  2133. {
  2134. DebugTrace(TEXT("Unsupported relational operator for Property Matching\n"));
  2135. hr = MAPI_E_INVALID_PARAMETER;
  2136. goto out;
  2137. }
  2138. if ((PROP_TYPE(lpPropRes->ulPropTag) == PT_CLSID) && (ulRelOp != RELOP_EQ) && (ulRelOp != RELOP_NE))
  2139. {
  2140. DebugTrace(TEXT("Unsupported relational operator for finding GUIDs \n"));
  2141. hr = MAPI_E_INVALID_PARAMETER;
  2142. goto out;
  2143. }
  2144. bMatchFound = FALSE;
  2145. //
  2146. // scan the existing props for our tag
  2147. //
  2148. for (j=0;j<MPSWabRecordHeader.ulcPropCount;j++)
  2149. {
  2150. if (lpulPropTagArray[j]==lpPropRes->ulPropTag)
  2151. {
  2152. bMatchFound = TRUE;
  2153. break;
  2154. }
  2155. }
  2156. // At this point we know whether or not the record contains this property of interest
  2157. // Now we look at the flags and relational operators to see what to do.
  2158. if ((ulFlags & AB_MATCH_PROP_ONLY))
  2159. {
  2160. // We are interested only in the presence or absence of this property
  2161. if ( ( (ulRelOp == RELOP_EQ) && (bMatchFound) ) ||
  2162. ( (ulRelOp == RELOP_NE) && (!bMatchFound) ) )
  2163. {
  2164. //save this entry id in our master list
  2165. lpdwEID[ulcEIDCount++] = MPSWabRecordHeader.dwEntryID;
  2166. }
  2167. // goto next record
  2168. continue;
  2169. }
  2170. else
  2171. {
  2172. // want to compare the values ...
  2173. // if we are trying to compare value data and the property doesnt even exist in the record,
  2174. // bail out now ...
  2175. if (!bMatchFound)
  2176. {
  2177. //nothing of interest - go to next record
  2178. continue;
  2179. }
  2180. LocalFreeAndNull(&szBuf);
  2181. szBuf = LocalAlloc(LMEM_ZEROINIT,MPSWabRecordHeader.ulRecordDataSize);
  2182. if (!szBuf)
  2183. {
  2184. DebugTrace(TEXT("Error allocating memory\n"));
  2185. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  2186. goto out;
  2187. }
  2188. if(!ReadFile( hMPSWabFile,
  2189. (LPVOID) szBuf,
  2190. (DWORD) MPSWabRecordHeader.ulRecordDataSize,
  2191. &dwNumofBytes,
  2192. NULL))
  2193. {
  2194. DebugTrace(TEXT("Reading Record Data failed.\n"));
  2195. goto out;
  2196. }
  2197. ulPreviousRecordOffset += dwNumofBytes;
  2198. lp = szBuf;
  2199. //reset bMatchFound - used again later in this routine
  2200. bMatchFound = FALSE;
  2201. //go through all the property values
  2202. for(i=0;i< MPSWabRecordHeader.ulcPropCount;i++)
  2203. {
  2204. //Read Property Tag
  2205. CopyMemory(&TmpProp.ulPropTag,lp,sizeof(ULONG));
  2206. lp+=sizeof(ULONG) / sizeof(TCHAR);
  2207. //Check if it is MultiValued
  2208. if ((TmpProp.ulPropTag & MV_FLAG))
  2209. {
  2210. //Read cValues
  2211. CopyMemory(&ulcTmpValues,lp,sizeof(ULONG));
  2212. lp+=sizeof(ULONG) / sizeof(TCHAR);
  2213. }
  2214. //read DataSize
  2215. CopyMemory(&ulcTmpDataSize,lp,sizeof(ULONG));
  2216. lp+=sizeof(ULONG) / sizeof(TCHAR);
  2217. if (TmpProp.ulPropTag != lpPropRes->ulPropTag)
  2218. {
  2219. //skip this prop
  2220. lp += ulcTmpDataSize;
  2221. // go check next Prop Tag
  2222. continue;
  2223. }
  2224. if ((TmpProp.ulPropTag & MV_FLAG))
  2225. {
  2226. //skip this prop
  2227. lp += ulcTmpDataSize;
  2228. //go check next prop tag
  2229. continue;
  2230. }
  2231. // copy the requisite number of bytes into memory
  2232. switch(PROP_TYPE(TmpProp.ulPropTag))
  2233. {
  2234. case(PT_I2):
  2235. case(PT_LONG):
  2236. case(PT_APPTIME):
  2237. case(PT_SYSTIME):
  2238. case(PT_R4):
  2239. case(PT_BOOLEAN):
  2240. case(PT_CURRENCY):
  2241. case(PT_I8):
  2242. CopyMemory(&TmpProp.Value.i,lp,min(ulcTmpDataSize,sizeof(TmpProp.Value.i)));
  2243. break;
  2244. case(PT_CLSID):
  2245. case(PT_TSTRING):
  2246. TmpProp.Value.LPSZ = LocalAlloc(LMEM_ZEROINIT,ulcTmpDataSize);
  2247. if (!TmpProp.Value.LPSZ)
  2248. {
  2249. DebugTrace(TEXT("Error allocating memory\n"));
  2250. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  2251. goto out;
  2252. }
  2253. CopyMemory(TmpProp.Value.LPSZ,lp,ulcTmpDataSize);
  2254. break;
  2255. case(PT_BINARY):
  2256. TmpProp.Value.bin.lpb = LocalAlloc(LMEM_ZEROINIT,ulcTmpDataSize);
  2257. if (!TmpProp.Value.bin.lpb)
  2258. {
  2259. DebugTrace(TEXT("Error allocating memory\n"));
  2260. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  2261. goto out;
  2262. }
  2263. CopyMemory(TmpProp.Value.bin.lpb,lp,ulcTmpDataSize);
  2264. TmpProp.Value.bin.cb = ulcTmpDataSize;
  2265. break;
  2266. default:
  2267. // something I dont understand .. skip
  2268. lp += ulcTmpDataSize;
  2269. //go check next prop tag
  2270. continue;
  2271. break;
  2272. }
  2273. lp += ulcTmpDataSize;
  2274. // Do the comparison
  2275. switch(PROP_TYPE(TmpProp.ulPropTag))
  2276. {
  2277. case(PT_I2):
  2278. nComp = TmpProp.Value.i - lpPropRes->lpProp->Value.i;
  2279. break;
  2280. case(PT_LONG):
  2281. nComp = TmpProp.Value.l - lpPropRes->lpProp->Value.l;
  2282. break;
  2283. case(PT_R4):
  2284. if ((TmpProp.Value.flt - lpPropRes->lpProp->Value.flt) < 0)
  2285. {
  2286. nComp = -1;
  2287. }
  2288. else if ((TmpProp.Value.flt - lpPropRes->lpProp->Value.flt) == 0)
  2289. {
  2290. nComp = 0;
  2291. }
  2292. else
  2293. {
  2294. nComp = 1;
  2295. }
  2296. break;
  2297. case(PT_DOUBLE):
  2298. if ((TmpProp.Value.dbl - lpPropRes->lpProp->Value.dbl) < 0)
  2299. {
  2300. nComp = -1;
  2301. }
  2302. else if ((TmpProp.Value.dbl - lpPropRes->lpProp->Value.dbl) == 0)
  2303. {
  2304. nComp = 0;
  2305. }
  2306. else
  2307. {
  2308. nComp = 1;
  2309. }
  2310. break;
  2311. case(PT_BOOLEAN):
  2312. nComp = TmpProp.Value.b - lpPropRes->lpProp->Value.b;
  2313. break;
  2314. case(PT_CURRENCY):
  2315. // ???TBD: nComp = TmpProp.Value.cur - lpPropRes->lpProp->Value.cur;
  2316. if((TmpProp.Value.cur.Hi - lpPropRes->lpProp->Value.cur.Hi) < 0)
  2317. {
  2318. nComp = -1;
  2319. }
  2320. else if((TmpProp.Value.cur.Hi - lpPropRes->lpProp->Value.cur.Hi) > 0)
  2321. {
  2322. nComp = +1;
  2323. }
  2324. else
  2325. {
  2326. if(TmpProp.Value.cur.Lo < lpPropRes->lpProp->Value.cur.Lo)
  2327. {
  2328. nComp = -1;
  2329. }
  2330. else if((TmpProp.Value.cur.Lo - lpPropRes->lpProp->Value.cur.Lo) > 0)
  2331. {
  2332. nComp = +1;
  2333. }
  2334. else
  2335. {
  2336. nComp = 0;
  2337. }
  2338. }
  2339. break;
  2340. case(PT_APPTIME):
  2341. if ((TmpProp.Value.at - lpPropRes->lpProp->Value.at) < 0)
  2342. {
  2343. nComp = -1;
  2344. }
  2345. else if ((TmpProp.Value.at - lpPropRes->lpProp->Value.at) == 0)
  2346. {
  2347. nComp = 0;
  2348. }
  2349. else
  2350. {
  2351. nComp = 1;
  2352. }
  2353. break;
  2354. case(PT_SYSTIME):
  2355. nComp = CompareFileTime(&(TmpProp.Value.ft), (FILETIME *) (&(lpPropRes->lpProp->Value.ft)));
  2356. break;
  2357. case(PT_TSTRING):
  2358. nComp = lstrcmpi(TmpProp.Value.LPSZ,lpPropRes->lpProp->Value.LPSZ);
  2359. break;
  2360. case(PT_BINARY):
  2361. min = (TmpProp.Value.bin.cb < lpPropRes->lpProp->Value.bin.cb) ? TmpProp.Value.bin.cb : lpPropRes->lpProp->Value.bin.cb;
  2362. k=0;
  2363. nComp=0;
  2364. while((k<min) && ((int)TmpProp.Value.bin.lpb[k] == (int)lpPropRes->lpProp->Value.bin.lpb[k]))
  2365. k++; //find first difference
  2366. if (k!=min)
  2367. nComp = (int) TmpProp.Value.bin.lpb[k] - (int) lpPropRes->lpProp->Value.bin.lpb[k];
  2368. break;
  2369. case(PT_CLSID):
  2370. nComp = IsEqualGUID(TmpProp.Value.lpguid,lpPropRes->lpProp->Value.lpguid);
  2371. break;
  2372. case(PT_I8):
  2373. // ??? TBD how to do this one ??
  2374. if((TmpProp.Value.li.HighPart - lpPropRes->lpProp->Value.li.HighPart) < 0)
  2375. {
  2376. nComp = -1;
  2377. }
  2378. else if((TmpProp.Value.li.HighPart - lpPropRes->lpProp->Value.li.HighPart) > 0)
  2379. {
  2380. nComp = +1;
  2381. }
  2382. else
  2383. {
  2384. if(TmpProp.Value.li.LowPart < lpPropRes->lpProp->Value.li.LowPart)
  2385. {
  2386. nComp = -1;
  2387. }
  2388. else if((TmpProp.Value.li.LowPart - lpPropRes->lpProp->Value.li.LowPart) > 0)
  2389. {
  2390. nComp = +1;
  2391. }
  2392. else
  2393. {
  2394. nComp = 0;
  2395. }
  2396. }
  2397. break;
  2398. default:
  2399. break;
  2400. }
  2401. // If we get what we are looking for then there is no need to look at the
  2402. // rest of the record. In that case we go to the next record.
  2403. //
  2404. switch(ulRelOp)
  2405. {
  2406. case(RELOP_EQ):
  2407. if (nComp == 0)
  2408. {
  2409. // We got atleast one match, so we can store this entryID and
  2410. // skip to next record
  2411. lpdwEID[ulcEIDCount++] = MPSWabRecordHeader.dwEntryID;
  2412. bMatchFound = TRUE;
  2413. }
  2414. break;
  2415. case(RELOP_NE):
  2416. // We can only declare success for the != operator if and only if all values
  2417. // of this property in the record do not meet the given value.
  2418. // This means that we have to scan the whole record before we can declare success.
  2419. // Thus, instead of marking the flag on success, we actually mark it on
  2420. // failure. At the end of the 'for' loop, if there was even 1 failure in the
  2421. // test, we can mark the record as having failed our test.
  2422. if (nComp == 0)
  2423. {
  2424. bMatchFound = TRUE;
  2425. }
  2426. break;
  2427. case(RELOP_GT):
  2428. if (nComp > 0)
  2429. {
  2430. // We got atleast one match, so we can store this entryID and
  2431. // skip to next record
  2432. lpdwEID[ulcEIDCount++] = MPSWabRecordHeader.dwEntryID;
  2433. bMatchFound = TRUE;
  2434. }
  2435. break;
  2436. case(RELOP_GE):
  2437. if (nComp >= 0)
  2438. {
  2439. // We got atleast one match, so we can store this entryID and
  2440. // skip to next record
  2441. lpdwEID[ulcEIDCount++] = MPSWabRecordHeader.dwEntryID;
  2442. bMatchFound = TRUE;
  2443. }
  2444. break;
  2445. case(RELOP_LT):
  2446. if (nComp < 0)
  2447. {
  2448. // We got atleast one match, so we can store this entryID and
  2449. // skip to next record
  2450. lpdwEID[ulcEIDCount++] = MPSWabRecordHeader.dwEntryID;
  2451. bMatchFound = TRUE;
  2452. }
  2453. break;
  2454. case(RELOP_LE):
  2455. if (nComp <= 0)
  2456. {
  2457. // We got atleast one match, so we can store this entryID and
  2458. // skip to next record
  2459. lpdwEID[ulcEIDCount++] = MPSWabRecordHeader.dwEntryID;
  2460. bMatchFound = TRUE;
  2461. }
  2462. break;
  2463. default:
  2464. break;
  2465. }
  2466. switch(PROP_TYPE(TmpProp.ulPropTag))
  2467. {
  2468. case(PT_CLSID):
  2469. case(PT_TSTRING):
  2470. LocalFreeAndNull((LPVOID *) (&TmpProp.Value.LPSZ));
  2471. break;
  2472. case(PT_BINARY):
  2473. LocalFreeAndNull((LPVOID *) (&TmpProp.Value.bin.lpb));
  2474. break;
  2475. }
  2476. // if we got a match above, we dont look in this record anymore
  2477. if (bMatchFound)
  2478. break;
  2479. } //(for i= ...
  2480. if ((ulRelOp == RELOP_NE) && (bMatchFound == FALSE))
  2481. {
  2482. //We exited the for loop legitimately and still didnt find a match
  2483. //so we can finally declare a success for this one relop
  2484. lpdwEID[ulcEIDCount++] = MPSWabRecordHeader.dwEntryID;
  2485. }
  2486. } //else
  2487. if ((ulcEIDCount == ulMaxCount) && (ulMaxCount != 0))
  2488. {
  2489. // got enough records to return
  2490. // break out of do loop
  2491. break;
  2492. }
  2493. LocalFreeAndNull(&szBuf);
  2494. LocalFreeAndNull(&lpulPropTagArray);
  2495. }//for loop
  2496. filterFolderMembers:
  2497. #define WAB_IGNORE_ENTRY 0xFFFFFFFF
  2498. // if a folder was specified, only return the entries that are part of this folder
  2499. // pmbinFold will be NULL when there is no Outlook and no profiles
  2500. // otherwise it will have something in it
  2501. // If pmbinFold->cb and ->lpb are empty, then this is the virtual PAB folder and
  2502. // we want to return EVERYTHING in it
  2503. if(pmbinFold)// && pmbinFold->cb && pmbinFold->lpb)
  2504. {
  2505. // if it is the virtual root folder, only accept entries that dont have
  2506. // PR_WAB_FOLDER_PARENT set on it
  2507. // if it is not the root virtual folder, only return this entry if it is
  2508. // a member of the folder
  2509. /***/ if(!pmbinFold->cb && !pmbinFold->lpb)
  2510. {
  2511. // only accept entries that dont have PR_WAB_FOLDER_PARENT
  2512. for(i=0;i<ulcEIDCount;i++)
  2513. {
  2514. ULONG ulObjType = 0;
  2515. if(bIsFolderMember(hMPSWabFile, lpMPSWabFileInfo, lpdwEID[i], &ulObjType))
  2516. lpdwEID[i] = WAB_IGNORE_ENTRY;
  2517. //if(ulObjType == RECORD_CONTAINER)
  2518. // lpdwEID[i] = WAB_IGNORE_ENTRY;
  2519. }
  2520. }
  2521. else if(pmbinFold->cb && pmbinFold->lpb)
  2522. /****/ {
  2523. LPDWORD lpdwFolderEIDs = NULL;
  2524. ULONG ulFolderEIDs = 0;
  2525. if(!HR_FAILED(GetFolderEIDs( hMPSWabFile, lpMPSWabFileInfo,
  2526. pmbinFold, &ulFolderEIDs, &lpdwFolderEIDs)))
  2527. {
  2528. if(ulFolderEIDs && lpdwFolderEIDs)
  2529. {
  2530. for(i=0;i<ulcEIDCount;i++)
  2531. {
  2532. BOOL bFound = FALSE;
  2533. for(j=0;j<ulFolderEIDs;j++)
  2534. {
  2535. if(lpdwEID[i] == lpdwFolderEIDs[j])
  2536. {
  2537. bFound = TRUE;
  2538. break;
  2539. }
  2540. }
  2541. if(!bFound)
  2542. lpdwEID[i] = WAB_IGNORE_ENTRY;
  2543. }
  2544. }
  2545. else
  2546. {
  2547. // empty folder so dont return anything
  2548. ulcEIDCount = 0;
  2549. if(lpdwEID)
  2550. {
  2551. LocalFree(lpdwEID);
  2552. lpdwEID = NULL;
  2553. }
  2554. }
  2555. }
  2556. if(lpdwFolderEIDs)
  2557. LocalFree(lpdwFolderEIDs);
  2558. }
  2559. }
  2560. *lpulcEIDCount = 0;
  2561. if(lpdwEID && ulcEIDCount)
  2562. {
  2563. //So now if we got here, we can return the array
  2564. lpdwEntryIDs = LocalAlloc(LMEM_ZEROINIT, ulcEIDCount * SIZEOF_WAB_ENTRYID);
  2565. if (!lpdwEntryIDs)
  2566. {
  2567. DebugTrace(TEXT("Error allocating memory\n"));
  2568. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  2569. goto out;
  2570. }
  2571. for(i=0;i<ulcEIDCount;i++)
  2572. {
  2573. if(lpdwEID[i]!=WAB_IGNORE_ENTRY)
  2574. {
  2575. lpdwEntryIDs[*lpulcEIDCount]=lpdwEID[i];
  2576. (*lpulcEIDCount)++;
  2577. }
  2578. }
  2579. }
  2580. hr = S_OK;
  2581. out:
  2582. if(!HR_FAILED(hr) &&
  2583. lpdwEntryIDs &&
  2584. *lpulcEIDCount)
  2585. {
  2586. // Convert to the array of SBinarys we will return
  2587. (*lprgsbEntryIDs) = LocalAlloc(LMEM_ZEROINIT, sizeof(SBinary) * (*lpulcEIDCount));
  2588. if(*lprgsbEntryIDs)
  2589. {
  2590. for(i=0;i<*lpulcEIDCount;i++)
  2591. {
  2592. (*lprgsbEntryIDs)[i].lpb = LocalAlloc(LMEM_ZEROINIT, SIZEOF_WAB_ENTRYID);
  2593. if((*lprgsbEntryIDs)[i].lpb)
  2594. {
  2595. (*lprgsbEntryIDs)[i].cb = SIZEOF_WAB_ENTRYID;
  2596. CopyMemory((*lprgsbEntryIDs)[i].lpb, &(lpdwEntryIDs[i]), SIZEOF_WAB_ENTRYID);
  2597. }
  2598. }
  2599. }
  2600. else
  2601. *lpulcEIDCount = 0; // out of memory
  2602. }
  2603. if(lpdwEntryIDs)
  2604. LocalFree(lpdwEntryIDs);
  2605. LocalFreeAndNull(&szBuf);
  2606. LocalFreeAndNull(&lpulPropTagArray);
  2607. LocalFreeAndNull(&lpdwEID);
  2608. if(bErrorDetected)
  2609. TagWABFileError(lpMPSWabFileInfo->lpMPSWabFileHeader, hMPSWabFile);
  2610. if (hMPSWabFile)
  2611. IF_WIN32(CloseHandle(hMPSWabFile);) IF_WIN16(CloseFile(hMPSWabFile);)
  2612. if(bLockFile)
  2613. {
  2614. if (bFileLocked)
  2615. UnLockFileAccess(lpMPSWabFileInfo);
  2616. }
  2617. return(hr);
  2618. }
  2619. //$$//////////////////////////////////////////////////////////////////////////////////
  2620. //
  2621. // DeleteRecord
  2622. //
  2623. // IN hPropertyStore - handle to property store
  2624. // IN dwEntryID - EntryID of record to delete
  2625. //
  2626. // Basically, we invalidate the existing record specified by the EntryID
  2627. // and we also reduce the total count, update the modification count,
  2628. // and remove the corresponding indexes from all the 4 indexes
  2629. //
  2630. // Returns
  2631. // Success: S_OK
  2632. // Failure: E_FAIL
  2633. //
  2634. ////////////////////////////////////////////////////////////////////////////////////
  2635. HRESULT DeleteRecord( IN HANDLE hPropertyStore,
  2636. IN LPSBinary lpsbEID)
  2637. {
  2638. HRESULT hr = E_FAIL;
  2639. ULONG nIndexPos = 0, j = 0, i = 0;
  2640. HANDLE hMPSWabFile = NULL;
  2641. DWORD dwNumofBytes = 0;
  2642. ULONG index = 0;
  2643. BOOL bFileLocked = FALSE;
  2644. BOOL bEntryAlreadyDeleted = FALSE;
  2645. DWORD dwEntryID = 0;
  2646. MPSWab_RECORD_HEADER MPSWabRecordHeader;
  2647. LPMPSWab_FILE_INFO lpMPSWabFileInfo;
  2648. SBinary sbEID = {0};
  2649. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  2650. if(pt_bIsWABOpenExSession)
  2651. {
  2652. // This is a WABOpenEx session using outlooks storage provider
  2653. if(!hPropertyStore)
  2654. return MAPI_E_NOT_INITIALIZED;
  2655. {
  2656. LPWABSTORAGEPROVIDER lpWSP = (LPWABSTORAGEPROVIDER) hPropertyStore;
  2657. hr = lpWSP->lpVtbl->DeleteRecord(lpWSP,
  2658. lpsbEID);
  2659. DebugTrace(TEXT("WABStorageProvider::DeleteRecord returned:%x\n"),hr);
  2660. return hr;
  2661. }
  2662. }
  2663. lpMPSWabFileInfo = hPropertyStore;
  2664. if(lpsbEID && lpsbEID->cb != SIZEOF_WAB_ENTRYID)
  2665. {
  2666. // this may be a WAB container .. reset the entryid to a WAB entryid
  2667. if(WAB_CONTAINER == IsWABEntryID(lpsbEID->cb, (LPENTRYID)lpsbEID->lpb,
  2668. NULL,NULL,NULL,NULL,NULL))
  2669. {
  2670. IsWABEntryID(lpsbEID->cb, (LPENTRYID)lpsbEID->lpb,
  2671. (LPVOID*)&sbEID.lpb,(LPVOID*)&sbEID.cb,NULL,NULL,NULL);
  2672. if(sbEID.cb == SIZEOF_WAB_ENTRYID)
  2673. lpsbEID = &sbEID;
  2674. }
  2675. }
  2676. if(!lpsbEID || lpsbEID->cb != SIZEOF_WAB_ENTRYID)
  2677. {
  2678. hr = MAPI_E_INVALID_PARAMETER;
  2679. goto out;
  2680. }
  2681. CopyMemory(&dwEntryID, lpsbEID->lpb, min(lpsbEID->cb, sizeof(dwEntryID)));
  2682. DebugTrace(TEXT("----Thread:%x\tDeleteRecord: Entry\n----EntryID:%d\n"),GetCurrentThreadId(),dwEntryID);
  2683. //
  2684. // If we had started this whole session requesting read-only access
  2685. // make sure we dont mistakenly try to violate it ...
  2686. //
  2687. if (lpMPSWabFileInfo->bReadOnlyAccess)
  2688. {
  2689. DebugTrace(TEXT("Access Permissions are Read-Only"));
  2690. hr = MAPI_E_NO_ACCESS;
  2691. goto out;
  2692. }
  2693. if(!LockFileAccess(lpMPSWabFileInfo))
  2694. {
  2695. DebugTrace(TEXT("LockFileAccess Failed\n"));
  2696. hr = MAPI_E_NO_ACCESS;
  2697. goto out;
  2698. }
  2699. else
  2700. {
  2701. bFileLocked = TRUE;
  2702. }
  2703. //Open the file
  2704. hr = OpenWABFile(lpMPSWabFileInfo->lpszMPSWabFileName, NULL, &hMPSWabFile);
  2705. if ( (hMPSWabFile == INVALID_HANDLE_VALUE) ||
  2706. HR_FAILED(hr))
  2707. {
  2708. DebugTrace(TEXT("Could not open file.\nExiting ...\n"));
  2709. goto out;
  2710. }
  2711. //
  2712. // To ensure that file info is accurate,
  2713. // Any time we open a file, read the file info again ...
  2714. //
  2715. if(!ReloadMPSWabFileInfo(
  2716. lpMPSWabFileInfo,
  2717. hMPSWabFile))
  2718. {
  2719. DebugTrace(TEXT("Reading file info failed.\n"));
  2720. goto out;
  2721. }
  2722. //
  2723. // Anytime we detect an error - try to fix it ...
  2724. //
  2725. if((lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags & WAB_ERROR_DETECTED) ||
  2726. (lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags & WAB_WRITE_IN_PROGRESS))
  2727. {
  2728. if(HR_FAILED(HrDoQuickWABIntegrityCheck(lpMPSWabFileInfo,hMPSWabFile)))
  2729. {
  2730. hr = HrDoDetailedWABIntegrityCheck(lpMPSWabFileInfo,hMPSWabFile);
  2731. if(HR_FAILED(hr))
  2732. {
  2733. DebugTrace(TEXT("HrDoDetailedWABIntegrityCheck failed:%x\n"),hr);
  2734. goto out;
  2735. }
  2736. }
  2737. }
  2738. // Tag this file as undergoing a write operation
  2739. if(!bTagWriteTransaction( lpMPSWabFileInfo->lpMPSWabFileHeader,
  2740. hMPSWabFile) )
  2741. {
  2742. DebugTrace(TEXT("Taggin file write failed\n"));
  2743. goto out;
  2744. }
  2745. //
  2746. // First check if this is a valid entryID
  2747. //
  2748. if (!BinSearchEID( IN lpMPSWabFileInfo->lpMPSWabIndexEID,
  2749. IN dwEntryID,
  2750. IN lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries,
  2751. OUT &nIndexPos))
  2752. {
  2753. DebugTrace(TEXT("Specified EntryID: %d doesnt exist!"),dwEntryID);
  2754. hr = MAPI_E_INVALID_ENTRYID;
  2755. goto out;
  2756. }
  2757. //
  2758. // Yes it's valid. Go to this record and invalidate the record.
  2759. //
  2760. if(!ReadDataFromWABFile(hMPSWabFile,
  2761. lpMPSWabFileInfo->lpMPSWabIndexEID[nIndexPos].ulOffset,
  2762. (LPVOID) &MPSWabRecordHeader,
  2763. (DWORD) sizeof(MPSWab_RECORD_HEADER)))
  2764. goto out;
  2765. if ((MPSWabRecordHeader.bValidRecord == FALSE) && (MPSWabRecordHeader.bValidRecord != TRUE))
  2766. {
  2767. //
  2768. // this should never happen but who knows
  2769. //
  2770. DebugTrace(TEXT("Specified entry has already been invalidated ...\n"));
  2771. // hr = S_OK;
  2772. // goto out;
  2773. // if we hit an invalid entryid through the index, then we need to remove that link from the index
  2774. // so we'll go ahead and pretend that its all fine and continue like nothing happened.
  2775. // This will ensure that the entryid reference is also removed ...
  2776. bEntryAlreadyDeleted = TRUE;
  2777. }
  2778. //
  2779. // Set valid flag to false
  2780. //
  2781. MPSWabRecordHeader.bValidRecord = FALSE;
  2782. //
  2783. // Write it back
  2784. // Set File Pointer to this record
  2785. //
  2786. if(!WriteDataToWABFile( hMPSWabFile,
  2787. lpMPSWabFileInfo->lpMPSWabIndexEID[nIndexPos].ulOffset,
  2788. (LPVOID) &MPSWabRecordHeader,
  2789. sizeof(MPSWab_RECORD_HEADER)))
  2790. goto out;
  2791. //
  2792. // Now we need to remove this entry from the EntryID index and also remove this
  2793. // entry from the other indexes
  2794. //
  2795. // Set File Pointer to the Pt. in the EntryID index on file
  2796. // at which this record appears
  2797. //
  2798. if (0xFFFFFFFF == SetFilePointer ( hMPSWabFile,
  2799. lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulOffset + (nIndexPos)*sizeof(MPSWab_INDEX_ENTRY_DATA_ENTRYID),
  2800. NULL,
  2801. FILE_BEGIN))
  2802. {
  2803. DebugTrace(TEXT("SetFilePointer Failed\n"));
  2804. goto out;
  2805. }
  2806. // Write the remainder of the array back to disk to overwrite this entry
  2807. if (lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries > (nIndexPos+1))
  2808. {
  2809. if(!WriteFile( hMPSWabFile,
  2810. (LPVOID) &lpMPSWabFileInfo->lpMPSWabIndexEID[nIndexPos+1],
  2811. (DWORD) sizeof(MPSWab_INDEX_ENTRY_DATA_ENTRYID)*(lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries - nIndexPos - 1),
  2812. &dwNumofBytes,
  2813. NULL))
  2814. {
  2815. DebugTrace(TEXT("Writing Index failed.\n"));
  2816. goto out;
  2817. }
  2818. }
  2819. if(lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries>0)
  2820. lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries--;
  2821. if(lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].UtilizedBlockSize>0)
  2822. lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].UtilizedBlockSize -= sizeof(MPSWab_INDEX_ENTRY_DATA_ENTRYID);
  2823. // DebugTrace(TEXT("Thread:%x\tIndex: %d\tulNumEntries: %d\n"),GetCurrentThreadId(),indexEntryID,lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries);
  2824. //
  2825. // Similarly scan the str index arrays
  2826. //
  2827. for (index = indexDisplayName; index < indexMax; index++)
  2828. {
  2829. if (!LoadIndex( IN lpMPSWabFileInfo,
  2830. IN index,
  2831. IN hMPSWabFile) )
  2832. {
  2833. DebugTrace(TEXT("Error Loading Index!"));
  2834. goto out;
  2835. }
  2836. nIndexPos = 0xFFFFFFFF;
  2837. for(j=0;j<lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[index].ulcNumEntries;j++)
  2838. {
  2839. if (lpMPSWabFileInfo->lpMPSWabIndexStr[j].dwEntryID == dwEntryID)
  2840. {
  2841. nIndexPos = j;
  2842. break;
  2843. }
  2844. }
  2845. // if the entry doesnt exist .. no problem
  2846. // if it does - delete it ...
  2847. if (index == indexDisplayName)
  2848. Assert(nIndexPos != 0xFFFFFFFF);
  2849. if (nIndexPos != 0xFFFFFFFF)
  2850. {
  2851. if (0xFFFFFFFF == SetFilePointer ( hMPSWabFile,
  2852. lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[index].ulOffset + (nIndexPos)*sizeof(MPSWab_INDEX_ENTRY_DATA_STRING),
  2853. NULL,
  2854. FILE_BEGIN))
  2855. {
  2856. DebugTrace(TEXT("SetFilePointer Failed\n"));
  2857. goto out;
  2858. }
  2859. // Write the remainder of the array back to disk to overwrite this entry
  2860. if (lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[index].ulcNumEntries > (nIndexPos+1))
  2861. {
  2862. if(!WriteFile( hMPSWabFile,
  2863. (LPVOID) &lpMPSWabFileInfo->lpMPSWabIndexStr[nIndexPos+1],
  2864. (DWORD) sizeof(MPSWab_INDEX_ENTRY_DATA_STRING)*(lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[index].ulcNumEntries - nIndexPos - 1),
  2865. &dwNumofBytes,
  2866. NULL))
  2867. {
  2868. DebugTrace(TEXT("Writing Index failed.\n"));
  2869. goto out;
  2870. }
  2871. }
  2872. if(lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[index].ulcNumEntries>0)
  2873. lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[index].ulcNumEntries--;
  2874. if(lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[index].UtilizedBlockSize>0)
  2875. lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[index].UtilizedBlockSize -= sizeof(MPSWab_INDEX_ENTRY_DATA_STRING);
  2876. //DebugTrace(TEXT("Thread:%x\tIndex: %d\tulNumEntries: %d\n"),GetCurrentThreadId(),index,lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[index].ulcNumEntries);
  2877. }
  2878. }
  2879. // Save the fileheader back to the file
  2880. if(!bEntryAlreadyDeleted)
  2881. {
  2882. if(lpMPSWabFileInfo->lpMPSWabFileHeader->ulcNumEntries>0)
  2883. lpMPSWabFileInfo->lpMPSWabFileHeader->ulcNumEntries--;
  2884. lpMPSWabFileInfo->lpMPSWabFileHeader->ulModificationCount++;
  2885. lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags |= WAB_BACKUP_NOW;
  2886. }
  2887. if (0xFFFFFFFF == SetFilePointer ( hMPSWabFile,
  2888. 0,
  2889. NULL,
  2890. FILE_BEGIN))
  2891. {
  2892. DebugTrace(TEXT("SetFilePointer Failed\n"));
  2893. goto out;
  2894. }
  2895. if(lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries != lpMPSWabFileInfo->lpMPSWabFileHeader->ulcNumEntries)
  2896. lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags |= WAB_ERROR_DETECTED;
  2897. for(i=indexDisplayName;i<indexMax;i++)
  2898. {
  2899. if(lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[i].ulcNumEntries > lpMPSWabFileInfo->lpMPSWabFileHeader->ulcNumEntries)
  2900. lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags |= WAB_ERROR_DETECTED;
  2901. }
  2902. if(!WriteFile( hMPSWabFile,
  2903. (LPVOID) lpMPSWabFileInfo->lpMPSWabFileHeader,
  2904. (DWORD) sizeof(MPSWab_FILE_HEADER),
  2905. &dwNumofBytes,
  2906. NULL))
  2907. {
  2908. DebugTrace(TEXT("Writing FileHeader Failed failed.\n"));
  2909. goto out;
  2910. }
  2911. if ( (lpMPSWabFileInfo->lpMPSWabFileHeader->ulModificationCount > MAX_ALLOWABLE_WASTED_SPACE_ENTRIES) ) // ||
  2912. {
  2913. // above condition means that if more than space for 50 entries is wasted
  2914. // of if number of modifications are more than the number of entries
  2915. // we should clean up the file
  2916. if (!CompressFile( lpMPSWabFileInfo,
  2917. hMPSWabFile,
  2918. NULL,
  2919. FALSE,
  2920. 0))
  2921. {
  2922. DebugTrace(TEXT("Thread:%x\tCompress file failed\n"),GetCurrentThreadId());
  2923. hr = E_FAIL;
  2924. goto out;
  2925. }
  2926. }
  2927. hr = S_OK;
  2928. out:
  2929. // UnTag this file as undergoing a write operation
  2930. // We only want the flag to stay there during crashes not during
  2931. // normal operations
  2932. //
  2933. if(lpMPSWabFileInfo)
  2934. {
  2935. if(!bUntagWriteTransaction( lpMPSWabFileInfo->lpMPSWabFileHeader,
  2936. hMPSWabFile) )
  2937. {
  2938. DebugTrace(TEXT("Untaggin file write failed\n"));
  2939. }
  2940. }
  2941. if (hMPSWabFile)
  2942. IF_WIN32(CloseHandle(hMPSWabFile);) IF_WIN16(CloseFile(hMPSWabFile);)
  2943. if (bFileLocked)
  2944. UnLockFileAccess(lpMPSWabFileInfo);
  2945. //DebugTrace(TEXT("----Thread:%x\tDeleteRecords: Exit\n"),GetCurrentThreadId());
  2946. return(hr);
  2947. }
  2948. /*
  2949. -
  2950. - ReadRecordFreePropArray
  2951. *
  2952. * Memory from ReadRecord can be obtained through a convoluted plethora of different
  2953. * allocation types .. we therefore need to free it much more safely than other memory types
  2954. *
  2955. */
  2956. void ReadRecordFreePropArray(HANDLE hPropertyStore, ULONG ulcPropCount, LPSPropValue * lppPropArray)
  2957. {
  2958. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  2959. if( pt_bIsWABOpenExSession && //outlook session
  2960. !pt_bIsUnicodeOutlook && //outlook doesn't support Unicode
  2961. !lpfnAllocateMoreExternal ) //don't have an outlook allocator
  2962. {
  2963. // this is special case MAPI Allocated memory
  2964. FreeBufferAndNull(lppPropArray);
  2965. }
  2966. else
  2967. LocalFreePropArray(hPropertyStore, ulcPropCount, lppPropArray);
  2968. }
  2969. /*
  2970. -
  2971. - HrDupeOlkPropsAtoWC
  2972. *
  2973. * Outlook properties are unmungable without having the outlook allocators
  2974. * In an independent WAB session, the Outlook allocators are not available, hence
  2975. * we have to recreate the property arrays with the WAB allocators so we can modify
  2976. * them and turn them from Outlooks non-unicode to the WAB's needed unicode format.
  2977. */
  2978. HRESULT HrDupeOlkPropsAtoWC(ULONG ulCount, LPSPropValue lpPropArray, LPSPropValue * lppSPVNew)
  2979. {
  2980. HRESULT hr = S_OK;
  2981. SCODE sc = 0;
  2982. LPSPropValue lpSPVNew = NULL;
  2983. ULONG cb = 0;
  2984. if (FAILED(sc = ScCountProps(ulCount, lpPropArray, &cb)))
  2985. {
  2986. hr = ResultFromScode(sc);
  2987. goto exit;
  2988. }
  2989. if (FAILED(sc = MAPIAllocateBuffer(cb, &lpSPVNew)))
  2990. {
  2991. hr = ResultFromScode(sc);
  2992. goto exit;
  2993. }
  2994. if (FAILED(sc = ScCopyProps(ulCount, lpPropArray, lpSPVNew, NULL)))
  2995. {
  2996. hr = ResultFromScode(sc);
  2997. goto exit;
  2998. }
  2999. // [PaulHi] Raid 73237 @hack
  3000. // Outlook marks the contact as mail or DL (group) through the PR_DISPLAY_TYPE
  3001. // property tag. However, the WAB relies on the PR_OBJECT_TYPE tag to determine
  3002. // how the contact appears in the listview. If there is no PR_OBJECT_TYPE tag
  3003. // but there is a PR_DISPLAY_TYPE tag then convert it to PR_OBJECT_TYPE.
  3004. {
  3005. ULONG ul;
  3006. ULONG ulDpType = (ULONG)(-1);
  3007. BOOL bConvert = TRUE;
  3008. for (ul=0; ul<ulCount; ul++)
  3009. {
  3010. if (lpSPVNew[ul].ulPropTag == PR_OBJECT_TYPE)
  3011. {
  3012. bConvert = FALSE;
  3013. break;
  3014. }
  3015. else if (lpSPVNew[ul].ulPropTag == PR_DISPLAY_TYPE)
  3016. ulDpType = ul;
  3017. }
  3018. if ( bConvert && (ulDpType != (ULONG)(-1)) )
  3019. {
  3020. // Convert PR_DISPLAY_TYPE to PR_OBJECT_TYPE
  3021. lpSPVNew[ulDpType].ulPropTag = PR_OBJECT_TYPE;
  3022. if ( (lpSPVNew[ulDpType].Value.ul == DT_PRIVATE_DISTLIST) ||
  3023. (lpSPVNew[ulDpType].Value.ul == DT_DISTLIST) )
  3024. {
  3025. lpSPVNew[ulDpType].Value.ul = MAPI_DISTLIST;
  3026. }
  3027. else
  3028. {
  3029. lpSPVNew[ulDpType].Value.ul = MAPI_MAILUSER;
  3030. }
  3031. }
  3032. }
  3033. if(FAILED(sc = ScConvertAPropsToW((LPALLOCATEMORE)(&MAPIAllocateMore), lpSPVNew, ulCount, 0)))
  3034. {
  3035. hr = ResultFromScode(sc);
  3036. goto exit;
  3037. }
  3038. *lppSPVNew = lpSPVNew;
  3039. exit:
  3040. if(HR_FAILED(hr))
  3041. {
  3042. FreeBufferAndNull(&lpSPVNew);
  3043. *lppSPVNew = NULL;
  3044. }
  3045. return hr;
  3046. }
  3047. //$$//////////////////////////////////////////////////////////////////////////////////
  3048. //
  3049. // ReadRecord
  3050. //
  3051. // IN hPropertyStore - handle to property store
  3052. // IN dwEntryID - EntryID of record to read
  3053. // IN ulFlags
  3054. // OUT ulcPropCount - number of props returned
  3055. // OUT lpPropArray - Array of Property values
  3056. //
  3057. // Basically, we find the record offset, read in the record, copy the data
  3058. // into SPropValue arrays and return the arrays
  3059. //
  3060. // IMPORTANT NOTE: To free memory allocated from here call ReadRecordFreePropArray
  3061. // Returns
  3062. // Success: S_OK
  3063. // Failure: E_FAIL
  3064. //
  3065. ////////////////////////////////////////////////////////////////////////////////////
  3066. HRESULT ReadRecord( IN HANDLE hPropertyStore,
  3067. IN LPSBinary lpsbEntryID,
  3068. IN ULONG ulFlags,
  3069. OUT LPULONG lpulcPropCount,
  3070. OUT LPPROPERTY_ARRAY * lppPropArray)
  3071. {
  3072. HRESULT hr = E_FAIL;
  3073. HANDLE hMPSWabFile = NULL;
  3074. BOOL bFileLocked = FALSE;
  3075. DWORD dwEntryID = 0;
  3076. MPSWab_RECORD_HEADER MPSWabRecordHeader = {0};
  3077. LPMPSWab_FILE_INFO lpMPSWabFileInfo = hPropertyStore;
  3078. SBinary sbEID = {0};
  3079. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  3080. if(pt_bIsWABOpenExSession && !(ulFlags & AB_IGNORE_OUTLOOK))
  3081. {
  3082. // This is a WABOpenEx session using outlooks storage provider
  3083. if(!hPropertyStore)
  3084. return MAPI_E_NOT_INITIALIZED;
  3085. {
  3086. LPWABSTORAGEPROVIDER lpWSP = (LPWABSTORAGEPROVIDER) hPropertyStore;
  3087. hr = lpWSP->lpVtbl->ReadRecord( lpWSP,
  3088. lpsbEntryID,
  3089. ulFlags,
  3090. lpulcPropCount,
  3091. lppPropArray);
  3092. DebugTrace(TEXT("WABStorageProvider::ReadRecord returned:%x\n"),hr);
  3093. if(!HR_FAILED(hr) && *lpulcPropCount && *lppPropArray && !pt_bIsUnicodeOutlook)
  3094. {
  3095. // Map all the contacts props to Unicode if needed since Outlook9 and older don't
  3096. // support unicode
  3097. SCODE sc = 0;
  3098. if(lpfnAllocateMoreExternal)
  3099. {
  3100. // the memory that comes from outlook is allocated using outlooks allocators
  3101. // and we can't mess with it .. unless we have the allocators passed in through
  3102. // wabopenex
  3103. if(sc = ScConvertAPropsToW(lpfnAllocateMoreExternal, *lppPropArray, *lpulcPropCount, 0))
  3104. hr = ResultFromScode(sc);
  3105. }
  3106. else
  3107. {
  3108. // we don't have external allocators, which means we need to muck with reallocating memory etc
  3109. // therefore we'll need to duplicate the prop array and then convert it
  3110. //
  3111. // Because of this mess, we need to have a special way of releasing this memory so
  3112. // we don't leak all over the place
  3113. ULONG ulCount = *lpulcPropCount;
  3114. LPSPropValue lpSPVNew = NULL;
  3115. if(HR_FAILED(hr = HrDupeOlkPropsAtoWC(ulCount, *lppPropArray, &lpSPVNew)))
  3116. goto exit;
  3117. // Free the old props
  3118. LocalFreePropArray(hPropertyStore, *lpulcPropCount, lppPropArray);
  3119. *lppPropArray = lpSPVNew;
  3120. *lpulcPropCount = ulCount;
  3121. }
  3122. }
  3123. exit:
  3124. return hr;
  3125. }
  3126. }
  3127. if(lpsbEntryID && lpsbEntryID->cb != SIZEOF_WAB_ENTRYID)
  3128. {
  3129. // this may be a WAB container .. reset the entryid to a WAB entryid
  3130. if(WAB_CONTAINER == IsWABEntryID(lpsbEntryID->cb, (LPENTRYID)lpsbEntryID->lpb,
  3131. NULL,NULL,NULL,NULL,NULL))
  3132. {
  3133. IsWABEntryID(lpsbEntryID->cb, (LPENTRYID)lpsbEntryID->lpb,
  3134. (LPVOID*)&sbEID.lpb, (LPVOID*)&sbEID.cb, NULL,NULL,NULL);
  3135. if(sbEID.cb == SIZEOF_WAB_ENTRYID)
  3136. lpsbEntryID = &sbEID;
  3137. }
  3138. }
  3139. if(!lpsbEntryID || lpsbEntryID->cb != SIZEOF_WAB_ENTRYID)
  3140. {
  3141. hr = MAPI_E_INVALID_PARAMETER;
  3142. goto out;
  3143. }
  3144. CopyMemory(&dwEntryID, lpsbEntryID->lpb, min(lpsbEntryID->cb, sizeof(dwEntryID)));
  3145. //DebugTrace(TEXT("--ReadRecord: dwEntryID=%d\n"), dwEntryID);
  3146. *lpulcPropCount = 0;
  3147. *lppPropArray = NULL;
  3148. if(!LockFileAccess(lpMPSWabFileInfo))
  3149. {
  3150. DebugTrace(TEXT("LockFileAccess Failed\n"));
  3151. hr = MAPI_E_NO_ACCESS;
  3152. goto out;
  3153. }
  3154. else
  3155. {
  3156. bFileLocked = TRUE;
  3157. }
  3158. //Open the file
  3159. hr = OpenWABFile(lpMPSWabFileInfo->lpszMPSWabFileName, NULL, &hMPSWabFile);
  3160. if ( (hMPSWabFile == INVALID_HANDLE_VALUE) ||
  3161. HR_FAILED(hr))
  3162. {
  3163. DebugTrace(TEXT("Could not open file.\nExiting ...\n"));
  3164. goto out;
  3165. }
  3166. //
  3167. // To ensure that file info is accurate,
  3168. // Any time we open a file, read the file info again ...
  3169. //
  3170. if(!ReloadMPSWabFileInfo(
  3171. lpMPSWabFileInfo,
  3172. hMPSWabFile))
  3173. {
  3174. DebugTrace(TEXT("Reading file info failed.\n"));
  3175. goto out;
  3176. }
  3177. //
  3178. // Anytime we detect an error - try to fix it ...
  3179. //
  3180. if((lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags & WAB_ERROR_DETECTED) ||
  3181. (lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags & WAB_WRITE_IN_PROGRESS))
  3182. {
  3183. if(HR_FAILED(HrDoQuickWABIntegrityCheck(lpMPSWabFileInfo,hMPSWabFile)))
  3184. {
  3185. hr = HrDoDetailedWABIntegrityCheck(lpMPSWabFileInfo,hMPSWabFile);
  3186. if(HR_FAILED(hr))
  3187. {
  3188. DebugTrace(TEXT("HrDoDetailedWABIntegrityCheck failed:%x\n"),hr);
  3189. goto out;
  3190. }
  3191. }
  3192. }
  3193. hr = ReadRecordWithoutLocking(
  3194. hMPSWabFile,
  3195. lpMPSWabFileInfo,
  3196. dwEntryID,
  3197. lpulcPropCount,
  3198. lppPropArray);
  3199. out:
  3200. //a little cleanup on failure
  3201. if (FAILED(hr))
  3202. {
  3203. if ((*lppPropArray) && (MPSWabRecordHeader.ulcPropCount > 0))
  3204. {
  3205. LocalFreePropArray(hPropertyStore, MPSWabRecordHeader.ulcPropCount, lppPropArray);
  3206. *lppPropArray = NULL;
  3207. }
  3208. }
  3209. if(hMPSWabFile)
  3210. IF_WIN32(CloseHandle(hMPSWabFile);) IF_WIN16(CloseFile(hMPSWabFile);)
  3211. if (bFileLocked)
  3212. UnLockFileAccess(lpMPSWabFileInfo);
  3213. //DebugTrace(( TEXT("ReadRecord: Exit\n-----------\n")));
  3214. return(hr);
  3215. }
  3216. #ifdef OLD_STUFF /*
  3217. //$$//////////////////////////////////////////////////////////////////////////////////
  3218. //
  3219. // ReadIndex - Given a specified proptag, returns an array containing all the
  3220. // data in the addressbook that corresponds to the supplied proptag
  3221. //
  3222. // IN hPropertyStore - handle to property store
  3223. // IN ulPropTag - EntryID of record to read
  3224. // OUT lpulEIDCount - number of props returned
  3225. // OUT lppdwIndex - Array of Property values
  3226. //
  3227. // Basically, we find the record offset, read in the record, copy the data
  3228. // into SPropValue arrays and return the arrays.
  3229. //
  3230. // Each SPropValue within the array corresponds to data for that prop in
  3231. // the property store. The SPropVal.Value holds the data and the
  3232. // SPropVal.ulPropTag holds the **ENTRY-ID** of the record containing
  3233. // the data and not any prop tag value
  3234. //
  3235. // Returns
  3236. // Success: S_OK
  3237. // Failure: E_FAIL
  3238. //
  3239. ////////////////////////////////////////////////////////////////////////////////////
  3240. HRESULT ReadIndex( IN HANDLE hPropertyStore,
  3241. IN PROPERTY_TAG ulPropTag,
  3242. OUT LPULONG lpulEIDCount,
  3243. OUT LPPROPERTY_ARRAY * lppdwIndex)
  3244. {
  3245. HRESULT hr = E_FAIL;
  3246. SPropertyRestriction PropRes;
  3247. ULONG ulPropCount = 0;
  3248. ULONG ulEIDCount = 0;
  3249. //ULONG ulArraySize = 0;
  3250. LPDWORD lpdwEntryIDs = NULL;
  3251. HANDLE hMPSWabFile = NULL;
  3252. DWORD dwNumofBytes = 0;
  3253. LPPROPERTY_ARRAY lpPropArray = NULL;
  3254. TCHAR * szBuf = NULL;
  3255. TCHAR * lp = NULL;
  3256. ULONG i=0,j=0,k=0;
  3257. ULONG nIndexPos=0,ulRecordOffset = 0;
  3258. BOOL bFileLocked = FALSE;
  3259. BOOL bMatchFound = FALSE;
  3260. ULONG ulDataSize = 0;
  3261. ULONG ulcValues = 0;
  3262. ULONG ulTmpPropTag = 0;
  3263. ULONG ulFileSize = 0;
  3264. BOOL bErrorDetected = FALSE;
  3265. MPSWab_RECORD_HEADER MPSWabRecordHeader = {0};
  3266. LPMPSWab_FILE_INFO lpMPSWabFileInfo = hPropertyStore;
  3267. DebugTrace(( TEXT("-----------\nReadIndex: Entry\n")));
  3268. *lpulEIDCount = 0;
  3269. *lppdwIndex = NULL;
  3270. if(!LockFileAccess(lpMPSWabFileInfo))
  3271. {
  3272. DebugTrace(TEXT("LockFileAccess Failed\n"));
  3273. hr = MAPI_E_NO_ACCESS;
  3274. goto out;
  3275. }
  3276. else
  3277. {
  3278. bFileLocked = TRUE;
  3279. }
  3280. PropRes.ulPropTag = ulPropTag;
  3281. PropRes.relop = RELOP_EQ;
  3282. PropRes.lpProp = NULL;
  3283. hr = FindRecords( IN hPropertyStore,
  3284. IN AB_MATCH_PROP_ONLY,
  3285. FALSE,
  3286. &PropRes,
  3287. &ulEIDCount,
  3288. &lpdwEntryIDs);
  3289. if (FAILED(hr))
  3290. goto out;
  3291. //reset hr
  3292. hr = E_FAIL;
  3293. if (ulEIDCount == 0)
  3294. {
  3295. DebugTrace(TEXT("No Records Found\n"));
  3296. hr = MAPI_E_NOT_FOUND;
  3297. goto out;
  3298. }
  3299. // We now know that we are going to get ulEIDCount records
  3300. // We will assume that each record has only 1 property which we are interested in
  3301. lpPropArray = LocalAlloc(LMEM_ZEROINIT, ulEIDCount * sizeof(SPropValue));
  3302. if (!lpPropArray)
  3303. {
  3304. DebugTrace(TEXT("Error allocating memory\n"));
  3305. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  3306. goto out;
  3307. }
  3308. //Open the file
  3309. hr = OpenWABFile(lpMPSWabFileInfo->lpszMPSWabFileName, NULL, &hMPSWabFile);
  3310. if ( (hMPSWabFile == INVALID_HANDLE_VALUE) ||
  3311. HR_FAILED(hr))
  3312. {
  3313. DebugTrace(TEXT("Could not open file.\nExiting ...\n"));
  3314. goto out;
  3315. }
  3316. ulFileSize = GetFileSize(hMPSWabFile, NULL);
  3317. //
  3318. // To ensure that file info is accurate,
  3319. // Any time we open a file, read the file info again ...
  3320. //
  3321. if(!ReloadMPSWabFileInfo(
  3322. lpMPSWabFileInfo,
  3323. hMPSWabFile))
  3324. {
  3325. DebugTrace(TEXT("Reading file info failed.\n"));
  3326. goto out;
  3327. }
  3328. //
  3329. // Anytime we detect an error - try to fix it ...
  3330. //
  3331. if((lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags & WAB_ERROR_DETECTED) ||
  3332. (lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags & WAB_WRITE_IN_PROGRESS))
  3333. {
  3334. if(HR_FAILED(HrDoQuickWABIntegrityCheck(lpMPSWabFileInfo,hMPSWabFile)))
  3335. {
  3336. hr = HrDoDetailedWABIntegrityCheck(lpMPSWabFileInfo,hMPSWabFile);
  3337. if(HR_FAILED(hr))
  3338. {
  3339. DebugTrace(TEXT("HrDoDetailedWABIntegrityCheck failed:%x\n"),hr);
  3340. goto out;
  3341. }
  3342. }
  3343. }
  3344. // ulArraySize = 0;
  3345. *lpulEIDCount = 0;
  3346. ulPropCount = 0;
  3347. for(i = 0; i < ulEIDCount; i++)
  3348. {
  3349. //Get offset for this entryid
  3350. if (!BinSearchEID( IN lpMPSWabFileInfo->lpMPSWabIndexEID,
  3351. IN lpdwEntryIDs[i],
  3352. IN lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries,
  3353. OUT &nIndexPos))
  3354. {
  3355. DebugTrace(TEXT("Specified EntryID doesnt exist!\n"));
  3356. continue;
  3357. //goto out;
  3358. }
  3359. ulRecordOffset = lpMPSWabFileInfo->lpMPSWabIndexEID[nIndexPos].ulOffset;
  3360. if(!ReadDataFromWABFile(hMPSWabFile,
  3361. ulRecordOffset,
  3362. (LPVOID) &MPSWabRecordHeader,
  3363. (DWORD) sizeof(MPSWab_RECORD_HEADER)))
  3364. goto out;
  3365. if(!bIsValidRecord( MPSWabRecordHeader,
  3366. lpMPSWabFileInfo->lpMPSWabFileHeader->dwNextEntryID,
  3367. ulRecordOffset,
  3368. ulFileSize))
  3369. // if ((MPSWabRecordHeader.bValidRecord == FALSE) && (MPSWabRecordHeader.bValidRecord != TRUE))
  3370. {
  3371. //this should never happen but who knows
  3372. DebugTrace(TEXT("Error: Obtained an invalid record ...\n"));
  3373. bErrorDetected = TRUE;
  3374. //hr = MAPI_E_INVALID_OBJECT;
  3375. //goto out;
  3376. //ignore it and continue
  3377. continue;
  3378. }
  3379. //ReadData
  3380. LocalFreeAndNull(&szBuf);
  3381. szBuf = LocalAlloc(LMEM_ZEROINIT, MPSWabRecordHeader.ulRecordDataSize);
  3382. if (!szBuf)
  3383. {
  3384. DebugTrace(TEXT("Error allocating memory\n"));
  3385. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  3386. goto out;
  3387. }
  3388. // Set File Pointer to beginning of Data Section
  3389. if (0xFFFFFFFF == SetFilePointer ( hMPSWabFile,
  3390. MPSWabRecordHeader.ulPropTagArraySize,
  3391. NULL,
  3392. FILE_CURRENT))
  3393. {
  3394. DebugTrace(TEXT("SetFilePointer Failed\n"));
  3395. goto out;
  3396. }
  3397. //Read in the data
  3398. // Read record header
  3399. if(!ReadFile( hMPSWabFile,
  3400. (LPVOID) szBuf,
  3401. (DWORD) MPSWabRecordHeader.ulRecordDataSize,
  3402. &dwNumofBytes,
  3403. NULL))
  3404. {
  3405. DebugTrace(TEXT("Reading Record Header failed.\n"));
  3406. goto out;
  3407. }
  3408. lp = szBuf;
  3409. // Go through all the properties in this record searching for the
  3410. // desired one ...
  3411. bMatchFound = FALSE;
  3412. ulDataSize = 0;
  3413. ulcValues = 0;
  3414. ulTmpPropTag = 0;
  3415. for (j = 0; j< MPSWabRecordHeader.ulcPropCount; j++)
  3416. {
  3417. CopyMemory(&ulTmpPropTag,lp,sizeof(ULONG));
  3418. lp+=sizeof(ULONG);
  3419. if ((ulTmpPropTag & MV_FLAG))
  3420. {
  3421. CopyMemory(&ulcValues,lp,sizeof(ULONG));
  3422. lp += sizeof(ULONG); //skip cValues
  3423. }
  3424. CopyMemory(&ulDataSize,lp,sizeof(ULONG));
  3425. lp+=sizeof(ULONG);
  3426. // if the tag doesnt match, skip this property
  3427. if (ulTmpPropTag != ulPropTag) //skip
  3428. {
  3429. lp += ulDataSize; //skip over data
  3430. continue;
  3431. }
  3432. else
  3433. {
  3434. bMatchFound = TRUE;
  3435. break;
  3436. }
  3437. } // for j ...
  3438. if (bMatchFound)
  3439. {
  3440. //
  3441. // if we are here, the property matched and we want its data
  3442. //
  3443. //
  3444. // **** note: ***** we store the entryid in the proptag variable
  3445. //
  3446. lpPropArray[ulPropCount].ulPropTag = lpdwEntryIDs[i];
  3447. if ((ulPropTag & MV_FLAG))
  3448. {
  3449. //now get the data
  3450. switch(PROP_TYPE(ulPropTag))
  3451. {
  3452. case(PT_MV_I2):
  3453. case(PT_MV_LONG):
  3454. case(PT_MV_R4):
  3455. case(PT_MV_DOUBLE):
  3456. case(PT_MV_CURRENCY):
  3457. case(PT_MV_APPTIME):
  3458. case(PT_MV_SYSTIME):
  3459. case(PT_MV_CLSID):
  3460. case(PT_MV_I8):
  3461. lpPropArray[ulPropCount].Value.MVi.lpi = LocalAlloc(LMEM_ZEROINIT,ulDataSize);
  3462. if (!(lpPropArray[ulPropCount].Value.MVi.lpi))
  3463. {
  3464. DebugTrace(TEXT("Error allocating memory\n"));
  3465. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  3466. goto out;
  3467. }
  3468. lpPropArray[ulPropCount].Value.MVi.cValues = ulcValues;
  3469. CopyMemory(lpPropArray[ulPropCount].Value.MVi.lpi, lp, ulDataSize);
  3470. lp += ulDataSize;
  3471. break;
  3472. case(PT_MV_BINARY):
  3473. lpPropArray[ulPropCount].Value.MVbin.lpbin = LocalAlloc(LMEM_ZEROINIT, ulcValues * sizeof(SBinary));
  3474. if (!(lpPropArray[ulPropCount].Value.MVbin.lpbin))
  3475. {
  3476. DebugTrace(TEXT("Error allocating memory\n"));
  3477. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  3478. goto out;
  3479. }
  3480. lpPropArray[ulPropCount].Value.MVbin.cValues = ulcValues;
  3481. for (k=0;k<ulcValues;k++)
  3482. {
  3483. ULONG nLen;
  3484. // copy cBytes
  3485. CopyMemory(&nLen, lp, sizeof(ULONG));
  3486. lp += sizeof(ULONG);
  3487. lpPropArray[ulPropCount].Value.MVbin.lpbin[k].cb = nLen;
  3488. lpPropArray[ulPropCount].Value.MVbin.lpbin[k].lpb = LocalAlloc(LMEM_ZEROINIT, nLen);
  3489. if (!(lpPropArray[ulPropCount].Value.MVbin.lpbin[k].lpb))
  3490. {
  3491. DebugTrace(TEXT("Error allocating memory\n"));
  3492. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  3493. goto out;
  3494. }
  3495. CopyMemory(lpPropArray[ulPropCount].Value.MVbin.lpbin[k].lpb, lp, nLen);
  3496. lp += nLen;
  3497. }
  3498. lpPropArray[ulPropCount].Value.MVbin.cValues = ulcValues;
  3499. break;
  3500. case(PT_MV_TSTRING):
  3501. lpPropArray[ulPropCount].Value.MVSZ.LPPSZ = LocalAlloc(LMEM_ZEROINIT, ulcValues * sizeof(LPTSTR));
  3502. if (!(lpPropArray[ulPropCount].Value.MVSZ.LPPSZ))
  3503. {
  3504. DebugTrace(TEXT("Error allocating memory\n"));
  3505. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  3506. goto out;
  3507. }
  3508. for (k=0;k<ulcValues;k++)
  3509. {
  3510. ULONG nLen;
  3511. // get string length (includes terminating zero)
  3512. CopyMemory(&nLen, lp, sizeof(ULONG));
  3513. lp += sizeof(ULONG);
  3514. lpPropArray[ulPropCount].Value.MVSZ.LPPSZ[k] = LocalAlloc(LMEM_ZEROINIT, nLen);
  3515. if (!(lpPropArray[ulPropCount].Value.MVSZ.LPPSZ[k]))
  3516. {
  3517. DebugTrace(TEXT("Error allocating memory\n"));
  3518. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  3519. goto out;
  3520. }
  3521. CopyMemory(lpPropArray[ulPropCount].Value.MVSZ.LPPSZ[k], lp, nLen);
  3522. lp += nLen;
  3523. }
  3524. lpPropArray[ulPropCount].Value.MVSZ.cValues = ulcValues;
  3525. break;
  3526. } //switch
  3527. }
  3528. else
  3529. {
  3530. //Single Valued
  3531. switch(PROP_TYPE(ulPropTag))
  3532. {
  3533. case(PT_I2):
  3534. case(PT_LONG):
  3535. case(PT_APPTIME):
  3536. case(PT_SYSTIME):
  3537. case(PT_R4):
  3538. case(PT_BOOLEAN):
  3539. case(PT_CURRENCY):
  3540. case(PT_I8):
  3541. CopyMemory(&(lpPropArray[ulPropCount].Value.i),lp,ulDataSize);
  3542. lp+=ulDataSize;
  3543. break;
  3544. case(PT_CLSID):
  3545. case(PT_TSTRING):
  3546. lpPropArray[ulPropCount].Value.LPSZ = LocalAlloc(LMEM_ZEROINIT,ulDataSize);
  3547. if (!(lpPropArray[ulPropCount].Value.LPSZ))
  3548. {
  3549. DebugTrace(TEXT("Error allocating memory\n"));
  3550. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  3551. goto out;
  3552. }
  3553. CopyMemory(lpPropArray[ulPropCount].Value.LPSZ,lp,ulDataSize);
  3554. lp+=ulDataSize;
  3555. break;
  3556. case(PT_BINARY):
  3557. lpPropArray[ulPropCount].Value.bin.lpb = LocalAlloc(LMEM_ZEROINIT,ulDataSize);
  3558. if (!(lpPropArray[ulPropCount].Value.bin.lpb))
  3559. {
  3560. DebugTrace(TEXT("Error allocating memory\n"));
  3561. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  3562. goto out;
  3563. }
  3564. CopyMemory(lpPropArray[ulPropCount].Value.bin.lpb,lp,ulDataSize);
  3565. lpPropArray[ulPropCount].Value.bin.cb = ulDataSize;
  3566. lp+=ulDataSize;
  3567. break;
  3568. } //switch
  3569. } // if MV_PROP
  3570. ulPropCount++;
  3571. } // if bMatchFound
  3572. } //for i=
  3573. DebugTrace(( TEXT("ulPropCount: %d\tulEIDCount: %d\n"),ulPropCount, ulEIDCount));
  3574. //Got all the prop tags
  3575. if (lpPropArray)
  3576. {
  3577. *lpulEIDCount = ulPropCount;
  3578. *lppdwIndex = lpPropArray;
  3579. }
  3580. hr = S_OK;
  3581. out:
  3582. LocalFreeAndNull(&lpdwEntryIDs);
  3583. if (FAILED(hr))
  3584. {
  3585. if((lpPropArray) && (ulEIDCount > 0))
  3586. LocalFreePropArray(hPropertyStore, ulEIDCount,&lpPropArray);
  3587. *lppdwIndex = NULL;
  3588. *lpulEIDCount = 0;
  3589. }
  3590. if(bErrorDetected)
  3591. TagWABFileError(lpMPSWabFileInfo->lpMPSWabFileHeader, hMPSWabFile);
  3592. if(hMPSWabFile)
  3593. IF_WIN32(CloseHandle(hMPSWabFile);) IF_WIN16(CloseFile(hMPSWabFile);)
  3594. if (bFileLocked)
  3595. UnLockFileAccess(lpMPSWabFileInfo);
  3596. DebugTrace(( TEXT("ReadIndex: Exit\n-----------\n")));
  3597. return(hr);
  3598. }
  3599. */
  3600. #endif // OLD_STUFF
  3601. //$$//////////////////////////////////////////////////////////////////////////////////
  3602. //
  3603. // BackupPropertyStore - Creates a clean, backup version of the property store
  3604. //
  3605. // IN hPropertyStore - handle to property store
  3606. // IN lpszBackupFileName - name to back up in ...
  3607. //
  3608. // Returns
  3609. // Success: S_OK
  3610. // Failure: E_FAIL
  3611. //
  3612. ////////////////////////////////////////////////////////////////////////////////////
  3613. HRESULT BackupPropertyStore(HANDLE hPropertyStore, LPTSTR lpszBackupFileName)
  3614. {
  3615. HRESULT hr = E_FAIL;
  3616. HANDLE hMPSWabFile = NULL;
  3617. BOOL bWFileLocked = FALSE;
  3618. DWORD dwNumofBytes = 0;
  3619. LPMPSWab_FILE_INFO lpMPSWabFileInfo = hPropertyStore;
  3620. HCURSOR hOldCur = SetCursor(LoadCursor(NULL,IDC_WAIT));
  3621. DebugTrace(( TEXT("BackupPropertyStore: Entry\n")));
  3622. if (lpszBackupFileName == NULL)
  3623. {
  3624. DebugTrace(TEXT("Invalid backup file name\n"));
  3625. hr = MAPI_E_INVALID_PARAMETER;
  3626. goto out;
  3627. }
  3628. if(!LockFileAccess(lpMPSWabFileInfo))
  3629. {
  3630. DebugTrace(TEXT("LockFileAccess Failed\n"));
  3631. goto out;
  3632. }
  3633. else
  3634. {
  3635. bWFileLocked = TRUE;
  3636. }
  3637. hMPSWabFile = CreateFile( lpMPSWabFileInfo->lpszMPSWabFileName,
  3638. GENERIC_READ | GENERIC_WRITE,
  3639. FILE_SHARE_READ | FILE_SHARE_WRITE,
  3640. (LPSECURITY_ATTRIBUTES) NULL,
  3641. OPEN_EXISTING,
  3642. FILE_FLAG_RANDOM_ACCESS,
  3643. (HANDLE) NULL);
  3644. if (hMPSWabFile == INVALID_HANDLE_VALUE)
  3645. {
  3646. DebugTrace(TEXT("Could not open file.\nExiting ...\n"));
  3647. goto out;
  3648. }
  3649. //
  3650. // We dont want to back up this file if it has errors in it so first
  3651. // check for errors
  3652. //
  3653. if(!ReloadMPSWabFileInfo(
  3654. lpMPSWabFileInfo,
  3655. hMPSWabFile))
  3656. {
  3657. DebugTrace(TEXT("Reading file info failed.\n"));
  3658. goto out;
  3659. }
  3660. if(!(lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags & WAB_BACKUP_NOW))
  3661. {
  3662. DebugTrace(( TEXT("No need to backup!\n")));
  3663. hr = S_OK;
  3664. goto out;
  3665. }
  3666. if(lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags & (WAB_ERROR_DETECTED | WAB_WRITE_IN_PROGRESS))
  3667. {
  3668. DebugTrace(TEXT("Errors in file - Won't backup!\n"));
  3669. goto out;
  3670. }
  3671. DebugTrace( TEXT("Backing up to %s\n"),lpszBackupFileName);
  3672. //
  3673. // reset the backup flag before backing up
  3674. //
  3675. lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags &= ~WAB_BACKUP_NOW;
  3676. if(!WriteDataToWABFile( hMPSWabFile,
  3677. 0,
  3678. (LPVOID) lpMPSWabFileInfo->lpMPSWabFileHeader,
  3679. sizeof(MPSWab_FILE_HEADER)))
  3680. goto out;
  3681. if (!CompressFile( lpMPSWabFileInfo,
  3682. hMPSWabFile,
  3683. lpszBackupFileName,
  3684. FALSE,
  3685. 0))
  3686. {
  3687. DebugTrace(TEXT("Compress file failed\n"));
  3688. goto out;
  3689. }
  3690. //SetFileAttributes(lpszBackupFileName, FILE_ATTRIBUTE_HIDDEN);
  3691. hr = S_OK;
  3692. out:
  3693. if (hMPSWabFile)
  3694. IF_WIN32(CloseHandle(hMPSWabFile);) IF_WIN16(CloseFile(hMPSWabFile);)
  3695. if(bWFileLocked)
  3696. UnLockFileAccess(lpMPSWabFileInfo);
  3697. SetCursor(hOldCur);
  3698. DebugTrace(( TEXT("BackupPropertyStore: Exit\n")));
  3699. return hr;
  3700. }
  3701. //$$//////////////////////////////////////////////////////////////////////////////////
  3702. //
  3703. // UnlockFileAccess - UnLocks Exclusive Access to the property store
  3704. //
  3705. ////////////////////////////////////////////////////////////////////////////////////
  3706. BOOL UnLockFileAccessTmp(LPMPSWab_FILE_INFO lpMPSWabFileInfo)
  3707. {
  3708. BOOL bRet = FALSE;
  3709. DebugTrace(( TEXT("\t\tUnlockFileAccess: Entry\n")));
  3710. if(lpMPSWabFileInfo)
  3711. bRet = ReleaseMutex(lpMPSWabFileInfo->hDataAccessMutex);
  3712. return bRet;
  3713. }
  3714. //$$//////////////////////////////////////////////////////////////////////////////////
  3715. //
  3716. // LockFileAccess - Gives exclusive access to the Property Store
  3717. //
  3718. ////////////////////////////////////////////////////////////////////////////////////
  3719. BOOL LockFileAccessTmp(LPMPSWab_FILE_INFO lpMPSWabFileInfo)
  3720. {
  3721. BOOL bRet = FALSE;
  3722. DWORD dwWait = 0;
  3723. DebugTrace(( TEXT("\t\tLockFileAccess: Entry\n")));
  3724. if(lpMPSWabFileInfo)
  3725. {
  3726. dwWait = WaitForSingleObject(lpMPSWabFileInfo->hDataAccessMutex,MAX_LOCK_FILE_TIMEOUT);
  3727. if ((dwWait == WAIT_TIMEOUT) || (dwWait == WAIT_FAILED))
  3728. {
  3729. DebugTrace(TEXT("Thread:%x\tWaitFOrSingleObject failed.\n"),GetCurrentThreadId());
  3730. bRet = FALSE;
  3731. }
  3732. }
  3733. return(bRet);
  3734. }
  3735. //$$//////////////////////////////////////////////////////////////////////////////////
  3736. //
  3737. // ReloadMPSWabFileInfo - Reloads the MPSWabFileHeader and reloads the
  3738. // memory indexes. This is a performance hit but cant be helped since it
  3739. // is the most reliable way to ensure we are working with the latest
  3740. // valid information
  3741. //
  3742. // Thus a write by one program cannot mess up the read by another program
  3743. //
  3744. ////////////////////////////////////////////////////////////////////////////////////
  3745. BOOL ReloadMPSWabFileInfoTmp(HANDLE hPropertyStore)
  3746. {
  3747. HANDLE hMPSWabFile = NULL;
  3748. LPMPSWab_FILE_INFO lpMPSWabFileInfo = hPropertyStore;
  3749. BOOL bRet = FALSE;
  3750. DWORD dwNumofBytes = 0;
  3751. HRESULT hr = E_FAIL;
  3752. hr = OpenWABFile(lpMPSWabFileInfo->lpszMPSWabFileName, NULL, &hMPSWabFile);
  3753. if ( (hMPSWabFile == INVALID_HANDLE_VALUE) ||
  3754. HR_FAILED(hr))
  3755. {
  3756. goto out;
  3757. }
  3758. if(0xFFFFFFFF == SetFilePointer ( hMPSWabFile,
  3759. 0,
  3760. NULL,
  3761. FILE_BEGIN))
  3762. {
  3763. DebugTrace(TEXT("SetFilePointer Failed\n"));
  3764. goto out;
  3765. }
  3766. bRet = ReloadMPSWabFileInfo(lpMPSWabFileInfo,hMPSWabFile);
  3767. out:
  3768. if (hMPSWabFile)
  3769. IF_WIN32(CloseHandle(hMPSWabFile);) IF_WIN16(CloseFile(hMPSWabFile);)
  3770. return bRet;
  3771. }
  3772. //$$//////////////////////////////////////////////////////////////////////////////////
  3773. //
  3774. // LockPropertyStore - Locks the property store and reloads the indexes so we have
  3775. // the most current ones ...
  3776. //
  3777. // IN hPropertyStore - handle to property store
  3778. //
  3779. // Returns
  3780. // Success: S_OK
  3781. // Failure: E_FAIL
  3782. //
  3783. ////////////////////////////////////////////////////////////////////////////////////
  3784. HRESULT LockPropertyStore(IN HANDLE hPropertyStore)
  3785. {
  3786. HRESULT hr = E_FAIL;
  3787. LPMPSWab_FILE_INFO lpMPSWabFileInfo = (LPMPSWab_FILE_INFO) hPropertyStore;
  3788. if (!LockFileAccessTmp(lpMPSWabFileInfo))
  3789. {
  3790. goto out;
  3791. }
  3792. // reload the indexes
  3793. if(!ReloadMPSWabFileInfoTmp(hPropertyStore))
  3794. {
  3795. goto out;
  3796. }
  3797. hr = hrSuccess;
  3798. out:
  3799. return hr;
  3800. }
  3801. //$$//////////////////////////////////////////////////////////////////////////////////
  3802. //
  3803. // UnLockPropertyStore -
  3804. //
  3805. // IN hPropertyStore - handle to property store
  3806. //
  3807. // Returns
  3808. // Success: S_OK
  3809. // Failure: E_FAIL
  3810. //
  3811. ////////////////////////////////////////////////////////////////////////////////////
  3812. HRESULT UnlockPropertyStore(IN HANDLE hPropertyStore)
  3813. {
  3814. HRESULT hr = E_FAIL;
  3815. LPMPSWab_FILE_INFO lpMPSWabFileInfo = (LPMPSWab_FILE_INFO) hPropertyStore;
  3816. if (!UnLockFileAccessTmp(lpMPSWabFileInfo))
  3817. {
  3818. goto out;
  3819. }
  3820. hr = hrSuccess;
  3821. out:
  3822. return hr;
  3823. }
  3824. //$$//////////////////////////////////////////////////////////////////////////////////
  3825. //
  3826. // ReadPropArray - Given a specified array of proptags and a search key,
  3827. // finds all records with that search key, and reads the records for
  3828. // all the props specified in the proptagarray.
  3829. //
  3830. // IN hPropertyStore - handle to property store
  3831. // IN pmbinFold - <Outlook> EntryID of folder to search in (NULL for default)
  3832. // IN SPropRes - property restriction set specifying what we're searching for
  3833. // IN ulFlags - search flags - only acceptable one is AB_MATCH_PROP_ONLY
  3834. // IN ulcPropTagCount - number of props per record requested
  3835. // IN lpPropTagArray - array of ulPropTags to return
  3836. // OUT lpContentList - List of AdrEntry structures corresponding to each matched record.
  3837. // SPropValue of each structure contains the requested props.
  3838. //
  3839. // Returns
  3840. // Success: S_OK
  3841. // Failure: E_FAIL
  3842. //
  3843. ////////////////////////////////////////////////////////////////////////////////////
  3844. HRESULT ReadPropArray( IN HANDLE hPropertyStore,
  3845. IN LPSBinary pmbinFold,
  3846. IN SPropertyRestriction * lpPropRes,
  3847. IN ULONG ulSearchFlags,
  3848. IN ULONG ulcPropTagCount,
  3849. IN LPULONG lpPTArray,
  3850. OUT LPCONTENTLIST * lppContentList)
  3851. {
  3852. LPULONG lpPropTagArray = NULL;
  3853. HRESULT hr = E_FAIL;
  3854. SCODE sc = SUCCESS_SUCCESS;
  3855. ULONG ulcEIDCount = 0;
  3856. LPSBinary rgsbEntryIDs = NULL;
  3857. HANDLE hMPSWabFile = NULL;
  3858. DWORD dwNumofBytes = 0;
  3859. LPBYTE szBuf = NULL;
  3860. LPBYTE lp = NULL;
  3861. LPCONTENTLIST lpContentList = NULL;
  3862. ULONG i=0,j=0,k=0;
  3863. ULONG nIndexPos=0,ulRecordOffset = 0;
  3864. BOOL bFileLocked = FALSE;
  3865. LPSPropValue lpPropArray = NULL;
  3866. ULONG ulcFoundPropCount = 0; //Counts the number of finds so it can exit early
  3867. BOOL * lpbFoundProp = NULL;
  3868. ULONG ulFileSize = 0;
  3869. int nCount=0;
  3870. BOOL bErrorDetected = FALSE;
  3871. MPSWab_RECORD_HEADER MPSWabRecordHeader = {0};
  3872. LPMPSWab_FILE_INFO lpMPSWabFileInfo;
  3873. //DebugTrace(("-----------\nReadPropArray: Entry\n"));
  3874. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  3875. // Check arguments
  3876. if(ulcPropTagCount < 1)
  3877. return(MAPI_E_INVALID_PARAMETER);
  3878. if(pt_bIsWABOpenExSession)
  3879. {
  3880. // This is a WABOpenEx session using outlooks storage provider
  3881. ULONG ulFlags = ulSearchFlags;
  3882. if(!hPropertyStore)
  3883. return MAPI_E_NOT_INITIALIZED;
  3884. if(ulFlags & AB_UNICODE && !pt_bIsUnicodeOutlook)
  3885. ulFlags &= ~AB_UNICODE;
  3886. {
  3887. LPWABSTORAGEPROVIDER lpWSP = (LPWABSTORAGEPROVIDER) hPropertyStore;
  3888. LPSPropertyRestriction lpPropResA = NULL;
  3889. if( !pt_bIsUnicodeOutlook)
  3890. {
  3891. // Need to thunk the restriction down to ANSI
  3892. HrDupePropResWCtoA(ulFlags, lpPropRes, &lpPropResA);
  3893. // Since the native Outlook properties are all non-UNICODE, if someone is requesting
  3894. // Unicode data, we need to convert requsted Unicode props in the PropTagArray into ANSI props
  3895. //
  3896. if(ulSearchFlags & AB_UNICODE)
  3897. {
  3898. if(!(lpPropTagArray = LocalAlloc(LMEM_ZEROINIT, sizeof(ULONG)*ulcPropTagCount)))
  3899. return MAPI_E_NOT_ENOUGH_MEMORY;
  3900. for(i=0;i<ulcPropTagCount;i++)
  3901. {
  3902. if(PROP_TYPE(lpPTArray[i]) == PT_UNICODE)
  3903. lpPropTagArray[i] = CHANGE_PROP_TYPE(lpPTArray[i], PT_STRING8);
  3904. else if(PROP_TYPE(lpPTArray[i]) == PT_MV_UNICODE)
  3905. lpPropTagArray[i] = CHANGE_PROP_TYPE(lpPTArray[i], PT_MV_STRING8);
  3906. else
  3907. lpPropTagArray[i] = lpPTArray[i];
  3908. }
  3909. }
  3910. else
  3911. {
  3912. lpPropTagArray = lpPTArray;
  3913. }
  3914. }
  3915. hr = lpWSP->lpVtbl->ReadPropArray(lpWSP,
  3916. (pmbinFold && pmbinFold->cb && pmbinFold->lpb) ? pmbinFold : NULL,
  3917. lpPropResA ? lpPropResA : lpPropRes,
  3918. ulFlags,
  3919. ulcPropTagCount,
  3920. lpPTArray,
  3921. lppContentList);
  3922. DebugTrace(TEXT("WABStorageProvider::ReadPropArray returned:%x\n"),hr);
  3923. if(lpPropResA)
  3924. {
  3925. FreeBufferAndNull(&lpPropResA->lpProp);
  3926. FreeBufferAndNull(&lpPropResA);
  3927. }
  3928. if(ulSearchFlags & AB_UNICODE && !pt_bIsUnicodeOutlook)
  3929. {
  3930. // Sender specifically requested Unicode data which Outlook doesn't return
  3931. // so need to modify the returned data list ..
  3932. if(!HR_FAILED(hr) && *lppContentList)
  3933. {
  3934. LPCONTENTLIST lpAdrList = *lppContentList;
  3935. for(i=0;lpAdrList->cEntries;i++)
  3936. {
  3937. // Now we thunk the data back to ANSI for Outlook
  3938. // ignore errors for now
  3939. if(lpAdrList->aEntries[i].rgPropVals)
  3940. ScConvertWPropsToA((LPALLOCATEMORE) (&MAPIAllocateMore), lpAdrList->aEntries[i].rgPropVals, lpAdrList->aEntries[i].cValues, 0);
  3941. }
  3942. }
  3943. }
  3944. if(lpPropTagArray != lpPTArray)
  3945. LocalFreeAndNull(&lpPropTagArray);
  3946. return hr;
  3947. }
  3948. }
  3949. lpMPSWabFileInfo = hPropertyStore;
  3950. if ((ulSearchFlags & ~(AB_MATCH_PROP_ONLY|AB_UNICODE) ) ||
  3951. (!(lpPTArray)) ||
  3952. (!(lpPropRes)) ||
  3953. ( ulcPropTagCount == 0 ) ||
  3954. ( hPropertyStore == NULL))
  3955. {
  3956. hr = MAPI_E_INVALID_PARAMETER;
  3957. goto out;
  3958. }
  3959. // Since the native properties are all UNICODE, if someone is NOT requesting
  3960. // Unicode data, we need to convert ANSI props in the PropTagArray into UNICODE props
  3961. //
  3962. if(!(ulSearchFlags & AB_UNICODE))
  3963. {
  3964. if(!(lpPropTagArray = LocalAlloc(LMEM_ZEROINIT, sizeof(ULONG)*ulcPropTagCount)))
  3965. {
  3966. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  3967. goto out;
  3968. }
  3969. for(i=0;i<ulcPropTagCount;i++)
  3970. {
  3971. if(PROP_TYPE(lpPTArray[i]) == PT_STRING8)
  3972. lpPropTagArray[i] = CHANGE_PROP_TYPE(lpPTArray[i], PT_UNICODE);
  3973. else if(PROP_TYPE(lpPTArray[i]) == PT_MV_STRING8)
  3974. lpPropTagArray[i] = CHANGE_PROP_TYPE(lpPTArray[i], PT_MV_UNICODE);
  3975. else
  3976. lpPropTagArray[i] = lpPTArray[i];
  3977. }
  3978. }
  3979. else
  3980. {
  3981. lpPropTagArray = lpPTArray;
  3982. }
  3983. if(!LockFileAccess(lpMPSWabFileInfo))
  3984. {
  3985. DebugTrace(TEXT("LockFileAccess Failed\n"));
  3986. hr = MAPI_E_NO_ACCESS;
  3987. goto out;
  3988. }
  3989. else
  3990. {
  3991. bFileLocked = TRUE;
  3992. }
  3993. hr = FindRecords( IN hPropertyStore,
  3994. pmbinFold,
  3995. IN ulSearchFlags,
  3996. FALSE,
  3997. lpPropRes,
  3998. &ulcEIDCount,
  3999. &rgsbEntryIDs);
  4000. if (FAILED(hr))
  4001. goto out;
  4002. if (ulcEIDCount == 0)
  4003. {
  4004. DebugTrace(TEXT("No Records Found\n"));
  4005. hr = MAPI_E_NOT_FOUND;
  4006. goto out;
  4007. }
  4008. //reset hr
  4009. hr = E_FAIL;
  4010. //Open the file
  4011. hr = OpenWABFile(lpMPSWabFileInfo->lpszMPSWabFileName, NULL, &hMPSWabFile);
  4012. if ( (hMPSWabFile == INVALID_HANDLE_VALUE) ||
  4013. HR_FAILED(hr))
  4014. {
  4015. DebugTrace(TEXT("Could not open file.\nExiting ...\n"));
  4016. goto out;
  4017. }
  4018. ulFileSize = GetFileSize(hMPSWabFile, NULL);
  4019. //
  4020. // To ensure that file info is accurate,
  4021. // Any time we open a file, read the file info again ...
  4022. //
  4023. if(!ReloadMPSWabFileInfo(
  4024. lpMPSWabFileInfo,
  4025. hMPSWabFile))
  4026. {
  4027. DebugTrace(TEXT("Reading file info failed.\n"));
  4028. goto out;
  4029. }
  4030. //
  4031. // Anytime we detect an error - try to fix it ...
  4032. //
  4033. if((lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags & WAB_ERROR_DETECTED) ||
  4034. (lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags & WAB_WRITE_IN_PROGRESS))
  4035. {
  4036. if(HR_FAILED(HrDoQuickWABIntegrityCheck(lpMPSWabFileInfo,hMPSWabFile)))
  4037. {
  4038. hr = HrDoDetailedWABIntegrityCheck(lpMPSWabFileInfo,hMPSWabFile);
  4039. if(HR_FAILED(hr))
  4040. {
  4041. DebugTrace(TEXT("HrDoDetailedWABIntegrityCheck failed:%x\n"),hr);
  4042. goto out;
  4043. }
  4044. }
  4045. }
  4046. *lppContentList = NULL;
  4047. // we know we matched ulcEIDCount records so
  4048. // pre-create an array of that many records
  4049. *lppContentList = LocalAlloc(LMEM_ZEROINIT, sizeof(CONTENTLIST) + ulcEIDCount * sizeof(ADRENTRY));
  4050. if(!(*lppContentList))
  4051. {
  4052. DebugTrace(TEXT("LocalAlloc failed to allocate memory\n"));
  4053. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  4054. goto out;
  4055. }
  4056. lpContentList = (*lppContentList);
  4057. lpContentList->cEntries = ulcEIDCount;
  4058. nCount = 0;
  4059. for (i = 0; i < ulcEIDCount; i++)
  4060. {
  4061. DWORD dwEID = 0;
  4062. LPADRENTRY lpAdrEntry = &(lpContentList->aEntries[nCount]);
  4063. CopyMemory(&dwEID, rgsbEntryIDs[i].lpb, min(rgsbEntryIDs[i].cb, sizeof(dwEID)));
  4064. //Get offset for this entryid
  4065. if (!BinSearchEID( IN lpMPSWabFileInfo->lpMPSWabIndexEID,
  4066. IN dwEID,
  4067. IN lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries,
  4068. OUT &nIndexPos))
  4069. {
  4070. DebugTrace(TEXT("Specified EntryID doesnt exist!\n"));
  4071. // skip this entry ... we'd rather ignore than fail ...
  4072. continue;
  4073. //goto out;
  4074. }
  4075. ulRecordOffset = lpMPSWabFileInfo->lpMPSWabIndexEID[nIndexPos].ulOffset;
  4076. if(!ReadDataFromWABFile(hMPSWabFile,
  4077. ulRecordOffset,
  4078. (LPVOID) &MPSWabRecordHeader,
  4079. (DWORD) sizeof(MPSWab_RECORD_HEADER)))
  4080. goto out;
  4081. if(!bIsValidRecord( MPSWabRecordHeader,
  4082. lpMPSWabFileInfo->lpMPSWabFileHeader->dwNextEntryID,
  4083. ulRecordOffset,
  4084. ulFileSize))
  4085. {
  4086. //this should never happen but who knows
  4087. DebugTrace(TEXT("Error: Obtained an invalid record ...\n"));
  4088. bErrorDetected = TRUE;
  4089. // skip rather than fail
  4090. continue;
  4091. }
  4092. if(MPSWabRecordHeader.ulObjType == RECORD_CONTAINER)
  4093. continue; //skip the container records - dont want them in our contents tables
  4094. //Allocate each AdrEntry Structure
  4095. lpAdrEntry->cValues = ulcPropTagCount;
  4096. lpAdrEntry->rgPropVals = LocalAlloc(LMEM_ZEROINIT, ulcPropTagCount * sizeof(SPropValue));
  4097. if(!(lpAdrEntry->rgPropVals))
  4098. {
  4099. DebugTrace(TEXT("LocalAlloc failed to allocate memory\n"));
  4100. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  4101. goto out;
  4102. }
  4103. // Initialize this rgPropVals empty array.
  4104. // We set all the proptypes to PT_ERROR so that if any property
  4105. // could not be found in the record, its corresponding property is already
  4106. // initialized to an Error
  4107. for(j=0;j<ulcPropTagCount;j++)
  4108. {
  4109. lpAdrEntry->rgPropVals[j].ulPropTag = PROP_TAG(PT_ERROR,0x0000);
  4110. }
  4111. //ReadData
  4112. LocalFreeAndNull(&szBuf);
  4113. szBuf = LocalAlloc(LMEM_ZEROINIT, MPSWabRecordHeader.ulRecordDataSize);
  4114. if (!szBuf)
  4115. {
  4116. DebugTrace(TEXT("Error allocating memory\n"));
  4117. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  4118. goto out;
  4119. }
  4120. // Set File Pointer to beginning of Data Section
  4121. if (0xFFFFFFFF == SetFilePointer ( hMPSWabFile,
  4122. MPSWabRecordHeader.ulPropTagArraySize,
  4123. NULL,
  4124. FILE_CURRENT))
  4125. {
  4126. DebugTrace(TEXT("SetFilePointer Failed\n"));
  4127. goto out;
  4128. }
  4129. //Read in the data
  4130. // Read record header
  4131. if(!ReadFile( hMPSWabFile,
  4132. (LPVOID) szBuf,
  4133. (DWORD) MPSWabRecordHeader.ulRecordDataSize,
  4134. &dwNumofBytes,
  4135. NULL))
  4136. {
  4137. DebugTrace(TEXT("Reading Record Header failed.\n"));
  4138. goto out;
  4139. }
  4140. lp = szBuf;
  4141. // Go through all the properties in this record searching for the
  4142. // desired ones ...
  4143. // We also initialize a bool array that tracks if each individual
  4144. // property has been set ... this prevents us from overwriting a prop
  4145. // once it has been found
  4146. LocalFreeAndNull(&lpbFoundProp);
  4147. lpbFoundProp = LocalAlloc(LMEM_ZEROINIT, sizeof(BOOL) * ulcPropTagCount);
  4148. if(!lpbFoundProp)
  4149. {
  4150. DebugTrace(TEXT("LocalAlloc failed to allocate memory\n"));
  4151. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  4152. goto out;
  4153. }
  4154. for(j=0;j<ulcPropTagCount;j++)
  4155. lpbFoundProp[j]=FALSE;
  4156. ulcFoundPropCount = 0;
  4157. for (j = 0; j< MPSWabRecordHeader.ulcPropCount; j++)
  4158. {
  4159. LPSPropValue lpSPropVal=NULL;
  4160. ULONG ulDataSize = 0;
  4161. ULONG ulcValues = 0;
  4162. ULONG ulTmpPropTag = 0;
  4163. BOOL bPropMatch = FALSE;
  4164. ULONG ulPropMatchIndex = 0;
  4165. // Did we find as many props as we were looking for?
  4166. // if yes, then dont look for any more
  4167. if (ulcFoundPropCount == ulcPropTagCount)
  4168. break;
  4169. // Get the fresh property tag
  4170. CopyMemory(&ulTmpPropTag,lp,sizeof(ULONG));
  4171. lp+=sizeof(ULONG);
  4172. if ((ulTmpPropTag & MV_FLAG)) // MVProps have an additional cValues thrown in
  4173. {
  4174. CopyMemory(&ulcValues,lp,sizeof(ULONG));
  4175. lp += sizeof(ULONG);
  4176. }
  4177. //Get the prop data size
  4178. CopyMemory(&ulDataSize,lp,sizeof(ULONG));
  4179. lp+=sizeof(ULONG);
  4180. // Check if we want this property
  4181. for(k=0;k<ulcPropTagCount;k++)
  4182. {
  4183. if (ulTmpPropTag == lpPropTagArray[k])
  4184. {
  4185. bPropMatch = TRUE;
  4186. ulPropMatchIndex = k;
  4187. break;
  4188. }
  4189. }
  4190. //skip if no match
  4191. if ((!bPropMatch))
  4192. {
  4193. lp += ulDataSize; //skip over data
  4194. continue;
  4195. }
  4196. //if we already found this property and filled it, skip
  4197. if (lpbFoundProp[ulPropMatchIndex] == TRUE)
  4198. {
  4199. lp += ulDataSize; //skip over data
  4200. continue;
  4201. }
  4202. //Set this prop in the array we will return
  4203. lpSPropVal = &(lpAdrEntry->rgPropVals[ulPropMatchIndex]);
  4204. lpSPropVal->ulPropTag = ulTmpPropTag;
  4205. //Single Valued
  4206. switch(PROP_TYPE(ulTmpPropTag))
  4207. {
  4208. case(PT_I2):
  4209. case(PT_LONG):
  4210. case(PT_APPTIME):
  4211. case(PT_SYSTIME):
  4212. case(PT_R4):
  4213. case(PT_BOOLEAN):
  4214. case(PT_CURRENCY):
  4215. case(PT_I8):
  4216. CopyMemory(&(lpSPropVal->Value.i),lp,min(ulDataSize,sizeof(lpSPropVal->Value.i)));
  4217. lp+=ulDataSize;
  4218. break;
  4219. case(PT_CLSID):
  4220. case(PT_TSTRING):
  4221. lpSPropVal->Value.LPSZ = LocalAlloc(LMEM_ZEROINIT,ulDataSize);
  4222. if (!(lpSPropVal->Value.LPSZ))
  4223. {
  4224. DebugTrace(TEXT("Error allocating memory\n"));
  4225. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  4226. goto out;
  4227. }
  4228. CopyMemory(lpSPropVal->Value.LPSZ,lp,ulDataSize);
  4229. lp+=ulDataSize;
  4230. break;
  4231. case(PT_BINARY):
  4232. lpSPropVal->Value.bin.lpb = LocalAlloc(LMEM_ZEROINIT,ulDataSize);
  4233. if (!(lpSPropVal->Value.bin.lpb))
  4234. {
  4235. DebugTrace(TEXT("Error allocating memory\n"));
  4236. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  4237. goto out;
  4238. }
  4239. CopyMemory(lpSPropVal->Value.bin.lpb,lp,ulDataSize);
  4240. lpSPropVal->Value.bin.cb = ulDataSize;
  4241. lp+=ulDataSize;
  4242. break;
  4243. // Multi-valued
  4244. case PT_MV_TSTRING:
  4245. lpSPropVal->Value.MVSZ.LPPSZ = LocalAlloc(LMEM_ZEROINIT, ulcValues * sizeof(LPTSTR));
  4246. if (!lpSPropVal->Value.MVSZ.LPPSZ)
  4247. {
  4248. DebugTrace(TEXT("Error allocating memory\n"));
  4249. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  4250. goto out;
  4251. }
  4252. lpSPropVal->Value.MVSZ.cValues = ulcValues;
  4253. for (k=0;k<ulcValues;k++)
  4254. {
  4255. ULONG nLen;
  4256. // get string length (includes terminating zero)
  4257. CopyMemory(&nLen, lp, sizeof(ULONG));
  4258. lp += sizeof(ULONG);
  4259. lpSPropVal->Value.MVSZ.LPPSZ[k] = LocalAlloc(LMEM_ZEROINIT, nLen);
  4260. if (!lpSPropVal->Value.MVSZ.LPPSZ[k])
  4261. {
  4262. DebugTrace(TEXT("Error allocating memory\n"));
  4263. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  4264. goto out;
  4265. }
  4266. CopyMemory(lpSPropVal->Value.MVSZ.LPPSZ[k], lp, nLen);
  4267. lp += nLen;
  4268. }
  4269. break;
  4270. case PT_MV_BINARY:
  4271. lpSPropVal->Value.MVbin.lpbin = LocalAlloc(LMEM_ZEROINIT, ulcValues * sizeof(SBinary));
  4272. if (!lpSPropVal->Value.MVbin.lpbin)
  4273. {
  4274. DebugTrace(TEXT("Error allocating memory\n"));
  4275. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  4276. goto out;
  4277. }
  4278. lpSPropVal->Value.MVbin.cValues = ulcValues;
  4279. for (k=0;k<ulcValues;k++)
  4280. {
  4281. ULONG nLen;
  4282. CopyMemory(&nLen, lp, sizeof(ULONG));
  4283. lp += sizeof(ULONG);
  4284. lpSPropVal->Value.MVbin.lpbin[k].cb = nLen;
  4285. lpSPropVal->Value.MVbin.lpbin[k].lpb = LocalAlloc(LMEM_ZEROINIT, nLen);
  4286. if (!lpSPropVal->Value.MVbin.lpbin[k].lpb)
  4287. {
  4288. DebugTrace(TEXT("Error allocating memory\n"));
  4289. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  4290. goto out;
  4291. }
  4292. CopyMemory(lpSPropVal->Value.MVbin.lpbin[k].lpb, lp, nLen);
  4293. lp += nLen;
  4294. }
  4295. break;
  4296. } //switch
  4297. ulcFoundPropCount++;
  4298. lpbFoundProp[ulPropMatchIndex]=TRUE;
  4299. }// for j
  4300. if(!(ulSearchFlags & AB_UNICODE)) //default DATA is in UNICODE, switch it to ANSI
  4301. ConvertWCPropsToALocalAlloc(lpAdrEntry->rgPropVals, lpAdrEntry->cValues);
  4302. LocalFreeAndNull(&szBuf);
  4303. LocalFreeAndNull(&lpbFoundProp);
  4304. nCount++;
  4305. }//for i
  4306. lpContentList->cEntries = nCount;
  4307. hr = S_OK;
  4308. out:
  4309. if(lpPropTagArray && lpPropTagArray!=lpPTArray)
  4310. LocalFree(lpPropTagArray);
  4311. LocalFreeAndNull(&szBuf);
  4312. LocalFreeAndNull(&lpbFoundProp);
  4313. FreeEntryIDs(hPropertyStore,
  4314. ulcEIDCount,
  4315. rgsbEntryIDs);
  4316. if(bErrorDetected)
  4317. TagWABFileError(lpMPSWabFileInfo->lpMPSWabFileHeader, hMPSWabFile);
  4318. if(hMPSWabFile)
  4319. IF_WIN32(CloseHandle(hMPSWabFile);) IF_WIN16(CloseFile(hMPSWabFile);)
  4320. if (HR_FAILED(hr))
  4321. {
  4322. if (*lppContentList)
  4323. {
  4324. FreePcontentlist(hPropertyStore, *lppContentList);
  4325. (*lppContentList) = NULL;
  4326. }
  4327. }
  4328. if (bFileLocked)
  4329. UnLockFileAccess(lpMPSWabFileInfo);
  4330. //DebugTrace(("ReadPropArray: Exit\n-----------\n"));
  4331. return(hr);
  4332. }
  4333. typedef struct _tagWabEIDList
  4334. {
  4335. WAB_ENTRYID dwEntryID;
  4336. struct _tagWabEIDList * lpNext;
  4337. } WAB_EID_LIST, * LPWAB_EID_LIST;
  4338. //$$private swap routine
  4339. void my_swap(LPWAB_ENTRYID lpdwEID, int left, int right)
  4340. {
  4341. WAB_ENTRYID temp;
  4342. temp = lpdwEID[left];
  4343. lpdwEID[left] = lpdwEID[right];
  4344. lpdwEID[right] = temp;
  4345. return;
  4346. }
  4347. //$$ private quick sort routine
  4348. // copied from Kernighan and Ritchie p.87
  4349. void my_qsort(LPWAB_ENTRYID lpdwEID, int left, int right)
  4350. {
  4351. int i, last;
  4352. if(left >= right)
  4353. return;
  4354. my_swap(lpdwEID, left, (left+right)/2);
  4355. last = left;
  4356. for(i=left+1;i<=right;i++)
  4357. if(lpdwEID[i]<lpdwEID[left])
  4358. my_swap(lpdwEID, ++last, i);
  4359. my_swap(lpdwEID, left, last);
  4360. my_qsort(lpdwEID, left, last-1);
  4361. my_qsort(lpdwEID, last+1, right);
  4362. return;
  4363. }
  4364. //$$//////////////////////////////////////////////////////////////////////////////////
  4365. //
  4366. // HrFindFuzzyRecordMatches - given a str to search for, goes throught the
  4367. // indexes and looks for partial matches. Returns a DWORD array of entry ids
  4368. // of all records that met the criteria ... if the flag AB_FAIL_AMBIGUOUS is
  4369. // supplied the function bails out if it finds more than 1 result (this
  4370. // is advantageous for ResolveNames since we have to call the function
  4371. // again and this way we avoid duplicate work
  4372. // If the search string contains spaces - we break it down into substrings
  4373. // and find only those targets that have all the sub strings. Reason for
  4374. // doing this is that if we have a Display Name of Thomas A. Edison, we should
  4375. // be able to search for Tom Edison and succeed. Caveat: we will also succeed
  4376. // for Ed Mas.<TBD> fix it
  4377. //
  4378. // One final addendum - if we get 1 exact match and multiple fuzzy matches and
  4379. // AB_FAIL_AMBIGUOUS is set then we give the 1 exact match precedence
  4380. // over the rest and declare it the unique result
  4381. //
  4382. // IN hPropertyStore - handle to property store
  4383. // IN pmbinFold - <Outlook> EntryID of folder to search in (NULL for default)
  4384. // IN lpszSearchStr - String to search for ...
  4385. // IN ulFlags - 0
  4386. // AB_FAIL_AMBIGUOUS // Means fail if no exact match
  4387. // And any combination of
  4388. // AB_FUZZY_FIND_NAME // search display name index
  4389. // AB_FUZZY_FIND_EMAIL // search email address index
  4390. // AB_FUZZY_FIND_ALIAS // search nickname index
  4391. // AB_FUZZY_FIND_ALL // search all three indexes
  4392. //
  4393. // OUT lpcValues - number of records matched
  4394. // OUT rgsbEntryIDs - array of SBinary EntryIDs of matching records
  4395. //
  4396. // TBD: This implementation Doesnt support Multi Valued propertys right now
  4397. //
  4398. //
  4399. //
  4400. // Returns
  4401. // Success: S_OK
  4402. // Failure: E_FAIL, MAPI_E_AMBIGUOUS_RECIP if AB_FUZZY_FAIL_AMBIGUOUS specified
  4403. //
  4404. ////////////////////////////////////////////////////////////////////////////////////
  4405. HRESULT HrFindFuzzyRecordMatches( HANDLE hPropertyStore,
  4406. LPSBinary pmbinFold,
  4407. LPTSTR lpszSearchForThisString,
  4408. ULONG ulFlags,
  4409. ULONG * lpcValues,
  4410. LPSBinary * lprgsbEntryIDs)
  4411. {
  4412. HRESULT hr= E_FAIL;
  4413. HANDLE hMPSWabFile = NULL;
  4414. BOOL bFileLocked = FALSE;
  4415. ULONG j = 0;
  4416. ULONG i = 0,k=0;
  4417. ULONG cValues = 0;
  4418. LPWAB_EID_LIST lpHead = NULL,lpCurrent = NULL;
  4419. ULONG ulNumIndexesToSearch = 0;
  4420. LPMPSWab_FILE_INFO lpMPSWabFileInfo;
  4421. LPWAB_ENTRYID lpdwEntryIDs = NULL;
  4422. LPTSTR * lppszSubStr = NULL;
  4423. ULONG ulSubStrCount = 0;
  4424. LPTSTR lpszSearchStr = NULL;
  4425. ULONG ulUniqueMatchCount = 0;
  4426. DWORD dwUniqueEID = 0;
  4427. LPDWORD lpdwFolderEIDs = NULL;
  4428. ULONG ulFolderEIDs = 0;
  4429. BOOL bSearchVirtualRootFolder = FALSE;
  4430. ULONG cchSize;
  4431. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  4432. if(pt_bIsWABOpenExSession)
  4433. {
  4434. // This is a WABOpenEx session using outlooks storage provider
  4435. if(!hPropertyStore)
  4436. return MAPI_E_NOT_INITIALIZED;
  4437. {
  4438. LPWABSTORAGEPROVIDER lpWSP = (LPWABSTORAGEPROVIDER) hPropertyStore;
  4439. LPSTR lpSearchString = ConvertWtoA(lpszSearchForThisString);
  4440. hr = lpWSP->lpVtbl->FindFuzzyRecordMatches( lpWSP,
  4441. pmbinFold,
  4442. lpSearchString,
  4443. ulFlags,
  4444. lpcValues,
  4445. lprgsbEntryIDs);
  4446. LocalFreeAndNull(&lpSearchString);
  4447. DebugTrace(TEXT("WABStorageProvider::FindFuzzyRecordMatches returned:%x\n"),hr);
  4448. return hr;
  4449. }
  4450. }
  4451. lpMPSWabFileInfo = hPropertyStore;
  4452. //DebugTrace(("//////////\nHrFindFuzzyRecordMatches: Entry\n"));
  4453. if ((!lpszSearchForThisString) ||
  4454. (!lprgsbEntryIDs) ||
  4455. ( hPropertyStore == NULL) )
  4456. {
  4457. hr = MAPI_E_INVALID_PARAMETER;
  4458. DebugTrace(TEXT("Invalid Parameters\n"));
  4459. goto out;
  4460. }
  4461. *lprgsbEntryIDs = NULL;
  4462. *lpcValues = 0;
  4463. if(!LockFileAccess(lpMPSWabFileInfo))
  4464. {
  4465. DebugTrace(TEXT("LockFileAccess Failed\n"));
  4466. hr = MAPI_E_NO_ACCESS;
  4467. goto out;
  4468. }
  4469. else
  4470. {
  4471. bFileLocked = TRUE;
  4472. }
  4473. // Parse the search string for spaces and break it down into substrings
  4474. cchSize = lstrlen(lpszSearchForThisString)+1;
  4475. lpszSearchStr = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize);
  4476. if(!lpszSearchStr)
  4477. {
  4478. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  4479. goto out;
  4480. }
  4481. StrCpyN(lpszSearchStr, lpszSearchForThisString, cchSize);
  4482. TrimSpaces(lpszSearchStr);
  4483. ulSubStrCount = 0;
  4484. {
  4485. // Count the spaces
  4486. LPTSTR lpTemp = lpszSearchStr;
  4487. LPTSTR lpStart = lpszSearchStr;
  4488. ulSubStrCount = nCountSubStrings(lpszSearchStr);
  4489. lppszSubStr = LocalAlloc(LMEM_ZEROINIT, sizeof(LPTSTR) * ulSubStrCount);
  4490. if(!lppszSubStr)
  4491. {
  4492. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  4493. goto out;
  4494. }
  4495. // Fill in the substrings
  4496. i=0;
  4497. lpTemp = lpszSearchStr;
  4498. while(*lpTemp)
  4499. {
  4500. if (IsSpace(lpTemp) &&
  4501. ! IsSpace(CharNext(lpTemp))) {
  4502. LPTSTR lpNextString = CharNext(lpTemp);
  4503. *lpTemp = '\0';
  4504. lpTemp = lpNextString;
  4505. cchSize = lstrlen(lpStart)+1;
  4506. lppszSubStr[i] = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize);
  4507. if(!lppszSubStr[i])
  4508. {
  4509. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  4510. goto out;
  4511. }
  4512. StrCpyN(lppszSubStr[i], lpStart, cchSize);
  4513. lpStart = lpTemp;
  4514. i++;
  4515. }
  4516. else
  4517. lpTemp = CharNext(lpTemp);
  4518. }
  4519. if(i==ulSubStrCount-1)
  4520. {
  4521. //we're off by one
  4522. cchSize = lstrlen(lpStart)+1;
  4523. lppszSubStr[i] = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize);
  4524. if(!lppszSubStr[i])
  4525. {
  4526. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  4527. goto out;
  4528. }
  4529. StrCpyN(lppszSubStr[i], lpStart, cchSize);
  4530. }
  4531. for(i=0;i<ulSubStrCount;i++)
  4532. TrimSpaces(lppszSubStr[i]);
  4533. }
  4534. //Open the file
  4535. hr = OpenWABFile(lpMPSWabFileInfo->lpszMPSWabFileName, NULL, &hMPSWabFile);
  4536. if ( (hMPSWabFile == INVALID_HANDLE_VALUE) ||
  4537. HR_FAILED(hr))
  4538. {
  4539. DebugTrace(TEXT("Could not open file.\nExiting ...\n"));
  4540. goto out;
  4541. }
  4542. //
  4543. // To ensure that file info is accurate,
  4544. // Any time we open a file, read the file info again ...
  4545. //
  4546. if(!ReloadMPSWabFileInfo(
  4547. lpMPSWabFileInfo,
  4548. hMPSWabFile))
  4549. {
  4550. DebugTrace(TEXT("Reading file info failed.\n"));
  4551. goto out;
  4552. }
  4553. //
  4554. // Anytime we detect an error - try to fix it ...
  4555. //
  4556. if((lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags & WAB_ERROR_DETECTED) ||
  4557. (lpMPSWabFileInfo->lpMPSWabFileHeader->ulFlags & WAB_WRITE_IN_PROGRESS))
  4558. {
  4559. if(HR_FAILED(HrDoQuickWABIntegrityCheck(lpMPSWabFileInfo,hMPSWabFile)))
  4560. {
  4561. hr = HrDoDetailedWABIntegrityCheck(lpMPSWabFileInfo,hMPSWabFile);
  4562. if(HR_FAILED(hr))
  4563. {
  4564. DebugTrace(TEXT("HrDoDetailedWABIntegrityCheck failed:%x\n"),hr);
  4565. goto out;
  4566. }
  4567. }
  4568. }
  4569. // If a WAB folder EID is specified, then we only want to search within the contents
  4570. // of that particular WAB folder .. that way we don't have to search through the whole WAB
  4571. // So we will open the WAB folder and get a list of it's member EIDs and check that a entryid
  4572. // is a member of that folder before we search through it
  4573. if(ulFlags & AB_FUZZY_FIND_PROFILEFOLDERONLY)
  4574. {
  4575. if(pmbinFold && pmbinFold->cb && pmbinFold->lpb)
  4576. {
  4577. // We need to look through the specified folder only
  4578. hr = GetFolderEIDs(hMPSWabFile, lpMPSWabFileInfo, pmbinFold,
  4579. &ulFolderEIDs, &lpdwFolderEIDs);
  4580. if(!HR_FAILED(hr) && !ulFolderEIDs && !lpdwFolderEIDs)
  4581. goto out; //empty container - nothing to search
  4582. }
  4583. else
  4584. {
  4585. // we need to look through the virtual folder
  4586. // It's harder to assemble a list of virtual folder contents
  4587. // without looking at each entry .. so instead we will just look
  4588. // at the entry prior to searching through it and if it's not in th
  4589. // virtual folder, we will ignore it ..
  4590. bSearchVirtualRootFolder = TRUE;
  4591. }
  4592. }
  4593. // If we can always assume that the Display Name is made up of
  4594. // First and Last name .. then by searching only the display name
  4595. // we dont need to search the other indexes.
  4596. // later when we have email implemented as an index - we can think about searching
  4597. // the email also ...
  4598. if (ulFlags & AB_FUZZY_FIND_NAME)
  4599. ulNumIndexesToSearch++;
  4600. if (ulFlags & AB_FUZZY_FIND_EMAIL)
  4601. ulNumIndexesToSearch++;
  4602. if (ulFlags & AB_FUZZY_FIND_ALIAS)
  4603. ulNumIndexesToSearch++;
  4604. for(k=0;k<ulNumIndexesToSearch;k++)
  4605. {
  4606. if(ulFlags & AB_FUZZY_FIND_NAME)
  4607. {
  4608. ulFlags &= ~AB_FUZZY_FIND_NAME;
  4609. j = indexDisplayName;
  4610. }
  4611. else if(ulFlags & AB_FUZZY_FIND_EMAIL)
  4612. {
  4613. ulFlags &= ~AB_FUZZY_FIND_EMAIL;
  4614. j = indexEmailAddress;
  4615. }
  4616. else if(ulFlags & AB_FUZZY_FIND_ALIAS)
  4617. {
  4618. ulFlags &= ~AB_FUZZY_FIND_ALIAS;
  4619. j = indexAlias;
  4620. }
  4621. //
  4622. // Get the index
  4623. //
  4624. if (!LoadIndex( IN lpMPSWabFileInfo,
  4625. IN j,
  4626. IN hMPSWabFile) )
  4627. {
  4628. DebugTrace(TEXT("Error Loading Index!\n"));
  4629. goto out;
  4630. }
  4631. for(i=0;i<lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[j].ulcNumEntries;i++)
  4632. {
  4633. // if there is a match we will store it in a linked list for now
  4634. // since that is simpler to implement ...
  4635. // later on we can clean up the action .. TBD
  4636. LPTSTR lpszTarget = lpMPSWabFileInfo->lpMPSWabIndexStr[i].szIndex;
  4637. ULONG n = 0;
  4638. // Before looking at any particular entry, check that it is part of the
  4639. // current folder
  4640. if(ulFolderEIDs && lpdwFolderEIDs)
  4641. {
  4642. BOOL bFound = FALSE;
  4643. for(n=0;n<ulFolderEIDs;n++)
  4644. {
  4645. if(lpMPSWabFileInfo->lpMPSWabIndexStr[i].dwEntryID == lpdwFolderEIDs[n])
  4646. {
  4647. bFound = TRUE;
  4648. break;
  4649. }
  4650. }
  4651. if(!bFound)
  4652. continue;
  4653. }
  4654. else
  4655. if(bSearchVirtualRootFolder)
  4656. {
  4657. // Discard this entry if it belongs to any folder .. we only want to
  4658. // consider entries that don't belong to any folder ..
  4659. ULONG ulObjType = 0;
  4660. if(bIsFolderMember( hMPSWabFile, lpMPSWabFileInfo,
  4661. lpMPSWabFileInfo->lpMPSWabIndexStr[i].dwEntryID, &ulObjType) ||
  4662. (ulObjType == RECORD_CONTAINER) )
  4663. continue;
  4664. }
  4665. for(n=0;n<ulSubStrCount;n++)
  4666. {
  4667. if(j == indexEmailAddress && IsInternetAddress(lppszSubStr[n], NULL))
  4668. {
  4669. // Bug 33422 - we are resolving correct email addresses to incorrect email addresses
  4670. // If the address looks like a valid internet address, we should do a starts with search
  4671. // This way [email protected] doesnt resolve to [email protected]
  4672. if(lstrlen(lppszSubStr[n]) > lstrlen(lpszTarget))
  4673. break;
  4674. // Bug 7881: need to do a caseinsensitive search here ..
  4675. {
  4676. LPTSTR lp = lppszSubStr[n], lpT = lpszTarget;
  4677. while(lp && *lp && lpT && *lpT &&
  4678. ( ( (TCHAR)CharLower( (LPTSTR)(DWORD_PTR)MAKELONG(*lp, 0)) == *lpT) ||
  4679. ( (TCHAR)CharUpper( (LPTSTR)(DWORD_PTR)MAKELONG(*lp, 0)) == *lpT) ) )
  4680. {
  4681. lp++;
  4682. lpT++;
  4683. }
  4684. if(*lp) // which means didnt reach the end of the string
  4685. break;
  4686. }
  4687. }
  4688. else
  4689. if (!SubstringSearch(lpszTarget, lppszSubStr[n]))
  4690. break;
  4691. }
  4692. {
  4693. BOOL bExactMatch = FALSE;
  4694. // look for exact matches too
  4695. if(lstrlen(lpszSearchForThisString) > MAX_INDEX_STRING-1)
  4696. {
  4697. // this is a really long string so we can't really compare it correctly
  4698. // so for starters we will compare the first 32 chars
  4699. TCHAR sz[MAX_INDEX_STRING];
  4700. CopyMemory(sz, lpszSearchForThisString, min(sizeof(TCHAR)*lstrlen(lpszTarget),sizeof(sz)));
  4701. sz[min(lstrlen(lpszTarget),ARRAYSIZE(sz)-1)] = '\0'; // depending on the language target string may or maynot be 32 chars - might be less
  4702. if(!lstrcmpi(sz, lpszTarget))
  4703. {
  4704. // Match .. now to check the whole string ...
  4705. ULONG ulcProps = 0;
  4706. LPSPropValue lpProps = NULL;
  4707. if(!HR_FAILED(ReadRecordWithoutLocking(hMPSWabFile, lpMPSWabFileInfo,
  4708. lpMPSWabFileInfo->lpMPSWabIndexStr[i].dwEntryID,
  4709. &ulcProps, &lpProps)))
  4710. {
  4711. ULONG k = 0;
  4712. ULONG ulProp = (j==indexDisplayName) ? PR_DISPLAY_NAME : ((j==indexEmailAddress) ? PR_EMAIL_ADDRESS : PR_NICKNAME);
  4713. for(k=0;k<ulcProps;k++)
  4714. {
  4715. if(lpProps[k].ulPropTag == ulProp)
  4716. {
  4717. if(!lstrcmpi(lpszSearchForThisString, lpProps[k].Value.LPSZ))
  4718. {
  4719. bExactMatch = TRUE;
  4720. break;
  4721. }
  4722. }
  4723. }
  4724. LocalFreePropArray(hMPSWabFile, ulcProps, &lpProps);
  4725. }
  4726. }
  4727. }
  4728. else if(!lstrcmpi(lpszSearchForThisString, lpszTarget))
  4729. bExactMatch = TRUE;
  4730. if(bExactMatch)
  4731. {
  4732. //exact match
  4733. ulUniqueMatchCount++;
  4734. dwUniqueEID = lpMPSWabFileInfo->lpMPSWabIndexStr[i].dwEntryID;
  4735. if( ulFlags == AB_FUZZY_FAIL_AMBIGUOUS && ulUniqueMatchCount > 1 )
  4736. {
  4737. // more than two - genuine fail
  4738. hr = MAPI_E_AMBIGUOUS_RECIP;
  4739. DebugTrace(TEXT("Found multiple exact matches: Ambiguous search\n"));
  4740. goto out;
  4741. } //if
  4742. }
  4743. else // not an exact match - revert back to regular error check
  4744. if(n != ulSubStrCount) // something didnt match
  4745. continue;
  4746. }
  4747. // if (SubstringSearch(lpszTarget, lpszSearchStr))
  4748. {
  4749. // Yes a partial match ...
  4750. LPWAB_EID_LIST lpTemp = NULL;
  4751. BOOL bDupe = FALSE;
  4752. // before adding this to the list, make sure it is not a FOLDER .. if it is a folder,
  4753. // we need to ignore it ..
  4754. {
  4755. ULONG ulObjType = 0;
  4756. bIsFolderMember( hMPSWabFile, lpMPSWabFileInfo, lpMPSWabFileInfo->lpMPSWabIndexStr[i].dwEntryID, &ulObjType);
  4757. if(ulObjType == RECORD_CONTAINER)
  4758. continue;
  4759. }
  4760. // before adding this entryid to the list, make sure that it isnt already in the list
  4761. if(lpHead)
  4762. {
  4763. lpTemp = lpHead;
  4764. while(lpTemp)
  4765. {
  4766. if(lpTemp->dwEntryID == lpMPSWabFileInfo->lpMPSWabIndexStr[i].dwEntryID)
  4767. {
  4768. bDupe = TRUE;
  4769. break;
  4770. }
  4771. lpTemp = lpTemp->lpNext;
  4772. }
  4773. }
  4774. if(bDupe)
  4775. continue;
  4776. lpTemp = LocalAlloc(LMEM_ZEROINIT,sizeof(WAB_EID_LIST));
  4777. if(!lpTemp)
  4778. {
  4779. DebugTrace(TEXT("Local Alloc Failed\n"));
  4780. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  4781. goto out;
  4782. }
  4783. lpTemp->lpNext = NULL;
  4784. lpTemp->dwEntryID = lpMPSWabFileInfo->lpMPSWabIndexStr[i].dwEntryID;
  4785. if (lpCurrent)
  4786. {
  4787. lpCurrent->lpNext = lpTemp;
  4788. lpCurrent = lpTemp;
  4789. }
  4790. else
  4791. lpCurrent = lpTemp;
  4792. if(!lpHead)
  4793. lpHead = lpCurrent;
  4794. cValues++;
  4795. // if we have to give exact match precedence over fuzzy match then
  4796. // this means that we have to search everything and can't bail just yet
  4797. //
  4798. /*
  4799. if( (ulFlags == AB_FUZZY_FAIL_AMBIGUOUS) &&
  4800. (cValues > 1) )
  4801. {
  4802. // There is always the possibility that the same element
  4803. // has been found twice, once under display name and once
  4804. // under e-mail (e.g. Joe Smith, [email protected], searching for Joe)
  4805. // So if we have two elements and the entryids are the same,
  4806. // this is no cause for failure
  4807. if(cValues==2)
  4808. {
  4809. if(lpHead && lpCurrent)
  4810. {
  4811. if(lpHead->dwEntryID == lpCurrent->dwEntryID)
  4812. continue;
  4813. }
  4814. }
  4815. // more than two - genuine fail
  4816. hr = MAPI_E_AMBIGUOUS_RECIP;
  4817. DebugTrace(TEXT("Found multiple matches: Ambiguous search\n"));
  4818. goto out;
  4819. } //if
  4820. */
  4821. }//if Substring search
  4822. }//for(i= ..
  4823. }//for k=..
  4824. lpCurrent = lpHead;
  4825. if (lpCurrent == NULL)
  4826. {
  4827. // nothing found
  4828. hr = hrSuccess;
  4829. *lpcValues = 0;
  4830. DebugTrace(( TEXT("No matches found\n")));
  4831. goto out;
  4832. }
  4833. //
  4834. // if we want this search to fail when it's ambiguous, this means
  4835. // we give preference to exact matches. Hence if we have a single exact match,
  4836. // then we should return only that single exact match..
  4837. if( ulFlags==AB_FUZZY_FAIL_AMBIGUOUS && ulUniqueMatchCount==1 )
  4838. {
  4839. *lpcValues = 1;
  4840. *lprgsbEntryIDs = LocalAlloc(LMEM_ZEROINIT, sizeof(SBinary));
  4841. if(!(*lprgsbEntryIDs))
  4842. {
  4843. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  4844. goto out;
  4845. }
  4846. (*lprgsbEntryIDs)[0].lpb = LocalAlloc(LMEM_ZEROINIT, SIZEOF_WAB_ENTRYID);
  4847. if((*lprgsbEntryIDs)[0].lpb)
  4848. {
  4849. (*lprgsbEntryIDs)[0].cb = SIZEOF_WAB_ENTRYID;
  4850. CopyMemory((*lprgsbEntryIDs)[0].lpb,&dwUniqueEID, SIZEOF_WAB_ENTRYID);
  4851. }
  4852. }
  4853. else
  4854. {
  4855. // At the end of the above loops, we should have a linked list of
  4856. // entry ids - if we are searching through more than one index, then
  4857. // chances are that we have duplicates in this above list or entryids.
  4858. // We need to weed out the duplicates before we return this array
  4859. // First we turn the linked list into an array, freeing the linked list in the
  4860. // process. Then we quick sort the array of entryids
  4861. // Then we remove the duplicates and return another cleaned up array
  4862. lpdwEntryIDs = LocalAlloc(LMEM_ZEROINIT,cValues * SIZEOF_WAB_ENTRYID);
  4863. if(!lpdwEntryIDs)
  4864. {
  4865. DebugTrace(TEXT("LocalAlloc failed to allocate memory\n"));
  4866. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  4867. goto out;
  4868. }
  4869. for(j=0;j<cValues;j++)
  4870. {
  4871. if(lpCurrent)
  4872. {
  4873. lpdwEntryIDs[j]=lpCurrent->dwEntryID;
  4874. lpHead = lpCurrent->lpNext;
  4875. LocalFreeAndNull(&lpCurrent);
  4876. lpCurrent = lpHead;
  4877. }
  4878. }
  4879. lpCurrent = NULL;
  4880. // Now quicksort this array
  4881. my_qsort(lpdwEntryIDs, 0, cValues-1);
  4882. // Now we have a quicksorted array - scan it and remove duplicates
  4883. *lpcValues = 1;
  4884. for(i=0;i<cValues-1;i++)
  4885. {
  4886. if(lpdwEntryIDs[i] == lpdwEntryIDs[i+1])
  4887. lpdwEntryIDs[i] = 0;
  4888. else
  4889. (*lpcValues)++;
  4890. }
  4891. *lprgsbEntryIDs = LocalAlloc(LMEM_ZEROINIT,(*lpcValues) * sizeof(SBinary));
  4892. if(!(*lprgsbEntryIDs))
  4893. {
  4894. DebugTrace(TEXT("LocalAlloc failed to allocate memory\n"));
  4895. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  4896. goto out;
  4897. }
  4898. *lpcValues = 0;
  4899. for(j=0;j<cValues;j++)
  4900. {
  4901. if(lpdwEntryIDs[j] > 0)
  4902. {
  4903. int index = *lpcValues;
  4904. (*lprgsbEntryIDs)[index].lpb = LocalAlloc(LMEM_ZEROINIT, SIZEOF_WAB_ENTRYID);
  4905. if((*lprgsbEntryIDs)[index].lpb)
  4906. {
  4907. (*lprgsbEntryIDs)[index].cb = SIZEOF_WAB_ENTRYID;
  4908. CopyMemory((*lprgsbEntryIDs)[index].lpb,&(lpdwEntryIDs[j]), SIZEOF_WAB_ENTRYID);
  4909. (*lpcValues)++;
  4910. }
  4911. }
  4912. }
  4913. }
  4914. hr = hrSuccess;
  4915. out:
  4916. if(lpdwFolderEIDs)
  4917. LocalFree(lpdwFolderEIDs);
  4918. if(lpCurrent)
  4919. {
  4920. while(lpCurrent)
  4921. {
  4922. lpHead = lpCurrent->lpNext;
  4923. LocalFreeAndNull(&lpCurrent);
  4924. lpCurrent = lpHead;
  4925. }
  4926. }
  4927. if(lppszSubStr)
  4928. {
  4929. for(i=0;i<ulSubStrCount;i++)
  4930. LocalFreeAndNull(&lppszSubStr[i]);
  4931. LocalFree(lppszSubStr);
  4932. }
  4933. LocalFreeAndNull(&lpszSearchStr);
  4934. LocalFreeAndNull(&lpdwEntryIDs);
  4935. if(hMPSWabFile)
  4936. IF_WIN32(CloseHandle(hMPSWabFile);) IF_WIN16(CloseFile(hMPSWabFile);)
  4937. if (bFileLocked)
  4938. UnLockFileAccess(lpMPSWabFileInfo);
  4939. DebugTrace(TEXT("HrFindFuzzyRecordMatches: Exit: %x cValues: %d\n"),hr,*lpcValues);
  4940. return hr;
  4941. }
  4942. //$$////////////////////////////////////////////////////////////////////////
  4943. //
  4944. // bTagWriteTransaction -
  4945. //
  4946. // During a write transaction, we tag the header as write-in-progress so that
  4947. // if the transaction shuts down in the middle we dont get messed up the next
  4948. // time we open up and so we can attepmt a repair the next time we open up
  4949. //
  4950. ////////////////////////////////////////////////////////////////////////////
  4951. BOOL bTagWriteTransaction(LPMPSWab_FILE_HEADER lpMPSWabFileHeader,
  4952. HANDLE hMPSWabFile)
  4953. {
  4954. BOOL bRet = FALSE;
  4955. DWORD dwNumofBytes = 0;
  4956. if(!lpMPSWabFileHeader || !hMPSWabFile)
  4957. {
  4958. DebugTrace(TEXT("Invalid Parameter\n"));
  4959. goto out;
  4960. }
  4961. lpMPSWabFileHeader->ulFlags |= WAB_WRITE_IN_PROGRESS;
  4962. if(!WriteDataToWABFile( hMPSWabFile,
  4963. 0,
  4964. (LPVOID) lpMPSWabFileHeader,
  4965. sizeof(MPSWab_FILE_HEADER)))
  4966. goto out;
  4967. bRet = TRUE;
  4968. out:
  4969. return bRet;
  4970. }
  4971. //$$////////////////////////////////////////////////////////////////////////
  4972. //
  4973. // bUntagWriteTransaction -
  4974. //
  4975. // During a write transaction, we tag the header as write-in-progress so that
  4976. // if the transaction shuts down in the middle we dont get messed up the next
  4977. // time we open up and so we can attepmt a repair the next time we open up
  4978. //
  4979. ////////////////////////////////////////////////////////////////////////////
  4980. BOOL bUntagWriteTransaction(LPMPSWab_FILE_HEADER lpMPSWabFileHeader,
  4981. HANDLE hMPSWabFile)
  4982. {
  4983. BOOL bRet = FALSE;
  4984. DWORD dwNumofBytes = 0;
  4985. if(!lpMPSWabFileHeader || !hMPSWabFile)
  4986. {
  4987. DebugTrace(TEXT("Invalid Parameter\n"));
  4988. goto out;
  4989. }
  4990. lpMPSWabFileHeader->ulFlags &= ~WAB_WRITE_IN_PROGRESS;
  4991. // update the file header
  4992. if(!WriteDataToWABFile( hMPSWabFile,
  4993. 0,
  4994. (LPVOID) lpMPSWabFileHeader,
  4995. sizeof(MPSWab_FILE_HEADER)))
  4996. goto out;
  4997. bRet = TRUE;
  4998. out:
  4999. return bRet;
  5000. }
  5001. /*
  5002. - GetNamedPropsFromBuffer
  5003. -
  5004. * bDoAtoWConversion - when importing from an old-non-unicode WAB file, we need to
  5005. * update the 'name' strings from ASCII to Unicode .. this flag tells us to do so
  5006. *
  5007. */
  5008. BOOL GetNamedPropsFromBuffer(LPBYTE szBuf,
  5009. ULONG ulcGUIDCount,
  5010. BOOL bDoAtoWConversion,
  5011. OUT LPGUID_NAMED_PROPS * lppgnp)
  5012. {
  5013. LPBYTE lp = szBuf;
  5014. LPGUID_NAMED_PROPS lpgnp = NULL;
  5015. ULONG i = 0,j=0;
  5016. lpgnp = LocalAlloc(LMEM_ZEROINIT, ulcGUIDCount * sizeof(GUID_NAMED_PROPS));
  5017. if(!lpgnp)
  5018. {
  5019. DebugTrace(TEXT("LocalAlloc failed\n"));
  5020. goto out;
  5021. }
  5022. for(i=0;i<ulcGUIDCount;i++)
  5023. {
  5024. lpgnp[i].lpGUID = LocalAlloc(LMEM_ZEROINIT, sizeof(GUID));
  5025. if(!lpgnp[i].lpGUID)
  5026. {
  5027. DebugTrace(TEXT("LocalAlloc failed\n"));
  5028. goto out;
  5029. }
  5030. CopyMemory(lpgnp[i].lpGUID, lp, sizeof(GUID));
  5031. lp += sizeof(GUID); // for GUID
  5032. CopyMemory(&(lpgnp[i].cValues), lp, sizeof(ULONG));
  5033. lp += sizeof(ULONG); // for cValues
  5034. lpgnp[i].lpnm = LocalAlloc(LMEM_ZEROINIT, (lpgnp[i].cValues)*sizeof(NAMED_PROP));
  5035. if(!lpgnp[i].lpnm)
  5036. {
  5037. DebugTrace(TEXT("LocalAlloc failed\n"));
  5038. goto out;
  5039. }
  5040. for(j=0;j<lpgnp[i].cValues;j++)
  5041. {
  5042. ULONG nLen;
  5043. LPWSTR lpW = NULL;
  5044. CopyMemory(&(lpgnp[i].lpnm[j].ulPropTag), lp, sizeof(ULONG));
  5045. lp += sizeof(ULONG); //saves PropTag
  5046. // nLen includes trailing zero
  5047. CopyMemory(&nLen, lp, sizeof(ULONG));
  5048. lp += sizeof(ULONG); //saves lstrlen
  5049. if(!bDoAtoWConversion)
  5050. {
  5051. if(!(lpW = LocalAlloc(LMEM_ZEROINIT, nLen)))
  5052. {
  5053. DebugTrace(TEXT("LocalAlloc failed\n"));
  5054. goto out;
  5055. }
  5056. CopyMemory(lpW, lp, nLen);
  5057. }
  5058. else
  5059. {
  5060. LPSTR lpA = NULL;
  5061. if(!(lpA = LocalAlloc(LMEM_ZEROINIT, nLen)))
  5062. {
  5063. DebugTrace(TEXT("LocalAlloc failed\n"));
  5064. goto out;
  5065. }
  5066. CopyMemory(lpA, lp, nLen);
  5067. lpW = ConvertAtoW(lpA);
  5068. LocalFreeAndNull(&lpA);
  5069. }
  5070. lpgnp[i].lpnm[j].lpsz = lpW;
  5071. // [PaulHi] HACK 3/25/99 The wabimprt.c code expects lpW to ALWAYS be at least
  5072. // two characters in length, and skips the first character. If this is
  5073. // less than or equal to one character then create a two character buffer filled
  5074. // with zeros.
  5075. if (nLen <= 2) // Length is in bytes
  5076. {
  5077. LocalFreeAndNull(&(lpgnp[i].lpnm[j].lpsz));
  5078. lpgnp[i].lpnm[j].lpsz = LocalAlloc(LMEM_ZEROINIT, (2 * sizeof(WCHAR)));
  5079. if (!lpgnp[i].lpnm[j].lpsz)
  5080. {
  5081. DebugTrace(TEXT("LocalAlloc failed\n"));
  5082. goto out;
  5083. }
  5084. }
  5085. lp += nLen;
  5086. }
  5087. }
  5088. *lppgnp = lpgnp;
  5089. return TRUE;
  5090. out:
  5091. if(lpgnp)
  5092. FreeGuidnamedprops(ulcGUIDCount, lpgnp);
  5093. return FALSE;
  5094. }
  5095. //$$////////////////////////////////////////////////////////////////////////
  5096. ////
  5097. //// GetNamedPropsFromPropStore -
  5098. ////
  5099. //// Used for retreiving the named props to the property store
  5100. //// The supplied lppgn pointer is filled with GUID_NAMED_PROP array
  5101. ////
  5102. //// IN hPropertyStore - handle to the property store
  5103. //// OUT lpulcGUIDCount - number of different GUIDs in the lpgnp array
  5104. //// OUT lppgnp - returned LPGUID_NAMED_PROP structure array
  5105. ////
  5106. //// The lppgnp Structure is LocalAlloced. Caller should calle
  5107. //// FreeGuidnamedprop to free this structure
  5108. ////
  5109. ////////////////////////////////////////////////////////////////////////////
  5110. HRESULT GetNamedPropsFromPropStore( IN HANDLE hPropertyStore,
  5111. OUT LPULONG lpulcGUIDCount,
  5112. OUT LPGUID_NAMED_PROPS * lppgnp)
  5113. {
  5114. HRESULT hr= E_FAIL;
  5115. HANDLE hMPSWabFile = NULL;
  5116. BOOL bFileLocked = FALSE;
  5117. ULONG j = 0;
  5118. ULONG i = 0,k=0;
  5119. LPMPSWab_FILE_INFO lpMPSWabFileInfo = (LPMPSWab_FILE_INFO) hPropertyStore;
  5120. DWORD dwNumofBytes = 0;
  5121. ULONG ulSize = 0;
  5122. LPGUID_NAMED_PROPS lpgnp = NULL;
  5123. ULONG ulcGUIDCount = 0;
  5124. LPBYTE szBuf = NULL;
  5125. LPBYTE lp = NULL;
  5126. if ((!lppgnp) ||
  5127. ( hPropertyStore == NULL) )
  5128. {
  5129. hr = MAPI_E_INVALID_PARAMETER;
  5130. DebugTrace(TEXT("Invalid Parameters\n"));
  5131. goto out;
  5132. }
  5133. *lppgnp = NULL;
  5134. *lpulcGUIDCount = 0;
  5135. if(!LockFileAccess(lpMPSWabFileInfo))
  5136. {
  5137. DebugTrace(TEXT("LockFileAccess Failed\n"));
  5138. hr = MAPI_E_NO_ACCESS;
  5139. goto out;
  5140. }
  5141. else
  5142. {
  5143. bFileLocked = TRUE;
  5144. }
  5145. //Open the file
  5146. hr = OpenWABFile(lpMPSWabFileInfo->lpszMPSWabFileName, NULL, &hMPSWabFile);
  5147. if ( (hMPSWabFile == INVALID_HANDLE_VALUE) ||
  5148. HR_FAILED(hr))
  5149. {
  5150. DebugTrace(TEXT("Could not open file.\nExiting ...\n"));
  5151. goto out;
  5152. }
  5153. //
  5154. // To ensure that file info is accurate,
  5155. // Any time we open a file, read the file info again ...
  5156. //
  5157. if(!ReloadMPSWabFileInfo(
  5158. lpMPSWabFileInfo,
  5159. hMPSWabFile))
  5160. {
  5161. DebugTrace(TEXT("Reading file info failed.\n"));
  5162. goto out;
  5163. }
  5164. //
  5165. // First we need to figure out how much space we need to save the named
  5166. // properties structure
  5167. //
  5168. ulSize = lpMPSWabFileInfo->lpMPSWabFileHeader->NamedPropData.AllocatedBlockSize;
  5169. ulcGUIDCount = lpMPSWabFileInfo->lpMPSWabFileHeader->NamedPropData.ulcNumEntries;
  5170. // Now the file is big enough, create the memory block for the named props
  5171. // and fill the block with the given Data
  5172. szBuf = LocalAlloc(LMEM_ZEROINIT, ulSize);
  5173. if(!szBuf)
  5174. {
  5175. DebugTrace(TEXT("LocalAlloc failed\n"));
  5176. goto out;
  5177. }
  5178. if(!ReadDataFromWABFile(hMPSWabFile,
  5179. lpMPSWabFileInfo->lpMPSWabFileHeader->NamedPropData.ulOffset,
  5180. (LPVOID) szBuf,
  5181. ulSize))
  5182. goto out;
  5183. if(!GetNamedPropsFromBuffer(szBuf, ulcGUIDCount, FALSE, lppgnp))
  5184. goto out;
  5185. *lpulcGUIDCount = ulcGUIDCount;
  5186. // done
  5187. hr = S_OK;
  5188. out:
  5189. if(HR_FAILED(hr))
  5190. {
  5191. FreeGuidnamedprops(ulcGUIDCount, lpgnp);
  5192. }
  5193. LocalFreeAndNull(&szBuf);
  5194. if(hMPSWabFile)
  5195. IF_WIN32(CloseHandle(hMPSWabFile);) IF_WIN16(CloseFile(hMPSWabFile);)
  5196. if (bFileLocked)
  5197. UnLockFileAccess(lpMPSWabFileInfo);
  5198. return hr;
  5199. }
  5200. /*
  5201. - SetNamedPropsToBuffer
  5202. -
  5203. *
  5204. */
  5205. BOOL SetNamedPropsToBuffer( ULONG ulcGUIDCount,
  5206. LPGUID_NAMED_PROPS lpgnp,
  5207. ULONG * lpulSize,
  5208. LPBYTE * lpp)
  5209. {
  5210. ULONG ulSize = 0, i =0, j=0;
  5211. LPBYTE szBuf = NULL, lp = NULL;
  5212. //
  5213. // First we need to figure out how much space we need to save the named
  5214. // properties structure
  5215. //
  5216. ulSize = 0;
  5217. for(i=0;i<ulcGUIDCount;i++)
  5218. {
  5219. if(lpgnp[i].lpGUID)
  5220. {
  5221. ulSize += sizeof(GUID); // for GUID
  5222. ulSize += sizeof(ULONG); // for cValues
  5223. for(j=0;j<lpgnp[i].cValues;j++)
  5224. {
  5225. ulSize += sizeof(ULONG); //saves PropTag
  5226. if(lpgnp[i].lpnm[j].lpsz)
  5227. {
  5228. ulSize += sizeof(ULONG); //saves lstrlen
  5229. ulSize += sizeof(TCHAR)*(lstrlen(lpgnp[i].lpnm[j].lpsz)+1);
  5230. }
  5231. }
  5232. }
  5233. }
  5234. // Now the file is big enough, create the memory block for the named props
  5235. // and fill the block with the given Data
  5236. szBuf = LocalAlloc(LMEM_ZEROINIT, ulSize);
  5237. if(!szBuf)
  5238. {
  5239. DebugTrace(TEXT("LocalAlloc failed\n"));
  5240. goto out;
  5241. }
  5242. lp = szBuf;
  5243. for(i=0;i<ulcGUIDCount;i++)
  5244. {
  5245. if(lpgnp[i].lpGUID)
  5246. {
  5247. CopyMemory(lp, lpgnp[i].lpGUID, sizeof(GUID));
  5248. lp += sizeof(GUID); // for GUID
  5249. CopyMemory(lp, &(lpgnp[i].cValues), sizeof(ULONG));
  5250. lp += sizeof(ULONG); // for cValues
  5251. for(j=0;j<lpgnp[i].cValues;j++)
  5252. {
  5253. ULONG nLen;
  5254. CopyMemory(lp, &(lpgnp[i].lpnm[j].ulPropTag), sizeof(ULONG));
  5255. lp += sizeof(ULONG); //saves PropTag
  5256. // This assumes that there is always a string to save
  5257. nLen = sizeof(TCHAR)*(lstrlen(lpgnp[i].lpnm[j].lpsz)+1);
  5258. CopyMemory(lp, &nLen, sizeof(ULONG));
  5259. lp += sizeof(ULONG); //saves lstrlen
  5260. CopyMemory(lp, lpgnp[i].lpnm[j].lpsz, nLen);
  5261. lp += nLen;
  5262. }
  5263. }
  5264. }
  5265. *lpp = szBuf;
  5266. *lpulSize = ulSize;
  5267. return TRUE;
  5268. out:
  5269. if(szBuf)
  5270. LocalFree(szBuf);
  5271. return FALSE;
  5272. }
  5273. //$$////////////////////////////////////////////////////////////////////////
  5274. ////
  5275. //// SetNamedPropsToPropStore -
  5276. ////
  5277. //// Used for writing the named props to the property store
  5278. //// The input lpgnp pointer contents will overwrite whatever exists in the
  5279. //// property store hence this should be used to replace not to add.
  5280. //// For each application GUID, there can be any number of properties
  5281. //// The number of application GUIDs is stored in the
  5282. //// FileHeader.NamedPropData.ulcNumEntries field. The actual data is of the
  5283. //// form:
  5284. //// GUID.#-of-Named-Prop-Tags.proptag.strlen.string.proptag.strlen.string etc.
  5285. ////
  5286. //// This function will grow the property store as needed to fit the given
  5287. //// data.
  5288. ////
  5289. //// IN hPropertyStore - handle to the property store
  5290. //// IN ulcGUIDCount - number of different GUIDs in the lpgnp array
  5291. //// IN lpgnp - LPGUID_NAMED_PROP structure array
  5292. ////////////////////////////////////////////////////////////////////////////
  5293. HRESULT SetNamedPropsToPropStore( IN HANDLE hPropertyStore,
  5294. IN ULONG ulcGUIDCount,
  5295. OUT LPGUID_NAMED_PROPS lpgnp)
  5296. {
  5297. HRESULT hr= E_FAIL;
  5298. HANDLE hMPSWabFile = NULL;
  5299. BOOL bFileLocked = FALSE;
  5300. ULONG j = 0;
  5301. ULONG i = 0,k=0;
  5302. LPMPSWab_FILE_INFO lpMPSWabFileInfo = (LPMPSWab_FILE_INFO) hPropertyStore;
  5303. DWORD dwNumofBytes = 0;
  5304. ULONG ulSize = 0;
  5305. LPBYTE szBuf = NULL;
  5306. LPBYTE lp = NULL;
  5307. DebugTrace(TEXT("\tSetNamedPropsToPropStore: Entry\n"));
  5308. if ((!lpgnp) ||
  5309. (lpgnp && !ulcGUIDCount) ||
  5310. ( hPropertyStore == NULL) )
  5311. {
  5312. hr = MAPI_E_INVALID_PARAMETER;
  5313. DebugTrace(TEXT("Invalid Parameters\n"));
  5314. goto out;
  5315. }
  5316. if(!LockFileAccess(lpMPSWabFileInfo))
  5317. {
  5318. DebugTrace(TEXT("LockFileAccess Failed\n"));
  5319. hr = MAPI_E_NO_ACCESS;
  5320. goto out;
  5321. }
  5322. else
  5323. {
  5324. bFileLocked = TRUE;
  5325. }
  5326. //Open the file
  5327. hr = OpenWABFile(lpMPSWabFileInfo->lpszMPSWabFileName, NULL, &hMPSWabFile);
  5328. if ( (hMPSWabFile == INVALID_HANDLE_VALUE) ||
  5329. HR_FAILED(hr))
  5330. {
  5331. DebugTrace(TEXT("Could not open file.\nExiting ...\n"));
  5332. goto out;
  5333. }
  5334. //
  5335. // To ensure that file info is accurate,
  5336. // Any time we open a file, read the file info again ...
  5337. //
  5338. if(!ReloadMPSWabFileInfo(
  5339. lpMPSWabFileInfo,
  5340. hMPSWabFile))
  5341. {
  5342. DebugTrace(TEXT("Reading file info failed.\n"));
  5343. goto out;
  5344. }
  5345. if(!SetNamedPropsToBuffer(ulcGUIDCount, lpgnp,
  5346. &ulSize, &szBuf))
  5347. goto out;
  5348. // We now know we need ulSize bytes of space.
  5349. // Do we have this much space in the store ? if not, grow the store
  5350. while(lpMPSWabFileInfo->lpMPSWabFileHeader->NamedPropData.AllocatedBlockSize < ulSize)
  5351. {
  5352. if (!CompressFile( lpMPSWabFileInfo,
  5353. hMPSWabFile,
  5354. NULL,
  5355. TRUE,
  5356. AB_GROW_NAMEDPROP))
  5357. {
  5358. DebugTrace(TEXT("Growing the file failed\n"));
  5359. goto out;
  5360. }
  5361. if(!ReloadMPSWabFileInfo(
  5362. lpMPSWabFileInfo,
  5363. hMPSWabFile))
  5364. {
  5365. DebugTrace(TEXT("Reading file info failed.\n"));
  5366. goto out;
  5367. }
  5368. }
  5369. //
  5370. // Write this buffer into the file
  5371. //
  5372. if(!WriteDataToWABFile( hMPSWabFile,
  5373. lpMPSWabFileInfo->lpMPSWabFileHeader->NamedPropData.ulOffset,
  5374. (LPVOID) szBuf,
  5375. ulSize))
  5376. goto out;
  5377. //
  5378. // Update the file header and write it
  5379. //
  5380. lpMPSWabFileInfo->lpMPSWabFileHeader->NamedPropData.UtilizedBlockSize = ulSize;
  5381. lpMPSWabFileInfo->lpMPSWabFileHeader->NamedPropData.ulcNumEntries = ulcGUIDCount;
  5382. if(!WriteDataToWABFile( hMPSWabFile,
  5383. 0,
  5384. (LPVOID) lpMPSWabFileInfo->lpMPSWabFileHeader,
  5385. sizeof(MPSWab_FILE_HEADER)))
  5386. goto out;
  5387. // done
  5388. hr = S_OK;
  5389. out:
  5390. LocalFreeAndNull(&szBuf);
  5391. if(hMPSWabFile)
  5392. IF_WIN32(CloseHandle(hMPSWabFile);) IF_WIN16(CloseFile(hMPSWabFile);)
  5393. if (bFileLocked)
  5394. UnLockFileAccess(lpMPSWabFileInfo);
  5395. //DebugTrace(TEXT("//////////\nSetNamedPropsToPropStore: Exit\n"));
  5396. return hr;
  5397. }
  5398. /*
  5399. -
  5400. - GetOutlookRefreshCountData
  5401. *
  5402. * Outlook notifications are a bit funky in that Outlook sets an event and the first
  5403. * WAB process to get that event resets it to the mutual exclusion of all other WAB
  5404. * processes ... so we do an event count through the registry .. each process will make
  5405. * a registry check of the latest event count and fire a refresh if their copy is older
  5406. * than the count in the registry
  5407. */
  5408. static const LPTSTR lpOlkContactRefresh = TEXT("OlkContactRefresh");
  5409. static const LPTSTR lpOlkFolderRefresh = TEXT("OlkFolderRefresh");
  5410. void GetOutlookRefreshCountData(LPDWORD lpdwOlkRefreshCount,LPDWORD lpdwOlkFolderRefreshCount)
  5411. {
  5412. HKEY hKey = NULL;
  5413. DWORD dwDisposition = 0,dwSize = 0,dwType = 0;
  5414. // begin registry stuff
  5415. if (ERROR_SUCCESS != RegCreateKeyEx(HKEY_CURRENT_USER, lpNewWABRegKey, 0, //reserved
  5416. NULL, REG_OPTION_NON_VOLATILE, KEY_READ,
  5417. NULL, &hKey, &dwDisposition))
  5418. {
  5419. goto exit;
  5420. }
  5421. dwSize = sizeof(DWORD);
  5422. dwType = REG_DWORD;
  5423. RegQueryValueEx(hKey,lpOlkContactRefresh,NULL,&dwType,(LPBYTE)lpdwOlkRefreshCount, &dwSize);
  5424. dwSize = sizeof(DWORD);
  5425. dwType = REG_DWORD;
  5426. RegQueryValueEx(hKey,lpOlkFolderRefresh,NULL,&dwType,(LPBYTE)lpdwOlkFolderRefreshCount, &dwSize);
  5427. exit:
  5428. if(hKey)
  5429. RegCloseKey(hKey);
  5430. }
  5431. /*
  5432. -
  5433. - SetOutlookRefreshCountData
  5434. *
  5435. */
  5436. void SetOutlookRefreshCountData(DWORD dwOlkRefreshCount,DWORD dwOlkFolderRefreshCount)
  5437. {
  5438. HKEY hKey = NULL;
  5439. DWORD dwDisposition = 0,dwSize = 0;
  5440. // begin registry stuff
  5441. if (ERROR_SUCCESS != RegCreateKeyEx(HKEY_CURRENT_USER, lpNewWABRegKey, 0, //reserved
  5442. NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS,
  5443. NULL, &hKey, &dwDisposition))
  5444. {
  5445. goto exit;
  5446. }
  5447. dwSize = sizeof(DWORD);
  5448. RegSetValueEx(hKey,lpOlkContactRefresh, 0, REG_DWORD, (LPBYTE)&dwOlkRefreshCount, dwSize);
  5449. RegSetValueEx(hKey,lpOlkFolderRefresh, 0, REG_DWORD, (LPBYTE)&dwOlkFolderRefreshCount, dwSize);
  5450. exit:
  5451. if(hKey)
  5452. RegCloseKey(hKey);
  5453. }
  5454. /*
  5455. -
  5456. - Copies a set of container info from Outlook to the WAB
  5457. *
  5458. * The difference is that Outlook always returns ANSI while WAB may
  5459. * want Unicode in some cases
  5460. *
  5461. */
  5462. void ConvertOlkConttoWABCont(ULONG * lpcolk, OutlookContInfo ** lprgolk,
  5463. ULONG * lpcolkci, OlkContInfo ** lprgolkci)
  5464. {
  5465. ULONG i = 0;
  5466. SCODE sc = S_OK;
  5467. ULONG cVal = *lpcolk;
  5468. OlkContInfo * rgolkci = NULL;
  5469. if(!(sc = MAPIAllocateBuffer(sizeof(OlkContInfo)*(cVal), &rgolkci)))
  5470. {
  5471. for(i = 0; i < *lpcolk ; i++)
  5472. {
  5473. if(!(sc = MAPIAllocateMore(sizeof(SBinary), rgolkci, (LPVOID*)(&rgolkci[i].lpEntryID))))
  5474. {
  5475. rgolkci[i].lpEntryID->cb = ((*lprgolk)[i]).lpEntryID->cb;
  5476. if(!(sc = MAPIAllocateMore(rgolkci[i].lpEntryID->cb, rgolkci, (LPVOID*)(&(rgolkci[i].lpEntryID->lpb)))))
  5477. {
  5478. CopyMemory(rgolkci[i].lpEntryID->lpb, ((*lprgolk)[i]).lpEntryID->lpb, rgolkci[i].lpEntryID->cb);
  5479. }
  5480. }
  5481. sc = ScAnsiToWCMore((LPALLOCATEMORE) (&MAPIAllocateMore), rgolkci,((*lprgolk)[i]).lpszName, &rgolkci[i].lpszName);
  5482. }
  5483. }
  5484. *lpcolkci = *lpcolk;
  5485. *lprgolkci = rgolkci;
  5486. }
  5487. /***************************************************************************
  5488. Name : CheckChangedWAB
  5489. Purpose : Has the file been written since we last checked?
  5490. Parameters: hPropertyStore = open property store handle
  5491. lpftLast -> Last file time for this dialog
  5492. Returns : TRUE if property store has changed since last check
  5493. Comment : The first time this function is called is regarded as
  5494. initialization and will always return FALSE.
  5495. ***************************************************************************/
  5496. BOOL CheckChangedWAB(LPPROPERTY_STORE lpPropertyStore, HANDLE hMutex,
  5497. LPDWORD lpdwContact, LPDWORD lpdwFolder, LPFILETIME lpftLast)
  5498. {
  5499. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  5500. BOOL fChanged = FALSE;
  5501. HANDLE hPropertyStore = lpPropertyStore->hPropertyStore;
  5502. if(!pt_bIsWABOpenExSession)
  5503. {
  5504. LPMPSWab_FILE_INFO lpMPSWabFileInfo = (LPMPSWab_FILE_INFO)hPropertyStore;
  5505. HANDLE hFind = INVALID_HANDLE_VALUE;
  5506. WIN32_FIND_DATA FindData;
  5507. if (lpMPSWabFileInfo) {
  5508. if (INVALID_HANDLE_VALUE == (hFind = FindFirstFile(
  5509. lpMPSWabFileInfo->lpszMPSWabFileName, // pointer to name of file to search for
  5510. &FindData))) {
  5511. DebugTrace(TEXT("CheckWABRefresh:FindFirstFile -> %u\n"), GetLastError());
  5512. } else {
  5513. if (lpftLast->dwHighDateTime < FindData.ftLastWriteTime.dwHighDateTime ||
  5514. (lpftLast->dwHighDateTime == FindData.ftLastWriteTime.dwHighDateTime &&
  5515. lpftLast->dwLowDateTime < FindData.ftLastWriteTime.dwLowDateTime)) {
  5516. fChanged = TRUE;
  5517. if (lpftLast->dwLowDateTime == 0 && lpftLast->dwHighDateTime == 0) {
  5518. fChanged = FALSE;
  5519. }
  5520. *lpftLast = FindData.ftLastWriteTime;
  5521. }
  5522. FindClose(hFind);
  5523. }
  5524. }
  5525. }
  5526. else
  5527. {
  5528. // WABOpenEx Session (ie Outlook session)
  5529. // Check our 2 events to see if anything needs updating
  5530. BOOL fContact = FALSE, fFolders = FALSE;
  5531. DWORD dwContact = 0, dwFolder = 0;
  5532. if(WAIT_OBJECT_0 == WaitForSingleObject(hMutex,0))
  5533. {
  5534. if(WAIT_OBJECT_0 == WaitForSingleObject(ghEventOlkRefreshContacts, 0))
  5535. fContact = TRUE;
  5536. if(WAIT_OBJECT_0 == WaitForSingleObject(ghEventOlkRefreshFolders, 0))
  5537. fFolders = TRUE;
  5538. if(!fContact && !fFolders)
  5539. {
  5540. // Didn't catch an event .. check if we missed any in the past by looking at the registry settings
  5541. GetOutlookRefreshCountData(&dwContact,&dwFolder);
  5542. if(*lpdwContact < dwContact)
  5543. {
  5544. fContact = TRUE;
  5545. *lpdwContact = dwContact;
  5546. }
  5547. if(*lpdwFolder < dwFolder)
  5548. {
  5549. fFolders = TRUE;
  5550. *lpdwFolder = dwFolder;
  5551. }
  5552. }
  5553. else
  5554. {
  5555. //Caught an event .. update the registry
  5556. if(fContact)
  5557. {
  5558. DebugTrace(TEXT("####>> Got Outlook Contact Refresh Event\n"));
  5559. ResetEvent(ghEventOlkRefreshContacts);
  5560. }
  5561. if(fFolders)
  5562. {
  5563. DebugTrace(TEXT("####>> Got Outlook Folder Refresh Event\n"));
  5564. ResetEvent(ghEventOlkRefreshFolders);
  5565. }
  5566. GetOutlookRefreshCountData(&dwContact,&dwFolder);
  5567. *lpdwContact = dwContact + (fContact ? 1 : 0);
  5568. *lpdwFolder = dwFolder + (fFolders ? 1 : 0);
  5569. SetOutlookRefreshCountData(*lpdwContact, *lpdwFolder);
  5570. }
  5571. if(fContact)
  5572. {
  5573. SYSTEMTIME st = {0};
  5574. GetSystemTime(&st);
  5575. SystemTimeToFileTime(&st, lpftLast);
  5576. }
  5577. if(fFolders)
  5578. {
  5579. // Need to specifically update the folders list in the rgolkci ..
  5580. LPWABSTORAGEPROVIDER lpWSP = (LPWABSTORAGEPROVIDER) hPropertyStore;
  5581. HRESULT hr = E_FAIL;
  5582. ULONG colk = 0;
  5583. OutlookContInfo * rgolk = NULL;
  5584. FreeBufferAndNull(&(lpPropertyStore->rgolkci));
  5585. hr = lpWSP->lpVtbl->GetContainerList(lpWSP, &colk, &rgolk);
  5586. if(!HR_FAILED(hr))
  5587. {
  5588. DebugTrace(TEXT("WABStorageProvider::GetContainerList returns:%x\n"),hr);
  5589. ConvertOlkConttoWABCont(&colk, &rgolk, &lpPropertyStore->colkci, &lpPropertyStore->rgolkci);
  5590. FreeBufferAndNull(&rgolk);
  5591. }
  5592. }
  5593. fChanged = fContact | fFolders;
  5594. ReleaseMutex(hMutex);
  5595. }
  5596. }
  5597. return(fChanged);
  5598. }
  5599. /***************************************************************************
  5600. Name : FreeEntryIDs
  5601. Purpose : Frees any LPSBinary structures allocated and returned
  5602. by funtions in thie file (e.g. WriteRecord, etc)
  5603. Parameters: lpsbEID - SBinary structure containing an entryid
  5604. Returns : void
  5605. ***************************************************************************/
  5606. HRESULT FreeEntryIDs(IN HANDLE hPropertyStore,
  5607. IN ULONG ulCount,
  5608. IN LPSBinary rgsbEIDs)
  5609. {
  5610. ULONG i = 0;
  5611. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  5612. if(pt_bIsWABOpenExSession)
  5613. {
  5614. // This is a WABOpenEx session using outlooks storage provider
  5615. if(!hPropertyStore)
  5616. return MAPI_E_NOT_INITIALIZED;
  5617. {
  5618. LPWABSTORAGEPROVIDER lpWSP = (LPWABSTORAGEPROVIDER) hPropertyStore;
  5619. HRESULT hr = E_FAIL;
  5620. hr = lpWSP->lpVtbl->FreeEntryIDs( lpWSP,
  5621. ulCount,
  5622. rgsbEIDs);
  5623. DebugTrace(TEXT("WABStorageProvider::FreeEntryIDs returned:%x\n"),hr);
  5624. return hr;
  5625. }
  5626. }
  5627. if(ulCount && rgsbEIDs)
  5628. {
  5629. for(i=0;i<ulCount;i++)
  5630. LocalFree(rgsbEIDs[i].lpb);
  5631. LocalFree(rgsbEIDs);
  5632. }
  5633. return S_OK;
  5634. }
  5635. const LPTSTR szOutlook = TEXT("Outlook Contact Store");
  5636. //$$////////////////////////////////////////////////////////////////////////
  5637. ////
  5638. //// GetWABFileName()
  5639. ////
  5640. //// If this is a WAB File then returns a pointer to the file name
  5641. //// If running against outlook, returns szEmpty
  5642. //// Caller should not free this
  5643. ////////////////////////////////////////////////////////////////////////////
  5644. LPTSTR GetWABFileName(IN HANDLE hPropertyStore, BOOL bRetOutlookStr)
  5645. {
  5646. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  5647. LPMPSWab_FILE_INFO lpMPSWabFileInfo = (LPMPSWab_FILE_INFO) hPropertyStore;
  5648. if(pt_bIsWABOpenExSession)
  5649. {
  5650. return (bRetOutlookStr ? szOutlook : szEmpty);
  5651. }
  5652. return lpMPSWabFileInfo->lpszMPSWabFileName;
  5653. }
  5654. //$$////////////////////////////////////////////////////////////////////////
  5655. ////
  5656. //// GetWABFileEntryCount() - returns actual number of entries in a WAB
  5657. /// This number includes all contacts, groups, and foldesr
  5658. ////
  5659. ////////////////////////////////////////////////////////////////////////////
  5660. DWORD GetWABFileEntryCount(IN HANDLE hPropertyStore)
  5661. {
  5662. LPMPSWab_FILE_INFO lpMPSWabFileInfo = (LPMPSWab_FILE_INFO) hPropertyStore;
  5663. return lpMPSWabFileInfo->lpMPSWabFileHeader->ulcNumEntries;
  5664. }
  5665. //$$////////////////////////////////////////////////////////////////////////////
  5666. //
  5667. // LocalFreePropArray - Frees an SPropValue structure allocated using LocalAlloc
  5668. // instead of MAPIAllocateBuffer.
  5669. //
  5670. // When called internally from property store functions, hPropertyStore can be
  5671. // NULL ...
  5672. // If this is a Outlook session and there is a hPropertyStore then we release through
  5673. // Outlook.
  5674. // If there is no hPropertyStore then this was locally allocated memory when we
  5675. // LocalFree ...
  5676. //
  5677. ////////////////////////////////////////////////////////////////////////////////
  5678. void LocalFreePropArray(HANDLE hPropertyStore, ULONG ulcPropCount, LPPROPERTY_ARRAY * lppPropArray)
  5679. {
  5680. ULONG i=0,j=0,k=0;
  5681. LPSPropValue lpPropArray = *lppPropArray;
  5682. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  5683. if(!lpPropArray || !ulcPropCount)
  5684. goto out;
  5685. if(pt_bIsWABOpenExSession && hPropertyStore)
  5686. {
  5687. // This is a WABOpenEx session using outlooks storage provider
  5688. {
  5689. LPWABSTORAGEPROVIDER lpWSP = (LPWABSTORAGEPROVIDER) hPropertyStore;
  5690. HRESULT hr = E_FAIL;
  5691. hr = lpWSP->lpVtbl->FreePropArray( lpWSP,
  5692. ulcPropCount,
  5693. *lppPropArray);
  5694. DebugTrace(TEXT("WABStorageProvider::FreePropArray returned:%x\n"),hr);
  5695. *lppPropArray = NULL;
  5696. return;
  5697. }
  5698. }
  5699. for(i = 0; i<ulcPropCount;i++)
  5700. {
  5701. // we only care to free the sub-level pointers which we
  5702. // might have allocated
  5703. switch(PROP_TYPE(lpPropArray[i].ulPropTag))
  5704. {
  5705. case PT_CLSID:
  5706. LocalFreeAndNull((LPVOID *) (&(lpPropArray[i].Value.lpguid)));
  5707. break;
  5708. case PT_STRING8:
  5709. if (lpPropArray[i].Value.lpszA)// && lpPropArray[i].Value.lpszA != szEmpty)
  5710. LocalFreeAndNull((LPVOID *) (&(lpPropArray[i].Value.lpszA)));
  5711. break;
  5712. case PT_UNICODE:
  5713. if (lpPropArray[i].Value.lpszW && lpPropArray[i].Value.lpszW != szEmpty)
  5714. LocalFreeAndNull((LPVOID *) (&(lpPropArray[i].Value.lpszW)));
  5715. break;
  5716. case PT_BINARY:
  5717. if (lpPropArray[i].Value.bin.cb)
  5718. LocalFreeAndNull((LPVOID *) (&(lpPropArray[i].Value.bin.lpb)));
  5719. break;
  5720. case PT_MV_STRING8:
  5721. j = lpPropArray[i].Value.MVszA.cValues;
  5722. for(k = 0; k < j; k++)
  5723. {
  5724. if (lpPropArray[i].Value.MVszA.lppszA[k])// && lpPropArray[i].Value.MVszA.lppszA[k] != szEmpty)
  5725. LocalFreeAndNull((LPVOID *) (&(lpPropArray[i].Value.MVszA.lppszA[k])));
  5726. }
  5727. LocalFree(lpPropArray[i].Value.MVszA.lppszA);
  5728. break;
  5729. case PT_MV_UNICODE:
  5730. j = lpPropArray[i].Value.MVszW.cValues;
  5731. for(k = 0; k < j; k++)
  5732. {
  5733. if (lpPropArray[i].Value.MVszW.lppszW[k] && lpPropArray[i].Value.MVszW.lppszW[k] != szEmpty)
  5734. LocalFreeAndNull((LPVOID *) (&(lpPropArray[i].Value.MVszW.lppszW[k])));
  5735. }
  5736. LocalFree(lpPropArray[i].Value.MVszW.lppszW);
  5737. break;
  5738. case PT_MV_BINARY:
  5739. j = lpPropArray[i].Value.MVbin.cValues;
  5740. for(k = 0; k < j; k++)
  5741. {
  5742. LocalFreeAndNull((LPVOID *) (&(lpPropArray[i].Value.MVbin.lpbin[k].lpb)));
  5743. }
  5744. LocalFree(lpPropArray[i].Value.MVbin.lpbin);
  5745. break;
  5746. case(PT_MV_I2):
  5747. case(PT_MV_LONG):
  5748. case(PT_MV_R4):
  5749. case(PT_MV_DOUBLE):
  5750. case(PT_MV_CURRENCY):
  5751. case(PT_MV_APPTIME):
  5752. case(PT_MV_SYSTIME):
  5753. case(PT_MV_CLSID):
  5754. case(PT_MV_I8):
  5755. LocalFree(lpPropArray[i].Value.MVi.lpi);
  5756. break;
  5757. default:
  5758. break;
  5759. }
  5760. }
  5761. LocalFreeAndNull((LPVOID *) (lppPropArray)); // yes, no &
  5762. out:
  5763. return;
  5764. }
  5765. //$$///////////////////////////////////////////////////////////////////////////
  5766. //
  5767. //
  5768. // FreePcontentlist is used to free LPCONTENTLIST structures
  5769. // Even though the LPCONTENTLIST is exactly the same as LPADRLIST
  5770. // there is a difference in how the 2 are created with the former
  5771. // being created using LocalAlloc and the latter thru MAPIAllocateBuffer
  5772. //
  5773. //
  5774. /////////////////////////////////////////////////////////////////////////////
  5775. void FreePcontentlist(HANDLE hPropertyStore,
  5776. IN OUT LPCONTENTLIST lpContentList)
  5777. {
  5778. ULONG i=0;
  5779. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  5780. if(pt_bIsWABOpenExSession)
  5781. {
  5782. // This is a WABOpenEx session using outlooks storage provider
  5783. if(!hPropertyStore)
  5784. return;// MAPI_E_NOT_INITIALIZED;
  5785. {
  5786. LPWABSTORAGEPROVIDER lpWSP = (LPWABSTORAGEPROVIDER) hPropertyStore;
  5787. HRESULT hr = E_FAIL;
  5788. hr = lpWSP->lpVtbl->FreeContentList(lpWSP,
  5789. lpContentList);
  5790. DebugTrace(TEXT("WABStorageProvider::FreeContentList returned:%x\n"),hr);
  5791. return;
  5792. }
  5793. }
  5794. if (!lpContentList) goto out;
  5795. for (i=0;i<lpContentList->cEntries;i++)
  5796. {
  5797. if (lpContentList->aEntries[i].rgPropVals)
  5798. LocalFreePropArray(hPropertyStore, lpContentList->aEntries[i].cValues, (LPPROPERTY_ARRAY *) (&(lpContentList->aEntries[i].rgPropVals)));
  5799. }
  5800. LocalFreeAndNull(&lpContentList);
  5801. out:
  5802. return;
  5803. }
  5804. /*
  5805. -
  5806. - GetFolderEIDs
  5807. -
  5808. * Returns a list of EIDs that are a member of a given folder
  5809. *
  5810. */
  5811. HRESULT GetFolderEIDs(HANDLE hMPSWabFile,
  5812. LPMPSWab_FILE_INFO lpMPSWabFileInfo,
  5813. LPSBinary pmbinFold,
  5814. ULONG * lpulFolderEIDs,
  5815. LPDWORD * lppdwFolderEIDs)
  5816. {
  5817. HRESULT hr = S_OK;
  5818. ULONG ulcPropCount = 0;
  5819. LPSPropValue lpPropArray = NULL;
  5820. DWORD dwEntryID = 0;
  5821. ULONG i = 0,j=0;
  5822. LPDWORD lpdwFolderEIDs = NULL;
  5823. SBinary sbEID = {0};
  5824. if(pmbinFold && pmbinFold->cb != SIZEOF_WAB_ENTRYID)
  5825. {
  5826. // this may be a WAB container .. reset the entryid to a WAB entryid
  5827. if(WAB_CONTAINER == IsWABEntryID(pmbinFold->cb, (LPENTRYID)pmbinFold->lpb,
  5828. NULL,NULL,NULL,NULL,NULL))
  5829. {
  5830. IsWABEntryID(pmbinFold->cb, (LPENTRYID)pmbinFold->lpb,
  5831. (LPVOID*)&sbEID.lpb,(LPVOID*)&sbEID.cb,NULL,NULL,NULL);
  5832. if(sbEID.cb == SIZEOF_WAB_ENTRYID)
  5833. pmbinFold = &sbEID;
  5834. }
  5835. }
  5836. if(!pmbinFold || pmbinFold->cb != SIZEOF_WAB_ENTRYID)
  5837. {
  5838. return MAPI_E_INVALID_PARAMETER;
  5839. }
  5840. CopyMemory(&dwEntryID, pmbinFold->lpb, min(pmbinFold->cb,sizeof(dwEntryID)));
  5841. if(HR_FAILED(hr = ReadRecordWithoutLocking( hMPSWabFile,
  5842. lpMPSWabFileInfo,
  5843. dwEntryID,
  5844. &ulcPropCount,
  5845. &lpPropArray)))
  5846. return hr;
  5847. for(i=0;i<ulcPropCount;i++)
  5848. {
  5849. if(lpPropArray[i].ulPropTag == PR_WAB_FOLDER_ENTRIES)
  5850. {
  5851. *lpulFolderEIDs = lpPropArray[i].Value.MVbin.cValues;
  5852. if(*lpulFolderEIDs)
  5853. {
  5854. lpdwFolderEIDs = LocalAlloc(LMEM_ZEROINIT, *lpulFolderEIDs * sizeof(DWORD));
  5855. if(lpdwFolderEIDs)
  5856. {
  5857. for(j=0;j<*lpulFolderEIDs;j++)
  5858. {
  5859. CopyMemory(&(lpdwFolderEIDs[j]), lpPropArray[i].Value.MVbin.lpbin[j].lpb, min(lpPropArray[i].Value.MVbin.lpbin[j].cb, sizeof(lpdwFolderEIDs[0])));
  5860. }
  5861. }
  5862. }
  5863. break;
  5864. }
  5865. }
  5866. if(*lpulFolderEIDs && lpdwFolderEIDs)
  5867. *lppdwFolderEIDs = lpdwFolderEIDs;
  5868. LocalFreePropArray(NULL, ulcPropCount, &lpPropArray);
  5869. return S_OK;
  5870. }
  5871. /*
  5872. -
  5873. - bIsFolderMember
  5874. -
  5875. * Returns TRUE if specified entry is a member of a folder
  5876. *
  5877. */
  5878. BOOL bIsFolderMember(HANDLE hMPSWabFile,
  5879. LPMPSWab_FILE_INFO lpMPSWabFileInfo,
  5880. DWORD dwEntryID, ULONG * lpulObjType)
  5881. {
  5882. BOOL bRet = FALSE;
  5883. ULONG ulRecordOffset = 0;
  5884. ULONG nIndexPos = 0;
  5885. ULONG * lpulPropTags = NULL;
  5886. //
  5887. // First check if this is a valid entryID
  5888. //
  5889. if (!BinSearchEID( IN lpMPSWabFileInfo->lpMPSWabIndexEID,
  5890. IN dwEntryID,
  5891. IN lpMPSWabFileInfo->lpMPSWabFileHeader->IndexData[indexEntryID].ulcNumEntries,
  5892. OUT &nIndexPos))
  5893. {
  5894. DebugTrace(TEXT("Specified EntryID doesnt exist!\n"));
  5895. goto out;
  5896. }
  5897. //if entryid exists, we can start reading the record
  5898. ulRecordOffset = lpMPSWabFileInfo->lpMPSWabIndexEID[nIndexPos].ulOffset;
  5899. {
  5900. MPSWab_RECORD_HEADER MPSWabRecordHeader = {0};
  5901. DWORD dwNumofBytes = 0;
  5902. ULONG i = 0;
  5903. if(!ReadDataFromWABFile(hMPSWabFile,
  5904. ulRecordOffset,
  5905. (LPVOID) &MPSWabRecordHeader,
  5906. (DWORD) sizeof(MPSWab_RECORD_HEADER)))
  5907. goto out;
  5908. if(lpulObjType)
  5909. *lpulObjType = MPSWabRecordHeader.ulObjType;
  5910. lpulPropTags = LocalAlloc(LMEM_ZEROINIT, MPSWabRecordHeader.ulcPropCount * sizeof(ULONG));
  5911. if(!lpulPropTags)
  5912. {
  5913. DebugTrace(TEXT("Error allocating memory\n"));
  5914. goto out;
  5915. }
  5916. //Read in the data
  5917. if(!ReadFile( hMPSWabFile,
  5918. (LPVOID) lpulPropTags,
  5919. (DWORD) MPSWabRecordHeader.ulPropTagArraySize,
  5920. &dwNumofBytes,
  5921. NULL))
  5922. {
  5923. DebugTrace(TEXT("Reading Record Header failed.\n"));
  5924. goto out;
  5925. }
  5926. for(i=0;i<MPSWabRecordHeader.ulcPropCount;i++)
  5927. {
  5928. if(lpulPropTags[i] == PR_WAB_FOLDER_PARENT || lpulPropTags[i] == PR_WAB_FOLDER_PARENT_OLDPROP)
  5929. {
  5930. bRet = TRUE;
  5931. break;
  5932. }
  5933. }
  5934. }
  5935. out:
  5936. if(lpulPropTags)
  5937. LocalFree(lpulPropTags);
  5938. return bRet;
  5939. }
  5940. /*
  5941. -
  5942. - ConvertWCPropsToALocalAlloc()
  5943. -
  5944. * Takes a SPropValue array and converts Unicode strings to ANSI equivalents
  5945. * Uses LocalAlloc for the new strings .. unlike the ScWCtoAnsiMore which uses the
  5946. * internal memory allocators
  5947. */
  5948. void ConvertWCPropsToALocalAlloc(LPSPropValue lpProps, ULONG ulcValues)
  5949. {
  5950. ULONG i = 0, j = 0, ulCount = 0;
  5951. LPSTR * lppszA = NULL;
  5952. LPSTR lpszA = NULL;
  5953. for(i=0;i<ulcValues;i++)
  5954. {
  5955. switch(PROP_TYPE(lpProps[i].ulPropTag))
  5956. {
  5957. case PT_UNICODE:
  5958. lpszA = ConvertWtoA(lpProps[i].Value.lpszW);
  5959. LocalFreeAndNull((LPVOID *) (&lpProps[i].Value.lpszW));
  5960. lpProps[i].Value.lpszA = lpszA;
  5961. lpProps[i].ulPropTag = CHANGE_PROP_TYPE( lpProps[i].ulPropTag, PT_STRING8);
  5962. break;
  5963. case PT_MV_UNICODE:
  5964. ulCount = lpProps[i].Value.MVszW.cValues;
  5965. if(lppszA = LocalAlloc(LMEM_ZEROINIT, sizeof(LPSTR)*ulCount))
  5966. {
  5967. for(j=0;j<ulCount;j++)
  5968. {
  5969. lppszA[j] = ConvertWtoA(lpProps[i].Value.MVszW.lppszW[j]);
  5970. LocalFreeAndNull((LPVOID*)&(lpProps[i].Value.MVszW.lppszW[j]));
  5971. }
  5972. LocalFreeAndNull((LPVOID*)(&lpProps[i].Value.MVszW.lppszW));
  5973. lpProps[i].Value.MVszW.cValues = 0;
  5974. lpProps[i].Value.MVszA.cValues = ulCount;
  5975. lpProps[i].Value.MVszA.lppszA = lppszA;
  5976. lppszA = NULL;
  5977. lpProps[i].ulPropTag = CHANGE_PROP_TYPE( lpProps[i].ulPropTag, PT_MV_STRING8);
  5978. }
  5979. break;
  5980. }
  5981. }
  5982. }
  5983. /*
  5984. -
  5985. - ConvertAPropsToWCLocalAlloc()
  5986. -
  5987. * Takes a SPropValue array and converts Unicode strings to ANSI equivalents
  5988. * Uses LocalAlloc for the new strings .. unlike the ScWCtoAnsiMore which uses the
  5989. * internal memory allocators
  5990. */
  5991. void ConvertAPropsToWCLocalAlloc(LPSPropValue lpProps, ULONG ulcValues)
  5992. {
  5993. ULONG i = 0, j = 0, ulCount = 0;
  5994. LPWSTR * lppszW = NULL;
  5995. LPWSTR lpszW = NULL;
  5996. for(i=0;i<ulcValues;i++)
  5997. {
  5998. switch(PROP_TYPE(lpProps[i].ulPropTag))
  5999. {
  6000. case PT_STRING8:
  6001. lpszW = ConvertAtoW(lpProps[i].Value.lpszA);
  6002. LocalFreeAndNull((LPVOID *) (&lpProps[i].Value.lpszA));
  6003. lpProps[i].Value.lpszW = lpszW;
  6004. lpProps[i].ulPropTag = CHANGE_PROP_TYPE( lpProps[i].ulPropTag, PT_UNICODE);
  6005. break;
  6006. case PT_MV_STRING8:
  6007. ulCount = lpProps[i].Value.MVszA.cValues;
  6008. if(lppszW = LocalAlloc(LMEM_ZEROINIT, sizeof(LPWSTR)*ulCount))
  6009. {
  6010. for(j=0;j<ulCount;j++)
  6011. {
  6012. lppszW[j] = ConvertAtoW(lpProps[i].Value.MVszA.lppszA[j]);
  6013. LocalFreeAndNull((LPVOID *) (&lpProps[i].Value.MVszA.lppszA[j]));
  6014. }
  6015. LocalFreeAndNull((LPVOID *)&(lpProps[i].Value.MVszW.lppszW));
  6016. lpProps[i].Value.MVszA.cValues = 0;
  6017. lpProps[i].Value.MVszW.cValues = ulCount;
  6018. lpProps[i].Value.MVszW.lppszW = lppszW;
  6019. lppszW = NULL;
  6020. lpProps[i].ulPropTag = CHANGE_PROP_TYPE( lpProps[i].ulPropTag, PT_MV_UNICODE);
  6021. }
  6022. break;
  6023. }
  6024. }
  6025. }