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.

2323 lines
79 KiB

  1. /*
  2. * ABCONT.C
  3. *
  4. * Generic IMAPIContainer implementation.
  5. *
  6. * Copyright 1992 - 1996 Microsoft Corporation. All Rights Reserved.
  7. */
  8. #include "_apipch.h"
  9. #ifdef WIN16
  10. #undef GetLastError
  11. #endif
  12. static HRESULT
  13. HrGetFirstRowInTad(LPTABLEDATA lpTableData,
  14. LPTABLEINFO lpTableInfo,
  15. ULONG ulcTableInfo,
  16. ULONG uliTable,
  17. ULONG * puliRow);
  18. static HRESULT
  19. HrGetLastRowInTad(LPTABLEDATA lpTableData,
  20. LPTABLEINFO lpTableInfo,
  21. ULONG ulcTableInfo,
  22. ULONG uliTable,
  23. ULONG * puliRow);
  24. OlkContInfo *FindContainer(LPIAB lpIAB, ULONG cbEntryID, LPENTRYID lpEID);
  25. NOTIFCALLBACK lHierarchyNotifCallBack;
  26. extern CONTAINER_Vtbl vtblROOT;
  27. extern CONTAINER_Vtbl vtblLDAPCONT;
  28. extern HRESULT HrSmartResolve(LPIAB lpIAB, LPABCONT lpContainer, ULONG ulFlags,
  29. LPADRLIST lpAdrList, LPFlagList lpFlagList, LPAMBIGUOUS_TABLES lpAmbiguousTables);
  30. // extern CONTAINER_Vtbl vtblDISTLIST;
  31. CONTAINER_Vtbl vtblCONTAINER = {
  32. VTABLE_FILL
  33. // (CONTAINER_QueryInterface_METHOD *) IAB_QueryInterface, //bug 2707:this crashes
  34. CONTAINER_QueryInterface,
  35. (CONTAINER_AddRef_METHOD *) WRAP_AddRef,
  36. CONTAINER_Release,
  37. (CONTAINER_GetLastError_METHOD *) IAB_GetLastError,
  38. (CONTAINER_SaveChanges_METHOD *) WRAP_SaveChanges,
  39. (CONTAINER_GetProps_METHOD *) WRAP_GetProps,
  40. (CONTAINER_GetPropList_METHOD *) WRAP_GetPropList,
  41. CONTAINER_OpenProperty,
  42. (CONTAINER_SetProps_METHOD *) WRAP_SetProps,
  43. (CONTAINER_DeleteProps_METHOD *) WRAP_DeleteProps,
  44. (CONTAINER_CopyTo_METHOD *) WRAP_CopyTo,
  45. (CONTAINER_CopyProps_METHOD *) WRAP_CopyProps,
  46. (CONTAINER_GetNamesFromIDs_METHOD *) WRAP_GetNamesFromIDs,
  47. CONTAINER_GetIDsFromNames,
  48. CONTAINER_GetContentsTable,
  49. CONTAINER_GetHierarchyTable,
  50. CONTAINER_OpenEntry,
  51. CONTAINER_SetSearchCriteria,
  52. CONTAINER_GetSearchCriteria,
  53. CONTAINER_CreateEntry,
  54. CONTAINER_CopyEntries,
  55. CONTAINER_DeleteEntries,
  56. CONTAINER_ResolveNames
  57. };
  58. //
  59. // Interfaces supported by this object
  60. //
  61. #define CONTAINER_cInterfaces 3
  62. LPIID CONTAINER_LPIID[CONTAINER_cInterfaces] =
  63. {
  64. (LPIID) &IID_IABContainer,
  65. (LPIID) &IID_IMAPIContainer,
  66. (LPIID) &IID_IMAPIProp
  67. };
  68. #define DISTLIST_cInterfaces 4
  69. LPIID DISTLIST_LPIID[DISTLIST_cInterfaces] =
  70. {
  71. (LPIID) &IID_IDistList,
  72. (LPIID) &IID_IABContainer,
  73. (LPIID) &IID_IMAPIContainer,
  74. (LPIID) &IID_IMAPIProp
  75. };
  76. SizedSSortOrderSet(1, sosPR_ENTRYID) =
  77. {
  78. 1, 0, 0,
  79. {
  80. PR_ENTRYID
  81. }
  82. };
  83. SizedSSortOrderSet(1, sosPR_ROWID) =
  84. {
  85. 1, 0, 0,
  86. {
  87. PR_ROWID
  88. }
  89. };
  90. SizedSPropTagArray(2, tagaInsKey) =
  91. {
  92. 2,
  93. {
  94. PR_INSTANCE_KEY,
  95. PR_NULL // Space for PR_ROWID
  96. }
  97. };
  98. //
  99. // container default properties
  100. // Put essential props first
  101. //
  102. enum {
  103. icdPR_DISPLAY_NAME,
  104. icdPR_OBJECT_TYPE,
  105. icdPR_CONTAINER_FLAGS,
  106. icdPR_DISPLAY_TYPE,
  107. icdPR_ENTRYID, // optional
  108. icdPR_DEF_CREATE_MAILUSER, // optional
  109. icdPR_DEF_CREATE_DL, // optional
  110. icdMax
  111. };
  112. /***************************************************************************
  113. Name : HrSetCONTAINERAccess
  114. Purpose : Sets access flags on a container object
  115. Parameters: lpCONTAINER -> Container object
  116. ulOpenFlags = MAPI flags: MAPI_MODIFY | MAPI_BEST_ACCESS
  117. Returns : HRESULT
  118. Comment : Set the access flags on the container.
  119. ***************************************************************************/
  120. HRESULT HrSetCONTAINERAccess(LPCONTAINER lpCONTAINER, ULONG ulFlags) {
  121. ULONG ulAccess = IPROP_READONLY;
  122. switch (ulFlags& (MAPI_MODIFY | MAPI_BEST_ACCESS)) {
  123. case MAPI_MODIFY:
  124. case MAPI_BEST_ACCESS:
  125. ulAccess = IPROP_READWRITE;
  126. break;
  127. case 0:
  128. break;
  129. default:
  130. Assert(FALSE);
  131. }
  132. return(lpCONTAINER->lpPropData->lpVtbl->HrSetObjAccess(lpCONTAINER->lpPropData, ulAccess));
  133. }
  134. /***************************************************************************
  135. Name : HrNewCONTAINER
  136. Purpose : Creates a container object
  137. Parameters: lpIAB -> addrbook object
  138. ulType = {AB_ROOT, AB_WELL, AB_DL, AB_CONTAINER}
  139. lpInterface -> requested interface
  140. ulOpenFlags = flags
  141. cbEID = size of lpEID
  142. lpEID -> optional entryid of this object
  143. lpulObjType -> returned object type
  144. lppContainer -> returned IABContainer object
  145. Returns : HRESULT
  146. Comment :
  147. ***************************************************************************/
  148. HRESULT HrNewCONTAINER(LPIAB lpIAB,
  149. ULONG ulType,
  150. LPCIID lpInterface,
  151. ULONG ulOpenFlags,
  152. ULONG cbEID,
  153. LPENTRYID lpEID,
  154. ULONG *lpulObjType,
  155. LPVOID *lppContainer)
  156. {
  157. HRESULT hResult = hrSuccess;
  158. LPCONTAINER lpCONTAINER = NULL;
  159. SCODE sc;
  160. LPSPropValue lpProps = NULL;
  161. LPPROPDATA lpPropData = NULL;
  162. ULONG ulObjectType;
  163. BYTE bEntryIDType;
  164. ULONG cProps;
  165. TCHAR szDisplayName[MAX_PATH] = TEXT("");
  166. LPTSTR lpDisplayName = szDisplayName;
  167. BOOL fLoadedLDAP = FALSE;
  168. OlkContInfo *polkci;
  169. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  170. EnterCriticalSection(&lpIAB->cs);
  171. if (lpInterface != NULL) {
  172. if (memcmp(lpInterface, &IID_IABContainer, sizeof(IID)) &&
  173. memcmp(lpInterface, &IID_IDistList, sizeof(IID)) &&
  174. memcmp(lpInterface, &IID_IMAPIContainer, sizeof(IID)) &&
  175. memcmp(lpInterface, &IID_IMAPIProp, sizeof(IID))) {
  176. hResult = ResultFromScode(MAPI_E_INTERFACE_NOT_SUPPORTED);
  177. goto exit;
  178. }
  179. }
  180. //
  181. // Allocate space for the CONTAINER structure
  182. //
  183. if ((sc = MAPIAllocateBuffer(sizeof(CONTAINER), (LPVOID *)&lpCONTAINER))
  184. != SUCCESS_SUCCESS) {
  185. return(ResultFromScode(sc));
  186. }
  187. // [PaulHi] 12/16/98
  188. // We don't set all structure variables so zero out first!
  189. ZeroMemory(lpCONTAINER, sizeof(CONTAINER));
  190. lpCONTAINER->pmbinOlk = NULL;
  191. switch (ulType) {
  192. case AB_ROOT: // Root container object
  193. ulObjectType = MAPI_ABCONT;
  194. lpCONTAINER->lpVtbl = &vtblROOT;
  195. lpCONTAINER->cIID = CONTAINER_cInterfaces;
  196. lpCONTAINER->rglpIID = CONTAINER_LPIID;
  197. bEntryIDType = WAB_ROOT;
  198. #ifdef NEW_STUFF
  199. if (! LoadString(hinstMapiX, idsRootName, szDisplayName, ARRAYSIZE(szDisplayName))) {
  200. DebugTrace(TEXT("Can't load root name from resource\n"));
  201. }
  202. #else
  203. StrCpyN(szDisplayName, TEXT("WAB Root Container"), ARRAYSIZE(szDisplayName));
  204. #endif
  205. MAPISetBufferName(lpCONTAINER, TEXT("AB Root Container Object"));
  206. break;
  207. case AB_WELL:
  208. // What the heck is this supposed to be?
  209. Assert(FALSE);
  210. hResult = ResultFromScode(MAPI_E_INTERFACE_NOT_SUPPORTED);
  211. goto exit;
  212. break;
  213. case AB_DL: // Distribution List container
  214. ulObjectType = MAPI_DISTLIST;
  215. lpCONTAINER->lpVtbl = &vtblDISTLIST;
  216. lpCONTAINER->cIID = DISTLIST_cInterfaces;
  217. lpCONTAINER->rglpIID = DISTLIST_LPIID;
  218. bEntryIDType = WAB_DISTLIST;
  219. MAPISetBufferName(lpCONTAINER, TEXT("AB DISTLIST Container Object"));
  220. break;
  221. case AB_PAB: // "Default" PAB Container
  222. ulObjectType = MAPI_ABCONT;
  223. lpCONTAINER->lpVtbl = &vtblCONTAINER;
  224. lpCONTAINER->cIID = CONTAINER_cInterfaces;
  225. lpCONTAINER->rglpIID = CONTAINER_LPIID;
  226. bEntryIDType = WAB_PAB;
  227. if (pt_bIsWABOpenExSession) {
  228. // if this is an Outlook Session, then the container is the
  229. // first one in the list of Outlook containers
  230. Assert(lpIAB->lpPropertyStore->rgolkci);
  231. lpDisplayName = lpIAB->lpPropertyStore->rgolkci->lpszName;
  232. }
  233. else if(WAB_PABSHARED == IsWABEntryID(cbEID, lpEID, NULL, NULL, NULL, NULL, NULL))
  234. {
  235. // WAB's "shared contacts" container
  236. if(FAILED(hResult = MAPIAllocateMore( sizeof(SBinary) + cbEID, lpCONTAINER, (LPVOID *)&lpCONTAINER->pmbinOlk)))
  237. goto exit;
  238. // The shared contacts container has a special entryid of 0 bytes
  239. // and NULL entryid to distinguish it from other entryids
  240. lpCONTAINER->pmbinOlk->cb = 0;
  241. lpCONTAINER->pmbinOlk->lpb = NULL;
  242. LoadString(hinstMapiX, idsSharedContacts, szDisplayName, ARRAYSIZE(szDisplayName));
  243. }
  244. else if(bAreWABAPIProfileAware(lpIAB) && bIsThereACurrentUser(lpIAB))
  245. {
  246. // if calling client asked for profile support and logging into the
  247. // identity manager was successful and returned a valid profile, then
  248. // we need to return the user's default folder as the PAB
  249. //
  250. if(FAILED(hResult = MAPIAllocateMore( sizeof(SBinary) + cbEID, lpCONTAINER, (LPVOID *)&lpCONTAINER->pmbinOlk)))
  251. goto exit;
  252. lpDisplayName = lpIAB->lpWABCurrentUserFolder->lpFolderName;
  253. lpCONTAINER->pmbinOlk->cb = lpIAB->lpWABCurrentUserFolder->sbEID.cb;//cbEID;
  254. lpCONTAINER->pmbinOlk->lpb = (LPBYTE)(lpCONTAINER->pmbinOlk + 1);
  255. CopyMemory(lpCONTAINER->pmbinOlk->lpb, lpIAB->lpWABCurrentUserFolder->sbEID.lpb, lpCONTAINER->pmbinOlk->cb);//lpEID, cbEID);
  256. }
  257. else // old style "Contacts" container
  258. if (! LoadString(hinstMapiX, idsContacts, szDisplayName, ARRAYSIZE(szDisplayName))) {
  259. DebugTrace(TEXT("Can't load pab name from resource\n"));
  260. }
  261. MAPISetBufferName(lpCONTAINER, TEXT("AB PAB Container Object"));
  262. break;
  263. case AB_CONTAINER: // regular container/folder - we have an identifying entryid
  264. ulObjectType = MAPI_ABCONT;
  265. lpCONTAINER->lpVtbl = &vtblCONTAINER;
  266. lpCONTAINER->cIID = CONTAINER_cInterfaces;
  267. lpCONTAINER->rglpIID = CONTAINER_LPIID;
  268. bEntryIDType = WAB_CONTAINER;
  269. if (pt_bIsWABOpenExSession || bIsWABSessionProfileAware(lpIAB))
  270. {
  271. // If this is an outlook session or if this is an identity-aware
  272. // session, look for the specified container and use it
  273. polkci = FindContainer(lpIAB, cbEID, lpEID);
  274. if (!polkci)
  275. {
  276. hResult = ResultFromScode(MAPI_E_NOT_FOUND);
  277. goto exit;
  278. }
  279. lpDisplayName = polkci->lpszName;
  280. hResult = MAPIAllocateMore( sizeof(SBinary) + cbEID, lpCONTAINER,
  281. (LPVOID *)&lpCONTAINER->pmbinOlk);
  282. if (FAILED(hResult))
  283. goto exit;
  284. lpCONTAINER->pmbinOlk->cb = cbEID;
  285. lpCONTAINER->pmbinOlk->lpb = (LPBYTE)(lpCONTAINER->pmbinOlk + 1);
  286. CopyMemory(lpCONTAINER->pmbinOlk->lpb, lpEID, cbEID);
  287. }
  288. MAPISetBufferName(lpCONTAINER, TEXT("AB Container Object"));
  289. break;
  290. case AB_LDAP_CONTAINER: // LDAP container
  291. ulObjectType = MAPI_ABCONT;
  292. lpCONTAINER->lpVtbl = &vtblLDAPCONT;
  293. lpCONTAINER->cIID = CONTAINER_cInterfaces;
  294. lpCONTAINER->rglpIID = CONTAINER_LPIID;
  295. bEntryIDType = WAB_LDAP_CONTAINER;
  296. // Extract the server name from the LDAP entryid
  297. IsWABEntryID(cbEID, lpEID,&lpDisplayName,
  298. NULL,NULL, NULL, NULL);
  299. fLoadedLDAP = InitLDAPClientLib();
  300. MAPISetBufferName(lpCONTAINER, TEXT("AB LDAP Container Object"));
  301. break;
  302. default: // shouldnt' hit this one.
  303. MAPISetBufferName(lpCONTAINER, TEXT("AB Container Object"));
  304. Assert(FALSE);
  305. }
  306. lpCONTAINER->lcInit = 1;
  307. lpCONTAINER->hLastError = hrSuccess;
  308. lpCONTAINER->idsLastError = 0;
  309. lpCONTAINER->lpszComponent = NULL;
  310. lpCONTAINER->ulContext = 0;
  311. lpCONTAINER->ulLowLevelError = 0;
  312. lpCONTAINER->ulErrorFlags = 0;
  313. lpCONTAINER->lpMAPIError = NULL;
  314. lpCONTAINER->ulType = ulType;
  315. lpCONTAINER->lpIAB = lpIAB;
  316. lpCONTAINER->fLoadedLDAP = fLoadedLDAP;
  317. // Addref our parent IAB object
  318. UlAddRef(lpIAB);
  319. //
  320. // Create IPropData
  321. //
  322. if (FAILED(sc = CreateIProp(&IID_IMAPIPropData,
  323. (ALLOCATEBUFFER FAR * ) MAPIAllocateBuffer,
  324. (ALLOCATEMORE FAR *) MAPIAllocateMore,
  325. MAPIFreeBuffer,
  326. NULL,
  327. &lpPropData))) {
  328. hResult = ResultFromScode(sc);
  329. goto exit;
  330. }
  331. MAPISetBufferName(lpPropData, TEXT("lpPropData in HrNewCONTAINER"));
  332. if (sc = MAPIAllocateBuffer(icdMax * sizeof(SPropValue), &lpProps)) {
  333. hResult = ResultFromScode(sc);
  334. }
  335. // Set the basic set of properties on this container object such as
  336. // display-name etc
  337. lpProps[icdPR_OBJECT_TYPE].ulPropTag = PR_OBJECT_TYPE;
  338. lpProps[icdPR_OBJECT_TYPE].Value.l = ulObjectType;
  339. lpProps[icdPR_DISPLAY_NAME].ulPropTag = PR_DISPLAY_NAME;
  340. lpProps[icdPR_DISPLAY_NAME].Value.LPSZ = lpDisplayName;
  341. lpProps[icdPR_CONTAINER_FLAGS].ulPropTag = PR_CONTAINER_FLAGS;
  342. lpProps[icdPR_CONTAINER_FLAGS].Value.l = (ulType == AB_ROOT) ? AB_UNMODIFIABLE : AB_MODIFIABLE;
  343. lpProps[icdPR_DISPLAY_TYPE].ulPropTag = PR_DISPLAY_TYPE;
  344. lpProps[icdPR_DISPLAY_TYPE].Value.l = DT_LOCAL;
  345. cProps = 4;
  346. // in addition to the above properties, add some additional ones depending
  347. // on what type of container this is...
  348. switch (ulType) {
  349. case AB_PAB:
  350. lpProps[icdPR_ENTRYID].ulPropTag = PR_ENTRYID;
  351. if(lpCONTAINER->pmbinOlk)
  352. {
  353. // if we have an entryid for the container, just reuse it
  354. lpProps[icdPR_ENTRYID].Value.bin.cb = lpCONTAINER->pmbinOlk->cb; //cbEID;
  355. lpProps[icdPR_ENTRYID].Value.bin.lpb = lpCONTAINER->pmbinOlk->lpb;//(LPBYTE)lpEID;
  356. }
  357. else // create a wab entryid that we can hand about
  358. if (HR_FAILED(hResult = CreateWABEntryID(bEntryIDType,
  359. NULL, NULL, NULL,0, 0,
  360. (LPVOID) lpProps,
  361. (LPULONG) (&lpProps[icdPR_ENTRYID].Value.bin.cb),
  362. (LPENTRYID *)&lpProps[icdPR_ENTRYID].Value.bin.lpb)))
  363. {
  364. goto exit;
  365. }
  366. cProps++;
  367. // Add the default template IDs used for creating new users
  368. lpProps[icdPR_DEF_CREATE_MAILUSER].ulPropTag = PR_DEF_CREATE_MAILUSER;
  369. if (HR_FAILED(hResult = CreateWABEntryID(WAB_DEF_MAILUSER,
  370. NULL, NULL, NULL,
  371. 0, 0,
  372. (LPVOID) lpProps, // lpRoot
  373. (LPULONG) (&lpProps[icdPR_DEF_CREATE_MAILUSER].Value.bin.cb),
  374. (LPENTRYID *)&lpProps[icdPR_DEF_CREATE_MAILUSER].Value.bin.lpb))) {
  375. goto exit;
  376. }
  377. cProps++;
  378. lpProps[icdPR_DEF_CREATE_DL].ulPropTag = PR_DEF_CREATE_DL;
  379. if (HR_FAILED(hResult = CreateWABEntryID(WAB_DEF_DL,
  380. NULL, NULL, NULL,
  381. 0, 0,
  382. (LPVOID) lpProps, // lpRoot
  383. (LPULONG) (&lpProps[icdPR_DEF_CREATE_DL].Value.bin.cb),
  384. (LPENTRYID *)&lpProps[icdPR_DEF_CREATE_DL].Value.bin.lpb))) {
  385. goto exit;
  386. }
  387. cProps++;
  388. break;
  389. case AB_CONTAINER:
  390. lpProps[icdPR_ENTRYID].ulPropTag = PR_ENTRYID;
  391. lpProps[icdPR_ENTRYID].Value.bin.cb = cbEID;
  392. lpProps[icdPR_ENTRYID].Value.bin.lpb = (LPBYTE)lpEID;
  393. cProps++;
  394. lpProps[icdPR_DEF_CREATE_MAILUSER].ulPropTag = PR_DEF_CREATE_MAILUSER;
  395. if (HR_FAILED(hResult = CreateWABEntryID(WAB_DEF_MAILUSER,
  396. NULL, NULL, NULL,
  397. 0, 0,
  398. (LPVOID) lpProps, // lpRoot
  399. (LPULONG) (&lpProps[icdPR_DEF_CREATE_MAILUSER].Value.bin.cb),
  400. (LPENTRYID *)&lpProps[icdPR_DEF_CREATE_MAILUSER].Value.bin.lpb))) {
  401. goto exit;
  402. }
  403. cProps++;
  404. lpProps[icdPR_DEF_CREATE_DL].ulPropTag = PR_DEF_CREATE_DL;
  405. if (HR_FAILED(hResult = CreateWABEntryID(WAB_DEF_DL,
  406. NULL, NULL, NULL,
  407. 0, 0,
  408. (LPVOID) lpProps, // lpRoot
  409. (LPULONG) (&lpProps[icdPR_DEF_CREATE_DL].Value.bin.cb),
  410. (LPENTRYID *)&lpProps[icdPR_DEF_CREATE_DL].Value.bin.lpb))) {
  411. goto exit;
  412. }
  413. cProps++;
  414. break;
  415. case AB_ROOT:
  416. lpProps[icdPR_ENTRYID].ulPropTag = PR_ENTRYID;
  417. lpProps[icdPR_ENTRYID].Value.bin.cb = 0;
  418. lpProps[icdPR_ENTRYID].Value.bin.lpb = NULL;
  419. cProps++;
  420. lpProps[icdPR_DEF_CREATE_MAILUSER].ulPropTag = PR_DEF_CREATE_MAILUSER;
  421. if (HR_FAILED(hResult = CreateWABEntryID(WAB_DEF_MAILUSER,
  422. NULL, NULL, NULL,
  423. 0, 0,
  424. (LPVOID) lpProps, // lpRoot
  425. (LPULONG) (&lpProps[icdPR_DEF_CREATE_MAILUSER].Value.bin.cb),
  426. (LPENTRYID *)&lpProps[icdPR_DEF_CREATE_MAILUSER].Value.bin.lpb))) {
  427. goto exit;
  428. }
  429. cProps++;
  430. lpProps[icdPR_DEF_CREATE_DL].ulPropTag = PR_DEF_CREATE_DL;
  431. if (HR_FAILED(hResult = CreateWABEntryID(WAB_DEF_DL,
  432. NULL, NULL, NULL,
  433. 0, 0,
  434. (LPVOID) lpProps, // lpRoot
  435. (LPULONG) (&lpProps[icdPR_DEF_CREATE_DL].Value.bin.cb),
  436. (LPENTRYID *)&lpProps[icdPR_DEF_CREATE_DL].Value.bin.lpb))) {
  437. goto exit;
  438. }
  439. cProps++;
  440. break;
  441. case AB_LDAP_CONTAINER:
  442. lpProps[icdPR_ENTRYID].ulPropTag = PR_ENTRYID;
  443. lpProps[icdPR_ENTRYID].Value.bin.cb = cbEID;
  444. lpProps[icdPR_ENTRYID].Value.bin.lpb = (LPBYTE)lpEID;
  445. cProps++;
  446. // Hack! Don't need PR_DEF_CREATE_* so use those slots for
  447. // PR_WAB_LDAP_SERVER.
  448. lpProps[icdPR_DEF_CREATE_MAILUSER].ulPropTag = PR_WAB_LDAP_SERVER;
  449. lpProps[icdPR_DEF_CREATE_MAILUSER].Value.LPSZ = lpDisplayName;
  450. cProps++;
  451. break;
  452. }
  453. //
  454. // Set the default properties
  455. //
  456. if (HR_FAILED(hResult = lpPropData->lpVtbl->SetProps(lpPropData,
  457. cProps,
  458. lpProps,
  459. NULL))) {
  460. LPMAPIERROR lpMAPIError = NULL;
  461. lpPropData->lpVtbl->GetLastError(lpPropData,
  462. hResult,
  463. 0, // Ansi only
  464. &lpMAPIError);
  465. goto exit;
  466. }
  467. // default object access is ReadOnly (means the container object can't
  468. // be modified but it's data can be modified)
  469. lpPropData->lpVtbl->HrSetObjAccess(lpPropData, IPROP_READONLY);
  470. lpCONTAINER->lpPropData = lpPropData;
  471. // All we want to do is initialize the Root container's critical section
  472. InitializeCriticalSection(&lpCONTAINER->cs);
  473. *lpulObjType = ulObjectType;
  474. *lppContainer = (LPVOID)lpCONTAINER;
  475. exit:
  476. FreeBufferAndNull(&lpProps);
  477. if (HR_FAILED(hResult)) {
  478. if (fLoadedLDAP) {
  479. DeinitLDAPClientLib();
  480. }
  481. FreeBufferAndNull(&lpCONTAINER);
  482. UlRelease(lpPropData);
  483. }
  484. LeaveCriticalSection(&lpIAB->cs);
  485. return(hResult);
  486. }
  487. /***************************************************
  488. *
  489. * ABContainer methods
  490. */
  491. /*
  492. * IUnknown
  493. */
  494. /***************************************************************************
  495. Name : CONTAINER::QueryInterface
  496. Purpose : Calls the IAB_QueryInterface correctly
  497. Parameters:
  498. Returns :
  499. ***************************************************************************/
  500. STDMETHODIMP
  501. CONTAINER_QueryInterface(LPCONTAINER lpContainer,
  502. REFIID lpiid,
  503. LPVOID * lppNewObj)
  504. {
  505. // Check to see if it has a jump table
  506. if (IsBadReadPtr(lpContainer, sizeof(LPVOID))) {
  507. // No jump table found
  508. return(ResultFromScode(E_INVALIDARG));
  509. }
  510. // Check to see if the jump table has at least sizeof IUnknown
  511. if (IsBadReadPtr(lpContainer->lpVtbl, 3*sizeof(LPVOID))) {
  512. // Jump table not derived from IUnknown
  513. return(ResultFromScode(E_INVALIDARG));
  514. }
  515. // Check to see that it's IAB_QueryInterface
  516. if (lpContainer->lpVtbl->QueryInterface != CONTAINER_QueryInterface) {
  517. // Not my jump table
  518. return(ResultFromScode(E_INVALIDARG));
  519. }
  520. // default to the IAB QueryInterface method
  521. return lpContainer->lpIAB->lpVtbl->QueryInterface(lpContainer->lpIAB, lpiid, lppNewObj);
  522. }
  523. /***************************************************************************
  524. Name : CONTAINER::Release
  525. Purpose : Releases the container object
  526. Parameters: lpCONTAINER -> Container object
  527. Returns : current reference count
  528. Comment : Decrememnt lpInit
  529. When lcInit == 0, release the parent objects and
  530. free up the lpCONTAINER structure
  531. ***************************************************************************/
  532. STDMETHODIMP_(ULONG)
  533. CONTAINER_Release(LPCONTAINER lpCONTAINER) {
  534. #ifdef PARAMETER_VALIDATION
  535. // Check to see if it has a jump table
  536. if (IsBadReadPtr(lpCONTAINER, sizeof(LPVOID))) {
  537. // No jump table found
  538. return(1);
  539. }
  540. #endif // PARAMETER_VALIDATION
  541. EnterCriticalSection(&lpCONTAINER->cs);
  542. --lpCONTAINER->lcInit;
  543. if (lpCONTAINER->lcInit == 0) {
  544. // Remove this object from the objects currently on this session.
  545. // Not yet implemented...
  546. // Remove the associated lpPropData
  547. UlRelease(lpCONTAINER->lpPropData);
  548. // Set the Jump table to NULL. This way the client will find out
  549. // real fast if it's calling a method on a released object. That is,
  550. // the client will crash. Hopefully, this will happen during the
  551. // development stage of the client.
  552. lpCONTAINER->lpVtbl = NULL;
  553. // Free error string if allocated from MAPI memory.
  554. FreeBufferAndNull(&(lpCONTAINER->lpMAPIError));
  555. // Release the IAB since we addref'd it in root object creation.
  556. UlRelease(lpCONTAINER->lpIAB);
  557. if (lpCONTAINER->fLoadedLDAP) {
  558. DeinitLDAPClientLib();
  559. }
  560. LeaveCriticalSection(&lpCONTAINER->cs);
  561. DeleteCriticalSection(&lpCONTAINER->cs);
  562. // Need to free the object
  563. FreeBufferAndNull(&lpCONTAINER);
  564. return(0);
  565. }
  566. LeaveCriticalSection(&lpCONTAINER->cs);
  567. return(lpCONTAINER->lcInit);
  568. }
  569. /*
  570. * IMAPIProp
  571. */
  572. /***************************************************************************
  573. Name : CONTAINER::OpenProperty
  574. Purpose : Opens an object interface on a particular property
  575. Parameters: lpCONTAINER -> Container object
  576. ulPropTag = property to open
  577. lpiid -> requested interface
  578. ulInterfaceOptions =
  579. ulFlags =
  580. lppUnk -> returned object
  581. Returns : HRESULT
  582. Comment :
  583. ***************************************************************************/
  584. STDMETHODIMP
  585. CONTAINER_OpenProperty(LPCONTAINER lpCONTAINER,
  586. ULONG ulPropTag,
  587. LPCIID lpiid,
  588. ULONG ulInterfaceOptions,
  589. ULONG ulFlags,
  590. LPUNKNOWN * lppUnk)
  591. {
  592. LPIAB lpIAB;
  593. LPSTR lpszMessage = NULL;
  594. ULONG ulLowLevelError = 0;
  595. HRESULT hr;
  596. #ifdef PARAMETER_VALIDATION
  597. // Validate parameters
  598. // Check to see if it has a jump table
  599. if (IsBadReadPtr(lpCONTAINER, sizeof(LPVOID))) {
  600. // No jump table found
  601. hr = ResultFromScode(MAPI_E_INVALID_PARAMETER);
  602. return(hr);
  603. }
  604. if ((ulInterfaceOptions & ~(MAPI_UNICODE)) || (ulFlags & ~(MAPI_DEFERRED_ERRORS))) {
  605. return(hr = ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
  606. }
  607. if (FBadOpenProperty(lpCONTAINER, ulPropTag, lpiid, ulInterfaceOptions, ulFlags,
  608. lppUnk)) {
  609. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  610. }
  611. #endif // PARAMETER_VALIDATION
  612. #ifdef IABCONTAINER_OPENPROPERTY_SUPPORT // ??Were we supporting this? - vm 3/25/97??
  613. EnterCriticalSection(&lpCONTAINER->cs);
  614. lpIAB = lpCONTAINER->lpIAB;
  615. //
  616. // Check to see if I need a display table
  617. //
  618. if (ulPropTag == PR_CREATE_TEMPLATES) {
  619. //
  620. // Looking for the display table
  621. //
  622. //
  623. // Check to see if they're expecting a table interface
  624. //
  625. if (memcmp(lpiid, &IID_IMAPITable, sizeof(IID))) {
  626. hr = ResultFromScode(MAPI_E_INTERFACE_NOT_SUPPORTED);
  627. goto err;
  628. }
  629. // Check to see if we already have a table
  630. EnterCriticalSection(&lpIAB->cs);
  631. //
  632. // Get a view from the TAD
  633. //
  634. hr = lpIAB->lpOOData->lpVtbl->HrGetView(
  635. lpIAB->lpOOData,
  636. (LPSSortOrderSet)&sosPR_ROWID,
  637. NULL,
  638. 0,
  639. (LPMAPITABLE *)lppUnk);
  640. // Leave the critical section after we get our view.
  641. LeaveCriticalSection(&lpIAB->cs);
  642. #ifdef DEBUG
  643. if (hr == hrSuccess) {
  644. MAPISetBufferName(*lppUnk, TEXT("OneOff Data VUE1 Object"));
  645. }
  646. #endif
  647. goto err; // Maybe error, maybe not...
  648. } else if (ulPropTag == PR_CONTAINER_CONTENTS) {
  649. //
  650. // Check to see if they're expecting a table interface
  651. //
  652. if (memcmp(lpiid, &IID_IMAPITable, sizeof(IID))) {
  653. hr = ResultFromScode(MAPI_E_INTERFACE_NOT_SUPPORTED);
  654. goto err;
  655. }
  656. hr = lpCONTAINER->lpVtbl->GetContentsTable(lpCONTAINER,
  657. ulInterfaceOptions,
  658. (LPMAPITABLE *)lppUnk);
  659. goto err;
  660. } else if (ulPropTag == PR_CONTAINER_HIERARCHY) {
  661. //
  662. // Check to see if they're expecting a table interface
  663. //
  664. if (memcmp(lpiid, &IID_IMAPITable, sizeof(IID))) {
  665. hr = ResultFromScode(MAPI_E_INTERFACE_NOT_SUPPORTED);
  666. goto err;
  667. }
  668. hr = lpCONTAINER->lpVtbl->GetHierarchyTable(lpCONTAINER,
  669. ulInterfaceOptions,
  670. (LPMAPITABLE *)lppUnk);
  671. goto err;
  672. }
  673. //
  674. // Don't recognize the property they want opened.
  675. //
  676. hr = ResultFromScode(MAPI_E_NO_SUPPORT);
  677. err:
  678. LeaveCriticalSection(&lpCONTAINER->cs);
  679. #else // IABCONTAINER_OPENPROPERTY_SUPPORT
  680. hr = ResultFromScode(MAPI_E_NO_SUPPORT);
  681. #endif // IABCONTAINER_OPENPROPERTY_SUPPORT
  682. DebugTraceResult(CONTAINER_OpenProperty, hr);
  683. return(hr);
  684. }
  685. /***************************************************************************
  686. Name : CONTAINER_GetGetIDsFromNames
  687. Returns : HRESULT
  688. Comment : Just default this to the standard GetIdsFromNames
  689. that we use everywhere
  690. ***************************************************************************/
  691. STDMETHODIMP
  692. CONTAINER_GetIDsFromNames(LPCONTAINER lpRoot, ULONG cPropNames,
  693. LPMAPINAMEID * lppPropNames, ULONG ulFlags, LPSPropTagArray * lppPropTags)
  694. {
  695. return HrGetIDsFromNames(lpRoot->lpIAB,
  696. cPropNames,
  697. lppPropNames, ulFlags, lppPropTags);
  698. }
  699. /*
  700. -
  701. - HrDupeOutlookContentsTable
  702. *
  703. * Since Outlook is unable to provide a Unicode contents table and we can't fo into the
  704. * outlook contents table to modify it's data, we have to recreate the contentstable to
  705. * create a WAB version of it ..
  706. * This is likely to be a big performance issue .. :-(
  707. *
  708. */
  709. HRESULT HrDupeOutlookContentsTable(LPMAPITABLE lpOlkTable, LPMAPITABLE * lppTable)
  710. {
  711. HRESULT hr = S_OK;
  712. ULONG ulCount = 0, iRow = 0;
  713. DWORD dwIndex = 0;
  714. LPSRowSet lpsRow = 0, lpSRowSet = NULL;
  715. ULONG ulCurrentRow = (ULONG)-1;
  716. ULONG ulNum, ulDen, lRowsSeeked;
  717. LPTABLEDATA lpTableData = NULL;
  718. SCODE sc = 0;
  719. // Create a table object
  720. if (FAILED(sc = CreateTable( NULL, // LPCIID
  721. (ALLOCATEBUFFER FAR *) MAPIAllocateBuffer,
  722. (ALLOCATEMORE FAR *) MAPIAllocateMore,
  723. MAPIFreeBuffer,
  724. NULL, // lpvReserved,
  725. TBLTYPE_DYNAMIC, // ulTableType,
  726. PR_ENTRYID, // ulPropTagIndexCol,
  727. (LPSPropTagArray)&ITableColumnsRoot, // LPSPropTagArray lpptaCols,
  728. &lpTableData)))
  729. {
  730. DebugTrace(TEXT("CreateTable failed %x\n"), sc);
  731. hr = ResultFromScode(sc);
  732. goto out;
  733. }
  734. Assert(lpTableData);
  735. ((TAD *)lpTableData)->bMAPIUnicodeTable = TRUE; //this is only called for retreiving unicode tables so the flag is true
  736. // How big is the outlook table?
  737. if(HR_FAILED(hr = lpOlkTable->lpVtbl->GetRowCount(lpOlkTable, 0, &ulCount)))
  738. goto out;
  739. DebugTrace( TEXT("Table contains %u rows\n"), ulCount);
  740. // Allocate the SRowSet
  741. if (FAILED(sc = MAPIAllocateBuffer(sizeof(SRowSet) + ulCount * sizeof(SRow),&lpSRowSet)))
  742. {
  743. DebugTrace(TEXT("Allocation of SRowSet -> %x\n"), sc);
  744. hr = ResultFromScode(sc);
  745. goto out;
  746. }
  747. MAPISetBufferName(lpSRowSet, TEXT("Outlook_ContentsTable_Copy SRowSet"));
  748. ZeroMemory( lpSRowSet, (UINT) (sizeof(SRowSet) + ulCount * sizeof(SRow)));
  749. lpSRowSet->cRows = ulCount;
  750. iRow = 0;
  751. // Copy UNICODE versions of all the properties from the Outlook table
  752. for (dwIndex = 0; dwIndex < ulCount; dwIndex++)
  753. {
  754. // Get the next row
  755. if(HR_FAILED(hr = lpOlkTable->lpVtbl->QueryRows(lpOlkTable, 1, 0, &lpsRow)))
  756. goto out;
  757. if (lpsRow)
  758. {
  759. LPSPropValue lpSPVNew = NULL;
  760. Assert(lpsRow->cRows == 1); // should have exactly one row
  761. ///****INVESTIGATE if we can reuse this prop array without duplicating***/
  762. if(HR_FAILED(hr = HrDupeOlkPropsAtoWC(lpsRow->aRow[0].cValues, lpsRow->aRow[0].lpProps, &lpSPVNew)))
  763. goto out;
  764. // Attach the props to the SRowSet
  765. lpSRowSet->aRow[iRow].lpProps = lpSPVNew;
  766. lpSRowSet->aRow[iRow].cValues = lpsRow->aRow[0].cValues;
  767. lpSRowSet->aRow[iRow].ulAdrEntryPad = 0;
  768. FreeProws(lpsRow);
  769. iRow++;
  770. }
  771. }
  772. // Add all this data we just created to the the Table.
  773. if (hr = lpTableData->lpVtbl->HrModifyRows(lpTableData, 0, lpSRowSet))
  774. {
  775. DebugTraceResult( TEXT("ROOT_GetContentsTable:HrModifyRows"), hr);
  776. goto out;
  777. }
  778. hr = lpTableData->lpVtbl->HrGetView(lpTableData, NULL, ContentsViewGone, 0, lppTable);
  779. out:
  780. FreeProws(lpSRowSet);
  781. // Cleanup table if failure
  782. if (HR_FAILED(hr))
  783. {
  784. if (lpTableData)
  785. {
  786. UlRelease(lpTableData);
  787. }
  788. }
  789. return hr;
  790. }
  791. /***************************************************************************
  792. Name : CONTAINER::GetContentsTable
  793. Purpose : Opens a table of the contents of the container.
  794. Parameters: lpCONTAINER -> Container object
  795. ulFlags =
  796. WAB_PROFILE_CONTENTS - When caller opens the PAB container and want's to
  797. get the complete set of contents for the current identity
  798. without wanting to enumerate each sub-container seperately
  799. - they can specify this flag and we'll return everything
  800. corresponding to the current identity all in the same table
  801. WAB_CONTENTTABLE_NODATA - Internal only flag .. GetContentsTable normally
  802. loads a full contents table and if this is followed by SetColumns,
  803. SetColumns also loads a full contents table .. so we basically
  804. do the same work twice - to reduce this wasted work, caller can
  805. specify not to load data the first time but caller must call
  806. SetColumns immediately (or this will probably fault)
  807. lppTable -> returned table object
  808. Returns : HRESULT
  809. Comment :
  810. ***************************************************************************/
  811. STDMETHODIMP
  812. CONTAINER_GetContentsTable (LPCONTAINER lpCONTAINER,
  813. ULONG ulFlags,
  814. LPMAPITABLE * lppTable)
  815. {
  816. HRESULT hResult;
  817. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  818. #ifdef PARAMETER_VALIDATION
  819. // Check to see if it has a jump table
  820. if (IsBadReadPtr(lpCONTAINER, sizeof(LPVOID))) {
  821. // No jump table found
  822. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  823. }
  824. if (ulFlags & ~(MAPI_DEFERRED_ERRORS|MAPI_UNICODE|WAB_PROFILE_CONTENTS|WAB_CONTENTTABLE_NODATA)) {
  825. DebugTraceArg(CONTAINER_GetContentsTable, TEXT("Unknown flags"));
  826. //return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
  827. }
  828. if (IsBadWritePtr(lppTable, sizeof(LPMAPITABLE))) {
  829. DebugTraceArg(CONTAINER_GetContentsTable, TEXT("Invalid Flags"));
  830. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  831. }
  832. #endif // PARAMETER_VALIDATION
  833. if(pt_bIsWABOpenExSession)
  834. {
  835. ULONG ulOlkFlags = ulFlags;
  836. // This is a WABOpenEx session using outlooks storage provider
  837. if(!lpCONTAINER->lpIAB->lpPropertyStore->hPropertyStore)
  838. return MAPI_E_NOT_INITIALIZED;
  839. // Since the Outlook store doesn't understand the private flags, these
  840. // flags need to be filtered out otherwise the outlook store
  841. // provider will fail with E_INVALIDARG or something
  842. //
  843. if(ulOlkFlags & WAB_PROFILE_CONTENTS)
  844. ulOlkFlags &= ~WAB_PROFILE_CONTENTS;
  845. if(ulOlkFlags & WAB_CONTENTTABLE_NODATA)
  846. ulOlkFlags &= ~WAB_CONTENTTABLE_NODATA;
  847. if(ulFlags & MAPI_UNICODE && !pt_bIsUnicodeOutlook)
  848. {
  849. // This version of Outlook can't handle Unicode so don't tell it to else it'll barf
  850. ulOlkFlags &= ~MAPI_UNICODE;
  851. }
  852. // Outlook provides it's own implementation of GetContentsTable for
  853. // efficiencies sake otherwise recreating the table going through the
  854. // WAB layer would be just too darned slow ...
  855. {
  856. LPWABSTORAGEPROVIDER lpWSP = (LPWABSTORAGEPROVIDER) lpCONTAINER->lpIAB->lpPropertyStore->hPropertyStore;
  857. Assert((lpCONTAINER->ulType == AB_PAB) ||
  858. (lpCONTAINER->ulType == AB_CONTAINER));
  859. hResult = lpWSP->lpVtbl->GetContentsTable(lpWSP,
  860. lpCONTAINER->pmbinOlk,
  861. ulOlkFlags,
  862. lppTable);
  863. DebugPrintTrace((TEXT("WABStorageProvider::GetContentsTable returned:%x\n"),hResult));
  864. if( ulFlags & MAPI_UNICODE && !pt_bIsUnicodeOutlook &&
  865. *lppTable && !HR_FAILED(hResult))
  866. {
  867. // This version of Outlook can't handle Unicode
  868. // but caller wants unicode, so now we have to go in and tweak this data
  869. // manually ..
  870. LPMAPITABLE lpWABTable = NULL;
  871. if(!HR_FAILED(hResult = HrDupeOutlookContentsTable(*lppTable, &lpWABTable)))
  872. {
  873. (*lppTable)->lpVtbl->Release(*lppTable);
  874. *lppTable = lpWABTable;
  875. }
  876. }
  877. return hResult;
  878. }
  879. }
  880. // Create a new contents table object
  881. hResult = NewContentsTable((LPABCONT)lpCONTAINER,
  882. lpCONTAINER->lpIAB,
  883. ulFlags,
  884. NULL,
  885. lppTable);
  886. if(!(HR_FAILED(hResult)) && *lppTable &&
  887. (ulFlags & WAB_PROFILE_CONTENTS) && !(ulFlags & WAB_CONTENTTABLE_NODATA))
  888. {
  889. // There is a problem with searching multiple subfolders in that the data does not
  890. // come back sorted when it is collated across multiple folders.
  891. // We need to sort the table before we return it .. it's somewhat inefficient to do this
  892. // sort at this point .. ideally the data should be added to the table sorted...
  893. LPSSortOrderSet lpSortCriteria = NULL;
  894. SCODE sc = MAPIAllocateBuffer(sizeof(SSortOrderSet)+sizeof(SSortOrder), &lpSortCriteria);
  895. if(!sc)
  896. {
  897. lpSortCriteria->cCategories = lpSortCriteria->cExpanded = 0;
  898. lpSortCriteria->cSorts = 1;
  899. lpSortCriteria->aSort[0].ulPropTag = PR_DISPLAY_NAME;
  900. if(!(((LPTAD)(*lppTable))->bMAPIUnicodeTable))
  901. lpSortCriteria->aSort[0].ulPropTag = CHANGE_PROP_TYPE( lpSortCriteria->aSort[0].ulPropTag, PT_STRING8);
  902. lpSortCriteria->aSort[0].ulOrder = TABLE_SORT_ASCEND;
  903. hResult = (*lppTable)->lpVtbl->SortTable((*lppTable), lpSortCriteria, 0);
  904. FreeBufferAndNull(&lpSortCriteria);
  905. }
  906. else
  907. {
  908. hResult = MAPI_E_NOT_ENOUGH_MEMORY;
  909. }
  910. }
  911. return(hResult);
  912. }
  913. /***************************************************************************
  914. Name : CONTAINER::GetHierarchyTable
  915. Purpose : Returns the merge of all the root hierarchy tables
  916. Parameters: lpCONTAINER -> Container object
  917. ulFlags =
  918. lppTable -> returned table object
  919. Returns : HRESULT
  920. Comment :
  921. ***************************************************************************/
  922. STDMETHODIMP
  923. CONTAINER_GetHierarchyTable (LPCONTAINER lpCONTAINER,
  924. ULONG ulFlags,
  925. LPMAPITABLE * lppTable)
  926. {
  927. LPTSTR lpszMessage = NULL;
  928. ULONG ulLowLevelError = 0;
  929. HRESULT hr = hrSuccess;
  930. #ifdef PARAMETER_VALIDATION
  931. // Validate parameters
  932. // Check to see if it has a jump table
  933. if (IsBadReadPtr(lpCONTAINER, sizeof(LPVOID))) {
  934. // No jump table found
  935. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  936. }
  937. // See if I can set the return variable
  938. if (IsBadWritePtr (lppTable, sizeof (LPMAPITABLE))) {
  939. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  940. }
  941. // Check flags:
  942. // The only valid flags are CONVENIENT_DEPTH and MAPI_DEFERRED_ERRORS
  943. if (ulFlags & ~(CONVENIENT_DEPTH|MAPI_DEFERRED_ERRORS|MAPI_UNICODE)) {
  944. DebugTraceArg(CONTAINER_GetHierarchyTable, TEXT("Invalid Flags"));
  945. // return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
  946. }
  947. #endif
  948. EnterCriticalSection(&lpCONTAINER->cs);
  949. if (lpCONTAINER->ulType != AB_ROOT) {
  950. //
  951. // Wrong version of this object. Pretend this object doesn't exist.
  952. //
  953. hr = ResultFromScode(MAPI_E_NO_SUPPORT);
  954. goto out;
  955. }
  956. //
  957. // Get a view from the TAD
  958. //
  959. hr = lpCONTAINER->lpIAB->lpTableData->lpVtbl->HrGetView(
  960. lpCONTAINER->lpIAB->lpTableData,
  961. (LPSSortOrderSet) &sosPR_ROWID,
  962. NULL,
  963. 0,
  964. lppTable);
  965. if (HR_FAILED(hr)) {
  966. DebugTrace(TEXT("IAB_GetHierarchyTable Get Tad View failed\n"));
  967. goto out;
  968. }
  969. #ifdef DEBUG
  970. if (hr == hrSuccess) {
  971. MAPISetBufferName(*lppTable, TEXT("MergeHier VUE Object"));
  972. }
  973. #endif
  974. // If the convenient depth flag was not specified we restrict on
  975. // PR_DEPTH == 1.
  976. if (!(ulFlags & CONVENIENT_DEPTH)) {
  977. SRestriction restrictDepth;
  978. SPropValue spvDepth;
  979. spvDepth.ulPropTag = PR_DEPTH;
  980. spvDepth.Value.l = 0;
  981. restrictDepth.rt = RES_PROPERTY;
  982. restrictDepth.res.resProperty.relop = RELOP_EQ;
  983. restrictDepth.res.resProperty.ulPropTag = PR_DEPTH;
  984. restrictDepth.res.resProperty.lpProp = &spvDepth;
  985. if (HR_FAILED(hr = (*lppTable)->lpVtbl->Restrict(*lppTable, &restrictDepth, 0))) {
  986. DebugTrace(TEXT("IAB_GetHierarchyTable restriction failed\n"));
  987. goto out;
  988. }
  989. }
  990. out:
  991. LeaveCriticalSection(&lpCONTAINER->cs);
  992. DebugTraceResult(CONTAINER_GetHierarchyTable, hr);
  993. return(hr);
  994. }
  995. /***************************************************************************
  996. Name : HrMergeTableRows
  997. Purpose : Creates a merged hierarchy r of all the root level
  998. hierarchies from the AB providers installed.
  999. Parameters: lptadDst -> TABLEDATA object
  1000. lpmtSrc -> source hierarchy table
  1001. ulProviderNum =
  1002. Returns : HRESULT
  1003. Comment : NOTE: This may be irrelevant for WAB.
  1004. ***************************************************************************/
  1005. HRESULT
  1006. HrMergeTableRows(LPTABLEDATA lptadDst,
  1007. LPMAPITABLE lpmtSrc,
  1008. ULONG ulProviderNum)
  1009. {
  1010. HRESULT hResult = hrSuccess;
  1011. SCODE sc;
  1012. ULONG ulRowID = ulProviderNum * ((LONG)IAB_PROVIDER_HIERARCHY_MAX + 1);
  1013. LPSRowSet lpsRowSet = NULL;
  1014. LPSRow lprowT;
  1015. if (hResult = HrQueryAllRows(lpmtSrc, NULL, NULL, NULL, 0, &lpsRowSet)) {
  1016. DebugTrace(TEXT("HrMergeTableRows() - Could not query provider rows.\n"));
  1017. goto ret;
  1018. }
  1019. if (lpsRowSet->cRows >= IAB_PROVIDER_HIERARCHY_MAX) {
  1020. DebugTrace(TEXT("HrMergeTableRows() - Provider has too many rows.\n"));
  1021. hResult = ResultFromScode(MAPI_E_TABLE_TOO_BIG);
  1022. goto ret;
  1023. }
  1024. // Set the ROWID to the end since will be looping in reverse order.
  1025. ulRowID = ulProviderNum * ((LONG) IAB_PROVIDER_HIERARCHY_MAX + 1)
  1026. + lpsRowSet->cRows;
  1027. for (lprowT = lpsRowSet->aRow + lpsRowSet->cRows;
  1028. --lprowT >= lpsRowSet->aRow;) {
  1029. ULONG cbInsKey;
  1030. LPBYTE lpbNewKey = NULL;
  1031. // Make ulRowID zero based
  1032. ulRowID--;
  1033. //
  1034. // Munge the PR_INSTANCE_KEY
  1035. //
  1036. if ((lprowT->lpProps[0].ulPropTag != PR_INSTANCE_KEY)
  1037. || !(cbInsKey = lprowT->lpProps[0].Value.bin.cb)
  1038. || ((cbInsKey + sizeof(ULONG)) > UINT_MAX)
  1039. || IsBadReadPtr(lprowT->lpProps[0].Value.bin.lpb, (UINT) cbInsKey)) {
  1040. // Can't create our INSTANCE_KEY without a valid provider
  1041. // INSTANCE_KEY
  1042. DebugTrace(TEXT("HrMergeTableRows - Provider row has no valid PR_INSTANCE_KEY"));
  1043. continue;
  1044. }
  1045. // Allocate a new buffer for munging the instance key
  1046. if (FAILED(sc = MAPIAllocateMore(cbInsKey + sizeof(ULONG), lprowT->lpProps, &lpbNewKey))) {
  1047. hResult = ResultFromScode(sc);
  1048. DebugTrace(TEXT("HrMergeTableRows() - MAPIAllocMore Failed"));
  1049. goto ret;
  1050. }
  1051. *((LPULONG) lpbNewKey) = ulProviderNum;
  1052. CopyMemory(lpbNewKey + sizeof(ULONG), lprowT->lpProps[0].Value.bin.lpb, cbInsKey);
  1053. lprowT->lpProps[0].ulPropTag = PR_INSTANCE_KEY;
  1054. lprowT->lpProps[0].Value.bin.lpb = lpbNewKey;
  1055. lprowT->lpProps[0].Value.bin.cb = cbInsKey + sizeof(ULONG);
  1056. // Add the ROWID so that the original order of the providers is
  1057. // preserved
  1058. Assert((PROP_ID(lprowT->lpProps[1].ulPropTag) == PROP_ID(PR_ROWID))
  1059. || (PROP_ID(lprowT->lpProps[1].ulPropTag) == PROP_ID(PR_NULL)));
  1060. lprowT->lpProps[1].ulPropTag = PR_ROWID;
  1061. lprowT->lpProps[1].Value.l = ulRowID;
  1062. }
  1063. // Now put them into the TAD all at once.
  1064. // Note! We now rely on PR_ROWID to keep the rows in order
  1065. if (HR_FAILED(hResult = lptadDst->lpVtbl->HrModifyRows(lptadDst, 0, lpsRowSet))) {
  1066. DebugTrace(TEXT("HrMergeTableRows() - Failed to modify destination TAD.\n"));
  1067. }
  1068. ret:
  1069. //
  1070. // Free up the row set
  1071. //
  1072. FreeProws(lpsRowSet);
  1073. return(hResult);
  1074. }
  1075. /***************************************************************************
  1076. Name : CONTAINER::OpenEntry
  1077. Purpose : Opens an entry
  1078. Parameters: lpCONTAINER -> Container object
  1079. cbEntryID = size of entryid
  1080. lpEntryID -> EntryID to open
  1081. lpInterface -> requested interface or NULL for default.
  1082. ulFlags =
  1083. lpulObjType -> returned object type
  1084. lppUnk -> returned object
  1085. Returns : HRESULT
  1086. Comment : Calls up to IAB's OpenEntry.
  1087. ***************************************************************************/
  1088. STDMETHODIMP
  1089. CONTAINER_OpenEntry(LPCONTAINER lpCONTAINER,
  1090. ULONG cbEntryID,
  1091. LPENTRYID lpEntryID,
  1092. LPCIID lpInterface,
  1093. ULONG ulFlags,
  1094. ULONG * lpulObjType,
  1095. LPUNKNOWN * lppUnk)
  1096. {
  1097. #ifdef PARAMETER_VALIDATION
  1098. // Validate the object.
  1099. if (BAD_STANDARD_OBJ(lpCONTAINER, CONTAINER_, OpenEntry, lpVtbl)) {
  1100. // jump table not large enough to support this method
  1101. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  1102. }
  1103. // Check the entryid parameter. It needs to be big enough to hold an entryid.
  1104. // Null entryids are valid
  1105. /*
  1106. if (lpEntryID) {
  1107. if (cbEntryID < offsetof(ENTRYID, ab)
  1108. || IsBadReadPtr((LPVOID)lpEntryID, (UINT)cbEntryID)) {
  1109. DebugTraceArg(CONTAINER_OpenEntry, TEXT("lpEntryID fails address check"));
  1110. return(ResultFromScode(MAPI_E_INVALID_ENTRYID));
  1111. }
  1112. NFAssertSz(FValidEntryIDFlags(lpEntryID->abFlags),
  1113. TEXT("Undefined bits set in EntryID flags\n"));
  1114. }
  1115. */
  1116. // Don't check the interface parameter unless the entry is something
  1117. // MAPI itself handles. The provider should return an error if this
  1118. // parameter is something that it doesn't understand.
  1119. // At this point, we just make sure it's readable.
  1120. if (lpInterface && IsBadReadPtr(lpInterface, sizeof(IID))) {
  1121. DebugTraceArg(CONTAINER_OpenEntry, TEXT("lpInterface fails address check"));
  1122. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  1123. }
  1124. if (ulFlags & ~(MAPI_MODIFY | MAPI_DEFERRED_ERRORS | MAPI_BEST_ACCESS)) {
  1125. DebugTraceArg(CONTAINER_OpenEntry, TEXT("Unknown flags used"));
  1126. // return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
  1127. }
  1128. if (IsBadWritePtr((LPVOID)lpulObjType, sizeof(ULONG))) {
  1129. DebugTraceArg(CONTAINER_OpenEntry, TEXT("lpulObjType"));
  1130. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  1131. }
  1132. if (IsBadWritePtr((LPVOID)lppUnk, sizeof(LPUNKNOWN))) {
  1133. DebugTraceArg(CONTAINER_OpenEntry, TEXT("lppUnk"));
  1134. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  1135. }
  1136. #endif // PARAMETER_VALIDATION
  1137. // Should just call IAB::OpenEntry()...
  1138. return(lpCONTAINER->lpIAB->lpVtbl->OpenEntry(lpCONTAINER->lpIAB,
  1139. cbEntryID,
  1140. lpEntryID,
  1141. lpInterface,
  1142. ulFlags,
  1143. lpulObjType,
  1144. lppUnk));
  1145. }
  1146. STDMETHODIMP
  1147. CONTAINER_SetSearchCriteria(LPCONTAINER lpCONTAINER,
  1148. LPSRestriction lpRestriction,
  1149. LPENTRYLIST lpContainerList,
  1150. ULONG ulSearchFlags)
  1151. {
  1152. #ifdef PARAMETER_VALIDATION
  1153. // Validate the object.
  1154. if (BAD_STANDARD_OBJ(lpCONTAINER, CONTAINER_, SetSearchCriteria, lpVtbl)) {
  1155. // jump table not large enough to support this method
  1156. DebugTraceArg(CONTAINER_SetSearchCriteria, TEXT("Bad object/vtble"));
  1157. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  1158. }
  1159. // ensure we can read the restriction
  1160. if (lpRestriction && IsBadReadPtr(lpRestriction, sizeof(SRestriction))) {
  1161. DebugTraceArg(CONTAINER_SetSearchCriteria, TEXT("Bad Restriction parameter"));
  1162. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  1163. }
  1164. if (FBadEntryList(lpContainerList)) {
  1165. DebugTraceArg(CONTAINER_SetSearchCriteria, TEXT("Bad ContainerList parameter"));
  1166. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  1167. }
  1168. if (ulSearchFlags & ~(STOP_SEARCH | RESTART_SEARCH | RECURSIVE_SEARCH
  1169. | SHALLOW_SEARCH | FOREGROUND_SEARCH | BACKGROUND_SEARCH)) {
  1170. DebugTraceArg(CONTAINER_GetSearchCriteria, TEXT("Unknown flags used"));
  1171. // return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
  1172. }
  1173. #endif // PARAMETER_VALIDATION
  1174. return(ResultFromScode(MAPI_E_NO_SUPPORT));
  1175. }
  1176. /***************************************************************************
  1177. Name : CONTAINER::GetSearchCriteria
  1178. Purpose :
  1179. Parameters: lpCONTAINER -> Container object
  1180. ulFlags =
  1181. lppRestriction -> Restriction to apply to searches
  1182. lppContainerList ->
  1183. lpulSearchState -> returned state
  1184. Returns : HRESULT
  1185. Comment : Not implemented in WAB.
  1186. ***************************************************************************/
  1187. STDMETHODIMP
  1188. CONTAINER_GetSearchCriteria(LPCONTAINER lpCONTAINER,
  1189. ULONG ulFlags,
  1190. LPSRestriction FAR * lppRestriction,
  1191. LPENTRYLIST FAR * lppContainerList,
  1192. ULONG FAR * lpulSearchState)
  1193. {
  1194. #ifdef PARAMETER_VALIDATION
  1195. // Validate the object.
  1196. if (BAD_STANDARD_OBJ(lpCONTAINER, CONTAINER_, GetSearchCriteria, lpVtbl)) {
  1197. // jump table not large enough to support this method
  1198. DebugTraceArg(CONTAINER_GetSearchCriteria, TEXT("Bad object/vtble"));
  1199. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  1200. }
  1201. if (ulFlags & ~(MAPI_UNICODE)) {
  1202. DebugTraceArg(CONTAINER_GetSearchCriteria, TEXT("Unknown Flags"));
  1203. // return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
  1204. }
  1205. // ensure we can write the restriction
  1206. if (lppRestriction && IsBadWritePtr(lppRestriction, sizeof(LPSRestriction))) {
  1207. DebugTraceArg(CONTAINER_GetSearchCriteria, TEXT("Bad Restriction write parameter"));
  1208. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  1209. }
  1210. // ensure we can read the container list
  1211. if (lppContainerList && IsBadWritePtr(lppContainerList, sizeof(LPENTRYLIST))) {
  1212. DebugTraceArg(CONTAINER_GetSearchCriteria, TEXT("Bad ContainerList parameter"));
  1213. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  1214. }
  1215. if (lpulSearchState && IsBadWritePtr(lpulSearchState, sizeof(ULONG))) {
  1216. DebugTraceArg(CONTAINER_GetSearchCriteria, TEXT("lpulSearchState fails address check"));
  1217. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  1218. }
  1219. #endif // PARAMETER_VALIDATION
  1220. return(ResultFromScode(MAPI_E_NO_SUPPORT));
  1221. }
  1222. /***************************************************************************
  1223. Name : CONTAINER::CreateEntry
  1224. Purpose : Creates an entry in the container
  1225. Parameters: lpCONTAINER -> Container object
  1226. cbEntryID = size of entryid
  1227. lpEntryID -> entryID of template
  1228. [ cbEID and lpEID are the Template Entryids
  1229. In reality, these are actually flags that just tell
  1230. us internally what kind of object to create ]
  1231. ulCreateFlags =
  1232. lppMAPIPropEntry -> returned MAPIProp object
  1233. Returns : HRESULT
  1234. Comment :
  1235. ***************************************************************************/
  1236. STDMETHODIMP
  1237. CONTAINER_CreateEntry(LPCONTAINER lpCONTAINER,
  1238. ULONG cbEntryID,
  1239. LPENTRYID lpEntryID,
  1240. ULONG ulCreateFlags,
  1241. LPMAPIPROP FAR * lppMAPIPropEntry)
  1242. {
  1243. BYTE bType;
  1244. #ifdef PARAMETER_VALIDATION
  1245. // Validate the object.
  1246. if (BAD_STANDARD_OBJ(lpCONTAINER, CONTAINER_, CreateEntry, lpVtbl)) {
  1247. // jump table not large enough to support this method
  1248. DebugTraceArg(CONTAINER_CreateEntry, TEXT("Bad object/Vtbl"));
  1249. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  1250. }
  1251. // Check the entryid parameter. It needs to be big enough to hold an entryid.
  1252. // Null entryid are bad
  1253. /*
  1254. if (lpEntryID) {
  1255. if (cbEntryID < offsetof(ENTRYID, ab)
  1256. || IsBadReadPtr((LPVOID) lpEntryID, (UINT)cbEntryID)) {
  1257. DebugTraceArg(CONTAINER_CreateEntry, TEXT("lpEntryID fails address check"));
  1258. return(ResultFromScode(MAPI_E_INVALID_ENTRYID));
  1259. }
  1260. //NFAssertSz(FValidEntryIDFlags(lpEntryID->abFlags),
  1261. // TEXT("Undefined bits set in EntryID flags\n"));
  1262. } else {
  1263. DebugTraceArg(CONTAINER_CreateEntry, TEXT("lpEntryID NULL"));
  1264. return(ResultFromScode(MAPI_E_INVALID_ENTRYID));
  1265. }
  1266. */
  1267. if (ulCreateFlags & ~(CREATE_CHECK_DUP_STRICT | CREATE_CHECK_DUP_LOOSE
  1268. | CREATE_REPLACE | CREATE_MERGE)) {
  1269. DebugTraceArg(CONTAINER_CreateEntry, TEXT("Unknown flags used"));
  1270. // return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
  1271. }
  1272. if (IsBadWritePtr(lppMAPIPropEntry, sizeof(LPMAPIPROP))) {
  1273. DebugTraceArg(CONTAINER_CreateEntry, TEXT("Bad MAPI Property write parameter"));
  1274. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  1275. }
  1276. #endif // PARAMETER_VALIDATION
  1277. #ifdef NEVER
  1278. if (lpCONTAINER->ulType == AB_ROOT)
  1279. return ResultFromScode(MAPI_E_NO_SUPPORT);
  1280. #endif // NEVER
  1281. // What kind of entry are we creating?
  1282. // Default is MailUser
  1283. // The passed in entryid is the Tempalte entry ID
  1284. bType = IsWABEntryID(cbEntryID, lpEntryID, NULL, NULL, NULL, NULL, NULL);
  1285. if (bType == WAB_DEF_MAILUSER || cbEntryID == 0) {
  1286. //
  1287. // Create a new (in memory) entry and return it's mapiprop
  1288. //
  1289. return(HrNewMAILUSER(lpCONTAINER->lpIAB, lpCONTAINER->pmbinOlk, MAPI_MAILUSER, ulCreateFlags, lppMAPIPropEntry));
  1290. } else if (bType == WAB_DEF_DL) {
  1291. //
  1292. // Create a new (in memory) distribution list and return it's mapiprop?
  1293. return(HrNewMAILUSER(lpCONTAINER->lpIAB, lpCONTAINER->pmbinOlk, MAPI_DISTLIST, ulCreateFlags, lppMAPIPropEntry));
  1294. } else {
  1295. DebugTrace(TEXT("CONTAINER_CreateEntry got unknown template entryID\n"));
  1296. return(ResultFromScode(MAPI_E_INVALID_ENTRYID));
  1297. }
  1298. }
  1299. /***************************************************************************
  1300. Name : CONTAINER::CopyEntries
  1301. Purpose : Copies a list of entries into this container.
  1302. Parameters: lpCONTAINER -> Container object
  1303. lpEntries -> List of entryid's to copy
  1304. ulUIParam = HWND
  1305. lpPropgress -> progress dialog structure
  1306. ulFlags =
  1307. Returns : HRESULT
  1308. Comment : Not implemented in WAB.
  1309. ***************************************************************************/
  1310. STDMETHODIMP
  1311. CONTAINER_CopyEntries(LPCONTAINER lpCONTAINER,
  1312. LPENTRYLIST lpEntries,
  1313. ULONG_PTR ulUIParam,
  1314. LPMAPIPROGRESS lpProgress,
  1315. ULONG ulFlags)
  1316. {
  1317. #ifdef PARAMETER_VALIDATION
  1318. if (BAD_STANDARD_OBJ(lpCONTAINER, CONTAINER_, CopyEntries, lpVtbl)) {
  1319. // jump table not large enough to support this method
  1320. DebugTraceArg(CONTAINER_CopyEntries, TEXT("Bad object/vtbl"));
  1321. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  1322. }
  1323. // ensure we can read the container list
  1324. if (FBadEntryList(lpEntries)) {
  1325. DebugTraceArg(CONTAINER_CopyEntries, TEXT("Bad Entrylist parameter"));
  1326. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  1327. }
  1328. if (ulUIParam && ! IsWindow((HWND)ulUIParam)) {
  1329. DebugTraceArg(CONTAINER_CopyEntries, TEXT("Invalid window handle"));
  1330. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  1331. }
  1332. if (lpProgress && IsBadReadPtr(lpProgress, sizeof(IMAPIProgress))) {
  1333. DebugTraceArg(CONTAINER_CopyEntries, TEXT("Bad MAPI Progress parameter"));
  1334. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  1335. }
  1336. if (ulFlags & ~(AB_NO_DIALOG | CREATE_CHECK_DUP_LOOSE)) {
  1337. DebugTraceArg(CONTAINER_CreateEntry, TEXT("Unknown flags used"));
  1338. // return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
  1339. }
  1340. #endif // PARAMETER_VALIDATION
  1341. return(ResultFromScode(MAPI_E_NO_SUPPORT));
  1342. }
  1343. /***************************************************************************
  1344. Name : CONTAINER::DeleteEntries
  1345. Purpose : Delete entries from this container.
  1346. Parameters: lpCONTAINER -> Container object
  1347. lpEntries -> list of entryid's to delete
  1348. ulFlags =
  1349. Returns : HRESULT
  1350. Comment :
  1351. ***************************************************************************/
  1352. STDMETHODIMP
  1353. CONTAINER_DeleteEntries(LPCONTAINER lpCONTAINER,
  1354. LPENTRYLIST lpEntries,
  1355. ULONG ulFlags)
  1356. {
  1357. ULONG i;
  1358. HRESULT hResult = hrSuccess;
  1359. ULONG cDeleted = 0;
  1360. ULONG cToDelete;
  1361. #ifndef DONT_ADDREF_PROPSTORE
  1362. {
  1363. SCODE sc;
  1364. if ((FAILED(sc = OpenAddRefPropertyStore(NULL, lpCONTAINER->lpIAB->lpPropertyStore)))) {
  1365. hResult = ResultFromScode(sc);
  1366. goto exitNotAddRefed;
  1367. }
  1368. }
  1369. #endif
  1370. #ifdef PARAMETER_VALIDATION
  1371. if (BAD_STANDARD_OBJ(lpCONTAINER, CONTAINER_, DeleteEntries, lpVtbl)) {
  1372. // jump table not large enough to support this method
  1373. DebugTraceArg(CONTAINER_DeleteEntries, TEXT("Bad object/vtbl"));
  1374. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  1375. }
  1376. // ensure we can read the container list
  1377. if (FBadEntryList(lpEntries)) {
  1378. DebugTraceArg(CONTAINER_DeleteEntries, TEXT("Bad Entrylist parameter"));
  1379. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  1380. }
  1381. if (ulFlags) {
  1382. DebugTraceArg(CONTAINER_CreateEntry, TEXT("Unknown flags used"));
  1383. // return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
  1384. }
  1385. #endif // PARAMETER_VALIDATION
  1386. // List of entryids is in lpEntries. This is a counted array of
  1387. // entryid SBinary structs.
  1388. cToDelete = lpEntries->cValues;
  1389. // Delete each entry
  1390. for (i = 0; i < cToDelete; i++)
  1391. {
  1392. if(0 != IsWABEntryID(lpEntries->lpbin[i].cb,
  1393. (LPENTRYID) lpEntries->lpbin[i].lpb,
  1394. NULL, NULL, NULL, NULL, NULL))
  1395. {
  1396. DebugTrace(TEXT("CONTAINER_DeleteEntries got bad entryid of size %u\n"), lpEntries->lpbin[i].cb);
  1397. continue;
  1398. }
  1399. hResult = DeleteCertStuff((LPADRBOOK)lpCONTAINER->lpIAB, (LPENTRYID)lpEntries->lpbin[i].lpb, lpEntries->lpbin[i].cb);
  1400. hResult = HrSaveHotmailSyncInfoOnDeletion((LPADRBOOK) lpCONTAINER->lpIAB, &(lpEntries->lpbin[i]));
  1401. if (HR_FAILED(hResult = DeleteRecord(lpCONTAINER->lpIAB->lpPropertyStore->hPropertyStore,
  1402. &(lpEntries->lpbin[i])))) {
  1403. DebugTraceResult( TEXT("DeleteEntries: DeleteRecord"), hResult);
  1404. continue;
  1405. }
  1406. cDeleted++;
  1407. }
  1408. if (! hResult) {
  1409. if (cDeleted != cToDelete) {
  1410. hResult = ResultFromScode(MAPI_W_PARTIAL_COMPLETION);
  1411. DebugTrace(TEXT("DeleteEntries deleted %u of requested %u\n"), cDeleted, cToDelete);
  1412. }
  1413. }
  1414. #ifndef DONT_ADDREF_PROPSTORE
  1415. ReleasePropertyStore(lpCONTAINER->lpIAB->lpPropertyStore);
  1416. exitNotAddRefed:
  1417. #endif
  1418. return(hResult);
  1419. }
  1420. /***************************************************************************
  1421. Name : CONTAINER::ResolveNames
  1422. Purpose : Resolve names from this container.
  1423. Parameters: lpCONTAINER -> Container object
  1424. lptagColSet -> Set of property tags to get from each
  1425. resolved match.
  1426. ulFlags = flags (none valid)
  1427. WAB_IGNORE_PROFILES means that even if this is
  1428. a profile enabled session, search the whole WAB,
  1429. not just the current container
  1430. WAB_RESOLVE_ALL_EMAILS - valid if trying to resolve an
  1431. e-mail address and we want to search across all e-mail addresses
  1432. not just the default. Should be used sparingly since it's a labor
  1433. intensive search
  1434. MAPI_UNICODE - Adrlist strings are in UNICODE and should return them
  1435. in Unicode
  1436. lpAdrList -> [in] set of addresses to resolve, [out] resolved
  1437. addresses.
  1438. lpFlagList -> [in/out] resolve flags.
  1439. Returns : HRESULT
  1440. Comment :
  1441. ***************************************************************************/
  1442. STDMETHODIMP
  1443. CONTAINER_ResolveNames(LPCONTAINER lpRoot,
  1444. LPSPropTagArray lptagaColSet,
  1445. ULONG ulFlags,
  1446. LPADRLIST lpAdrList,
  1447. LPFlagList lpFlagList)
  1448. {
  1449. LPADRENTRY lpAdrEntry;
  1450. ULONG i, j;
  1451. ULONG ulCount = 1;
  1452. LPSBinary rgsbEntryIDs = NULL;
  1453. HRESULT hResult = hrSuccess;
  1454. LPMAPIPROP lpMailUser = NULL;
  1455. LPSPropTagArray lpPropTags;
  1456. LPSPropValue lpPropArray = NULL;
  1457. LPSPropValue lpPropArrayNew = NULL;
  1458. ULONG ulObjType, cPropsNew;
  1459. ULONG cValues;
  1460. SCODE sc = SUCCESS_SUCCESS;
  1461. LPTSTR lpsz = NULL;
  1462. #ifndef DONT_ADDREF_PROPSTORE
  1463. if ((FAILED(sc = OpenAddRefPropertyStore(NULL, lpRoot->lpIAB->lpPropertyStore)))) {
  1464. hResult = ResultFromScode(sc);
  1465. goto exitNotAddRefed;
  1466. }
  1467. #endif
  1468. #ifdef PARAMETER_VALIDATION
  1469. if (BAD_STANDARD_OBJ(lpRoot, CONTAINER_, ResolveNames, lpVtbl)) {
  1470. // jump table not large enough to support this method
  1471. DebugTraceArg(CONTAINER_ResolveNames, TEXT("Bad object/vtbl"));
  1472. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  1473. }
  1474. // BUGBUG: Should also check lptagColSet, lpAdrList and lpFlagList!
  1475. if (ulFlags&(~(WAB_IGNORE_PROFILES|WAB_RESOLVE_ALL_EMAILS|MAPI_UNICODE))) {
  1476. DebugTraceArg(CONTAINER_ResolveNames, TEXT("Unknown flags used"));
  1477. // return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
  1478. }
  1479. #endif // PARAMETER_VALIDATION
  1480. // if no set of props to return is specified, return the default set
  1481. lpPropTags = lptagaColSet ? lptagaColSet : (LPSPropTagArray)&ptaResolveDefaults;
  1482. if(ulFlags & WAB_RESOLVE_ALL_EMAILS)
  1483. {
  1484. hResult = HrSmartResolve(lpRoot->lpIAB, (LPABCONT)lpRoot,
  1485. WAB_RESOLVE_ALL_EMAILS | (ulFlags & MAPI_UNICODE ? WAB_RESOLVE_UNICODE : 0),
  1486. lpAdrList, lpFlagList, NULL);
  1487. // If it's too complex, then just search normally
  1488. if (MAPI_E_TOO_COMPLEX != hResult) {
  1489. goto exit;
  1490. }
  1491. else {
  1492. hResult = hrSuccess;
  1493. }
  1494. }
  1495. // search for each name in the lpAdrList
  1496. for (i = 0; i < lpAdrList->cEntries; i++)
  1497. {
  1498. // Make sure we don't resolve an entry which is already resolved.
  1499. if (lpFlagList->ulFlag[i] == MAPI_RESOLVED)
  1500. {
  1501. continue;
  1502. }
  1503. lpAdrEntry = &(lpAdrList->aEntries[i]);
  1504. // Search for this address
  1505. // BUGBUG: For now, we only resolve perfect matches in the PR_DISPLAY_NAME or PR_EMAIL_ADDRESS
  1506. // all other properties in ADRLIST are ignored
  1507. // Look through the ADRENTRY for a PR_DISPLAY_NAME and create an SPropRestriction
  1508. // to pass down to the property store.
  1509. for (j = 0; j < lpAdrEntry->cValues; j++)
  1510. {
  1511. ULONG ulPropTag = lpAdrEntry->rgPropVals[j].ulPropTag;
  1512. if(!(ulFlags & MAPI_UNICODE) && PROP_TYPE(ulPropTag)==PT_STRING8)
  1513. ulPropTag = CHANGE_PROP_TYPE(ulPropTag, PT_UNICODE);
  1514. if ( ulPropTag == PR_DISPLAY_NAME || ulPropTag == PR_EMAIL_ADDRESS)
  1515. {
  1516. ULONG Flags = AB_FUZZY_FAIL_AMBIGUOUS | AB_FUZZY_FIND_ALL;
  1517. if(!(ulFlags & WAB_IGNORE_PROFILES))
  1518. {
  1519. // if we didn't ask to surpress profile awareness,
  1520. // and profile awareness is enabled, restrict this search to
  1521. // the single folder
  1522. if(bAreWABAPIProfileAware(lpRoot->lpIAB))
  1523. Flags |= AB_FUZZY_FIND_PROFILEFOLDERONLY;
  1524. }
  1525. ulCount = 1;
  1526. // Search the property store
  1527. Assert(lpRoot->lpIAB->lpPropertyStore->hPropertyStore);
  1528. if(ulFlags & MAPI_UNICODE)
  1529. {
  1530. lpsz = lpAdrEntry->rgPropVals[j].Value.lpszW;
  1531. }
  1532. else
  1533. {
  1534. LocalFreeAndNull(&lpsz);
  1535. lpsz = ConvertAtoW(lpAdrEntry->rgPropVals[j].Value.lpszA);
  1536. }
  1537. if (HR_FAILED(hResult = HrFindFuzzyRecordMatches(lpRoot->lpIAB->lpPropertyStore->hPropertyStore,
  1538. lpRoot->pmbinOlk,
  1539. lpsz,
  1540. Flags,
  1541. &ulCount, // IN: number of matches to find, OUT: number found
  1542. &rgsbEntryIDs)))
  1543. {
  1544. if (ResultFromScode(hResult) == MAPI_E_AMBIGUOUS_RECIP)
  1545. {
  1546. lpFlagList->ulFlag[i] = MAPI_AMBIGUOUS;
  1547. continue;
  1548. } else
  1549. {
  1550. DebugTraceResult( TEXT("HrFindFuzzyRecordMatches"), hResult);
  1551. goto exit;
  1552. }
  1553. }
  1554. if (ulCount) { // Was a match found?
  1555. Assert(rgsbEntryIDs);
  1556. if (rgsbEntryIDs)
  1557. {
  1558. if (ulCount == 1)
  1559. {
  1560. // Open the entry and read the properties you care about.
  1561. if (HR_FAILED(hResult = lpRoot->lpVtbl->OpenEntry(lpRoot,
  1562. rgsbEntryIDs[0].cb, // cbEntryID
  1563. (LPENTRYID)(rgsbEntryIDs[0].lpb), // entryid of first match
  1564. NULL, // interface
  1565. 0, // ulFlags
  1566. &ulObjType, // returned object type
  1567. (LPUNKNOWN *)&lpMailUser)))
  1568. {
  1569. // Failed! Hmmm.
  1570. DebugTraceResult( TEXT("ResolveNames OpenEntry"), hResult);
  1571. goto exit;
  1572. }
  1573. Assert(lpMailUser);
  1574. if (HR_FAILED(hResult = lpMailUser->lpVtbl->GetProps(lpMailUser,
  1575. lpPropTags, // lpPropTagArray
  1576. (ulFlags & MAPI_UNICODE) ? MAPI_UNICODE : 0,
  1577. &cValues, // how many properties were there?
  1578. &lpPropArray)))
  1579. {
  1580. DebugTraceResult( TEXT("ResolveNames GetProps"), hResult);
  1581. goto exit;
  1582. }
  1583. UlRelease(lpMailUser);
  1584. lpMailUser = NULL;
  1585. // Now, construct the new ADRENTRY
  1586. // (Allocate a new one, free the old one.
  1587. Assert(lpPropArray);
  1588. // Merge the new props with the ADRENTRY props
  1589. if (sc = ScMergePropValues(lpAdrEntry->cValues,
  1590. lpAdrEntry->rgPropVals, // source1
  1591. cValues,
  1592. lpPropArray, // source2
  1593. &cPropsNew,
  1594. &lpPropArrayNew))
  1595. {
  1596. goto exit;
  1597. }
  1598. // [PaulHi] 2/1/99 GetProps now returns the requested tag string
  1599. // types. So if our client is non-UNICODE make sure we convert any
  1600. // UNICODE string properties to ANSI.
  1601. if (!(ulFlags & MAPI_UNICODE))
  1602. {
  1603. if(sc = ScConvertWPropsToA((LPALLOCATEMORE) (&MAPIAllocateMore), (LPSPropValue ) lpPropArrayNew, (ULONG) cPropsNew, 0))
  1604. goto exit;
  1605. }
  1606. // Free the original prop value array
  1607. FreeBufferAndNull((LPVOID *) (&(lpAdrEntry->rgPropVals)));
  1608. lpAdrEntry->cValues = cPropsNew;
  1609. lpAdrEntry->rgPropVals = lpPropArrayNew;
  1610. FreeBufferAndNull(&lpPropArray);
  1611. // Mark this entry as found.
  1612. lpFlagList->ulFlag[i] = MAPI_RESOLVED;
  1613. } else
  1614. {
  1615. DebugTrace(TEXT("ResolveNames found more than 1 match... MAPI_AMBIGUOUS\n"));
  1616. lpFlagList->ulFlag[i] = MAPI_AMBIGUOUS;
  1617. }
  1618. FreeEntryIDs(lpRoot->lpIAB->lpPropertyStore->hPropertyStore,
  1619. ulCount,
  1620. rgsbEntryIDs);
  1621. }
  1622. }
  1623. break;
  1624. }
  1625. }
  1626. }
  1627. exit:
  1628. #ifndef DONT_ADDREF_PROPSTORE
  1629. ReleasePropertyStore(lpRoot->lpIAB->lpPropertyStore);
  1630. exitNotAddRefed:
  1631. #endif
  1632. FreeBufferAndNull(&lpPropArray);
  1633. UlRelease(lpMailUser);
  1634. if(!(ulFlags & MAPI_UNICODE))
  1635. LocalFreeAndNull(&lpsz);
  1636. return(hResult);
  1637. }
  1638. #ifdef NOTIFICATION // save for notifications
  1639. /***************************************************************************
  1640. Name : lTableNotifyCallBack
  1641. Purpose : Callback function for notifications
  1642. Parameters: lpvContext ->
  1643. cNotif =
  1644. lpNotif ->
  1645. Returns :
  1646. Comment :
  1647. ***************************************************************************/
  1648. long STDAPICALLTYPE
  1649. lTableNotifyCallBack(LPVOID lpvContext,
  1650. ULONG cNotif,
  1651. LPNOTIFICATION lpNotif)
  1652. {
  1653. LPTABLEINFO lpTableInfo = (LPTABLEINFO)lpvContext;
  1654. HRESULT hResult;
  1655. LPSRowSet lpsrowsetProv = NULL;
  1656. LPIAB lpIAB = lpTableInfo->lpIAB;
  1657. LPTABLEDATA lpTableData;
  1658. ULONG ulcTableInfo;
  1659. LPTABLEINFO pargTableInfo;
  1660. Assert(lpvContext);
  1661. Assert(lpNotif);
  1662. Assert(lpTableInfo->lpTable);
  1663. Assert(lpTableInfo->lpIAB);
  1664. Assert(! IsBadWritePtr(lpTableInfo->lpIAB, sizeof(IAB)));
  1665. // To avoid deadlock we will NOT enter the Address Books critical
  1666. // section. The Address Book must enter our critical section BEFORE
  1667. // it modifies anything our callback needs
  1668. // if the container is null then the tableinfo structure is being
  1669. // used to keep track of the open one off tables otherwise its
  1670. // being used to keep track of the open hierarchy tables.
  1671. if (lpTableInfo->lpContainer == NULL) {
  1672. // open one off table data
  1673. lpTableData = lpIAB->lpOOData;
  1674. ulcTableInfo = lpIAB->ulcOOTableInfo;
  1675. pargTableInfo = lpIAB->pargOOTableInfo;
  1676. } else {
  1677. // open hierarchy table data
  1678. lpTableData =lpIAB->lpTableData;
  1679. ulcTableInfo =lpIAB->ulcTableInfo;
  1680. pargTableInfo =lpIAB->pargTableInfo;
  1681. // While we here, blow away the SearchPath cache
  1682. #if defined (WIN32) && !defined (MAC)
  1683. if (fGlobalCSValid) {
  1684. EnterCriticalSection(&csMapiSearchPath);
  1685. } else {
  1686. DebugTrace(TEXT("lTableNotifyCallback: WAB32.DLL already detached.\n"));
  1687. }
  1688. #endif
  1689. FreeBufferAndNull(&(lpIAB->lpspvSearchPathCache));
  1690. lpIAB->lpspvSearchPathCache = NULL;
  1691. #if defined (WIN32) && !defined (MAC)
  1692. if (fGlobalCSValid) {
  1693. LeaveCriticalSection(&csMapiSearchPath);
  1694. } else {
  1695. DebugTrace(TEXT("lTableNotifyCallback: WAB32.DLL got detached.\n"));
  1696. }
  1697. #endif
  1698. }
  1699. switch (lpNotif->info.tab.ulTableEvent) {
  1700. case TABLE_ROW_ADDED:
  1701. case TABLE_ROW_DELETED:
  1702. case TABLE_ROW_MODIFIED:
  1703. case TABLE_CHANGED: {
  1704. ULONG uliTable;
  1705. // table has changed. We need to delete all the rows of
  1706. // this table in the tad and then add all the rows currently
  1707. // in that table to the tad. We need to find the start and
  1708. // end row indexes of the tables data in the tad.
  1709. // get the index of the given table in the table info array
  1710. for (uliTable=0; uliTable < ulcTableInfo; uliTable++) {
  1711. if (pargTableInfo[uliTable].lpTable==lpTableInfo->lpTable) {
  1712. break;
  1713. }
  1714. }
  1715. Assert(uliTable < ulcTableInfo);
  1716. // Delete all the rows of the table in the tad by querying
  1717. // all the rows from the TEXT("restricted") view for this provider
  1718. // and then calling HrDeleteRows.
  1719. // We'll add all the new rows back later
  1720. if (HR_FAILED(hResult = HrQueryAllRows(lpTableInfo->lpmtRestricted,
  1721. NULL, NULL, NULL, 0, &lpsrowsetProv))) {
  1722. DebugTrace(TEXT("lTableNotifyCallBack() - Can't query rows from restricted view.\n"));
  1723. goto ret;
  1724. }
  1725. if (lpsrowsetProv->cRows) {
  1726. // Only call HrDeleteRows if there are rows to delete
  1727. if (HR_FAILED(hResult = lpTableData->lpVtbl->HrDeleteRows(lpTableData, 0, lpsrowsetProv, NULL))) {
  1728. DebugTrace(TEXT("lTableNotifyCallBack() - Can't delete rows.\n"));
  1729. goto ret;
  1730. }
  1731. }
  1732. // Add the contents of the provider table back to the TAD.
  1733. // Seek to the beginning of the input table
  1734. if (HR_FAILED(hResult = lpTableInfo->lpTable->lpVtbl->SeekRow(lpTableInfo->lpTable , BOOKMARK_BEGINNING, 0, NULL))) {
  1735. // table must be empty
  1736. goto ret;
  1737. }
  1738. // Add all rows from the given provider back to the merged table.
  1739. // NOTE! HrMergeTableRows takes a 1 based provider NUMBER not
  1740. // a provider index.
  1741. if (HR_FAILED(hResult = HrMergeTableRows(lpTableData, lpTableInfo->lpTable, uliTable + 1))) {
  1742. //$BUG Handle per provider errors.
  1743. DebugTrace(TEXT("lTableNotifyCallBack() - HrMergeTableRows returns (hResult = 0x%08lX)\n"), hResult);
  1744. }
  1745. break;
  1746. }
  1747. }
  1748. ret:
  1749. // free the row set returned from MAPITABLE::QueryRows
  1750. FreeProws(lpsrowsetProv);
  1751. return(0);
  1752. }
  1753. /***************************************************************************
  1754. Name : HrGetBookmarkInTad
  1755. Purpose : Returns the row number in the tabledata object of the row
  1756. that corresponds to the row at the bookmark in the given table.
  1757. Parameters: lpTableData ->
  1758. lpTable ->
  1759. Bookmark =
  1760. puliRow ->
  1761. Returns : HRESULT
  1762. Comment :
  1763. ***************************************************************************/
  1764. static HRESULT
  1765. HrGetBookmarkInTad(LPTABLEDATA lpTableData,
  1766. LPMAPITABLE lpTable,
  1767. BOOKMARK Bookmark,
  1768. ULONG * puliRow)
  1769. {
  1770. LPSRowSet lpsRowSet = NULL;
  1771. LPSRow lpsRow;
  1772. ULONG uliProp;
  1773. HRESULT hResult = hrSuccess;
  1774. Assert(lpTableData);
  1775. Assert(lpTable);
  1776. Assert(puliRow);
  1777. // seek to the bookmark in the given table
  1778. if (HR_FAILED(hResult=lpTable->lpVtbl->SeekRow(
  1779. lpTable,
  1780. Bookmark,
  1781. 0,
  1782. NULL))) {
  1783. goto err;
  1784. }
  1785. // get the row
  1786. if (HR_FAILED(hResult=lpTable->lpVtbl->QueryRows(
  1787. lpTable,
  1788. (Bookmark==BOOKMARK_END ? -1 : 1),
  1789. TBL_NOADVANCE,
  1790. &lpsRowSet))) {
  1791. goto err;
  1792. }
  1793. // find the entryid in the property value array
  1794. for (uliProp = 0; uliProp < lpsRowSet->aRow[0].cValues; uliProp++) {
  1795. if (lpsRowSet->aRow[0].lpProps[uliProp].ulPropTag == PR_ENTRYID) {
  1796. break;
  1797. }
  1798. }
  1799. Assert(uliProp < lpsRowSet->aRow[0].cValues);
  1800. // Look for the row in the tad with the same entryid.
  1801. if (HR_FAILED(hResult=lpTableData->lpVtbl->HrQueryRow(
  1802. lpTableData,
  1803. lpsRowSet->aRow[0].lpProps+uliProp,
  1804. &lpsRow,
  1805. puliRow))) {
  1806. // can't find the row in the table data should never happen
  1807. goto err;
  1808. }
  1809. // free the row set returned from QueryRows on the tad
  1810. FreeBufferAndNull(&lpsRow);
  1811. err:
  1812. // free the row set returned from MAPITABLE::QueryRows
  1813. FreeProws(lpsRowSet);
  1814. return(hResult);
  1815. }
  1816. #endif
  1817. /*
  1818. - FindContainer
  1819. -
  1820. * Given an entryid, searches in the cached list of containers for
  1821. * the structure containing the container so that we can get
  1822. * additional container properties out of the strucutre painlessly
  1823. *
  1824. * Returns a pointer to an OlkContInfo structure so don't need to free
  1825. * the returned value
  1826. */
  1827. OlkContInfo *FindContainer(LPIAB lpIAB, ULONG cbEID, LPENTRYID lpEID)
  1828. {
  1829. ULONG iolkci, colkci;
  1830. BOOL ul=FALSE;
  1831. OlkContInfo *rgolkci;
  1832. Assert(lpIAB);
  1833. Assert(lpIAB->lpPropertyStore);
  1834. // If the WAB session is Profile Aware, then the WAB's list of containers
  1835. // is cached on the IAB object
  1836. if(bIsWABSessionProfileAware(lpIAB))
  1837. {
  1838. colkci = lpIAB->cwabci;
  1839. rgolkci = lpIAB->rgwabci;
  1840. }
  1841. else // it's in the list of the Outlook containers
  1842. {
  1843. colkci = lpIAB->lpPropertyStore->colkci;
  1844. rgolkci = lpIAB->lpPropertyStore->rgolkci;
  1845. }
  1846. // if we didn't find any cached info, nothing more to do
  1847. if(!colkci || !rgolkci)
  1848. return NULL;
  1849. for (iolkci = 1; iolkci < colkci; iolkci++)
  1850. {
  1851. Assert(rgolkci[iolkci].lpEntryID);
  1852. if (rgolkci[iolkci].lpEntryID &&
  1853. (cbEID == rgolkci[iolkci].lpEntryID->cb))
  1854. {
  1855. // Look for the match and return that item
  1856. Assert(rgolkci[iolkci].lpEntryID->lpb);
  1857. if(cbEID && rgolkci[iolkci].lpEntryID->lpb &&
  1858. (0 == memcmp((LPVOID) lpEID,(LPVOID)rgolkci[iolkci].lpEntryID->lpb, cbEID)))
  1859. {
  1860. ul = TRUE;
  1861. break;
  1862. }
  1863. }
  1864. }
  1865. return(ul ? &(rgolkci[iolkci]) : NULL);
  1866. }