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.

2651 lines
102 KiB

  1. /*--------------------------------------------------------------
  2. *
  3. *
  4. * ui_addr.c - contains stuff for showing the :Address UI
  5. *
  6. *
  7. *
  8. *
  9. *
  10. *
  11. *
  12. --------------------------------------------------------------*/
  13. #include "_apipch.h"
  14. extern HINSTANCE ghCommCtrlDLLInst;
  15. #define SET_UNICODE_STR(lp1,lp2,lpAdrParms) if(lpAdrParms->ulFlags & MAPI_UNICODE)\
  16. lp1 = (LPWSTR)lp2; \
  17. else \
  18. lp1 = ConvertAtoW((LPSTR)lp2); \
  19. #define FREE_UNICODE_STR(lp1,lp2) if(lp1 != lp2) LocalFreeAndNull(&lp1);
  20. typedef struct _AddressParms
  21. {
  22. LPADRBOOK lpIAB; //Stores a pointer to the ADRBOOK object
  23. LPADRPARM lpAdrParms; //AdrParms structure passed into Address
  24. LPADRLIST *lppAdrList; //AdrList of input names
  25. HANDLE hPropertyStore; //pointer to the property store
  26. int DialogState; //Identifies the ongoing function
  27. LPRECIPIENT_INFO lpContentsList;//Contains a list of entries in the contents structure
  28. LPRECIPIENT_INFO lpListTo; //Entries in the To Well
  29. LPRECIPIENT_INFO lpListCC; //Entries in the CC well
  30. LPRECIPIENT_INFO lpListBCC; //Entries in the BCC well
  31. SORT_INFO SortInfo; //Contains current sort info
  32. int nContextID; //identifies which list view called the context menu
  33. BOOL bDontRefresh; //Used to ensure that nothing refreshes during modal operations
  34. BOOL bLDAPinProgress;
  35. HCURSOR hWaitCur;
  36. int nRetVal;
  37. LPMAPIADVISESINK lpAdviseSink;
  38. ULONG ulAdviseConnection;
  39. BOOL bDeferNotification; // Used to defer next notification request
  40. HWND hDlg;
  41. HWND hWndAddr;
  42. } ADDRESS_PARMS, *LPADDRESS_PARMS;
  43. enum _lppAdrListReturnedProps
  44. {
  45. propPR_DISPLAY_NAME,
  46. propPR_ENTRYID,
  47. propPR_RECIPIENT_TYPE,
  48. TOTAL_ADRLIST_PROPS
  49. };
  50. static DWORD rgAddrHelpIDs[] =
  51. {
  52. IDC_ADDRBK_EDIT_QUICKFIND, IDH_WAB_PICK_RECIP_TYPE_NAME,
  53. IDC_ADDRBK_STATIC_CONTENTS, IDH_WAB_PICK_RECIP_NAME_LIST,
  54. IDC_ADDRBK_LIST_ADDRESSES, IDH_WAB_PICK_RECIP_NAME_LIST,
  55. IDC_ADDRBK_BUTTON_PROPS, IDH_WAB_PICK_RECIP_NAME_PROPERTIES,
  56. IDC_ADDRBK_BUTTON_NEW, IDH_WAB_PICK_RECIP_NAME_NEW,
  57. IDC_ADDRBK_BUTTON_TO, IDH_WAB_PICK_RECIP_NAME_TO_BUTTON,
  58. IDC_ADDRBK_BUTTON_CC, IDH_WAB_PICK_RECIP_NAME_CC_BUTTON,
  59. IDC_ADDRBK_BUTTON_BCC, IDH_WAB_PICK_RECIP_NAME_BCC_BUTTON,
  60. IDC_ADDRBK_LIST_TO, IDH_WAB_PICK_RECIP_NAME_TO_LIST,
  61. IDC_ADDRBK_LIST_CC, IDH_WAB_PICK_RECIP_NAME_CC_LIST,
  62. IDC_ADDRBK_LIST_BCC, IDH_WAB_PICK_RECIP_NAME_BCC_LIST,
  63. IDC_ADDRBK_BUTTON_DELETE, IDH_WAB_PICK_RECIP_NAME_DELETE,
  64. IDC_ADDRBK_BUTTON_NEWGROUP, IDH_WAB_PICK_RECIP_NAME_NEW_GROUP,
  65. IDC_ADDRBK_STATIC_RECIP_TITLE, IDH_WAB_COMM_GROUPBOX,
  66. IDC_ADDRBK_BUTTON_FIND, IDH_WAB_PICK_RECIP_NAME_FIND,
  67. IDC_ADDRBK_COMBO_CONT, IDH_WAB_GROUPS_CONTACTS_FOLDER,
  68. 0,0
  69. };
  70. // forward declarations
  71. INT_PTR CALLBACK fnAddress(HWND hDlg,
  72. UINT message,
  73. WPARAM wParam,
  74. LPARAM lParam);
  75. BOOL SetAddressBookUI(HWND hDlg,
  76. LPADDRESS_PARMS lpAP);
  77. void FillListFromCurrentContainer(HWND hDlg, LPADDRESS_PARMS lpAP);
  78. BOOL FillWells(HWND hDlg, LPADRLIST lpAdrList, LPADRPARM lpAdrParms, LPRECIPIENT_INFO * lppListTo, LPRECIPIENT_INFO * lppListCC, LPRECIPIENT_INFO * lppListBCC);
  79. BOOL ListDeleteItem(HWND hDlg, int CtlID, LPRECIPIENT_INFO * lppList);
  80. BOOL ListAddItem(HWND hDlg, HWND hWndAddr, int CtlID, LPRECIPIENT_INFO * lppList, ULONG RecipientType);
  81. void UpdateLVItems(HWND hWndLV,LPTSTR lpszName);
  82. void ShowAddrBkLVProps(LPIAB lpIAB, HWND hDlg, HWND hWndAddr, LPADDRESS_PARMS lpAP, LPFILETIME lpftLast);
  83. HRESULT HrUpdateAdrListEntry( LPADRBOOK lpIAB,
  84. LPENTRYID lpEntryID,
  85. ULONG cbEntryID,
  86. ULONG ulFlags,
  87. LPADRLIST * lppAdrList);
  88. enum _AddressDialogReturnValues
  89. {
  90. ADDRESS_RESET = 0, //Blank initialization value
  91. ADDRESS_CANCEL,
  92. ADDRESS_OK,
  93. };
  94. //$$/////////////////////////////////////////////////////////////////////////////////////////
  95. //
  96. // FillContainerCombo - Fills the container combo with container names
  97. //
  98. /////////////////////////////////////////////////////////////////////////////////////////////
  99. void FillContainerCombo(HWND hWndCombo, LPIAB lpIAB)
  100. {
  101. ULONG iolkci, colkci;
  102. OlkContInfo *rgolkci;
  103. int nPos, nDefault=0;
  104. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  105. // Clear out the combo
  106. SendMessage(hWndCombo, CB_RESETCONTENT, 0, 0);
  107. Assert(lpIAB);
  108. EnterCriticalSection(&lpIAB->cs);
  109. if(pt_bIsWABOpenExSession || bIsWABSessionProfileAware(lpIAB))
  110. {
  111. colkci = pt_bIsWABOpenExSession ? lpIAB->lpPropertyStore->colkci : lpIAB->cwabci;
  112. Assert(colkci);
  113. rgolkci = lpIAB->lpPropertyStore->colkci ? lpIAB->lpPropertyStore->rgolkci : lpIAB->rgwabci;
  114. Assert(rgolkci);
  115. // Add the multiple folders here
  116. for(iolkci = 0; iolkci < colkci; iolkci++)
  117. {
  118. nPos = (int) SendMessage(hWndCombo, CB_ADDSTRING, 0, (LPARAM) rgolkci[iolkci].lpszName);
  119. if(nPos != CB_ERR)
  120. SendMessage(hWndCombo, CB_SETITEMDATA, (WPARAM)nPos, (LPARAM) (DWORD_PTR)(iolkci==0 ? NULL : rgolkci[iolkci].lpEntryID));
  121. if( bIsThereACurrentUser(lpIAB) &&
  122. !lstrcmpi(lpIAB->lpWABCurrentUserFolder->lpFolderName, rgolkci[iolkci].lpszName) &&//folder names are unique
  123. nPos != CB_ERR)
  124. {
  125. nDefault = nPos;
  126. }
  127. }
  128. }
  129. LeaveCriticalSection(&lpIAB->cs);
  130. SendMessage(hWndCombo, CB_SETCURSEL, (WPARAM) nDefault, 0);
  131. }
  132. //$$*------------------------------------------------------------------------
  133. //| IAddrBook::Advise::OnNotify handler
  134. //|
  135. //*------------------------------------------------------------------------
  136. ULONG AddrAdviseOnNotify(LPVOID lpvContext, ULONG cNotif, LPNOTIFICATION lpNotif)
  137. {
  138. LPADDRESS_PARMS lpAP = (LPADDRESS_PARMS) lpvContext;
  139. DebugTrace( TEXT("+++ AddrAdviseOnNotify ===\n"));
  140. if(lpAP->bDeferNotification)
  141. {
  142. DebugTrace( TEXT("+++ Advise Defered ===\n"));
  143. lpAP->bDeferNotification = FALSE;
  144. return S_OK;
  145. }
  146. if(!lpAP->bDontRefresh)
  147. {
  148. DebugTrace( TEXT("+++ Calling FillListFromCurrentContainer ===\n"));
  149. FillListFromCurrentContainer(lpAP->hDlg, lpAP);
  150. }
  151. return S_OK;
  152. }
  153. /////////////////////////////////////////////////////////////////////////////////
  154. //
  155. // ShowAddressUI - does some parameter checking and calls the PropertySheets
  156. //
  157. //
  158. //
  159. /////////////////////////////////////////////////////////////////////////////////
  160. HRESULT HrShowAddressUI(IN LPADRBOOK lpIAB,
  161. IN HANDLE hPropertyStore,
  162. IN ULONG_PTR * lpulUIParam,
  163. IN LPADRPARM lpAdrParms,
  164. IN LPADRLIST *lppAdrList)
  165. {
  166. HRESULT hr = E_FAIL;
  167. //ADDRESS_PARMS AP = {0};
  168. LPADDRESS_PARMS lpAP = NULL;
  169. TCHAR szBuf[MAX_UI_STR];
  170. HWND hWndParent = NULL;
  171. int nRetVal = 0;
  172. int DialogState = 0;
  173. //Addref the AdrBook object to make sure it stays valid throughout ..
  174. // Remember to release before leaving ...
  175. // NOTE: Must be before any jumps to out!
  176. UlAddRef(lpIAB);
  177. // if no common control, exit
  178. if (NULL == ghCommCtrlDLLInst) {
  179. hr = ResultFromScode(MAPI_E_UNCONFIGURED);
  180. goto out;
  181. }
  182. if (lpulUIParam)
  183. hWndParent = (HWND) *lpulUIParam;
  184. if ( // Can't pick-user with wells
  185. ((lpAdrParms->ulFlags & ADDRESS_ONE) && (lpAdrParms->cDestFields != 0)) ||
  186. // cDestFields has limited for tier 0.5
  187. (lpAdrParms->cDestFields > 3) ||
  188. // Cant pick user without an input lpAdrList
  189. //((lpAdrParms->ulFlags & ADDRESS_ONE) && (*lppAdrList == NULL)) ||
  190. ((lpAdrParms->ulFlags & DIALOG_SDI) && (lpAdrParms->cDestFields != 0)) )
  191. {
  192. hr = MAPI_E_INVALID_PARAMETER;
  193. goto out;
  194. }
  195. //
  196. // The possible states of this dialog box are
  197. // 1. Select recipients Wells shown, returns an AdrList of picked up entries, Cant delete entries
  198. // 2. Select a single user, No wells shown, single selection, cannot delete, must have input Adrlist
  199. // 3. Open for browsing only, multiple selection, can create delete, create, view details
  200. // Determine what the dialog state is
  201. if (lpAdrParms->cDestFields > 0)
  202. {
  203. //lpAP->DialogState = STATE_SELECT_RECIPIENTS;
  204. DialogState = STATE_SELECT_RECIPIENTS;
  205. }
  206. else if (lpAdrParms->ulFlags & ADDRESS_ONE)
  207. {
  208. DialogState = STATE_PICK_USER;
  209. }
  210. else if (lpAdrParms->ulFlags & DIALOG_MODAL)
  211. {
  212. DialogState = STATE_BROWSE_MODAL;
  213. }
  214. else if (lpAdrParms->ulFlags & DIALOG_SDI)
  215. {
  216. DialogState = STATE_BROWSE;
  217. }
  218. if (DialogState == STATE_BROWSE)
  219. {
  220. // Show the browse window and leave
  221. //
  222. HWND hWndAB = NULL;
  223. hWndAB = hCreateAddressBookWindow( lpIAB,
  224. hWndParent,
  225. lpAdrParms);
  226. if (hWndAB)
  227. {
  228. *lpulUIParam = (ULONG_PTR) hWndAB;
  229. hr = S_OK;
  230. }
  231. goto out;
  232. }
  233. lpAP = LocalAlloc(LMEM_ZEROINIT, sizeof(ADDRESS_PARMS));
  234. if (!lpAP)
  235. {
  236. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  237. goto out;
  238. }
  239. lpAP->DialogState = DialogState;
  240. lpAP->lpIAB = lpIAB;
  241. lpAP->lpAdrParms = lpAdrParms;
  242. lpAP->lppAdrList = lppAdrList;
  243. lpAP->hPropertyStore = hPropertyStore;
  244. ReadRegistrySortInfo((LPIAB)lpIAB, &(lpAP->SortInfo));
  245. lpAP->lpContentsList = NULL;
  246. lpAP->bDontRefresh = FALSE;
  247. lpAP->bLDAPinProgress = FALSE;
  248. lpAP->hWaitCur = NULL;
  249. HrAllocAdviseSink(&AddrAdviseOnNotify, (LPVOID) lpAP, &(lpAP->lpAdviseSink));
  250. nRetVal = (int) DialogBoxParam( hinstMapiX,
  251. MAKEINTRESOURCE(IDD_DIALOG_ADDRESSBOOK),
  252. hWndParent,
  253. fnAddress,
  254. (LPARAM) lpAP);
  255. switch(nRetVal)
  256. {
  257. case -1: //some error occured
  258. hr = E_FAIL;
  259. break;
  260. case ADDRESS_CANCEL:
  261. hr = MAPI_E_USER_CANCEL;
  262. break;
  263. case ADDRESS_OK:
  264. default:
  265. hr = S_OK;
  266. break;
  267. }
  268. if(lpAP->lpAdviseSink)
  269. {
  270. lpAP->lpIAB->lpVtbl->Unadvise(lpAP->lpIAB, lpAP->ulAdviseConnection);
  271. lpAP->lpAdviseSink->lpVtbl->Release(lpAP->lpAdviseSink);
  272. lpAP->lpAdviseSink = NULL;
  273. lpAP->ulAdviseConnection = 0;
  274. }
  275. out:
  276. lpIAB->lpVtbl->Release(lpIAB);
  277. LocalFreeAndNull(&lpAP);
  278. return hr;
  279. }
  280. #define lpAP_lppContentsList (&(lpAP->lpContentsList))
  281. #define lpAP_lppListTo (&(lpAP->lpListTo))
  282. #define lpAP_lppListCC (&(lpAP->lpListCC))
  283. #define lpAP_lppListBCC (&(lpAP->lpListBCC))
  284. #define lpAP_bDontRefresh (lpAP->bDontRefresh)
  285. #define _hWndAddr lpAP->hWndAddr
  286. //$$/////////////////////////////////////////////////////////////////////////////
  287. //
  288. // GetCurrentComboSelection - Get the current selection from the combo
  289. //
  290. /////////////////////////////////////////////////////////////////////////////////
  291. LPSBinary GetCurrentComboSelection(HWND hWndCombo)
  292. {
  293. int nPos = (int) SendMessage(hWndCombo, CB_GETCURSEL, 0, 0);
  294. LPSBinary lpsbCont = NULL;
  295. if(nPos == CB_ERR)
  296. nPos = 0;
  297. lpsbCont = (LPSBinary) SendMessage(hWndCombo, CB_GETITEMDATA, (WPARAM) nPos, 0);
  298. if(CB_ERR == (DWORD_PTR) lpsbCont)
  299. lpsbCont = NULL;
  300. return lpsbCont;
  301. }
  302. //$$/////////////////////////////////////////////////////////////////////////////
  303. //
  304. // FillListFromCurrentContainer - Get the selection from the combo and fill it
  305. //
  306. /////////////////////////////////////////////////////////////////////////////////
  307. void FillListFromCurrentContainer(HWND hDlg, LPADDRESS_PARMS lpAP)
  308. {
  309. HWND hWndAddr = GetDlgItem(hDlg,IDC_ADDRBK_LIST_ADDRESSES);
  310. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  311. LPSBinary lpsbCont = NULL;
  312. if(pt_bIsWABOpenExSession || bIsWABSessionProfileAware((LPIAB)lpAP->lpIAB))
  313. {
  314. HWND hWndCombo = GetDlgItem(hDlg, IDC_ADDRBK_COMBO_CONT);
  315. int nPos = (int) SendMessage(hWndCombo, CB_GETCURSEL, 0, 0);
  316. if(nPos != CB_ERR)
  317. {
  318. // Refill the combo in case the folder list changed
  319. FillContainerCombo(hWndCombo, (LPIAB)lpAP->lpIAB);
  320. nPos = (int) SendMessage(hWndCombo, CB_SETCURSEL, (WPARAM) nPos, 0);
  321. }
  322. lpsbCont = GetCurrentComboSelection(hWndCombo);
  323. }
  324. HrGetWABContents( hWndAddr,
  325. lpAP->lpIAB, lpsbCont,
  326. lpAP->SortInfo, lpAP_lppContentsList);
  327. }
  328. extern BOOL APIENTRY_16 fnFolderDlgProc(HWND hDlg, UINT message, UINT wParam, LPARAM lParam);
  329. /////////////////////////////////////////////////////////////////////////////////
  330. //
  331. // fnAddress - the PropertySheet Message Handler
  332. //
  333. //
  334. //
  335. /////////////////////////////////////////////////////////////////////////////////
  336. INT_PTR CALLBACK fnAddress(HWND hDlg,
  337. UINT message,
  338. WPARAM wParam,
  339. LPARAM lParam)
  340. {
  341. static FILETIME ftLast = {0};
  342. LPADDRESS_PARMS lpAP = (LPADDRESS_PARMS ) GetWindowLongPtr(hDlg,DWLP_USER);
  343. switch(message)
  344. {
  345. case WM_INITDIALOG:
  346. SetWindowLongPtr(hDlg,DWLP_USER,lParam); //Save this for future reference
  347. lpAP = (LPADDRESS_PARMS) lParam;
  348. lpAP->hWndAddr = GetDlgItem(hDlg,IDC_ADDRBK_LIST_ADDRESSES);
  349. lpAP->hDlg = hDlg;
  350. lpAP_bDontRefresh = FALSE;
  351. lpAP->nContextID = IDC_ADDRBK_LIST_ADDRESSES;
  352. SetAddressBookUI(hDlg,lpAP);
  353. // if this is a pick-user dialog, need to have the names by
  354. // first name so we can find the closest match ..
  355. if(lpAP->DialogState == STATE_PICK_USER)
  356. (lpAP->SortInfo).bSortByLastName = FALSE;
  357. FillListFromCurrentContainer(hDlg, lpAP);
  358. if (lpAP->DialogState == STATE_SELECT_RECIPIENTS)
  359. {
  360. FillWells(hDlg,*(lpAP->lppAdrList),(lpAP->lpAdrParms),lpAP_lppListTo,lpAP_lppListCC,lpAP_lppListBCC);
  361. // we want to highlight the first item in the list
  362. if (ListView_GetItemCount(_hWndAddr) > 0)
  363. LVSelectItem( _hWndAddr, 0);
  364. }
  365. else if (lpAP->DialogState == STATE_PICK_USER &&
  366. *(lpAP->lppAdrList) )
  367. {
  368. // if this is a pick user dialog, then try to match the supplied name to the
  369. // closest entry in the List Box
  370. if (ListView_GetItemCount(_hWndAddr) > 0)
  371. {
  372. LPTSTR lpszDisplayName = NULL;
  373. ULONG i;
  374. // Scan only the first entry in the lpAdrList for a display name
  375. for(i=0;i< (*(lpAP->lppAdrList))->aEntries[0].cValues;i++)
  376. {
  377. ULONG ulPropTag = PR_DISPLAY_NAME;
  378. if(!(lpAP->lpAdrParms->ulFlags & MAPI_UNICODE))
  379. ulPropTag = CHANGE_PROP_TYPE(ulPropTag, PT_STRING8);
  380. if((*(lpAP->lppAdrList))->aEntries[0].rgPropVals[i].ulPropTag == ulPropTag)
  381. {
  382. SET_UNICODE_STR(lpszDisplayName, (*(lpAP->lppAdrList))->aEntries[0].rgPropVals[i].Value.LPSZ,lpAP->lpAdrParms);
  383. break;
  384. }
  385. }
  386. if (lpszDisplayName)
  387. {
  388. // We have Something to search for
  389. TCHAR szBuf[MAX_UI_STR];
  390. ULONG nLen;
  391. LV_FINDINFO lvF = {0};
  392. // Typically, we are not going to get a full match ...
  393. // Instead we want to make a partial match on disply name.
  394. // The ListViewFindItem does an exact partial match if the supplied
  395. // string matches the first few entries of an existing item
  396. // Hence, to obtain a semi-partial match, we start with the
  397. // original Display Name working our way backwards from last
  398. // character to first character until we get a match or run
  399. // out of characters.
  400. int iItemIndex = -1;
  401. nLen = lstrlen(lpszDisplayName);
  402. if (nLen >= CharSizeOf(szBuf))
  403. nLen = CharSizeOf(szBuf)-1;
  404. lvF.flags = LVFI_PARTIAL | LVFI_STRING;
  405. while((nLen > 0) && (iItemIndex == -1))
  406. {
  407. nLen = TruncatePos(lpszDisplayName, nLen);
  408. if (nLen==0) break;
  409. CopyMemory(szBuf, lpszDisplayName, sizeof(TCHAR)*nLen);
  410. szBuf[nLen] = '\0';
  411. lvF.psz = szBuf;
  412. iItemIndex = ListView_FindItem(_hWndAddr,-1, &lvF);
  413. nLen--;
  414. }
  415. // Set focus to the selected item or to the first item in the list
  416. if (iItemIndex < 0) iItemIndex = 0;
  417. LVSelectItem(_hWndAddr, iItemIndex);
  418. FREE_UNICODE_STR(lpszDisplayName, (*(lpAP->lppAdrList))->aEntries[0].rgPropVals[i].Value.LPSZ);
  419. }
  420. }
  421. }
  422. if(lpAP->lpAdviseSink)
  423. {
  424. // Register for notifications
  425. lpAP->lpIAB->lpVtbl->Advise(lpAP->lpIAB, 0, NULL, fnevObjectModified,
  426. lpAP->lpAdviseSink, &lpAP->ulAdviseConnection);
  427. }
  428. if (ListView_GetSelectedCount(_hWndAddr) <= 0)
  429. LVSelectItem(_hWndAddr, 0);
  430. // if we want the user to pick something actively, we disable OK until they click on something
  431. // or do something specific ..
  432. if( lpAP->DialogState == STATE_PICK_USER )
  433. {
  434. EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
  435. SendMessage (hDlg, DM_SETDEFID, IDCANCEL, 0);
  436. }
  437. SetFocus(GetDlgItem(hDlg,IDC_ADDRBK_EDIT_QUICKFIND));
  438. return FALSE;
  439. // return TRUE;
  440. break;
  441. case WM_SYSCOLORCHANGE:
  442. //Forward any system changes to the list view
  443. SendMessage(_hWndAddr, message, wParam, lParam);
  444. SetColumnHeaderBmp(_hWndAddr, lpAP->SortInfo);
  445. break;
  446. case WM_HELP:
  447. WABWinHelp(((LPHELPINFO)lParam)->hItemHandle,
  448. g_szWABHelpFileName,
  449. HELP_WM_HELP,
  450. (DWORD_PTR)(LPSTR) rgAddrHelpIDs );
  451. break;
  452. case WM_SETCURSOR:
  453. if (lpAP->bLDAPinProgress)
  454. {
  455. SetCursor(lpAP->hWaitCur);
  456. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, MAKELONG(TRUE, 0));
  457. return(TRUE);
  458. }
  459. break;
  460. case WM_COMMAND:
  461. switch(GET_WM_COMMAND_CMD(wParam,lParam)) //check the notification code
  462. {
  463. case CBN_SELCHANGE:
  464. FillListFromCurrentContainer(hDlg, lpAP);
  465. break;
  466. }
  467. switch(GET_WM_COMMAND_ID(wParam, lParam))
  468. {
  469. default:
  470. if (lpAP->nContextID != -1)
  471. {
  472. LRESULT fRet = FALSE;
  473. lpAP_bDontRefresh = TRUE;
  474. fRet = ProcessActionCommands((LPIAB) lpAP->lpIAB,_hWndAddr,
  475. hDlg, message, wParam, lParam);
  476. lpAP_bDontRefresh = FALSE;
  477. return fRet;
  478. }
  479. break;
  480. case IDC_ADDRBK_BUTTON_DELETE:
  481. if(!lpAP->bLDAPinProgress)
  482. {
  483. lpAP->bLDAPinProgress = TRUE;
  484. lpAP_bDontRefresh = TRUE;
  485. DeleteSelectedItems(_hWndAddr, lpAP->lpIAB, lpAP->hPropertyStore, &ftLast);
  486. lpAP->bDeferNotification = TRUE;
  487. lpAP_bDontRefresh = FALSE;
  488. lpAP->bLDAPinProgress = FALSE;
  489. }
  490. break;
  491. case IDM_LVCONTEXT_DELETE:
  492. if(!lpAP->bLDAPinProgress)
  493. {
  494. lpAP->bLDAPinProgress = TRUE;
  495. switch(lpAP->nContextID)
  496. {
  497. case IDC_ADDRBK_LIST_ADDRESSES:
  498. lpAP_bDontRefresh = TRUE;
  499. DeleteSelectedItems(_hWndAddr, lpAP->lpIAB, lpAP->hPropertyStore, &ftLast);
  500. lpAP->bDeferNotification = TRUE;
  501. lpAP_bDontRefresh = FALSE;
  502. break;
  503. case IDC_ADDRBK_LIST_TO:
  504. ListDeleteItem(hDlg, IDC_ADDRBK_LIST_TO, lpAP_lppListTo);
  505. break;
  506. case IDC_ADDRBK_LIST_CC:
  507. ListDeleteItem(hDlg, IDC_ADDRBK_LIST_CC, lpAP_lppListCC);
  508. break;
  509. case IDC_ADDRBK_LIST_BCC:
  510. ListDeleteItem(hDlg, IDC_ADDRBK_LIST_BCC, lpAP_lppListBCC);
  511. break;
  512. default:
  513. break;
  514. }
  515. lpAP->bLDAPinProgress = FALSE;
  516. }
  517. break;
  518. case IDM_LVCONTEXT_COPY:
  519. lpAP_bDontRefresh = TRUE;
  520. HrCopyItemDataToClipboard(hDlg, lpAP->lpIAB, GetDlgItem(hDlg,lpAP->nContextID));
  521. lpAP_bDontRefresh = FALSE;
  522. break;
  523. case IDM_LVCONTEXT_PROPERTIES:
  524. case IDC_ADDRBK_BUTTON_PROPS:
  525. if(!lpAP->bLDAPinProgress)
  526. {
  527. lpAP->bLDAPinProgress = TRUE;
  528. if (lpAP->nContextID != -1)
  529. {
  530. lpAP_bDontRefresh = TRUE;
  531. ShowAddrBkLVProps((LPIAB)lpAP->lpIAB, hDlg, GetDlgItem(hDlg, lpAP->nContextID), lpAP, &ftLast);
  532. lpAP->bDeferNotification = TRUE;
  533. lpAP_bDontRefresh = FALSE;
  534. }
  535. lpAP->bLDAPinProgress = FALSE;
  536. }
  537. break;
  538. /* Uncomment to enable NEW_FOLDER functionality from this dialog
  539. case IDM_LVCONTEXT_NEWFOLDER:
  540. {
  541. TCHAR sz[MAX_UI_STR];
  542. LPTSTR lpsz = NULL;
  543. *sz = '\0';
  544. if( IDCANCEL != DialogBoxParam( hinstMapiX, MAKEINTRESOURCE(IDD_DIALOG_FOLDER),
  545. hDlg, fnFolderDlgProc, (LPARAM) sz)
  546. && lstrlen(sz))
  547. {
  548. // if we're here we have a valid folder name ..
  549. if(!HR_FAILED(HrCreateNewFolder((LPIAB)lpAP->lpIAB, sz, NULL, FALSE, NULL, NULL)))
  550. {
  551. int i,nTotal;
  552. HWND hWndC = GetDlgItem(hDlg, IDC_ADDRBK_COMBO_CONT);
  553. // Fill in the Combo with the container names
  554. FillContainerCombo(hWndC, (LPIAB)lpAP->lpIAB);
  555. nTotal = SendMessage(hWndC, CB_GETCOUNT, 0, 0);
  556. if(nTotal != CB_ERR)
  557. {
  558. // Find the item we just added in the combo and set the sel on it
  559. TCHAR szC[MAX_UI_STR];
  560. for(i=0;i<nTotal;i++)
  561. {
  562. *szC = '\0';
  563. SendMessage(hWndC, CB_GETLBTEXT, (WPARAM) i, (LPARAM) szC);
  564. if(!lstrcmpi(sz, szC))
  565. {
  566. SendMessage(hWndC, CB_SETCURSEL, (WPARAM) i, 0);
  567. break;
  568. }
  569. }
  570. }
  571. FillListFromCurrentContainer(hDlg, lpAP);
  572. }
  573. }
  574. }
  575. break;
  576. */
  577. case IDM_LVCONTEXT_NEWCONTACT:
  578. case IDC_ADDRBK_BUTTON_NEW:
  579. // only difference between contact and group is the object being added
  580. case IDM_LVCONTEXT_NEWGROUP:
  581. case IDC_ADDRBK_BUTTON_NEWGROUP:
  582. if(!lpAP->bLDAPinProgress)
  583. {
  584. ULONG cbEID = 0;
  585. LPENTRYID lpEID = NULL;
  586. int nID = GET_WM_COMMAND_ID(wParam, lParam);
  587. ULONG ulObjType = (nID == IDM_LVCONTEXT_NEWCONTACT || nID == IDC_ADDRBK_BUTTON_NEW) ? MAPI_MAILUSER : MAPI_DISTLIST;
  588. LPSBinary lpsbContEID = NULL;
  589. if(bIsWABSessionProfileAware((LPIAB)lpAP->lpIAB))
  590. lpsbContEID = GetCurrentComboSelection(GetDlgItem(hDlg,IDC_ADDRBK_COMBO_CONT));
  591. lpAP->bLDAPinProgress = TRUE;
  592. lpAP_bDontRefresh = TRUE;
  593. AddNewObjectToListViewEx( lpAP->lpIAB, _hWndAddr, NULL, NULL,
  594. lpsbContEID,
  595. ulObjType,
  596. &(lpAP->SortInfo), lpAP_lppContentsList, &ftLast, &cbEID, &lpEID);
  597. FreeBufferAndNull(&lpEID);
  598. SetFocus(_hWndAddr);
  599. lpAP->bDeferNotification = TRUE;
  600. lpAP_bDontRefresh = FALSE;
  601. lpAP->bLDAPinProgress = FALSE;
  602. }
  603. break;
  604. case IDM_LVCONTEXT_ADDWELL1:
  605. case IDC_ADDRBK_BUTTON_TO:
  606. if(!lpAP->bLDAPinProgress)
  607. {
  608. ULONG ulMapiTo = MAPI_TO;
  609. lpAP->bLDAPinProgress = TRUE;
  610. if ((lpAP->lpAdrParms->cDestFields > 0) && (lpAP->lpAdrParms->lpulDestComps))
  611. {
  612. ulMapiTo = lpAP->lpAdrParms->lpulDestComps[0];
  613. }
  614. if(ListAddItem(hDlg, _hWndAddr, IDC_ADDRBK_LIST_TO, lpAP_lppListTo, ulMapiTo))
  615. SendMessage (hDlg, DM_SETDEFID, IDOK/*IDC_ADDRBK_BUTTON_OK*/, 0);
  616. lpAP->bLDAPinProgress = FALSE;
  617. }
  618. break;
  619. case IDM_LVCONTEXT_ADDWELL2:
  620. case IDC_ADDRBK_BUTTON_CC:
  621. if(!lpAP->bLDAPinProgress)
  622. {
  623. ULONG ulMapiCC = MAPI_CC;
  624. lpAP->bLDAPinProgress = TRUE;
  625. if ((lpAP->lpAdrParms->cDestFields > 0) && (lpAP->lpAdrParms->lpulDestComps))
  626. {
  627. ulMapiCC = lpAP->lpAdrParms->lpulDestComps[1];
  628. }
  629. if(ListAddItem(hDlg, _hWndAddr, IDC_ADDRBK_LIST_CC, lpAP_lppListCC, ulMapiCC))
  630. SendMessage (hDlg, DM_SETDEFID, IDOK/*IDC_ADDRBK_BUTTON_OK*/, 0);
  631. lpAP->bLDAPinProgress = FALSE;
  632. }
  633. break;
  634. case IDM_LVCONTEXT_ADDWELL3:
  635. case IDC_ADDRBK_BUTTON_BCC:
  636. if(!lpAP->bLDAPinProgress)
  637. {
  638. ULONG ulMapiBCC = MAPI_BCC;
  639. lpAP->bLDAPinProgress = TRUE;
  640. if ((lpAP->lpAdrParms->cDestFields > 0) && (lpAP->lpAdrParms->lpulDestComps))
  641. {
  642. ulMapiBCC = lpAP->lpAdrParms->lpulDestComps[2];
  643. }
  644. if(ListAddItem(hDlg, _hWndAddr, IDC_ADDRBK_LIST_BCC, lpAP_lppListBCC, ulMapiBCC))
  645. SendMessage (hDlg, DM_SETDEFID, IDOK/*IDC_ADDRBK_BUTTON_OK*/, 0);
  646. lpAP->bLDAPinProgress = FALSE;
  647. }
  648. break;
  649. case IDM_LVCONTEXT_FIND:
  650. case IDC_ADDRBK_BUTTON_FIND:
  651. if(!lpAP->bLDAPinProgress)
  652. {
  653. ADRPARM_FINDINFO apfi = {0};
  654. LPADRPARM_FINDINFO lpapfi = NULL;
  655. ULONG ulOldFlags = lpAP->lpAdrParms->ulFlags;
  656. lpAP->bLDAPinProgress = TRUE;
  657. apfi.DialogState = lpAP->DialogState;
  658. if (lpAP->DialogState==STATE_SELECT_RECIPIENTS)
  659. {
  660. apfi.lpAdrParms = lpAP->lpAdrParms;
  661. apfi.lppTo = lpAP_lppListTo;
  662. apfi.lppCC = lpAP_lppListCC;
  663. apfi.lppBCC = lpAP_lppListBCC;
  664. lpapfi = &apfi;
  665. }
  666. else if (lpAP->DialogState == STATE_PICK_USER)
  667. {
  668. TCHAR sz[MAX_UI_STR];
  669. LPTSTR lpsz = NULL;
  670. LoadString(hinstMapiX, idsPickUserSelect, sz, CharSizeOf(sz));
  671. lpsz = (LPTSTR) sz;
  672. apfi.lpAdrParms = lpAP->lpAdrParms;
  673. apfi.lpAdrParms->cDestFields = 1;
  674. apfi.lpAdrParms->lppszDestTitles = &lpsz; // <TBD> use resource
  675. apfi.lpAdrParms->ulFlags |= MAPI_UNICODE;
  676. apfi.cbEntryID = 0;
  677. apfi.lpEntryID = NULL;
  678. apfi.nRetVal = 0;
  679. lpapfi = &apfi;
  680. {
  681. // Setup the Find persistent info to show the name we are trying to resolve
  682. ULONG i;
  683. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  684. for(i=0;i<ldspMAX;i++)
  685. {
  686. pt_LDAPsp.szData[i][0] = TEXT('\0');
  687. }
  688. if(*(lpAP->lppAdrList))
  689. {
  690. for(i=0;i<(*(lpAP->lppAdrList))->aEntries[0].cValues;i++)
  691. {
  692. ULONG ulPropTag = PR_DISPLAY_NAME;
  693. if(!(lpAP->lpAdrParms->ulFlags & MAPI_UNICODE))
  694. ulPropTag = CHANGE_PROP_TYPE(ulPropTag, PT_STRING8);
  695. if ((*(lpAP->lppAdrList))->aEntries[0].rgPropVals[i].ulPropTag == ulPropTag)
  696. {
  697. LPTSTR lpTitle = NULL;
  698. SET_UNICODE_STR(lpTitle, (*(lpAP->lppAdrList))->aEntries[0].rgPropVals[i].Value.LPSZ,lpAP->lpAdrParms);
  699. StrCpyN(pt_LDAPsp.szData[ldspDisplayName], lpTitle, ARRAYSIZE(pt_LDAPsp.szData[ldspDisplayName]));
  700. FREE_UNICODE_STR(lpTitle, (*(lpAP->lppAdrList))->aEntries[0].rgPropVals[i].Value.LPSZ);
  701. break;
  702. }
  703. }
  704. }
  705. }
  706. }
  707. //lpAP_bDontRefresh = TRUE;
  708. HrShowSearchDialog(lpAP->lpIAB,
  709. hDlg,
  710. lpapfi,
  711. (LPLDAPURL) NULL,
  712. &(lpAP->SortInfo));
  713. //lpAP_bDontRefresh = FALSE;
  714. lpAP->bLDAPinProgress = FALSE;
  715. // reset
  716. lpAP->lpAdrParms->ulFlags = ulOldFlags;
  717. if (lpAP->DialogState == STATE_PICK_USER)
  718. {
  719. // Reset these fake values
  720. lpAP->lpAdrParms->cDestFields = 0;
  721. lpAP->lpAdrParms->lppszDestTitles = NULL; // <TBD> use resource
  722. // If the above dialog was CANCELed or CLOSEd, we dont do anything
  723. // If the above dialog was closed with the Use button, then we basically
  724. // have the person we were looking for .. we will just return that name
  725. // and EntryID because that is all we need to return
  726. if((lpapfi->nRetVal == SEARCH_USE) &&
  727. lpapfi->lpEntryID &&
  728. lpapfi->cbEntryID)
  729. {
  730. HCURSOR hOldCur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  731. // Prevent the user from doing anything on this window ..
  732. EnableWindow(hDlg, FALSE);
  733. // Figure out what to do here ...
  734. // We could add a hidden item to the listview, select it and send
  735. // an ok message to the dialog which would then do the needful.
  736. if(HR_FAILED(HrUpdateAdrListEntry(
  737. lpAP->lpIAB,
  738. lpapfi->lpEntryID,
  739. lpapfi->cbEntryID,
  740. (lpAP->lpAdrParms->ulFlags & MAPI_UNICODE)?MAPI_UNICODE:0,
  741. lpAP->lppAdrList)))
  742. {
  743. lpAP->nRetVal = -1;
  744. }
  745. else
  746. {
  747. lpAP->nRetVal = ADDRESS_OK;
  748. }
  749. LocalFreeAndNull(&(lpapfi->lpEntryID));
  750. lpapfi->cbEntryID = 0;
  751. // Since we've done our processing, we'll fall thru to
  752. // the cancel dialog
  753. SetCursor(hOldCur);
  754. SendMessage (hDlg, WM_COMMAND, (WPARAM) IDC_ADDRBK_BUTTON_CANCEL, 0);
  755. }
  756. }
  757. }
  758. break;
  759. case IDC_ADDRBK_EDIT_QUICKFIND:
  760. if(!lpAP->bLDAPinProgress)
  761. {
  762. lpAP->bLDAPinProgress = TRUE;
  763. switch(HIWORD(wParam)) //check the notification code
  764. {
  765. case EN_CHANGE: //edit box changed
  766. /***/
  767. DoLVQuickFind((HWND)lParam,_hWndAddr);
  768. /***
  769. DoLVQuickFilter(lpAP->lpIAB,
  770. (HWND)lParam,
  771. _hWndAddr,
  772. &(lpAP->SortInfo),
  773. AB_FUZZY_FIND_NAME | AB_FUZZY_FIND_EMAIL,
  774. 1,
  775. lpAP_lppContentsList);
  776. ***/
  777. break;
  778. }
  779. lpAP->bLDAPinProgress = FALSE;
  780. }
  781. break;
  782. case IDOK:
  783. case IDC_ADDRBK_BUTTON_OK:
  784. if(!lpAP->bLDAPinProgress)
  785. {
  786. HCURSOR hOldCur;
  787. lpAP->nRetVal = ADDRESS_OK;
  788. lpAP->hWaitCur = LoadCursor(NULL, IDC_WAIT);
  789. hOldCur = SetCursor(lpAP->hWaitCur);
  790. lpAP->bLDAPinProgress = TRUE;
  791. SetWindowLongPtr(hDlg, DWLP_MSGRESULT, MAKELONG(TRUE, 0));
  792. //ShowWindow(hDlg, SW_HIDE);
  793. //EnableWindow(hDlg, FALSE);
  794. //SetWindowPos(hDlg, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
  795. EnableWindow(GetDlgItem(hDlg, IDOK), FALSE);
  796. EnableWindow(GetDlgItem(hDlg, IDCANCEL), FALSE);
  797. EnableWindow(GetDlgItem(hDlg, IDC_ADDRBK_BUTTON_FIND), FALSE);
  798. EnableWindow(GetDlgItem(hDlg, IDC_ADDRBK_BUTTON_TO), FALSE);
  799. EnableWindow(GetDlgItem(hDlg, IDC_ADDRBK_BUTTON_CC), FALSE);
  800. EnableWindow(GetDlgItem(hDlg, IDC_ADDRBK_BUTTON_BCC), FALSE);
  801. EnableWindow(GetDlgItem(hDlg, IDC_ADDRBK_LIST_TO), FALSE);
  802. EnableWindow(GetDlgItem(hDlg, IDC_ADDRBK_LIST_CC), FALSE);
  803. EnableWindow(GetDlgItem(hDlg, IDC_ADDRBK_LIST_BCC), FALSE);
  804. EnableWindow(_hWndAddr, FALSE);
  805. //
  806. // Do TEXT("OK") stuff here and then Fall Thru to the cancel stuff
  807. // in PSN_RESET where we clean up
  808. //
  809. // if the ADDRESS_ONE flag was set we're supposed to return the
  810. // selected entry
  811. //
  812. // else if wells were displayed we return the recipients in the AdrList
  813. //
  814. // else we dont change the AdrList ..
  815. //
  816. if (lpAP->DialogState == STATE_PICK_USER)
  817. {
  818. // We have been asked to return an entry in the LpAdrList,
  819. // we dont care about recipient type - just Display Name and EntryID
  820. // First check if anything is selected at all
  821. int iItemIndex = ListView_GetNextItem(_hWndAddr,-1,LVNI_SELECTED);
  822. if (iItemIndex != -1)
  823. {
  824. LPRECIPIENT_INFO lpItem = GetItemFromLV(_hWndAddr, iItemIndex);
  825. if (lpItem)
  826. {
  827. if(HR_FAILED(HrUpdateAdrListEntry(
  828. lpAP->lpIAB,
  829. lpItem->lpEntryID,
  830. lpItem->cbEntryID,
  831. (lpAP->lpAdrParms->ulFlags & MAPI_UNICODE)?MAPI_UNICODE:0,
  832. lpAP->lppAdrList)))
  833. {
  834. lpAP->nRetVal = -1;
  835. }
  836. }
  837. }
  838. }
  839. else if ((lpAP->DialogState==STATE_SELECT_RECIPIENTS) && ((*lpAP_lppListTo)||(*lpAP_lppListCC)||(*lpAP_lppListBCC)))
  840. {
  841. //
  842. //if user selected something in the TO/CC wells, we want to return
  843. //a relevant AdrList back ...
  844. //
  845. ULONG ulcEntryCount = 0;
  846. LPRECIPIENT_INFO lpItem = NULL;
  847. //
  848. // get a count of how many elements we need to return
  849. //
  850. lpItem = (*lpAP_lppListTo);
  851. while(lpItem)
  852. {
  853. ulcEntryCount++;
  854. lpItem = lpItem->lpNext;
  855. }
  856. lpItem = (*lpAP_lppListCC);
  857. while(lpItem)
  858. {
  859. ulcEntryCount++;
  860. lpItem = lpItem->lpNext;
  861. }
  862. lpItem = (*lpAP_lppListBCC);
  863. while(lpItem)
  864. {
  865. ulcEntryCount++;
  866. lpItem = lpItem->lpNext;
  867. }
  868. if (ulcEntryCount != 0)
  869. {
  870. ULONG nIndex = 0;
  871. LPADRENTRY lpAdrEntryTemp = NULL;
  872. LPADRLIST lpAdrList = NULL;
  873. SCODE sc;
  874. BOOL bProcessingCC = FALSE;
  875. //
  876. // if there was something in the passed in AdrList, free it and
  877. // create a new list
  878. //
  879. if(!FAILED(sc = MAPIAllocateBuffer( sizeof(ADRLIST) + ulcEntryCount * sizeof(ADRENTRY),
  880. &lpAdrList)))
  881. {
  882. lpAdrList->cEntries = ulcEntryCount;
  883. nIndex = 0;
  884. // Start getting items from the TO list
  885. lpItem = (*lpAP_lppListTo);
  886. while(nIndex < ulcEntryCount)
  887. {
  888. if (lpItem == NULL)
  889. {
  890. if (bProcessingCC == FALSE)
  891. {
  892. lpItem = (*lpAP_lppListCC);
  893. bProcessingCC = TRUE;
  894. }
  895. else
  896. lpItem = (*lpAP_lppListBCC);
  897. }
  898. if (lpItem != NULL)
  899. {
  900. LPSPropValue rgProps = NULL;
  901. ULONG cValues = 0;
  902. LPSPropValue lpPropArrayNew = NULL;
  903. ULONG cValuesNew = 0;
  904. LPTSTR lpszTemp = NULL;
  905. LPVOID lpbTemp = NULL;
  906. ULONG i = 0;
  907. SCODE sc;
  908. HRESULT hr = hrSuccess;
  909. //reset hr
  910. hr = hrSuccess;
  911. // We are walking through our linked lists representing the TO and CC
  912. // selected recipients. We want to return proper set of existing props
  913. // for all the resolved users and the passed in set of props for the
  914. // unresolved user. Hence we compare to see what we can get for each
  915. // individual user. For unresolved users, the only distinctive criteria is
  916. // their display name .. we have no other information .. <TBD> this is
  917. // problematic because if there are 2 entries in the input adrlist with the
  918. // same unresolved display name, even if they have difference rgPropVals
  919. // we might end up giving them identical ones back .... what to do .. <TBD>
  920. // Items that have entry ids are resolved ... items that dont have entryids
  921. // are not resolved ...
  922. if (lpItem->cbEntryID != 0)
  923. {
  924. // if this was an item from the original list .. we dont really
  925. // want to mess with it irrespective of whether it is a resolved
  926. // or unresolved entry.
  927. // However, if this is a new entry, then we want to get its
  928. // minimum props from the store ...
  929. if (lpItem->ulOldAdrListEntryNumber == 0)
  930. {
  931. //resolved entry
  932. hr = HrGetPropArray(lpAP->lpIAB,
  933. (LPSPropTagArray) &ptaResolveDefaults,
  934. lpItem->cbEntryID,
  935. lpItem->lpEntryID,
  936. (lpAP->lpAdrParms->ulFlags & MAPI_UNICODE) ? MAPI_UNICODE : 0,
  937. &cValues,
  938. &rgProps);
  939. }
  940. else
  941. {
  942. rgProps = NULL;
  943. cValues = 0;
  944. }
  945. if (!HR_FAILED(hr))
  946. {
  947. if(lpItem->ulOldAdrListEntryNumber != 0)
  948. {
  949. ULONG index = lpItem->ulOldAdrListEntryNumber - 1; //remember the increment-by-one ..
  950. // This is from the original entry list ...
  951. // We want to merge the newly generated properties with the old
  952. // original properties .. the original properties will include a
  953. // PR_RECIPIENT_TYPE (or this entry would have been rejected)
  954. sc = ScMergePropValues( (*(lpAP->lppAdrList))->aEntries[index].cValues,
  955. (*(lpAP->lppAdrList))->aEntries[index].rgPropVals,
  956. cValues,
  957. rgProps,
  958. &cValuesNew,
  959. &lpPropArrayNew);
  960. if (sc != S_OK)
  961. {
  962. // If errors then dont merge .. just take the temp set of props
  963. // in rgProps
  964. if (lpPropArrayNew)
  965. MAPIFreeBuffer(lpPropArrayNew);
  966. lpPropArrayNew = rgProps;
  967. cValuesNew = cValues;
  968. lpAP->nRetVal = -1;
  969. }
  970. else
  971. {
  972. // merged successfully, discard the temp sets of props
  973. if (rgProps)
  974. MAPIFreeBuffer(rgProps);
  975. }
  976. }
  977. else
  978. {
  979. // totally new item
  980. // we have to give it a valid PR_RECIPIENT_TYPE
  981. // so create a new one and merge it with the above props
  982. SPropValue Prop = {0};
  983. Prop.ulPropTag = PR_RECIPIENT_TYPE;
  984. Prop.Value.l = lpItem->ulRecipientType;
  985. sc = ScMergePropValues( 1,
  986. &Prop,
  987. cValues,
  988. rgProps,
  989. &cValuesNew,
  990. &lpPropArrayNew);
  991. if (sc != S_OK)
  992. {
  993. // oops this failed
  994. if (lpPropArrayNew)
  995. MAPIFreeBuffer(lpPropArrayNew);
  996. lpPropArrayNew = NULL;
  997. lpAP->nRetVal = -1;
  998. }
  999. //free rgProps
  1000. if (rgProps)
  1001. MAPIFreeBuffer(rgProps);
  1002. } // end have previous adr list items
  1003. // [PaulHi] 2/15/99 Make sure that the new property string
  1004. // values are converted to ANSI if our client is non-UNICODE.
  1005. if ( !FAILED(sc) && !(lpAP->lpAdrParms->ulFlags & MAPI_UNICODE) && lpPropArrayNew )
  1006. {
  1007. sc = ScConvertWPropsToA((LPALLOCATEMORE) (&MAPIAllocateMore), lpPropArrayNew, cValuesNew, 0);
  1008. if (FAILED(sc))
  1009. {
  1010. if (lpPropArrayNew)
  1011. MAPIFreeBuffer(lpPropArrayNew);
  1012. lpPropArrayNew = NULL;
  1013. lpAP->nRetVal = -1;
  1014. }
  1015. }
  1016. } // end GetProps succeeded
  1017. }
  1018. else
  1019. {
  1020. // this is an unresolved entry
  1021. // we need to get its original sets of props from the original AdrList
  1022. if (lpItem->ulOldAdrListEntryNumber == 0)
  1023. {
  1024. // ouch - this kind of error shouldnt have happened
  1025. DebugPrintError(( TEXT("Address: Unresolved entry has no index number!!!\n")));
  1026. lpAP->nRetVal = -1; //error code
  1027. }
  1028. else
  1029. {
  1030. ULONG cb = 0;
  1031. ULONG index = lpItem->ulOldAdrListEntryNumber - 1; //remember to decrement the +1 increment
  1032. cValuesNew = (*(lpAP->lppAdrList))->aEntries[index].cValues;
  1033. // copy over the props from our old array into a new one
  1034. if (!(FAILED(sc = ScCountProps( cValuesNew,
  1035. (*(lpAP->lppAdrList))->aEntries[index].rgPropVals,
  1036. &cb))))
  1037. {
  1038. if (!(FAILED(sc = MAPIAllocateBuffer(cb, &lpPropArrayNew))))
  1039. {
  1040. if (FAILED(sc = ScCopyProps( cValuesNew,
  1041. (*(lpAP->lppAdrList))->aEntries[index].rgPropVals,
  1042. lpPropArrayNew,
  1043. NULL)))
  1044. {
  1045. DebugPrintError(( TEXT("Address: ScCopyProps fails!!!\n")));
  1046. lpAP->nRetVal = -1;
  1047. }
  1048. }
  1049. else
  1050. {
  1051. lpAP->nRetVal = -1;
  1052. }
  1053. }
  1054. else
  1055. {
  1056. lpAP->nRetVal = -1;
  1057. }
  1058. }
  1059. }
  1060. // At this point, if we've still got no errors,
  1061. // we should have a valid lpPropArrayNew and cValuesNew which we should
  1062. // be able to add to our new AdrList
  1063. if (lpAP->nRetVal != -1)
  1064. {
  1065. lpAdrList->aEntries[nIndex].cValues = cValuesNew;
  1066. lpAdrList->aEntries[nIndex].rgPropVals = lpPropArrayNew;
  1067. }
  1068. else
  1069. {
  1070. // some error
  1071. if (lpPropArrayNew)
  1072. {
  1073. MAPIFreeBuffer(lpPropArrayNew);
  1074. lpPropArrayNew = NULL;
  1075. }
  1076. }
  1077. lpItem = lpItem->lpNext;
  1078. nIndex++;
  1079. }
  1080. }
  1081. if (*(lpAP->lppAdrList))
  1082. {
  1083. FreePadrlist(*(lpAP->lppAdrList));
  1084. }
  1085. *(lpAP->lppAdrList) = lpAdrList;
  1086. }
  1087. }
  1088. }
  1089. else if ((lpAP->DialogState==STATE_SELECT_RECIPIENTS) && ((*lpAP_lppListTo)==NULL) && ((*lpAP_lppListCC)==NULL) && ((*lpAP_lppListBCC)==NULL))
  1090. {
  1091. // we were asked to select recipients but if these pointers are null
  1092. // then the user deleted the entries in the wells and we thus dont
  1093. // want to return anything. So free the lpaddrlist
  1094. // and make it NULL
  1095. if (*(lpAP->lppAdrList))
  1096. {
  1097. // Bug 27483 - dont NULL the lpAdrList - just set cEntries to 0
  1098. ULONG iEntry = 0;
  1099. for (iEntry = 0; iEntry < (*(lpAP->lppAdrList))->cEntries; iEntry++)
  1100. {
  1101. MAPIFreeBuffer((*(lpAP->lppAdrList))->aEntries[iEntry].rgPropVals);
  1102. }
  1103. (*(lpAP->lppAdrList))->cEntries = 0;
  1104. }
  1105. }
  1106. //
  1107. // Save the sort info to the registry
  1108. //
  1109. if(lpAP->DialogState != STATE_PICK_USER)
  1110. WriteRegistrySortInfo((LPIAB)lpAP->lpIAB, lpAP->SortInfo);
  1111. lpAP->bLDAPinProgress = FALSE;
  1112. lpAP->hWaitCur = NULL;
  1113. SetCursor(hOldCur);
  1114. }
  1115. // fall thru to cleanup code
  1116. case IDCANCEL:
  1117. case IDC_ADDRBK_BUTTON_CANCEL:
  1118. if(!lpAP->bLDAPinProgress)
  1119. {
  1120. if ((lpAP->nRetVal != ADDRESS_OK) && // Are we falling thru from above ??
  1121. (lpAP->nRetVal != -1) ) // or did someone trigger an error above ??
  1122. {
  1123. // if not ..
  1124. lpAP->nRetVal = ADDRESS_CANCEL;
  1125. }
  1126. if ((*lpAP_lppContentsList))
  1127. ClearListView( GetDlgItem(hDlg, IDC_ADDRBK_LIST_ADDRESSES),
  1128. lpAP_lppContentsList);
  1129. if ((*lpAP_lppListTo))
  1130. ClearListView( GetDlgItem(hDlg, IDC_ADDRBK_LIST_TO),
  1131. lpAP_lppListTo);
  1132. if ((*lpAP_lppListCC))
  1133. ClearListView( GetDlgItem(hDlg, IDC_ADDRBK_LIST_CC),
  1134. lpAP_lppListCC);
  1135. if ((*lpAP_lppListBCC))
  1136. ClearListView( GetDlgItem(hDlg, IDC_ADDRBK_LIST_BCC),
  1137. lpAP_lppListBCC);
  1138. lpAP->bLDAPinProgress = FALSE;
  1139. EndDialog(hDlg,lpAP->nRetVal);
  1140. return TRUE;
  1141. }
  1142. break;
  1143. }
  1144. break;
  1145. case WM_CLOSE:
  1146. //treat it like a cancel button
  1147. SendMessage (hDlg, WM_COMMAND, (WPARAM) IDC_ADDRBK_BUTTON_CANCEL, 0);
  1148. break;
  1149. case WM_CONTEXTMENU:
  1150. {
  1151. int id = GetDlgCtrlID((HWND)wParam);
  1152. //
  1153. //This call to the context menu may generate any one of several
  1154. //command messages - for properties and for delete, we need to
  1155. //know which List View initiated the command ...
  1156. //
  1157. lpAP->nContextID = id;
  1158. switch(id)
  1159. {
  1160. case IDC_ADDRBK_LIST_ADDRESSES:
  1161. if (lpAP->DialogState == STATE_BROWSE_MODAL)
  1162. ShowLVContextMenu( lvDialogModalABContents,
  1163. (HWND)wParam,
  1164. NULL, //GetDlgItem(hDlg, IDC_ADDRBK_COMBO_SHOWNAMES),
  1165. lParam,
  1166. (LPVOID) lpAP->lpAdrParms,
  1167. lpAP->lpIAB, NULL);
  1168. else
  1169. ShowLVContextMenu( lvDialogABContents,
  1170. (HWND)wParam,
  1171. NULL, //GetDlgItem(hDlg, IDC_ADDRBK_COMBO_SHOWNAMES),
  1172. lParam,
  1173. (LPVOID) lpAP->lpAdrParms,
  1174. lpAP->lpIAB, NULL);
  1175. break;
  1176. case IDC_ADDRBK_LIST_TO:
  1177. ShowLVContextMenu(lvDialogABTo,(HWND)wParam, NULL, lParam, NULL,lpAP->lpIAB, NULL);
  1178. break;
  1179. case IDC_ADDRBK_LIST_BCC:
  1180. ShowLVContextMenu(lvDialogABCC,(HWND)wParam, NULL, lParam, NULL,lpAP->lpIAB, NULL);
  1181. break;
  1182. case IDC_ADDRBK_LIST_CC:
  1183. ShowLVContextMenu(lvDialogABBCC,(HWND)wParam, NULL, lParam, NULL,lpAP->lpIAB, NULL);
  1184. break;
  1185. default:
  1186. //reset it ..
  1187. lpAP->nContextID = -1;
  1188. WABWinHelp((HWND) wParam,
  1189. g_szWABHelpFileName,
  1190. HELP_CONTEXTMENU,
  1191. (DWORD_PTR)(LPVOID) rgAddrHelpIDs );
  1192. break;
  1193. }
  1194. }
  1195. break;
  1196. case WM_NOTIFY:
  1197. {
  1198. LV_DISPINFO * pLvdi = (LV_DISPINFO *)lParam;
  1199. NM_LISTVIEW * pNm = (NM_LISTVIEW *)lParam;
  1200. switch((int) wParam)
  1201. {
  1202. case IDC_ADDRBK_LIST_TO:
  1203. case IDC_ADDRBK_LIST_CC:
  1204. case IDC_ADDRBK_LIST_BCC:
  1205. switch(((LV_DISPINFO *)lParam)->hdr.code)
  1206. {
  1207. case LVN_KEYDOWN:
  1208. switch(((LV_KEYDOWN FAR *) lParam)->wVKey)
  1209. {
  1210. case VK_DELETE:
  1211. if ((int) wParam == IDC_ADDRBK_LIST_TO)
  1212. ListDeleteItem(hDlg, (int) wParam, lpAP_lppListTo);
  1213. else if ((int) wParam == IDC_ADDRBK_LIST_CC)
  1214. ListDeleteItem(hDlg, (int) wParam, lpAP_lppListCC);
  1215. else
  1216. ListDeleteItem(hDlg, (int) wParam, lpAP_lppListBCC);
  1217. break;
  1218. }
  1219. break;
  1220. case NM_SETFOCUS:
  1221. lpAP->nContextID = GetDlgCtrlID(((NM_LISTVIEW *)lParam)->hdr.hwndFrom);
  1222. break;
  1223. case NM_DBLCLK:
  1224. //properties of the item ...
  1225. lpAP->nContextID = GetDlgCtrlID(((NM_LISTVIEW *)lParam)->hdr.hwndFrom);
  1226. SendMessage (hDlg, WM_COMMAND, (WPARAM) IDM_LVCONTEXT_PROPERTIES, 0);
  1227. break;
  1228. case NM_CUSTOMDRAW:
  1229. return ProcessLVCustomDraw(hDlg, lParam, TRUE);
  1230. break;
  1231. }
  1232. break;
  1233. case IDC_ADDRBK_LIST_ADDRESSES:
  1234. switch(pLvdi->hdr.code)
  1235. {
  1236. case LVN_KEYDOWN:
  1237. switch(((LV_KEYDOWN FAR *) lParam)->wVKey)
  1238. {
  1239. case VK_DELETE:
  1240. if (lpAP->DialogState == STATE_BROWSE_MODAL)
  1241. SendMessage(hDlg, WM_COMMAND, IDC_ADDRBK_BUTTON_DELETE, 0);
  1242. break;
  1243. }
  1244. break;
  1245. case LVN_COLUMNCLICK:
  1246. SortListViewColumn((LPIAB)lpAP->lpIAB, pNm->hdr.hwndFrom, pNm->iSubItem, &(lpAP->SortInfo), FALSE);
  1247. break;
  1248. case NM_CLICK:
  1249. case NM_RCLICK:
  1250. if(lpAP->DialogState == STATE_PICK_USER)
  1251. {
  1252. int iItemIndex = ListView_GetNextItem(pNm->hdr.hwndFrom,-1,LVNI_SELECTED);
  1253. if (iItemIndex == -1)
  1254. {
  1255. //Nothing is selected .. dont let them say OK
  1256. EnableWindow(GetDlgItem(hDlg,IDOK/*IDC_ADDRBK_BUTTON_OK*/),FALSE);
  1257. SendMessage (hDlg, DM_SETDEFID, IDCANCEL, 0);
  1258. }
  1259. else
  1260. {
  1261. EnableWindow(GetDlgItem(hDlg,IDOK/*IDC_ADDRBK_BUTTON_OK*/),TRUE);
  1262. SendMessage (hDlg, DM_SETDEFID, IDOK, 0);
  1263. }
  1264. }
  1265. break;
  1266. case NM_SETFOCUS:
  1267. lpAP->nContextID = GetDlgCtrlID(pNm->hdr.hwndFrom);
  1268. if(lpAP->DialogState == STATE_PICK_USER)
  1269. {
  1270. int iItemIndex = ListView_GetNextItem(pNm->hdr.hwndFrom,-1,LVNI_SELECTED);
  1271. if (iItemIndex == -1)
  1272. {
  1273. //Nothing is selected .. dont let them say OK
  1274. EnableWindow(GetDlgItem(hDlg,IDOK/*IDC_ADDRBK_BUTTON_OK*/),FALSE);
  1275. SendMessage (hDlg, DM_SETDEFID, IDCANCEL, 0);
  1276. }
  1277. else
  1278. {
  1279. EnableWindow(GetDlgItem(hDlg,IDOK/*IDC_ADDRBK_BUTTON_OK*/),TRUE);
  1280. SendMessage (hDlg, DM_SETDEFID, IDOK, 0);
  1281. }
  1282. }
  1283. break;
  1284. case NM_DBLCLK:
  1285. {
  1286. //if an entry is selected - do this - otherwise dont do anything
  1287. int iItemIndex = ListView_GetNextItem(pNm->hdr.hwndFrom,-1,LVNI_SELECTED);
  1288. if (iItemIndex == -1)
  1289. break;
  1290. {
  1291. //DWORD dwDefId = SendMessage(hDlg, DM_GETDEFID, 0, 0);
  1292. //if(dwDefId)
  1293. // SendMessage(hDlg, WM_COMMAND, (WPARAM) LOWORD(dwDefId), 0);
  1294. SendMessage(hDlg, WM_COMMAND, (WPARAM) IDC_ADDRBK_BUTTON_TO + lpAP->lpAdrParms->nDestFieldFocus, 0);
  1295. }
  1296. }
  1297. break;
  1298. case NM_CUSTOMDRAW:
  1299. return ProcessLVCustomDraw(hDlg, lParam, TRUE);
  1300. break;
  1301. }
  1302. break;
  1303. }
  1304. }
  1305. break;
  1306. default:
  1307. if( (g_msgMSWheel && message == g_msgMSWheel)
  1308. // || message == WM_MOUSEWHEEL
  1309. )
  1310. {
  1311. if(GetFocus() == GetDlgItem(hDlg, IDC_ADDRBK_LIST_TO))
  1312. SendMessage(GetDlgItem(hDlg, IDC_ADDRBK_LIST_TO), message, wParam, lParam);
  1313. else if(GetFocus() == GetDlgItem(hDlg, IDC_ADDRBK_LIST_CC))
  1314. SendMessage(GetDlgItem(hDlg, IDC_ADDRBK_LIST_CC), message, wParam, lParam);
  1315. else if(GetFocus() == GetDlgItem(hDlg, IDC_ADDRBK_LIST_BCC))
  1316. SendMessage(GetDlgItem(hDlg, IDC_ADDRBK_LIST_TO), message, wParam, lParam);
  1317. else
  1318. SendMessage(_hWndAddr, message, wParam, lParam);
  1319. }
  1320. break;
  1321. }
  1322. return FALSE;
  1323. }
  1324. /////////////////////////////////////////////////////////////////////////////////
  1325. //
  1326. // ListAddItem - Adds an item to the wells
  1327. //
  1328. // hDlg - HWND of parent
  1329. // hWndAddr - HWND of source ListView from which the item will be added
  1330. // CtlID - control ID of the target list view
  1331. // lppList - Item list corresponding to the target list view to which this item will be appended
  1332. // RecipientType - Specified recipient type to tag the new item with
  1333. //
  1334. /////////////////////////////////////////////////////////////////////////////////
  1335. BOOL ListAddItem(HWND hDlg, HWND hWndAddr, int CtlID, LPRECIPIENT_INFO * lppList, ULONG RecipientType)
  1336. {
  1337. BOOL bRet = FALSE;
  1338. int iItemIndex = 0;
  1339. HWND hWndList = GetDlgItem(hDlg,CtlID);
  1340. iItemIndex = ListView_GetNextItem(hWndAddr,-1,LVNI_SELECTED);
  1341. if (iItemIndex != -1)
  1342. {
  1343. int iLastIndex = 0;
  1344. do
  1345. {
  1346. // otherwise get the entry id of this thing
  1347. LPRECIPIENT_INFO lpItem = GetItemFromLV(hWndAddr, iItemIndex);
  1348. if (lpItem)
  1349. {
  1350. LV_ITEM lvI;
  1351. LPRECIPIENT_INFO lpNew = LocalAlloc(LMEM_ZEROINIT, sizeof(RECIPIENT_INFO));
  1352. if(!lpNew)
  1353. {
  1354. DebugPrintError(( TEXT("LocalAlloc failed to allocate memory\n")));
  1355. goto out;
  1356. }
  1357. lpNew->ulObjectType = lpItem->ulObjectType;
  1358. StrCpyN(lpNew->szDisplayName, lpItem->szDisplayName, ARRAYSIZE(lpNew->szDisplayName));
  1359. StrCpyN(lpNew->szByFirstName, lpItem->szByFirstName, ARRAYSIZE(lpNew->szByFirstName));
  1360. StrCpyN(lpNew->szByLastName, lpItem->szByLastName, ARRAYSIZE(lpNew->szByLastName));
  1361. StrCpyN(lpNew->szEmailAddress, lpItem->szEmailAddress, ARRAYSIZE(lpNew->szEmailAddress));
  1362. StrCpyN(lpNew->szHomePhone, lpItem->szHomePhone, ARRAYSIZE(lpNew->szHomePhone));
  1363. StrCpyN(lpNew->szOfficePhone, lpItem->szOfficePhone, ARRAYSIZE(lpNew->szOfficePhone));
  1364. lpNew->bHasCert = lpItem->bHasCert;
  1365. lpNew->ulRecipientType = RecipientType;
  1366. lpNew->ulOldAdrListEntryNumber = 0; //Flag this as not from the original AdrList
  1367. if (lpItem->cbEntryID)
  1368. {
  1369. lpNew->cbEntryID = lpItem->cbEntryID;
  1370. lpNew->lpEntryID = LocalAlloc(LMEM_ZEROINIT, lpItem->cbEntryID);
  1371. if(!lpNew->lpEntryID)
  1372. {
  1373. DebugPrintError(( TEXT("LocalAlloc failed to allocate memory\n")));
  1374. LocalFree(lpNew);
  1375. goto out;
  1376. }
  1377. CopyMemory(lpNew->lpEntryID,lpItem->lpEntryID,lpItem->cbEntryID);
  1378. }
  1379. lpNew->lpNext = (*lppList);
  1380. if (*lppList)
  1381. (*lppList)->lpPrev = lpNew;
  1382. lpNew->lpPrev = NULL;
  1383. (*lppList) = lpNew;
  1384. lvI.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
  1385. lvI.state = 0;
  1386. lvI.stateMask = 0;
  1387. lvI.iSubItem = 0;
  1388. lvI.cchTextMax = MAX_DISPLAY_NAME_LENGTH;
  1389. lvI.iImage = GetWABIconImage(lpNew);
  1390. // now fill in the List
  1391. lvI.iItem = ListView_GetItemCount(hWndList);
  1392. lvI.pszText = lpNew->szDisplayName;
  1393. lvI.lParam = (LPARAM) lpNew;
  1394. ListView_InsertItem(hWndList, &lvI);
  1395. ListView_EnsureVisible(hWndList,ListView_GetItemCount(hWndList)-1,FALSE);
  1396. }
  1397. iLastIndex = iItemIndex;
  1398. // Get next selected item ...
  1399. iItemIndex = ListView_GetNextItem(hWndAddr,iLastIndex,LVNI_SELECTED);
  1400. } while (iItemIndex != -1);
  1401. //SetFocus(hWndAddr);
  1402. }
  1403. else
  1404. {
  1405. ShowMessageBox(hDlg, IDS_ADDRBK_MESSAGE_NO_ITEMS_ADD, MB_ICONEXCLAMATION);
  1406. goto out;
  1407. }
  1408. if((ListView_GetItemCount(hWndList) > 0) &&
  1409. (ListView_GetSelectedCount(hWndList) <= 0))
  1410. LVSelectItem(hWndList, 0);
  1411. bRet = TRUE;
  1412. out:
  1413. return bRet;
  1414. }
  1415. /////////////////////////////////////////////////////////////////////////////////
  1416. //
  1417. // ListDeleteItem - deletes an item from the Wells - unlike the Address COntents list we
  1418. // make sure to delete it here because we want the linked lists to only have valid entries
  1419. //
  1420. //
  1421. /////////////////////////////////////////////////////////////////////////////////
  1422. BOOL ListDeleteItem(HWND hDlg, int CtlID, LPRECIPIENT_INFO * lppList)
  1423. {
  1424. BOOL bRet = TRUE;
  1425. LPRECIPIENT_INFO lpItem = NULL;
  1426. HWND hWndAddr = GetDlgItem(hDlg,CtlID);
  1427. int iItemIndex=0;
  1428. iItemIndex = ListView_GetNextItem(hWndAddr,-1,LVNI_SELECTED);
  1429. if (iItemIndex != -1)
  1430. {
  1431. int iLastItem = 0;
  1432. do
  1433. {
  1434. // otherwise get the entry id of this thing
  1435. lpItem = GetItemFromLV(hWndAddr, iItemIndex);
  1436. if (lpItem)
  1437. {
  1438. // remove this item from our linked list of arrays
  1439. // if this is the first item in the list then handle that special case too
  1440. if ((*lppList) == lpItem)
  1441. (*lppList) = lpItem->lpNext;
  1442. if (lpItem->lpNext)
  1443. lpItem->lpNext->lpPrev = lpItem->lpPrev;
  1444. if (lpItem->lpPrev)
  1445. lpItem->lpPrev->lpNext = lpItem->lpNext;
  1446. // we need to update our display
  1447. ListView_DeleteItem(hWndAddr,iItemIndex);
  1448. //UpdateWindow(hWndAddr);
  1449. FreeRecipItem(&lpItem);
  1450. }
  1451. iLastItem = iItemIndex;
  1452. // Get next selected item ...
  1453. iItemIndex = ListView_GetNextItem(hWndAddr,-1,LVNI_SELECTED);
  1454. }while (iItemIndex != -1);
  1455. // select the previous or next item ...
  1456. if (iLastItem >= ListView_GetItemCount(hWndAddr))
  1457. iLastItem = ListView_GetItemCount(hWndAddr) - 1;
  1458. LVSelectItem(hWndAddr, iLastItem);
  1459. }
  1460. SetFocus(hWndAddr);
  1461. return bRet;
  1462. }
  1463. /////////////////////////////////////////////////////////////////////////////////
  1464. //
  1465. // FillWells - Dismembers the lpAdrList to create the To and CC wells
  1466. //
  1467. // Scans the AdrEntry Structures in the LpAdrList, looks at PR_RECIPIENT_TYPE,
  1468. // ignores entries which it cant understand ... creates a temporary linked
  1469. // list of To and CC recipient lists which are used to populate the
  1470. // To and CC List boxes
  1471. //
  1472. /////////////////////////////////////////////////////////////////////////////////
  1473. BOOL FillWells(HWND hDlg, LPADRLIST lpAdrList, LPADRPARM lpAdrParms, LPRECIPIENT_INFO * lppListTo, LPRECIPIENT_INFO * lppListCC, LPRECIPIENT_INFO * lppListBCC)
  1474. {
  1475. BOOL bRet = FALSE;
  1476. LPRECIPIENT_INFO lpNew = NULL;
  1477. LPADRENTRY lpAdrEntry = NULL;
  1478. ULONG i=0,j=0,nLen=0;
  1479. int index=0;
  1480. LV_ITEM lvI;
  1481. HWND hWndAddr = NULL;
  1482. ULONG ulMapiTo = MAPI_TO;
  1483. ULONG ulMapiCC = MAPI_CC;
  1484. ULONG ulMapiBCC = MAPI_BCC;
  1485. BOOL bUnicode = (lpAdrParms->ulFlags & MAPI_UNICODE);
  1486. *lppListTo = NULL;
  1487. *lppListCC = NULL;
  1488. *lppListBCC = NULL;
  1489. if (lpAdrList == NULL) //nothing to do
  1490. {
  1491. bRet = TRUE;
  1492. goto out;
  1493. }
  1494. //
  1495. // The Input AdrParms structure has a lpulDestComps field that lets the
  1496. // caller specify his own recipient types. If this is missing, we are supposed
  1497. // to use the default recipient types.
  1498. //
  1499. if ((lpAdrParms->cDestFields > 0) && (lpAdrParms->lpulDestComps))
  1500. {
  1501. ULONG i=0;
  1502. for (i=0;i<lpAdrParms->cDestFields;i++)
  1503. {
  1504. switch(i)
  1505. {
  1506. case 0:
  1507. ulMapiTo = lpAdrParms->lpulDestComps[i];
  1508. break;
  1509. case 1:
  1510. ulMapiCC = lpAdrParms->lpulDestComps[i];
  1511. break;
  1512. case 2:
  1513. ulMapiBCC = lpAdrParms->lpulDestComps[i];
  1514. break;
  1515. }
  1516. }
  1517. }
  1518. for(i=0; i < lpAdrList->cEntries; i++)
  1519. {
  1520. lpAdrEntry = &(lpAdrList->aEntries[i]);
  1521. if (lpAdrEntry->cValues != 0)
  1522. {
  1523. TCHAR szBuf[MAX_DISPLAY_NAME_LENGTH];
  1524. ULONG ulRecipientType = 0;
  1525. ULONG ulObjectType = 0;
  1526. ULONG cbEntryID = 0;
  1527. BOOL bHasCert = FALSE;
  1528. LPENTRYID lpEntryID = NULL;
  1529. szBuf[0]='\0';
  1530. for(j=0;j<lpAdrEntry->cValues;j++)
  1531. {
  1532. ULONG ulPropTag = lpAdrEntry->rgPropVals[j].ulPropTag;
  1533. if(!bUnicode && PROP_TYPE(ulPropTag) == PT_STRING8)
  1534. ulPropTag = CHANGE_PROP_TYPE(ulPropTag, PT_UNICODE);
  1535. switch(ulPropTag)
  1536. {
  1537. case(PR_DISPLAY_NAME):
  1538. {
  1539. LPTSTR lpNameW = NULL;
  1540. SET_UNICODE_STR(lpNameW, lpAdrEntry->rgPropVals[j].Value.LPSZ,lpAdrParms);
  1541. nLen = CopyTruncate(szBuf, lpNameW, MAX_DISPLAY_NAME_LENGTH);
  1542. FREE_UNICODE_STR(lpNameW, lpAdrEntry->rgPropVals[j].Value.LPSZ);
  1543. }
  1544. break;
  1545. case(PR_RECIPIENT_TYPE):
  1546. ulRecipientType = lpAdrEntry->rgPropVals[j].Value.l;
  1547. break;
  1548. case(PR_OBJECT_TYPE):
  1549. ulObjectType = lpAdrEntry->rgPropVals[j].Value.l;
  1550. break;
  1551. case(PR_ENTRYID):
  1552. cbEntryID = lpAdrEntry->rgPropVals[j].Value.bin.cb;
  1553. lpEntryID = (LPENTRYID) lpAdrEntry->rgPropVals[j].Value.bin.lpb;
  1554. break;
  1555. case PR_USER_X509_CERTIFICATE:
  1556. bHasCert = TRUE;
  1557. break;
  1558. }
  1559. }
  1560. if (lstrlen(szBuf) && ((ulRecipientType == ulMapiBCC) || (ulRecipientType == ulMapiTo) || (ulRecipientType == ulMapiCC)))
  1561. {
  1562. lpNew = LocalAlloc(LMEM_ZEROINIT, sizeof(RECIPIENT_INFO));
  1563. if(!lpNew)
  1564. {
  1565. DebugPrintError(( TEXT("LocalAlloc failed to allocate memory\n")));
  1566. goto out;
  1567. }
  1568. // ***NOTE***
  1569. // Store this index number, ie 1st item in AdrList is 1, then 2, 3, so on
  1570. // we do a plus 1 here because 0 value means it wasnt passed in and thus the
  1571. // minimum valid value is 1
  1572. lpNew->ulOldAdrListEntryNumber = i+1;
  1573. lpNew->bHasCert = bHasCert;
  1574. StrCpyN(lpNew->szDisplayName,szBuf,ARRAYSIZE(lpNew->szDisplayName));
  1575. lpNew->ulRecipientType = ulRecipientType;
  1576. lpNew->ulObjectType = ulObjectType;
  1577. if (cbEntryID != 0)
  1578. {
  1579. lpNew->cbEntryID = cbEntryID;
  1580. lpNew->lpEntryID = LocalAlloc(LMEM_ZEROINIT,cbEntryID);
  1581. if(!lpNew->lpEntryID)
  1582. {
  1583. DebugPrintError(( TEXT("LocalAlloc failed to allocate memory\n")));
  1584. goto out;
  1585. }
  1586. CopyMemory(lpNew->lpEntryID,lpEntryID,cbEntryID);
  1587. }
  1588. if (ulRecipientType == ulMapiTo)
  1589. {
  1590. lpNew->lpNext = *lppListTo;
  1591. if (*lppListTo)
  1592. (*lppListTo)->lpPrev = lpNew;
  1593. lpNew->lpPrev = NULL;
  1594. *lppListTo = lpNew;
  1595. }
  1596. else if (ulRecipientType == ulMapiCC)
  1597. {
  1598. lpNew->lpNext = *lppListCC;
  1599. if (*lppListCC)
  1600. (*lppListCC)->lpPrev = lpNew;
  1601. lpNew->lpPrev = NULL;
  1602. *lppListCC = lpNew;
  1603. }
  1604. else if (ulRecipientType == ulMapiBCC)
  1605. {
  1606. lpNew->lpNext = *lppListBCC;
  1607. if (*lppListBCC)
  1608. (*lppListBCC)->lpPrev = lpNew;
  1609. lpNew->lpPrev = NULL;
  1610. *lppListBCC = lpNew;
  1611. }
  1612. }
  1613. }
  1614. }
  1615. lvI.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
  1616. lvI.state = 0;
  1617. lvI.stateMask = 0;
  1618. lvI.iSubItem = 0;
  1619. lvI.cchTextMax = MAX_DISPLAY_NAME_LENGTH;
  1620. for(i=0;i<3;i++)
  1621. {
  1622. switch(i)
  1623. {
  1624. case 0:
  1625. lpNew = *lppListTo;
  1626. break;
  1627. case 1:
  1628. lpNew = *lppListCC;
  1629. break;
  1630. case 2:
  1631. lpNew = *lppListBCC;
  1632. break;
  1633. }
  1634. hWndAddr = GetDlgItem(hDlg, IDC_ADDRBK_LIST_TO+i);
  1635. index = 0;
  1636. while(lpNew)
  1637. {
  1638. lvI.iItem = index;
  1639. lvI.pszText = lpNew->szDisplayName;
  1640. lvI.lParam = (LPARAM) lpNew;
  1641. lvI.iImage = GetWABIconImage(lpNew);
  1642. ListView_InsertItem(hWndAddr, &lvI);
  1643. index++;
  1644. lpNew = lpNew->lpNext;
  1645. }
  1646. }
  1647. // We will highlight the first item in any filled list box
  1648. // because basically that looks good when tabbing through them ...
  1649. for(i=0;i<lpAdrParms->cDestFields;i++)
  1650. {
  1651. HWND hWndLV = GetDlgItem(hDlg, IDC_ADDRBK_LIST_TO+i);
  1652. if (ListView_GetItemCount(hWndLV) > 0)
  1653. LVSelectItem(hWndLV,0);
  1654. }
  1655. bRet = TRUE;
  1656. out:
  1657. return bRet;
  1658. }
  1659. /////////////////////////////////////////////////////////////////////////////////
  1660. //
  1661. // SetAddressBookUI - juggles the address book UI in response to various parameters
  1662. //
  1663. // This function will probably be more complex with each tier
  1664. //
  1665. //
  1666. //
  1667. /////////////////////////////////////////////////////////////////////////////////
  1668. BOOL SetAddressBookUI(HWND hDlg,
  1669. LPADDRESS_PARMS lpAP)
  1670. {
  1671. BOOL bRet = FALSE;
  1672. //LV_COLUMN lvC;
  1673. RECT rc, rc1, rc2;
  1674. POINT ptLU1,ptRB1;
  1675. int nButtonsVisible = 0;
  1676. int nButtonSpacing = 7;
  1677. int nButtonWidth = 0;
  1678. ULONG nLen = 0;
  1679. TCHAR szBuf[MAX_UI_STR*4];
  1680. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  1681. HWND hWndListAddresses = GetDlgItem(hDlg, IDC_ADDRBK_LIST_ADDRESSES);
  1682. LPTSTR szCaption = NULL;
  1683. SET_UNICODE_STR(szCaption, lpAP->lpAdrParms->lpszCaption,lpAP->lpAdrParms);
  1684. if(!szCaption || !lstrlen(szCaption))
  1685. {
  1686. LoadString(hinstMapiX, IDS_ADDRBK_CAPTION, szBuf, CharSizeOf(szBuf));
  1687. szCaption = szBuf;
  1688. }
  1689. // Set the font of all the children to the default GUI font
  1690. EnumChildWindows( hDlg,
  1691. SetChildDefaultGUIFont,
  1692. (LPARAM) 0);
  1693. if(pt_bIsWABOpenExSession || bIsWABSessionProfileAware((LPIAB)lpAP->lpIAB))
  1694. {
  1695. // Fill in the Combo with the container names
  1696. FillContainerCombo(GetDlgItem(hDlg, IDC_ADDRBK_COMBO_CONT), (LPIAB)lpAP->lpIAB);
  1697. }
  1698. else
  1699. {
  1700. HWND hWndCombo = GetDlgItem(hDlg, IDC_ADDRBK_COMBO_CONT);
  1701. EnableWindow(hWndCombo, FALSE);
  1702. ShowWindow(hWndCombo, SW_HIDE);
  1703. // resize the listview to take place of the hidden combo
  1704. GetWindowRect(hWndCombo,&rc2);
  1705. GetWindowRect(hWndListAddresses,&rc);
  1706. //
  1707. //This api works for both mirrored and unmirrored windows.
  1708. //
  1709. MapWindowPoints(NULL, hDlg, (LPPOINT)&rc2, 2);
  1710. MapWindowPoints(NULL, hDlg, (LPPOINT)&rc, 2);
  1711. ptLU1.x = rc2.left;
  1712. ptLU1.y = rc2.top;
  1713. ptRB1.x = rc.right;
  1714. ptRB1.y = rc.bottom;
  1715. MoveWindow(hWndListAddresses,ptLU1.x,ptLU1.y,(ptRB1.x - ptLU1.x), (ptRB1.y - ptLU1.y), TRUE);
  1716. }
  1717. //
  1718. // There are only two states that need configuration -
  1719. // Pick User - in which we have to hide the wells
  1720. // and
  1721. // Select Recipients, in which we have to hide the wells
  1722. // as per the input criteria and resize accordingly and
  1723. // also set the labels based on the input criteria
  1724. //
  1725. if (lpAP->DialogState == STATE_SELECT_RECIPIENTS)
  1726. {
  1727. SendMessage (hDlg, DM_SETDEFID, IDC_ADDRBK_BUTTON_TO, 0);
  1728. // in case the nDestFieldFocus parameter is supplied, use it ..
  1729. if (
  1730. (lpAP->lpAdrParms->nDestFieldFocus < lpAP->lpAdrParms->cDestFields))
  1731. {
  1732. if (lpAP->lpAdrParms->nDestFieldFocus == 1)
  1733. SendMessage (hDlg, DM_SETDEFID, IDC_ADDRBK_BUTTON_CC, 0);
  1734. else if (lpAP->lpAdrParms->nDestFieldFocus == 2)
  1735. SendMessage (hDlg, DM_SETDEFID, IDC_ADDRBK_BUTTON_BCC, 0);
  1736. }
  1737. }
  1738. else if (lpAP->DialogState == STATE_PICK_USER)
  1739. SendMessage (hDlg, DM_SETDEFID, IDOK/*IDC_ADDRBK_BUTTON_OK*/, 0);
  1740. else if (lpAP->DialogState == STATE_BROWSE_MODAL)
  1741. SendMessage (hDlg, DM_SETDEFID, IDC_ADDRBK_BUTTON_PROPS, 0);
  1742. // Set the window caption
  1743. if (szCaption)
  1744. SetWindowText(hDlg,szCaption);
  1745. // Set the caption over the destination wells
  1746. if (lpAP->lpAdrParms->lpszDestWellsTitle)
  1747. {
  1748. LPWSTR lpTitle = NULL; // <note> assumes UNICODE defined
  1749. SET_UNICODE_STR(lpTitle,lpAP->lpAdrParms->lpszDestWellsTitle,lpAP->lpAdrParms);
  1750. SetDlgItemText(hDlg,IDC_ADDRBK_STATIC_RECIP_TITLE,lpTitle);
  1751. FREE_UNICODE_STR(lpTitle, lpAP->lpAdrParms->lpszDestWellsTitle);
  1752. }
  1753. if (lpAP->DialogState == STATE_PICK_USER &&
  1754. *(lpAP->lppAdrList) )
  1755. {
  1756. ULONG i=0;
  1757. LPTSTR lpszRecipName = NULL;
  1758. //Get the user whose name we are trying to find
  1759. for(i=0;i<(*(lpAP->lppAdrList))->aEntries[0].cValues;i++)
  1760. {
  1761. ULONG ulPropTag = PR_DISPLAY_NAME;
  1762. if(!(lpAP->lpAdrParms->ulFlags & MAPI_UNICODE))
  1763. ulPropTag = CHANGE_PROP_TYPE(ulPropTag, PT_STRING8);
  1764. if ((*(lpAP->lppAdrList))->aEntries[0].rgPropVals[i].ulPropTag == ulPropTag)
  1765. {
  1766. SET_UNICODE_STR(lpszRecipName,(*(lpAP->lppAdrList))->aEntries[0].rgPropVals[i].Value.LPSZ,lpAP->lpAdrParms);
  1767. break;
  1768. }
  1769. }
  1770. if(lpszRecipName)
  1771. {
  1772. LPTSTR lpszBuffer = NULL;
  1773. TCHAR szTmp[MAX_PATH], *lpszTmp;
  1774. LoadString(hinstMapiX, IDS_ADDRBK_RESOLVE_CAPTION, szBuf, CharSizeOf(szBuf));
  1775. CopyTruncate(szTmp, lpszRecipName, MAX_PATH - 1);
  1776. lpszTmp = szTmp;
  1777. if(FormatMessage( FORMAT_MESSAGE_FROM_STRING |
  1778. FORMAT_MESSAGE_ARGUMENT_ARRAY |
  1779. FORMAT_MESSAGE_ALLOCATE_BUFFER,
  1780. szBuf,
  1781. 0,0, //ignored
  1782. (LPTSTR) &lpszBuffer,
  1783. MAX_UI_STR,
  1784. (va_list *)&lpszTmp))
  1785. {
  1786. // if the display name is too long, it doesnt show up properly in the UI ..
  1787. // so we will purposely limit the visible portion to 64 characters - arbitarily defined limit..
  1788. szBuf[0]='\0';
  1789. nLen = CopyTruncate(szBuf, lpszBuffer, 2 * MAX_DISPLAY_NAME_LENGTH);
  1790. LocalFreeAndNull(&lpszBuffer);
  1791. }
  1792. //Increase the size of the static control to = what the Contents List width will be
  1793. GetWindowRect(GetDlgItem(hDlg,IDC_ADDRBK_STATIC_CONTENTS),&rc2);
  1794. GetWindowRect(GetDlgItem(hDlg,IDC_ADDRBK_LIST_TO),&rc);
  1795. //
  1796. //This api working in both mirrored and unmirrored windows.
  1797. //
  1798. MapWindowPoints(NULL, hDlg, (LPPOINT)&rc2, 2);
  1799. MapWindowPoints(NULL, hDlg, (LPPOINT)&rc, 2);
  1800. ptLU1.x = rc2.left;
  1801. ptLU1.y = rc2.top;
  1802. ptRB1.x = rc.right;
  1803. ptRB1.y = rc2.bottom;
  1804. MoveWindow(GetDlgItem(hDlg,IDC_ADDRBK_STATIC_CONTENTS),ptLU1.x,ptLU1.y,(ptRB1.x - ptLU1.x), (ptRB1.y - ptLU1.y), TRUE);
  1805. SetDlgItemText(hDlg,IDC_ADDRBK_STATIC_CONTENTS,szBuf);
  1806. FREE_UNICODE_STR(lpszRecipName,(*(lpAP->lppAdrList))->aEntries[0].rgPropVals[i].Value.LPSZ);
  1807. }
  1808. }
  1809. if (lpAP->DialogState == STATE_PICK_USER)
  1810. {
  1811. // If ADDRESS_ONE has been selected, then make the IDC_ADDRBK_LIST_ADDRESSES
  1812. // single selection only
  1813. DWORD dwStyle;
  1814. dwStyle = GetWindowLong(hWndListAddresses, GWL_STYLE);
  1815. SetWindowLong(hWndListAddresses, GWL_STYLE, dwStyle | LVS_SINGLESEL);
  1816. }
  1817. if ((lpAP->DialogState == STATE_PICK_USER)||(lpAP->DialogState == STATE_BROWSE_MODAL))
  1818. {
  1819. int i = 0;
  1820. // Dont show wells which means we have to do some rearranging
  1821. // * Hide the wells and the To, CC, BCC buttons
  1822. // * Resize the IDC_ADDRBK_LIST_ADDRESSES to fill the whole dialog
  1823. // * Move the 3 buttons below it to the left side of the dialog
  1824. //
  1825. // Get the dimensions of the ToListBox
  1826. GetWindowRect(GetDlgItem(hDlg,IDC_ADDRBK_LIST_TO),&rc2);
  1827. GetWindowRect(hWndListAddresses,&rc);
  1828. //
  1829. //This api works for in both mirrored and unmirrored windows.
  1830. //
  1831. MapWindowPoints(NULL, hDlg, (LPPOINT)&rc2, 2);
  1832. MapWindowPoints(NULL, hDlg, (LPPOINT)&rc, 2);
  1833. ptLU1.x = rc.left;
  1834. ptLU1.y = rc.top;
  1835. ptRB1.x = rc2.right;
  1836. ptRB1.y = rc.bottom;
  1837. MoveWindow(hWndListAddresses,ptLU1.x,ptLU1.y,(ptRB1.x - ptLU1.x), (ptRB1.y - ptLU1.y), TRUE);
  1838. for(i=0;i<3;i++)
  1839. {
  1840. ShowWindow(GetDlgItem(hDlg, IDC_ADDRBK_BUTTON_TO + i), SW_HIDE);
  1841. ShowWindow(GetDlgItem(hDlg, IDC_ADDRBK_LIST_TO + i), SW_HIDE);
  1842. }
  1843. ShowWindow(GetDlgItem(hDlg, IDC_ADDRBK_STATIC_RECIP_TITLE), SW_HIDE); // TEXT("Message Recipients") label
  1844. }
  1845. // other things to do
  1846. // Load Headers for List box
  1847. GetWindowRect(hWndListAddresses,&rc);
  1848. HrInitListView(hWndListAddresses, LVS_REPORT, TRUE);
  1849. GetWindowRect(GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_PROPS),&rc2);
  1850. nButtonsVisible = 2;
  1851. nButtonWidth = (rc2.right - rc2.left);
  1852. // get the new coordinates of the 1st visible button
  1853. //
  1854. //This api working in both mirrored and unmirrored windows.
  1855. //
  1856. MapWindowPoints(NULL, hDlg, (LPPOINT)&rc2, 2);
  1857. MapWindowPoints(NULL, hDlg, (LPPOINT)&rc, 2);
  1858. ptLU1.x = rc.left;
  1859. ptLU1.y = rc2.top;
  1860. ptRB1.x = ptLU1.x + nButtonWidth;
  1861. ptRB1.y = rc2.bottom;
  1862. MoveWindow(GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_NEW),ptLU1.x,ptLU1.y,nButtonWidth, (ptRB1.y - ptLU1.y), TRUE);
  1863. ptLU1.x += nButtonWidth + nButtonSpacing;
  1864. ptRB1.x = ptLU1.x + nButtonWidth;
  1865. if (lpAP->DialogState == STATE_BROWSE_MODAL)
  1866. {
  1867. MoveWindow(GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_NEWGROUP),ptLU1.x,ptLU1.y,nButtonWidth, (ptRB1.y - ptLU1.y), TRUE);
  1868. ptLU1.x += nButtonWidth + nButtonSpacing;
  1869. ptRB1.x = ptLU1.x + nButtonWidth;
  1870. }
  1871. else
  1872. {
  1873. // The NewGroup button is visible only in the DialogModalView
  1874. EnableWindow(GetDlgItem(hDlg, IDC_ADDRBK_BUTTON_NEWGROUP), FALSE);
  1875. ShowWindow(GetDlgItem(hDlg, IDC_ADDRBK_BUTTON_NEWGROUP), SW_HIDE);
  1876. }
  1877. MoveWindow(GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_PROPS),ptLU1.x,ptLU1.y,nButtonWidth, (ptRB1.y - ptLU1.y), TRUE);
  1878. ptLU1.x += nButtonWidth + nButtonSpacing;
  1879. ptRB1.x = ptLU1.x + nButtonWidth;
  1880. MoveWindow(GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_DELETE),ptLU1.x,ptLU1.y,nButtonWidth, (ptRB1.y - ptLU1.y), TRUE);
  1881. // The delete button is visible only in the DialogModalView
  1882. if (lpAP->DialogState != STATE_BROWSE_MODAL)
  1883. {
  1884. EnableWindow(GetDlgItem(hDlg, IDC_ADDRBK_BUTTON_DELETE), FALSE);
  1885. ShowWindow(GetDlgItem(hDlg, IDC_ADDRBK_BUTTON_DELETE), SW_HIDE);
  1886. }
  1887. //
  1888. // We now need to customize this window if we are selecting
  1889. // recipients ...
  1890. //
  1891. if (lpAP->DialogState == STATE_SELECT_RECIPIENTS)
  1892. {
  1893. // We need to see which wells are visible and
  1894. // then we need to resize the buttons based on their captions
  1895. //
  1896. int i=0;
  1897. int nLen=0;
  1898. int cDF = lpAP->lpAdrParms->cDestFields;
  1899. int iLeft=0,iTop=0;
  1900. SIZE size={0};
  1901. ULONG MaxWidth=0;
  1902. ULONG maxHeightPerLV = 0;
  1903. HWND hw;
  1904. HDC hdc=GetDC(hDlg);
  1905. if (lpAP->lpAdrParms->lppszDestTitles)
  1906. {
  1907. for(i=0; i < cDF; i++)
  1908. {
  1909. LPTSTR lpTitle = NULL;
  1910. ULONG Len = 0;
  1911. SET_UNICODE_STR(lpTitle,lpAP->lpAdrParms->lppszDestTitles[i],lpAP->lpAdrParms);
  1912. if(!lpTitle)
  1913. continue;
  1914. Len = lstrlen(lpTitle);
  1915. if (Len > CharSizeOf(szBuf) - 4)
  1916. {
  1917. ULONG iLen = TruncatePos(lpTitle, CharSizeOf(szBuf) - 4);
  1918. CopyMemory(szBuf,lpTitle,iLen*sizeof(TCHAR));
  1919. szBuf[iLen] = '\0';
  1920. }
  1921. else
  1922. {
  1923. StrCpyN(szBuf,lpTitle,ARRAYSIZE(szBuf));
  1924. }
  1925. StrCatBuff(szBuf,szArrow,ARRAYSIZE(szBuf));
  1926. if (lstrlen(szBuf) >= nLen)
  1927. {
  1928. nLen = lstrlen(szBuf);
  1929. GetTextExtentPoint32(hdc, szBuf, nLen, &size);
  1930. MaxWidth = size.cx;
  1931. }
  1932. // Set the new text
  1933. SetDlgItemText(hDlg,IDC_ADDRBK_BUTTON_TO+i,szBuf);
  1934. FREE_UNICODE_STR(lpTitle,lpAP->lpAdrParms->lppszDestTitles[i]);
  1935. }
  1936. }
  1937. ReleaseDC(hDlg,hdc);
  1938. if (MaxWidth == 0)
  1939. {
  1940. //get the default width
  1941. GetWindowRect(GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_TO),&rc1);
  1942. MaxWidth = rc1.right - rc1.left;
  1943. }
  1944. //Get the maximum allowable height per well
  1945. GetWindowRect(hWndListAddresses,&rc);
  1946. GetChildClientRect(hWndListAddresses, &rc);
  1947. GetWindowRect(GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_NEW),&rc1);
  1948. GetChildClientRect(GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_NEW), &rc1);
  1949. maxHeightPerLV = (rc1.bottom-rc.top - (cDF - 1)*CONTROL_SPACING)/cDF;
  1950. iTop = rc.top;
  1951. for(i=0;i<cDF;i++)
  1952. {
  1953. hw = GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_TO + i);
  1954. // resize the buttons to fit the text
  1955. GetWindowRect(hw,&rc1);
  1956. GetChildClientRect(hw,&rc1);
  1957. MoveWindow(hw,rc1.left,iTop,MaxWidth,rc1.bottom - rc1.top,FALSE);
  1958. iLeft = rc1.left + MaxWidth + 2*CONTROL_SPACING;
  1959. // Move the list boxes to accomodate the resized buttons
  1960. hw = GetDlgItem(hDlg,IDC_ADDRBK_LIST_TO + i);
  1961. GetWindowRect(hw, &rc1);
  1962. GetChildClientRect(hw, &rc1);
  1963. MoveWindow(hw,iLeft,iTop,rc1.right-iLeft,maxHeightPerLV,FALSE);
  1964. ListView_SetExtendedListViewStyle(hw,LVS_EX_FULLROWSELECT);
  1965. iTop += maxHeightPerLV + CONTROL_SPACING;
  1966. }
  1967. //Move the label over the wells and restrict it's size
  1968. hw = GetDlgItem(hDlg,IDC_ADDRBK_STATIC_RECIP_TITLE);
  1969. GetWindowRect(hw, &rc2);
  1970. GetChildClientRect(hw, &rc2);
  1971. if(pt_bIsWABOpenExSession || bIsWABSessionProfileAware((LPIAB)lpAP->lpIAB)) // need to move this to the same height as combo
  1972. {
  1973. int ht = rc2.bottom - rc2.top;
  1974. rc2.bottom = rc.top - CONTROL_SPACING;
  1975. rc2.top = rc2.bottom - ht;
  1976. }
  1977. MoveWindow(hw,iLeft,rc2.top,rc1.right-iLeft,rc2.bottom-rc2.top,FALSE);
  1978. // Now we have the position and width of the list boxes .. need to get their height
  1979. if (cDF!=3) //if not the default preset position, reposition
  1980. {
  1981. switch(cDF)
  1982. {
  1983. case 1:
  1984. ShowWindow(GetDlgItem(hDlg, IDC_ADDRBK_BUTTON_CC), SW_HIDE);
  1985. ShowWindow(GetDlgItem(hDlg, IDC_ADDRBK_LIST_CC), SW_HIDE);
  1986. case 2:
  1987. ShowWindow(GetDlgItem(hDlg, IDC_ADDRBK_BUTTON_BCC), SW_HIDE);
  1988. ShowWindow(GetDlgItem(hDlg, IDC_ADDRBK_LIST_BCC), SW_HIDE);
  1989. break;
  1990. }
  1991. }
  1992. for(i=0;i<cDF;i++)
  1993. HrInitListView(GetDlgItem(hDlg, IDC_ADDRBK_LIST_TO + i), LVS_REPORT, FALSE);
  1994. /***
  1995. // Add a column to the To,CC,BCC List Boxes
  1996. GetWindowRect(GetDlgItem(hDlg,IDC_ADDRBK_LIST_TO),&rc);
  1997. lvC.mask = LVCF_FMT | LVCF_WIDTH;// | LVCF_TEXT;
  1998. lvC.fmt = LVCFMT_LEFT;
  1999. lvC.cx = (rc.right - rc.left)-20;
  2000. lvC.iSubItem = 0;
  2001. lvC.pszText = NULL; // TEXT(" 'TO' Recipients");
  2002. ListView_InsertColumn(GetDlgItem(hDlg,IDC_ADDRBK_LIST_TO),lvC.iSubItem, &lvC);
  2003. ListView_InsertColumn(GetDlgItem(hDlg,IDC_ADDRBK_LIST_CC),lvC.iSubItem, &lvC);
  2004. ListView_InsertColumn(GetDlgItem(hDlg,IDC_ADDRBK_LIST_BCC),lvC.iSubItem, &lvC);
  2005. /***/
  2006. for (i=0;i<cDF;i++)
  2007. {
  2008. ShowWindow(GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_TO+i), SW_SHOWNORMAL);
  2009. UpdateWindow(GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_TO+i));
  2010. ShowWindow(GetDlgItem(hDlg,IDC_ADDRBK_LIST_TO+i), SW_SHOWNORMAL);
  2011. UpdateWindow(GetDlgItem(hDlg,IDC_ADDRBK_LIST_TO+i));
  2012. }
  2013. }
  2014. // The window is taking too long to display with several 100 entries in the
  2015. // property store ... so we force all the contents to visible so that we
  2016. // can view the fill contents ...
  2017. //ShowWindow(GetDlgItem(hDlg,IDC_ADDRBK_LIST_ADDRESSES), SW_SHOWNORMAL);
  2018. //UpdateWindow(GetDlgItem(hDlg,IDC_ADDRBK_LIST_ADDRESSES));
  2019. ShowWindow(GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_PROPS), SW_SHOWNORMAL);
  2020. UpdateWindow(GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_PROPS));
  2021. ShowWindow(GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_NEW), SW_SHOWNORMAL);
  2022. UpdateWindow(GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_NEW));
  2023. ShowWindow(GetDlgItem(hDlg,IDOK/*IDC_ADDRBK_BUTTON_OK*/), SW_SHOWNORMAL);
  2024. UpdateWindow(GetDlgItem(hDlg,IDOK/*IDC_ADDRBK_BUTTON_OK*/));
  2025. ShowWindow(GetDlgItem(hDlg,IDCANCEL/*IDC_ADDRBK_BUTTON_CANCEL*/), SW_SHOWNORMAL);
  2026. UpdateWindow(GetDlgItem(hDlg,IDCANCEL/*IDC_ADDRBK_BUTTON_CANCEL*/));
  2027. ShowWindow(GetDlgItem(hDlg,IDC_ADDRBK_STATIC_CONTENTS), SW_SHOWNORMAL);
  2028. UpdateWindow(GetDlgItem(hDlg,IDC_ADDRBK_STATIC_CONTENTS));
  2029. ShowWindow(GetDlgItem(hDlg,IDC_ADDRBK_STATIC_15), SW_SHOWNORMAL);
  2030. UpdateWindow(GetDlgItem(hDlg,IDC_ADDRBK_STATIC_15));
  2031. ShowWindow(hDlg,SW_SHOWNORMAL);
  2032. UpdateWindow(hDlg);
  2033. {
  2034. // HICON hIcon = LoadIcon(hinstMapiX,MAKEINTRESOURCE(IDI_ICON_FIND));
  2035. // associate the icon with the button.
  2036. // SendMessage(GetDlgItem(hDlg,IDC_ADDRBK_BUTTON_FIND),BM_SETIMAGE,(WPARAM)IMAGE_ICON,(LPARAM)(HANDLE)hIcon);
  2037. }
  2038. bRet = TRUE;
  2039. if( szCaption != lpAP->lpAdrParms->lpszCaption &&
  2040. szCaption != szBuf)
  2041. LocalFreeAndNull(&szCaption);
  2042. return bRet;
  2043. }
  2044. //$$///////////////////////////////////////////////////////////////////////////////////////////
  2045. //
  2046. // UpdateLVItems ....
  2047. // When we call properties on an object, its props can change ...
  2048. // Since the particular user may appear in any of the 4 list views,
  2049. // we have to make sure that all views are updated for that entry
  2050. //
  2051. ///////////////////////////////////////////////////////////////////////////////////////////////
  2052. void UpdateLVItems(HWND hWndLV,LPTSTR lpszName)
  2053. {
  2054. // We have the handle to the list view initiating the Properties call
  2055. // We know the old name to look for
  2056. //
  2057. // We know which item is selected - we can get its entryid and lParam
  2058. // We then search all the list views for the old display name
  2059. // if the old display name matches, we compare the entry id
  2060. // if the entryid matches, then we update that item ...
  2061. int iItemIndex = 0, iLastItemIndex = 0;
  2062. LPRECIPIENT_INFO lpOriginalItem;
  2063. ULONG i=0;
  2064. ULONG nCount = 0;
  2065. int id = 0;
  2066. HWND hDlg = GetParent(hWndLV);
  2067. HWND hw = NULL;
  2068. LV_FINDINFO lvf={0};
  2069. if ( (ListView_GetSelectedCount(hWndLV) != 1) ||
  2070. (lpszName == NULL) )
  2071. {
  2072. goto out;
  2073. }
  2074. iItemIndex = ListView_GetNextItem(hWndLV, -1, LVNI_SELECTED);
  2075. lpOriginalItem = GetItemFromLV(hWndLV, iItemIndex);
  2076. if(!lpOriginalItem)
  2077. goto out;
  2078. // There can be upto 4 list view boxes in the view, each of which can
  2079. // contain a displayed copy of this item ..
  2080. // We want to go through all 4 and update all entries that match this item
  2081. // Our strategy is to search for each and every item that
  2082. // matches the display name - check its entry ID and if
  2083. // the entry ID matches, update it ...
  2084. lvf.flags = LVFI_STRING;
  2085. lvf.psz = lpszName;
  2086. for(i=0;i<4;i++)
  2087. {
  2088. switch(i)
  2089. {
  2090. case 0:
  2091. id = IDC_ADDRBK_LIST_ADDRESSES;
  2092. break;
  2093. case 1:
  2094. id = IDC_ADDRBK_LIST_TO;
  2095. break;
  2096. case 2:
  2097. id = IDC_ADDRBK_LIST_CC;
  2098. break;
  2099. case 3:
  2100. id = IDC_ADDRBK_LIST_BCC;
  2101. break;
  2102. }
  2103. hw = GetDlgItem(hDlg,id);
  2104. // if its hidden, ignore it
  2105. if (!IsWindowVisible(hw))
  2106. continue;
  2107. // if its empty, ignore it
  2108. nCount = ListView_GetItemCount(hw);
  2109. if (nCount <= 0)
  2110. continue;
  2111. // The contents list view wont have duplicates so ignore it if its the original
  2112. if ((id == IDC_ADDRBK_LIST_ADDRESSES) &&
  2113. (hw == hWndLV))
  2114. continue;
  2115. // see if we can find the matching items
  2116. iLastItemIndex = -1;
  2117. iItemIndex = ListView_FindItem(hw,iLastItemIndex,&lvf);
  2118. while (iItemIndex != -1)
  2119. {
  2120. // inspect this item
  2121. LPRECIPIENT_INFO lpItem = GetItemFromLV(hWndLV, iItemIndex);
  2122. if (lpItem && (lpItem->cbEntryID != 0) && (lpOriginalItem->cbEntryID == lpItem->cbEntryID))
  2123. {
  2124. if(!memcmp(lpOriginalItem->lpEntryID,lpItem->lpEntryID,lpItem->cbEntryID))
  2125. {
  2126. // this is the same item ... update it
  2127. if (lstrcmpi(lpItem->szDisplayName,lpOriginalItem->szDisplayName))
  2128. {
  2129. ListView_SetItemText(hw,iItemIndex,colDisplayName,lpOriginalItem->szDisplayName);
  2130. StrCpyN(lpItem->szDisplayName,lpOriginalItem->szDisplayName,ARRAYSIZE(lpItem->szDisplayName));
  2131. }
  2132. if (lstrcmpi(lpItem->szEmailAddress,lpOriginalItem->szEmailAddress))
  2133. {
  2134. ListView_SetItemText(hw,iItemIndex,colEmailAddress,lpOriginalItem->szEmailAddress);
  2135. StrCpyN(lpItem->szEmailAddress,lpOriginalItem->szEmailAddress,ARRAYSIZE(lpItem->szEmailAddress));
  2136. }
  2137. if (lstrcmpi(lpItem->szHomePhone,lpOriginalItem->szHomePhone))
  2138. {
  2139. ListView_SetItemText(hw,iItemIndex,colHomePhone,lpOriginalItem->szHomePhone);
  2140. StrCpyN(lpItem->szHomePhone,lpOriginalItem->szHomePhone,ARRAYSIZE(lpItem->szHomePhone));
  2141. }
  2142. if (lstrcmpi(lpItem->szOfficePhone,lpOriginalItem->szOfficePhone))
  2143. {
  2144. ListView_SetItemText(hw,iItemIndex,colOfficePhone,lpOriginalItem->szOfficePhone);
  2145. StrCpyN(lpItem->szOfficePhone,lpOriginalItem->szOfficePhone,ARRAYSIZE(lpItem->szOfficePhone));
  2146. }
  2147. if (lstrcmpi(lpItem->szByFirstName,lpOriginalItem->szByFirstName))
  2148. StrCpyN(lpItem->szByFirstName,lpOriginalItem->szByFirstName,ARRAYSIZE(lpItem->szByFirstName));
  2149. if (lstrcmpi(lpItem->szByLastName,lpOriginalItem->szByLastName))
  2150. StrCpyN(lpItem->szByLastName,lpOriginalItem->szByLastName,ARRAYSIZE(lpItem->szByLastName));
  2151. }
  2152. }
  2153. iLastItemIndex = iItemIndex;
  2154. iItemIndex = ListView_FindItem(hw,iLastItemIndex,&lvf);
  2155. }
  2156. }
  2157. out:
  2158. return;
  2159. }
  2160. //$$///////////////////////////////////////////////////////////////////////////////////////////
  2161. //
  2162. // ShowAddrBkLVProps ....
  2163. //
  2164. ///////////////////////////////////////////////////////////////////////////////////////////////
  2165. void ShowAddrBkLVProps(LPIAB lpIAB, HWND hDlg, HWND hWndAddr,LPADDRESS_PARMS lpAP, LPFILETIME lpftLast)
  2166. {
  2167. // get the display name of this item
  2168. TCHAR szName[MAX_DISPLAY_NAME_LENGTH];
  2169. szName[0]='\0';
  2170. if (ListView_GetSelectedCount(hWndAddr) == 1)
  2171. {
  2172. ListView_GetItemText( hWndAddr,
  2173. ListView_GetNextItem(hWndAddr,-1,LVNI_SELECTED),
  2174. 0,
  2175. szName,
  2176. CharSizeOf(szName));
  2177. }
  2178. if( (MAPI_E_OBJECT_CHANGED == HrShowLVEntryProperties(hWndAddr, 0, lpAP->lpIAB, lpftLast)) &&
  2179. (szName) &&
  2180. (lpAP->DialogState == STATE_SELECT_RECIPIENTS)
  2181. )
  2182. {
  2183. // if the entry has changed and we have multiple list views visible,
  2184. // we need to update all instances of the entry in all the list views
  2185. //
  2186. UpdateLVItems(hWndAddr,szName);
  2187. SortListViewColumn(lpIAB, GetDlgItem(hDlg,IDC_ADDRBK_LIST_ADDRESSES), colDisplayName, &(lpAP->SortInfo), TRUE);
  2188. }
  2189. SetFocus(hWndAddr);
  2190. }
  2191. //$$///////////////////////////////////////////////////////////////////////////////////////////
  2192. //
  2193. // HrUpdateAdrListEntry ....
  2194. //
  2195. // When returning from a PickUser operation, updates the
  2196. // entry in the lpAdrList with the newly found item
  2197. //
  2198. // ulFLags 0 or MAPI_UNICODE passed down to GetProps
  2199. //
  2200. // Returns: Hr
  2201. //
  2202. ///////////////////////////////////////////////////////////////////////////////////////////////
  2203. HRESULT HrUpdateAdrListEntry( LPADRBOOK lpIAB,
  2204. LPENTRYID lpEntryID,
  2205. ULONG cbEntryID,
  2206. ULONG ulFlags,
  2207. LPADRLIST * lppAdrList)
  2208. {
  2209. LPSPropValue rgProps = NULL;
  2210. ULONG cValues = 0;
  2211. LPSPropValue lpPropArrayNew = NULL;
  2212. ULONG cValuesNew = 0;
  2213. LPTSTR lpszTemp = NULL;
  2214. LPVOID lpbTemp = NULL;
  2215. ULONG i = 0;
  2216. SCODE sc;
  2217. HRESULT hr = E_FAIL;
  2218. if (!lppAdrList || !lpEntryID || !lpIAB || !cbEntryID)
  2219. goto out;
  2220. hr = HrGetPropArray(lpIAB,
  2221. (LPSPropTagArray) &ptaResolveDefaults,
  2222. cbEntryID,
  2223. lpEntryID,
  2224. ulFlags,
  2225. &cValues,
  2226. &rgProps);
  2227. if (!HR_FAILED(hr))
  2228. {
  2229. if(!*lppAdrList)
  2230. {
  2231. // Allocate one ..
  2232. LPADRLIST lpAdrList = NULL;
  2233. sc = MAPIAllocateBuffer(sizeof(ADRLIST) + sizeof(ADRENTRY),
  2234. &lpAdrList);
  2235. if(FAILED(sc))
  2236. {
  2237. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  2238. goto out;
  2239. }
  2240. *lppAdrList = lpAdrList;
  2241. (*lppAdrList)->cEntries = 1;
  2242. (*lppAdrList)->aEntries[0].ulReserved1 = 0;
  2243. (*lppAdrList)->aEntries[0].cValues = 0;
  2244. (*lppAdrList)->aEntries[0].rgPropVals = NULL;
  2245. }
  2246. //Merge the new list with the old list
  2247. sc = ScMergePropValues( (*lppAdrList)->aEntries[0].cValues,
  2248. (*lppAdrList)->aEntries[0].rgPropVals,
  2249. cValues,
  2250. rgProps,
  2251. &cValuesNew,
  2252. &lpPropArrayNew);
  2253. if (sc == S_OK)
  2254. {
  2255. // if OK replace the lpspropvalue array
  2256. // if not we havent changed anything
  2257. (*lppAdrList)->aEntries[0].cValues = cValuesNew;
  2258. if((*lppAdrList)->aEntries[0].rgPropVals)
  2259. MAPIFreeBuffer((*lppAdrList)->aEntries[0].rgPropVals);
  2260. (*lppAdrList)->aEntries[0].rgPropVals = lpPropArrayNew;
  2261. }
  2262. else
  2263. {
  2264. // If errors Free up the allocated memory
  2265. if (lpPropArrayNew)
  2266. MAPIFreeBuffer(lpPropArrayNew);
  2267. hr = E_FAIL;
  2268. }
  2269. }
  2270. // we free this anyway whether the above succeeded or not
  2271. if (rgProps)
  2272. MAPIFreeBuffer(rgProps);
  2273. out:
  2274. return hr;
  2275. }