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.

6831 lines
223 KiB

  1. /*********************************************************************************
  2. IAdrBook.c
  3. - This file contains the code for implementing the IAdrBook object.
  4. Copyright 1992 - 1996 Microsoft Corporation. All Rights Reserved.
  5. Revision History:
  6. 03/01/96 Bruce Kelley Copied MAPI code to WAB
  7. ***********************************************************************************/
  8. #include <_apipch.h>
  9. #ifdef WIN16
  10. #undef GetLastError
  11. #endif
  12. extern MAPIUID muidOOP;
  13. extern MAPIUID muidProviderSection;
  14. extern SPropTagArray ptagaABSearchPath;
  15. extern void UninitExtInfo();
  16. extern void UninitContextExtInfo();
  17. extern void UIOLEUninit();
  18. extern void SetOutlookRefreshCountData(DWORD dwOlkRefreshCount,DWORD dwOlkFolderRefreshCount);
  19. extern void GetOutlookRefreshCountData(LPDWORD lpdwOlkRefreshCount,LPDWORD lpdwOlkFolderRefreshCount);
  20. extern void LocalFreeSBinary(LPSBinary lpsb);
  21. // USed for cleaning up the IAB object
  22. void IAB_Neuter (LPIAB lpIAB);
  23. typedef enum {
  24. ENTERED_EMAIL_ADDRESS,
  25. RECEIVED_EMAIL_ADDRESS,
  26. AMBIGUOUS_EMAIL_ADDRESS
  27. } RESOLVE_TYPE;
  28. HRESULT HrResolveOneOffs(LPIAB lpIAB, LPADRLIST lpAdrList, LPFlagList lpFlagList, ULONG ulFlags,
  29. RESOLVE_TYPE ResolveType);
  30. //
  31. // IAdrBook jump table is defined here...
  32. //
  33. IAB_Vtbl vtblIAB = {
  34. VTABLE_FILL
  35. IAB_QueryInterface,
  36. IAB_AddRef,
  37. IAB_Release,
  38. IAB_GetLastError,
  39. (IAB_SaveChanges_METHOD *) WRAP_SaveChanges,
  40. (IAB_GetProps_METHOD *) WRAP_GetProps,
  41. (IAB_GetPropList_METHOD *) WRAP_GetPropList,
  42. (IAB_OpenProperty_METHOD *) WRAP_OpenProperty,
  43. (IAB_SetProps_METHOD *) WRAP_SetProps,
  44. (IAB_DeleteProps_METHOD *) WRAP_DeleteProps,
  45. (IAB_CopyTo_METHOD *) WRAP_CopyTo,
  46. (IAB_CopyProps_METHOD *) WRAP_CopyProps,
  47. (IAB_GetNamesFromIDs_METHOD *) WRAP_GetNamesFromIDs,
  48. IAB_GetIDsFromNames,
  49. IAB_OpenEntry,
  50. IAB_CompareEntryIDs,
  51. IAB_Advise,
  52. IAB_Unadvise,
  53. IAB_CreateOneOff,
  54. IAB_NewEntry,
  55. IAB_ResolveName,
  56. IAB_Address,
  57. IAB_Details,
  58. IAB_RecipOptions,
  59. IAB_QueryDefaultRecipOpt,
  60. IAB_GetPAB,
  61. IAB_SetPAB,
  62. IAB_GetDefaultDir,
  63. IAB_SetDefaultDir,
  64. IAB_GetSearchPath,
  65. IAB_SetSearchPath,
  66. IAB_PrepareRecips
  67. };
  68. //
  69. // Interfaces supported by this object
  70. //
  71. #define IAB_cInterfaces 2
  72. LPIID IAB_LPIID[IAB_cInterfaces] = {
  73. (LPIID) &IID_IAddrBook,
  74. (LPIID) &IID_IMAPIProp
  75. };
  76. #define WM_DOWABNOTIFY WM_USER+102
  77. //***************************************************************************************
  78. //
  79. // Private functions
  80. //
  81. //***************************************************************************************
  82. //
  83. // VerifyWABOpenEx session - Outlook has a bad bug where the first thread which calls WABOpenEx
  84. // passes lpIAB to a second thread .. since the second thread didnt call WABOpenEx, it thinks
  85. // this is a regular WAB session and tries to access the WAB Store and crashes - here we set the
  86. // pt_bIsWABOpenExSession based on the flag set on lpIAB
  87. //
  88. // Right now this is only set for the original IAB_methods - wrapped methods from WRAP_methods
  89. // dont call this function - but hopefully this is enough for now ..
  90. //
  91. void VerifyWABOpenExSession(LPIAB lpIAB)
  92. {
  93. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  94. pt_bIsWABOpenExSession = lpIAB->lpPropertyStore->bIsWABOpenExSession;
  95. }
  96. /*
  97. - HrLoadNamedProps
  98. -
  99. * Helper function for loading a bunch of named properties at the same time
  100. *
  101. * uMax - # of props
  102. * nStartIndex - starting index (NOTE this assumes that the indexes for the
  103. * properties are contiguous values since we'll gor through a
  104. * loop from nStartIndex to uMax
  105. * lpGUID - GUID identifying the named props
  106. * lppta - returned prop array
  107. -
  108. */
  109. HRESULT HrLoadNamedProps(LPIAB lpIAB, ULONG uMax, int nStartIndex,
  110. LPGUID lpGUID, LPSPropTagArray * lppta)
  111. {
  112. HRESULT hr = S_OK;
  113. LPMAPINAMEID * lppConfPropNames;
  114. SCODE sc;
  115. ULONG i = 0;
  116. sc = MAPIAllocateBuffer(sizeof(LPMAPINAMEID) * uMax, (LPVOID *) &lppConfPropNames);
  117. if(sc)
  118. {
  119. hr = ResultFromScode(sc);
  120. goto err;
  121. }
  122. for(i=0;i<uMax;i++)
  123. {
  124. sc = MAPIAllocateMore(sizeof(MAPINAMEID), lppConfPropNames, &(lppConfPropNames[i]));
  125. if(sc)
  126. {
  127. hr = ResultFromScode(sc);
  128. goto err;
  129. }
  130. lppConfPropNames[i]->lpguid = lpGUID;
  131. lppConfPropNames[i]->ulKind = MNID_ID;
  132. lppConfPropNames[i]->Kind.lID = nStartIndex + i;
  133. }
  134. hr = ((LPADRBOOK)lpIAB)->lpVtbl->GetIDsFromNames((LPADRBOOK)lpIAB, uMax, lppConfPropNames,
  135. MAPI_CREATE, lppta);
  136. err:
  137. if(lppConfPropNames)
  138. MAPIFreeBuffer(lppConfPropNames);
  139. return hr;
  140. }
  141. /*
  142. - ReadWABCustomColumnProps
  143. - reads the customized Listview properties from the registry
  144. - Right now there are only 2 customizable props
  145. - Customization settings are saved per identity and so need to be read
  146. - from the identities personal key
  147. *
  148. */
  149. void ReadWABCustomColumnProps(LPIAB lpIAB)
  150. {
  151. HKEY hKey = NULL;
  152. HKEY hKeyRoot = (lpIAB && lpIAB->hKeyCurrentUser) ?
  153. lpIAB->hKeyCurrentUser : HKEY_CURRENT_USER;
  154. PR_WAB_CUSTOMPROP1 = PR_WAB_CUSTOMPROP2 = 0;
  155. szCustomProp1[0] = TEXT('\0');
  156. szCustomProp2[0] = TEXT('\0');
  157. if(ERROR_SUCCESS == RegOpenKeyEx(hKeyRoot, lpNewWABRegKey, 0, KEY_READ, &hKey))
  158. {
  159. int i = 0;
  160. for(i=0;i<2;i++)
  161. {
  162. LPTSTR szPropTag = (i==0?szPropTag1:szPropTag2);
  163. LPTSTR szPropLabel = (i==0?szCustomProp1:szCustomProp2);
  164. LPULONG lpulProp = (i==0? (&PR_WAB_CUSTOMPROP1):(&PR_WAB_CUSTOMPROP2));
  165. DWORD dwSize = sizeof(DWORD);
  166. DWORD dwType = 0;
  167. DWORD dwValue = 0;
  168. TCHAR szTemp[MAX_PATH];
  169. *szTemp = '\0';
  170. if(ERROR_SUCCESS == RegQueryValueEx(hKey, szPropTag, NULL, &dwType, (LPBYTE) &dwValue, &dwSize))
  171. {
  172. if(dwValue && PROP_TYPE(dwValue) == PT_TSTRING)
  173. {
  174. #ifdef COLSEL_MENU
  175. if( ColSel_PropTagToString(dwValue, szTemp, CharSizeOf( szTemp ) ) )
  176. {
  177. StrCpyN(szPropLabel, szTemp, ARRAYSIZE(szCustomProp1));
  178. lstrcpy( szPropLabel, szTemp );
  179. *lpulProp = dwValue;
  180. }
  181. #endif
  182. }
  183. }
  184. }
  185. }
  186. if(hKey)
  187. RegCloseKey(hKey);
  188. }
  189. /*
  190. - HrLoadPrivateWABProps
  191. -
  192. - WAB uses a bunch of named properties internally .. load them all
  193. - upfront - these will be globals accessible from elsewhere all the time
  194. *
  195. *
  196. */
  197. HRESULT HrLoadPrivateWABProps(LPIAB lpIAB)
  198. {
  199. ULONG i;
  200. HRESULT hr = E_FAIL;
  201. LPSPropTagArray lpta = NULL;
  202. SCODE sc ;
  203. // Load the set of conferencing named props
  204. //
  205. if(HR_FAILED(hr = HrLoadNamedProps( lpIAB, prWABConfMax, OLK_NAMEDPROPS_START,
  206. (LPGUID) &PS_Conferencing, &lpta)))
  207. goto err;
  208. if(lpta)
  209. {
  210. // Set the property types on the returned props
  211. PR_WAB_CONF_SERVERS = CHANGE_PROP_TYPE(lpta->aulPropTag[prWABConfServers], PT_MV_TSTRING);
  212. PR_WAB_CONF_DEFAULT_INDEX = CHANGE_PROP_TYPE(lpta->aulPropTag[prWABConfDefaultIndex], PT_LONG);
  213. PR_WAB_CONF_BACKUP_INDEX = CHANGE_PROP_TYPE(lpta->aulPropTag[prWABConfBackupIndex], PT_LONG);
  214. PR_WAB_CONF_EMAIL_INDEX = CHANGE_PROP_TYPE(lpta->aulPropTag[prWABConfEmailIndex], PT_LONG);
  215. }
  216. ptaUIDetlsPropsConferencing.cValues = prWABConfMax;
  217. ptaUIDetlsPropsConferencing.aulPropTag[prWABConfServers] = PR_WAB_CONF_SERVERS;
  218. ptaUIDetlsPropsConferencing.aulPropTag[prWABConfDefaultIndex] = PR_WAB_CONF_DEFAULT_INDEX;
  219. ptaUIDetlsPropsConferencing.aulPropTag[prWABConfBackupIndex] = PR_WAB_CONF_BACKUP_INDEX;
  220. ptaUIDetlsPropsConferencing.aulPropTag[prWABConfEmailIndex] = PR_WAB_CONF_EMAIL_INDEX;
  221. if(lpta)
  222. MAPIFreeBuffer(lpta);
  223. // Load the set of WAB's internal named props
  224. //
  225. if(HR_FAILED(hr = HrLoadNamedProps( lpIAB, prWABUserMax, WAB_NAMEDPROPS_START,
  226. (LPGUID) &MPSWab_GUID_V4, &lpta)))
  227. goto err;
  228. if(lpta)
  229. {
  230. // Set the property types on the returned props
  231. PR_WAB_USER_PROFILEID = CHANGE_PROP_TYPE(lpta->aulPropTag[prWABUserProfileID], PT_TSTRING);
  232. PR_WAB_USER_SUBFOLDERS = CHANGE_PROP_TYPE(lpta->aulPropTag[prWABUserSubfolders],PT_MV_BINARY);
  233. PR_WAB_HOTMAIL_CONTACTIDS = CHANGE_PROP_TYPE(lpta->aulPropTag[prWABHotmailContactIDs],PT_MV_TSTRING);
  234. PR_WAB_HOTMAIL_MODTIMES = CHANGE_PROP_TYPE(lpta->aulPropTag[prWABHotmailModTimes],PT_MV_TSTRING);
  235. PR_WAB_HOTMAIL_SERVERIDS = CHANGE_PROP_TYPE(lpta->aulPropTag[prWABHotmailServerIDs],PT_MV_TSTRING);
  236. PR_WAB_DL_ONEOFFS = CHANGE_PROP_TYPE(lpta->aulPropTag[prWABDLOneOffs],PT_MV_BINARY);
  237. PR_WAB_IPPHONE = CHANGE_PROP_TYPE(lpta->aulPropTag[prWABIPPhone],PT_TSTRING);
  238. PR_WAB_FOLDER_PARENT = CHANGE_PROP_TYPE(lpta->aulPropTag[prWABFolderParent],PT_MV_BINARY);
  239. PR_WAB_SHAREDFOLDER = CHANGE_PROP_TYPE(lpta->aulPropTag[prWABSharedFolder],PT_LONG);
  240. PR_WAB_FOLDEROWNER = CHANGE_PROP_TYPE(lpta->aulPropTag[prWABFolderOwner],PT_TSTRING);
  241. }
  242. if(lpta)
  243. MAPIFreeBuffer(lpta);
  244. // Load the set of Yomi named props
  245. //
  246. if(HR_FAILED(hr = HrLoadNamedProps( lpIAB, prWABYomiMax, OLK_YOMIPROPS_START,
  247. (LPGUID) &PS_YomiProps, &lpta)))
  248. goto err;
  249. if(lpta)
  250. {
  251. // Set the property types on the returned props
  252. PR_WAB_YOMI_FIRSTNAME = CHANGE_PROP_TYPE(lpta->aulPropTag[prWABYomiFirst], PT_TSTRING);
  253. PR_WAB_YOMI_LASTNAME = CHANGE_PROP_TYPE(lpta->aulPropTag[prWABYomiLast], PT_TSTRING);
  254. PR_WAB_YOMI_COMPANYNAME = CHANGE_PROP_TYPE(lpta->aulPropTag[prWABYomiCompany], PT_TSTRING);
  255. }
  256. if(lpta)
  257. MAPIFreeBuffer(lpta);
  258. // Load the default mailing address property
  259. //
  260. if(HR_FAILED(hr = HrLoadNamedProps( lpIAB, prWABPostalMax, OLK_POSTALID_START,
  261. (LPGUID) &PS_PostalAddressID, &lpta)))
  262. goto err;
  263. if(lpta)
  264. {
  265. // Set the property types on the returned props
  266. PR_WAB_POSTALID = CHANGE_PROP_TYPE(lpta->aulPropTag[prWABPostalID], PT_LONG);
  267. }
  268. err:
  269. if(lpta)
  270. MAPIFreeBuffer(lpta);
  271. return hr;
  272. }
  273. // The WAB's notification engine is currently a hidden window
  274. // that checks for file changes every NOTIFICATIONTIME milliseconds
  275. // If changes are detected, it fires off a generic notification
  276. //
  277. // <TBD> At some point of time this should be made more granular so apps
  278. // get a message telling them which entry changed rather than a generic
  279. // notification
  280. //
  281. ///////////////////////////////////////////////////////////////////////////////
  282. // Way to globally turn off all notifications in this process. Needed because
  283. // of global Outlook MAPI allocator weirdness. See the HrSendMail function in
  284. // uimisc.c
  285. //
  286. // Includes one static variable and two helper functions
  287. // [PaulHi]
  288. ///////////////////////////////////////////////////////////////////////////////
  289. static BOOL s_bDisableAllNotifications = FALSE;
  290. void vTurnOffAllNotifications()
  291. {
  292. s_bDisableAllNotifications = TRUE;
  293. }
  294. void vTurnOnAllNotifications()
  295. {
  296. s_bDisableAllNotifications = FALSE;
  297. }
  298. #define NOTIFICATIONTIME 2000 //millisecs
  299. #define NOTIFTIMER 777
  300. /*
  301. - IABNotifWndProc
  302. -
  303. * Window procedure for the hidden window on the iadrbook object
  304. * that has a notification timer and processes timer messages only
  305. * Current timer duration is 3 seconds - so every 3 seconds we check
  306. * for changes and fire notifications accordingly
  307. *
  308. *
  309. */
  310. LRESULT CALLBACK IABNotifWndProc( HWND hWnd,
  311. UINT uMsg,
  312. WPARAM wParam,
  313. LPARAM lParam)
  314. {
  315. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  316. LPIAB lpIAB = NULL;
  317. switch(uMsg)
  318. {
  319. case WM_CREATE:
  320. {
  321. LPCREATESTRUCT lpCS = (LPCREATESTRUCT) lParam;
  322. lpIAB = (LPIAB) lpCS->lpCreateParams;
  323. SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) lpIAB);
  324. // [PaulHi] 4/27/99 Raid 76520. Don't use the notification
  325. // timer for normal WAB store sessions. We still need this
  326. // for Outlook store sessions, however.
  327. if (pt_bIsWABOpenExSession)
  328. {
  329. lpIAB->ulNotifyTimer = SetTimer(hWnd, NOTIFTIMER, //random number
  330. NOTIFICATIONTIME,
  331. 0);
  332. }
  333. }
  334. break;
  335. case WM_DOWABNOTIFY:
  336. lpIAB = (LPIAB)GetWindowLongPtr(hWnd, GWLP_USERDATA);
  337. if ( lpIAB && !IsBadReadPtr(lpIAB, sizeof(LPVOID)) && !s_bDisableAllNotifications )
  338. {
  339. DebugTrace(TEXT("*** *** *** Firing WAB Change Notification *** *** ***\n"));
  340. HrWABNotify(lpIAB);
  341. }
  342. break;
  343. case WM_TIMER:
  344. if(wParam == NOTIFTIMER) // is this the WAB timer ID
  345. {
  346. lpIAB = (LPIAB)GetWindowLongPtr(hWnd, GWLP_USERDATA);
  347. if (lpIAB &&
  348. !IsBadReadPtr(lpIAB, sizeof(LPVOID)) &&
  349. lpIAB->lpPropertyStore &&
  350. lpIAB->ulNotifyTimer &&
  351. CheckChangedWAB(lpIAB->lpPropertyStore, lpIAB->hMutexOlk,
  352. &lpIAB->dwOlkRefreshCount, &lpIAB->dwOlkFolderRefreshCount,
  353. &(lpIAB->ftLast)))
  354. {
  355. DebugTrace(TEXT("*** *** *** Firing WAB Change Notification *** *** ***\n"));
  356. HrWABNotify(lpIAB);
  357. }
  358. }
  359. break;
  360. case WM_DESTROY:
  361. lpIAB = (LPIAB)GetWindowLongPtr(hWnd, GWLP_USERDATA);
  362. if(lpIAB && lpIAB->ulNotifyTimer)
  363. KillTimer(hWnd, lpIAB->ulNotifyTimer);
  364. SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR) NULL);
  365. break;
  366. default:
  367. return DefWindowProc(hWnd,uMsg,wParam,lParam);
  368. }
  369. return 0;
  370. }
  371. static TCHAR szWABNotifClassName[] = TEXT("WAB Notification Engine");
  372. static TCHAR szWABNotifWinName[] = TEXT("WAB Notification Window");
  373. /*
  374. - CreateIABNotificationTimer
  375. -
  376. * Creates a hidden window on the IAB object. This window has a timer
  377. * which is used to check for changes and fire notifications accordingly
  378. *
  379. *
  380. */
  381. void CreateIABNotificationTimer(LPIAB lpIAB)
  382. {
  383. HINSTANCE hinst = hinstMapiXWAB;
  384. WNDCLASS wc;
  385. HWND hwnd = NULL;
  386. lpIAB->hWndNotify = FALSE;
  387. lpIAB->ulNotifyTimer = 0;
  388. // Register the window class. Ignore any failures; handle those
  389. // when the window is created.
  390. if (!GetClassInfo(hinst, szWABNotifClassName, &wc))
  391. {
  392. ZeroMemory(&wc, sizeof(WNDCLASS));
  393. wc.style = CS_GLOBALCLASS;
  394. wc.hInstance = hinst;
  395. wc.lpfnWndProc = IABNotifWndProc;
  396. wc.lpszClassName = szWABNotifClassName;
  397. (void)RegisterClass(&wc);
  398. }
  399. // Create the window.
  400. hwnd = CreateWindow( szWABNotifClassName,
  401. szWABNotifWinName,
  402. WS_POPUP, // MAPI bug 6111: pass on Win95 hotkey
  403. 0, 0, 0, 0,
  404. NULL, NULL,
  405. hinst,
  406. (LPVOID)lpIAB);
  407. if (!hwnd)
  408. {
  409. DebugTrace(TEXT("HrNewIAB: failure creating notification window (0x%lx)\n"), GetLastError());
  410. return;
  411. }
  412. lpIAB->hWndNotify = hwnd;
  413. return;
  414. }
  415. ///////////////////////////////////////////////////////////////////////////////
  416. // IABNotifyThreadProc
  417. //
  418. // Worker thread that waits for a WAB file mod notification from the system
  419. // using FindFirstChangeNotification/FindNextChangeNotification functions.
  420. // When the WAB file store has been modified, this thread will call the WAB
  421. // client notification function.
  422. ///////////////////////////////////////////////////////////////////////////////
  423. DWORD WINAPI IABNotifyThreadProc(LPVOID lpParam)
  424. {
  425. LPIAB lpIAB = (LPIAB)lpParam;
  426. HANDLE hFCN;
  427. HANDLE ahWaitHandles[2];
  428. DWORD dwWaitRtn;
  429. Assert(lpIAB);
  430. // Set up the FindFirstChangeNotification handle
  431. hFCN = FindFirstChangeNotification(
  432. lpIAB->lpwszWABFilePath, // Directory path to watch
  433. FALSE, // bWatchSubtree
  434. FILE_NOTIFY_CHANGE_LAST_WRITE); // Condition(s) to watch
  435. if (INVALID_HANDLE_VALUE == hFCN || NULL == hFCN)
  436. {
  437. Assert(0);
  438. lpIAB->hThreadNotify = INVALID_HANDLE_VALUE;
  439. return 0;
  440. }
  441. ahWaitHandles[0] = hFCN;
  442. ahWaitHandles[1] = lpIAB->hEventKillNotifyThread;
  443. // Wait for file change
  444. while (1)
  445. {
  446. // Wait on file change nofication, or terminate thread event
  447. dwWaitRtn = WaitForMultipleObjects(2, ahWaitHandles, FALSE, INFINITE);
  448. switch (dwWaitRtn)
  449. {
  450. case WAIT_OBJECT_0:
  451. // Reset the file change
  452. if (!FindNextChangeNotification(hFCN))
  453. {
  454. Assert(0);
  455. }
  456. // Distribute store change notifications. Do this on the main
  457. // IAB thread.
  458. if (lpIAB->hWndNotify)
  459. SendMessage(lpIAB->hWndNotify, WM_DOWABNOTIFY, 0, 0);
  460. break;
  461. case WAIT_FAILED:
  462. // If the wait failed then terminate the thread.
  463. Assert(0);
  464. case WAIT_OBJECT_0+1:
  465. // Close the file change notification handle and
  466. // terminate thread.
  467. FindCloseChangeNotification(hFCN);
  468. return 0;
  469. } // end switch
  470. } // end while
  471. }
  472. ///////////////////////////////////////////////////////////////////////////////
  473. // CreateIABNotificationThread
  474. //
  475. // Creates a worker thread that waits for a WAB store file modification
  476. ///////////////////////////////////////////////////////////////////////////////
  477. void CreateIABNotificationThread(LPIAB lpIAB)
  478. {
  479. DWORD dwThreadID = 0;
  480. LPWSTR lpwszTemp;
  481. // Put together the WAB store file directory path.
  482. LPMPSWab_FILE_INFO lpMPSWabFileInfo = (LPMPSWab_FILE_INFO)(lpIAB->lpPropertyStore->hPropertyStore);
  483. int nLen = lstrlen(lpMPSWabFileInfo->lpszMPSWabFileName);
  484. lpIAB->lpwszWABFilePath = LocalAlloc( LMEM_ZEROINIT, (sizeof(WCHAR) * (nLen+1)) );
  485. if (!lpIAB->lpwszWABFilePath)
  486. {
  487. Assert(0);
  488. return;
  489. }
  490. StrCpyN(lpIAB->lpwszWABFilePath, lpMPSWabFileInfo->lpszMPSWabFileName, nLen+1);
  491. // Remove file name at the end. This will take care of:
  492. // "c:\path\filename", "c:filename", "\\path\filename"
  493. lpwszTemp = lpIAB->lpwszWABFilePath + nLen;
  494. while ( (lpwszTemp != lpIAB->lpwszWABFilePath) &&
  495. (*lpwszTemp != '\\') && (*lpwszTemp != ':') )
  496. {
  497. --lpwszTemp;
  498. }
  499. if (*lpwszTemp == ':')
  500. ++lpwszTemp; // Keep ':' but not the '\\' ... Win95 won't accept the latter.
  501. (*lpwszTemp) = '\0';
  502. // Create the kill thread event
  503. lpIAB->hEventKillNotifyThread = CreateEvent(NULL, TRUE, FALSE, NULL);
  504. if (lpIAB->hEventKillNotifyThread == NULL)
  505. {
  506. Assert(0);
  507. return;
  508. }
  509. lpIAB->hThreadNotify = CreateThread(
  510. NULL, // no security attributes
  511. 0, // use default stack size
  512. IABNotifyThreadProc, // thread function
  513. (LPVOID)lpIAB, // argument to thread function
  514. 0, // use default creation flags
  515. &dwThreadID); // returns the thread identifier
  516. Assert(INVALID_HANDLE_VALUE != lpIAB->hThreadNotify);
  517. }
  518. /*
  519. - HrNewIAB
  520. -
  521. * Creates a new IAddrBook object (also known fondly as IAB object)
  522. *
  523. lpPropertyStore - Handle to the property store
  524. lpWABOBject - the WABOBject for this session (the 2 are closely linked)
  525. lppIAB - returned IAB object
  526. *
  527. */
  528. HRESULT HrNewIAB(LPPROPERTY_STORE lpPropertyStore,
  529. LPWABOBJECT lpWABObject, LPVOID *lppIAB)
  530. {
  531. LPIAB lpIAB = NULL;
  532. SCODE sc;
  533. HRESULT hr = hrSuccess;
  534. LPSTR lpszMessage = NULL;
  535. ULONG ulLowLevelError = 0;
  536. LPSTR lpszComponent = NULL;
  537. ULONG ulContext = 0;
  538. UINT ids = 0;
  539. ULONG ulMemFlag = 0;
  540. SPropValue spv[1];
  541. LPPROPDATA lpPropData = NULL;
  542. LPMAPIERROR lpMAPIError = NULL;
  543. LPSPropValue lpspvSearchPath = NULL;
  544. BOOL bAddRefedPropStore = FALSE;
  545. BOOL bAddRefedWABObject = FALSE;
  546. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  547. //
  548. // Allocate space for the IAB structure
  549. //
  550. if (FAILED(sc = MAPIAllocateBuffer(sizeof(IAB), (LPVOID *) &lpIAB))) {
  551. hr = ResultFromScode(sc);
  552. ulContext = CONT_SESS_OPENAB_1;
  553. // ids = IDS_NOT_ENOUGH_MEMORY;
  554. goto err;
  555. }
  556. MAPISetBufferName(lpIAB, TEXT("AB Object"));
  557. ZeroMemory(lpIAB, sizeof(IAB));
  558. lpIAB->lpVtbl = &vtblIAB;
  559. lpIAB->cIID = IAB_cInterfaces;
  560. lpIAB->rglpIID = IAB_LPIID;
  561. lpIAB->hThreadNotify = INVALID_HANDLE_VALUE;
  562. // The session's reference to the address book doesn't count. Only
  563. // client references (via SESSOBJ_OpenAddressBook) cause an increase
  564. // in the refcount.
  565. lpIAB->lcInit = 1; // Caller gets an instance
  566. lpIAB->hLastError = hrSuccess;
  567. lpIAB->idsLastError = 0;
  568. lpIAB->lpszComponent = NULL;
  569. lpIAB->ulContext = 0;
  570. lpIAB->ulLowLevelError = 0;
  571. lpIAB->ulErrorFlags = 0;
  572. lpIAB->lpMAPIError = NULL;
  573. lpIAB->lRowID = -1;
  574. if ((FAILED(sc = OpenAddRefPropertyStore(NULL, lpPropertyStore)))) {
  575. hr = ResultFromScode(sc);
  576. goto err;
  577. }
  578. bAddRefedPropStore = TRUE;
  579. lpIAB->lpPropertyStore = lpPropertyStore;
  580. lpIAB->lpEntryIDDD = NULL;
  581. lpIAB->cbEntryIDDD = 0;
  582. lpIAB->lpEntryIDPAB = NULL;
  583. lpIAB->cbEntryIDPAB = 0;
  584. lpIAB->lpspvSearchPathCache = NULL;
  585. lpIAB->lpTableData = NULL;
  586. lpIAB->lpOOData = NULL;
  587. lpIAB->ulcTableInfo = 0;
  588. lpIAB->pargTableInfo = NULL;
  589. lpIAB->ulcOOTableInfo = 0;
  590. lpIAB->pargOOTableInfo = NULL;
  591. lpIAB->padviselistIAB = NULL;
  592. lpIAB->pWABAdviseList = NULL;
  593. lpIAB->nPropExtDLLs = 0;
  594. lpIAB->lpPropExtDllList = NULL;
  595. lpIAB->lpWABObject = (LPIWOINT)lpWABObject;
  596. UlAddRef(lpWABObject);
  597. bAddRefedWABObject = TRUE;
  598. // If this session was opened with given Outlook allocator function pointers
  599. // then set the boolean
  600. lpIAB->bSetOLKAllocators = lpIAB->lpWABObject->bSetOLKAllocators;
  601. //
  602. // Create IPropData
  603. //
  604. sc = CreateIProp((LPIID)&IID_IMAPIPropData,
  605. (ALLOCATEBUFFER FAR *) MAPIAllocateBuffer,
  606. (ALLOCATEMORE FAR *) MAPIAllocateMore,
  607. MAPIFreeBuffer,
  608. NULL,
  609. &lpPropData);
  610. if (FAILED(sc)) {
  611. hr = ResultFromScode(sc);
  612. ulContext = CONT_SESS_OPENAB_2;
  613. // ids = IDS_NOT_ENOUGH_MEMORY;
  614. goto err;
  615. }
  616. MAPISetBufferName(lpPropData, TEXT("lpPropData in HrNewIAB"));
  617. // PR_OBJECT_TYPE
  618. spv[0].ulPropTag = PR_OBJECT_TYPE;
  619. spv[0].Value.l = MAPI_ADDRBOOK;
  620. //
  621. // Set the default properties
  622. //
  623. if (HR_FAILED(hr = lpPropData->lpVtbl->SetProps(lpPropData,
  624. 1,
  625. spv,
  626. NULL))) {
  627. lpPropData->lpVtbl->GetLastError(lpPropData,
  628. hr,
  629. 0,
  630. &lpMAPIError);
  631. ids = 0;
  632. ulMemFlag = 1;
  633. goto err;
  634. }
  635. // object itself can't be modified
  636. lpPropData->lpVtbl->HrSetObjAccess(lpPropData, IPROP_READONLY);
  637. lpIAB->lpPropData = lpPropData;
  638. lpIAB->fLoadedLDAP = FALSE;
  639. //if (ResolveLDAPServers()) {
  640. // // load the LDAP client dll
  641. // lpIAB->fLoadedLDAP = InitLDAPClientLib();
  642. //}
  643. // Create a notification timer for this IAddrBook obect
  644. // for handline IAddrBook::Advise calls.
  645. // [PaulHi] 4/27/99 This just creates the notification "hidden" window. The
  646. // timer will be created only if this is an Outlook session. Otherwise the
  647. // FCN wait thread uses this to notify IAB clients of a store change ... using
  648. // the original thread the IAB was created on.
  649. CreateIABNotificationTimer(lpIAB);
  650. // [PaulHi] 4/27/99 Raid 76520 Use FCN wait thread instead
  651. // of notify window timer for non-Outlook sessions.
  652. if (!pt_bIsWABOpenExSession)
  653. CreateIABNotificationThread(lpIAB);
  654. // All we want to do is initialize the IABs critical section
  655. // We are already in a SessObj critical section.
  656. InitializeCriticalSection(&lpIAB->cs);
  657. lpIAB->hMutexOlk = CreateMutex(NULL, FALSE, TEXT("MPSWABOlkStoreNotifyMutex"));
  658. if(GetLastError()!=ERROR_ALREADY_EXISTS)
  659. {
  660. // First one to create the mutex ... means we can reset the reg settings
  661. SetOutlookRefreshCountData(0,0);
  662. }
  663. GetOutlookRefreshCountData(&lpIAB->dwOlkRefreshCount,&lpIAB->dwOlkFolderRefreshCount);
  664. *lppIAB = (LPVOID)lpIAB;
  665. return(hrSuccess);
  666. err:
  667. FreeBufferAndNull(&lpIAB);
  668. UlRelease(lpPropData);
  669. if(bAddRefedWABObject)
  670. UlRelease(lpWABObject);
  671. if(bAddRefedPropStore)
  672. ReleasePropertyStore(lpPropertyStore); // undo the above operation
  673. return(hr);
  674. }
  675. /*
  676. - SetMAPIError
  677. -
  678. *
  679. * Parameters:
  680. * lpObject
  681. * hr
  682. * ids - ID of string resource associated with an internal error string
  683. * lpszComponent - Constant string, not allocated (must be ANSI)
  684. * ulContext
  685. * ulLowLevelError
  686. * ulErrorFlags - Whether or not the lpMAPIError is UNICODE or not (MAPI_UNICODE)
  687. * lpMAPIError - Allocated, generally from foreign object.
  688. */
  689. VOID SetMAPIError(LPVOID lpObject,
  690. HRESULT hr,
  691. UINT ids,
  692. LPTSTR lpszComponent,
  693. ULONG ulContext,
  694. ULONG ulLowLevelError,
  695. ULONG ulErrorFlags,
  696. LPMAPIERROR lpMAPIError)
  697. {
  698. LPIAB lpIAB = (LPIAB) lpObject;
  699. lpIAB->hLastError = hr;
  700. lpIAB->ulLowLevelError = ulLowLevelError;
  701. lpIAB->ulContext = ulContext;
  702. // Free any existing MAPI error
  703. FreeBufferAndNull(&(lpIAB->lpMAPIError));
  704. // If both a MAPIERROR and a string ID are present then we will
  705. // concatenate them when the error is reported.
  706. lpIAB->lpMAPIError = lpMAPIError;
  707. lpIAB->ulErrorFlags = ulErrorFlags;
  708. lpIAB->idsLastError = ids;
  709. lpIAB->lpszComponent = lpszComponent;
  710. return;
  711. }
  712. /***************************************************
  713. *
  714. * The actual IAdrBook methods
  715. */
  716. // --------
  717. // IUnknown
  718. STDMETHODIMP
  719. IAB_QueryInterface(LPIAB lpIAB,
  720. REFIID lpiid,
  721. LPVOID * lppNewObj)
  722. {
  723. ULONG iIID;
  724. #ifdef PARAMETER_VALIDATION
  725. // Check to see if it has a jump table
  726. if (IsBadReadPtr(lpIAB, sizeof(LPVOID))) {
  727. // No jump table found
  728. return(ResultFromScode(E_INVALIDARG));
  729. }
  730. // Check to see if the jump table has at least sizeof IUnknown
  731. if (IsBadReadPtr(lpIAB->lpVtbl, 3*sizeof(LPVOID))) {
  732. // Jump table not derived from IUnknown
  733. return(ResultFromScode(E_INVALIDARG));
  734. }
  735. // Check to see that it's IAB_QueryInterface
  736. if (lpIAB->lpVtbl->QueryInterface != IAB_QueryInterface) {
  737. // Not my jump table
  738. return(ResultFromScode(E_INVALIDARG));
  739. }
  740. // Is there enough there for an interface ID?
  741. if (IsBadReadPtr(lpiid, sizeof(IID))) {
  742. DebugTraceSc(IAB_QueryInterface, E_INVALIDARG);
  743. return(ResultFromScode(E_INVALIDARG));
  744. }
  745. // Is there enough there for a new object?
  746. if (IsBadWritePtr (lppNewObj, sizeof (LPIAB))) {
  747. DebugTraceSc(IAB_QueryInterface, E_INVALIDARG);
  748. return(ResultFromScode(E_INVALIDARG));
  749. }
  750. #endif // PARAMETER_VALIDATION
  751. EnterCriticalSection(&lpIAB->cs);
  752. // See if the requested interface is one of ours
  753. //
  754. // First check with IUnknown, since we all have to support that one...
  755. //
  756. if (! memcmp(lpiid, &IID_IUnknown, sizeof(IID))) {
  757. goto goodiid;
  758. }
  759. //
  760. // Now look through all the iids associated with this object, see if any match
  761. //
  762. for(iIID = 0; iIID < lpIAB->cIID; iIID++) {
  763. if (!memcmp(lpIAB->rglpIID[iIID], lpiid, sizeof(IID))) {
  764. goodiid:
  765. //
  766. // It's a match of interfaces, we support this one then...
  767. //
  768. ++lpIAB->lcInit;
  769. // Bug 48468 - we're not addrefing the WABObject here but
  770. // we're releasing it in the IadrBook->Release
  771. //
  772. UlAddRef(lpIAB->lpWABObject);
  773. *lppNewObj = lpIAB;
  774. LeaveCriticalSection(&lpIAB->cs);
  775. return(0);
  776. }
  777. }
  778. //
  779. // No interface we've heard of...
  780. //
  781. LeaveCriticalSection(&lpIAB->cs);
  782. *lppNewObj = NULL; // OLE requires NULLing out parm on failure
  783. DebugTraceSc(IAB_QueryInterface, E_NOINTERFACE);
  784. return(ResultFromScode(E_NOINTERFACE));
  785. }
  786. /**************************************************
  787. *
  788. * IAB_AddRef
  789. * Increment lcInit
  790. *
  791. */
  792. STDMETHODIMP_(ULONG) IAB_AddRef (LPIAB lpIAB)
  793. {
  794. #ifdef PARAMETER_VALIDATION
  795. // Check to see if it has a jump table
  796. if (IsBadReadPtr(lpIAB, sizeof(LPVOID))) {
  797. //No jump table found
  798. return(1);
  799. }
  800. // Check to see if the jump table has at least sizeof IUnknown
  801. if (IsBadReadPtr(lpIAB->lpVtbl, 3 * sizeof(LPVOID))) {
  802. // Jump table not derived from IUnknown
  803. return(1);
  804. }
  805. // Check to see if the method is the same
  806. if ((IAB_AddRef != lpIAB->lpVtbl->AddRef)
  807. #ifdef DEBUG
  808. // For spooler session leak tracking
  809. //&& ((IAB_AddRef_METHOD *)SESSOBJ_AddRef != lpIAB->lpVtbl->AddRef)
  810. #endif
  811. ) {
  812. // Wrong object - the object passed doesn't have this
  813. // method.
  814. return(1);
  815. }
  816. #endif // PARAMETER_VALIDATION
  817. EnterCriticalSection(&lpIAB->cs);
  818. ++lpIAB->lcInit;
  819. LeaveCriticalSection(&lpIAB->cs);
  820. UlAddRef(lpIAB->lpWABObject);
  821. return(lpIAB->lcInit);
  822. }
  823. /**************************************************
  824. *
  825. * IAB_Release
  826. * Decrement lpInit.
  827. * When lcInit == 0, free up the lpIAB structure
  828. *
  829. */
  830. STDMETHODIMP_(ULONG)
  831. IAB_Release (LPIAB lpIAB)
  832. {
  833. UINT uiABRef;
  834. BOOL bSetOLKAllocators;
  835. #ifdef PARAMETER_VALIDATION
  836. // Check to see if it has a jump table
  837. if (IsBadReadPtr(lpIAB, sizeof(LPVOID))) {
  838. // No jump table found
  839. return(1);
  840. }
  841. // Check to see if the jump table has at least sizeof IUnknown
  842. if (IsBadReadPtr(lpIAB->lpVtbl, 3*sizeof(LPVOID))) {
  843. // Jump table not derived from IUnknown
  844. return(1);
  845. }
  846. // Check to see if the method is the same
  847. if (IAB_Release != lpIAB->lpVtbl->Release) {
  848. // Wrong object - the object passed doesn't have this
  849. // method.
  850. return(1);
  851. }
  852. #endif // PARAMETER_VALIDATION
  853. VerifyWABOpenExSession(lpIAB);
  854. // The address book is part of the session object, and one doesn't go away
  855. // without the other going away also. This code checks that both the
  856. // session and the address book have a zero refcount before bringing
  857. // them both down. Note that when I want to get both critical sections,
  858. // I get the session object CS first. This avoids deadlock.
  859. // See SESSOBJ_Release in isess.c for very similar code.
  860. UlRelease(lpIAB->lpWABObject);
  861. EnterCriticalSection(&lpIAB->cs);
  862. if (lpIAB->lcInit == 0) {
  863. uiABRef = 0;
  864. } else {
  865. AssertSz(lpIAB->lcInit < UINT_MAX, TEXT("Overflow in IAB Reference count"));
  866. uiABRef = (UINT) --(lpIAB->lcInit);
  867. }
  868. LeaveCriticalSection(&lpIAB->cs);
  869. if (uiABRef) {
  870. return((ULONG)uiABRef);
  871. }
  872. EnterCriticalSection(&lpIAB->cs);
  873. uiABRef = (UINT) lpIAB->lcInit;
  874. LeaveCriticalSection(&lpIAB->cs);
  875. if (uiABRef) {
  876. return(uiABRef);
  877. }
  878. IAB_Neuter(lpIAB);
  879. bSetOLKAllocators = lpIAB->bSetOLKAllocators;
  880. FreeBufferAndNull(&lpIAB);
  881. // [PaulHi] 5/5/99 Raid 77138 Null out Outlook allocator function
  882. // pointers if our global count goes to zero.
  883. if (bSetOLKAllocators)
  884. {
  885. Assert(g_nExtMemAllocCount > 0);
  886. InterlockedDecrement((LPLONG)&g_nExtMemAllocCount);
  887. if (g_nExtMemAllocCount == 0)
  888. {
  889. lpfnAllocateBufferExternal = NULL;
  890. lpfnAllocateMoreExternal = NULL;
  891. lpfnFreeBufferExternal = NULL;
  892. }
  893. }
  894. return(0);
  895. }
  896. /*
  897. * IAB_Neuter
  898. *
  899. * Purpose
  900. * Destroys the memory and objects inside the address book object, leaving
  901. * nothing but the object itself to be freed. Called from CleanupSession()
  902. * in isess.c (client-side cleanup) and from SplsessRelease() in splsess.c
  903. * (spooler-side cleanup). Note that the address book object is only taken
  904. * down as a part of session takedown. Once this call is made, we can assume
  905. * the session is shutting down and can free up everything guilt-free
  906. */
  907. void
  908. IAB_Neuter(LPIAB lpIAB)
  909. {
  910. HINSTANCE hinst = hinstMapiXWAB;
  911. WNDCLASS wc;
  912. if (lpIAB == NULL) {
  913. TraceSz( TEXT("IAB_Neuter: given a NULL lpIAB"));
  914. return;
  915. }
  916. // clean up the advise list for the AB
  917. #ifdef OLD_STUFF
  918. if (lpIAB->padviselistIAB) {
  919. DestroyAdviseList(&lpIAB->padviselistIAB);
  920. }
  921. #endif // OLD_STUFF
  922. // Get rid of any cached context menu extension data
  923. UlRelease(lpIAB->lpCntxtMailUser);
  924. //
  925. // Get rid of my PropData
  926. //
  927. UlRelease(lpIAB->lpPropData);
  928. //
  929. // Get rid of any EntryIDs I've got floating around
  930. //
  931. FreeBufferAndNull(&(lpIAB->lpEntryIDDD));
  932. lpIAB->lpEntryIDDD = NULL;
  933. FreeBufferAndNull(&(lpIAB->lpEntryIDPAB));
  934. lpIAB->lpEntryIDPAB = NULL;
  935. // Remove the SearchPath cache
  936. #if defined (WIN32) && !defined (MAC)
  937. if (fGlobalCSValid) {
  938. EnterCriticalSection(&csMapiSearchPath);
  939. } else {
  940. DebugTrace( TEXT("IAB_Neuter: WAB32.DLL already detached.\n"));
  941. }
  942. #endif
  943. FreeBufferAndNull(&(lpIAB->lpspvSearchPathCache));
  944. lpIAB->lpspvSearchPathCache = NULL;
  945. #if defined (WIN32) && !defined (MAC)
  946. if (fGlobalCSValid) {
  947. LeaveCriticalSection(&csMapiSearchPath);
  948. } else {
  949. DebugTrace(TEXT("IAB_Neuter: WAB32.DLL got detached.\n"));
  950. }
  951. #endif
  952. //
  953. // Release any MAPI allocated error structure
  954. //
  955. FreeBufferAndNull(&(lpIAB->lpMAPIError));
  956. // Release the property store associated with the IAB
  957. ReleasePropertyStore(lpIAB->lpPropertyStore);
  958. // Unload LDAP client if it was loaded at IAB creation.
  959. //if (lpIAB->fLoadedLDAP)
  960. {
  961. DeinitLDAPClientLib();
  962. }
  963. if ((NULL != lpIAB->hWndNotify) && (FALSE != IsWindow(lpIAB->hWndNotify))) {
  964. SendMessage(lpIAB->hWndNotify, WM_CLOSE, 0, 0);
  965. }
  966. // On Windows NT/2000: No window classes registered by a .dll
  967. // are unregistered when the .dll is unloaded.
  968. // If we dont do this we might point to an old/invalid IABNotifWndProc
  969. // pointer in CreateIABNotificationTimer
  970. if (GetClassInfo(hinst, szWABNotifClassName, &wc)) {
  971. UnregisterClass(szWABNotifClassName, hinst);
  972. }
  973. lpIAB->hWndNotify = NULL;
  974. lpIAB->ulNotifyTimer = 0;
  975. // Terminate the wab file change notification thread
  976. if (lpIAB->hThreadNotify != INVALID_HANDLE_VALUE)
  977. {
  978. DWORD dwRtn;
  979. // Signal thread to terminate and wait
  980. Assert(lpIAB->hEventKillNotifyThread);
  981. SetEvent(lpIAB->hEventKillNotifyThread);
  982. dwRtn = WaitForSingleObject(lpIAB->hThreadNotify, INFINITE);
  983. CloseHandle(lpIAB->hThreadNotify);
  984. lpIAB->hThreadNotify = INVALID_HANDLE_VALUE;
  985. }
  986. if (lpIAB->lpwszWABFilePath)
  987. LocalFreeAndNull(&(lpIAB->lpwszWABFilePath));
  988. if (lpIAB->hEventKillNotifyThread)
  989. {
  990. CloseHandle(lpIAB->hEventKillNotifyThread);
  991. lpIAB->hEventKillNotifyThread = NULL;
  992. }
  993. while( lpIAB->pWABAdviseList && //shouldnt happen
  994. lpIAB->pWABAdviseList->cAdvises &&
  995. lpIAB->pWABAdviseList->lpNode)
  996. {
  997. HrUnadvise(lpIAB, lpIAB->pWABAdviseList->lpNode->ulConnection);
  998. }
  999. // Free any memory allocated to rt-click action items
  1000. //
  1001. if(lpIAB->lpActionList)
  1002. FreeActionItemList(lpIAB);
  1003. if(lpIAB->lpPropExtDllList)
  1004. FreePropExtList(lpIAB->lpPropExtDllList);
  1005. FreeWABFoldersList(lpIAB);
  1006. FreeProfileContainerInfo(lpIAB);
  1007. UninitExtInfo();
  1008. UninitContextExtInfo();
  1009. // Release the account manager
  1010. UninitAccountManager();
  1011. // Release the identity manager
  1012. HrRegisterUnregisterForIDNotifications( lpIAB, FALSE);
  1013. UninitUserIdentityManager(lpIAB);
  1014. if(lpIAB->hKeyCurrentUser)
  1015. RegCloseKey(lpIAB->hKeyCurrentUser);
  1016. // Release trident
  1017. UninitTrident();
  1018. UIOLEUninit();
  1019. //
  1020. // Set the time-bomb
  1021. //
  1022. lpIAB->lpVtbl = NULL;
  1023. DeleteCriticalSection(&lpIAB->cs);
  1024. if(lpIAB->hMutexOlk)
  1025. CloseHandle(lpIAB->hMutexOlk);
  1026. return;
  1027. }
  1028. // IMAPIProp
  1029. /**************************************************
  1030. *
  1031. * IAB_GetLastError()
  1032. *
  1033. * Returns a string associated with the last hResult
  1034. * returned by the IAB object.
  1035. *
  1036. * Now UNICODE enabled
  1037. *
  1038. */
  1039. STDMETHODIMP
  1040. IAB_GetLastError(LPIAB lpIAB,
  1041. HRESULT hError,
  1042. ULONG ulFlags,
  1043. LPMAPIERROR FAR * lppMAPIError)
  1044. {
  1045. HRESULT hr = hrSuccess;
  1046. #ifdef PARAMETER_VALIDATION
  1047. // Check to see if it has a jump table
  1048. if (IsBadReadPtr(lpIAB, sizeof(LPVOID))) {
  1049. // No jump table found
  1050. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  1051. }
  1052. // Check to see if the jump table has at least sizeof IUnknown
  1053. if (IsBadReadPtr(lpIAB->lpVtbl, 4*sizeof(LPVOID))) {
  1054. // Jump table not derived from IUnknown
  1055. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  1056. }
  1057. // Check to see if the method is the same
  1058. if (IAB_GetLastError != lpIAB->lpVtbl->GetLastError) {
  1059. // Wrong object - the object passed doesn't have this
  1060. // method.
  1061. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  1062. }
  1063. if (FBadGetLastError(lpIAB, hError, ulFlags, lppMAPIError)) {
  1064. DebugTraceArg(IAB_GetLastError, TEXT("Bad writeable parameter"));
  1065. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  1066. }
  1067. if (ulFlags & ~MAPI_UNICODE) {
  1068. DebugTraceArg(IAB_GetLastError, TEXT("reserved flags used"));
  1069. // return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
  1070. }
  1071. #endif // PARAMETER_VALIDATION
  1072. EnterCriticalSection(&lpIAB->cs);
  1073. if(lppMAPIError)
  1074. *lppMAPIError = NULL; // really isnt anything to return here for now
  1075. // set this to NULL, which means no error information
  1076. #ifdef OLD_STUFF
  1077. hr = HrGetLastError(lpIAB, hError, ulFlags, lppMAPIError);
  1078. #endif
  1079. LeaveCriticalSection(&lpIAB->cs);
  1080. return(hr);
  1081. }
  1082. //
  1083. // Set of properties set by Creating a one off.
  1084. //
  1085. enum {
  1086. iooPR_ADDRTYPE = 0,
  1087. iooPR_DISPLAY_NAME,
  1088. iooPR_EMAIL_ADDRESS,
  1089. iooPR_ENTRYID,
  1090. iooPR_OBJECT_TYPE,
  1091. iooMax
  1092. };
  1093. /***************************************************************************
  1094. Name : IsOneOffEID
  1095. Purpose : Is this EntryID a One-off?
  1096. Parameters: cbEntryID = size of lpEntryID
  1097. lpEntryID -> entry ID of one off to open
  1098. Returns : TRUE or FALSE
  1099. Comment :
  1100. ***************************************************************************/
  1101. BOOL IsOneOffEID(ULONG cbEntryID, LPENTRYID lpEntryID) {
  1102. return(WAB_ONEOFF == IsWABEntryID(cbEntryID, lpEntryID, NULL, NULL, NULL, NULL, NULL));
  1103. }
  1104. /***************************************************************************
  1105. Name : NewOneOff
  1106. Purpose : Create a new MailUser object based on a OneOff EntryID
  1107. Parameters: cbEntryID = size of lpEntryID
  1108. lpEntryID -> entry ID of one off to open
  1109. lpulObjType -> returned object type
  1110. Returns : HRESULT
  1111. Comment : OneOff EID format is MAPI_ENTRYID:
  1112. BYTE abFlags[4];
  1113. MAPIUID mapiuid; // = WABONEOFFEID
  1114. BYTE bData[]; // contains szaddrtype followed by szaddress
  1115. // the delimiter is the null after szaddrtype.
  1116. // The first ULONG in bData[] is the ulMapiDataType,
  1117. // which contains the MAPI_UNICODE flag if unicode.
  1118. Assumes that the EntryID contains valid strings. It is the job of
  1119. the caller to validate the EntryID before calling NewOneOff.
  1120. ***************************************************************************/
  1121. HRESULT NewOneOff(
  1122. LPIAB lpIAB,
  1123. ULONG cbEntryID,
  1124. LPENTRYID lpEntryID,
  1125. LPULONG lpulObjType,
  1126. LPUNKNOWN FAR * lppUnk)
  1127. {
  1128. HRESULT hResult = hrSuccess;
  1129. LPMAPI_ENTRYID lpMapiEID = (LPMAPI_ENTRYID)lpEntryID;
  1130. LPMAILUSER lpMailUser = NULL;
  1131. SPropValue spv[iooMax];
  1132. LPBYTE lpbDisplayName, lpbAddrType, lpbAddress;
  1133. LPTSTR lptszDisplayName = NULL;
  1134. LPTSTR lptszAddrType = NULL;
  1135. LPTSTR lptszAddress = NULL;
  1136. LPPROPDATA lpPropData = NULL;
  1137. ULONG ulMapiDataType = 0;
  1138. // Validate the EntryID as WAB_ONEOFF
  1139. if (WAB_ONEOFF != IsWABEntryID(cbEntryID, lpEntryID, &lpbDisplayName, &lpbAddrType, &lpbAddress, (LPVOID *)&ulMapiDataType, NULL)) {
  1140. hResult = ResultFromScode(MAPI_E_INVALID_ENTRYID);
  1141. goto exit;
  1142. }
  1143. // [PaulHi] 1/20/99 Raid 64211
  1144. // UNICODE is native in WAB. Convert strings to be consistent
  1145. if (!(ulMapiDataType & MAPI_UNICODE))
  1146. {
  1147. lptszDisplayName = ConvertAtoW((LPSTR)lpbDisplayName);
  1148. lptszAddrType = ConvertAtoW((LPSTR)lpbAddrType);
  1149. lptszAddress = ConvertAtoW((LPSTR)lpbAddress);
  1150. }
  1151. else
  1152. {
  1153. lptszDisplayName = (LPTSTR)lpbDisplayName;
  1154. lptszAddrType = (LPTSTR)lpbAddrType;
  1155. lptszAddress = (LPTSTR)lpbAddress;
  1156. }
  1157. // Parse the addrtype and address out of the entryid
  1158. // DebugTrace(TEXT("NewOneOff: [%s:%s:%s]\n"), lpDisplayName, lpAddrType, lpAddress);
  1159. // Create a new MAILUSER object
  1160. if (HR_FAILED(hResult = HrNewMAILUSER(lpIAB, NULL, MAPI_MAILUSER, 0, &lpMailUser))) {
  1161. goto exit;
  1162. }
  1163. lpPropData = ((LPMailUser)lpMailUser)->lpPropData;
  1164. // Fill it with properties... we only have a few.
  1165. // PR_OBJECT_TYPE
  1166. spv[iooPR_ADDRTYPE].ulPropTag = PR_ADDRTYPE;
  1167. spv[iooPR_ADDRTYPE].Value.LPSZ = lptszAddrType;
  1168. spv[iooPR_DISPLAY_NAME].ulPropTag = PR_DISPLAY_NAME;
  1169. spv[iooPR_DISPLAY_NAME].Value.LPSZ = lptszDisplayName;
  1170. spv[iooPR_EMAIL_ADDRESS].ulPropTag = PR_EMAIL_ADDRESS;
  1171. spv[iooPR_EMAIL_ADDRESS].Value.LPSZ = lptszAddress;
  1172. spv[iooPR_ENTRYID].ulPropTag = PR_ENTRYID;
  1173. spv[iooPR_ENTRYID].Value.bin.lpb = (LPBYTE)lpEntryID;
  1174. spv[iooPR_ENTRYID].Value.bin.cb = cbEntryID;
  1175. // BUGBUG: This is already done in HrNewMAILUSER.
  1176. spv[iooPR_OBJECT_TYPE].ulPropTag = PR_OBJECT_TYPE;
  1177. spv[iooPR_OBJECT_TYPE].Value.l = MAPI_MAILUSER;
  1178. Assert(lpMailUser);
  1179. // Set the properties
  1180. if (HR_FAILED(hResult = lpPropData->lpVtbl->SetProps(lpPropData,
  1181. iooMax, // number of properties to set
  1182. spv, // property array
  1183. NULL))) { // problem array
  1184. goto exit;
  1185. }
  1186. *lpulObjType = MAPI_MAILUSER;
  1187. *lppUnk = (LPUNKNOWN)lpMailUser;
  1188. exit:
  1189. if (!(ulMapiDataType & MAPI_UNICODE))
  1190. {
  1191. LocalFreeAndNull(&lptszDisplayName);
  1192. LocalFreeAndNull(&lptszAddrType);
  1193. LocalFreeAndNull(&lptszAddress);
  1194. }
  1195. if (HR_FAILED(hResult)) {
  1196. FreeBufferAndNull(&lpMailUser);
  1197. }
  1198. return(hResult);
  1199. }
  1200. typedef enum {
  1201. e_IMailUser,
  1202. e_IDistList,
  1203. e_IABContainer,
  1204. e_IMAPIContainer,
  1205. e_IMAPIProp,
  1206. } INTERFACE_INDEX;
  1207. /***************************************************************************
  1208. Name : HrAddPrSearchKey
  1209. Purpose : Dynamically creates a PR_SEARCH_KEY and adds it to the object.
  1210. Parameters: lppUnk -> pointer to mailuser object
  1211. Returns : HRESULT
  1212. Comment : No UNICODE flags.
  1213. ***************************************************************************/
  1214. HRESULT HrAddPrSearchKey(LPUNKNOWN FAR * lppUnk,
  1215. ULONG cbEntryID,
  1216. LPENTRYID lpEntryID)
  1217. {
  1218. HRESULT hr = E_FAIL;
  1219. ULONG ulcProps = 0;
  1220. LPSPropValue lpPropArray = NULL;
  1221. LPMAILUSER lpMailUser = NULL;
  1222. LPSPropValue lpPropArrayNew = NULL;
  1223. ULONG ulcPropsNew = 0;
  1224. ULONG i = 0;
  1225. SCODE sc;
  1226. ULONG ulObjAccess = 0;
  1227. LPIPDAT lpPropData = NULL;
  1228. if(!lppUnk || !(*lppUnk))
  1229. {
  1230. hr = MAPI_E_INVALID_PARAMETER;
  1231. goto exit;
  1232. }
  1233. lpMailUser = (LPMAILUSER) (*lppUnk);
  1234. lpPropData = (LPIPDAT) ((LPMailUser) lpMailUser)->lpPropData;
  1235. //temporarily overwrite the object access so we can modify it here
  1236. ulObjAccess = lpPropData->ulObjAccess;
  1237. lpPropData->ulObjAccess = IPROP_READWRITE;
  1238. hr = lpMailUser->lpVtbl->GetProps( lpMailUser,
  1239. NULL,
  1240. MAPI_UNICODE,
  1241. &ulcProps,
  1242. &lpPropArray);
  1243. if(HR_FAILED(hr))
  1244. goto exit;
  1245. if (ulcProps && lpPropArray)
  1246. {
  1247. // 4/14/97 - vikramm
  1248. // Outlook expects a PR_SEARCH_KEY on each mailuser or distlist
  1249. // This is a dynamic property created at runtime - ideally, if we're
  1250. // running against outlook store, we should have one at this point
  1251. // but to be consistent, if we dont have one we should add one
  1252. // The PR_SEARCH_KEY is a binary property which is made of the
  1253. // email address or if there is no email address, is the entryid of
  1254. // this contact ..
  1255. {
  1256. SPropValue PropSearchKey = {0};
  1257. LPTSTR lpszEmail = NULL;
  1258. LPTSTR lpszAddrType = NULL;
  1259. BOOL bSearchKeyFound = FALSE;
  1260. for (i = 0; i < ulcProps; i++)
  1261. {
  1262. switch(lpPropArray[i].ulPropTag)
  1263. {
  1264. case PR_EMAIL_ADDRESS:
  1265. lpszEmail = lpPropArray[i].Value.LPSZ;
  1266. break;
  1267. case PR_ADDRTYPE:
  1268. lpszAddrType = lpPropArray[i].Value.LPSZ;
  1269. break;
  1270. case PR_SEARCH_KEY:
  1271. bSearchKeyFound = TRUE;
  1272. break;
  1273. }
  1274. }
  1275. if(!bSearchKeyFound)
  1276. {
  1277. PropSearchKey.ulPropTag = PR_SEARCH_KEY;
  1278. //Create a search key
  1279. if(lpszEmail && lpszAddrType)
  1280. {
  1281. // Search Key is based on email address
  1282. // [PaulHi] 4/23/99 Raid 76717
  1283. // The Search Key strings must be single byte for Outlook. Do conversion here.
  1284. {
  1285. LPSTR lpszKey;
  1286. DWORD cchSize = (lstrlen(lpszAddrType) + 1 + lstrlen(lpszEmail) + 1);
  1287. LPWSTR lpwszKey = LocalAlloc( LMEM_ZEROINIT, (sizeof(WCHAR)*cchSize));
  1288. if (!lpwszKey)
  1289. {
  1290. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  1291. goto exit;
  1292. }
  1293. StrCpyN(lpwszKey, lpszAddrType, cchSize);
  1294. StrCatBuff(lpwszKey, szColon, cchSize);
  1295. StrCatBuff(lpwszKey, lpszEmail, cchSize);
  1296. // This search key should be in upper case
  1297. CharUpper(lpwszKey);
  1298. lpszKey = ConvertWtoA(lpwszKey);
  1299. LocalFreeAndNull(&lpwszKey);
  1300. if (!lpszKey)
  1301. {
  1302. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  1303. goto exit;
  1304. }
  1305. PropSearchKey.Value.bin.cb = (lstrlenA(lpszKey) + 1);
  1306. PropSearchKey.Value.bin.lpb = (LPBYTE)lpszKey;
  1307. }
  1308. }
  1309. else
  1310. {
  1311. // Search key is based on entry id
  1312. if(!cbEntryID || !lpEntryID)
  1313. {
  1314. hr = MAPI_E_INVALID_PARAMETER;
  1315. goto exit;
  1316. }
  1317. PropSearchKey.Value.bin.cb = cbEntryID;
  1318. PropSearchKey.Value.bin.lpb = (LPBYTE) lpEntryID;
  1319. }
  1320. // Add this search key to the proparray
  1321. sc = ScMergePropValues( 1,
  1322. &PropSearchKey,
  1323. ulcProps,
  1324. lpPropArray,
  1325. &ulcPropsNew,
  1326. &lpPropArrayNew);
  1327. // Free this pointer if it was allocated
  1328. if(PropSearchKey.Value.bin.lpb != (LPBYTE) lpEntryID)
  1329. LocalFree(PropSearchKey.Value.bin.lpb);
  1330. if (sc != S_OK)
  1331. {
  1332. hr = ResultFromScode(sc);
  1333. goto exit;
  1334. }
  1335. }
  1336. }
  1337. if (HR_FAILED(hr = lpMailUser->lpVtbl->SetProps(lpMailUser,
  1338. (lpPropArrayNew ? ulcPropsNew : ulcProps), // number of properties to set
  1339. (lpPropArrayNew ? lpPropArrayNew : lpPropArray), // property array
  1340. NULL))) // problem array
  1341. {
  1342. goto exit;
  1343. }
  1344. }
  1345. exit:
  1346. // reset the object access
  1347. if(!HR_FAILED(hr) &&
  1348. (ulObjAccess != lpPropData->ulObjAccess))
  1349. {
  1350. lpPropData->ulObjAccess = ulObjAccess;
  1351. }
  1352. if(lpPropArrayNew)
  1353. MAPIFreeBuffer(lpPropArrayNew);
  1354. if(lpPropArray)
  1355. MAPIFreeBuffer(lpPropArray);
  1356. return hr;
  1357. }
  1358. /***************************************************************************
  1359. Name : IADDRBOOK_GetIDsFromNames
  1360. Returns : HRESULT
  1361. Comment :
  1362. ***************************************************************************/
  1363. STDMETHODIMP
  1364. IAB_GetIDsFromNames(LPIAB lpIAB, ULONG cPropNames, LPMAPINAMEID * lppPropNames,
  1365. ULONG ulFlags, LPSPropTagArray * lppPropTags)
  1366. {
  1367. #if !defined(NO_VALIDATION)
  1368. // Make sure the object is valid.
  1369. if (BAD_STANDARD_OBJ(lpIAB, IAB_, GetIDsFromNames, lpVtbl)) {
  1370. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  1371. }
  1372. #endif
  1373. VerifyWABOpenExSession(lpIAB);
  1374. return HrGetIDsFromNames(lpIAB,
  1375. cPropNames,
  1376. lppPropNames, ulFlags, lppPropTags);
  1377. }
  1378. /***************************************************************************
  1379. Name : IADDRBOOK::OpenEntry
  1380. Purpose : Asks the appropriate provider to give a appropriate object
  1381. relevant to the given lpEntryID.
  1382. Parameters: lpIAB -> this addrbook object
  1383. cbEntryID = size of lpEntryID
  1384. lpEntryID -> entry ID of one off to open
  1385. lpInterface -> requested interface
  1386. ulFlags = flags
  1387. lpulObjType -> returned object type
  1388. lppUnk -> returned object
  1389. Returns : HRESULT
  1390. Comment : A special case is the One-Off Provider. There is no *real*
  1391. provider associated with One-Off entry IDs. Still though,
  1392. we'll try to treat them much the same as any other provider.
  1393. No UNICODE flags.
  1394. ***************************************************************************/
  1395. STDMETHODIMP
  1396. IAB_OpenEntry(LPIAB lpIAB,
  1397. ULONG cbEntryID,
  1398. LPENTRYID lpEntryID,
  1399. LPCIID lpInterface,
  1400. ULONG ulFlags,
  1401. ULONG FAR * lpulObjType,
  1402. LPUNKNOWN FAR * lppUnk)
  1403. {
  1404. HRESULT hr = hrSuccess;
  1405. LPMAILUSER lpMailUser = NULL;
  1406. LPMAPIPROP lpMapiProp = NULL;
  1407. ULONG ulcProps = 0;
  1408. LPSPropValue lpPropArray = NULL;
  1409. ULONG i;
  1410. ULONG ulType;
  1411. INTERFACE_INDEX ii = e_IMailUser;
  1412. SCODE sc;
  1413. #ifndef DONT_ADDREF_PROPSTORE
  1414. if ((FAILED(sc = OpenAddRefPropertyStore(NULL, lpIAB->lpPropertyStore)))) {
  1415. hr = ResultFromScode(sc);
  1416. goto exitNotAddRefed;
  1417. }
  1418. #endif
  1419. #ifdef PARAMETER_VALIDATION
  1420. //
  1421. // Parameter Validataion
  1422. //
  1423. // Is this one of mine??
  1424. if (IsBadReadPtr(lpIAB, sizeof(IAB))) {
  1425. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  1426. }
  1427. if (lpIAB->lpVtbl != &vtblIAB) {
  1428. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  1429. }
  1430. if (lpInterface && IsBadReadPtr(lpInterface, sizeof(IID))) {
  1431. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  1432. }
  1433. if (ulFlags & ~(MAPI_MODIFY | MAPI_DEFERRED_ERRORS | MAPI_BEST_ACCESS)) {
  1434. DebugTraceArg(IAB_OpenEntry , TEXT("Unknown flags used"));
  1435. // return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
  1436. }
  1437. if (IsBadWritePtr(lpulObjType, sizeof(ULONG))) {
  1438. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  1439. }
  1440. if (IsBadWritePtr(lppUnk, sizeof(LPUNKNOWN))) {
  1441. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  1442. }
  1443. #endif // PARAMETER_VALIDATION
  1444. VerifyWABOpenExSession(lpIAB);
  1445. EnterCriticalSection(&lpIAB->cs);
  1446. //
  1447. // First check to see if it's NULL - if so, it is our ROOT container
  1448. //
  1449. if (! lpEntryID) {
  1450. hr = HrNewCONTAINER(lpIAB,
  1451. AB_ROOT, // ulType
  1452. lpInterface,
  1453. ulFlags,
  1454. cbEntryID,
  1455. lpEntryID,
  1456. lpulObjType,
  1457. lppUnk);
  1458. goto exit;
  1459. }
  1460. switch (IsWABEntryID(cbEntryID, lpEntryID, NULL, NULL, NULL, NULL, NULL)) {
  1461. case WAB_PABSHARED:
  1462. case WAB_PAB:
  1463. hr = HrNewCONTAINER(lpIAB,
  1464. AB_PAB, // ulType
  1465. lpInterface,
  1466. ulFlags,
  1467. cbEntryID,
  1468. lpEntryID,
  1469. lpulObjType,
  1470. lppUnk);
  1471. goto exit;
  1472. case WAB_CONTAINER:
  1473. hr = HrNewCONTAINER(lpIAB,
  1474. AB_CONTAINER,
  1475. lpInterface,
  1476. ulFlags,
  1477. cbEntryID,
  1478. lpEntryID,
  1479. lpulObjType,
  1480. lppUnk);
  1481. goto exit;
  1482. case WAB_LDAP_CONTAINER:
  1483. // Check if the EntryID is for the WAB's PAB container.
  1484. hr = HrNewCONTAINER(lpIAB,
  1485. AB_LDAP_CONTAINER, // ulType
  1486. lpInterface,
  1487. ulFlags,
  1488. cbEntryID,
  1489. lpEntryID,
  1490. lpulObjType,
  1491. lppUnk);
  1492. goto exit;
  1493. case WAB_LDAP_MAILUSER:
  1494. hr = LDAP_OpenMAILUSER(lpIAB,
  1495. cbEntryID,
  1496. lpEntryID,
  1497. lpInterface,
  1498. ulFlags,
  1499. lpulObjType,
  1500. lppUnk);
  1501. if(!HR_FAILED(hr))
  1502. {
  1503. hr = HrAddPrSearchKey(lppUnk, cbEntryID, lpEntryID);
  1504. }
  1505. goto exit;
  1506. }
  1507. // Check for One-Off
  1508. if (IsOneOffEID(cbEntryID, lpEntryID)) {
  1509. // Create a one-off mailuser object
  1510. hr = NewOneOff(lpIAB,
  1511. cbEntryID,
  1512. lpEntryID,
  1513. lpulObjType,
  1514. lppUnk);
  1515. if(!HR_FAILED(hr))
  1516. {
  1517. hr = HrAddPrSearchKey(lppUnk, cbEntryID, lpEntryID);
  1518. }
  1519. goto exit;
  1520. }
  1521. //
  1522. // Not NULL, is it ours?
  1523. //
  1524. // assume it is ours ..
  1525. {
  1526. SBinary sbEID = {0};
  1527. sbEID.cb = cbEntryID;
  1528. sbEID.lpb = (LPBYTE) lpEntryID;
  1529. // What interface was requested?
  1530. // We've basically got 2 interfaces here... IMailUser and IDistList.
  1531. if (lpInterface != NULL) {
  1532. if (! memcmp(lpInterface, &IID_IMailUser, sizeof(IID))) {
  1533. ii = e_IMailUser;
  1534. } else if (! memcmp(lpInterface, &IID_IDistList, sizeof(IID))) {
  1535. ii = e_IDistList;
  1536. } else if (! memcmp(lpInterface, &IID_IABContainer, sizeof(IID))) {
  1537. ii = e_IABContainer;
  1538. } else if (! memcmp(lpInterface, &IID_IMAPIContainer, sizeof(IID))) {
  1539. ii = e_IMAPIContainer;
  1540. } else if (! memcmp(lpInterface, &IID_IMAPIProp, sizeof(IID))) {
  1541. ii = e_IMAPIProp;
  1542. } else {
  1543. hr = ResultFromScode(MAPI_E_INTERFACE_NOT_SUPPORTED);
  1544. goto exit;
  1545. }
  1546. }
  1547. /*** Bug:31975 - dont default to mail user
  1548. else {
  1549. ii = e_IMailUser;
  1550. }
  1551. */
  1552. Assert(lpIAB->lpPropertyStore->hPropertyStore);
  1553. if (HR_FAILED(hr = ReadRecord(lpIAB->lpPropertyStore->hPropertyStore,
  1554. &sbEID, // EntryID
  1555. 0, // ulFlags
  1556. &ulcProps, // number of props returned
  1557. &lpPropArray))) { // properties returned
  1558. DebugTraceResult(IAB_OpenEntry:ReadRecord, hr);
  1559. goto exit;
  1560. }
  1561. ulType = MAPI_MAILUSER; // Default
  1562. if (ulcProps) {
  1563. Assert(lpPropArray);
  1564. if (lpPropArray) {
  1565. // Look for PR_OBJECT_TYPE
  1566. for (i = 0; i < ulcProps; i++) {
  1567. if (lpPropArray[i].ulPropTag == PR_OBJECT_TYPE) {
  1568. ulType = lpPropArray[i].Value.l;
  1569. break;
  1570. }
  1571. }
  1572. }
  1573. }
  1574. /*** Bug 31975 - dont default to mailuser **/
  1575. if(!lpInterface)
  1576. {
  1577. ii = (ulType == MAPI_DISTLIST) ? e_IDistList : e_IMailUser;
  1578. }
  1579. switch (ulType) {
  1580. case MAPI_MAILUSER:
  1581. case MAPI_ABCONT:
  1582. switch (ii) {
  1583. case e_IMailUser:
  1584. case e_IMAPIContainer:
  1585. case e_IMAPIProp:
  1586. // Create a new MAILUSER object
  1587. if (HR_FAILED(hr = HrNewMAILUSER(lpIAB,
  1588. NULL,
  1589. MAPI_MAILUSER,
  1590. 0,
  1591. &lpMapiProp)))
  1592. {
  1593. goto exit;
  1594. }
  1595. HrSetMAILUSERAccess((LPMAILUSER)lpMapiProp, MAPI_MODIFY);
  1596. break;
  1597. default:
  1598. hr = ResultFromScode(MAPI_E_INTERFACE_NOT_SUPPORTED);
  1599. goto exit;
  1600. }
  1601. break;
  1602. case MAPI_DISTLIST:
  1603. switch (ii) {
  1604. case e_IMailUser:
  1605. case e_IMAPIProp:
  1606. // Create a new MAILUSER object
  1607. if (HR_FAILED(hr = HrNewMAILUSER(lpIAB,
  1608. NULL,
  1609. ulType,
  1610. 0,
  1611. &lpMapiProp))) {
  1612. goto exit;
  1613. }
  1614. HrSetMAILUSERAccess((LPMAILUSER)lpMapiProp, MAPI_MODIFY);
  1615. break;
  1616. case e_IDistList:
  1617. case e_IABContainer:
  1618. case e_IMAPIContainer:
  1619. // Create the Distribution List object.
  1620. if (HR_FAILED(hr = HrNewCONTAINER(lpIAB,
  1621. AB_DL, // ulType
  1622. lpInterface,
  1623. ulFlags,
  1624. 0,
  1625. NULL,
  1626. lpulObjType,
  1627. &lpMapiProp))) {
  1628. goto exit;
  1629. }
  1630. HrSetCONTAINERAccess((LPCONTAINER)lpMapiProp, MAPI_MODIFY);
  1631. break;
  1632. default:
  1633. Assert(FALSE);
  1634. }
  1635. break;
  1636. default:
  1637. {
  1638. //Assert(FALSE);
  1639. // Most likely if we got here we got an object of type MAPI_ABCONT somehow..
  1640. // better to fail here gracefully than to barf and assert and then crash
  1641. hr = MAPI_E_INVALID_OBJECT;
  1642. goto exit;
  1643. }
  1644. break;
  1645. }
  1646. if (ulcProps && lpPropArray)
  1647. {
  1648. LPPROPDATA lpPropData = NULL;
  1649. // If the entry had properties, set them in our returned object
  1650. lpPropData = ((LPMailUser)lpMapiProp)->lpPropData;
  1651. if (HR_FAILED(hr = lpPropData->lpVtbl->SetProps(lpPropData,
  1652. ulcProps, // number of properties to set
  1653. lpPropArray, // property array
  1654. NULL))) // problem array
  1655. {
  1656. goto exit;
  1657. }
  1658. }
  1659. switch (ulType) {
  1660. case MAPI_MAILUSER:
  1661. HrSetMAILUSERAccess((LPMAILUSER)lpMapiProp, ulFlags);
  1662. break;
  1663. case MAPI_DISTLIST:
  1664. HrSetCONTAINERAccess((LPCONTAINER)lpMapiProp, ulFlags);
  1665. break;
  1666. }
  1667. *lpulObjType = ulType;
  1668. *lppUnk = (LPUNKNOWN)lpMapiProp;
  1669. if(!HR_FAILED(hr))
  1670. {
  1671. hr = HrAddPrSearchKey(lppUnk, cbEntryID, lpEntryID);
  1672. }
  1673. goto exit; // success
  1674. }
  1675. hr = ResultFromScode(MAPI_E_INVALID_ENTRYID);
  1676. exit:
  1677. #ifndef DONT_ADDREF_PROPSTORE
  1678. ReleasePropertyStore(lpIAB->lpPropertyStore);
  1679. exitNotAddRefed:
  1680. #endif
  1681. ReadRecordFreePropArray( lpIAB->lpPropertyStore->hPropertyStore,
  1682. ulcProps,
  1683. &lpPropArray); // Free memory from ReadRecord
  1684. LeaveCriticalSection(&lpIAB->cs);
  1685. DebugTraceResult(IAB_OpenEntry, hr);
  1686. return(hr);
  1687. }
  1688. /**************************************************
  1689. *
  1690. * IADRBOOK::CreateOneOff()
  1691. *
  1692. * Creates an entry ID which has all the information
  1693. * about this entry contained within it.
  1694. *
  1695. * Notes:
  1696. * I need a MAPIUID. For now, I'll make one up.
  1697. * The ulDataType is UNICODE. I'll define that in
  1698. * _abint.h for now.
  1699. *
  1700. * Now UNICODE enabled. If the MAPI_UNICODE flag is set
  1701. * the text elements of the EntryID will be WCHAR.
  1702. */
  1703. STDMETHODIMP
  1704. IAB_CreateOneOff(LPIAB lpIAB,
  1705. LPTSTR lpszName,
  1706. LPTSTR lpszAdrType,
  1707. LPTSTR lpszAddress,
  1708. ULONG ulFlags,
  1709. ULONG * lpcbEntryID,
  1710. LPENTRYID * lppEntryID)
  1711. {
  1712. HRESULT hr = hrSuccess;
  1713. BOOL bIsUnicode = (ulFlags & MAPI_UNICODE) == MAPI_UNICODE;
  1714. LPTSTR lpName = NULL, lpAdrType = NULL, lpAddress = NULL;
  1715. if(!bIsUnicode) // <note> assumes UNICODE defined
  1716. {
  1717. lpName = ConvertAtoW((LPSTR)lpszName);
  1718. lpAdrType = ConvertAtoW((LPSTR)lpszAdrType);
  1719. lpAddress = ConvertAtoW((LPSTR)lpszAddress);
  1720. }
  1721. else
  1722. {
  1723. lpName = lpszName;
  1724. lpAdrType = lpszAdrType;
  1725. lpAddress = lpszAddress;
  1726. }
  1727. hr = CreateWABEntryIDEx(bIsUnicode,
  1728. WAB_ONEOFF,
  1729. lpName,
  1730. lpAdrType,
  1731. lpAddress,
  1732. 0, 0,
  1733. NULL,
  1734. lpcbEntryID,
  1735. lppEntryID);
  1736. if(!bIsUnicode) // <note> assumes UNICODE defined
  1737. {
  1738. LocalFreeAndNull(&lpName);
  1739. LocalFreeAndNull(&lpAdrType);
  1740. LocalFreeAndNull(&lpAddress);
  1741. }
  1742. return(hr);
  1743. }
  1744. STDMETHODIMP
  1745. IAB_CompareEntryIDs(LPIAB lpIAB,
  1746. ULONG cbEntryID1,
  1747. LPENTRYID lpEntryID1,
  1748. ULONG cbEntryID2,
  1749. LPENTRYID lpEntryID2,
  1750. ULONG ulFlags,
  1751. ULONG * lpulResult)
  1752. {
  1753. LPMAPI_ENTRYID lpMapiEid1 = (LPMAPI_ENTRYID) lpEntryID1;
  1754. LPMAPI_ENTRYID lpMapiEid2 = (LPMAPI_ENTRYID) lpEntryID2;
  1755. HRESULT hr = hrSuccess;
  1756. #ifdef PARAMETER_VALIDATION
  1757. //
  1758. // Parameter Validataion
  1759. //
  1760. // Is this one of mine??
  1761. if (IsBadReadPtr(lpIAB, sizeof(IAB)))
  1762. {
  1763. //return(ReportResult(0, MAPI_E_INVALID_PARAMETER, 0, 0));
  1764. DebugTrace(TEXT("ERROR: IAB_CompareEntryIDs - invalid lpIAB"));
  1765. return (MAPI_E_INVALID_PARAMETER);
  1766. }
  1767. if (lpIAB->lpVtbl != &vtblIAB)
  1768. {
  1769. //return(ReportResult(0, MAPI_E_INVALID_PARAMETER, 0, 0));
  1770. DebugTrace(TEXT("ERROR: IAB_CompareEntryIDs - invalid lpIAB Vtable"));
  1771. return (MAPI_E_INVALID_PARAMETER);
  1772. }
  1773. // ulFlags must be 0
  1774. if (ulFlags)
  1775. {
  1776. //return(ReportResult(0, MAPI_E_UNKNOWN_FLAGS, 0, 0));
  1777. DebugTrace(TEXT("WARNING: IAB_CompareEntryIDs - invalid flag parameter"));
  1778. // No need to return error
  1779. }
  1780. if (IsBadWritePtr(lpulResult, sizeof(ULONG)))
  1781. {
  1782. //return(ReportResult(0, MAPI_E_INVALID_PARAMETER, 0, 0));
  1783. DebugTrace(TEXT("ERROR: IAB_CompareEntryIDs - invalid out pointer"));
  1784. return (MAPI_E_INVALID_PARAMETER);
  1785. }
  1786. // NULL EIDs are OK
  1787. if ( cbEntryID1 && lpEntryID1 &&
  1788. IsBadReadPtr(lpEntryID1, cbEntryID1) )
  1789. {
  1790. DebugTrace(TEXT("ERROR: IAB_CompareEntryIDs - invalid EntryID1"));
  1791. return (MAPI_E_INVALID_PARAMETER);
  1792. }
  1793. if ( cbEntryID2 && lpEntryID2 &&
  1794. IsBadReadPtr(lpEntryID2, cbEntryID2))
  1795. {
  1796. DebugTrace(TEXT("ERROR: IAB_CompareEntryIDs - invalid EntryID2"));
  1797. return (MAPI_E_INVALID_PARAMETER);
  1798. }
  1799. #endif // PARAMETER_VALIDATION
  1800. EnterCriticalSection(&lpIAB->cs);
  1801. *lpulResult = FALSE; // default
  1802. // Optimization, see if they're binarily the same
  1803. if (cbEntryID1 == cbEntryID2) {
  1804. if (cbEntryID1 && 0 == memcmp((LPVOID) lpMapiEid1, (LPVOID) lpMapiEid2,
  1805. (size_t) cbEntryID1)) {
  1806. //
  1807. // They've got to be the same
  1808. //
  1809. *lpulResult = TRUE;
  1810. hr = hrSuccess;
  1811. goto exit;
  1812. }
  1813. }
  1814. exit:
  1815. LeaveCriticalSection(&lpIAB->cs);
  1816. return(hr);
  1817. }
  1818. //-----------------------------------------------------------------------------
  1819. // Synopsis: IAB_Advise()
  1820. // Description:
  1821. //
  1822. // Parameters:
  1823. // Returns:
  1824. // Effects:
  1825. // Notes:
  1826. // Revision:
  1827. //-----------------------------------------------------------------------------
  1828. STDMETHODIMP
  1829. IAB_Advise(LPIAB lpIAB,
  1830. ULONG cbEntryID,
  1831. LPENTRYID lpEntryID,
  1832. ULONG ulEventMask,
  1833. LPMAPIADVISESINK lpAdvise,
  1834. ULONG FAR * lpulConnection)
  1835. {
  1836. HRESULT hr = hrSuccess;
  1837. SCODE sc = S_OK;
  1838. LPSTR lpszError = NULL;
  1839. LPSTR lpszComponent = NULL;
  1840. // LPMAPI_ENTRYID lpMapiEid = (LPMAPI_ENTRYID) lpEntryID;
  1841. // LPLSTPROVDATA lpProvData = NULL;
  1842. // LPABLOGON lpABLogon = NULL;
  1843. // The basic advise implementation ignores the entryids and only looks
  1844. // for event masks of type OBjectModified. The only notifications fired
  1845. // are for any changes in the WAB store...
  1846. //
  1847. if (! ulEventMask || !(ulEventMask & fnevObjectModified))
  1848. return MAPI_E_INVALID_PARAMETER;
  1849. hr = HrAdvise(lpIAB,
  1850. cbEntryID,
  1851. lpEntryID,
  1852. ulEventMask,
  1853. lpAdvise,
  1854. lpulConnection);
  1855. return(hr);
  1856. }
  1857. //-----------------------------------------------------------------------------
  1858. // Synopsis: IAB_Unadvise()
  1859. // Description:
  1860. //
  1861. // Parameters:
  1862. // Returns:
  1863. // Effects:
  1864. // Notes:
  1865. // Revision:
  1866. //-----------------------------------------------------------------------------
  1867. STDMETHODIMP
  1868. IAB_Unadvise (LPIAB lpIAB, ULONG ulConnection)
  1869. {
  1870. HRESULT hr = hrSuccess;
  1871. SCODE sc = S_OK;
  1872. hr = HrUnadvise(lpIAB, ulConnection);
  1873. return(hr);
  1874. }
  1875. //
  1876. // Interesting table columns
  1877. //
  1878. enum {
  1879. ifePR_CONTACT_EMAIL_ADDRESSES = 0,
  1880. ifePR_EMAIL_ADDRESS,
  1881. ifePR_DISPLAY_NAME,
  1882. ifePR_OBJECT_TYPE,
  1883. ifePR_USER_X509_CERTIFICATE,
  1884. ifePR_ENTRYID,
  1885. ifePR_SEARCH_KEY,
  1886. ifeMax
  1887. };
  1888. static const SizedSPropTagArray(ifeMax, ptaFind) =
  1889. {
  1890. ifeMax,
  1891. {
  1892. PR_CONTACT_EMAIL_ADDRESSES,
  1893. PR_EMAIL_ADDRESS,
  1894. PR_DISPLAY_NAME,
  1895. PR_OBJECT_TYPE,
  1896. PR_USER_X509_CERTIFICATE,
  1897. PR_ENTRYID,
  1898. PR_SEARCH_KEY
  1899. }
  1900. };
  1901. /***************************************************************************
  1902. Name : HrRowToADRENTRY
  1903. Purpose : Gets the next row from a table and places it in the ADRENTRY
  1904. Parameters: lpIAB -> Address book object
  1905. lpTable -> table object
  1906. lpAdrEntry = ADRENTRY to fill
  1907. Returns : HRESULT
  1908. Comment :
  1909. ***************************************************************************/
  1910. HRESULT HrRowToADRENTRY(LPIAB lpIAB, LPMAPITABLE lpTable, LPADRENTRY lpAdrEntry, BOOL bUnicode) {
  1911. HRESULT hResult;
  1912. LPSRowSet lpRow = NULL;
  1913. SCODE sc;
  1914. LPMAPIPROP lpMailUser = NULL;
  1915. LPSPropValue lpPropArray = NULL;
  1916. LPSPropValue lpPropArrayNew = NULL;
  1917. ULONG ulObjType, cValues, cPropsNew;
  1918. if (hResult = lpTable->lpVtbl->QueryRows(lpTable,
  1919. 1, // First row only
  1920. 0, // ulFlags
  1921. &lpRow)) {
  1922. DebugTrace(TEXT("GetNextRowEID:QueryRows -> %x\n"), GetScode(hResult));
  1923. } else {
  1924. // Found it, copy entryid to new allocation
  1925. if (lpRow->cRows) {
  1926. if (HR_FAILED(hResult = lpIAB->lpVtbl->OpenEntry(lpIAB,
  1927. lpRow->aRow[0].lpProps[ifePR_ENTRYID].Value.bin.cb, // cbEntryID
  1928. (LPENTRYID)lpRow->aRow[0].lpProps[ifePR_ENTRYID].Value.bin.lpb, // entryid of first match
  1929. NULL, // interface
  1930. 0, // ulFlags
  1931. &ulObjType, // returned object type
  1932. (LPUNKNOWN *)&lpMailUser))) {
  1933. // Failed! Hmmm.
  1934. DebugTraceResult( TEXT("ResolveNames OpenEntry"), hResult);
  1935. goto exit;
  1936. }
  1937. Assert(lpMailUser);
  1938. if (HR_FAILED(hResult = lpMailUser->lpVtbl->GetProps(lpMailUser,
  1939. (LPSPropTagArray)&ptaResolveDefaults, // lpPropTagArray
  1940. (bUnicode ? MAPI_UNICODE : 0), // ulFlags
  1941. &cValues, // how many properties were there?
  1942. &lpPropArray))) {
  1943. DebugTraceResult( TEXT("ResolveNames GetProps"), hResult);
  1944. goto exit;
  1945. }
  1946. hResult = hrSuccess;
  1947. // Now, construct the new ADRENTRY
  1948. // (Allocate a new one, free the old one.
  1949. Assert(lpPropArray);
  1950. // Merge the new props with the ADRENTRY props
  1951. if (sc = ScMergePropValues(lpAdrEntry->cValues,
  1952. lpAdrEntry->rgPropVals, // source1
  1953. cValues,
  1954. lpPropArray, // source2
  1955. &cPropsNew,
  1956. &lpPropArrayNew)) { // dest
  1957. goto exit;
  1958. }
  1959. // [PaulHi] 2/1/99
  1960. // GetProps now only returns requested property strings in the requested
  1961. // format (UNICODE or ANSI). If the client calls this function without
  1962. // the MAPI_UNICODE flag then ensure all string properties are converted
  1963. // to ANSI.
  1964. //
  1965. // @review 2/1/99 These ScConvertWPropsToA conversions are expensive,
  1966. // since there currently is no "MAPIRealloc" function and the original
  1967. // string memory remains allocated until the props array is deallocated.
  1968. if (!bUnicode)
  1969. {
  1970. if(sc = ScConvertWPropsToA((LPALLOCATEMORE) (&MAPIAllocateMore), lpPropArrayNew, cPropsNew, 0))
  1971. goto exit;
  1972. }
  1973. // Free the original prop value array
  1974. FreeBufferAndNull((LPVOID *) (&(lpAdrEntry->rgPropVals)));
  1975. lpAdrEntry->cValues = cPropsNew;
  1976. lpAdrEntry->rgPropVals = lpPropArrayNew;
  1977. FreeBufferAndNull(&lpPropArray);
  1978. } else {
  1979. hResult = ResultFromScode(MAPI_E_NOT_FOUND);
  1980. }
  1981. }
  1982. exit:
  1983. if (lpMailUser) {
  1984. UlRelease(lpMailUser);
  1985. }
  1986. if (lpRow) {
  1987. FreeProws(lpRow);
  1988. }
  1989. return(hResult);
  1990. }
  1991. /***************************************************************************
  1992. Name : InitPropertyRestriction
  1993. Purpose : Fills in the property restriction structure
  1994. Parameters: lpsres -> SRestriction to fill in
  1995. lpspv -> property value structure for this property restriction
  1996. Returns : none
  1997. Comment :
  1998. ***************************************************************************/
  1999. void InitPropertyRestriction(LPSRestriction lpsres, LPSPropValue lpspv) {
  2000. lpsres->rt = RES_PROPERTY; // Restriction type Property
  2001. lpsres->res.resProperty.relop = RELOP_EQ;
  2002. lpsres->res.resProperty.ulPropTag = lpspv->ulPropTag;
  2003. lpsres->res.resProperty.lpProp = lpspv;
  2004. }
  2005. /***************************************************************************
  2006. Name : HrSmartResolve
  2007. Purpose : Goes to great lengths to single out contacts in the local WAB.
  2008. Parameters: lpIAB = adrbook object
  2009. lpContainer = container to search
  2010. ulFlags = flags passed to ResolveName
  2011. lpAdrList -> [in/out] ADRLIST
  2012. lpFlagList -> flags corresponding to adrlist
  2013. lpAmbiguousTables -> ambiguity dialog information
  2014. Returns : HRESULT
  2015. Comment : Assumes that the container's ResolveNames method has already
  2016. been called and has filled in lpFlagList. This routine goes
  2017. the extra mile to find email addresses and to resolve
  2018. ambiguity.
  2019. When we get here, we can assume that the DisplayName was
  2020. either not found or was ambiguous.
  2021. ***************************************************************************/
  2022. HRESULT HrSmartResolve(LPIAB lpIAB, LPABCONT lpContainer, ULONG ulFlags,
  2023. LPADRLIST lpAdrList, LPFlagList lpFlagList, LPAMBIGUOUS_TABLES lpAmbiguousTables) {
  2024. HRESULT hResult = hrSuccess;
  2025. SCODE sc;
  2026. SRestriction res;
  2027. SRestriction resAnd[5]; // array for AND restrictions
  2028. SPropValue propObjectType, propEmail, propEmails, propDisplayName;
  2029. LPSPropValue lpPropArray = NULL;
  2030. LPSRowSet lpRow = NULL;
  2031. LPSRowSet lpSRowSet = NULL;
  2032. LPMAPITABLE lpTable = NULL;
  2033. LPMAPITABLE lpAmbiguousTable;
  2034. LPTABLEDATA FAR lpTableData = NULL;
  2035. LPADRENTRY lpAdrEntry;
  2036. LPMAPIPROP lpMailUser = NULL;
  2037. LPTSTR lpDisplayName = NULL, lpEmailAddress = NULL;
  2038. ULONG ulObjectType;
  2039. ULONG ulObjType, ulRowCount, i, j, index, cValues;
  2040. ULONG resCount;
  2041. BOOL bUnicode = ulFlags & WAB_RESOLVE_UNICODE;
  2042. Assert(lpAdrList->cEntries == lpFlagList->cFlags);
  2043. //
  2044. // Get the contents table for the PAB container
  2045. //
  2046. if (HR_FAILED(hResult = lpContainer->lpVtbl->GetContentsTable(lpContainer,
  2047. WAB_PROFILE_CONTENTS | WAB_CONTENTTABLE_NODATA | MAPI_UNICODE, // This table is internal to this function hence is in Unicode
  2048. &lpTable))) {
  2049. DebugTrace(TEXT("PAB GetContentsTable -> %x\n"), GetScode(hResult));
  2050. goto exit;
  2051. }
  2052. // Set the column set
  2053. if (HR_FAILED(hResult = lpTable->lpVtbl->SetColumns(lpTable,
  2054. (LPSPropTagArray)&ptaFind, 0))) {
  2055. DebugTrace(TEXT("PAB SetColumns-> %x\n"), GetScode(hResult));
  2056. goto exit;
  2057. }
  2058. // Set up the property values for restrictions
  2059. propObjectType.ulPropTag = PR_OBJECT_TYPE;
  2060. propEmail.ulPropTag = PR_EMAIL_ADDRESS;
  2061. propDisplayName.ulPropTag = PR_DISPLAY_NAME;
  2062. propEmails.ulPropTag = PR_CONTACT_EMAIL_ADDRESSES;
  2063. propEmails.Value.MVSZ.cValues = 1;
  2064. // All of our restrictions are AND restrictions using the resAnd array
  2065. res.rt = RES_AND;
  2066. res.res.resAnd.lpRes = resAnd;
  2067. // res.res.resAnd.cRes = 2; Caller must fill in before calling Restrict
  2068. //
  2069. // Loop through every entry, looking for those that need
  2070. // attention.
  2071. //
  2072. for (i = 0; i < lpFlagList->cFlags; i++)
  2073. {
  2074. lpAdrEntry = &lpAdrList->aEntries[i];
  2075. if (lpFlagList->ulFlag[i] == MAPI_UNRESOLVED ||
  2076. lpFlagList->ulFlag[i] == MAPI_AMBIGUOUS)
  2077. {
  2078. if(!bUnicode) // <note> assumes Unicode Defined
  2079. {
  2080. LocalFreeAndNull(&lpDisplayName);
  2081. LocalFreeAndNull(&lpEmailAddress);
  2082. }
  2083. else
  2084. lpDisplayName = lpEmailAddress = NULL; // init the strings
  2085. ulObjectType = 0; // invalid type
  2086. resCount = 0;
  2087. ulRowCount = 0;
  2088. // walk through the prop list for this entry looking for interesting props
  2089. for (j = 0; j < lpAdrEntry->cValues; j++)
  2090. {
  2091. ULONG ulPropTag = lpAdrEntry->rgPropVals[j].ulPropTag;
  2092. if(!bUnicode && PROP_TYPE(ulPropTag)==PT_STRING8) // <note> assumes Unicode Defined
  2093. ulPropTag = CHANGE_PROP_TYPE(ulPropTag, PT_UNICODE);
  2094. if (ulPropTag == PR_OBJECT_TYPE)
  2095. {
  2096. ulObjectType = lpAdrEntry->rgPropVals[j].Value.l;
  2097. propObjectType.Value.ul = ulObjectType;
  2098. }
  2099. if (ulPropTag == PR_EMAIL_ADDRESS)
  2100. {
  2101. lpEmailAddress =(bUnicode) ?
  2102. lpAdrEntry->rgPropVals[j].Value.lpszW :
  2103. ConvertAtoW(lpAdrEntry->rgPropVals[j].Value.lpszA);
  2104. propEmails.Value.MVSZ.LPPSZ = &lpEmailAddress;
  2105. propEmail.Value.LPSZ = lpEmailAddress;
  2106. }
  2107. if (ulPropTag == PR_DISPLAY_NAME)
  2108. {
  2109. lpDisplayName = (bUnicode) ?
  2110. lpAdrEntry->rgPropVals[j].Value.lpszW :
  2111. ConvertAtoW(lpAdrEntry->rgPropVals[j].Value.lpszA);
  2112. propDisplayName.Value.LPSZ = lpDisplayName;
  2113. }
  2114. }
  2115. // Without email address, we can't improve on the standard resolve
  2116. if (lpEmailAddress)
  2117. {
  2118. // If unresolved, try PR_EMAIL_ADDRESS without displayname
  2119. if (lpFlagList->ulFlag[i] == MAPI_UNRESOLVED )
  2120. {
  2121. resCount = 0;
  2122. InitPropertyRestriction(&(resAnd[resCount++]), &propEmail);
  2123. if (ulObjectType)
  2124. {
  2125. InitPropertyRestriction(&(resAnd[resCount++]), &propObjectType);
  2126. }
  2127. if (ulFlags & WAB_RESOLVE_NEED_CERT)
  2128. {
  2129. resAnd[resCount].rt = RES_EXIST;
  2130. resAnd[resCount++].res.resExist.ulPropTag = PR_USER_X509_CERTIFICATE;
  2131. }
  2132. res.res.resAnd.cRes = resCount;
  2133. if (hResult = lpTable->lpVtbl->Restrict(lpTable, &res, 0))
  2134. {
  2135. goto exit;
  2136. }
  2137. // Did any match?
  2138. if (HR_FAILED(hResult = lpTable->lpVtbl->GetRowCount(lpTable, 0, &ulRowCount)))
  2139. {
  2140. DebugTrace(TEXT("GetRowCount from AB contents table -> %x\n"), GetScode(hResult));
  2141. goto exit;
  2142. }
  2143. switch (ulRowCount)
  2144. {
  2145. default: // too many
  2146. if (! (ulFlags & WAB_RESOLVE_FIRST_MATCH))
  2147. {
  2148. // No point in narrowing the search with PR_DISPLAY_NAME since
  2149. // we know it wasn't found. Also no point in putting in
  2150. // PR_CONTACT_EMAIL_ADDRESSES since that is ambiguous too.
  2151. // Drop out to the ambiguity handler
  2152. goto Ambiguity;
  2153. } // else fall through and take the first one
  2154. case 1: // Found one!
  2155. if (hResult = HrRowToADRENTRY(lpIAB, lpTable, lpAdrEntry, bUnicode))
  2156. {
  2157. goto exit;
  2158. }
  2159. lpFlagList->ulFlag[i] = MAPI_RESOLVED; // Mark this entry as found.
  2160. continue; // next entry
  2161. case 0:
  2162. // No match, try PR_CONTACT_EMAIL_ADDRESSES
  2163. // Create the restriction to find the email address in the multi-valued
  2164. // PR_CONTACT_EMAIL_ADDRESSES. (replace propEmail in the restriction)
  2165. resAnd[0].rt = RES_CONTENT;
  2166. resAnd[0].res.resContent.ulFuzzyLevel = FL_IGNORECASE | FL_FULLSTRING;
  2167. resAnd[0].res.resContent.ulPropTag = PR_CONTACT_EMAIL_ADDRESSES;
  2168. resAnd[0].res.resContent.lpProp = &propEmails;
  2169. if (hResult = lpTable->lpVtbl->Restrict(lpTable, &res, 0)) {
  2170. goto exit;
  2171. }
  2172. // Did any match?
  2173. if (HR_FAILED(hResult = lpTable->lpVtbl->GetRowCount(lpTable, 0, &ulRowCount))) {
  2174. DebugTrace(TEXT("GetRowCount from AB contents table -> %x\n"), GetScode(hResult));
  2175. goto exit;
  2176. }
  2177. switch (ulRowCount) {
  2178. default: // More than one. We'll catch it below.
  2179. // Drop out to the ambiguity handler
  2180. if (! (ulFlags & WAB_RESOLVE_FIRST_MATCH)) {
  2181. // No point in narrowing the search with PR_DISPLAY_NAME since
  2182. // we know it wasn't found.
  2183. // Drop out to the ambiguity handler
  2184. goto Ambiguity;
  2185. } // else fall through and take the first one
  2186. case 1: // Found one!
  2187. if (hResult = HrRowToADRENTRY(lpIAB, lpTable, lpAdrEntry, bUnicode)) {
  2188. goto exit;
  2189. }
  2190. lpFlagList->ulFlag[i] = MAPI_RESOLVED; // Mark this entry as found.
  2191. continue;
  2192. case 0:
  2193. // We're SOL on this one. Ignore it and move on.
  2194. continue;
  2195. }
  2196. break;
  2197. }
  2198. }
  2199. // We should only get here if there was a MAPI_AMBIGUOUS flag
  2200. //
  2201. // Look for PR_DISPLAY_NAME and PR_EMAIL_ADDRESS
  2202. //
  2203. // propEmail goes first so that we can replace it with propEmails later
  2204. InitPropertyRestriction(&(resAnd[resCount++]), &propEmail);
  2205. if (lpDisplayName) {
  2206. // Shouldn't add the display name in if it is the same as the email!
  2207. if (lstrcmpi(lpDisplayName, lpEmailAddress)) {
  2208. InitPropertyRestriction(&(resAnd[resCount++]), &propDisplayName);
  2209. }
  2210. }
  2211. if (ulObjectType) {
  2212. InitPropertyRestriction(&(resAnd[resCount++]), &propObjectType);
  2213. }
  2214. if (ulFlags & WAB_RESOLVE_NEED_CERT) {
  2215. resAnd[resCount].rt = RES_EXIST;
  2216. resAnd[resCount++].res.resExist.ulPropTag = PR_USER_X509_CERTIFICATE;
  2217. }
  2218. res.res.resAnd.cRes = resCount;
  2219. if (hResult = lpTable->lpVtbl->Restrict(lpTable, &res, 0)) {
  2220. goto exit;
  2221. }
  2222. // Did any match?
  2223. if (HR_FAILED(hResult = lpTable->lpVtbl->GetRowCount(lpTable, 0, &ulRowCount))) {
  2224. DebugTrace(TEXT("GetRowCount from AB contents table -> %x\n"), GetScode(hResult));
  2225. goto exit;
  2226. }
  2227. switch (ulRowCount) {
  2228. default: // too many
  2229. if (! (ulFlags & WAB_RESOLVE_FIRST_MATCH)) {
  2230. // No point in narrowing the search with PR_CONTACT_EMAIL_ADDRESSES
  2231. goto Ambiguity;
  2232. } // else fall through and take the first one
  2233. case 1: // Found one!
  2234. if (hResult = HrRowToADRENTRY(lpIAB, lpTable, lpAdrEntry, bUnicode)) {
  2235. goto exit;
  2236. }
  2237. lpFlagList->ulFlag[i] = MAPI_RESOLVED; // Mark this entry as found.
  2238. continue;
  2239. case 0:
  2240. // No match, try PR_DISPLAY_NAME and PR_CONTACT_EMAIL_ADDRESSES
  2241. // Create the restriction to find the email address in the multi-valued
  2242. // PR_CONTACT_EMAIL_ADDRESSES.
  2243. resAnd[0].rt = RES_CONTENT;
  2244. resAnd[0].res.resContent.ulFuzzyLevel = FL_IGNORECASE | FL_FULLSTRING;
  2245. resAnd[0].res.resContent.ulPropTag = PR_CONTACT_EMAIL_ADDRESSES;
  2246. resAnd[0].res.resContent.lpProp = &propEmails;
  2247. if (hResult = lpTable->lpVtbl->Restrict(lpTable, &res, 0)) {
  2248. goto exit;
  2249. }
  2250. // Did any match?
  2251. if (HR_FAILED(hResult = lpTable->lpVtbl->GetRowCount(lpTable, 0, &ulRowCount))) {
  2252. DebugTrace(TEXT("GetRowCount from AB contents table -> %x\n"), GetScode(hResult));
  2253. goto exit;
  2254. }
  2255. switch (ulRowCount) {
  2256. default: // More than one. We'll catch it below.
  2257. if (! (ulFlags & WAB_RESOLVE_FIRST_MATCH)) {
  2258. goto Ambiguity;
  2259. } // else fall through and take the first one
  2260. case 1: // Found one!
  2261. if (hResult = HrRowToADRENTRY(lpIAB, lpTable, lpAdrEntry, bUnicode)) {
  2262. goto exit;
  2263. }
  2264. lpFlagList->ulFlag[i] = MAPI_RESOLVED; // Mark this entry as found.
  2265. continue;
  2266. case 0:
  2267. // We're SOL on this one. Ignore it and move on.
  2268. continue;
  2269. }
  2270. break;
  2271. }
  2272. if (ulRowCount > 1)
  2273. {
  2274. Ambiguity:
  2275. // Ambiguous results still in table. We should do some more processing on
  2276. // this and if necesary, fill in the ambiguity table
  2277. // BUGBUG: Here is where we should add a restrict on the certificate property
  2278. if(lpAmbiguousTables)
  2279. {
  2280. // [PaulHi] 4/5/99 Use the Internal CreateTableData() function that takes
  2281. // the ulFlags and will deal with ANSI/UNICODE requests correctly
  2282. sc = CreateTableData(
  2283. NULL,
  2284. (ALLOCATEBUFFER FAR *) MAPIAllocateBuffer,
  2285. (ALLOCATEMORE FAR *) MAPIAllocateMore,
  2286. MAPIFreeBuffer,
  2287. NULL,
  2288. TBLTYPE_DYNAMIC,
  2289. PR_RECORD_KEY,
  2290. (LPSPropTagArray)&ITableColumns,
  2291. NULL,
  2292. 0,
  2293. NULL,
  2294. ulFlags,
  2295. &lpTableData);
  2296. if ( FAILED(sc) )
  2297. {
  2298. DebugTrace(TEXT("CreateTableData() failed %x\n"), sc);
  2299. hResult = ResultFromScode(sc);
  2300. goto exit;
  2301. }
  2302. if(ulFlags & MAPI_UNICODE)
  2303. ((TAD*)lpTableData)->bMAPIUnicodeTable = bUnicode;
  2304. // Allocate an SRowSet to hold the entries.
  2305. if (FAILED(sc = MAPIAllocateBuffer(sizeof(SRowSet) + ulRowCount* sizeof(SRow),
  2306. (LPVOID *)&lpSRowSet)))
  2307. {
  2308. DebugTrace(TEXT("Allocation of SRowSet failed\n"));
  2309. hResult = ResultFromScode(sc);
  2310. goto exit;
  2311. }
  2312. lpSRowSet->cRows = 0;
  2313. for (index = 0; index < ulRowCount; index++)
  2314. {
  2315. if (hResult = lpTable->lpVtbl->QueryRows(lpTable,1,0,&lpRow))
  2316. {
  2317. DebugTrace(TEXT("GetNextRowEID:QueryRows -> %x\n"), GetScode(hResult));
  2318. break;
  2319. }
  2320. else
  2321. {
  2322. // Found one, copy entryid to new allocation
  2323. if (!lpRow->cRows)
  2324. break;
  2325. if (HR_FAILED(hResult = lpIAB->lpVtbl->OpenEntry(lpIAB,
  2326. lpRow->aRow[0].lpProps[ifePR_ENTRYID].Value.bin.cb, // cbEntryID
  2327. (LPENTRYID)lpRow->aRow[0].lpProps[ifePR_ENTRYID].Value.bin.lpb, // entryid of first match
  2328. NULL, // interface
  2329. 0, // ulFlags
  2330. &ulObjType, // returned object type
  2331. (LPUNKNOWN *)&lpMailUser)))
  2332. {
  2333. DebugTraceResult( TEXT("ResolveNames OpenEntry"), hResult);
  2334. goto exit;
  2335. }
  2336. Assert(lpMailUser);
  2337. FreeProws(lpRow);
  2338. lpRow = NULL;
  2339. // This is stuffed into the SRowSet, so don't free it
  2340. if (HR_FAILED(hResult = lpMailUser->lpVtbl->GetProps(lpMailUser,
  2341. (LPSPropTagArray)&ptaResolveDefaults, // lpPropTagArray
  2342. (bUnicode ? MAPI_UNICODE : 0), // ulFlags
  2343. &cValues, // how many properties were there?
  2344. &lpPropArray)))
  2345. {
  2346. DebugTraceResult( TEXT("ResolveNames GetProps"), hResult);
  2347. goto exit;
  2348. }
  2349. hResult = hrSuccess;
  2350. UlRelease(lpMailUser);
  2351. lpMailUser = NULL;
  2352. // [PaulHi] 2/1/99 GetProps will return UNICODE strings from the
  2353. // ptaResolveDefaults request array. Convert to ANSI if our client
  2354. // is not UNICODE.
  2355. if (!bUnicode)
  2356. {
  2357. // @review [PaulHi] I am fairly certain that this lpPropArray array
  2358. // will ALWAYS be allocated from our local MAPIAllocateMore function
  2359. // and never from ((LPIDAT)lpMailUser->lpPropData)->inst.lpfAllocateMore.
  2360. // Check this.
  2361. if(sc = ScConvertWPropsToA((LPALLOCATEMORE) (&MAPIAllocateMore), lpPropArray, cValues, 0))
  2362. goto exit;
  2363. }
  2364. // Fixup the PR_RECORD_KEY
  2365. // Make certain we have proper indicies.
  2366. // For now, we will equate PR_INSTANCE_KEY and PR_RECORD_KEY to PR_ENTRYID.
  2367. lpPropArray[irdPR_INSTANCE_KEY].ulPropTag = PR_INSTANCE_KEY;
  2368. lpPropArray[irdPR_INSTANCE_KEY].Value.bin.cb =
  2369. lpPropArray[irdPR_ENTRYID].Value.bin.cb;
  2370. lpPropArray[irdPR_INSTANCE_KEY].Value.bin.lpb =
  2371. lpPropArray[irdPR_ENTRYID].Value.bin.lpb;
  2372. lpPropArray[irdPR_RECORD_KEY].ulPropTag = PR_RECORD_KEY;
  2373. lpPropArray[irdPR_RECORD_KEY].Value.bin.cb =
  2374. lpPropArray[irdPR_ENTRYID].Value.bin.cb;
  2375. lpPropArray[irdPR_RECORD_KEY].Value.bin.lpb =
  2376. lpPropArray[irdPR_ENTRYID].Value.bin.lpb;
  2377. // Put it in the RowSet
  2378. lpSRowSet->aRow[index].cValues = cValues; // number of properties
  2379. lpSRowSet->aRow[index].lpProps = lpPropArray; // LPSPropValue
  2380. }
  2381. }
  2382. // Add the rows to the table
  2383. lpSRowSet->cRows = index;
  2384. if (HR_FAILED(hResult = lpTableData->lpVtbl->HrModifyRows(lpTableData,
  2385. 0,lpSRowSet)))
  2386. {
  2387. DebugTrace(TEXT("HrModifyRows for ambiguity table -> %x\n"), GetScode(hResult));
  2388. goto exit;
  2389. }
  2390. hResult = hrSuccess;
  2391. // Clean up the row set
  2392. FreeProws(lpSRowSet);
  2393. lpSRowSet = NULL;
  2394. if (lpTableData)
  2395. {
  2396. if (HR_FAILED(hResult = lpTableData->lpVtbl->HrGetView(lpTableData,
  2397. NULL, // LPSSortOrderSet lpsos,
  2398. ContentsViewGone, // CALLERRELEASE FAR * lpfReleaseCallback,
  2399. 0, // ULONG ulReleaseData,
  2400. &lpAmbiguousTable)))
  2401. {
  2402. DebugTrace(TEXT("HrGetView of Ambiguity table -> %x\n"), ResultFromScode(hResult));
  2403. goto exit;
  2404. }
  2405. }
  2406. // Got a contents table; put it in the
  2407. // ambiguity tables list.
  2408. Assert(i < lpAmbiguousTables->cEntries);
  2409. lpAmbiguousTables->lpTable[i] = lpAmbiguousTable;
  2410. }
  2411. lpFlagList->ulFlag[i] = MAPI_AMBIGUOUS; // Mark this entry as ambiguous
  2412. }
  2413. }
  2414. }
  2415. }
  2416. exit:
  2417. if(!bUnicode) // <note> assumes Unicode Defined
  2418. {
  2419. LocalFreeAndNull(&lpDisplayName);
  2420. LocalFreeAndNull(&lpEmailAddress);
  2421. }
  2422. if (lpSRowSet) {
  2423. // Clean up the row set
  2424. FreeProws(lpSRowSet);
  2425. }
  2426. if (lpRow) {
  2427. FreeProws(lpRow);
  2428. }
  2429. UlRelease(lpMailUser);
  2430. UlRelease(lpTable);
  2431. if (hResult) {
  2432. DebugTrace(TEXT("HrSmartFind coudln't find %s %s <%s>\n"),
  2433. ulObjectType == MAPI_MAILUSER ? TEXT("Mail User") : TEXT("Distribution List"),
  2434. lpDisplayName ? lpDisplayName : TEXT(""),
  2435. lpEmailAddress ? lpEmailAddress : TEXT(""));
  2436. }
  2437. return(hResult);
  2438. }
  2439. /***************************************************************************
  2440. Name : CountFlags
  2441. Purpose : Count the ResolveNames flags in the FlagList.
  2442. Parameters: lpFlagList = flag list to count
  2443. lpulResolved -> return count of MAPI_RESOLVED here
  2444. lpulAmbiguous -> return count of MAPI_AMBIGUOUS here
  2445. lpulUnresolved -> return count of MAPI_UNRESOLVED here
  2446. Returns : none
  2447. Comment :
  2448. ***************************************************************************/
  2449. void CountFlags(LPFlagList lpFlagList, LPULONG lpulResolved,
  2450. LPULONG lpulAmbiguous, LPULONG lpulUnresolved) {
  2451. register ULONG i;
  2452. *lpulResolved = *lpulAmbiguous = *lpulUnresolved = 0;
  2453. for (i = 0; i < lpFlagList->cFlags; i++) {
  2454. switch (lpFlagList->ulFlag[i]) {
  2455. case MAPI_AMBIGUOUS:
  2456. (*lpulAmbiguous)++;
  2457. break;
  2458. case MAPI_RESOLVED:
  2459. (*lpulResolved)++;
  2460. break;
  2461. case MAPI_UNRESOLVED:
  2462. (*lpulUnresolved)++;
  2463. break;
  2464. default:
  2465. Assert(lpFlagList->ulFlag[i]);
  2466. }
  2467. }
  2468. }
  2469. /***************************************************************************
  2470. Name : InitFlagList
  2471. Purpose : Initialize the flags in a FlagList based on values in the
  2472. matching ADRLIST
  2473. Parameters: lpFlagList = flag list to fill in
  2474. lpAdrList = adrlist to search
  2475. Returns : none
  2476. Comment : Initialize the flag to MAPI_RESOLVED if and only if the
  2477. corresponding ADRENTRY has a PR_ENTRYID that is non-NULL.
  2478. ***************************************************************************/
  2479. void InitFlagList(LPFlagList lpFlagList, LPADRLIST lpAdrList) {
  2480. ULONG i, j;
  2481. LPADRENTRY lpAdrEntry;
  2482. Assert(lpAdrList->cEntries == lpFlagList->cFlags);
  2483. for (i = 0; i < lpFlagList->cFlags; i++) {
  2484. lpAdrEntry = &lpAdrList->aEntries[i];
  2485. lpFlagList->ulFlag[i] = MAPI_UNRESOLVED;
  2486. // No props? Then it's automatically resolved.
  2487. if (lpAdrEntry->cValues == 0) {
  2488. lpFlagList->ulFlag[i] = MAPI_RESOLVED;
  2489. }
  2490. // walk through the prop list for this user
  2491. for (j = 0; j < lpAdrEntry->cValues; j++) {
  2492. // Look for PR_ENTRYID which is not NULL
  2493. if (lpAdrEntry->rgPropVals[j].ulPropTag == PR_ENTRYID &&
  2494. lpAdrEntry->rgPropVals[j].Value.bin.cb != 0) {
  2495. // Already has a PR_ENTRYID, it's considered resolved.
  2496. lpFlagList->ulFlag[i] = MAPI_RESOLVED;
  2497. break;
  2498. }
  2499. }
  2500. }
  2501. }
  2502. /***************************************************************************
  2503. Name : UnresolveNoCerts
  2504. Purpose : Unresolve any entry in the ADRLIST which has no cert property
  2505. Parameters: lpIAB -> IAB object
  2506. lpFlagList = flag list to fill in
  2507. lpAdrList = adrlist to search
  2508. Returns : none
  2509. Comment : Initialize the flag to MAPI_RESOLVED if and only if the
  2510. corresponding ADRENTRY has a PR_ENTRYID that is non-NULL.
  2511. ***************************************************************************/
  2512. HRESULT UnresolveNoCerts(LPIAB lpIAB, LPADRLIST lpAdrList, LPFlagList lpFlagList) {
  2513. HRESULT hr = hrSuccess;
  2514. register ULONG i;
  2515. LPADRENTRY lpAdrEntry;
  2516. ULONG ulObjType;
  2517. LPSPropValue lpspvEID, lpspvCERT, lpspvProp = NULL, lpspvNew = NULL;
  2518. ULONG cProps, cPropsNew;
  2519. LPMAILUSER lpMailUser = NULL;
  2520. SizedSPropTagArray(1, ptaCert) =
  2521. { 1, {PR_USER_X509_CERTIFICATE} };
  2522. for (i = 0; i < lpFlagList->cFlags; i++) {
  2523. switch (lpFlagList->ulFlag[i]) {
  2524. case MAPI_RESOLVED:
  2525. // Look in the ADRENTRY for a PR_USER_X509_CERTIFICATE
  2526. lpAdrEntry = &lpAdrList->aEntries[i];
  2527. if (! (lpspvCERT = LpValFindProp(PR_USER_X509_CERTIFICATE,
  2528. lpAdrEntry->cValues, lpAdrEntry->rgPropVals))) {
  2529. // No property in the ADRLIST
  2530. // Does it exist on the underlying object?
  2531. if (! (lpspvEID = LpValFindProp(PR_ENTRYID,
  2532. lpAdrEntry->cValues, lpAdrEntry->rgPropVals))) {
  2533. // Weird!
  2534. Assert(FALSE);
  2535. // No cert prop, unmark it
  2536. lpFlagList->ulFlag[i] = MAPI_UNRESOLVED;
  2537. // Invalidate the entryid prop in the ADRENTRY
  2538. lpspvEID->Value.bin.cb = 0;
  2539. goto LoopContinue;
  2540. }
  2541. if (HR_FAILED(lpIAB->lpVtbl->OpenEntry(lpIAB,
  2542. lpspvEID->Value.bin.cb, // size of EntryID to open
  2543. (LPENTRYID)lpspvEID->Value.bin.lpb, // EntryID to open
  2544. NULL, // interface
  2545. 0, // flags
  2546. &ulObjType,
  2547. (LPUNKNOWN *)&lpMailUser))) {
  2548. // No cert prop, unmark it
  2549. lpFlagList->ulFlag[i] = MAPI_UNRESOLVED;
  2550. // Invalidate the entryid prop in the ADRENTRY
  2551. lpspvEID->Value.bin.cb = 0;
  2552. goto LoopContinue;
  2553. } else {
  2554. if (lpMailUser) {
  2555. if (HR_FAILED(lpMailUser->lpVtbl->GetProps(lpMailUser,
  2556. (LPSPropTagArray)&ptaCert,
  2557. MAPI_UNICODE,
  2558. &cProps,
  2559. &lpspvProp))) {
  2560. // No cert prop, unmark it
  2561. lpFlagList->ulFlag[i] = MAPI_UNRESOLVED;
  2562. // Invalidate the entryid prop in the ADRENTRY
  2563. lpspvEID->Value.bin.cb = 0;
  2564. goto LoopContinue;
  2565. }
  2566. if (PROP_ERROR(lpspvProp[0])) {
  2567. // No cert prop, unmark it
  2568. lpFlagList->ulFlag[i] = MAPI_UNRESOLVED;
  2569. // Invalidate the entryid prop in the ADRENTRY
  2570. lpspvEID->Value.bin.cb = 0;
  2571. goto LoopContinue;
  2572. }
  2573. if (lpspvProp) {
  2574. // BUGBUG: Validate cert against our known e-mail address
  2575. // Parse the MVBin and do cert stuff. Yuck!
  2576. // Blow it off for now, assume they have the right one here.
  2577. // Put this cert in the ADRENTRY
  2578. // Merge the new props with the ADRENTRY props
  2579. if (ScMergePropValues(lpAdrEntry->cValues,
  2580. lpAdrEntry->rgPropVals, // source1
  2581. cProps,
  2582. lpspvProp, // source2
  2583. &cPropsNew,
  2584. &lpspvNew)) { // dest
  2585. // Can't merge cert prop, fail
  2586. lpFlagList->ulFlag[i] = MAPI_UNRESOLVED;
  2587. // Invalidate the entryid prop in the ADRENTRY
  2588. lpspvEID->Value.bin.cb = 0;
  2589. goto LoopContinue;
  2590. }
  2591. // Free old prop array and put new prop array in ADRENTRY
  2592. FreeBufferAndNull((LPVOID *) (&lpAdrEntry->rgPropVals));
  2593. lpAdrEntry->rgPropVals = lpspvNew;
  2594. lpAdrEntry->cValues = cPropsNew;
  2595. }
  2596. }
  2597. }
  2598. LoopContinue:
  2599. FreeBufferAndNull(&lpspvProp);
  2600. if (lpMailUser) {
  2601. lpMailUser->lpVtbl->Release(lpMailUser);
  2602. lpMailUser = NULL;
  2603. }
  2604. }
  2605. break;
  2606. case MAPI_AMBIGUOUS:
  2607. case MAPI_UNRESOLVED:
  2608. break;
  2609. default:
  2610. Assert(lpFlagList->ulFlag[i]);
  2611. }
  2612. }
  2613. return(hr);
  2614. }
  2615. /***************************************************************************
  2616. Name : ResolveLocal
  2617. Purpose : Resolve a name entered by a user against a local container
  2618. Parameters: lpIAB = This IAB object
  2619. cbEID = bytes in EntryID
  2620. lpEID = EntryID of container
  2621. lpAdrList = adrlist to search
  2622. lpFlagList = flag list to fill in
  2623. ulFlags = flags
  2624. lpAmbiguousTables = ambiguity dialog info
  2625. Returns : none
  2626. ***************************************************************************/
  2627. void ResolveLocal(LPIAB lpIAB, ULONG cbEID, LPENTRYID lpEID,
  2628. LPADRLIST lpAdrList, LPFlagList lpFlagList, ULONG ulFlags,
  2629. LPAMBIGUOUS_TABLES lpAmbiguousTables)
  2630. {
  2631. HRESULT hr;
  2632. ULONG ulObjType, ulResolved, ulAmbiguous, ulUnresolved;
  2633. LPABCONT lpABCont = NULL;
  2634. hr = lpIAB->lpVtbl->OpenEntry(lpIAB, cbEID, lpEID, NULL, 0, &ulObjType, (LPUNKNOWN *)&lpABCont);
  2635. if (SUCCEEDED(hr))
  2636. {
  2637. ULONG Flags = 0;
  2638. if(bAreWABAPIProfileAware(lpIAB) &&
  2639. !(ulFlags & WAB_RESOLVE_USE_CURRENT_PROFILE))
  2640. Flags |= WAB_IGNORE_PROFILES;
  2641. if(ulFlags & WAB_RESOLVE_UNICODE)
  2642. Flags |= MAPI_UNICODE;
  2643. // Simple resolve on container - ignore errors
  2644. lpABCont->lpVtbl->ResolveNames( lpABCont, NULL,
  2645. Flags,
  2646. lpAdrList, lpFlagList);
  2647. // Make certain that any entries we found have a certificate property
  2648. // for this email address.
  2649. if (ulFlags & WAB_RESOLVE_NEED_CERT)
  2650. UnresolveNoCerts(lpIAB, lpAdrList, lpFlagList);
  2651. if (ulFlags & WAB_RESOLVE_ALL_EMAILS)
  2652. {
  2653. // If we need more aggressive resolution, use HrSmartResolve
  2654. // This is much slower, so use it judiciously.
  2655. // Count the flags
  2656. CountFlags(lpFlagList, &ulResolved, &ulAmbiguous, &ulUnresolved);
  2657. if (ulAmbiguous || ulUnresolved)
  2658. HrSmartResolve(lpIAB, lpABCont, ulFlags, lpAdrList, lpFlagList,
  2659. lpAmbiguousTables);
  2660. }
  2661. lpABCont->lpVtbl->Release(lpABCont);
  2662. }
  2663. }
  2664. /***************************************************************************
  2665. Name : ResolveCurrentProfile
  2666. Purpose : Resolve a name entered by a user against only the folders that
  2667. are listed in the current profile - this way a user doesnt get
  2668. unexpected name resolution results from what he sees in his
  2669. profile-enabled Outlook Express address book.
  2670. There is an assumption here that this function will only be called
  2671. in the very specific case that OE is running with profiles and the
  2672. user is pressing Ctrl-K to resolve names
  2673. In that case, we will target the contents of the users folders ..
  2674. if something resolves unambiguously good and fine, if something is
  2675. ambiguous we will mark it so, if it doesnt resolve ok ..
  2676. After we've hit the users folders for this resolution, we can then
  2677. call the regular ResolveLocal function to take care of the unmatched
  2678. entries ...
  2679. Parameters: lpIAB = This IAB object
  2680. lpAdrList = adrlist to search
  2681. lpFlagList = flag list to fill in
  2682. Returns : none
  2683. ***************************************************************************/
  2684. HRESULT HrResolveCurrentProfile(LPIAB lpIAB, LPADRLIST lpAdrList, LPFlagList lpFlagList, BOOL bOutlook, BOOL bUnicode)
  2685. {
  2686. LPADRENTRY lpAdrEntry;
  2687. ULONG i, j;
  2688. ULONG ulCount = 1;
  2689. LPSBinary rgsbEntryIDs = NULL;
  2690. HRESULT hResult = hrSuccess;
  2691. LPSPropValue lpPropArrayNew = NULL,lpProps = NULL;
  2692. ULONG ulObjType = 0, cPropsNew = 0,ulcProps = 0;
  2693. SCODE sc = SUCCESS_SUCCESS;
  2694. ULONG ulProfileCount = 0;
  2695. LPSBinary lpsb = NULL;
  2696. ULONG iolkci, colkci;
  2697. OlkContInfo *rgolkci;
  2698. ULONG ulFlags = AB_FUZZY_FIND_ALL;
  2699. EnterCriticalSection(&lpIAB->cs);
  2700. #ifndef DONT_ADDREF_PROPSTORE
  2701. if ((FAILED(sc = OpenAddRefPropertyStore(NULL, lpIAB->lpPropertyStore))))
  2702. {
  2703. hResult = ResultFromScode(sc);
  2704. goto exitNotAddRefed;
  2705. }
  2706. #endif
  2707. if(!bOutlook)
  2708. ulFlags |= AB_FUZZY_FIND_PROFILEFOLDERONLY;
  2709. colkci = bOutlook ? lpIAB->lpPropertyStore->colkci : lpIAB->cwabci;
  2710. Assert(colkci);
  2711. rgolkci = bOutlook ? lpIAB->lpPropertyStore->rgolkci : lpIAB->rgwabci;
  2712. Assert(rgolkci);
  2713. // search for each name in the lpAdrList
  2714. for (i = 0; i < lpAdrList->cEntries; i++)
  2715. {
  2716. // Make sure we don't resolve an entry which is already resolved.
  2717. if (lpFlagList->ulFlag[i] == MAPI_RESOLVED)
  2718. continue;
  2719. ulProfileCount = 0;
  2720. LocalFreeSBinary(lpsb);
  2721. lpsb = NULL;
  2722. lpAdrEntry = &(lpAdrList->aEntries[i]);
  2723. // Search for this address
  2724. for (j = 0; j < lpAdrEntry->cValues; j++)
  2725. {
  2726. ULONG ulPropTag = lpAdrEntry->rgPropVals[j].ulPropTag;
  2727. if(!bUnicode && PROP_TYPE(ulPropTag)==PT_STRING8) //<note> assumes UNICODE defined
  2728. ulPropTag = CHANGE_PROP_TYPE(ulPropTag, PT_UNICODE);
  2729. if (ulPropTag == PR_DISPLAY_NAME || ulPropTag == PR_EMAIL_ADDRESS )
  2730. {
  2731. LPTSTR lpsz = (bUnicode) ?
  2732. lpAdrEntry->rgPropVals[j].Value.lpszW :
  2733. ConvertAtoW(lpAdrEntry->rgPropVals[j].Value.lpszA);
  2734. ulCount = 1; // number of matches to find
  2735. rgsbEntryIDs = NULL;
  2736. iolkci = bOutlook ? 0 : 1; // if it's outlook we DO want to search the first folder
  2737. // if it's WAB, and this is a profile-enabled session and we are only searching
  2738. // through the profile folders, then we shouldn't search through the shared contacts
  2739. // folder which is the first folder on the list ...
  2740. // Only if we find nothing in the user's folders should we look into the shared contact
  2741. // folder ..
  2742. while (iolkci < colkci && ulProfileCount<=1 )
  2743. {
  2744. if(ulCount && rgsbEntryIDs)
  2745. {
  2746. FreeEntryIDs(lpIAB->lpPropertyStore->hPropertyStore, ulCount, rgsbEntryIDs);
  2747. ulCount = 1;
  2748. rgsbEntryIDs = NULL;
  2749. }
  2750. // Search the property store
  2751. Assert(lpIAB->lpPropertyStore->hPropertyStore);
  2752. if (HR_FAILED(hResult = HrFindFuzzyRecordMatches(lpIAB->lpPropertyStore->hPropertyStore,
  2753. rgolkci[iolkci].lpEntryID,
  2754. lpsz,
  2755. ulFlags,
  2756. &ulCount,// IN: number of matches to find, OUT: number found
  2757. &rgsbEntryIDs)))
  2758. {
  2759. DebugTraceResult( TEXT("HrFindFuzzyRecordMatches"), hResult);
  2760. goto exit;
  2761. }
  2762. ulProfileCount += ulCount;
  2763. if(ulProfileCount > 1)
  2764. {
  2765. LocalFreeSBinary(lpsb);
  2766. lpsb = NULL;
  2767. }
  2768. if(ulCount == 1 && ulProfileCount == 1)
  2769. {
  2770. lpsb = LocalAlloc(LMEM_ZEROINIT, sizeof(SBinary));
  2771. if(lpsb)
  2772. {
  2773. lpsb->cb = rgsbEntryIDs[0].cb;
  2774. lpsb->lpb = LocalAlloc(LMEM_ZEROINIT, lpsb->cb);
  2775. if(lpsb->lpb)
  2776. CopyMemory(lpsb->lpb, rgsbEntryIDs[0].lpb, lpsb->cb);
  2777. }
  2778. }
  2779. // next container
  2780. iolkci++;
  2781. } //while loop
  2782. if(ulProfileCount == 0 && !bOutlook)
  2783. {
  2784. if(ulCount && rgsbEntryIDs)
  2785. {
  2786. FreeEntryIDs(lpIAB->lpPropertyStore->hPropertyStore, ulCount, rgsbEntryIDs);
  2787. ulCount = 1;
  2788. rgsbEntryIDs = NULL;
  2789. }
  2790. // Search the property store
  2791. Assert(lpIAB->lpPropertyStore->hPropertyStore);
  2792. if (HR_FAILED(hResult = HrFindFuzzyRecordMatches(lpIAB->lpPropertyStore->hPropertyStore,
  2793. rgolkci[0].lpEntryID,
  2794. lpsz,
  2795. ulFlags,
  2796. &ulCount,// IN: number of matches to find, OUT: number found
  2797. &rgsbEntryIDs)))
  2798. {
  2799. DebugTraceResult( TEXT("HrFindFuzzyRecordMatches"), hResult);
  2800. goto exit;
  2801. }
  2802. ulProfileCount += ulCount;
  2803. if(ulProfileCount > 1)
  2804. {
  2805. LocalFreeSBinary(lpsb);
  2806. lpsb = NULL;
  2807. }
  2808. if(ulCount == 1 && ulProfileCount == 1)
  2809. {
  2810. lpsb = LocalAlloc(LMEM_ZEROINIT, sizeof(SBinary));
  2811. if(lpsb)
  2812. {
  2813. lpsb->cb = rgsbEntryIDs[0].cb;
  2814. lpsb->lpb = LocalAlloc(LMEM_ZEROINIT, lpsb->cb);
  2815. if(lpsb->lpb)
  2816. CopyMemory(lpsb->lpb, rgsbEntryIDs[0].lpb, lpsb->cb);
  2817. }
  2818. }
  2819. } // if ulProfileCount..
  2820. // If after doing all the containers, we have only 1 item that resolved
  2821. if(ulProfileCount > 1)
  2822. {
  2823. // This is ambiguous within this profile so mark it ambiguous
  2824. DebugTrace(TEXT("ResolveNames found more than 1 match in Current Profile... MAPI_AMBIGUOUS\n"));
  2825. lpFlagList->ulFlag[i] = MAPI_AMBIGUOUS;
  2826. }
  2827. else if(ulProfileCount == 1)
  2828. {
  2829. if (!HR_FAILED(HrGetPropArray((LPADRBOOK)lpIAB, (LPSPropTagArray)&ptaResolveDefaults,
  2830. lpsb->cb, (LPENTRYID)lpsb->lpb,
  2831. (bUnicode ? MAPI_UNICODE : 0),
  2832. &ulcProps, &lpProps)))
  2833. {
  2834. // Merge the new props with the ADRENTRY props
  2835. if (sc = ScMergePropValues(lpAdrEntry->cValues,
  2836. lpAdrEntry->rgPropVals,
  2837. ulcProps,
  2838. lpProps,
  2839. &cPropsNew,
  2840. &lpPropArrayNew))
  2841. {
  2842. goto exit;
  2843. }
  2844. // Free the original prop value array
  2845. FreeBufferAndNull((LPVOID*) (&(lpAdrEntry->rgPropVals)));
  2846. lpAdrEntry->cValues = cPropsNew;
  2847. lpAdrEntry->rgPropVals = lpPropArrayNew;
  2848. FreeBufferAndNull(&lpProps);
  2849. // [PaulHi] Raid 66515
  2850. // We need to convert these properties to ANSI since we are now the
  2851. // UNICODE WAB and if our client is !MAPI_UNICODE
  2852. if (!bUnicode)
  2853. {
  2854. if(sc = ScConvertWPropsToA((LPALLOCATEMORE) (&MAPIAllocateMore), lpPropArrayNew, cPropsNew, 0))
  2855. goto exit;
  2856. }
  2857. // Mark this entry as found.
  2858. lpFlagList->ulFlag[i] = MAPI_RESOLVED;
  2859. }
  2860. }
  2861. FreeEntryIDs(lpIAB->lpPropertyStore->hPropertyStore,
  2862. ulCount, rgsbEntryIDs);
  2863. rgsbEntryIDs = NULL;
  2864. break;
  2865. } // if PR_DISPLAY_NAME
  2866. }// for j ...
  2867. } // for i
  2868. exit:
  2869. #ifndef DONT_ADDREF_PROPSTORE
  2870. ReleasePropertyStore(lpIAB->lpPropertyStore);
  2871. exitNotAddRefed:
  2872. #endif
  2873. LeaveCriticalSection(&lpIAB->cs);
  2874. if(lpsb)
  2875. {
  2876. //Bug #101354 - (erici) Free leaked alloc.
  2877. LocalFreeSBinary(lpsb);
  2878. }
  2879. return(hResult);
  2880. }
  2881. /***************************************************************************
  2882. Name : IAB_ResolveName
  2883. Purpose : Resolve a name entered by a user
  2884. Parameters: lpIAB = This IAB object
  2885. ulUIParam = hwnd
  2886. ulFlags may contain MAPI_UNICODE or MAPI_DIALOG
  2887. If this is a profile based session, and we want to do
  2888. profile specific searches, then we must pass in
  2889. WAB_RESOLVE_USE_CURRENT_PROFILE. Failure to pass this in
  2890. will imply that the user wants to search the whole WAB.
  2891. lpszNewEntryTitle = title for ResolveName dialog
  2892. lpAdrList = ADRLIST input/output
  2893. Returns : HRESULT
  2894. Comment : For now, the search path is hard coded to be:
  2895. + reply one-offs
  2896. + WAB's default container
  2897. + SMTP one-offs
  2898. + LDAP containers
  2899. ***************************************************************************/
  2900. STDMETHODIMP
  2901. IAB_ResolveName(LPIAB lpIAB,
  2902. ULONG_PTR ulUIParam,
  2903. ULONG ulFlags,
  2904. LPTSTR lpszNewEntryTitle,
  2905. LPADRLIST lpAdrList)
  2906. {
  2907. HRESULT hr = hrSuccess;
  2908. SCODE sc = S_OK;
  2909. LPFlagList lpFlagList = NULL;
  2910. LPAMBIGUOUS_TABLES lpAmbiguousTables = NULL;
  2911. ULONG ulUnresolved = 0;
  2912. ULONG ulResolved = 0;
  2913. ULONG ulAmbiguous = 0;
  2914. ULONG cbWABEID;
  2915. LPENTRYID lpWABEID = NULL;
  2916. ULONG ulObjType;
  2917. LPABCONT lpWABCont = NULL;
  2918. ULONG i;
  2919. LPPTGDATA lpPTGData = GetThreadStoragePointer();
  2920. #ifndef DONT_ADDREF_PROPSTORE
  2921. if ((FAILED(sc = OpenAddRefPropertyStore(NULL, lpIAB->lpPropertyStore)))) {
  2922. hr = ResultFromScode(sc);
  2923. goto exitNotAddRefed;
  2924. }
  2925. #endif
  2926. #ifdef PARAMETER_VALIDATION
  2927. // Make sure it's an IAB
  2928. //
  2929. if (BAD_STANDARD_OBJ(lpIAB, IAB_, ResolveName, lpVtbl)) {
  2930. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  2931. }
  2932. if (ulUIParam && !IsWindow((HWND)ulUIParam)) {
  2933. DebugTraceArg(IAB_ResolveName, TEXT("Invalid window handle\n"));
  2934. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  2935. }
  2936. // BUGBUG: What's this 512 and where does it come from?
  2937. if (lpszNewEntryTitle && IsBadStringPtr(lpszNewEntryTitle, 512)) {
  2938. DebugTraceArg(IAB_ResolveName, TEXT("lpszNewEntryTitle fails address check"));
  2939. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  2940. }
  2941. if (lpAdrList && FBadAdrList(lpAdrList)) {
  2942. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  2943. }
  2944. // Due to a flag mixup, WAB_RESOLVE_LOCAL_ONLY equals MAPI_UNICODE, therefore IAB_Resolve is the
  2945. // only function that does not take the MAPI_UNICODE flag but instead needs the special
  2946. // WAB_RESOLVE_UNICODE flag
  2947. //
  2948. //if (ulFlags & WAB_RESOLVE_UNICODE) {
  2949. // DebugTraceArg(IAB_ResolveName, TEXT("Invalid character width"));
  2950. // return(ResultFromScode(MAPI_E_BAD_CHARWIDTH));
  2951. //}
  2952. #endif // PARAMETER_VALIDATION
  2953. // Validate flags
  2954. if (ulFlags & ~(WAB_RESOLVE_UNICODE | MAPI_DIALOG | WAB_RESOLVE_LOCAL_ONLY |
  2955. WAB_RESOLVE_ALL_EMAILS | WAB_RESOLVE_NO_ONE_OFFS | WAB_RESOLVE_NEED_CERT |
  2956. WAB_RESOLVE_NO_NOT_FOUND_UI | WAB_RESOLVE_USE_CURRENT_PROFILE | WAB_RESOLVE_FIRST_MATCH)) {
  2957. // Unknown flags
  2958. DebugTraceArg(IAB_ResolveName, TEXT("Unknown flags"));
  2959. // return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
  2960. }
  2961. if ( (ulFlags & WAB_RESOLVE_NEED_CERT) && !(ulFlags & WAB_RESOLVE_NO_ONE_OFFS) ) {
  2962. DebugTrace(TEXT("ResolveName got WAB_RESOLVE_NEED_CERT without WAB_RESOLVE_NO_ONE_OFFS\n"));
  2963. // Assert(FALSE);
  2964. return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
  2965. }
  2966. /*
  2967. if ((ulFlags & WAB_RESOLVE_USE_CURRENT_PROFILE) && (ulFlags & WAB_RESOLVE_ALL_EMAILS)) {
  2968. DebugTrace(TEXT("ResolveName can't handle both WAB_RESOLVE_USE_CURRENT_PROFILE and WAB_RESOLVE_ALL_EMAILS\n"));
  2969. Assert(FALSE);
  2970. return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
  2971. }
  2972. */
  2973. // A NULL address list is already resolved.
  2974. if (! lpAdrList) {
  2975. goto exit;
  2976. }
  2977. VerifyWABOpenExSession(lpIAB);
  2978. if (ulFlags & MAPI_DIALOG && ulUIParam) {
  2979. pt_hWndFind = (HWND) ulUIParam;
  2980. }
  2981. //
  2982. // Allocate the lpFlagList first and zero fill it.
  2983. if (sc = MAPIAllocateBuffer((UINT) CbNewSPropTagArray(lpAdrList->cEntries),
  2984. &lpFlagList)) {
  2985. hr = ResultFromScode(sc);
  2986. goto exit;
  2987. }
  2988. MAPISetBufferName(lpFlagList, TEXT("WAB: lpFlagList in IAB_ResolveName"));
  2989. lpFlagList->cFlags = lpAdrList->cEntries;
  2990. InitFlagList(lpFlagList, lpAdrList);
  2991. // Count the flags
  2992. CountFlags(lpFlagList, &ulResolved, &ulAmbiguous, &ulUnresolved);
  2993. // Allocate the Ambiguous Table list and zero fill it.
  2994. if (sc = MAPIAllocateBuffer(sizeof(AMBIGUOUS_TABLES) + lpAdrList->cEntries * sizeof(LPMAPITABLE),
  2995. (LPVOID*)&lpAmbiguousTables)) {
  2996. hr = ResultFromScode(sc);
  2997. goto exit;
  2998. }
  2999. MAPISetBufferName(lpAmbiguousTables, TEXT("IAB_ResolveNames:AmbiguousTables"));
  3000. lpAmbiguousTables->cEntries = lpAdrList->cEntries;
  3001. for (i = 0; i < lpAmbiguousTables->cEntries; i++) {
  3002. lpAmbiguousTables->lpTable[i] = NULL;
  3003. }
  3004. if (! (ulFlags & WAB_RESOLVE_NO_ONE_OFFS) && (ulAmbiguous || ulUnresolved)) {
  3005. // Resolve any PR_DISPLAY_NAME:PR_EMAIL_ADDRESS pairs to one-offs.
  3006. HrResolveOneOffs(lpIAB, lpAdrList, lpFlagList,
  3007. (ulFlags & WAB_RESOLVE_UNICODE)?MAPI_UNICODE:0,
  3008. RECEIVED_EMAIL_ADDRESS);
  3009. CountFlags(lpFlagList, &ulResolved, &ulAmbiguous, &ulUnresolved);
  3010. }
  3011. if( bAreWABAPIProfileAware(lpIAB) && bIsThereACurrentUser(lpIAB) &&
  3012. ulFlags&WAB_RESOLVE_USE_CURRENT_PROFILE && (ulAmbiguous || ulUnresolved))
  3013. {
  3014. HrResolveCurrentProfile(lpIAB, lpAdrList, lpFlagList, FALSE, (ulFlags & WAB_RESOLVE_UNICODE));
  3015. CountFlags(lpFlagList, &ulResolved, &ulAmbiguous, &ulUnresolved);
  3016. }
  3017. // Do the default WAB container
  3018. if ((ulAmbiguous || ulUnresolved) &&
  3019. !(ulFlags & WAB_RESOLVE_USE_CURRENT_PROFILE))
  3020. {
  3021. if (! (hr = lpIAB->lpVtbl->GetPAB(lpIAB,&cbWABEID,&lpWABEID)))
  3022. {
  3023. ResolveLocal(lpIAB, cbWABEID, lpWABEID, lpAdrList, lpFlagList, ulFlags, lpAmbiguousTables);
  3024. CountFlags(lpFlagList, &ulResolved, &ulAmbiguous, &ulUnresolved);
  3025. FreeBufferAndNull(&lpWABEID);
  3026. }
  3027. }
  3028. // Do the additional containers
  3029. if (pt_bIsWABOpenExSession)
  3030. {
  3031. HrResolveCurrentProfile(lpIAB, lpAdrList, lpFlagList, TRUE, (ulFlags & WAB_RESOLVE_UNICODE));
  3032. CountFlags(lpFlagList, &ulResolved, &ulAmbiguous, &ulUnresolved);
  3033. }
  3034. if (! (ulFlags & WAB_RESOLVE_NO_ONE_OFFS)) {
  3035. if (ulUnresolved) {
  3036. //
  3037. // Take care of any Internet one-off's
  3038. //
  3039. if (ulUnresolved) {
  3040. hr = HrResolveOneOffs(lpIAB, lpAdrList, lpFlagList,
  3041. (ulFlags & WAB_RESOLVE_UNICODE)?MAPI_UNICODE:0,
  3042. ENTERED_EMAIL_ADDRESS);
  3043. }
  3044. // Count the flags
  3045. CountFlags(lpFlagList, &ulResolved, &ulAmbiguous, &ulUnresolved);
  3046. }
  3047. if (ulAmbiguous)
  3048. {
  3049. // Resolve any valid e-mail addresses that are ambiguous
  3050. hr = HrResolveOneOffs(lpIAB, lpAdrList, lpFlagList,
  3051. (ulFlags & WAB_RESOLVE_UNICODE)?MAPI_UNICODE:0,
  3052. AMBIGUOUS_EMAIL_ADDRESS);
  3053. // Count the flags
  3054. CountFlags(lpFlagList, &ulResolved, &ulAmbiguous, &ulUnresolved);
  3055. }
  3056. }
  3057. //
  3058. // Search any LDAP containers
  3059. //
  3060. if (! (ulFlags & WAB_RESOLVE_LOCAL_ONLY) && ulUnresolved)
  3061. {
  3062. if (! (hr = LDAPResolveName((LPADRBOOK)lpIAB, lpAdrList, lpFlagList, lpAmbiguousTables, ulFlags)))
  3063. {
  3064. if (ulFlags & WAB_RESOLVE_NEED_CERT)
  3065. {
  3066. // Make certain that any entries we found have a certificate property
  3067. // for this email address.
  3068. UnresolveNoCerts(lpIAB, lpAdrList, lpFlagList);
  3069. }
  3070. // Count the flags
  3071. CountFlags(lpFlagList, &ulResolved, &ulAmbiguous, &ulUnresolved);
  3072. }
  3073. }
  3074. // If caller just wants the first match, pull them out of the ambiguity tables
  3075. if (ulFlags & WAB_RESOLVE_FIRST_MATCH && ulAmbiguous)
  3076. {
  3077. Assert(lpAdrList->cEntries == lpAmbiguousTables->cEntries);
  3078. for (i = 0; i < lpAmbiguousTables->cEntries; i++)
  3079. {
  3080. if (lpAmbiguousTables->lpTable[i])
  3081. {
  3082. LPADRENTRY lpAdrEntry = &lpAdrList->aEntries[i];
  3083. // Get the first row from this table and return it.
  3084. if (SUCCEEDED(HrRowToADRENTRY(lpIAB, lpAmbiguousTables->lpTable[i], lpAdrEntry, (ulFlags & WAB_RESOLVE_UNICODE))))
  3085. {
  3086. lpFlagList->ulFlag[i] = MAPI_RESOLVED; // Mark this entry as found.
  3087. UlRelease(lpAmbiguousTables->lpTable[i]);
  3088. lpAmbiguousTables->lpTable[i] = NULL;
  3089. }
  3090. }
  3091. }
  3092. // Count the flags
  3093. CountFlags(lpFlagList, &ulResolved, &ulAmbiguous, &ulUnresolved);
  3094. }
  3095. // Do UI if needed
  3096. if ((ulFlags & MAPI_DIALOG) && (ulAmbiguous || ulUnresolved))
  3097. {
  3098. #ifdef OLD_STUFF
  3099. // Dump the ambiguous tables
  3100. for (i = 0; i < lpAmbiguousTables->cEntries; i++) {
  3101. if (lpAmbiguousTables->lpTable[i]) {
  3102. DebugMapiTable(lpAmbiguousTables->lpTable[i]);
  3103. }
  3104. }
  3105. #endif // OLD_STUFF
  3106. // Do the UI here.
  3107. hr = HrShowResolveUI((LPADRBOOK)lpIAB, (HWND) ulUIParam,
  3108. lpIAB->lpPropertyStore->hPropertyStore,
  3109. ulFlags,
  3110. &lpAdrList, &lpFlagList, lpAmbiguousTables);
  3111. if (ulFlags & WAB_RESOLVE_NEED_CERT)
  3112. {
  3113. // Make certain that any entries we found have a certificate property
  3114. // for this email address.
  3115. UnresolveNoCerts(lpIAB, lpAdrList, lpFlagList);
  3116. }
  3117. // Count the flags
  3118. CountFlags(lpFlagList, &ulResolved, &ulAmbiguous, &ulUnresolved);
  3119. }
  3120. if (! hr)
  3121. {
  3122. if (ulAmbiguous)
  3123. hr = ResultFromScode(MAPI_E_AMBIGUOUS_RECIP);
  3124. else if (ulUnresolved)
  3125. hr = ResultFromScode(MAPI_E_NOT_FOUND);
  3126. }
  3127. exit:
  3128. #ifndef DONT_ADDREF_PROPSTORE
  3129. ReleasePropertyStore(lpIAB->lpPropertyStore);
  3130. exitNotAddRefed:
  3131. #endif
  3132. if (lpAmbiguousTables) {
  3133. for (i = 0; i < lpAmbiguousTables->cEntries; i++) {
  3134. UlRelease(lpAmbiguousTables->lpTable[i]);
  3135. }
  3136. FreeBufferAndNull(&lpAmbiguousTables);
  3137. }
  3138. FreeBufferAndNull(&lpFlagList);
  3139. if(ulFlags&MAPI_DIALOG && ulUIParam)
  3140. {
  3141. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  3142. pt_hWndFind = NULL;
  3143. }
  3144. return(hr);
  3145. }
  3146. /***************************************************************************
  3147. Name : IsDomainName
  3148. Purpose : Is this domain correctly formatted for an Internet address?
  3149. Parameters: lpDomain -> Domain name to check
  3150. fEnclosure = TRUE if the address started with '<'.
  3151. fTrimEnclosure = TRUE if we should truncate the address to
  3152. remove the '>'.
  3153. Returns : TRUE if the domain is a correct format for an Internet
  3154. address.
  3155. Comment : Valid domain names have this form:
  3156. bar[.bar]*
  3157. where bar must have non-empty contents
  3158. no high bits are allowed on any characters
  3159. no '@' allowed
  3160. the '>' character ends the address if there was a '<'
  3161. character at the start of the address.
  3162. ***************************************************************************/
  3163. BOOL IsDomainName(LPTSTR lpDomain, BOOL fEnclosure, BOOL fTrimEnclosure) {
  3164. if (lpDomain) {
  3165. if (*lpDomain == '\0' || *lpDomain == '.' || (fEnclosure && *lpDomain == '>')) {
  3166. // domain name must have contents and can't start with '.'
  3167. return(FALSE);
  3168. }
  3169. while (*lpDomain && (! fEnclosure || *lpDomain != '>')) {
  3170. // Internet addresses only allow pure ASCII. No high bits!
  3171. // No more '@' or '<' characters allowed.
  3172. if (*lpDomain >= 0x0080 || *lpDomain == '@' || *lpDomain == '<') {
  3173. return(FALSE);
  3174. }
  3175. if (*lpDomain == '.') {
  3176. // Recursively check this part of the domain name
  3177. return(IsDomainName(CharNext(lpDomain), fEnclosure, fTrimEnclosure));
  3178. }
  3179. lpDomain = CharNext(lpDomain);
  3180. }
  3181. if (fEnclosure) {
  3182. if (*lpDomain != '>') {
  3183. return(FALSE);
  3184. }
  3185. // Must be the last thing done before returning TRUE!
  3186. if (fTrimEnclosure && *lpDomain == '>') {
  3187. *lpDomain = '\0';
  3188. }
  3189. }
  3190. return(TRUE);
  3191. }
  3192. return(FALSE);
  3193. }
  3194. /***************************************************************************
  3195. Name : IsInternetAddress
  3196. Purpose : Is this address correctly formatted for an Internet address?
  3197. Parameters: lpAddress -> Address to check
  3198. lppEmail -> Returned email address (May be NULL input if
  3199. email should not be parsed.)
  3200. Returns : TRUE if the address is a correct format for an Internet
  3201. address.
  3202. Comment : Valid addresses have this form:
  3203. [display name <]foo@bar[.bar]*[>]
  3204. where foo and bar must have non-empty contents
  3205. and if there is a display name, there must be angle
  3206. brackets surrounding the email address.
  3207. ***************************************************************************/
  3208. BOOL IsInternetAddress(LPTSTR lpAddress, LPTSTR * lppEmail) {
  3209. if (lpAddress) {
  3210. BOOL fEnclosure = FALSE;
  3211. LPTSTR lpDisplay = lpAddress;
  3212. LPTSTR lpTemp = lpAddress;
  3213. LPTSTR lpBracket = NULL;
  3214. // Get past any DisplayName stuff
  3215. for(lpTemp = lpAddress; *lpTemp && *lpTemp != '<'; lpTemp = CharNext(lpTemp)); // Looking for NULL or '<'
  3216. if (*lpTemp) {
  3217. Assert(*lpTemp == '<');
  3218. // Found an enclosure.
  3219. // if we are returning the email, plop down a NULL at the end of the display name
  3220. lpBracket = lpTemp;
  3221. // Get past the '<' to the SMTP email address
  3222. lpTemp++;
  3223. fEnclosure = TRUE;
  3224. lpAddress = lpTemp;
  3225. } else {
  3226. lpTemp = lpAddress;
  3227. }
  3228. // Can't start with '@'
  3229. if (*lpTemp == '@') {
  3230. return(FALSE);
  3231. }
  3232. // Step through the address looking for '@'. If there's an at sign in the middle
  3233. // of a string, this is close enough to being an internet address for me.
  3234. while (*lpTemp) {
  3235. // Internet addresses only allow pure ASCII. No high bits!
  3236. WCHAR wc = *lpTemp;
  3237. if(wc > 0x007f)
  3238. return FALSE;
  3239. //if (*lpTemp & 0x80)
  3240. //{
  3241. // return(FALSE);
  3242. //}
  3243. if (*lpTemp == '@') {
  3244. // Found the at sign. Is there anything following?
  3245. // (Must NOT be another '@')
  3246. if (IsDomainName(CharNext(lpTemp), fEnclosure, !!lppEmail)) {
  3247. if (lppEmail) { // Want to parse into Display & Email
  3248. if (lpBracket) { // Seperate Display & Email
  3249. *lpBracket = '\0';
  3250. // Trim the trailing spaces from the display name
  3251. TrimSpaces(lpDisplay);
  3252. }
  3253. *lppEmail = lpAddress;
  3254. }
  3255. return(TRUE);
  3256. } else {
  3257. return(FALSE);
  3258. }
  3259. }
  3260. lpTemp = CharNext(lpTemp);
  3261. }
  3262. }
  3263. return(FALSE);
  3264. }
  3265. /***************************************************************************
  3266. Name : ScNewOOEID
  3267. Purpose : AllocateMore a One-Off EntryID
  3268. Parameters: lpsbin -> returned SBinary EntryID
  3269. lpRoot = buffer to allocateMore onto
  3270. szDisplayName = display name
  3271. szAddress = email address (may be == szDisplayName)
  3272. szAddrType = addrtype
  3273. bIsUnicode -> TRUE if caller expects Unicode MAPI EID strings
  3274. Returns : SCODE
  3275. Comment :
  3276. ***************************************************************************/
  3277. SCODE ScNewOOEID(
  3278. LPSBinary lpsbin,
  3279. LPVOID lpRoot,
  3280. LPTSTR szDisplayName,
  3281. LPTSTR szAddress,
  3282. LPTSTR szAddrType,
  3283. BOOL bIsUnicode)
  3284. {
  3285. return(GetScode(CreateWABEntryIDEx(bIsUnicode, WAB_ONEOFF, (LPVOID) szDisplayName, (LPVOID) szAddrType, (LPVOID) szAddress, 0, 0,
  3286. (LPVOID) lpRoot, (LPULONG) (&lpsbin->cb), (LPENTRYID *)&lpsbin->lpb)));
  3287. }
  3288. /***************************************************************************
  3289. Name : HrResolveOneOffs
  3290. Purpose : Resolves any Internet addresses in the ADRLIST.
  3291. Parameters: lpIAB -> IAddrBook object
  3292. lpAdrList -> input/output ADRLIST as with Resolvenames
  3293. lpFlagList -> flag list as with ResolveNames
  3294. ResolveType = type of one-off resolve to do
  3295. ulFlags - 0 or MAPI_UNICODE (if 0 means all strings in AdrList are ANSI/DBCS)
  3296. Returns : HRESULT
  3297. Comment :
  3298. ***************************************************************************/
  3299. enum {
  3300. ioopPR_DISPLAY_NAME = 0,
  3301. ioopPR_EMAIL_ADDRESS,
  3302. ioopPR_ADDRTYPE,
  3303. ioopPR_ENTRYID,
  3304. ioopPR_OBJECT_TYPE,
  3305. ioopMAX
  3306. };
  3307. const TCHAR szSMTP[] = TEXT("SMTP");
  3308. #define CB_SMTP sizeof(szSMTP)
  3309. HRESULT HrResolveOneOffs(LPIAB lpIAB, LPADRLIST lpAdrList, LPFlagList lpFlagList,
  3310. ULONG ulFlags,
  3311. RESOLVE_TYPE ResolveType)
  3312. {
  3313. HRESULT hResult = hrSuccess;
  3314. SCODE sc = SUCCESS_SUCCESS;
  3315. ULONG i, j, k;
  3316. LPADRENTRY lpAdrEntry = NULL;
  3317. LPSPropValue lpPropArrayTemp = NULL, lpPropArrayNew = NULL;
  3318. LPTSTR lpszDisplayName = NULL, lpszEmailAddress = NULL;
  3319. ULONG cbTemp, cbEmailAddress, cPropsNew;
  3320. LPBYTE lpb;
  3321. BOOL fNotDone;
  3322. // Walk through the flag list, looking for unresolved entries:
  3323. for (i = 0; i < lpFlagList->cFlags; i++)
  3324. {
  3325. BOOL bAmbiguous = FALSE;
  3326. if(ResolveType == AMBIGUOUS_EMAIL_ADDRESS && lpFlagList->ulFlag[i] == MAPI_AMBIGUOUS)
  3327. {
  3328. // Fake the routine into thinking this is an unresolved internet address
  3329. bAmbiguous = TRUE;
  3330. lpFlagList->ulFlag[i] = MAPI_UNRESOLVED;
  3331. }
  3332. if (lpFlagList->ulFlag[i] == MAPI_UNRESOLVED)
  3333. {
  3334. // Found an unresolved entry. Look at the PR_DISPLAY_NAME
  3335. // and, if RECEIVED_EMAIL_ADDRESS, PR_EMAIL_ADDRESS.
  3336. lpAdrEntry = &(lpAdrList->aEntries[i]);
  3337. if(ulFlags & MAPI_UNICODE)
  3338. {
  3339. lpszDisplayName = NULL;
  3340. lpszEmailAddress = NULL;
  3341. }
  3342. else
  3343. {
  3344. // [PaulHi] 12/17/98 Raid #62242
  3345. // Don't deallocate twice if the two pointers are equal.
  3346. if (lpszEmailAddress != lpszDisplayName)
  3347. LocalFreeAndNull(&lpszEmailAddress);
  3348. LocalFreeAndNull(&lpszDisplayName);
  3349. lpszEmailAddress = NULL;
  3350. }
  3351. fNotDone = TRUE;
  3352. for (j = 0; j < lpAdrEntry->cValues && fNotDone; j++)
  3353. {
  3354. ULONG ulPropTag = lpAdrEntry->rgPropVals[j].ulPropTag;
  3355. if(!(ulFlags & MAPI_UNICODE) && PROP_TYPE(ulPropTag)==PT_STRING8)
  3356. ulPropTag = CHANGE_PROP_TYPE(ulPropTag, PT_UNICODE);
  3357. switch (ulPropTag)
  3358. {
  3359. case PR_DISPLAY_NAME:
  3360. lpszDisplayName = (ulFlags & MAPI_UNICODE) ?
  3361. lpAdrEntry->rgPropVals[j].Value.lpszW :
  3362. ConvertAtoW(lpAdrEntry->rgPropVals[j].Value.lpszA);
  3363. switch (ResolveType)
  3364. {
  3365. case AMBIGUOUS_EMAIL_ADDRESS:
  3366. case ENTERED_EMAIL_ADDRESS:
  3367. // Just look at the display name
  3368. // we'll check it's validity as an email address.
  3369. break;
  3370. case RECEIVED_EMAIL_ADDRESS:
  3371. // If we are in RECEIVED_EMAIL_ADDRESS mode, find the email address.
  3372. // if it isn't there, this address doesn't resolve.
  3373. //
  3374. if (! lpszEmailAddress)
  3375. {
  3376. // Haven't seen it yet, go hunt for it.
  3377. for (k = j + 1; k < lpAdrEntry->cValues; k++)
  3378. {
  3379. ULONG ulPropTag = lpAdrEntry->rgPropVals[k].ulPropTag;
  3380. if(!(ulFlags & MAPI_UNICODE) && PROP_TYPE(ulPropTag)==PT_STRING8)
  3381. ulPropTag = CHANGE_PROP_TYPE(ulPropTag, PT_UNICODE);
  3382. if (ulPropTag == PR_EMAIL_ADDRESS)
  3383. {
  3384. lpszEmailAddress = (ulFlags & MAPI_UNICODE) ?
  3385. lpAdrEntry->rgPropVals[k].Value.lpszW :
  3386. ConvertAtoW(lpAdrEntry->rgPropVals[k].Value.lpszA);
  3387. break; // out of for loop
  3388. }
  3389. }
  3390. if (! lpszEmailAddress)
  3391. {
  3392. // No email address, can't resolve in
  3393. // RECEIVED_EMAIL_ADDRESS mode.
  3394. fNotDone = FALSE; // exit this ADRENTRY
  3395. continue; // break binds to switch, not for.
  3396. }
  3397. }
  3398. break; // found email addr and display name. It's a one-off.
  3399. default:
  3400. Assert(FALSE);
  3401. }
  3402. // At this point, we have two pointers: lpszDisplayName and maybe lpszEmailAddress.
  3403. // Is it an Internet address or a RECEIVED_EMAIL_ADDRESS?
  3404. if ((ResolveType == RECEIVED_EMAIL_ADDRESS && lpszEmailAddress
  3405. && lpszDisplayName)
  3406. || IsInternetAddress(lpszDisplayName, &lpszEmailAddress))
  3407. {
  3408. if (lpszEmailAddress)
  3409. {
  3410. // We can resolve this.
  3411. cbEmailAddress = sizeof(TCHAR)*(lstrlen(lpszEmailAddress) + 1);
  3412. // Allocate a temporary prop array for our new properties
  3413. cbTemp = ioopMAX * sizeof(SPropValue) + cbEmailAddress + CB_SMTP;
  3414. if (sc = MAPIAllocateBuffer(cbTemp, &lpPropArrayTemp))
  3415. {
  3416. goto exit;
  3417. }
  3418. MAPISetBufferName(lpPropArrayTemp, TEXT("WAB: lpPropArrayTemp in HrResolveOneOffs"));
  3419. lpb = (LPBYTE)&lpPropArrayTemp[ioopMAX]; // point past array
  3420. if(!lstrlen(lpszDisplayName))
  3421. lpszDisplayName = lpszEmailAddress;
  3422. else if(*lpszDisplayName == '"')
  3423. {
  3424. // strip out the leading quote if it's the only one ..
  3425. LPTSTR lp = lpszDisplayName;
  3426. int nQuoteCount = 0;
  3427. while(lp && *lp)
  3428. {
  3429. if(*lp == '"')
  3430. nQuoteCount++;
  3431. lp = CharNext(lp);
  3432. }
  3433. if(nQuoteCount == 1)
  3434. StrCpyN(lpszDisplayName, lpszDisplayName+1, lstrlen(lpszDisplayName)+1);
  3435. }
  3436. {
  3437. LPTSTR lp = NULL;
  3438. DWORD cchSize = (lstrlen(lpszDisplayName)+1);
  3439. if(sc = MAPIAllocateMore(sizeof(TCHAR)*cchSize, lpPropArrayTemp, &lp))
  3440. goto exit;
  3441. StrCpyN(lp, lpszDisplayName, cchSize);
  3442. lpPropArrayTemp[ioopPR_DISPLAY_NAME].ulPropTag = PR_DISPLAY_NAME;
  3443. lpPropArrayTemp[ioopPR_DISPLAY_NAME].Value.LPSZ = lp;
  3444. }
  3445. // Fill in our temp prop array
  3446. lpPropArrayTemp[ioopPR_EMAIL_ADDRESS].ulPropTag = PR_EMAIL_ADDRESS;
  3447. lpPropArrayTemp[ioopPR_EMAIL_ADDRESS].Value.LPSZ = (LPTSTR)lpb;
  3448. StrCpyN((LPTSTR)lpb, lpszEmailAddress, cbEmailAddress/sizeof(TCHAR));
  3449. lpb += cbEmailAddress;
  3450. lpPropArrayTemp[ioopPR_ADDRTYPE].ulPropTag = PR_ADDRTYPE;
  3451. lpPropArrayTemp[ioopPR_ADDRTYPE].Value.LPSZ = (LPTSTR)lpb;
  3452. StrCpyN((LPTSTR)lpb, szSMTP, CB_SMTP / sizeof(TCHAR));
  3453. lpb += CB_SMTP;
  3454. lpPropArrayTemp[ioopPR_ENTRYID].ulPropTag = PR_ENTRYID;
  3455. if (sc = ScNewOOEID(&lpPropArrayTemp[ioopPR_ENTRYID].Value.bin,
  3456. lpPropArrayTemp, // allocate more on here
  3457. lpszDisplayName,
  3458. lpszEmailAddress,
  3459. (LPTSTR)szSMTP,
  3460. (ulFlags & MAPI_UNICODE)))
  3461. {
  3462. goto exit;
  3463. }
  3464. lpPropArrayTemp[ioopPR_OBJECT_TYPE].ulPropTag = PR_OBJECT_TYPE;
  3465. lpPropArrayTemp[ioopPR_OBJECT_TYPE].Value.l = MAPI_MAILUSER;
  3466. if(!(ulFlags & MAPI_UNICODE))
  3467. {
  3468. if (sc = ScConvertWPropsToA((LPALLOCATEMORE) (&MAPIAllocateMore), lpPropArrayTemp, ioopMAX, 0))
  3469. goto exit;
  3470. }
  3471. if (sc = ScMergePropValues(lpAdrEntry->cValues,
  3472. lpAdrEntry->rgPropVals, // source1
  3473. ioopMAX,
  3474. lpPropArrayTemp, // source2
  3475. &cPropsNew,
  3476. &lpPropArrayNew))
  3477. {
  3478. goto exit;
  3479. }
  3480. FreeBufferAndNull(&lpPropArrayTemp);
  3481. // Free the original prop value array
  3482. FreeBufferAndNull((LPVOID *) (&(lpAdrEntry->rgPropVals)));
  3483. // Now, build the new ADRENTRY
  3484. lpAdrEntry->cValues = cPropsNew;
  3485. lpAdrEntry->rgPropVals = lpPropArrayNew;
  3486. // Mark this entry as found.
  3487. lpFlagList->ulFlag[i] = MAPI_RESOLVED;
  3488. }
  3489. }
  3490. // Once we've found PR_DISPLAY_NAME we don't need to look at
  3491. // any more props. Jump to next ADRENTRY.
  3492. fNotDone = FALSE; // exit this ADRENTRY
  3493. continue;
  3494. case PR_EMAIL_ADDRESS:
  3495. lpszEmailAddress = (ulFlags & MAPI_UNICODE) ?
  3496. lpAdrEntry->rgPropVals[j].Value.lpszW :
  3497. ConvertAtoW(lpAdrEntry->rgPropVals[j].Value.lpszA);
  3498. break;
  3499. }
  3500. }
  3501. }
  3502. // if the ambiguity could not be resolved as an email, reset it
  3503. if(bAmbiguous && lpFlagList->ulFlag[i] == MAPI_UNRESOLVED)
  3504. lpFlagList->ulFlag[i] = MAPI_AMBIGUOUS;
  3505. }
  3506. exit:
  3507. hResult = ResultFromScode(sc);
  3508. if(!(ulFlags & MAPI_UNICODE))
  3509. {
  3510. if(lpszEmailAddress != lpszDisplayName)
  3511. LocalFreeAndNull(&lpszEmailAddress);
  3512. LocalFreeAndNull(&lpszDisplayName);
  3513. }
  3514. return(hResult);
  3515. }
  3516. //---------------------------------------------------------------------------
  3517. // Name: IAB_NewEntry()
  3518. //
  3519. // Description:
  3520. // Parameters:
  3521. // Returns:
  3522. // Effects:
  3523. // Notes:
  3524. // Revision:
  3525. //---------------------------------------------------------------------------
  3526. STDMETHODIMP
  3527. IAB_NewEntry(LPIAB lpIAB,
  3528. ULONG_PTR ulUIParam,
  3529. ULONG ulFlags,
  3530. ULONG cbEIDContainer,
  3531. LPENTRYID lpEIDContainer,
  3532. ULONG cbEIDNewEntryTpl,
  3533. LPENTRYID lpEIDNewEntryTpl,
  3534. ULONG FAR * lpcbEIDNewEntry,
  3535. LPENTRYID FAR * lppEIDNewEntry)
  3536. {
  3537. HRESULT hr = hrSuccess;
  3538. BOOL bChangesMade = FALSE;
  3539. BYTE bType;
  3540. SCODE sc;
  3541. #ifndef DONT_ADDREF_PROPSTORE
  3542. if ((FAILED(sc = OpenAddRefPropertyStore(NULL, lpIAB->lpPropertyStore)))) {
  3543. hr = ResultFromScode(sc);
  3544. goto exitNotAddRefed;
  3545. }
  3546. #endif
  3547. // BUGBUG <JasonSo>: This code does not handle the Container param at all.
  3548. VerifyWABOpenExSession(lpIAB);
  3549. bType = IsWABEntryID(cbEIDNewEntryTpl, lpEIDNewEntryTpl, NULL, NULL, NULL, NULL, NULL);
  3550. if (bType == WAB_DEF_MAILUSER || cbEIDNewEntryTpl == 0)
  3551. {
  3552. if(!lpcbEIDNewEntry || !lppEIDNewEntry)
  3553. {
  3554. hr = MAPI_E_INVALID_PARAMETER;
  3555. goto exit;
  3556. }
  3557. *lpcbEIDNewEntry = 0;
  3558. *lppEIDNewEntry = NULL;
  3559. hr = HrShowDetails( (LPADRBOOK)lpIAB,
  3560. (HWND) ulUIParam,
  3561. lpIAB->lpPropertyStore->hPropertyStore,
  3562. cbEIDContainer,
  3563. lpEIDContainer,
  3564. lpcbEIDNewEntry,
  3565. lppEIDNewEntry,
  3566. NULL,
  3567. SHOW_NEW_ENTRY,
  3568. MAPI_MAILUSER,
  3569. &bChangesMade);
  3570. }
  3571. else if (bType == WAB_DEF_DL)
  3572. {
  3573. hr = HrShowDetails( (LPADRBOOK)lpIAB,
  3574. (HWND) ulUIParam,
  3575. lpIAB->lpPropertyStore->hPropertyStore,
  3576. cbEIDContainer,
  3577. lpEIDContainer,
  3578. lpcbEIDNewEntry,
  3579. lppEIDNewEntry,
  3580. NULL,
  3581. SHOW_NEW_ENTRY,
  3582. MAPI_DISTLIST,
  3583. &bChangesMade);
  3584. }
  3585. else
  3586. {
  3587. DebugTrace(TEXT("IAB_NewEntry got unknown template entryID\n"));
  3588. hr = ResultFromScode(MAPI_E_INVALID_ENTRYID);
  3589. goto exit;
  3590. }
  3591. exit:
  3592. #ifndef DONT_ADDREF_PROPSTORE
  3593. ReleasePropertyStore(lpIAB->lpPropertyStore);
  3594. exitNotAddRefed:
  3595. #endif
  3596. return(hr);
  3597. }
  3598. //---------------------------------------------------------------------------
  3599. // Name: IAB_Address()
  3600. //
  3601. // Description:
  3602. // Parameters:
  3603. // Returns:
  3604. // Effects:
  3605. // Notes:
  3606. // Revision:
  3607. //---------------------------------------------------------------------------
  3608. STDMETHODIMP
  3609. IAB_Address(LPIAB lpIAB,
  3610. ULONG_PTR FAR * lpulUIParam,
  3611. LPADRPARM lpAdrParms,
  3612. LPADRLIST FAR * lppAdrList)
  3613. {
  3614. SCODE sc;
  3615. HRESULT hr = hrSuccess;
  3616. // OOPENTRYIDCONT oopEntryID;
  3617. // LPMAPIERROR lpMAPIError = NULL;
  3618. // MAPIDLG_Address FAR *lpfnAddress;
  3619. // BOOL fInited;
  3620. #ifndef DONT_ADDREF_PROPSTORE
  3621. if ((FAILED(sc = OpenAddRefPropertyStore(NULL, lpIAB->lpPropertyStore)))) {
  3622. hr = ResultFromScode(sc);
  3623. goto exitNotAddRefed;
  3624. }
  3625. #endif
  3626. #ifdef PARAMETER_VALIDATION
  3627. // Make sure it's an IAB
  3628. //
  3629. if (BAD_STANDARD_OBJ(lpIAB, IAB_, Address, lpVtbl))
  3630. {
  3631. DebugTraceArg(IAB_Address, TEXT("Bad vtable"));
  3632. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  3633. }
  3634. // Validate Parameters
  3635. //
  3636. if ((lpulUIParam && IsBadWritePtr(lpulUIParam, sizeof(ULONG)))
  3637. || (!lpAdrParms || IsBadWritePtr(lpAdrParms, sizeof(ADRPARM))))
  3638. {
  3639. DebugTraceArg(IAB_Address, TEXT("Invalid lpulUIParam or lpAdrParms"));
  3640. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  3641. }
  3642. // Validate AdrParm
  3643. //
  3644. // validate lpAdrParm->cbABContEntryID and lpAdrParm->lpABContEntryID
  3645. if (lpAdrParms->cbABContEntryID
  3646. && (!lpAdrParms->lpABContEntryID || IsBadReadPtr(lpAdrParms->lpABContEntryID,
  3647. (UINT)lpAdrParms->cbABContEntryID)))
  3648. {
  3649. DebugTraceArg(IAB_Address, TEXT("Invalid lpAdrParam->lpABContEntryID"));
  3650. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  3651. }
  3652. // validate lpAdrParm->lpfnABSDI, only used if DIALOG_SDI is set.
  3653. if (lpAdrParms->ulFlags & DIALOG_SDI)
  3654. {
  3655. if (lpAdrParms->lpfnABSDI && IsBadCodePtr((FARPROC)lpAdrParms->lpfnABSDI))
  3656. {
  3657. DebugTraceArg(IAB_Address, TEXT("Invalid lpAdrParam->lpfnABSDI"));
  3658. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  3659. }
  3660. }
  3661. //
  3662. // Validate lpAdrList, if the call would allow modification of the list
  3663. //
  3664. if (lpAdrParms->ulFlags & DIALOG_MODAL)
  3665. {
  3666. if (lppAdrList) // Treat NULL as a special case of don't care
  3667. {
  3668. if (IsBadWritePtr(lppAdrList, sizeof(LPADRLIST)))
  3669. {
  3670. DebugTraceArg(IAB_Address, TEXT("Invalid lppAdrList"));
  3671. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  3672. }
  3673. if (*lppAdrList && FBadAdrList(*lppAdrList))
  3674. {
  3675. DebugTraceArg(IAB_Address, TEXT("Invalid *lppAdrList"));
  3676. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  3677. }
  3678. }
  3679. }
  3680. //
  3681. // Check strings
  3682. //
  3683. //
  3684. // lpszCaption - goes on the top of the dialog on the caption bar
  3685. //
  3686. if (lpAdrParms->lpszCaption
  3687. && (lpAdrParms->ulFlags & MAPI_UNICODE
  3688. ? IsBadStringPtrW((LPWSTR) lpAdrParms->lpszCaption, (UINT) -1)
  3689. : IsBadStringPtrA((LPSTR) lpAdrParms->lpszCaption, (UINT) -1)))
  3690. {
  3691. DebugTraceArg(IAB_Address, TEXT("Invalid lpAdrParm->lpszCaption"));
  3692. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  3693. }
  3694. //
  3695. // lpszNewEntryTitle - Goes on the NewEntry dialog by the radio button, uninteresting if
  3696. // AB_SELECTONLY is set.
  3697. //
  3698. if (!(lpAdrParms->ulFlags & AB_SELECTONLY) && lpAdrParms->lpszNewEntryTitle
  3699. && (lpAdrParms->ulFlags & MAPI_UNICODE
  3700. ? IsBadStringPtrW((LPWSTR) lpAdrParms->lpszNewEntryTitle, (UINT) -1)
  3701. : IsBadStringPtrA((LPSTR) lpAdrParms->lpszNewEntryTitle, (UINT) -1)))
  3702. {
  3703. DebugTraceArg(IAB_Address, TEXT("Invalid lpAdrParm->lpszNewEntryTitle"));
  3704. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  3705. }
  3706. //
  3707. // Only check the following parameters if cDestFields is non-zero and !-1
  3708. //
  3709. if (lpAdrParms->cDestFields && lpAdrParms->cDestFields != (ULONG) -1)
  3710. {
  3711. ULONG ulString;
  3712. //
  3713. // lpszDestWellsTitle - Goes above the destination wells, uninteresting if 0 wells is
  3714. // brought up.
  3715. //
  3716. if (lpAdrParms->lpszNewEntryTitle
  3717. && (lpAdrParms->ulFlags & MAPI_UNICODE
  3718. ? IsBadStringPtrW((LPWSTR) lpAdrParms->lpszNewEntryTitle, (UINT) -1)
  3719. : IsBadStringPtrA((LPSTR) lpAdrParms->lpszNewEntryTitle, (UINT) -1)))
  3720. {
  3721. DebugTraceArg(IAB_Address, TEXT("Invalid lpAdrParm->lpszNewEntryTitle"));
  3722. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  3723. }
  3724. //
  3725. // nDestFieldFocus - needs to be less than cDestFields unless cDestFields is 0.
  3726. //
  3727. if (lpAdrParms->nDestFieldFocus >= lpAdrParms->cDestFields)
  3728. {
  3729. DebugTraceArg(IAB_Address, TEXT("Invalid lpAdrParm->nDestFieldFocus"));
  3730. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  3731. }
  3732. //
  3733. // lppszDestTitles - should be more like rglpszDestTitles[cDestFields]. Each string
  3734. // should be valid (i.e. not NULL although "" is acceptable).
  3735. //
  3736. if (lpAdrParms->lppszDestTitles)
  3737. {
  3738. //
  3739. // Loop through each title and see if there's a valid string
  3740. //
  3741. for (ulString = 0; ulString < lpAdrParms->cDestFields; ulString++)
  3742. {
  3743. if (!*(lpAdrParms->lppszDestTitles+ulString)
  3744. || (lpAdrParms->ulFlags & MAPI_UNICODE
  3745. ? IsBadStringPtrW((LPWSTR) *(lpAdrParms->lppszDestTitles+ulString), (UINT)-1)
  3746. : IsBadStringPtrA((LPSTR) *(lpAdrParms->lppszDestTitles+ulString), (UINT)-1)))
  3747. {
  3748. DebugTraceArg(IAB_Address, TEXT("Invalid lpAdrParm->lppszDestTitles"));
  3749. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  3750. }
  3751. }
  3752. }
  3753. //
  3754. // lpulDestComps - should be more like rgulDestComps[cDestFields]. This is the value
  3755. // for the PR_RECIPIENT_TYPE for messages. In fact, on the adrlist that is returned from
  3756. // this method, one of the list of values for this list will be set for each recipient.
  3757. // We don't validate that these have one of the MAPI defined values as we cannot tell
  3758. // if this call is being made to address a message. We don't care about this value if
  3759. // cDestFields is 0.
  3760. //
  3761. if (lpAdrParms->lpulDestComps
  3762. && IsBadReadPtr(lpAdrParms->lpulDestComps, (UINT) lpAdrParms->cDestFields*sizeof(ULONG)))
  3763. {
  3764. DebugTraceArg(IAB_Address, TEXT("Invalid lpAdrParm->lpulDestComps"));
  3765. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  3766. }
  3767. }
  3768. //
  3769. // lpContRestriction - This restriction, if there, gets applied to every contents table
  3770. // that is opened during the life of this dialog.
  3771. //
  3772. if (lpAdrParms->lpContRestriction && FBadRestriction(lpAdrParms->lpContRestriction))
  3773. {
  3774. DebugTraceArg(IAB_Address, TEXT("Invalid lpAdrParm->lpContRestriction"));
  3775. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  3776. }
  3777. //
  3778. // lpHierRestriction - This restriction, if there, gets applied to the hierarchy table.
  3779. // It's very useful when done on PR_AB_PROVIDER_ID.
  3780. //
  3781. if (lpAdrParms->lpHierRestriction && FBadRestriction(lpAdrParms->lpHierRestriction))
  3782. {
  3783. DebugTraceArg(IAB_Address, TEXT("Invalid lpAdrParm->lpHierRestriction"));
  3784. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  3785. }
  3786. //
  3787. // DIALOG_SDI
  3788. //
  3789. if (lpAdrParms->ulFlags & DIALOG_SDI)
  3790. {
  3791. //
  3792. // Only if we're SDI do we check these function pointers. They don't
  3793. // have to exist, although our current implementation of the dialogs will
  3794. // behave strangely without them.
  3795. //
  3796. if (lpAdrParms->lpfnDismiss && IsBadCodePtr((FARPROC)lpAdrParms->lpfnDismiss))
  3797. {
  3798. DebugTraceArg(IAB_Address, TEXT("Invalid lpAdrParm->lpfnDismiss"));
  3799. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  3800. }
  3801. }
  3802. #endif // PARAMETER_VALIDATION
  3803. VerifyWABOpenExSession(lpIAB);
  3804. hr = HrShowAddressUI(
  3805. (LPADRBOOK)lpIAB,
  3806. lpIAB->lpPropertyStore->hPropertyStore,
  3807. lpulUIParam,
  3808. lpAdrParms,
  3809. lppAdrList);
  3810. #ifndef DONT_ADDREF_PROPSTORE
  3811. ReleasePropertyStore(lpIAB->lpPropertyStore);
  3812. exitNotAddRefed:
  3813. #endif
  3814. return hr;
  3815. }
  3816. //---------------------------------------------------------------------------
  3817. // Name: IAB_Details()
  3818. //
  3819. // Description:
  3820. // Parameters:
  3821. // Returns:
  3822. // Effects:
  3823. // Notes: ulFlags can be 0 or MAPI_UNICODE but the MAPI_UNICODE only affects
  3824. // the lpszButtonText which is not supported. Hence this function doesn't
  3825. // change any behaviour with MAPI_UNICODE flag.
  3826. // Revision:
  3827. //---------------------------------------------------------------------------
  3828. STDMETHODIMP
  3829. IAB_Details(LPIAB lpIAB,
  3830. ULONG_PTR FAR * lpulUIParam,
  3831. LPFNDISMISS lpfnDismiss,
  3832. LPVOID lpvDismissContext,
  3833. ULONG cbEntryID,
  3834. LPENTRYID lpEntryID,
  3835. LPFNBUTTON lpfButtonCallback,
  3836. LPVOID lpvButtonContext,
  3837. LPTSTR lpszButtonText,
  3838. ULONG ulFlags)
  3839. {
  3840. SCODE sc;
  3841. HRESULT hr = hrSuccess;
  3842. BOOL bChangesMade = FALSE; //flags us if Details lead to any editing
  3843. BYTE bType;
  3844. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  3845. // LPMAPIERROR lpMAPIError = NULL;
  3846. // MAPIDLG_Details FAR *lpfnDetails;
  3847. // BOOL fInited;
  3848. #ifndef DONT_ADDREF_PROPSTORE
  3849. if ((FAILED(sc = OpenAddRefPropertyStore(NULL, lpIAB->lpPropertyStore)))) {
  3850. hr = ResultFromScode(sc);
  3851. goto exitNotAddRefed;
  3852. }
  3853. #endif
  3854. #ifdef PARAMETER_VALIDATION
  3855. // Make sure it's an IAB
  3856. //
  3857. if (BAD_STANDARD_OBJ(lpIAB, IAB_, Details, lpVtbl))
  3858. {
  3859. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  3860. }
  3861. /*
  3862. * Validate flags
  3863. */
  3864. if (ulFlags & ~(MAPI_UNICODE | DIALOG_MODAL | DIALOG_SDI | WAB_ONEOFF_NOADDBUTTON))
  3865. {
  3866. /*
  3867. * Unknown flags
  3868. */
  3869. DebugTraceArg(IAB_Details, TEXT("Unknown flags used"));
  3870. //return ResultFromScode(MAPI_E_UNKNOWN_FLAGS);
  3871. }
  3872. // Validate Parameters
  3873. if (!lpulUIParam
  3874. || (lpulUIParam && IsBadWritePtr(lpulUIParam, sizeof(ULONG))))
  3875. {
  3876. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  3877. }
  3878. if (!cbEntryID
  3879. || IsBadReadPtr(lpEntryID, (UINT) cbEntryID))
  3880. {
  3881. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  3882. }
  3883. if (lpfButtonCallback
  3884. && (IsBadCodePtr((FARPROC) lpfButtonCallback)
  3885. || (lpszButtonText
  3886. && ((ulFlags & MAPI_UNICODE)
  3887. ? IsBadStringPtrW((LPWSTR) lpszButtonText, (UINT) -1)
  3888. : IsBadStringPtrA((LPSTR)lpszButtonText, (UINT) -1)))))
  3889. {
  3890. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  3891. }
  3892. if ((ulFlags & DIALOG_SDI) && IsBadCodePtr((FARPROC) lpfnDismiss))
  3893. {
  3894. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  3895. }
  3896. #endif // PARAMETER_VALIDATION
  3897. VerifyWABOpenExSession(lpIAB);
  3898. bType = IsWABEntryID(cbEntryID, lpEntryID, NULL, NULL, NULL, NULL, NULL);
  3899. if( (bType == 0) &&
  3900. cbEntryID && lpEntryID) // assume its valid ..
  3901. {
  3902. // its unlikely that anyone will ever give a template entry id to this
  3903. // function. Hence if we are here, we have some non-null cbEntryID
  3904. // and lpEntryid .. if we can open it, we can tell if its a mailuser
  3905. // or a distlist ...
  3906. // We'll have to open this entry and look at its ulObjectType
  3907. ULONG ulObjectType = 0;
  3908. LPMAPIPROP lpMailUser = NULL;
  3909. hr = lpIAB->lpVtbl->OpenEntry( lpIAB,
  3910. cbEntryID,
  3911. lpEntryID,
  3912. NULL,
  3913. 0,
  3914. &ulObjectType,
  3915. (LPUNKNOWN * )&lpMailUser);
  3916. if(HR_FAILED(hr))
  3917. goto exit;
  3918. if (ulObjectType == MAPI_DISTLIST)
  3919. bType = WAB_DEF_DL;
  3920. else
  3921. bType = WAB_DEF_MAILUSER;
  3922. if(lpMailUser)
  3923. lpMailUser->lpVtbl->Release(lpMailUser);
  3924. }
  3925. if ((bType == WAB_DEF_MAILUSER) || (cbEntryID == 0))
  3926. {
  3927. hr = HrShowDetails((LPADRBOOK) lpIAB,
  3928. (HWND) *lpulUIParam,
  3929. lpIAB->lpPropertyStore->hPropertyStore,
  3930. 0, NULL, //container EID
  3931. &cbEntryID,
  3932. &lpEntryID,
  3933. NULL,
  3934. SHOW_DETAILS,
  3935. MAPI_MAILUSER,
  3936. &bChangesMade);
  3937. }
  3938. else if (bType == WAB_DEF_DL)
  3939. {
  3940. hr = HrShowDetails((LPADRBOOK) lpIAB,
  3941. (HWND) *lpulUIParam,
  3942. lpIAB->lpPropertyStore->hPropertyStore,
  3943. 0, NULL, //container EID
  3944. &cbEntryID,
  3945. &lpEntryID,
  3946. NULL,
  3947. SHOW_DETAILS,
  3948. MAPI_DISTLIST,
  3949. &bChangesMade);
  3950. }
  3951. else if ((bType == WAB_ONEOFF) || (bType == WAB_LDAP_MAILUSER))
  3952. {
  3953. //this may be a one-off entry
  3954. hr = HrShowOneOffDetails((LPADRBOOK) lpIAB,
  3955. (HWND) *lpulUIParam,
  3956. cbEntryID,
  3957. lpEntryID,
  3958. MAPI_MAILUSER,
  3959. NULL,
  3960. NULL,
  3961. (ulFlags & WAB_ONEOFF_NOADDBUTTON) ?
  3962. SHOW_ONE_OFF | WAB_ONEOFF_NOADDBUTTON : SHOW_ONE_OFF);
  3963. }
  3964. else
  3965. {
  3966. DebugTrace(TEXT("IAB_Details got unknown entryID type\n"));
  3967. hr = ResultFromScode(MAPI_E_INVALID_ENTRYID);
  3968. goto exit;
  3969. }
  3970. exit:
  3971. #ifndef DONT_ADDREF_PROPSTORE
  3972. ReleasePropertyStore(lpIAB->lpPropertyStore);
  3973. exitNotAddRefed:
  3974. #endif
  3975. // [PaulHi] 3/22/99 Raid 69651 If the DL property sheet changed, assume the title has
  3976. // changed as well and refresh the Tree View
  3977. if ( (bType == WAB_DEF_DL) && bChangesMade && lpIAB->hWndBrowse)
  3978. PostMessage(lpIAB->hWndBrowse, WM_COMMAND, (WPARAM) IDM_VIEW_REFRESH, 0);
  3979. return(hr);
  3980. }
  3981. //-----------------------------------------------------------------------------
  3982. // Synopsis: IAB_RecipOptions()
  3983. // Description:
  3984. // Resolve per Recipient Options.
  3985. //
  3986. // Parameters:
  3987. // [in] LPIAB lpIAB Pointer to AB object
  3988. // [in] ULONG ulUIParam Platform dependant UI parm
  3989. // [in] ULONG ulFlags Flags. UNICODE Flags
  3990. // [in/out] LPADRENTRY * lppRecip Recipient whose options are to be
  3991. // displayed
  3992. // Returns:
  3993. // HRESULT hr hrSuccess: if no problems. Also if no Recip
  3994. // Options found.
  3995. // Effects:
  3996. // Notes:
  3997. // - HrRecipOptions() will have to be modified to take a
  3998. // ulFlag parameter so that any string properties are returned
  3999. // Unicode if requested.
  4000. //
  4001. // - UNICODE currently not supported
  4002. //
  4003. // Revision:
  4004. //-----------------------------------------------------------------------------
  4005. STDMETHODIMP
  4006. IAB_RecipOptions(LPIAB lpIAB, ULONG_PTR ulUIParam, ULONG ulFlags,
  4007. LPADRENTRY lpRecip)
  4008. {
  4009. HRESULT hr;
  4010. #ifdef OLD_STUFF
  4011. SCODE sc = S_OK;
  4012. LPMALLOC lpMalloc = NULL;
  4013. LPXPLOGON lpXPLogon = NULL;
  4014. LPOPTIONDATA lpOptionData = NULL;
  4015. LPSTR lpszError = NULL;
  4016. LPSTR lpszAdrType = NULL;
  4017. LPPROPDATA lpPropData = NULL;
  4018. LPMAPIPROP lpIPropWrapped = NULL;
  4019. LPPROFSUP lpSup = NULL;
  4020. LPMAPITABLE lpDisplayTable = NULL;
  4021. OPTIONCALLBACK * pfnXPOptionCallback = NULL;
  4022. UINT idsError = 0;
  4023. HINSTANCE hinstXP = 0;
  4024. ULONG cProps;
  4025. LPSPropValue lpProp;
  4026. LPGUID lpRecipGuid;
  4027. LPSTR lpszTitle = NULL;
  4028. MAPIDLG_DoConfigPropsheet FAR *lpfnPropsheet;
  4029. LPMAPIERROR lpMapiError = NULL;
  4030. BOOL fInited;
  4031. #ifdef PARAMETER_VALIDATION
  4032. // Check to see if it has a jump table
  4033. if (IsBadReadPtr(lpIAB, sizeof(LPVOID)))
  4034. {
  4035. // No jump table found
  4036. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  4037. }
  4038. // Check to see that it's IABs jump table
  4039. if (lpIAB->lpVtbl != &vtblIAB)
  4040. {
  4041. // Not my jump table
  4042. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  4043. }
  4044. // Validate that the UI handle is good
  4045. if (ulUIParam && !IsWindow((HWND)ulUIParam))
  4046. {
  4047. DebugTraceArg(IAB_RecipOptions, TEXT("invalid window handle\n"));
  4048. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  4049. }
  4050. // Validate flags
  4051. if (ulFlags & ~MAPI_UNICODE)
  4052. {
  4053. DebugTraceArg(IAB_RecipOptions, TEXT("reserved flags used\n"));
  4054. // return ResultFromScode(MAPI_E_UNKNOWN_FLAGS);
  4055. }
  4056. // Validate the ADRENTRY
  4057. if (IsBadWritePtr(lpRecip, sizeof(ADRENTRY))) // RAID 1967
  4058. {
  4059. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  4060. }
  4061. if (!(lpRecip) || FBadRgPropVal((LPSPropValue)lpRecip->rgPropVals, (int)lpRecip->cValues))
  4062. {
  4063. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  4064. }
  4065. #endif // PARAMETER_VALIDATION
  4066. EnterCriticalSection(&lpIAB->cs);
  4067. // We need the lpMalloc for the OptionCallback
  4068. lpMalloc = lpIAB->pSession->lpMalloc;
  4069. // Spin through the props and look for the PR_ENTRYID and PR_ADDRTYPE
  4070. lpProp = NULL;
  4071. cProps = lpRecip->cValues;
  4072. lpProp = LpValFindProp(PR_ENTRYID, cProps, lpRecip->rgPropVals);
  4073. if (!lpProp)
  4074. {
  4075. DebugTrace(TEXT("IAB_RecipOptions(): No EntryId found in AdrEntry prop array\n"));
  4076. hr = ResultFromScode(MAPI_E_INVALID_PARAMETER);
  4077. idsError = IDS_INVALID_PARAMETER;
  4078. goto exit;
  4079. }
  4080. // Get MAPI UID
  4081. lpRecipGuid = (LPGUID)((LPENTRYID)lpProp->Value.bin.lpb)->ab;
  4082. lpProp = NULL;
  4083. lpProp = LpValFindProp(PR_ADDRTYPE, cProps, lpRecip->rgPropVals);
  4084. if (lpProp)
  4085. {
  4086. if (PROP_TYPE(lpProp->ulPropTag) == PT_STRING8)
  4087. {
  4088. lpszAdrType = lpProp->Value.lpszA;
  4089. }
  4090. }
  4091. // Build the support object. Try using the Profile Support object.
  4092. if (HR_FAILED(hr = NewProfSup(lpIAB->pSession, &lpSup)))
  4093. {
  4094. idsError = IDS_NOT_ENOUGH_MEMORY;
  4095. DebugTrace(TEXT("IAB_RecipOptions(): error creating Support object\n"));
  4096. goto exit;
  4097. }
  4098. Assert(lpSup);
  4099. // Find out if there is any Option Data for us.
  4100. hr = HrGetRecipOptions(lpRecipGuid, lpszAdrType, &lpSup->muidSection,
  4101. &lpSup->muidService, &lpXPLogon, &lpOptionData);
  4102. if (GetScode(hr) == MAPI_E_NOT_FOUND)
  4103. {
  4104. // It's not really an error, just that no recip options exist for that
  4105. // recipient. Convert hr to a warning and exit.
  4106. hr = ResultFromScode(MAPI_W_ERRORS_RETURNED);
  4107. idsError = IDS_NO_RECIP_OPTIONS;
  4108. goto exit;
  4109. }
  4110. if (HR_FAILED(hr))
  4111. {
  4112. idsError = IDS_OPTIONS_DATA_ERROR;
  4113. DebugTrace(TEXT("IAB_RecipOptions(): Failure obtaining Option Data\n"));
  4114. goto exit;
  4115. }
  4116. Assert(lpXPLogon && lpOptionData);
  4117. // Get the XP callback function.
  4118. if (FAILED (ScMAPILoadProviderLibrary (lpOptionData->lpszDLLName, &hinstXP)))
  4119. {
  4120. SideAssert(sc = GetLastError());
  4121. idsError = IDS_CANT_INIT_PROVIDER;
  4122. DebugTrace(TEXT("IAB_RecipOptions(): error 0x%lx loading XP provider %s\n"),
  4123. sc, lpOptionData->lpszDLLName);
  4124. goto exit;
  4125. }
  4126. pfnXPOptionCallback = (OPTIONCALLBACK *)GetProcAddress(hinstXP,
  4127. (LPCSTR)lpOptionData->ulOrdinal);
  4128. if (!pfnXPOptionCallback)
  4129. {
  4130. DebugTrace(TEXT("IAB_RecipOptions(): error finding XPOptions callback\n"));
  4131. idsError = IDS_CANT_INIT_PROVIDER;
  4132. hr = ResultFromScode(MAPI_E_NOT_INITIALIZED);
  4133. goto exit;
  4134. }
  4135. // Create MAPIProp object
  4136. sc = CreateIProp((LPIID) &IID_IMAPIPropData,
  4137. MAPIAllocateBuffer,
  4138. MAPIAllocateMore,
  4139. MAPIFreeBuffer,
  4140. NULL,
  4141. &lpPropData);
  4142. if (FAILED(sc)) {
  4143. idsError = IDS_NOT_ENOUGH_MEMORY;
  4144. DebugTrace(TEXT("IAB_RecipOptions(): error creating IProp object\n"));
  4145. goto exit;
  4146. }
  4147. MAPISetBufferName(lpPropData, TEXT("lpPropData in IAB_RecipOptions"));
  4148. Assert(lpPropData);
  4149. // Copy over the Default props from the Options default props
  4150. if (lpOptionData->cOptionsProps && lpOptionData->lpOptionsProps)
  4151. {
  4152. cProps = lpOptionData->cOptionsProps;
  4153. lpProp = lpOptionData->lpOptionsProps;
  4154. if (HR_FAILED(hr = lpPropData->lpVtbl->SetProps(lpPropData, cProps, lpProp,
  4155. NULL)))
  4156. {
  4157. lpPropData->lpVtbl->GetLastError(lpPropData, hr, 0, &lpMapiError);
  4158. DebugTrace(TEXT("IAB_RecipOptions(): SetProps failed overall\n"));
  4159. goto exit;
  4160. }
  4161. }
  4162. // Copy over the props from the ADRENTRY to our IProp object
  4163. cProps = lpRecip->cValues;
  4164. lpProp = lpRecip->rgPropVals;
  4165. if (HR_FAILED(hr = lpPropData->lpVtbl->SetProps(lpPropData, cProps, lpProp,
  4166. NULL)))
  4167. {
  4168. lpPropData->lpVtbl->GetLastError(lpPropData, hr, 0, &lpMapiError);
  4169. DebugTrace(TEXT("IAB_RecipOptions(): SetProps failed overall\n"));
  4170. goto exit;
  4171. }
  4172. // Call the XP provider callback to get the wrapped IProp Interface
  4173. if (FAILED(sc = (*pfnXPOptionCallback)(hinstXP, lpMalloc,
  4174. OPTION_TYPE_RECIPIENT, lpOptionData->cbOptionsData,
  4175. lpOptionData->lpbOptionsData, (LPMAPISUP)lpSup,
  4176. (LPMAPIPROP)lpPropData, &lpIPropWrapped, &lpMapiError)))
  4177. {
  4178. DebugTrace(TEXT("IAB_RecipOptions(): failure calling XP Callback\n"));
  4179. goto exit;
  4180. }
  4181. Assert(lpIPropWrapped);
  4182. // Get PR_DISPLAY_DETAILS a MAPI Table object
  4183. if (HR_FAILED(hr = lpIPropWrapped->lpVtbl->OpenProperty(lpIPropWrapped,
  4184. PR_DETAILS_TABLE, (LPIID)&IID_IMAPITable, 0, MAPI_MODIFY,
  4185. (LPUNKNOWN *)&lpDisplayTable)))
  4186. {
  4187. lpIPropWrapped->lpVtbl->GetLastError(lpIPropWrapped, hr, 0, &lpMapiError);
  4188. DebugTrace(TEXT("IAB_RecipOptions(): failure opening PR_DISPLAY_DETAILS\n"));
  4189. goto exit;
  4190. }
  4191. Assert(lpDisplayTable);
  4192. // Initialize the common MAPI dialog DLL (MAPID??.DLL)
  4193. sc = ScGetDlgFunction(offsetof(JT_MAPIDLG, dlg_doconfigpropsheet),
  4194. (FARPROC FAR *)&lpfnPropsheet, &fInited);
  4195. if (FAILED(sc))
  4196. {
  4197. idsError = IDS_CANT_INIT_COMMON_DLG;
  4198. TraceSz("IAB_RecipOptions(): common dlg not init'd");
  4199. hr = ResultFromScode(sc);
  4200. goto exit;
  4201. }
  4202. // Loadstring the Subject Prefix text.
  4203. sc = ScStringFromIDS(MAPIAllocateBuffer, 0, IDS_RECIPIENT_OPTIONS,
  4204. &lpszTitle);
  4205. if (FAILED(sc))
  4206. {
  4207. hr = ResultFromScode(sc);
  4208. DebugTrace(TEXT("IAB_RecipOptions(): OOM for prop sheet title string\n"));
  4209. goto exit;
  4210. }
  4211. LeaveCriticalSection(&lpIAB->cs);
  4212. // Call into MAPIDLG_DoConfigPropSheet...
  4213. hr = (*lpfnPropsheet)(ulUIParam,
  4214. ulFlags,
  4215. lpszTitle,
  4216. 0,
  4217. 1,
  4218. &lpDisplayTable,
  4219. &lpIPropWrapped,
  4220. &lpMapiError);
  4221. if (fInited)
  4222. CloseMapidlg();
  4223. EnterCriticalSection(&lpIAB->cs);
  4224. if (HR_FAILED(hr))
  4225. {
  4226. // $ Internal fixup to return error info in this API call so it matches the
  4227. // the other methods.
  4228. DebugTrace(TEXT("IAB_RecipOptions(): DoConfigPropSheet error\n"));
  4229. goto exit;
  4230. }
  4231. // From the Wrapped Props we'll rebuild a new ADRENTRY prop array
  4232. // and pass it pack to the Client.
  4233. lpProp = NULL;
  4234. if (HR_FAILED(hr = lpIPropWrapped->lpVtbl->GetProps(lpIPropWrapped, NULL,
  4235. MAPI_UNICODE, // ansi
  4236. &cProps, &lpProp)))
  4237. {
  4238. lpIPropWrapped->lpVtbl->GetLastError(lpIPropWrapped, hr, 0, &lpMapiError);
  4239. DebugTrace(TEXT("IAB_RecipOptions(): GetProps on new wrapped IProps failed.\n"));
  4240. goto exit;
  4241. }
  4242. Assert(cProps && lpProp);
  4243. // Free up the old ADRENTRY prop array and hook up the new one
  4244. FreeBufferAndNull(&(lpRecip->rgPropVals));
  4245. lpRecip->rgPropVals = lpProp;
  4246. lpRecip->cValues = cProps;
  4247. exit: // and clean up
  4248. UlRelease(lpSup);
  4249. UlRelease(lpDisplayTable);
  4250. UlRelease(lpIPropWrapped);
  4251. // Free the XP Provider lib
  4252. #ifdef WIN32
  4253. if (hinstXP)
  4254. #else
  4255. if (hinstXP >= HINSTANCE_ERROR)
  4256. #endif
  4257. {
  4258. FreeLibrary(hinstXP);
  4259. }
  4260. UlRelease(lpPropData);
  4261. FreeBufferAndNull(&lpOptionData);
  4262. FreeBufferAndNull(&lpszTitle);
  4263. if (sc && !(hr))
  4264. hr = ResultFromScode(sc);
  4265. if (hr)
  4266. SetMAPIError(lpIAB, hr, idsError, NULL, 0, 0,
  4267. ulFlags & MAPI_UNICODE, lpMapiError);
  4268. FreeBufferAndNull(&lpMapiError);
  4269. LeaveCriticalSection(&lpIAB->cs);
  4270. #endif
  4271. hr = ResultFromScode(MAPI_E_NO_SUPPORT);
  4272. DebugTraceResult(SESSOBJ_MessageOptions, hr);
  4273. return hr;
  4274. }
  4275. //-----------------------------------------------------------------------------
  4276. // Synopsis: IAB_QueryDefaultRecipOpt()
  4277. //
  4278. // Description: Returns the XP provider registered default options property
  4279. // list.
  4280. //
  4281. // Parameters:
  4282. // [in] LPIAB lpIAB Pointer to AB object
  4283. // [in] LPTSTR lpszAdrType
  4284. // [in] ULONG ulFlags Flags. UNICODE Flags
  4285. // [out] ULONG FAR * lpcValues
  4286. // [out] LPSPropValue FAR * lppOptions
  4287. //
  4288. // Returns:
  4289. // HRESULT hr hrSuccess: if no problems. Also if no Recip
  4290. // Options found.
  4291. // Effects:
  4292. // Notes:
  4293. // - Unicode not implemented.
  4294. //
  4295. // Revision:
  4296. //-----------------------------------------------------------------------------
  4297. STDMETHODIMP
  4298. IAB_QueryDefaultRecipOpt(LPIAB lpIAB, LPTSTR lpszAdrType, ULONG ulFlags,
  4299. ULONG FAR * lpcValues, LPSPropValue FAR * lppOptions)
  4300. {
  4301. HRESULT hr = hrSuccess;
  4302. #ifdef OLD_STUFF
  4303. SCODE sc = S_OK;
  4304. LPXPLOGON lpXPLogon = NULL;
  4305. LPOPTIONDATA lpOptionData = NULL;
  4306. LPSPropValue lpPropCopy = NULL;
  4307. UINT idsError = 0;
  4308. LPSTR lpszAdrTypeA = NULL;
  4309. MAPIUID muidSection;
  4310. MAPIUID muidService;
  4311. #ifdef PARAMETER_VALIDATION
  4312. /*
  4313. * Check to see if it has a jump table
  4314. */
  4315. if (IsBadReadPtr(lpIAB, sizeof(LPVOID)))
  4316. {
  4317. /*
  4318. * No jump table found
  4319. */
  4320. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  4321. }
  4322. /*
  4323. * Check to see that it's IABs jump table
  4324. */
  4325. if (lpIAB->lpVtbl != &vtblIAB)
  4326. {
  4327. /*
  4328. * Not my jump table
  4329. */
  4330. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  4331. }
  4332. /*
  4333. * Check that return params can be written
  4334. */
  4335. if (IsBadWritePtr(lpcValues, sizeof(ULONG))
  4336. || IsBadWritePtr(lppOptions, sizeof(LPSPropValue)))
  4337. {
  4338. /*
  4339. * Bad output parameters
  4340. */
  4341. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  4342. }
  4343. /*
  4344. * Validate flags
  4345. */
  4346. if (ulFlags & ~MAPI_UNICODE)
  4347. {
  4348. /*
  4349. * Unknown flags
  4350. */
  4351. return ResultFromScode(MAPI_E_UNKNOWN_FLAGS);
  4352. }
  4353. if (IsBadStringPtrA((LPCSTR)lpszAdrType, (UINT)-1))
  4354. {
  4355. /*
  4356. * Bad input string
  4357. */
  4358. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  4359. }
  4360. #endif // PARAMETER_VALIDATION
  4361. EnterCriticalSection(&lpIAB->cs);
  4362. hr = HrGetRecipOptions(NULL, (LPSTR)lpszAdrType, &muidSection, &muidService,
  4363. &lpXPLogon, &lpOptionData);
  4364. if (GetScode(hr) == MAPI_E_NOT_FOUND)
  4365. {
  4366. // It's not an error, just that no recip options exist for that
  4367. // adrtype. Convert hr to hrSucces and exit.
  4368. hr = hrSuccess;
  4369. goto exit;
  4370. }
  4371. Assert(lpXPLogon && lpOptionData);
  4372. if (HR_FAILED(hr))
  4373. {
  4374. idsError = IDS_OPTIONS_DATA_ERROR;
  4375. DebugTrace(TEXT("IAB_QueryDefaultRecipOpt(): Failure obtaining Option Data\n"));
  4376. goto exit;
  4377. }
  4378. // Find out if we have any default options to return.
  4379. if (lpOptionData->cOptionsProps && lpOptionData->lpOptionsProps)
  4380. {
  4381. // Copy out the props from OptionData struct into new memory
  4382. if (FAILED(sc = ScDupPropset((int)lpOptionData->cOptionsProps,
  4383. lpOptionData->lpOptionsProps, MAPIAllocateBuffer,
  4384. &lpPropCopy)))
  4385. {
  4386. idsError = IDS_NOT_ENOUGH_MEMORY,
  4387. DebugTrace(TEXT("IAB_QueryDefaultRecipOpt(): Failure to copy prop set\n"));
  4388. goto exit;
  4389. }
  4390. }
  4391. *lpcValues = lpOptionData->cOptionsProps;
  4392. *lppOptions = lpPropCopy;
  4393. exit:
  4394. FreeBufferAndNull(&lpOptionData);
  4395. if (sc && !hr)
  4396. hr = ResultFromScode(sc);
  4397. if (hr)
  4398. SetMAPIError(lpIAB, hr, idsError, NULL, 0, 0, 0, NULL);
  4399. LeaveCriticalSection(&lpIAB->cs);
  4400. #endif
  4401. hr = ResultFromScode(MAPI_E_NO_SUPPORT);
  4402. DebugTraceResult(IAB_QueryDefaultRecipOpt, hr);
  4403. return hr;
  4404. }
  4405. //---------------------------------------------------------------------------
  4406. // Name: IAB_GetPAB()
  4407. // Description:
  4408. // This API normally returns what would be the default WAB Container
  4409. // In pre-IE5 implementations of WAB, there is only 1 container which is
  4410. // returned by this statement ..
  4411. // In IE5 WAB, the WAB can be running in profile mode or not in profile mode
  4412. // If the WAB is not in profile mode it runs same as before (GetPAB returns a
  4413. // single container that has all the WAB contents in it)
  4414. // If the WAB is in profile mode and has no current user, it runs same as before (GetPAB
  4415. // returns a single container that has all the WAB contents in it)
  4416. // If the WAB is in profile mode and has a user, the container returned here
  4417. // corresponds to the user's contact folder - thus external apps would manipulate
  4418. // directly into the users contact folder and not into other folders
  4419. // Internally, however, the WAB may want to have a "Shared Contacts" container which has
  4420. // stuff not in other folders. This shared contacts is needed for the WAB UI in both
  4421. // with-user and without-user modes .. to distinguish between when we want the
  4422. // shared contacts folder vs. when we want the all-contacts PAB or user's folder PAB,
  4423. // we define 2 internal functions that set the PAB EID to a special setting..
  4424. // The assumption is that GetPAB is always followed by OpenEntry to get the container ..
  4425. // .. if it is, then in OpenEntry we can check the PAB EID and determine what kind of
  4426. // container to create ..
  4427. // If lpContainer->pmbinOlk = NULL, this container contains all WAB contents
  4428. // If lpContainer->pmbinOlk != NULL but lpContainer->pmbinOlk.cb = 0 and
  4429. // lpContainer->pmbinOlk->lpb = NULL, this is the "Shared Contacts" folder
  4430. // If nothing is NULL, then this is the user's folder ..
  4431. //
  4432. // For the special EID, we set *lpcbEntryID == SIZEOF_WAB_ENTRYID and
  4433. // *lppEntryID to szEmpty (This is a hack but there is no flag param here and it
  4434. // should be safe for internal use only)
  4435. //
  4436. // Parameters:
  4437. // Returns:
  4438. // Effects:
  4439. // Notes:
  4440. // Revision:
  4441. //---------------------------------------------------------------------------
  4442. /*
  4443. - SetVirtualPABEID
  4444. - When calling GetPAB, we want to sometimes specify getting the virtual PAB
  4445. * Folder instead of getting the Current User's Folder which is what
  4446. * would be returned if this was a profile session. to somehow indicate to
  4447. * GetPAB what folder we want, we have a very special EID combination that
  4448. * needs to be hndled very carefully .. for this the cbSize if 4 and
  4449. * the lpEntryID is the static const string szEmpty
  4450. */
  4451. // This function is added here so we can keep it linked to how GetPAB works
  4452. void SetVirtualPABEID(LPIAB lpIAB, ULONG * lpcb, LPENTRYID * lppb)
  4453. {
  4454. //if(bAreWABAPIProfileAware(lpIAB))// && bIsThereACurrentUser(lpIAB))
  4455. {
  4456. *lpcb = SIZEOF_WAB_ENTRYID;
  4457. *lppb = (LPENTRYID) szEmpty;
  4458. }
  4459. }
  4460. // This function determines if the EID denotes a special virtual root PAB
  4461. BOOL bIsVirtualPABEID(ULONG cbEID, LPENTRYID lpEID)
  4462. {
  4463. return (cbEID == SIZEOF_WAB_ENTRYID && szEmpty == (LPTSTR) lpEID);
  4464. }
  4465. STDMETHODIMP
  4466. IAB_GetPAB (LPIAB lpIAB,
  4467. ULONG * lpcbEntryID,
  4468. LPENTRYID * lppEntryID)
  4469. {
  4470. HRESULT hr;
  4471. ULONG cbEID = 0;
  4472. LPENTRYID lpEID = NULL;
  4473. BOOL bSharedPAB = FALSE;
  4474. #ifdef PARAMETER_VALIDATION
  4475. // Check to see if it has a jump table
  4476. if (IsBadReadPtr(lpIAB, sizeof(LPVOID))) {
  4477. // No jump table found
  4478. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  4479. }
  4480. // Check to see that it's IABs jump table
  4481. if (lpIAB->lpVtbl != &vtblIAB) {
  4482. // Not my jump table
  4483. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  4484. }
  4485. if (IsBadWritePtr(lpcbEntryID, sizeof(ULONG)) ||
  4486. IsBadWritePtr(lppEntryID, sizeof(LPENTRYID)))
  4487. {
  4488. // Bad parameters.
  4489. return(ResultFromScode(MAPI_E_INVALID_PARAMETER));
  4490. }
  4491. #endif // PARAMETER_VALIDATION
  4492. VerifyWABOpenExSession(lpIAB);
  4493. cbEID = *lpcbEntryID;
  4494. lpEID = *lppEntryID;
  4495. if(bIsVirtualPABEID(cbEID, lpEID))
  4496. {
  4497. // this is a special case where we asked for an over-ride of the GetPAB behaviour ..
  4498. // in this case, we don't do anything
  4499. bSharedPAB =TRUE;
  4500. cbEID = 0; lpEID = NULL;
  4501. }
  4502. else
  4503. if(bAreWABAPIProfileAware(lpIAB) && bIsThereACurrentUser(lpIAB))
  4504. {
  4505. // if this is a user-session then
  4506. cbEID = lpIAB->lpWABCurrentUserFolder->sbEID.cb;
  4507. lpEID = (LPENTRYID)lpIAB->lpWABCurrentUserFolder->sbEID.lpb;
  4508. }
  4509. else
  4510. {
  4511. cbEID = 0;
  4512. lpEID = NULL;
  4513. }
  4514. *lppEntryID = NULL;
  4515. *lpcbEntryID = 0;
  4516. if(!cbEID && !lpEID)
  4517. {
  4518. BYTE bPABType = bSharedPAB ? WAB_PABSHARED : WAB_PAB;
  4519. if (HR_FAILED(hr = CreateWABEntryID( bPABType, // Create WAB's PAB entryid
  4520. lpEID, NULL, NULL,
  4521. cbEID, 0,
  4522. NULL, // lpRoot (allocmore here)
  4523. lpcbEntryID, // returned cbEntryID
  4524. lppEntryID)))
  4525. {
  4526. goto out;
  4527. }
  4528. }
  4529. else
  4530. {
  4531. if(!MAPIAllocateBuffer(cbEID, (LPVOID *)lppEntryID))
  4532. {
  4533. *lpcbEntryID = cbEID;
  4534. CopyMemory(*lppEntryID, lpEID, cbEID);
  4535. }
  4536. }
  4537. MAPISetBufferName(*lppEntryID, TEXT("WAB PAB Entry ID"));
  4538. hr = hrSuccess;
  4539. out:
  4540. return(hr);
  4541. }
  4542. //---------------------------------------------------------------------------
  4543. // Name: IAB_SetPAB()
  4544. // Description:
  4545. // Parameters:
  4546. // Returns:
  4547. // Effects:
  4548. // Notes:
  4549. // Revision:
  4550. //---------------------------------------------------------------------------
  4551. STDMETHODIMP
  4552. IAB_SetPAB (LPIAB lpIAB,
  4553. ULONG cbEntryID,
  4554. LPENTRYID lpEntryID)
  4555. {
  4556. return(ResultFromScode(MAPI_E_NO_SUPPORT));
  4557. }
  4558. //---------------------------------------------------------------------------
  4559. // Name: IAB_GetDefaultDir()
  4560. //
  4561. // Description:
  4562. // Parameters:
  4563. // Returns:
  4564. // Effects:
  4565. // Notes:
  4566. // Revision:
  4567. //---------------------------------------------------------------------------
  4568. STDMETHODIMP
  4569. IAB_GetDefaultDir (LPIAB lpIAB,
  4570. ULONG * lpcbEntryID,
  4571. LPENTRYID * lppEntryID)
  4572. {
  4573. #ifdef OLD_STUFF
  4574. HRESULT hr = hrSuccess;
  4575. SCODE sc;
  4576. ULONG cValues;
  4577. LPSPropValue lpPropVal = NULL;
  4578. LPSBinary lpbinEntryID = NULL;
  4579. #ifdef PARAMETER_VALIDATION
  4580. /*
  4581. * Check to see if it has a jump table
  4582. */
  4583. if (IsBadReadPtr(lpIAB, sizeof(LPVOID)))
  4584. {
  4585. /*
  4586. * No jump table found
  4587. */
  4588. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  4589. }
  4590. /*
  4591. * Check to see that it's IABs jump table
  4592. */
  4593. if (lpIAB->lpVtbl != &vtblIAB)
  4594. {
  4595. /*
  4596. * Not my jump table
  4597. */
  4598. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  4599. }
  4600. if (IsBadWritePtr(lpcbEntryID, sizeof(ULONG)) ||
  4601. IsBadWritePtr(lppEntryID, sizeof(LPENTRYID)))
  4602. {
  4603. /*
  4604. * Bad parameters.
  4605. */
  4606. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  4607. }
  4608. #endif // PARAMETER_VALIDATION
  4609. EnterCriticalSection(&lpIAB->cs);
  4610. *lppEntryID = NULL;
  4611. *lpcbEntryID = 0;
  4612. //
  4613. // Check to see if IAdrBook already has this info...
  4614. //
  4615. if (lpIAB->lpEntryIDDD)
  4616. {
  4617. // If so, copy it and we're done.
  4618. if ((sc = MAPIAllocateBuffer(lpIAB->cbEntryIDDD,
  4619. (LPVOID *) lppEntryID))
  4620. != S_OK)
  4621. {
  4622. hr = ResultFromScode(sc);
  4623. goto out;
  4624. }
  4625. MAPISetBufferName(*lppEntryID, TEXT("Entry ID"));
  4626. MemCopy(*lppEntryID, lpIAB->lpEntryIDDD, (UINT)lpIAB->cbEntryIDDD);
  4627. *lpcbEntryID = lpIAB->cbEntryIDDD;
  4628. hr = hrSuccess;
  4629. goto out;
  4630. }
  4631. // If not...
  4632. //
  4633. // Retrieve PR_AB_DEFAULT_DIR from MAPIs default profile section
  4634. //
  4635. if (HR_FAILED(hr = ResultFromScode(IAB_ScGetABProfSectProps(
  4636. lpIAB,
  4637. &SPT_DD,
  4638. &cValues,
  4639. &lpPropVal))))
  4640. {
  4641. SetMAPIError(lpIAB, hr, IDS_NO_DEFAULT_DIRECTORY, NULL, 0,
  4642. 0, 0, NULL);
  4643. goto out;
  4644. }
  4645. //
  4646. // Did I get it?? Is it in the hierarchy??
  4647. //
  4648. if (PROP_TYPE(lpPropVal->ulPropTag) == PT_ERROR ||
  4649. !FContainerInHierarchy(lpIAB,
  4650. lpPropVal->Value.bin.cb,
  4651. (LPENTRYID) lpPropVal->Value.bin.lpb))
  4652. {
  4653. // No, look for the first global read-only container with Recipients.
  4654. hr = HrFindDirectory(lpIAB, 0, AB_RECIPIENTS | AB_UNMODIFIABLE,
  4655. &lpbinEntryID, NULL, NULL);
  4656. if (HR_FAILED(hr))
  4657. {
  4658. if (GetScode(hr) != MAPI_E_NOT_FOUND)
  4659. {
  4660. // Assume HrFindDirectory set the last error sz
  4661. goto out;
  4662. }
  4663. // Didn't find any read-only containers, how about read write?
  4664. hr = HrFindDirectory(lpIAB, 0, AB_RECIPIENTS | AB_MODIFIABLE,
  4665. &lpbinEntryID, NULL, NULL);
  4666. if (HR_FAILED(hr))
  4667. {
  4668. // Assume HrFindDirectory set the last error sz
  4669. goto out;
  4670. }
  4671. }
  4672. sc = MAPIAllocateBuffer(lpbinEntryID->cb, lppEntryID);
  4673. if (FAILED(sc))
  4674. goto out;
  4675. MemCopy(*lppEntryID, lpbinEntryID->lpb, lpbinEntryID->cb);
  4676. *lpcbEntryID = lpbinEntryID->cb;
  4677. MAPISetBufferName(*lppEntryID, TEXT("Default Dir EntryID"));
  4678. }
  4679. else
  4680. {
  4681. // Yes? Copy it and return it to the caller
  4682. hr = hrSuccess; // Don't return warnings.
  4683. if ((sc = MAPIAllocateBuffer(lpPropVal->Value.bin.cb,
  4684. (LPVOID *) lppEntryID)) != S_OK)
  4685. {
  4686. hr = ResultFromScode(sc);
  4687. goto out;
  4688. }
  4689. MAPISetBufferName(*lppEntryID, TEXT("Entry ID"));
  4690. MemCopy(*lppEntryID, lpPropVal->Value.bin.lpb,
  4691. (UINT)lpPropVal->Value.bin.cb);
  4692. *lpcbEntryID = lpPropVal->Value.bin.cb;
  4693. }
  4694. // Cache default directory in Iadrbook.
  4695. sc = MAPIAllocateBuffer(*lpcbEntryID, (LPVOID *) &(lpIAB->lpEntryIDDD));
  4696. if (FAILED(sc))
  4697. {
  4698. hr = ResultFromScode(sc);
  4699. goto out;
  4700. }
  4701. MAPISetBufferName(lpIAB->lpEntryIDDD, TEXT("cached IAB Entry ID"));
  4702. // Set IAdrBooks Default directory
  4703. MemCopy(lpIAB->lpEntryIDDD, *lppEntryID,(UINT)*lpcbEntryID);
  4704. lpIAB->cbEntryIDDD = *lpcbEntryID;
  4705. out:
  4706. FreeBufferAndNull(&lpPropVal);
  4707. FreeBufferAndNull(&lpbinEntryID);
  4708. LeaveCriticalSection (&lpIAB->cs);
  4709. // MAPI_E_NOT_FOUND is not an error
  4710. if (MAPI_E_NOT_FOUND == GetScode(hr))
  4711. hr = hrSuccess;
  4712. DebugTraceResult(IAB_GetDefaultDir, hr);
  4713. return hr;
  4714. #endif
  4715. return(IAB_GetPAB(lpIAB, lpcbEntryID, lppEntryID));
  4716. }
  4717. //---------------------------------------------------------------------------
  4718. // Name: IAB_SetDefaultDir()
  4719. //
  4720. // Description:
  4721. // Parameters:
  4722. // Returns:
  4723. // Effects:
  4724. // Notes:
  4725. // Revision:
  4726. //---------------------------------------------------------------------------
  4727. STDMETHODIMP
  4728. IAB_SetDefaultDir (LPIAB lpIAB,
  4729. ULONG cbEntryID,
  4730. LPENTRYID lpEntryID)
  4731. {
  4732. #ifdef OLD_STUFF
  4733. HRESULT hr = hrSuccess;
  4734. SPropValue spvDD;
  4735. SCODE sc;
  4736. #ifdef PARAMETER_VALIDATION
  4737. /*
  4738. * Check to see if it has a jump table
  4739. */
  4740. if (IsBadReadPtr(lpIAB, sizeof(LPVOID)))
  4741. {
  4742. /*
  4743. * No jump table found
  4744. */
  4745. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  4746. }
  4747. /*
  4748. * Check to see that it's IABs jump table
  4749. */
  4750. if (lpIAB->lpVtbl != &vtblIAB)
  4751. {
  4752. /*
  4753. * Not my jump table
  4754. */
  4755. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  4756. }
  4757. if (IsBadReadPtr(lpEntryID, (UINT)cbEntryID)
  4758. || (cbEntryID < sizeof (LPENTRYID)))
  4759. {
  4760. /*
  4761. * Not my jump table
  4762. */
  4763. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  4764. }
  4765. #endif // PARAMETER_VALIDATION
  4766. EnterCriticalSection(&lpIAB->cs);
  4767. //
  4768. // Check to see if IAdrBook already has the Default Dir
  4769. //
  4770. if ((lpEntryID == lpIAB->lpEntryIDDD) ||
  4771. ((cbEntryID == lpIAB->cbEntryIDDD) &&
  4772. (!memcmp(lpEntryID, lpIAB->lpEntryIDDD, (UINT)cbEntryID))))
  4773. {
  4774. // If so, all done.
  4775. goto out;
  4776. }
  4777. //
  4778. // Free the old entryid
  4779. //
  4780. if (lpIAB->lpEntryIDDD)
  4781. {
  4782. FreeBufferAndNull(&(lpIAB->lpEntryIDDD));
  4783. lpIAB->lpEntryIDDD = NULL;
  4784. lpIAB->cbEntryIDDD = 0;
  4785. }
  4786. //
  4787. // Allocate space for a new entry id
  4788. //
  4789. if ((sc = MAPIAllocateBuffer(cbEntryID, (LPVOID *) &(lpIAB->lpEntryIDDD)))
  4790. != S_OK)
  4791. {
  4792. hr = ResultFromScode(sc);
  4793. goto out;
  4794. }
  4795. MAPISetBufferName(lpIAB->lpEntryIDDD, TEXT("cached IAB Entry ID"));
  4796. //
  4797. // Set IAdrBooks Default directory
  4798. //
  4799. MemCopy(lpIAB->lpEntryIDDD, lpEntryID, (UINT)cbEntryID);
  4800. lpIAB->cbEntryIDDD = cbEntryID;
  4801. //
  4802. // Set the PR_AB_DEFAULT_DIR
  4803. // If it fails, continue anyway.
  4804. //
  4805. spvDD.ulPropTag = PR_AB_DEFAULT_DIR;
  4806. spvDD.Value.bin.cb = cbEntryID;
  4807. spvDD.Value.bin.lpb = (LPBYTE) lpEntryID;
  4808. (void) IAB_ScSetABProfSectProps(lpIAB, 1, &spvDD);
  4809. out:
  4810. LeaveCriticalSection(&lpIAB->cs);
  4811. return hr;
  4812. #endif
  4813. // BUGBUG: We need to fool Word into thinking this call succeeded.
  4814. return(SUCCESS_SUCCESS);
  4815. }
  4816. // #pragma SEGMENT(IAdrBook2)
  4817. //---------------------------------------------------------------------------
  4818. // Name: IAB_GetSearchPath()
  4819. //
  4820. // Description:
  4821. // Parameters:
  4822. // Returns:
  4823. // Effects:
  4824. // Notes:
  4825. // Revision:
  4826. //---------------------------------------------------------------------------
  4827. STDMETHODIMP
  4828. IAB_GetSearchPath(LPIAB lpIAB,
  4829. ULONG ulFlags,
  4830. LPSRowSet FAR * lppSearchPath)
  4831. {
  4832. HRESULT hr = E_FAIL;
  4833. ULONG ulObjectType = 0;
  4834. LPROOT lpRoot = NULL;
  4835. LPMAPITABLE lpContentsTable = NULL;
  4836. LPSRowSet lpSRowSet = NULL;
  4837. ULONG i=0,j=0;
  4838. ULONG ulContainerCount = 0;
  4839. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  4840. #ifdef PARAMETER_VALIDATION
  4841. // Make sure it's an IAB
  4842. //
  4843. if (BAD_STANDARD_OBJ(lpIAB, IAB_, Address, lpVtbl))
  4844. {
  4845. DebugTraceArg(IAB_Address, TEXT("Bad vtable"));
  4846. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  4847. }
  4848. // [PaulHi] 1/28/99 Raid 58495
  4849. if (IsBadWritePtr(lppSearchPath, sizeof(LPSRowSet)))
  4850. {
  4851. DebugTrace(TEXT("ERROR: IAB_GetSearchPath - invalid out pointer"));
  4852. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  4853. }
  4854. #endif
  4855. VerifyWABOpenExSession(lpIAB);
  4856. hr = lpIAB->lpVtbl->OpenEntry( lpIAB,
  4857. 0,
  4858. NULL,
  4859. NULL,
  4860. 0,
  4861. &ulObjectType,
  4862. (LPUNKNOWN *) &lpRoot );
  4863. if (HR_FAILED(hr))
  4864. {
  4865. DebugPrintError(( TEXT("OpenEntry Failed: %x\n"),hr));
  4866. goto out;
  4867. }
  4868. hr = lpRoot->lpVtbl->GetContentsTable( lpRoot,
  4869. ulFlags,
  4870. &lpContentsTable);
  4871. if (HR_FAILED(hr))
  4872. {
  4873. DebugPrintError(( TEXT("GetContentsTable Failed: %x\n"),hr));
  4874. goto out;
  4875. }
  4876. // Set the columns to the bare minimum
  4877. hr = lpContentsTable->lpVtbl->SetColumns(lpContentsTable,
  4878. (LPSPropTagArray)&irnColumns,
  4879. 0);
  4880. // This contentstable contains a list of all the containers,
  4881. // which is basically the local container(s) followed by
  4882. // all the LDAP containers ...
  4883. //
  4884. // By doing a QueryAllRows we will get an allocated SRowSet
  4885. // which we will reuse and free the remaining elements of it
  4886. //
  4887. hr = HrQueryAllRows(lpContentsTable,
  4888. NULL,
  4889. NULL,
  4890. NULL,
  4891. 0,
  4892. &lpSRowSet);
  4893. if (HR_FAILED(hr))
  4894. {
  4895. DebugPrintError(( TEXT("HrQueryAllRows Failed: %x\n"),hr));
  4896. goto out;
  4897. }
  4898. // Now we want to return only the WAB container(s) and the
  4899. // only those LDAP containers that have been chosen for
  4900. // doing a ResolveNames operation ..
  4901. if (pt_bIsWABOpenExSession) {
  4902. ulContainerCount = lpIAB->lpPropertyStore->colkci;
  4903. Assert(ulContainerCount);
  4904. } else
  4905. ulContainerCount = 1; // always return WAB_PAB so minimum is one
  4906. // Do a restriction on the contentstable to get resolvename
  4907. // LDAP containers ..
  4908. {
  4909. SRestriction resAnd[2]; // 0 = LDAP, 1 = ResolveFlag
  4910. SRestriction resLDAPResolve;
  4911. SPropValue ResolveFlag;
  4912. ULONG cRows;
  4913. // Restrict: Only show LDAP containers with Resolve TRUE
  4914. resAnd[0].rt = RES_EXIST;
  4915. resAnd[0].res.resExist.ulReserved1 = 0;
  4916. resAnd[0].res.resExist.ulReserved2 = 0;
  4917. resAnd[0].res.resExist.ulPropTag = (ulFlags & MAPI_UNICODE) ? // <note> assumes UNICODE defined
  4918. PR_WAB_LDAP_SERVER :
  4919. CHANGE_PROP_TYPE( PR_WAB_LDAP_SERVER, PT_STRING8);
  4920. ResolveFlag.ulPropTag = PR_WAB_RESOLVE_FLAG;
  4921. ResolveFlag.Value.b = TRUE;
  4922. resAnd[1].rt = RES_PROPERTY;
  4923. resAnd[1].res.resProperty.relop = RELOP_EQ;
  4924. resAnd[1].res.resProperty.ulPropTag = PR_WAB_RESOLVE_FLAG;
  4925. resAnd[1].res.resProperty.lpProp = &ResolveFlag;
  4926. resLDAPResolve.rt = RES_AND;
  4927. resLDAPResolve.res.resAnd.cRes = 2;
  4928. resLDAPResolve.res.resAnd.lpRes = resAnd;
  4929. hr = lpContentsTable->lpVtbl->Restrict(lpContentsTable,
  4930. &resLDAPResolve,
  4931. 0);
  4932. if (HR_FAILED(hr))
  4933. {
  4934. DebugTraceResult( TEXT("RootTable: Restrict"), hr);
  4935. goto out;
  4936. }
  4937. // Since the number of resolve-LDAP-Containers is less than the
  4938. // set of all the containers ... we can safely use our LPSRowset
  4939. // allocated structure to get the items we want without worrying
  4940. // about overruns ..
  4941. {
  4942. ULONG cRows = 1;
  4943. while(cRows)
  4944. {
  4945. LPSRowSet lpRow = NULL;
  4946. hr = lpContentsTable->lpVtbl->QueryRows(lpContentsTable,
  4947. 1, //one row at a time
  4948. 0,
  4949. &lpRow);
  4950. if(HR_FAILED(hr))
  4951. {
  4952. DebugTraceResult( TEXT("ResolveName:QueryRows"), hr);
  4953. cRows = 0;
  4954. }
  4955. else if (lpRow)
  4956. {
  4957. cRows = lpRow->cRows;
  4958. if (cRows)
  4959. {
  4960. // replace a container in the lpSRowSet list with
  4961. // this one ...
  4962. FreeBufferAndNull((LPVOID *) (&lpSRowSet->aRow[ulContainerCount].lpProps));
  4963. lpSRowSet->aRow[ulContainerCount].cValues = lpRow->aRow[0].cValues;
  4964. lpSRowSet->aRow[ulContainerCount].lpProps = lpRow->aRow[0].lpProps;
  4965. lpRow->aRow[0].cValues = 0;
  4966. lpRow->aRow[0].lpProps = NULL;
  4967. ulContainerCount++;
  4968. }
  4969. FreeProws(lpRow);
  4970. }
  4971. else
  4972. {
  4973. cRows = 0;
  4974. }
  4975. } // while cRows
  4976. //Free any extra memory we might have got ...
  4977. for (i=ulContainerCount;i<lpSRowSet->cRows;i++)
  4978. {
  4979. FreeBufferAndNull((LPVOID *) (&lpSRowSet->aRow[i].lpProps));
  4980. }
  4981. lpSRowSet->cRows = ulContainerCount;
  4982. }
  4983. }
  4984. hr = S_OK;
  4985. *lppSearchPath = lpSRowSet;
  4986. out:
  4987. if(lpContentsTable)
  4988. lpContentsTable->lpVtbl->Release(lpContentsTable);
  4989. if(lpRoot)
  4990. lpRoot->lpVtbl->Release(lpRoot);
  4991. return(hr);
  4992. }
  4993. //---------------------------------------------------------------------------
  4994. // Name: IAB_SetSearchPath()
  4995. // Description:
  4996. // Sets new searchpath in the user's profile.
  4997. // Special case empty or NULL rowset by deleting search path
  4998. // property from the profile.
  4999. //
  5000. // Parameters:
  5001. // Returns:
  5002. // Effects:
  5003. // Notes:
  5004. // Revision:
  5005. //---------------------------------------------------------------------------
  5006. STDMETHODIMP
  5007. IAB_SetSearchPath(LPIAB lpIAB,
  5008. ULONG ulFlags,
  5009. LPSRowSet lpSearchPath)
  5010. {
  5011. #ifdef OLD_STUFF
  5012. SCODE sc = SUCCESS_SUCCESS;
  5013. LPSBinary lpargbinDirEntryIDs = NULL;
  5014. LPSRow lprow;
  5015. LPSBinary lpbin;
  5016. UINT idsErr = 0;
  5017. #ifdef PARAMETER_VALIDATION
  5018. /*
  5019. * Check to see if it has a jump table
  5020. */
  5021. if (IsBadReadPtr(lpIAB, sizeof(LPVOID)))
  5022. {
  5023. /*
  5024. * No jump table found
  5025. */
  5026. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  5027. }
  5028. /*
  5029. * Check to see that it's IABs jump table
  5030. */
  5031. if (lpIAB->lpVtbl != &vtblIAB)
  5032. {
  5033. /*
  5034. * Not my jump table
  5035. */
  5036. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  5037. }
  5038. if (FBadRowSet(lpSearchPath))
  5039. {
  5040. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  5041. }
  5042. #endif // PARAMETER_VALIDATION
  5043. if (ulFlags) {
  5044. //
  5045. // No flags are defined for this call
  5046. //
  5047. return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS));
  5048. }
  5049. EnterCriticalSection(&lpIAB->cs);
  5050. if (! lpSearchPath || ! lpSearchPath->cRows) {
  5051. sc = IAB_ScDeleteABProfSectProps(lpIAB,
  5052. (LPSPropTagArray)&ptagaABSearchPath);
  5053. // Clear the searchpath cache
  5054. #if defined (WIN32) && !defined (MAC)
  5055. if (fGlobalCSValid) {
  5056. EnterCriticalSection(&csMapiSearchPath);
  5057. } else {
  5058. DebugTrace(TEXT("IAB_SetSearchPath: MAPI32.DLL already detached.\n"));
  5059. }
  5060. #endif
  5061. FreeBufferAndNull(&(lpIAB->lpspvSearchPathCache));
  5062. #if defined (WIN32) && !defined (MAC)
  5063. if (fGlobalCSValid) {
  5064. LeaveCriticalSection(&csMapiSearchPath);
  5065. } else {
  5066. DebugTrace(TEXT("IAB_SetSearchPath: MAPI32.DLL got detached.\n"));
  5067. }
  5068. #endif
  5069. goto ret;
  5070. }
  5071. if (FAILED(sc = MAPIAllocateBuffer(lpSearchPath->cRows * sizeof(SBinary),
  5072. (LPVOID FAR *) &lpargbinDirEntryIDs))) {
  5073. DebugTrace(TEXT("IAB::SetSearchPath() - Error allocating space for search path array (SCODE = 0x%08lX)\n"), sc);
  5074. idsErr = IDS_NOT_ENOUGH_MEMORY;
  5075. goto err;
  5076. }
  5077. MAPISetBufferName(lpargbinDirEntryIDs, TEXT("IAB Search Path Array"));
  5078. // Convert the row set into an array of SBinarys
  5079. lprow = lpSearchPath->aRow + lpSearchPath->cRows;
  5080. lpbin = lpargbinDirEntryIDs + lpSearchPath->cRows;
  5081. while (lprow--, lpbin-- > lpargbinDirEntryIDs) {
  5082. //$??? Can I rely on the first column being the EntryID?
  5083. //$ No. - BJD
  5084. SPropValue *lpProp = PpropFindProp(lprow->lpProps, lprow->cValues, PR_ENTRYID);
  5085. if (!lpProp) {
  5086. DebugTrace(TEXT("IAB::SetSearchPath() - Row passed without PR_ENTRYID.\n"));
  5087. sc = MAPI_E_MISSING_REQUIRED_COLUMN;
  5088. goto err;
  5089. }
  5090. *lpbin = lpProp->Value.bin;
  5091. }
  5092. // Set the search path
  5093. sc = IAB_ScSetSearchPathI(lpIAB, lpSearchPath->cRows, lpargbinDirEntryIDs);
  5094. if (FAILED(sc)) {
  5095. DebugTrace(TEXT("IAB::SetSearchPath() - Error setting search path (SCODE = 0x%08lX)\n"), sc);
  5096. idsErr = IDS_SET_SEARCH_PATH;
  5097. goto err;
  5098. }
  5099. ret:
  5100. LeaveCriticalSection(&lpIAB->cs);
  5101. FreeBufferAndNull(&lpargbinDirEntryIDs);
  5102. DebugTraceSc(IAB_SetSearchPath, sc);
  5103. return(ResultFromScode(sc));
  5104. err:
  5105. SetMAPIError(lpIAB, ResultFromScode(sc), idsErr, NULL, 0, 0, 0, NULL);
  5106. goto ret;
  5107. return(ResultFromScode(sc));
  5108. #endif
  5109. return(ResultFromScode(MAPI_E_NO_SUPPORT));
  5110. }
  5111. //----------------------------------------------------------------------------
  5112. // Synopsis: IAB_PrepareRecips()
  5113. //
  5114. // Description:
  5115. // Calls each registered AB Provider with PrepareRecips.
  5116. // The providers convert short entryids to longterm entryids
  5117. // and ensures that the columnset contains the property tags
  5118. // identified in lpPropTagArray.
  5119. //
  5120. // Parameters:
  5121. // Returns:
  5122. // Effects:
  5123. // Notes:
  5124. // Revision:
  5125. // Now check to see if enough info has been provided to avoid
  5126. // calling each registerd provider. RAID 5291
  5127. //
  5128. //----------------------------------------------------------------------------
  5129. STDMETHODIMP
  5130. IAB_PrepareRecips( LPIAB lpIAB,
  5131. ULONG ulFlags,
  5132. LPSPropTagArray pPropTagArray,
  5133. LPADRLIST pRecipList)
  5134. {
  5135. #ifdef OLD_STUFF
  5136. #ifdef PARAMETER_VALIDATION
  5137. // Check to see if it has a jump table
  5138. if (IsBadReadPtr(lpIAB, sizeof(LPVOID)))
  5139. {
  5140. // No jump table found
  5141. DebugTraceArg(IAB_PrepareRecips, TEXT("Bad vtable"));
  5142. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  5143. }
  5144. // Check to see that it's IABs jump table
  5145. if (lpIAB->lpVtbl != &vtblIAB)
  5146. {
  5147. // Not my jump table
  5148. DebugTraceArg(IAB_PrepareRecips, TEXT("Bad vtable"));
  5149. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  5150. }
  5151. // validate the prop tag array
  5152. if (lpPropTagArray && FBadColumnSet(lpPropTagArray))
  5153. {
  5154. DebugTraceArg(IAB_PrepareRecips, TEXT("Bad PropTag Array"));
  5155. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  5156. }
  5157. if (!lpRecipList || FBadAdrList(lpRecipList))
  5158. {
  5159. DebugTraceArg(IAB_PrepareRecips, TEXT("Bad ADRLIST"));
  5160. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  5161. }
  5162. // Make sure we've got a valid lpSession
  5163. hr = HrCheckSession(0, lpIAB->pSession);
  5164. if (HR_FAILED(hr))
  5165. {
  5166. DebugTraceArg(IAB_PrepareRecips, TEXT("Bad Session Object"));
  5167. return ResultFromScode(MAPI_E_INVALID_PARAMETER);
  5168. }
  5169. #endif // PARAMETER_VALIDATION
  5170. #endif // oldstuff
  5171. HRESULT hr = hrSuccess;
  5172. ULONG ulRecip;
  5173. ULONG ulProp;
  5174. ULONG ulObjType;
  5175. ULONG cValues;
  5176. ULONG cTotal;
  5177. LPSPropValue pspv = NULL, pspvEID = NULL;
  5178. LPADRENTRY pRecipEntry;
  5179. LPMAILUSER pMailUser = NULL;
  5180. ULONG i = 0;
  5181. LPSPropValue lpPropArrayNew = NULL;
  5182. ULONG ulcPropsNew = 0;
  5183. SCODE sc;
  5184. Assert(pRecipList);
  5185. if (!pRecipList)
  5186. return(MAPI_E_INVALID_PARAMETER);
  5187. // Since our entry id's are always long-term, we are done if
  5188. // no additional properties are specified.
  5189. if (!pRecipList->cEntries || !pPropTagArray)
  5190. return S_OK;
  5191. EnterCriticalSection(&lpIAB->cs);
  5192. VerifyWABOpenExSession(lpIAB);
  5193. for (ulRecip = 0; ulRecip < pRecipList->cEntries; ulRecip++)
  5194. {
  5195. pspvEID = NULL;
  5196. pRecipEntry = &(pRecipList->aEntries[ulRecip]);
  5197. for(i=0;i<pRecipEntry->cValues;i++)
  5198. {
  5199. if(pRecipEntry->rgPropVals[i].ulPropTag == PR_ENTRYID)
  5200. {
  5201. pspvEID = &(pRecipEntry->rgPropVals[i]);
  5202. break;
  5203. }
  5204. }
  5205. // Ignore unresolved entries
  5206. if (!pspvEID)
  5207. continue;
  5208. // Open the entry
  5209. if (FAILED(lpIAB->lpVtbl->OpenEntry(lpIAB,
  5210. pspvEID->Value.bin.cb,
  5211. (LPENTRYID)pspvEID->Value.bin.lpb,
  5212. &IID_IMailUser, 0,
  5213. &ulObjType, (LPUNKNOWN *)&pMailUser)))
  5214. continue;
  5215. Assert((ulObjType == MAPI_MAILUSER) || (ulObjType == MAPI_DISTLIST));
  5216. // Get the requested props
  5217. hr = pMailUser->lpVtbl->GetProps(pMailUser, pPropTagArray, MAPI_UNICODE, &cValues, &pspv);
  5218. pMailUser->lpVtbl->Release(pMailUser);
  5219. if (FAILED(hr))
  5220. continue;
  5221. if(cValues && pspv)
  5222. {
  5223. sc = ScMergePropValues( cValues,
  5224. pspv,
  5225. pRecipEntry->cValues,
  5226. pRecipEntry->rgPropVals,
  5227. &ulcPropsNew,
  5228. &lpPropArrayNew);
  5229. if (sc != S_OK)
  5230. {
  5231. hr = ResultFromScode(sc);
  5232. goto out;
  5233. }
  5234. }
  5235. // We're done with this now
  5236. FreeBufferAndNull(&pspv);
  5237. pspv = NULL;
  5238. // Replace the props in the address list
  5239. FreeBufferAndNull((LPVOID *) (&pRecipEntry->rgPropVals));
  5240. pRecipEntry->rgPropVals = lpPropArrayNew;
  5241. pRecipEntry->cValues = ulcPropsNew;
  5242. lpPropArrayNew = NULL;
  5243. } // for
  5244. hr = hrSuccess;
  5245. out:
  5246. if (lpPropArrayNew)
  5247. FreeBufferAndNull(&lpPropArrayNew);
  5248. if (pspv)
  5249. FreeBufferAndNull(&pspv);
  5250. LeaveCriticalSection(&lpIAB->cs);
  5251. return hr;
  5252. }
  5253. #define MAX_DIGITS_ULONG_10 10 // 10 digits max in a ULONG base 10
  5254. /***************************************************************************
  5255. Name : GetNewPropTag
  5256. Purpose : Gets the next valid named PropTag for this property store.
  5257. Parameters: lpgnp -> GUID_NAMED_PROPS containing all named props for
  5258. this store.
  5259. ulEntryCount = number of GUIDs in lpgnp
  5260. Returns : returns the next valid PropTag value. If 0, there are no
  5261. more named properties. (This would be bad.)
  5262. Comment :
  5263. ***************************************************************************/
  5264. ULONG GetNewPropTag(LPGUID_NAMED_PROPS lpgnp, ULONG ulEntryCount) {
  5265. static WORD wPropIDNext = 0;
  5266. ULONG j, k;
  5267. if (wPropIDNext == 0) {
  5268. // look through the current named props
  5269. // Since we don't allow removing named prop ids
  5270. // we always increment past the largest ID in use.
  5271. for (j = 0; j < ulEntryCount; j++) {
  5272. for (k = 0; k < lpgnp[j].cValues; k++) {
  5273. wPropIDNext = max(wPropIDNext, (WORD)PROP_ID(lpgnp[j].lpnm[k].ulPropTag));
  5274. }
  5275. }
  5276. if (wPropIDNext == 0) {
  5277. wPropIDNext = 0x8000; // start at 8000
  5278. } else {
  5279. wPropIDNext++; // next = one past current
  5280. }
  5281. }
  5282. return(PROP_TAG(PT_UNSPECIFIED, wPropIDNext++));
  5283. }
  5284. /** WAB specific GetIDsFromNames **/
  5285. HRESULT HrGetIDsFromNames(LPIAB lpIAB, ULONG cPropNames,
  5286. LPMAPINAMEID * lppPropNames, ULONG ulFlags, LPSPropTagArray * lppPropTags)
  5287. {
  5288. HRESULT hResult;
  5289. LPGUID_NAMED_PROPS lpgnp = NULL, lpgnpNew = NULL, lpgnpOld = NULL;
  5290. LPNAMED_PROP lpnm;
  5291. ULONG ulEntryCount;
  5292. ULONG i, j, k;
  5293. ULONG ulEntryCountOld = 0;
  5294. BOOL fChanged = FALSE;
  5295. LPTSTR lpName = NULL;
  5296. LPTSTR * lpID = NULL;
  5297. LPTSTR * rgNames = NULL;
  5298. ULONG ulNameSize;
  5299. UCHAR ucDefaultChar = '\002';
  5300. UCHAR ucNumericChar = '\001';
  5301. LPPROPERTY_STORE lpPropertyStore = lpIAB->lpPropertyStore;
  5302. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  5303. if(pt_bIsWABOpenExSession)
  5304. {
  5305. // This is a WABOpenEx session using outlooks storage provider
  5306. if(!lpPropertyStore->hPropertyStore)
  5307. return MAPI_E_NOT_INITIALIZED;
  5308. {
  5309. LPWABSTORAGEPROVIDER lpWSP = (LPWABSTORAGEPROVIDER) lpPropertyStore->hPropertyStore;
  5310. hResult = lpWSP->lpVtbl->GetIDsFromNames( lpWSP,
  5311. cPropNames,
  5312. lppPropNames,
  5313. ulFlags,
  5314. lppPropTags);
  5315. DebugTrace(TEXT("WABStorageProvider::GetIDsFromNames returned:%x\n"),hResult);
  5316. return hResult;
  5317. }
  5318. }
  5319. *lppPropTags = NULL;
  5320. // Call into property store for the table of named props
  5321. if (hResult = GetNamedPropsFromPropStore(lpPropertyStore->hPropertyStore,
  5322. &ulEntryCountOld,
  5323. &lpgnpOld)) {
  5324. DebugTraceResult( TEXT("GetNamedPropsFromPropStore"), hResult);
  5325. goto exit;
  5326. }
  5327. ulEntryCount = ulEntryCountOld;
  5328. if (hResult = ResultFromScode(MAPIAllocateBuffer(sizeof(SPropTagArray) + (cPropNames * sizeof(ULONG)), lppPropTags))) {
  5329. DebugTraceResult( TEXT("GetIDsFromNames allocation of proptag array"), hResult);
  5330. goto exit;
  5331. }
  5332. (*lppPropTags)->cValues = cPropNames;
  5333. // If we're creating new entries, copy the existing array into a new one with space
  5334. // for worst-case expansion.
  5335. if (ulFlags & MAPI_CREATE) {
  5336. if (! (lpgnpNew = LocalAlloc(LPTR, (ulEntryCount + cPropNames) * sizeof(GUID_NAMED_PROPS)))) {
  5337. hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  5338. goto exit;
  5339. }
  5340. if (ulEntryCount) {
  5341. // Copy the existing array into the new one. Retain the same GUID pointers.
  5342. CopyMemory(lpgnpNew, lpgnpOld, ulEntryCount * sizeof(GUID_NAMED_PROPS));
  5343. // Now, copy the prop arrays for each GUID
  5344. for (i = 0; i < ulEntryCount; i++) {
  5345. if (! (lpnm = LocalAlloc(LPTR, (cPropNames + lpgnpNew[i].cValues) * sizeof(NAMED_PROP)))) {
  5346. LocalFreeAndNull(&lpgnpNew);
  5347. hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  5348. goto exit;
  5349. }
  5350. // Copy the existing array into the new one. Retain string pointers.
  5351. CopyMemory(lpnm, lpgnpOld[i].lpnm, lpgnpOld[i].cValues * sizeof(NAMED_PROP));
  5352. lpgnpNew[i].lpnm = lpnm;
  5353. }
  5354. }
  5355. lpgnp = lpgnpNew; // Use the new one
  5356. } else {
  5357. lpgnp = lpgnpOld; // Use the old one
  5358. }
  5359. // Allocate an array for ANSI name strings
  5360. if (! (rgNames = LocalAlloc(LPTR, cPropNames * sizeof(LPTSTR)))) {
  5361. DebugTrace(TEXT("GetIDsFromNames couldn't allocate names array\n"));
  5362. hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  5363. goto exit;
  5364. }
  5365. if (! (lpID = LocalAlloc(LPTR, cPropNames * sizeof(LPTSTR *)))) {
  5366. hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  5367. goto exit;
  5368. }
  5369. // For each requested property, look through the prop store values
  5370. for (i = 0; i < cPropNames; i++) {
  5371. if (lppPropNames[i]->ulKind == MNID_ID) {
  5372. // Map the numeric ID into a string name
  5373. DWORD cchSize = (MAX_DIGITS_ULONG_10 + 2);
  5374. if (! (rgNames[i] = LocalAlloc(LPTR, sizeof(TCHAR)*cchSize))) {
  5375. DebugTrace(TEXT("GetIDsFromNames couldn't allocate name buffer\n"));
  5376. hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  5377. goto exit;
  5378. }
  5379. wnsprintf(rgNames[i], cchSize, TEXT("%c%u"), ucNumericChar, lppPropNames[i]->Kind.lID);
  5380. lpName = rgNames[i];
  5381. }
  5382. else if (lppPropNames[i]->ulKind == MNID_STRING)
  5383. {
  5384. ulNameSize = lstrlen(lppPropNames[i]->Kind.lpwstrName)+1;
  5385. if (! ulNameSize) {
  5386. // invalid name
  5387. DebugTrace(TEXT("GetIDsFromNames WideCharToMultiByte -> %u\n"), GetLastError());
  5388. (*lppPropTags)->aulPropTag[i] = PROP_TAG(PT_ERROR, PR_NULL);
  5389. hResult = ResultFromScode(MAPI_W_ERRORS_RETURNED);
  5390. continue;
  5391. }
  5392. if (! (lpID[i] = LocalAlloc(LPTR, ulNameSize*sizeof(TCHAR)))) {
  5393. DebugTrace(TEXT("GetIDsFromNames couldn't allocate name buffer\n"));
  5394. hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  5395. goto exit;
  5396. }
  5397. StrCpyN(lpID[i],lppPropNames[i]->Kind.lpwstrName, ulNameSize);
  5398. lpName = lpID[i];
  5399. }
  5400. (*lppPropTags)->aulPropTag[i] = PR_NULL; // init to NULL
  5401. for (j = 0; j < ulEntryCount; j++) {
  5402. if (! memcmp(lppPropNames[i]->lpguid, lpgnp[j].lpGUID, sizeof(GUID))) {
  5403. for (k = 0; k < lpgnp[j].cValues; k++) {
  5404. if (! lstrcmpi(lpgnp[j].lpnm[k].lpsz, lpName)) {
  5405. // found it
  5406. (*lppPropTags)->aulPropTag[i] = lpgnp[j].lpnm[k].ulPropTag;
  5407. break;
  5408. }
  5409. }
  5410. if ((*lppPropTags)->aulPropTag[i] == PR_NULL) {
  5411. if (ulFlags & MAPI_CREATE) {
  5412. // Create a new one since it's not there
  5413. register ULONG cValues = lpgnp[j].cValues;
  5414. lpgnp[j].lpnm[cValues].lpsz = lpName;
  5415. lpgnp[j].lpnm[cValues].ulPropTag = GetNewPropTag(lpgnp, ulEntryCount);
  5416. (*lppPropTags)->aulPropTag[i] = lpgnp[j].lpnm[cValues].ulPropTag;
  5417. lpgnp[j].cValues++;
  5418. fChanged = TRUE;
  5419. } else {
  5420. // Error
  5421. (*lppPropTags)->aulPropTag[i] = PROP_TAG(PT_ERROR, PR_NULL);
  5422. hResult = ResultFromScode(MAPI_W_ERRORS_RETURNED);
  5423. }
  5424. }
  5425. break;
  5426. }
  5427. }
  5428. if ((*lppPropTags)->aulPropTag[i] == PR_NULL) {
  5429. if (ulFlags & MAPI_CREATE) {
  5430. register ULONG cValues = 0;
  5431. // Must add the new GUID
  5432. lpgnp[ulEntryCount].lpGUID = lppPropNames[i]->lpguid;
  5433. lpgnp[ulEntryCount].cValues = 0;
  5434. // conservative: Allocate room in case we need to put all of the
  5435. // requested prop names in here.
  5436. if (! (lpgnp[ulEntryCount].lpnm = LocalAlloc(LPTR, cPropNames * sizeof(NAMED_PROP)))) {
  5437. hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
  5438. goto exit;
  5439. }
  5440. // Now, create a new prop
  5441. lpgnp[ulEntryCount].lpnm[cValues].lpsz = lpName;
  5442. lpgnp[ulEntryCount].lpnm[cValues].ulPropTag = GetNewPropTag(lpgnp, ulEntryCount);
  5443. (*lppPropTags)->aulPropTag[i] = lpgnp[ulEntryCount].lpnm[cValues].ulPropTag;
  5444. lpgnp[ulEntryCount].cValues++;
  5445. ulEntryCount++; // new GUID
  5446. fChanged = TRUE;
  5447. } else {
  5448. // Error
  5449. (*lppPropTags)->aulPropTag[i] = PROP_TAG(PT_ERROR, PR_NULL);
  5450. hResult = ResultFromScode(MAPI_W_ERRORS_RETURNED);
  5451. }
  5452. }
  5453. }
  5454. if (ulFlags & MAPI_CREATE && fChanged) {
  5455. // Save the property mappings
  5456. if (hResult = SetNamedPropsToPropStore(lpPropertyStore->hPropertyStore,
  5457. ulEntryCount,
  5458. lpgnp)) {
  5459. DebugTraceResult( TEXT("SetNamedPropToPropStore"), hResult);
  5460. }
  5461. }
  5462. exit:
  5463. if (rgNames) {
  5464. for (i = 0; i < cPropNames; i++) {
  5465. LocalFreeAndNull(&(rgNames[i]));
  5466. LocalFreeAndNull(&(lpID[i]));
  5467. }
  5468. LocalFreeAndNull((LPVOID *)&rgNames);
  5469. }
  5470. if(lpID)
  5471. LocalFreeAndNull((LPVOID*)&lpID);
  5472. if (lpgnpOld) {
  5473. FreeGuidnamedprops(ulEntryCountOld, lpgnpOld);
  5474. }
  5475. if (lpgnpNew) { // not so simple, only free the arrays, not the strings, guids
  5476. for (i = 0; i < ulEntryCount; i++) {
  5477. LocalFreeAndNull(&(lpgnpNew[i].lpnm));
  5478. }
  5479. LocalFreeAndNull(&lpgnpNew);
  5480. }
  5481. if (HR_FAILED(hResult)) {
  5482. FreeBufferAndNull(lppPropTags); // yes, no &
  5483. }
  5484. return(hResult);
  5485. }
  5486. #ifdef OLD_STUFF
  5487. // Forward reference
  5488. HRESULT HrFixupTDN(LPADRLIST lpRecipList);
  5489. //---------------------------------------------------------------------------
  5490. // Name: HrPrepareRecips()
  5491. //
  5492. // Description:
  5493. // Internal function that does what IAB_PrepareRecips does but
  5494. // also supports a status flag so we know if we called down
  5495. // into a provider and really made some modifications.
  5496. //
  5497. // Parameters:
  5498. // Returns:
  5499. // Effects:
  5500. // Notes:
  5501. // Revision:
  5502. //---------------------------------------------------------------------------
  5503. STDMETHODIMP
  5504. HrPrepareRecips(LPIAB lpIAB, ULONG ulFlags, LPSPropTagArray lpPropTagArray,
  5505. LPADRLIST lpRecipList, ULONG * pulPrepRecipStatus)
  5506. {
  5507. HRESULT hr = hrSuccess;
  5508. SCODE sc;
  5509. BOOL fPrepRequired;
  5510. LPLSTPROVDATA lpABProvData;
  5511. BOOL fFixupTDN = FALSE;
  5512. ULONG iTag;
  5513. // Verify that we need to call provider's PrepareRecips
  5514. sc = ScVerifyPrepareRecips(lpIAB, ulFlags, lpPropTagArray, lpRecipList,
  5515. &fPrepRequired);
  5516. if (FAILED(sc))
  5517. {
  5518. DebugTrace(TEXT("Failure calling ScVerifyPrepareResult sc = %08X\n"), sc);
  5519. hr = ResultFromScode(sc);
  5520. goto exit;
  5521. }
  5522. // Recipient properties already prepared, we're out o' here
  5523. if (!fPrepRequired)
  5524. goto exit;
  5525. else
  5526. {
  5527. if (pulPrepRecipStatus)
  5528. {
  5529. *pulPrepRecipStatus |= PREPARE_RECIP_MOD_REQUIRED;
  5530. }
  5531. }
  5532. // First handle the one-offs...
  5533. hr = INT_PrepareRecips (lpIAB, ulFlags, lpPropTagArray, lpRecipList);
  5534. if (hr)
  5535. {
  5536. // Log it
  5537. DebugTraceResult(IAB_PrepareRecips, hr);
  5538. }
  5539. // Get the list of logged in ABProviders from the session and
  5540. // Iterate down the list
  5541. for (lpABProvData = lpIAB->pSession->lstAdrProv.lpProvData; lpABProvData;
  5542. lpABProvData=lpABProvData->lstNext)
  5543. {
  5544. // For each logged in session, have them fix up their entries
  5545. hr = ((LPABLOGON)(lpABProvData->lpProviderInfo))->lpVtbl->PrepareRecips(
  5546. (LPABLOGON)(lpABProvData->lpProviderInfo), ulFlags, lpPropTagArray,
  5547. lpRecipList);
  5548. #ifdef DEBUG
  5549. if (HR_FAILED(hr))
  5550. DebugTrace(TEXT("Failure in AB Provider <%s> calling PrepareRecips()\n"),
  5551. lpABProvData->lpInitData->lpszDLLName);
  5552. #endif
  5553. DebugTraceResult(IAB_PrepareRecips, hr);
  5554. }
  5555. // mask any provider errors
  5556. hr = hrSuccess;
  5557. //
  5558. // Ok, Check to see if PR_TRANSMITABLE_DISPLAY_NAME_A was asked for
  5559. // and if so, make sure each recipient has one.
  5560. //
  5561. if (lpPropTagArray)
  5562. {
  5563. for (iTag=0; !fFixupTDN && iTag<lpPropTagArray->cValues; iTag++)
  5564. fFixupTDN =
  5565. (lpPropTagArray->aulPropTag[iTag] == PR_TRANSMITABLE_DISPLAY_NAME_A);
  5566. if (fFixupTDN)
  5567. {
  5568. hr = HrFixupTDN(lpRecipList);
  5569. }
  5570. }
  5571. exit:
  5572. DebugTraceResult(HrPrepareRecips, hr);
  5573. return hr;
  5574. }
  5575. //
  5576. // HrFixupTDN - Fixup Transmitable Display Name
  5577. //
  5578. // For those entries that do not have PR_TRANSMITABLE_DISPLAY_NAME
  5579. // MAPI will generate it for them.
  5580. //
  5581. HRESULT
  5582. HrFixupTDN(LPADRLIST lpRecipList)
  5583. {
  5584. HRESULT hResult = hrSuccess;
  5585. SCODE sc = S_OK;
  5586. ULONG iRecip;
  5587. LPSPropValue lpspvTDN = NULL;
  5588. LPSPropValue lpspvDN = NULL;
  5589. for (iRecip = 0; iRecip < lpRecipList->cEntries; iRecip++)
  5590. {
  5591. LPSPropValue lpspvUser = lpRecipList->aEntries[iRecip].rgPropVals;
  5592. ULONG cValues = lpRecipList->aEntries[iRecip].cValues;
  5593. //$ This is where we default the value of PR_TRANSMITABLE_DISPLAY_NAME
  5594. //$ if was asked for.
  5595. //
  5596. //
  5597. lpspvTDN = PpropFindProp(lpspvUser,
  5598. cValues,
  5599. PROP_TAG(PT_ERROR, PROP_ID(PR_TRANSMITABLE_DISPLAY_NAME_A)));
  5600. lpspvDN = PpropFindProp(lpspvUser, cValues, PR_DISPLAY_NAME_A);
  5601. if (lpspvTDN && lpspvDN)
  5602. {
  5603. LPSTR lpszDN;
  5604. LPSTR lpszTDN;
  5605. lpszDN = lpspvDN->Value.lpszA;
  5606. //
  5607. // Check to see if the DN is already in the form 'name'.
  5608. //
  5609. if (*lpszDN == '\'' &&
  5610. *(lpszDN+lstrlen(lpszDN)-1) == '\'')
  5611. {
  5612. //
  5613. // Simply point lpspvT to lpspvDN
  5614. //
  5615. lpspvTDN->ulPropTag = PR_TRANSMITABLE_DISPLAY_NAME_A;
  5616. lpspvTDN->Value.lpszA = lpszDN;
  5617. } else
  5618. {
  5619. //
  5620. // We tic it ourselves and set it back in...
  5621. //
  5622. DWORD cchSize = (lstrlen(lpszDN)+3);
  5623. sc = MAPIAllocateMore(sizeof(TCHAR)*cchSize, lpspvUser, &lpszTDN);
  5624. if (sc)
  5625. {
  5626. DebugTrace(TEXT("HrFixupTDN out of memory\n"));
  5627. hResult = ResultFromScode(sc);
  5628. goto error;
  5629. }
  5630. *lpszTDN = '\'';
  5631. StrCpyN(&(lpszTDN[1]), lpszDN, cchSize-1);
  5632. StrCatBuff(lpszTDN, TEXT("\'"), cchSize);
  5633. lpspvTDN->ulPropTag = PR_TRANSMITABLE_DISPLAY_NAME_A;
  5634. lpspvTDN->Value.lpszA = lpszTDN;
  5635. }
  5636. }
  5637. }
  5638. error:
  5639. DebugTraceResult(HrFixupTDN, hResult);
  5640. return hResult;
  5641. }
  5642. #endif