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.

1037 lines
34 KiB

  1. /*
  2. * ABROOT.C
  3. *
  4. * IMAPIContainer implementation for the address book's root
  5. * container.
  6. */
  7. #include "_apipch.h"
  8. extern SPropTagArray sosPR_ROWID;
  9. /*
  10. * Root jump table is defined here...
  11. */
  12. ROOT_Vtbl vtblROOT =
  13. {
  14. VTABLE_FILL
  15. (ROOT_QueryInterface_METHOD *) CONTAINER_QueryInterface,
  16. (ROOT_AddRef_METHOD *) WRAP_AddRef,
  17. (ROOT_Release_METHOD *) CONTAINER_Release,
  18. (ROOT_GetLastError_METHOD *) IAB_GetLastError,
  19. (ROOT_SaveChanges_METHOD *) WRAP_SaveChanges,
  20. (ROOT_GetProps_METHOD *) WRAP_GetProps,
  21. (ROOT_GetPropList_METHOD *) WRAP_GetPropList,
  22. (ROOT_OpenProperty_METHOD *) CONTAINER_OpenProperty,
  23. (ROOT_SetProps_METHOD *) WRAP_SetProps,
  24. (ROOT_DeleteProps_METHOD *) WRAP_DeleteProps,
  25. (ROOT_CopyTo_METHOD *) WRAP_CopyTo,
  26. (ROOT_CopyProps_METHOD *) WRAP_CopyProps,
  27. (ROOT_GetNamesFromIDs_METHOD *) WRAP_GetNamesFromIDs,
  28. (ROOT_GetIDsFromNames_METHOD *) WRAP_GetIDsFromNames,
  29. ROOT_GetContentsTable,
  30. ROOT_GetHierarchyTable,
  31. ROOT_OpenEntry,
  32. ROOT_SetSearchCriteria,
  33. ROOT_GetSearchCriteria,
  34. ROOT_CreateEntry,
  35. ROOT_CopyEntries,
  36. ROOT_DeleteEntries,
  37. ROOT_ResolveNames
  38. };
  39. //
  40. // Interfaces supported by this object
  41. //
  42. #define ROOT_cInterfaces 3
  43. LPIID ROOT_LPIID[ROOT_cInterfaces] =
  44. {
  45. (LPIID)&IID_IABContainer,
  46. (LPIID)&IID_IMAPIContainer,
  47. (LPIID)&IID_IMAPIProp
  48. };
  49. // Registry strings
  50. const LPTSTR szWABKey = TEXT("Software\\Microsoft\\WAB");
  51. // PR_AB_PROVIDER_ID for Outlook
  52. static const MAPIUID muidCAB = {0xfd,0x42,0xaa,0x0a,0x18,0xc7,0x1a,0x10,0xe8,0x85,0x0B,0x65,0x1C,0x24,0x00,0x00};
  53. /*
  54. -
  55. - SetContainerlpProps
  56. *
  57. * The ROOT container will have a bunch of entries with props for each entry
  58. * The props are set in one place here
  59. *
  60. lpProps - LPSPropValue array in which we are storing the props
  61. lpszName - Container name
  62. iRow - Row of this entry in the table (?)
  63. cb, lpb - entryid of the container
  64. lpEID - alternat way of passing in the EID
  65. ulContainerFlags - any flags we want to cache on the container
  66. ulDepth ?
  67. bProviderID ?
  68. bLDAP - identifies LDAP containers which need some extra props
  69. fLDAPResolve - whether the LDAP container is used for name resolution or not
  70. */
  71. void SetContainerlpProps(LPSPropValue lpProps, LPTSTR lpszName, ULONG iRow,
  72. ULONG cb, LPBYTE lpb, LPSBinary lpEID,
  73. ULONG ulContainerFlags,
  74. ULONG ulDepth, BOOL bProviderID,
  75. ULONG ulFlags,
  76. BOOL bLDAP, BOOL fLDAPResolve)
  77. {
  78. LPSTR lpszNameA = NULL;
  79. if(!(ulFlags & MAPI_UNICODE)) // <note> this assumes UNICODE is defined
  80. ScWCToAnsiMore((LPALLOCATEMORE) (&MAPIAllocateMore), lpProps, lpszName, &lpszNameA);
  81. DebugTrace(TEXT("Adding root-table container:%s\n"),lpszName);
  82. lpProps[ircPR_DISPLAY_TYPE].ulPropTag = PR_DISPLAY_TYPE;
  83. lpProps[ircPR_DISPLAY_TYPE].Value.l = DT_LOCAL;
  84. lpProps[ircPR_OBJECT_TYPE].ulPropTag = PR_OBJECT_TYPE;
  85. lpProps[ircPR_OBJECT_TYPE].Value.l = MAPI_ABCONT;
  86. lpProps[ircPR_ROWID].ulPropTag = PR_ROWID;
  87. lpProps[ircPR_ROWID].Value.l = iRow;
  88. lpProps[ircPR_DEPTH].ulPropTag = PR_DEPTH;
  89. lpProps[ircPR_DEPTH].Value.l = ulDepth;
  90. lpProps[ircPR_CONTAINER_FLAGS].ulPropTag = PR_CONTAINER_FLAGS;
  91. lpProps[ircPR_CONTAINER_FLAGS].Value.l = ulContainerFlags;
  92. if(bLDAP)
  93. {
  94. if(ulFlags & MAPI_UNICODE) // <note> this assumes UNICODE is defined
  95. {
  96. lpProps[ircPR_WAB_LDAP_SERVER].ulPropTag = PR_WAB_LDAP_SERVER;
  97. lpProps[ircPR_WAB_LDAP_SERVER].Value.lpszW = lpszName;
  98. }
  99. else
  100. {
  101. lpProps[ircPR_WAB_LDAP_SERVER].ulPropTag = CHANGE_PROP_TYPE( PR_WAB_LDAP_SERVER, PT_STRING8);
  102. lpProps[ircPR_WAB_LDAP_SERVER].Value.lpszA = lpszNameA;
  103. }
  104. lpProps[ircPR_WAB_RESOLVE_FLAG].ulPropTag = PR_WAB_RESOLVE_FLAG;
  105. lpProps[ircPR_WAB_RESOLVE_FLAG].Value.b = (USHORT) !!fLDAPResolve;
  106. }
  107. else
  108. {
  109. lpProps[ircPR_WAB_LDAP_SERVER].ulPropTag = PR_NULL;
  110. lpProps[ircPR_WAB_RESOLVE_FLAG].ulPropTag = PR_NULL;
  111. }
  112. if(ulFlags & MAPI_UNICODE) // <note> this assumes UNICODE is defined
  113. {
  114. lpProps[ircPR_DISPLAY_NAME].ulPropTag = PR_DISPLAY_NAME;
  115. lpProps[ircPR_DISPLAY_NAME].Value.lpszW = lpszName;
  116. }
  117. else
  118. {
  119. lpProps[ircPR_DISPLAY_NAME].ulPropTag = CHANGE_PROP_TYPE( PR_DISPLAY_NAME, PT_STRING8);
  120. lpProps[ircPR_DISPLAY_NAME].Value.lpszA = lpszNameA;
  121. }
  122. if(bProviderID)
  123. {
  124. lpProps[ircPR_AB_PROVIDER_ID].ulPropTag = PR_AB_PROVIDER_ID;
  125. lpProps[ircPR_AB_PROVIDER_ID].Value.bin.cb = sizeof(MAPIUID);
  126. lpProps[ircPR_AB_PROVIDER_ID].Value.bin.lpb = (LPBYTE)&muidCAB;
  127. } else
  128. {
  129. lpProps[ircPR_AB_PROVIDER_ID].ulPropTag = PR_NULL;
  130. }
  131. lpProps[ircPR_ENTRYID].ulPropTag = PR_ENTRYID;
  132. if(lpEID)
  133. lpProps[ircPR_ENTRYID].Value.bin = *lpEID;
  134. else
  135. {
  136. lpProps[ircPR_ENTRYID].Value.bin.cb = cb;
  137. lpProps[ircPR_ENTRYID].Value.bin.lpb = lpb;
  138. }
  139. // Make certain we have proper indicies.
  140. // For now, we will equate PR_INSTANCE_KEY and PR_RECORD_KEY to PR_ENTRYID.
  141. lpProps[ircPR_INSTANCE_KEY].ulPropTag = PR_INSTANCE_KEY;
  142. lpProps[ircPR_INSTANCE_KEY].Value.bin.cb = lpProps[ircPR_ENTRYID].Value.bin.cb;
  143. lpProps[ircPR_INSTANCE_KEY].Value.bin.lpb = lpProps[ircPR_ENTRYID].Value.bin.lpb;
  144. lpProps[ircPR_RECORD_KEY].ulPropTag = PR_RECORD_KEY;
  145. lpProps[ircPR_RECORD_KEY].Value.bin.cb = lpProps[ircPR_ENTRYID].Value.bin.cb;
  146. lpProps[ircPR_RECORD_KEY].Value.bin.lpb = lpProps[ircPR_ENTRYID].Value.bin.lpb;
  147. }
  148. /*
  149. - bIsDupeContainerName
  150. -
  151. * The Root_GetContentsTable fails badly if there are multiple containers
  152. * with the same index name because the Table methods can't handle it ..
  153. *
  154. * Therefore, to prevent such problems, we double-check if a container name
  155. * is duplicated before adding it to the container list.
  156. *
  157. */
  158. BOOL bIsDupeContainerName(LPSRowSet lpsrs, LPTSTR lpszName)
  159. {
  160. ULONG i = 0;
  161. BOOL bRet = FALSE;
  162. // walk through the rows one by one
  163. for(i=0;i<lpsrs->cRows;i++)
  164. {
  165. LPSPropValue lpProps = lpsrs->aRow[i].lpProps;
  166. if(!lpProps || !lpsrs->aRow[i].cValues)
  167. continue;
  168. if( lpProps[ircPR_DISPLAY_NAME].ulPropTag == PR_DISPLAY_NAME &&
  169. !lstrcmpi(lpProps[ircPR_DISPLAY_NAME].Value.LPSZ, lpszName))
  170. {
  171. DebugTrace(TEXT("Found dupe container name .. skipping ...\n"));
  172. bRet = TRUE;
  173. break;
  174. }
  175. }
  176. return bRet;
  177. }
  178. /***************************************************
  179. *
  180. * The actual ABContainer methods
  181. */
  182. /* ---------
  183. * IMAPIContainer
  184. */
  185. /*************************************************************************
  186. *
  187. *
  188. - ROOT_GetContentsTable
  189. -
  190. *
  191. * ulFlags - WAB_LOCAL_CONTAINERS means don't add the LDAP containers to this table
  192. * Just do the local WAB containers
  193. * WAB_NO_PROFILE_CONTAINERS means don't add the profile containers
  194. * Just add a single local container that will have all the contents
  195. *
  196. */
  197. STDMETHODIMP
  198. ROOT_GetContentsTable(LPROOT lpROOT, ULONG ulFlags, LPMAPITABLE * lppTable)
  199. {
  200. LPTABLEDATA lpTableData = NULL;
  201. HRESULT hResult = hrSuccess;
  202. SCODE sc;
  203. LPSRowSet lpSRowSet = NULL;
  204. LPSPropValue lpProps = NULL;
  205. ULONG i;
  206. ULONG iRow;
  207. ULONG cProps, cRows, colkci = 0, cwabci = 0;
  208. ULONG cLDAPContainers = 0;
  209. TCHAR szBuffer[MAX_PATH];
  210. IImnAccountManager2 * lpAccountManager = NULL;
  211. LPSERVER_NAME lpServerNames = NULL, lpNextServer;
  212. OlkContInfo *rgolkci, *rgwabci;
  213. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  214. BOOL bUserProfileContainersOnly = FALSE;
  215. BOOL bAllContactsContainerOnly = FALSE;
  216. // BUGBUG: This routine actually returns the Hierarchy table, not the
  217. // contents table, but too much code depends on this to change it right
  218. // now.
  219. #ifdef PARAMETER_VALIDATION
  220. // Check to see if it has a jump table
  221. if (IsBadReadPtr(lpROOT, sizeof(LPVOID))) {
  222. // No jump table found
  223. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  224. }
  225. // Check to see that it's ROOTs jump table
  226. if (lpROOT->lpVtbl != &vtblROOT) {
  227. // Not my jump table
  228. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  229. }
  230. if (ulFlags & ~(MAPI_DEFERRED_ERRORS|MAPI_UNICODE|WAB_LOCAL_CONTAINERS|WAB_NO_PROFILE_CONTAINERS)) {
  231. DebugTraceArg(ROOT_GetContentsTable, TEXT("Unknown flags"));
  232. // return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
  233. }
  234. if (IsBadWritePtr(lppTable, sizeof(LPMAPITABLE))) {
  235. DebugTraceArg(ROOT_GetContentsTable, TEXT("Invalid Table parameter"));
  236. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  237. }
  238. #endif // PARAMETER_VALIDATION
  239. EnterCriticalSection(&lpROOT->lpIAB->cs);
  240. // Create a table object
  241. // [PaulHi] 4/5/99 Use the Internal CreateTableData() function that takes
  242. // the ulFlags and will deal with ANSI/UNICODE requests correctly
  243. sc = CreateTableData(
  244. NULL,
  245. (ALLOCATEBUFFER FAR * ) MAPIAllocateBuffer,
  246. (ALLOCATEMORE FAR *) MAPIAllocateMore,
  247. MAPIFreeBuffer,
  248. NULL,
  249. TBLTYPE_DYNAMIC,
  250. PR_RECORD_KEY,
  251. (LPSPropTagArray)&ITableColumnsRoot,
  252. NULL,
  253. 0,
  254. NULL,
  255. ulFlags,
  256. &lpTableData);
  257. if ( FAILED(sc) )
  258. {
  259. DebugTrace(TEXT("CreateTableData() failed %x\n"), sc);
  260. hResult = ResultFromScode(sc);
  261. goto exit;
  262. }
  263. Assert(lpTableData);
  264. if(ulFlags & WAB_NO_PROFILE_CONTAINERS)
  265. bAllContactsContainerOnly = TRUE;
  266. if(ulFlags & MAPI_UNICODE)
  267. ((TAD *)lpTableData)->bMAPIUnicodeTable = TRUE;
  268. // Enumerate the LDAP accounts
  269. if(!(ulFlags & WAB_LOCAL_CONTAINERS))
  270. {
  271. cLDAPContainers = 0;
  272. if (! HR_FAILED(hResult = InitAccountManager(lpROOT->lpIAB, &lpAccountManager, NULL))) {
  273. // Count and enumerate LDAP servers to ServerList
  274. if (hResult = EnumerateLDAPtoServerList(lpAccountManager, &lpServerNames, &cLDAPContainers)) {
  275. DebugTrace(TEXT("EnumerateLDAPtoServerList -> %x\n"), GetScode(hResult));
  276. hResult = hrSuccess; // not fatal
  277. }
  278. } else {
  279. DebugTrace(TEXT("InitAccountManager -> %x\n"), GetScode(hResult));
  280. hResult = hrSuccess;
  281. }
  282. }
  283. // If this is an outlook session then use the outlook's list of containers
  284. // as provided by outlook...
  285. if (pt_bIsWABOpenExSession) {
  286. colkci = lpROOT->lpIAB->lpPropertyStore->colkci;
  287. Assert(colkci);
  288. rgolkci = lpROOT->lpIAB->lpPropertyStore->rgolkci;
  289. Assert(rgolkci);
  290. } else
  291. colkci = 1;
  292. // If we have a user profile active, then dont return the virtual PAB folder
  293. // as part of this table .. only return the actual folders in the user's view
  294. // The test for this is that (1) Have Profiles enabled (2) Have a current user
  295. // and (3) The NO_PROFILE_CONTAINERS should not have been specified
  296. bUserProfileContainersOnly = ( bAreWABAPIProfileAware(lpROOT->lpIAB) &&
  297. bIsThereACurrentUser(lpROOT->lpIAB) &&
  298. !bAllContactsContainerOnly);
  299. // If we have Profile awareness and no NO_PROFILE flag,
  300. // use the wab's list of folder
  301. if (bAreWABAPIProfileAware(lpROOT->lpIAB) && !bAllContactsContainerOnly)
  302. {
  303. cwabci = lpROOT->lpIAB->cwabci;
  304. Assert(cwabci);
  305. rgwabci = lpROOT->lpIAB->rgwabci;
  306. Assert(rgwabci);
  307. } else
  308. cwabci = 1;
  309. // Since outlook and identity_profiles are mutually exclusive, we can
  310. // do '-1' here to remove whatever container we don't need
  311. // and if we don't want ldap containers, we can do another -1
  312. cRows = cwabci + colkci + cLDAPContainers - 1 - (bUserProfileContainersOnly?1:0); // Outlook and Profiles are mutually exclusive
  313. iRow = 0; // current row
  314. // Allocate the SRowSet
  315. if (FAILED(sc = MAPIAllocateBuffer(sizeof(SRowSet) + cRows * sizeof(SRow),
  316. &lpSRowSet))) {
  317. DebugTrace(TEXT("Allocation of SRowSet -> %x\n"), sc);
  318. hResult = ResultFromScode(sc);
  319. goto exit;
  320. }
  321. MAPISetBufferName(lpSRowSet, TEXT("Root_ContentsTable SRowSet"));
  322. // Set each LPSRow to NULL so we can easily free on error
  323. ZeroMemory( lpSRowSet, (UINT) (sizeof(SRowSet) + cRows * sizeof(SRow)));
  324. lpSRowSet->cRows = cRows;
  325. cProps = ircMax;
  326. if (FAILED(sc = MAPIAllocateBuffer(ircMax * sizeof(SPropValue), &lpProps))) {
  327. DebugTrace(TEXT("ROOT_GetContentsTable: Allocation of props -> %x\n"), sc);
  328. hResult = ResultFromScode(sc);
  329. goto exit;
  330. }
  331. //
  332. // Add our PAB container
  333. //
  334. if(!bUserProfileContainersOnly)
  335. {
  336. // Load the display name from resource string
  337. if (!LoadString(hinstMapiX, IDS_ADDRBK_CAPTION, szBuffer, ARRAYSIZE(szBuffer)))
  338. StrCpyN(szBuffer, szEmpty, ARRAYSIZE(szBuffer));
  339. {
  340. ULONG cb = 0;
  341. LPENTRYID lpb = NULL;
  342. if (HR_FAILED(hResult = CreateWABEntryID(WAB_PAB, NULL, NULL, NULL, 0, 0, lpProps, &cb, &lpb)))
  343. goto exit;
  344. // Set props for the pab object
  345. SetContainerlpProps(lpProps,
  346. pt_bIsWABOpenExSession ? lpROOT->lpIAB->lpPropertyStore->rgolkci->lpszName : szBuffer,
  347. iRow,
  348. cb, (LPBYTE)lpb, NULL,
  349. AB_MODIFIABLE | AB_RECIPIENTS,
  350. pt_bIsWABOpenExSession ? 1 : 0,
  351. pt_bIsWABOpenExSession ? TRUE : FALSE,
  352. ulFlags,
  353. FALSE, FALSE);
  354. }
  355. // Attach the props to the SRowSet
  356. lpSRowSet->aRow[iRow].lpProps = lpProps;
  357. lpSRowSet->aRow[iRow].cValues = cProps;
  358. lpSRowSet->aRow[iRow].ulAdrEntryPad = 0;
  359. iRow++;
  360. }
  361. //
  362. // Next, add any additional containers
  363. //
  364. for (i = 1; i < colkci; i++) {
  365. if (FAILED(sc = MAPIAllocateBuffer(ircMax * sizeof(SPropValue), &lpProps))) {
  366. DebugTrace(TEXT("ROOT_GetContentsTable: Allocation of props -> %x\n"), sc);
  367. hResult = ResultFromScode(sc);
  368. goto exit;
  369. }
  370. SetContainerlpProps(lpProps,
  371. rgolkci[i].lpszName, iRow,
  372. 0, NULL, rgolkci[i].lpEntryID,
  373. AB_MODIFIABLE | AB_RECIPIENTS,
  374. 1, TRUE,
  375. ulFlags,
  376. FALSE, FALSE);
  377. // Attach the props to the SRowSet
  378. lpSRowSet->aRow[iRow].lpProps = lpProps;
  379. lpSRowSet->aRow[iRow].cValues = cProps;
  380. lpSRowSet->aRow[iRow].ulAdrEntryPad = 0;
  381. iRow++;
  382. }
  383. for (i = 1; i < cwabci; i++)
  384. {
  385. if (FAILED(sc = MAPIAllocateBuffer(ircMax * sizeof(SPropValue), &lpProps))) {
  386. DebugTrace(TEXT("ROOT_GetContentsTable: Allocation of props -> %x\n"), sc);
  387. hResult = ResultFromScode(sc);
  388. goto exit;
  389. }
  390. SetContainerlpProps(lpProps,
  391. rgwabci[i].lpszName, iRow,
  392. 0, NULL, rgwabci[i].lpEntryID,
  393. AB_MODIFIABLE | AB_RECIPIENTS,
  394. 1, TRUE,
  395. ulFlags,
  396. FALSE, FALSE);
  397. // Attach the props to the SRowSet
  398. lpSRowSet->aRow[iRow].lpProps = lpProps;
  399. lpSRowSet->aRow[iRow].cValues = cProps;
  400. lpSRowSet->aRow[iRow].ulAdrEntryPad = 0;
  401. iRow++;
  402. }
  403. //
  404. // Now, add the LDAP objects
  405. //
  406. lpNextServer = lpServerNames;
  407. for (i = 0; i < cLDAPContainers && lpNextServer; i++)
  408. {
  409. UNALIGNED WCHAR *lpName = lpNextServer->lpszName;
  410. if (lpName)
  411. {
  412. LDAPSERVERPARAMS sParams;
  413. if(bIsDupeContainerName(lpSRowSet, (LPTSTR) lpName))
  414. {
  415. lpSRowSet->cRows--;
  416. goto endloop;
  417. }
  418. //DebugTrace(TEXT("LDAP Server: %s\n"), lpNextServer->lpszName);
  419. cProps = ircMax;
  420. if (FAILED(sc = MAPIAllocateBuffer(ircMax * sizeof(SPropValue), &lpProps))) {
  421. DebugTrace(TEXT("ROOT_GetContentsTable: Allocation of props -> %x\n"), sc);
  422. hResult = ResultFromScode(sc);
  423. goto exit;
  424. }
  425. GetLDAPServerParams(lpNextServer->lpszName, &sParams);
  426. {
  427. ULONG cb = 0;
  428. LPENTRYID lpb = NULL;
  429. LPVOID pv = lpName;
  430. if (HR_FAILED(hResult = CreateWABEntryID(WAB_LDAP_CONTAINER,
  431. pv, // server name
  432. NULL, NULL, 0, 0,
  433. lpProps, &cb, &lpb)))
  434. {
  435. goto exit;
  436. }
  437. SetContainerlpProps(lpProps,
  438. (LPTSTR) lpName, iRow,
  439. cb, (LPBYTE)lpb, NULL,
  440. AB_FIND_ON_OPEN | AB_UNMODIFIABLE,
  441. 0, FALSE,
  442. ulFlags,
  443. TRUE, sParams.fResolve);
  444. }
  445. FreeLDAPServerParams(sParams);
  446. // Attach the props to the SRowSet
  447. lpSRowSet->aRow[iRow].lpProps = lpProps;
  448. lpSRowSet->aRow[iRow].cValues = cProps;
  449. lpSRowSet->aRow[iRow].ulAdrEntryPad = 0;
  450. iRow++;
  451. }
  452. endloop:
  453. lpNextServer = lpNextServer->lpNext;
  454. }
  455. // Add all this data we just created to the the Table.
  456. if (hResult = lpTableData->lpVtbl->HrModifyRows(lpTableData,
  457. 0, // ulFlags
  458. lpSRowSet)) {
  459. DebugTraceResult( TEXT("ROOT_GetContentsTable:HrModifyRows"), hResult);
  460. goto exit;
  461. }
  462. hResult = lpTableData->lpVtbl->HrGetView(lpTableData,
  463. NULL, // LPSSortOrderSet lpsos,
  464. ContentsViewGone, // CALLERRELEASE FAR * lpfReleaseCallback,
  465. 0, // ULONG ulReleaseData,
  466. lppTable); // LPMAPITABLE FAR * lplpmt)
  467. exit:
  468. while(lpServerNames)
  469. {
  470. lpNextServer = lpServerNames;
  471. lpServerNames = lpServerNames->lpNext;
  472. LocalFreeAndNull(&lpNextServer->lpszName);
  473. LocalFreeAndNull(&lpNextServer);
  474. }
  475. FreeProws(lpSRowSet);
  476. // Cleanup table if failure
  477. if (HR_FAILED(hResult)) {
  478. if (lpTableData) {
  479. UlRelease(lpTableData);
  480. }
  481. }
  482. LeaveCriticalSection(&lpROOT->lpIAB->cs);
  483. return(hResult);
  484. }
  485. /*************************************************************************
  486. *
  487. *
  488. - ROOT_GetHierarchyTable
  489. -
  490. * Returns the merge of all the root hierarchy tables
  491. *
  492. *
  493. *
  494. */
  495. STDMETHODIMP
  496. ROOT_GetHierarchyTable (LPROOT lpROOT,
  497. ULONG ulFlags,
  498. LPMAPITABLE * lppTable)
  499. {
  500. LPTSTR lpszMessage = NULL;
  501. ULONG ulLowLevelError = 0;
  502. HRESULT hr = hrSuccess;
  503. #ifdef PARAMETER_VALIDATION
  504. // Validate parameters
  505. // Check to see if it has a jump table
  506. if (IsBadReadPtr(lpROOT, sizeof(LPVOID))) {
  507. // No jump table found
  508. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  509. }
  510. // Check to see that it's ROOTs jump table
  511. if (lpROOT->lpVtbl != &vtblROOT) {
  512. // Not my jump table
  513. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  514. }
  515. // See if I can set the return variable
  516. if (IsBadWritePtr (lppTable, sizeof (LPMAPITABLE))) {
  517. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  518. }
  519. // Check flags:
  520. // The only valid flags are CONVENIENT_DEPTH and MAPI_DEFERRED_ERRORS
  521. if (ulFlags & ~(CONVENIENT_DEPTH|MAPI_DEFERRED_ERRORS|MAPI_UNICODE)) {
  522. DebugTraceArg(ROOT_GetHierarchyTable, TEXT("Unknown flags used"));
  523. // return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
  524. }
  525. #endif
  526. // BUGBUG: We use the code which is incorrectly in GetContentsTable...
  527. hr = ROOT_GetContentsTable(lpROOT, ulFlags & ~CONVENIENT_DEPTH, lppTable);
  528. DebugTraceResult(ROOT_GetHierarchyTable, hr);
  529. return(hr);
  530. }
  531. /*************************************************************************
  532. *
  533. *
  534. - ROOT_OpenEntry
  535. -
  536. * Just call ABP_OpenEntry
  537. *
  538. *
  539. *
  540. */
  541. STDMETHODIMP
  542. ROOT_OpenEntry(LPROOT lpROOT,
  543. ULONG cbEntryID,
  544. LPENTRYID lpEntryID,
  545. LPCIID lpInterface,
  546. ULONG ulFlags,
  547. ULONG * lpulObjType,
  548. LPUNKNOWN * lppUnk)
  549. {
  550. #ifdef PARAMETER_VALIDATION
  551. // Validate the object.
  552. if (BAD_STANDARD_OBJ(lpROOT, ROOT_, OpenEntry, lpVtbl)) {
  553. // jump table not large enough to support this method
  554. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  555. }
  556. // Check the entryid parameter. It needs to be big enough to hold an entryid.
  557. // Null entryids are valid
  558. /*
  559. if (lpEntryID) {
  560. if (cbEntryID < offsetof(ENTRYID, ab)
  561. || IsBadReadPtr((LPVOID) lpEntryID, (UINT)cbEntryID)) {
  562. DebugTraceArg(ROOT_OpenEntry, TEXT("lpEntryID fails address check"));
  563. return(ResultFromScode(MAPI_E_INVALID_ENTRYID));
  564. }
  565. //NFAssertSz(FValidEntryIDFlags(lpEntryID->abFlags),
  566. // TEXT("Undefined bits set in EntryID flags\n"));
  567. }
  568. */
  569. // Don't check the interface parameter unless the entry is something
  570. // MAPI itself handles. The provider should return an error if this
  571. // parameter is something that it doesn't understand.
  572. // At this point, we just make sure it's readable.
  573. if (lpInterface && IsBadReadPtr(lpInterface, sizeof(IID))) {
  574. DebugTraceArg(ROOT_OpenEntry, TEXT("lpInterface fails address check"));
  575. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  576. }
  577. if (ulFlags & ~(MAPI_MODIFY | MAPI_DEFERRED_ERRORS | MAPI_BEST_ACCESS)) {
  578. DebugTraceArg(ROOT_OpenEntry, TEXT("Unknown flags used"));
  579. // return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
  580. }
  581. if (IsBadWritePtr((LPVOID) lpulObjType, sizeof (ULONG))) {
  582. DebugTraceArg(ROOT_OpenEntry, TEXT("lpulObjType"));
  583. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  584. }
  585. if (IsBadWritePtr((LPVOID) lppUnk, sizeof (LPUNKNOWN))) {
  586. DebugTraceArg(ROOT_OpenEntry, TEXT("lppUnk"));
  587. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  588. }
  589. #endif // PARAMETER_VALIDATION
  590. // Should just call IAB::OpenEntry()...
  591. return(lpROOT->lpIAB->lpVtbl->OpenEntry(lpROOT->lpIAB,
  592. cbEntryID,
  593. lpEntryID,
  594. lpInterface,
  595. ulFlags,
  596. lpulObjType,
  597. lppUnk));
  598. }
  599. STDMETHODIMP
  600. ROOT_SetSearchCriteria(LPROOT lpROOT,
  601. LPSRestriction lpRestriction,
  602. LPENTRYLIST lpContainerList,
  603. ULONG ulSearchFlags)
  604. {
  605. #ifdef PARAMETER_VALIDATION
  606. // Validate the object.
  607. if (BAD_STANDARD_OBJ(lpROOT, ROOT_, SetSearchCriteria, lpVtbl)) {
  608. // jump table not large enough to support this method
  609. DebugTraceArg(ROOT_SetSearchCriteria, TEXT("Bad object/vtble"));
  610. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  611. }
  612. // ensure we can read the restriction
  613. if (lpRestriction && IsBadReadPtr(lpRestriction, sizeof(SRestriction))) {
  614. DebugTraceArg(ROOT_SetSearchCriteria, TEXT("Bad Restriction parameter"));
  615. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  616. }
  617. if (FBadEntryList(lpContainerList)) {
  618. DebugTraceArg(ROOT_SetSearchCriteria, TEXT("Bad ContainerList parameter"));
  619. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  620. }
  621. if (ulSearchFlags & ~(STOP_SEARCH | RESTART_SEARCH | RECURSIVE_SEARCH
  622. | SHALLOW_SEARCH | FOREGROUND_SEARCH | BACKGROUND_SEARCH)) {
  623. DebugTraceArg(ROOT_GetSearchCriteria, TEXT("Unknown flags used"));
  624. // return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
  625. }
  626. #endif // PARAMETER_VALIDATION
  627. return(ResultFromScode(MAPI_E_NO_SUPPORT));
  628. }
  629. STDMETHODIMP
  630. ROOT_GetSearchCriteria(LPROOT lpROOT,
  631. ULONG ulFlags,
  632. LPSRestriction FAR * lppRestriction,
  633. LPENTRYLIST FAR * lppContainerList,
  634. ULONG FAR * lpulSearchState)
  635. {
  636. #ifdef PARAMETER_VALIDATION
  637. // Validate the object.
  638. if (BAD_STANDARD_OBJ(lpROOT, ROOT_, GetSearchCriteria, lpVtbl)) {
  639. // jump table not large enough to support this method
  640. DebugTraceArg(ROOT_GetSearchCriteria, TEXT("Bad object/vtble"));
  641. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  642. }
  643. if (ulFlags & ~(MAPI_UNICODE)) {
  644. DebugTraceArg(ROOT_GetSearchCriteria, TEXT("Unknown Flags"));
  645. // return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
  646. }
  647. // ensure we can write the restriction
  648. if (lppRestriction && IsBadWritePtr(lppRestriction, sizeof(LPSRestriction))) {
  649. DebugTraceArg(ROOT_GetSearchCriteria, TEXT("Bad Restriction write parameter"));
  650. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  651. }
  652. // ensure we can read the container list
  653. if (lppContainerList && IsBadWritePtr(lppContainerList, sizeof(LPENTRYLIST))) {
  654. DebugTraceArg(ROOT_GetSearchCriteria, TEXT("Bad ContainerList parameter"));
  655. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  656. }
  657. if (lpulSearchState && IsBadWritePtr(lpulSearchState, sizeof(ULONG))) {
  658. DebugTraceArg(ROOT_GetSearchCriteria, TEXT("lpulSearchState fails address check"));
  659. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  660. }
  661. #endif // PARAMETER_VALIDATION
  662. return(ResultFromScode(MAPI_E_NO_SUPPORT));
  663. }
  664. //----------------------------------------------------------------------------
  665. // Synopsis: ROOT_CreateEntry()
  666. //
  667. // Description:
  668. // If called from a OneOff container a OneOff MAIL_USER object
  669. // is created via the use of any arbitrary template.
  670. // CreateEntry is not supported from a ROOT container.
  671. //
  672. // Parameters:
  673. // Returns:
  674. // Effects:
  675. //
  676. // Notes: OneOff EntryIDs contain MAPI_UNICODE flag information in
  677. // the ulDataType member.
  678. //
  679. // Revision:
  680. //----------------------------------------------------------------------------
  681. STDMETHODIMP
  682. ROOT_CreateEntry(LPROOT lpROOT,
  683. ULONG cbEntryID,
  684. LPENTRYID lpEntryID,
  685. ULONG ulCreateFlags,
  686. LPMAPIPROP FAR * lppMAPIPropEntry)
  687. {
  688. BYTE bType;
  689. #ifdef PARAMETER_VALIDATION
  690. // Validate the object.
  691. if (BAD_STANDARD_OBJ(lpROOT, ROOT_, CreateEntry, lpVtbl)) {
  692. // jump table not large enough to support this method
  693. DebugTraceArg(ROOT_CreateEntry, TEXT("Bad object/Vtbl"));
  694. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  695. }
  696. // Check the entryid parameter. It needs to be big enough to hold an entryid.
  697. // Null entryid are bad
  698. /*
  699. if (lpEntryID) {
  700. if (cbEntryID < offsetof(ENTRYID, ab)
  701. || IsBadReadPtr((LPVOID) lpEntryID, (UINT)cbEntryID)) {
  702. DebugTraceArg(ROOT_CreateEntry, TEXT("lpEntryID fails address check"));
  703. return(ResultFromScode(MAPI_E_INVALID_ENTRYID));
  704. }
  705. //NFAssertSz(FValidEntryIDFlags(lpEntryID->abFlags),
  706. // "Undefined bits set in EntryID flags\n");
  707. } else {
  708. DebugTraceArg(ROOT_CreateEntry, TEXT("lpEntryID NULL"));
  709. return(ResultFromScode(MAPI_E_INVALID_ENTRYID));
  710. }
  711. */
  712. if (ulCreateFlags & ~(CREATE_CHECK_DUP_STRICT | CREATE_CHECK_DUP_LOOSE
  713. | CREATE_REPLACE | CREATE_MERGE)) {
  714. DebugTraceArg(ROOT_CreateEntry, TEXT("Unknown flags used"));
  715. // return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
  716. }
  717. if (IsBadWritePtr(lppMAPIPropEntry, sizeof(LPMAPIPROP))) {
  718. DebugTraceArg(ROOT_CreateEntry, TEXT("Bad MAPI Property write parameter"));
  719. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  720. }
  721. #endif // PARAMETER_VALIDATION
  722. #ifdef NEVER
  723. if (lpROOT->ulType == AB_ROOT)
  724. return ResultFromScode(MAPI_E_NO_SUPPORT);
  725. #endif // NEVER
  726. // What kind of entry are we creating?
  727. // Default is MailUser
  728. bType = IsWABEntryID(cbEntryID, lpEntryID, NULL, NULL, NULL, NULL, NULL);
  729. if (bType == WAB_DEF_MAILUSER || cbEntryID == 0) {
  730. //
  731. // Create a new (in memory) entry and return it's mapiprop
  732. //
  733. return(HrNewMAILUSER(lpROOT->lpIAB, lpROOT->pmbinOlk, MAPI_MAILUSER, ulCreateFlags, lppMAPIPropEntry));
  734. } else if (bType == WAB_DEF_DL) {
  735. //
  736. // Create a new (in memory) distribution list and return it's mapiprop?
  737. return(HrNewMAILUSER(lpROOT->lpIAB, lpROOT->pmbinOlk, MAPI_DISTLIST, ulCreateFlags, lppMAPIPropEntry));
  738. } else {
  739. DebugTrace(TEXT("ROOT_CreateEntry got unknown template entryID\n"));
  740. return(ResultFromScode(MAPI_E_INVALID_ENTRYID));
  741. }
  742. }
  743. /*
  744. - CopyEntries
  745. -
  746. * Copies a list of entries into this container... Since you can't
  747. * do that with this container we just return not supported.
  748. */
  749. STDMETHODIMP
  750. ROOT_CopyEntries(LPROOT lpROOT,
  751. LPENTRYLIST lpEntries,
  752. ULONG_PTR ulUIParam,
  753. LPMAPIPROGRESS lpProgress,
  754. ULONG ulFlags)
  755. {
  756. #ifdef PARAMETER_VALIDATION
  757. if (BAD_STANDARD_OBJ(lpROOT, ROOT_, CopyEntries, lpVtbl)) {
  758. // jump table not large enough to support this method
  759. DebugTraceArg(ROOT_CopyEntries, TEXT("Bad object/vtbl"));
  760. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  761. }
  762. // ensure we can read the container list
  763. if (FBadEntryList(lpEntries)) {
  764. DebugTraceArg(ROOT_CopyEntries, TEXT("Bad Entrylist parameter"));
  765. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  766. }
  767. if (ulUIParam && !IsWindow((HWND)ulUIParam)) {
  768. DebugTraceArg(ROOT_CopyEntries, TEXT("Invalid window handle"));
  769. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  770. }
  771. if (lpProgress && IsBadReadPtr(lpProgress, sizeof(IMAPIProgress))) {
  772. DebugTraceArg(ROOT_CopyEntries, TEXT("Bad MAPI Progress parameter"));
  773. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  774. }
  775. if (ulFlags & ~(AB_NO_DIALOG | CREATE_CHECK_DUP_LOOSE)) {
  776. DebugTraceArg(ROOT_CreateEntry, TEXT("Unknown flags used"));
  777. // return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
  778. }
  779. #endif // PARAMETER_VALIDATION
  780. return(ResultFromScode(MAPI_E_NO_SUPPORT));
  781. }
  782. /*
  783. - DeleteEntries
  784. -
  785. *
  786. * Deletes entries within this container... Funny that. There really
  787. * isn't a true container here. Do we just say "Sure, that worked just
  788. * fine" or "Sorry this operation not supported." I don't think it really
  789. * matters... For now it's the former.
  790. */
  791. STDMETHODIMP
  792. ROOT_DeleteEntries (LPROOT lpROOT,
  793. LPENTRYLIST lpEntries,
  794. ULONG ulFlags)
  795. {
  796. ULONG i;
  797. HRESULT hResult = hrSuccess;
  798. ULONG cDeleted = 0;
  799. ULONG cToDelete;
  800. SCODE sc;
  801. #ifndef DONT_ADDREF_PROPSTORE
  802. if ((FAILED(sc = OpenAddRefPropertyStore(NULL, lpROOT->lpIAB->lpPropertyStore)))) {
  803. hResult = ResultFromScode(sc);
  804. goto exitNotAddRefed;
  805. }
  806. #endif
  807. #ifdef PARAMETER_VALIDATION
  808. if (BAD_STANDARD_OBJ(lpROOT, ROOT_, DeleteEntries, lpVtbl)) {
  809. // jump table not large enough to support this method
  810. DebugTraceArg(ROOT_DeleteEntries, TEXT("Bad object/vtbl"));
  811. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  812. }
  813. // ensure we can read the container list
  814. if (FBadEntryList(lpEntries)) {
  815. DebugTraceArg(ROOT_DeleteEntries, TEXT("Bad Entrylist parameter"));
  816. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  817. }
  818. if (ulFlags) {
  819. DebugTraceArg(ROOT_DeleteEntries, TEXT("Unknown flags used"));
  820. // return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
  821. }
  822. #endif // PARAMETER_VALIDATION
  823. // List of entryids is in lpEntries. This is a counted array of
  824. // entryid SBinary structs.
  825. cToDelete = lpEntries->cValues;
  826. // Delete each entry
  827. for (i = 0; i < cToDelete; i++)
  828. {
  829. if(0 != IsWABEntryID(lpEntries->lpbin[i].cb,
  830. (LPENTRYID) IntToPtr(lpEntries->lpbin[i].cb),
  831. NULL, NULL, NULL, NULL, NULL))
  832. {
  833. DebugTrace(TEXT("CONTAINER_DeleteEntries got bad entryid of size %u\n"), lpEntries->lpbin[i].cb);
  834. continue;
  835. }
  836. hResult = DeleteCertStuff((LPADRBOOK)lpROOT->lpIAB, (LPENTRYID)lpEntries->lpbin[i].lpb, lpEntries->lpbin[i].cb);
  837. hResult = HrSaveHotmailSyncInfoOnDeletion((LPADRBOOK) lpROOT->lpIAB, &(lpEntries->lpbin[i]));
  838. if (HR_FAILED(hResult = DeleteRecord(lpROOT->lpIAB->lpPropertyStore->hPropertyStore,
  839. &(lpEntries->lpbin[i])))) {
  840. DebugTraceResult( TEXT("DeleteEntries: DeleteRecord"), hResult);
  841. continue;
  842. }
  843. cDeleted++;
  844. }
  845. if (! hResult) {
  846. if (cDeleted != cToDelete) {
  847. hResult = ResultFromScode(MAPI_W_PARTIAL_COMPLETION);
  848. DebugTrace(TEXT("DeleteEntries deleted %u of requested %u\n"), cDeleted, cToDelete);
  849. }
  850. }
  851. #ifndef DONT_ADDREF_PROPSTORE
  852. ReleasePropertyStore(lpROOT->lpIAB->lpPropertyStore);
  853. exitNotAddRefed:
  854. #endif
  855. return(hResult);
  856. }
  857. STDMETHODIMP
  858. ROOT_ResolveNames( LPROOT lpRoot,
  859. LPSPropTagArray lptagaColSet,
  860. ULONG ulFlags,
  861. LPADRLIST lpAdrList,
  862. LPFlagList lpFlagList)
  863. {
  864. return(ResultFromScode(MAPI_E_NO_SUPPORT));
  865. }