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.

1212 lines
38 KiB

  1. /*--------------------------------------------------------------
  2. *
  3. *
  4. * ui_reslv.c - shows the resolve name dialog
  5. *
  6. *
  7. *
  8. *
  9. *
  10. *
  11. *
  12. --------------------------------------------------------------*/
  13. #include "_apipch.h"
  14. extern HINSTANCE ghCommCtrlDLLInst;
  15. #define MAX_RESLV_STRING 52 // Max # of characters to display in the static label ...
  16. enum _ReturnValuesFromResolveDialog
  17. {
  18. RESOLVE_PICKUSER=0,
  19. RESOLVE_CANCEL,
  20. RESOLVE_OK
  21. };
  22. typedef struct _ResolveInfo
  23. {
  24. LPADRLIST * lppAdrList; // Stores the AdrList
  25. ULONG nIndex; // Index of the item of interest
  26. LPTSTR lpszDisplayName;// Preextracted display name for that
  27. LPADRBOOK lpIAB; // Pointer to the IAB object
  28. HWND hWndParent; // Stores hWndParents for dialog generating windows
  29. ULONG ulFlag; // Stores Resolved or Ambiguos state
  30. LPRECIPIENT_INFO lpContentsList;
  31. LPMAPITABLE lpMapiTable;
  32. BOOL bUnicode; // TRUE if MAPI_UNICODE specified in IAB::ResolveName
  33. } RESOLVE_INFO, * LPRESOLVE_INFO;
  34. static DWORD rgReslvHelpIDs[] =
  35. {
  36. IDC_RESOLVE_BUTTON_BROWSE, IDH_WAB_PICK_USER,
  37. IDC_RESOLVE_LIST_MATCHES, IDH_WAB_CHK_NAME_LIST,
  38. IDC_RESOLVE_STATIC_1, IDH_WAB_CHK_NAME_LIST,
  39. IDC_RESOLVE_BUTTON_PROPS, IDH_WAB_PICK_RECIP_NAME_PROPERTIES,
  40. IDC_RESOLVE_BUTTON_NEWCONTACT, IDH_WAB_PICK_RECIP_NAME_NEW,
  41. 0,0
  42. };
  43. //forward declarations
  44. HRESULT HrResolveName(LPADRBOOK lpIAB,
  45. HWND hWndParent,
  46. HANDLE hPropertyStore,
  47. ULONG nIndex,
  48. ULONG ulFlag,
  49. BOOL bUnicode,
  50. LPADRLIST * lppAdrList,
  51. LPMAPITABLE lpMapiTable);
  52. INT_PTR CALLBACK fnResolve(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);
  53. BOOL ProcessResolveLVNotifications(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  54. HRESULT HrShowPickUserDialog(LPRESOLVE_INFO lpRI, LPTSTR lpszCaption);
  55. HRESULT HrShowNewEntryFromResolve(LPRESOLVE_INFO lpRI, HWND hWndParent, ULONG ulObjectType);
  56. HRESULT HrFillLVWithMatches( HWND hWndLV,
  57. LPRESOLVE_INFO lpRI);
  58. HRESULT HrMergeSelectionWithOriginal(LPRESOLVE_INFO lpRI,
  59. ULONG cbEID,
  60. LPENTRYID lpEID);
  61. void ExitResolveDialog(HWND hDlg, LPRESOLVE_INFO lpRI, int nRetVal);
  62. BOOL GetLVSelectedItem(HWND hWndLV, LPRESOLVE_INFO lpRI);
  63. ///////////////////////////////////////////////////////////////////////////////////////////////////
  64. //
  65. //
  66. // HrShowResolveUI
  67. //
  68. // Wraps the UI for Resolve Names
  69. //
  70. //
  71. //
  72. ///////////////////////////////////////////////////////////////////////////////////////////////////
  73. HRESULT HrShowResolveUI(IN LPADRBOOK lpIAB,
  74. HWND hWndParent,
  75. HANDLE hPropertyStore,
  76. ULONG ulFlags, // WAB_RESOLVE_NO_NOT_FOUND_UI
  77. LPADRLIST * lppAdrList,
  78. LPFlagList *lppFlagList,
  79. LPAMBIGUOUS_TABLES lpAmbiguousTables)
  80. {
  81. HRESULT hr = hrSuccess;
  82. ULONG i=0;
  83. LPFlagList lpFlagList= NULL;
  84. LPMAPITABLE lpMapiTable = NULL;
  85. BOOL bUnicode = (ulFlags & WAB_RESOLVE_UNICODE);
  86. // if no common control, exit
  87. if (NULL == ghCommCtrlDLLInst) {
  88. hr = ResultFromScode(MAPI_E_UNCONFIGURED);
  89. goto out;
  90. }
  91. if(!hPropertyStore || !lppAdrList || !lppFlagList || !(*lppAdrList) || !(*lppFlagList))
  92. {
  93. hr = MAPI_E_INVALID_PARAMETER;
  94. goto out;
  95. }
  96. lpFlagList=(*lppFlagList);
  97. // we need to scan the lpFlagList and look for unresolved entries
  98. for (i = 0; i < lpFlagList->cFlags; i++)
  99. {
  100. //
  101. // Occasionally someone (like athena) may hand us an adrlist with null rgPropVals
  102. // We need to anticipate that.
  103. //
  104. if ( ((*lppAdrList)->aEntries[i].cValues == 0) ||
  105. ((*lppAdrList)->aEntries[i].rgPropVals == NULL) )
  106. continue;
  107. switch (lpFlagList->ulFlag[i])
  108. {
  109. case MAPI_RESOLVED:
  110. break;
  111. case MAPI_AMBIGUOUS:
  112. //
  113. // W2 - we now have an Ambiguous Table parameter .. for Unresolved
  114. // entries, there is no Table but for Ambiguous entries, there is
  115. // a corresponding ambiguous table filled in from the LDAP servers
  116. //
  117. if(lpAmbiguousTables)
  118. {
  119. if (lpAmbiguousTables->cEntries != 0)
  120. {
  121. lpMapiTable = lpAmbiguousTables->lpTable[i];
  122. }
  123. }
  124. //Fall through
  125. case MAPI_UNRESOLVED:
  126. //
  127. // We show a dialog asking the user what they want to do ...
  128. // For this version, they can
  129. // (b) browse the list of users or (c) cancel this user ..
  130. // We will assume that we already the AdrList already has
  131. // Recipient_Type and Display_Name and we only need to fill
  132. // in the EntryID of this user ...
  133. //
  134. if ((! (ulFlags & WAB_RESOLVE_NO_NOT_FOUND_UI) ||
  135. lpFlagList->ulFlag[i] == MAPI_AMBIGUOUS)) {
  136. hr = HrResolveName( lpIAB,
  137. hWndParent,
  138. hPropertyStore,
  139. i,
  140. lpFlagList->ulFlag[i],
  141. bUnicode,
  142. lppAdrList,
  143. lpMapiTable);
  144. if (!HR_FAILED(hr))
  145. lpFlagList->ulFlag[i] = MAPI_RESOLVED;
  146. else
  147. {
  148. // Cancels are final .. other errors are not ..
  149. if (hr == MAPI_E_USER_CANCEL)
  150. goto out;
  151. }
  152. }
  153. break;
  154. }
  155. }
  156. out:
  157. return hr;
  158. }
  159. // *** Dont change *** the order of the first 2 properties between here and the similar structure
  160. // in ui_addr.c
  161. enum _lppAdrListReturnedProps
  162. {
  163. propPR_DISPLAY_NAME,
  164. propPR_ENTRYID,
  165. TOTAL_ADRLIST_PROPS
  166. };
  167. ////////////////////////////////////////////////////////////////////////////////////////
  168. //
  169. // HrResolveName - tackles one entry at a time ...
  170. //
  171. ////////////////////////////////////////////////////////////////////////////////////////
  172. HRESULT HrResolveName( IN LPADRBOOK lpIAB,
  173. HWND hWndParent,
  174. HANDLE hPropertyStore,
  175. ULONG nIndex,
  176. ULONG ulFlag,
  177. BOOL bUnicode,
  178. LPADRLIST * lppAdrList,
  179. LPMAPITABLE lpMapiTable)
  180. {
  181. ULONG i=0;
  182. LPTSTR lpszDisplayName = NULL, lpszEmailAddress = NULL;
  183. int nRetVal = 0;
  184. HRESULT hr = hrSuccess;
  185. RESOLVE_INFO RI = {0};
  186. LPADRLIST lpAdrList = *lppAdrList;
  187. ULONG ulTagDN = PR_DISPLAY_NAME, ulTagEmail = PR_EMAIL_ADDRESS;
  188. if(!bUnicode)
  189. {
  190. ulTagDN = CHANGE_PROP_TYPE(ulTagDN, PT_STRING8);
  191. ulTagEmail = CHANGE_PROP_TYPE(ulTagEmail, PT_STRING8);
  192. }
  193. //Scan this adrlist entries properties
  194. for(i=0;i < lpAdrList->aEntries[nIndex].cValues; i++)
  195. {
  196. if (lpAdrList->aEntries[nIndex].rgPropVals[i].ulPropTag == ulTagDN)
  197. {
  198. lpszDisplayName = bUnicode ?
  199. (LPWSTR)lpAdrList->aEntries[nIndex].rgPropVals[i].Value.LPSZ :
  200. ConvertAtoW((LPSTR)lpAdrList->aEntries[nIndex].rgPropVals[i].Value.LPSZ);
  201. }
  202. if (lpAdrList->aEntries[nIndex].rgPropVals[i].ulPropTag == ulTagEmail)
  203. {
  204. lpszEmailAddress = bUnicode ?
  205. (LPWSTR)lpAdrList->aEntries[nIndex].rgPropVals[i].Value.LPSZ :
  206. ConvertAtoW((LPSTR)lpAdrList->aEntries[nIndex].rgPropVals[i].Value.LPSZ);
  207. }
  208. }
  209. // we need some display name info to resolve on ...
  210. if (lpszDisplayName == NULL) //we need this info or cant proceed
  211. {
  212. if (lpszEmailAddress)
  213. {
  214. lpszDisplayName = lpszEmailAddress;
  215. lpszEmailAddress = NULL;
  216. }
  217. else
  218. {
  219. hr = MAPI_E_INVALID_PARAMETER;
  220. goto out;
  221. }
  222. }
  223. RI.nIndex = nIndex;
  224. RI.lppAdrList = lppAdrList;
  225. RI.lpszDisplayName = lpszDisplayName;
  226. RI.lpIAB = lpIAB;
  227. RI.hWndParent = hWndParent;
  228. RI.ulFlag = ulFlag;
  229. RI.lpContentsList = NULL;
  230. RI.lpMapiTable = lpMapiTable;
  231. RI.bUnicode = bUnicode;
  232. nRetVal = (int) DialogBoxParam( hinstMapiX,
  233. MAKEINTRESOURCE(IDD_DIALOG_RESOLVENAME),
  234. hWndParent,
  235. fnResolve,
  236. (LPARAM) &RI);
  237. switch(nRetVal)
  238. {
  239. case RESOLVE_CANCEL:
  240. hr = MAPI_E_USER_CANCEL; //Cancel, flag it as pass and dont change anything
  241. goto out;
  242. break;
  243. case RESOLVE_OK:
  244. hr = hrSuccess;
  245. goto out;
  246. case -1: // something went wrong ...
  247. DebugPrintTrace(( TEXT("DialogBoxParam -> %u\n"), GetLastError()));
  248. hr = E_FAIL;
  249. goto out;
  250. break;
  251. } //switch
  252. out:
  253. if(!bUnicode) // <note> assumes UNICODE defined
  254. {
  255. LocalFreeAndNull(&lpszDisplayName);
  256. LocalFreeAndNull(&lpszEmailAddress);
  257. }
  258. return hr;
  259. }
  260. /////////////////////////////////////////////////////////////////////////////////
  261. //
  262. // SetResolveUI -
  263. //
  264. //
  265. /////////////////////////////////////////////////////////////////////////////////
  266. BOOL SetResolveUI(HWND hDlg)
  267. {
  268. // This function initializes a list view
  269. HrInitListView( GetDlgItem(hDlg,IDC_RESOLVE_LIST_MATCHES),
  270. LVS_REPORT,
  271. FALSE); // Hide or show column headers
  272. // Set the font of all the children to the default GUI font
  273. EnumChildWindows( hDlg,
  274. SetChildDefaultGUIFont,
  275. (LPARAM) 0);
  276. return TRUE;
  277. }
  278. void SetLabelLDAP(HWND hDlg, HWND hWndLV)
  279. {
  280. // look at an entryid from the hWNdLV
  281. // Use it only if its an LDAP entryid
  282. // if the entryid is something else, we need to get its name and
  283. // fill the structure accordingly
  284. LPRECIPIENT_INFO lpItem;
  285. if(ListView_GetItemCount(hWndLV) <= 0)
  286. goto out;
  287. lpItem = GetItemFromLV(hWndLV, 0);
  288. if(lpItem)
  289. {
  290. LPTSTR lpServer = NULL;
  291. LPTSTR lpDNS = NULL;
  292. LPTSTR lpName = NULL;
  293. TCHAR szName[40]; // we will limit the name to 40 chars so that the whole
  294. // string will fit in the UI for really large chars
  295. // is this an LDAP entryid ?
  296. if (WAB_LDAP_MAILUSER == IsWABEntryID( lpItem->cbEntryID,
  297. lpItem->lpEntryID,
  298. &lpServer,
  299. &lpDNS,
  300. NULL, NULL, NULL))
  301. {
  302. //lpServer contains the server name
  303. LPTSTR lpsz;
  304. TCHAR szBuf[MAX_UI_STR];
  305. TCHAR szTmp[MAX_PATH], *lpszTmp;
  306. CopyTruncate(szName, lpServer, ARRAYSIZE(szName));
  307. lpName = (LPTSTR) szName;
  308. LoadString(hinstMapiX, idsResolveMatchesOnLDAP, szBuf, ARRAYSIZE(szBuf));
  309. CopyTruncate(szTmp, lpName, MAX_PATH - 1);
  310. lpszTmp = szTmp;
  311. if(FormatMessage( FORMAT_MESSAGE_FROM_STRING |
  312. FORMAT_MESSAGE_ARGUMENT_ARRAY |
  313. FORMAT_MESSAGE_ALLOCATE_BUFFER,
  314. szBuf,
  315. 0,0, //ignored
  316. (LPTSTR) &lpsz,
  317. MAX_UI_STR,
  318. (va_list *)&lpszTmp))
  319. {
  320. SetDlgItemText(hDlg, IDC_RESOLVE_STATIC_MATCHES, lpsz);
  321. IF_WIN32(LocalFree(lpsz);)
  322. IF_WIN16(FormatMessageFreeMem(lpsz);)
  323. }
  324. }
  325. }
  326. out:
  327. return;
  328. }
  329. void FillUI(HWND hDlg, HWND hWndLV, LPRESOLVE_INFO lpRI)
  330. {
  331. TCHAR szBuf[MAX_UI_STR];
  332. ULONG nLen = 0;
  333. LPTSTR lpszDisplayName = lpRI->lpszDisplayName;
  334. BOOL bNothingFound = FALSE;
  335. LPTSTR lpszBuffer = NULL;
  336. LPTSTR lpName = NULL;
  337. TCHAR szTmp[MAX_PATH], *lpszTmp;
  338. TCHAR szName[40]; // we will limit the name to 40 chars so that the whole
  339. // string will fit in the UI for really large chars
  340. if ( (lpRI->ulFlag == MAPI_UNRESOLVED) ||
  341. (HR_FAILED(HrFillLVWithMatches(hWndLV, lpRI)))
  342. )
  343. bNothingFound = TRUE;
  344. nLen = CopyTruncate(szName, lpszDisplayName, ARRAYSIZE(szName));
  345. lpName = (LPTSTR) szName;
  346. LoadString(hinstMapiX, (bNothingFound ? IDS_RESOLVE_NO_MATCHES_FOR : IDS_ADDRBK_RESOLVE_CAPTION),
  347. szBuf, ARRAYSIZE(szBuf));
  348. // Win9x bug FormatMessage cannot have more than 1023 chars
  349. CopyTruncate(szTmp, lpName, MAX_PATH - 1);
  350. lpszTmp = szTmp;
  351. if(FormatMessage( FORMAT_MESSAGE_FROM_STRING |
  352. FORMAT_MESSAGE_ARGUMENT_ARRAY |
  353. FORMAT_MESSAGE_ALLOCATE_BUFFER,
  354. szBuf,
  355. 0,0, //ignored
  356. (LPTSTR) &lpszBuffer,
  357. MAX_UI_STR,
  358. (va_list *)&lpszTmp))
  359. {
  360. SetDlgItemText(hDlg, IDC_RESOLVE_STATIC_1,lpszBuffer);
  361. IF_WIN32(LocalFreeAndNull(&lpszBuffer);)
  362. IF_WIN16(FormatMessageFreeMem(lpszBuffer);)
  363. }
  364. if(bNothingFound)
  365. {
  366. // If this has already been flagged as unresolved .. or
  367. // the attempt to find fuzzy matches was unsuccessful ...
  368. // tell 'em nothing found ...
  369. LoadString(hinstMapiX, IDS_RESOLVE_NO_MATCHES, szBuf, ARRAYSIZE(szBuf));
  370. {
  371. LV_ITEM lvI = {0};
  372. lvI.mask = LVIF_TEXT;
  373. lvI.cchTextMax = lstrlen(szBuf)+1;
  374. lvI.pszText = szBuf;
  375. ListView_InsertItem(hWndLV, &lvI);
  376. ListView_SetColumnWidth(hWndLV,0,400); //400 is a totally random number, we just want the column to be big enough not to truncate text
  377. }
  378. EnableWindow(hWndLV,FALSE);
  379. EnableWindow(GetDlgItem(hDlg,IDC_RESOLVE_BUTTON_PROPS),FALSE);
  380. EnableWindow(GetDlgItem(hDlg,IDOK/*IDC_RESOLVE_BUTTON_OK*/),FALSE);
  381. ShowWindow(GetDlgItem(hDlg,IDC_RESOLVE_STATIC_MATCHES),SW_HIDE);
  382. }
  383. else
  384. {
  385. // if the search results are from an ldap server, we need
  386. // to set the label on the dialog to say the results are from
  387. // an LDAP server
  388. SetLabelLDAP(hDlg, hWndLV);
  389. // If the list view is filled, select the first item
  390. if (ListView_GetItemCount(hWndLV) > 0)
  391. {
  392. LVSelectItem(hWndLV, 0);
  393. SetFocus(hWndLV);
  394. }
  395. }
  396. return;
  397. }
  398. /*************************************************************************
  399. //
  400. // resolve Dialog - simple implementation for 0.5
  401. //
  402. **************************************************************************/
  403. INT_PTR CALLBACK fnResolve(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
  404. {
  405. TCHAR szBuf[MAX_UI_STR];
  406. ULONG nLen = 0, nLenMax = 0, nRetVal=0;
  407. HRESULT hr = hrSuccess;
  408. LPRESOLVE_INFO lpRI = (LPRESOLVE_INFO) GetWindowLongPtr(hDlg,DWLP_USER);
  409. switch(message)
  410. {
  411. case WM_INITDIALOG:
  412. {
  413. HWND hWndLV = GetDlgItem(hDlg,IDC_RESOLVE_LIST_MATCHES);
  414. SetWindowLongPtr(hDlg,DWLP_USER,lParam); //Save this for future reference
  415. lpRI = (LPRESOLVE_INFO) lParam;
  416. SetResolveUI(hDlg);
  417. FillUI(hDlg, hWndLV, lpRI);
  418. }
  419. break;
  420. default:
  421. #ifndef WIN16
  422. if((g_msgMSWheel && message == g_msgMSWheel)
  423. // || message == WM_MOUSEWHEEL
  424. )
  425. {
  426. SendMessage(GetDlgItem(hDlg, IDC_RESOLVE_LIST_MATCHES), message, wParam, lParam);
  427. break;
  428. }
  429. #endif // !WIN16
  430. return FALSE;
  431. break;
  432. case WM_SYSCOLORCHANGE:
  433. //Forward any system changes to the list view
  434. SendMessage(GetDlgItem(hDlg, IDC_RESOLVE_LIST_MATCHES), message, wParam, lParam);
  435. break;
  436. case WM_COMMAND:
  437. switch (GET_WM_COMMAND_ID(wParam,lParam))
  438. {
  439. default:
  440. return ProcessActionCommands((LPIAB) lpRI->lpIAB,
  441. GetDlgItem(hDlg, IDC_RESOLVE_LIST_MATCHES),
  442. hDlg, message, wParam, lParam);
  443. break;
  444. case IDM_LVCONTEXT_DELETE: //We renamed the delete on the context menu to say TEXT("Show more Names")
  445. case IDC_RESOLVE_BUTTON_BROWSE:
  446. GetWindowText(hDlg, szBuf, ARRAYSIZE(szBuf));
  447. lpRI->hWndParent = hDlg;
  448. hr = HrShowPickUserDialog(lpRI, szBuf);
  449. if(!HR_FAILED(hr))
  450. {
  451. if(lpRI->lpContentsList)
  452. ClearListView( GetDlgItem(hDlg, IDC_RESOLVE_LIST_MATCHES),
  453. &(lpRI->lpContentsList));
  454. ExitResolveDialog(hDlg, lpRI, RESOLVE_OK);
  455. // EndDialog( hDlg, RESOLVE_OK);
  456. }
  457. else
  458. {
  459. if(hr != MAPI_E_USER_CANCEL)
  460. {
  461. // Some error occured .. dont know what .. but since this dialog
  462. // will stick around, need to warn the user about it ...
  463. ShowMessageBox(hDlg,idsCouldNotSelectUser,MB_ICONERROR | MB_OK);
  464. }
  465. }
  466. break;
  467. case IDOK:
  468. case IDC_RESOLVE_BUTTON_OK:
  469. if (GetLVSelectedItem(GetDlgItem(hDlg, IDC_RESOLVE_LIST_MATCHES),lpRI))
  470. ExitResolveDialog(hDlg, lpRI, RESOLVE_OK);
  471. break;
  472. case IDCANCEL:
  473. case IDC_RESOLVE_BUTTON_CANCEL:
  474. ExitResolveDialog(hDlg, lpRI, RESOLVE_CANCEL);
  475. break;
  476. case IDM_LVCONTEXT_NEWCONTACT:
  477. case IDC_RESOLVE_BUTTON_NEWCONTACT:
  478. hr = HrShowNewEntryFromResolve(lpRI,hDlg,MAPI_MAILUSER);
  479. if (!HR_FAILED(hr))
  480. ExitResolveDialog(hDlg, lpRI, RESOLVE_OK);
  481. break;
  482. case IDM_LVCONTEXT_NEWGROUP:
  483. // case IDC_RESOLVE_BUTTON_NEWCONTACT:
  484. hr = HrShowNewEntryFromResolve(lpRI,hDlg,MAPI_DISTLIST);
  485. if (!HR_FAILED(hr))
  486. ExitResolveDialog(hDlg, lpRI, RESOLVE_OK);
  487. break;
  488. case IDM_LVCONTEXT_COPY:
  489. HrCopyItemDataToClipboard(hDlg, lpRI->lpIAB, GetDlgItem(hDlg, IDC_RESOLVE_LIST_MATCHES));
  490. break;
  491. case IDM_LVCONTEXT_PROPERTIES:
  492. case IDC_RESOLVE_BUTTON_PROPS:
  493. EnableWindow(GetDlgItem(hDlg, IDC_RESOLVE_BUTTON_PROPS), FALSE);
  494. HrShowLVEntryProperties(GetDlgItem(hDlg,IDC_RESOLVE_LIST_MATCHES), 0,
  495. lpRI->lpIAB, NULL);
  496. EnableWindow(GetDlgItem(hDlg, IDC_RESOLVE_BUTTON_PROPS), TRUE);
  497. break;
  498. }
  499. break;
  500. case WM_CLOSE:
  501. //treat it like a cancel button
  502. SendMessage (hDlg, WM_COMMAND, (WPARAM) IDC_RESOLVE_BUTTON_CANCEL, 0);
  503. break;
  504. case WM_CONTEXTMENU:
  505. if ((HWND)wParam == GetDlgItem(hDlg,IDC_RESOLVE_LIST_MATCHES))
  506. {
  507. ShowLVContextMenu( lvDialogResolve, (HWND)wParam, NULL, lParam, NULL,lpRI->lpIAB, NULL);
  508. }
  509. else
  510. {
  511. WABWinHelp((HWND) wParam,
  512. g_szWABHelpFileName,
  513. HELP_CONTEXTMENU,
  514. (DWORD_PTR)(LPVOID) rgReslvHelpIDs );
  515. }
  516. break;
  517. case WM_HELP:
  518. WABWinHelp(((LPHELPINFO)lParam)->hItemHandle,
  519. g_szWABHelpFileName,
  520. HELP_WM_HELP,
  521. (DWORD_PTR)(LPSTR) rgReslvHelpIDs );
  522. break;
  523. case WM_NOTIFY:
  524. switch((int) wParam)
  525. {
  526. case IDC_RESOLVE_LIST_MATCHES:
  527. return ProcessResolveLVNotifications(hDlg,message,wParam,lParam);
  528. }
  529. break;
  530. }
  531. return TRUE;
  532. }
  533. /////////////////////////////////////////////////////////////
  534. //
  535. // Processes Notification messages for the list view control
  536. //
  537. //
  538. ////////////////////////////////////////////////////////////
  539. BOOL ProcessResolveLVNotifications(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  540. {
  541. NM_LISTVIEW * pNm = (NM_LISTVIEW *)lParam;
  542. switch(pNm->hdr.code)
  543. {
  544. case NM_DBLCLK:
  545. // Doubleclick on the list view is equivalent to a OK with a selected item
  546. SendMessage(hDlg, WM_COMMAND, (WPARAM) IDOK/*IDC_RESOLVE_BUTTON_OK*/, 0);
  547. break;
  548. case NM_CUSTOMDRAW:
  549. return (0 != ProcessLVCustomDraw(hDlg, lParam, TRUE));
  550. break;
  551. }
  552. return FALSE;
  553. }
  554. //////////////////////////////////////////////////////////////////////////////
  555. //
  556. //
  557. // Pops up the New Entry dialog and then replaces the old entry with the
  558. // newly created entry ...
  559. //
  560. //////////////////////////////////////////////////////////////////////////////
  561. HRESULT HrShowNewEntryFromResolve(LPRESOLVE_INFO lpRI, HWND hWndParent, ULONG ulObjectType)
  562. {
  563. ULONG cbEID=0;
  564. LPENTRYID lpEID=NULL;
  565. HRESULT hr = hrSuccess;
  566. ULONG cbTplEID = 0;
  567. LPENTRYID lpTplEID = NULL;
  568. //OutputDebugString( TEXT("HrShowNewEntryFromResolve entry\n"));
  569. if (ulObjectType!=MAPI_MAILUSER && ulObjectType!=MAPI_DISTLIST)
  570. goto out;
  571. if(HR_FAILED(hr = HrGetWABTemplateID( lpRI->lpIAB,
  572. ulObjectType,
  573. &cbTplEID,
  574. &lpTplEID)))
  575. {
  576. DebugPrintError(( TEXT("HrGetWABTemplateID failed: %x\n"), hr));
  577. goto out;
  578. }
  579. if (HR_FAILED(hr = (lpRI->lpIAB)->lpVtbl->NewEntry( lpRI->lpIAB,
  580. (ULONG_PTR) hWndParent,
  581. 0,
  582. 0,NULL,
  583. cbTplEID,lpTplEID,
  584. &cbEID,&lpEID)))
  585. {
  586. DebugPrintError(( TEXT("NewEntry failed: %x\n"),hr));
  587. goto out;
  588. }
  589. // We created a new entry, and we want to use it to replace the old unresolved entry
  590. hr = HrMergeSelectionWithOriginal(lpRI, cbEID, lpEID);
  591. out:
  592. FreeBufferAndNull(&lpEID);
  593. FreeBufferAndNull(&lpTplEID);
  594. //OutputDebugString( TEXT("HrShowNewEntryFromResolve exit\n"));
  595. return hr;
  596. }
  597. ////////////////////////////////////////////////////////////////
  598. //
  599. // Takes entry id of users selection and returns it appropriately ...
  600. //
  601. //
  602. ////////////////////////////////////////////////////////////////
  603. HRESULT HrMergeSelectionWithOriginal(LPRESOLVE_INFO lpRI,
  604. ULONG cbEID,
  605. LPENTRYID lpEID)
  606. {
  607. HRESULT hr = hrSuccess;
  608. ULONG cValues = 0;
  609. LPSPropValue lpPropArray = NULL;
  610. LPADRLIST lpAdrList = *(lpRI->lppAdrList);
  611. SCODE sc;
  612. ULONG nIndex = lpRI->nIndex;
  613. //OutputDebugString( TEXT("HrMergeSelectionWithOriginal entry\n"));
  614. hr = HrGetPropArray((lpRI->lpIAB),
  615. (LPSPropTagArray) &ptaResolveDefaults,
  616. cbEID,
  617. lpEID,
  618. lpRI->bUnicode ? MAPI_UNICODE : 0,
  619. &cValues,
  620. &lpPropArray);
  621. if (HR_FAILED(hr)) goto out;
  622. if ((!cValues) || (!lpPropArray))
  623. {
  624. hr = E_FAIL;
  625. goto out;
  626. }
  627. else
  628. {
  629. LPSPropValue lpPropArrayNew = NULL;
  630. ULONG cValuesNew = 0;
  631. sc = ScMergePropValues( lpAdrList->aEntries[nIndex].cValues,
  632. lpAdrList->aEntries[nIndex].rgPropVals,
  633. cValues,
  634. lpPropArray,
  635. &cValuesNew,
  636. &lpPropArrayNew);
  637. if (sc != S_OK)
  638. {
  639. hr = ResultFromScode(sc);
  640. goto out;
  641. }
  642. if ((lpPropArrayNew) && (cValuesNew > 0))
  643. {
  644. // [PaulHi] Raid 69325
  645. // We need to convert these properties to ANSI since we are now the
  646. // UNICODE WAB and if our client is !MAPI_UNICODE
  647. if (!(lpRI->bUnicode))
  648. {
  649. if(sc = ScConvertWPropsToA((LPALLOCATEMORE) (&MAPIAllocateMore), lpPropArrayNew, cValuesNew, 0))
  650. goto out;
  651. }
  652. MAPIFreeBuffer(lpAdrList->aEntries[nIndex].rgPropVals);
  653. lpAdrList->aEntries[nIndex].rgPropVals = lpPropArrayNew;
  654. lpAdrList->aEntries[nIndex].cValues = cValuesNew;
  655. }
  656. }
  657. hr = hrSuccess;
  658. out:
  659. if (lpPropArray)
  660. MAPIFreeBuffer(lpPropArray);
  661. //OutputDebugString( TEXT("HrMergeSelectionWithOriginal exit\n"));
  662. return hr;
  663. }
  664. ////////////////////////////////////////////////////////////////////////////////////////
  665. //
  666. // HrShowPickuserDialog - shows the pick user dialog
  667. //
  668. ////////////////////////////////////////////////////////////////////////////////////////
  669. HRESULT HrShowPickUserDialog(LPRESOLVE_INFO lpRI,
  670. LPTSTR lpszCaption)
  671. {
  672. LPADRLIST lpAdrList = *(lpRI->lppAdrList);
  673. ULONG nIndex = lpRI->nIndex;
  674. LPTSTR lpszDisplayName = lpRI->lpszDisplayName;
  675. LPADRLIST lpAdrListSingle = NULL;
  676. ADRPARM AdrParms = {0};
  677. SCODE sc;
  678. HRESULT hr = hrSuccess;
  679. DWORD cchSize = 0;
  680. //OutputDebugString( TEXT("HrShowPickUserDialog entry\n"));
  681. // create an AdrList structure which we pass to Address ... to show UI
  682. // We pass in the bare minimum props here which are - Display Name and Entry ID field (which is really NULL)
  683. // The Address UI, if successful, gives us a whole list of props back which we merge with
  684. // the original list, overwriting what we got back fresh ...
  685. sc = MAPIAllocateBuffer(sizeof(ADRLIST) + sizeof(ADRENTRY), &lpAdrListSingle);
  686. if (sc != S_OK)
  687. {
  688. hr = ResultFromScode(sc);
  689. goto out;
  690. }
  691. lpAdrListSingle->cEntries = 1;
  692. lpAdrListSingle->aEntries[0].ulReserved1 = 0;
  693. lpAdrListSingle->aEntries[0].cValues = TOTAL_ADRLIST_PROPS;
  694. sc = MAPIAllocateBuffer( TOTAL_ADRLIST_PROPS * sizeof(SPropValue),
  695. (LPVOID *) (&(lpAdrListSingle->aEntries[0].rgPropVals)));
  696. if (sc != S_OK)
  697. {
  698. hr = ResultFromScode(sc);
  699. goto out;
  700. }
  701. lpAdrListSingle->aEntries[0].rgPropVals[propPR_DISPLAY_NAME].ulPropTag = PR_DISPLAY_NAME;
  702. cchSize = (lstrlen(lpszDisplayName)+1);
  703. sc = MAPIAllocateMore((sizeof(TCHAR) * cchSize),
  704. lpAdrListSingle->aEntries[0].rgPropVals,
  705. (LPVOID *) (&lpAdrListSingle->aEntries[0].rgPropVals[propPR_DISPLAY_NAME].Value.LPSZ));
  706. if (sc != S_OK)
  707. {
  708. hr = ResultFromScode(sc);
  709. goto out;
  710. }
  711. StrCpyN(lpAdrListSingle->aEntries[0].rgPropVals[propPR_DISPLAY_NAME].Value.LPSZ, lpszDisplayName, cchSize);
  712. lpAdrListSingle->aEntries[0].rgPropVals[propPR_ENTRYID].ulPropTag = PR_ENTRYID;
  713. lpAdrListSingle->aEntries[0].rgPropVals[propPR_ENTRYID].Value.bin.cb = 0;
  714. lpAdrListSingle->aEntries[0].rgPropVals[propPR_ENTRYID].Value.bin.lpb = NULL;
  715. AdrParms.cDestFields = 0;
  716. AdrParms.ulFlags = DIALOG_MODAL | ADDRESS_ONE | MAPI_UNICODE;
  717. AdrParms.lpszCaption = lpszCaption;
  718. if (!HR_FAILED(hr = (lpRI->lpIAB)->lpVtbl->Address(
  719. lpRI->lpIAB,
  720. (PULONG_PTR) &(lpRI->hWndParent),
  721. &AdrParms,
  722. &lpAdrListSingle)))
  723. {
  724. // We successfully selected some user and the lpAdrListSingle contains
  725. // a new set of lpProps for that user ...
  726. //
  727. LPSPropValue lpPropArrayNew = NULL;
  728. ULONG cValuesNew = 0;
  729. sc = ScMergePropValues( lpAdrList->aEntries[nIndex].cValues,
  730. lpAdrList->aEntries[nIndex].rgPropVals,
  731. lpAdrListSingle->aEntries[0].cValues,
  732. lpAdrListSingle->aEntries[0].rgPropVals,
  733. &cValuesNew,
  734. &lpPropArrayNew);
  735. if (sc != S_OK)
  736. {
  737. hr = ResultFromScode(sc);
  738. goto out;
  739. }
  740. if ((lpPropArrayNew) && (cValuesNew > 0))
  741. {
  742. // [PaulHi] Raid 69325
  743. // We need to convert these properties to ANSI since we are now the
  744. // UNICODE WAB and if our client is !MAPI_UNICODE
  745. if (!(lpRI->bUnicode))
  746. {
  747. if(sc = ScConvertWPropsToA((LPALLOCATEMORE) (&MAPIAllocateMore), lpPropArrayNew, cValuesNew, 0))
  748. goto out;
  749. }
  750. MAPIFreeBuffer(lpAdrList->aEntries[nIndex].rgPropVals);
  751. lpAdrList->aEntries[nIndex].rgPropVals = lpPropArrayNew;
  752. lpAdrList->aEntries[nIndex].cValues = cValuesNew;
  753. }
  754. }
  755. out:
  756. if (lpAdrListSingle)
  757. {
  758. FreePadrlist(lpAdrListSingle);
  759. }
  760. //OutputDebugString( TEXT("HrShowPickUserDialog exit\n"));
  761. return hr;
  762. }
  763. //$$/////////////////////////////////////////////////////////////////////////////////
  764. //
  765. //
  766. // HrFillLVWithMatches - fills the list view with close matches for the given name
  767. //
  768. // Fails (E_FAIL) if it doesnt find anything to fill in the List View
  769. //
  770. //////////////////////////////////////////////////////////////////////////////////////////
  771. HRESULT HrFillLVWithMatches( HWND hWndLV,
  772. LPRESOLVE_INFO lpRI)
  773. {
  774. HRESULT hr = hrSuccess;
  775. LPSBinary * lprgsbEntryIDs = NULL;
  776. ULONG iolkci=0, colkci = 0;
  777. OlkContInfo *rgolkci;
  778. ULONG * lpcValues = NULL;
  779. ULONG i = 0, j = 0;
  780. LPSRowSet lpSRowSet = NULL;
  781. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  782. ULONG ulFlags = AB_FUZZY_FIND_ALL;
  783. EnterCriticalSection(&(((LPIAB)(lpRI->lpIAB))->cs));
  784. if (pt_bIsWABOpenExSession)
  785. {
  786. colkci = ((LPIAB)(lpRI->lpIAB))->lpPropertyStore->colkci;
  787. Assert(colkci);
  788. rgolkci = ((LPIAB)(lpRI->lpIAB))->lpPropertyStore->rgolkci;
  789. Assert(rgolkci);
  790. }
  791. else
  792. if (bAreWABAPIProfileAware((LPIAB)lpRI->lpIAB))
  793. {
  794. colkci = ((LPIAB)(lpRI->lpIAB))->cwabci;
  795. Assert(colkci);
  796. rgolkci = ((LPIAB)(lpRI->lpIAB))->rgwabci;
  797. Assert(rgolkci);
  798. if(colkci > 1 && !lpRI->lpMapiTable)
  799. ulFlags |= AB_FUZZY_FIND_PROFILEFOLDERONLY;
  800. }
  801. else
  802. colkci = 1;
  803. lprgsbEntryIDs = LocalAlloc(LMEM_ZEROINIT, colkci*sizeof(LPSBinary));
  804. lpcValues = LocalAlloc(LMEM_ZEROINIT, colkci*sizeof(ULONG));
  805. if(!lprgsbEntryIDs || !lpcValues)
  806. {
  807. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  808. goto out;
  809. }
  810. //
  811. // First search the property store
  812. //
  813. if(!(lpRI->lpMapiTable))
  814. {
  815. // if we dont have a ambiguous table to look in then that means we look in the
  816. // property store for ambiguous stuff ...
  817. while (iolkci < colkci)
  818. {
  819. hr = HrFindFuzzyRecordMatches(
  820. ((LPIAB)(lpRI->lpIAB))->lpPropertyStore->hPropertyStore,
  821. (colkci == 1) ? NULL : rgolkci[iolkci].lpEntryID,
  822. lpRI->lpszDisplayName,
  823. ulFlags, //flags
  824. &(lpcValues[iolkci]),
  825. &(lprgsbEntryIDs[iolkci]));
  826. iolkci++;
  827. }
  828. if (HR_FAILED(hr))
  829. goto out;
  830. if(bAreWABAPIProfileAware((LPIAB)lpRI->lpIAB))
  831. {
  832. // it's possible that nothing in the profile matched but other stuff in the WAB matched
  833. // Doublecheck that if we found nothing in the profile, we can search the whole WAB
  834. ULONG nCount = 0;
  835. for(i=0;i<colkci;i++)
  836. nCount += lpcValues[i];
  837. if(!nCount)
  838. {
  839. // search the whole WAB
  840. hr = HrFindFuzzyRecordMatches(
  841. ((LPIAB)(lpRI->lpIAB))->lpPropertyStore->hPropertyStore,
  842. NULL,
  843. lpRI->lpszDisplayName,
  844. AB_FUZZY_FIND_ALL, //flags
  845. &(lpcValues[0]),
  846. &(lprgsbEntryIDs[0]));
  847. }
  848. }
  849. // Now we have a list of EntryIDs
  850. // Use them to populate the List View
  851. //
  852. // We can
  853. // (a) Read the entryids one by one and fill the list view
  854. // AddWABEntryToListView
  855. // or
  856. // (b) We can create an lpContentsList and fill it in one shot
  857. // HrFillListView
  858. // We'll go with (a) for now
  859. // If performance is bad, do (b)
  860. for(i=0;i<colkci;i++)
  861. {
  862. for(j=0;j<lpcValues[i];j++)
  863. {
  864. AddWABEntryToListView( lpRI->lpIAB,
  865. hWndLV,
  866. lprgsbEntryIDs[i][j].cb,
  867. (LPENTRYID) lprgsbEntryIDs[i][j].lpb,
  868. &(lpRI->lpContentsList));
  869. }
  870. }
  871. }
  872. else if(lpRI->lpMapiTable)
  873. {
  874. // if there is a MAPI ambiguous contents table associated with this display name
  875. // use it to further fill in the lpContentsList
  876. BOOL bUnicode = ((LPVUE)lpRI->lpMapiTable)->lptadParent->bMAPIUnicodeTable;
  877. hr = HrQueryAllRows(lpRI->lpMapiTable,
  878. NULL,
  879. NULL,
  880. NULL,
  881. 0,
  882. &lpSRowSet);
  883. if (HR_FAILED(hr))
  884. {
  885. DebugPrintError(( TEXT("HrQueryAllRows Failed: %x\n"),hr));
  886. goto out;
  887. }
  888. for(i=0;i<lpSRowSet->cRows;i++)
  889. {
  890. LPSPropValue lpPropArray = lpSRowSet->aRow[i].lpProps;
  891. ULONG ulcPropCount = lpSRowSet->aRow[i].cValues;
  892. LPRECIPIENT_INFO lpItem = LocalAlloc(LMEM_ZEROINIT, sizeof(RECIPIENT_INFO));
  893. if (!lpItem)
  894. {
  895. DebugPrintError(( TEXT("LocalAlloc Failed \n")));
  896. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  897. goto out;
  898. }
  899. if(!bUnicode) // the props are in ANSI - convert to UNICODE for our use
  900. {
  901. if(ScConvertAPropsToW((LPALLOCATEMORE) (&MAPIAllocateMore), lpPropArray, ulcPropCount, 0))
  902. goto out;
  903. }
  904. GetRecipItemFromPropArray(ulcPropCount, lpPropArray, &lpItem);
  905. // The critical prop is display name - without it we are nothing ...
  906. // If no display name, junk this entry and continue ..
  907. if (!lstrlen(lpItem->szDisplayName) || (lpItem->cbEntryID == 0)) //This entry id is not allowed
  908. {
  909. FreeRecipItem(&lpItem);
  910. continue;
  911. }
  912. AddSingleItemToListView(hWndLV, lpItem);
  913. //
  914. // Hook in the lpItem into the lpContentsList so we can free it later
  915. //
  916. lpItem->lpPrev = NULL;
  917. lpItem->lpNext = lpRI->lpContentsList;
  918. if (lpRI->lpContentsList)
  919. lpRI->lpContentsList->lpPrev = lpItem;
  920. lpRI->lpContentsList = lpItem;
  921. lpItem = NULL;
  922. } //for i ....
  923. }
  924. //
  925. // If, after all this we still have an empty list box, we will report a failure
  926. //
  927. if(ListView_GetItemCount(hWndLV)<=0)
  928. {
  929. DebugPrintTrace(( TEXT("Empty List View - no matches found\n")));
  930. hr = E_FAIL;
  931. goto out;
  932. }
  933. out:
  934. for(i=0;i<colkci;i++)
  935. {
  936. FreeEntryIDs(((LPIAB)(lpRI->lpIAB))->lpPropertyStore->hPropertyStore,
  937. lpcValues[i],
  938. lprgsbEntryIDs[i]);
  939. }
  940. if(lpcValues)
  941. LocalFree(lpcValues);
  942. if(lprgsbEntryIDs)
  943. LocalFree(lprgsbEntryIDs);
  944. if (lpSRowSet)
  945. FreeProws(lpSRowSet);
  946. //
  947. // ReSet the ListView SortAscending style off
  948. //
  949. // SetWindowLong(hWndLV, GWL_STYLE, (dwStyle | LVS_SORTASCENDING));
  950. LeaveCriticalSection(&(((LPIAB)(lpRI->lpIAB))->cs));
  951. return hr;
  952. }
  953. //////////////////////////////////////////////////////////////////////////
  954. //
  955. // Returns the item selected in the list view
  956. //
  957. ////////////////////////////////////////////////////////////////////////
  958. BOOL GetLVSelectedItem(HWND hWndLV, LPRESOLVE_INFO lpRI)
  959. {
  960. int iItemIndex = 0;
  961. LV_ITEM lvi = {0};
  962. LPRECIPIENT_INFO lpItem;
  963. BOOL bRet = FALSE;
  964. //OutputDebugString( TEXT("GetLVSelectedItem Entry\n"));
  965. if (ListView_GetSelectedCount(hWndLV) != 1)
  966. goto out;
  967. iItemIndex = ListView_GetNextItem(hWndLV, -1, LVNI_SELECTED);
  968. lpItem = GetItemFromLV(hWndLV, iItemIndex);
  969. if(lpItem)
  970. HrMergeSelectionWithOriginal(lpRI,lpItem->cbEntryID,lpItem->lpEntryID);
  971. else
  972. goto out;
  973. bRet = TRUE;
  974. out:
  975. //OutputDebugString( TEXT("GetLVSelectedItem Exit\n"));
  976. return bRet;
  977. }
  978. ////////////////////////////////////////////////////////////////////////
  979. //
  980. // Generic exit function
  981. //
  982. ////////////////////////////////////////////////////////////////////////
  983. void ExitResolveDialog(HWND hDlg, LPRESOLVE_INFO lpRI, int nRetVal)
  984. {
  985. HWND hWndLV = GetDlgItem(hDlg, IDC_RESOLVE_LIST_MATCHES);
  986. //OutputDebugString( TEXT("ExitResolveDialog Entry\n"));
  987. if(lpRI->lpContentsList)
  988. {
  989. ClearListView(hWndLV,&(lpRI->lpContentsList));
  990. }
  991. if(ListView_GetItemCount(hWndLV) > 0)
  992. ListView_DeleteAllItems(hWndLV);
  993. EndDialog(hDlg, nRetVal);
  994. //OutputDebugString( TEXT("ExitResolveDialog Exit\n"));
  995. return;
  996. }