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.

1949 lines
64 KiB

  1. /**********************************************************************************
  2. *
  3. *
  4. * DL.C - contains functions for the DL dialog
  5. *
  6. *
  7. *
  8. *
  9. *
  10. *
  11. *
  12. **********************************************************************************/
  13. #include "_apipch.h"
  14. extern HINSTANCE ghCommCtrlDLLInst;
  15. // extern LPPROPERTYSHEET gpfnPropertySheet;
  16. // extern LP_CREATEPROPERTYSHEETPAGE gpfnCreatePropertySheetPage;
  17. extern LPPROPERTYSHEET_A gpfnPropertySheetA;
  18. extern LP_CREATEPROPERTYSHEETPAGE_A gpfnCreatePropertySheetPageA;
  19. extern LPPROPERTYSHEET_W gpfnPropertySheetW;
  20. extern LP_CREATEPROPERTYSHEETPAGE_W gpfnCreatePropertySheetPageW;
  21. extern LPTSTR szHTTP;
  22. extern BOOL bIsHttpPrefix(LPTSTR szBuf);
  23. extern void ShowURL(HWND hWnd, int id,LPTSTR lpURL);
  24. extern void ShowExpediaMAP(HWND hDlg, LPMAPIPROP lpPropObj, BOOL bHome);
  25. extern void ShowHideMapButton(HWND hWndButton);
  26. extern void SetHTTPPrefix(HWND hDlg, int id);
  27. extern BOOL bIsIE401OrGreater();
  28. extern ChangeLocaleBasedTabOrder(HWND hDlg, int nPropSheet);
  29. static DWORD rgDLHelpIDs[] =
  30. {
  31. IDC_DISTLIST_EDIT_GROUPNAME, IDH_WAB_GROUPNAME,
  32. IDC_DISTLIST_STATIC_GROUPNAME, IDH_WAB_GROUPNAME,
  33. IDC_DISTLIST_EDIT_NOTES, IDH_WAB_NOTES,
  34. IDC_DISTLIST_STATIC_NOTES, IDH_WAB_NOTES,
  35. IDC_DISTLIST_LISTVIEW, IDH_WAB_GROUP_NAME_LIST,
  36. IDC_DISTLIST_FRAME_MEMBERS, IDH_WAB_GROUP_NAME_LIST,
  37. IDC_DISTLIST_BUTTON_ADD, IDH_WAB_ADD_GROUP_MEMBERS,
  38. IDC_DISTLIST_BUTTON_REMOVE, IDH_WAB_DELETE_GROUP_MEMBERS,
  39. IDC_DISTLIST_BUTTON_PROPERTIES, IDH_WAB_GROUP_PROPERTIES,
  40. IDC_DISTLIST_BUTTON_ADDNEW, IDH_WAB_ADD_NEW_GROUP_CONTACTS,
  41. IDC_DISTLIST_STATIC_COUNT, IDH_WAB_ADD_NEW_GROUP_CONTACTS,
  42. IDC_DISTLIST_STATIC_ADD, IDH_WAB_ADD_NEW_GROUP_CONTACTS,
  43. IDC_DISTLIST_STATIC_ADDNAME, IDH_WAB_GROUP_NAME,
  44. IDC_DISTLIST_EDIT_ADDNAME, IDH_WAB_GROUP_NAME,
  45. IDC_DISTLIST_STATIC_ADDEMAIL, IDH_WAB_GROUP_EMAIL,
  46. IDC_DISTLIST_EDIT_ADDEMAIL, IDH_WAB_GROUP_EMAIL,
  47. IDC_DISTLIST_BUTTON_ADDUPDATE, IDH_WAB_GROUP_UPDATE,
  48. IDC_DISTLIST_BUTTON_UPDATECANCEL, IDH_WAB_GROUP_CANCEL_EDIT,
  49. IDD_DISTLIST_OTHER, IDH_WAB_ADD_NEW_GROUP_CONTACTS,
  50. IDC_DISTLIST_STATIC_STREET, IDH_WAB_DETAILS_ADDRESS,
  51. IDC_DISTLIST_EDIT_ADDRESS, IDH_WAB_DETAILS_ADDRESS,
  52. IDC_DISTLIST_STATIC_CITY, IDH_WAB_DETAILS_CITY,
  53. IDC_DISTLIST_EDIT_CITY, IDH_WAB_DETAILS_CITY,
  54. IDC_DISTLIST_STATIC_STATE, IDH_WAB_DETAILS_STATE,
  55. IDC_DISTLIST_EDIT_STATE, IDH_WAB_DETAILS_STATE,
  56. IDC_DISTLIST_STATIC_ZIP, IDH_WAB_DETAILS_ZIP,
  57. IDC_DISTLIST_EDIT_ZIP, IDH_WAB_DETAILS_ZIP,
  58. IDC_DISTLIST_STATIC_COUNTRY, IDH_WAB_DETAILS_COUNTRY,
  59. IDC_DISTLIST_EDIT_COUNTRY, IDH_WAB_DETAILS_COUNTRY,
  60. IDC_DISTLIST_STATIC_PHONE, IDH_WAB_DETAILS_PHONE,
  61. IDC_DISTLIST_EDIT_PHONE, IDH_WAB_DETAILS_PHONE,
  62. IDC_DISTLIST_STATIC_FAX, IDH_WAB_DETAILS_FAX,
  63. IDC_DISTLIST_EDIT_FAX, IDH_WAB_DETAILS_FAX,
  64. IDC_DISTLIST_STATIC_WEB, IDH_WAB_DETAILS_WEBPAGE,
  65. IDC_DISTLIST_EDIT_URL, IDH_WAB_DETAILS_WEBPAGE,
  66. IDC_DISTLIST_BUTTON_URL, IDH_WAB_DETAILS_GO,
  67. IDC_DISTLIST_BUTTON_MAP, IDH_WAB_BUSINESS_VIEWMAP,
  68. 0,0
  69. };
  70. // forward declarations
  71. INT_PTR CALLBACK fnDLProc(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam);
  72. INT_PTR CALLBACK fnDLOtherProc(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam);
  73. BOOL FillDLUI(HWND hDlg, int nPropSheet, LPDL_INFO lpPai,BOOL * lpbChangesMade);
  74. BOOL GetDLFromUI(HWND hDlg, int nPropSheet, LPDL_INFO lpPai , BOOL bSomethingChanged, LPSPropValue * lppPropArray, LPULONG lpulcPropCount);
  75. BOOL SetDLUI(HWND hDlg, int nPropSheet);
  76. void RemoveSelectedDistListItems(HWND hWndLV, LPDL_INFO lpPai);
  77. void AddDLMembers(HWND hwnd, HWND hWndLV, LPDL_INFO lpPai);
  78. LPSBinary FindAdrEntryID(LPADRLIST lpAdrList, ULONG index);
  79. /****************************************************************************
  80. * FUNCTION: CreateDLPropertySheet(HWND)
  81. *
  82. * PURPOSE: Creates the DL property sheet
  83. *
  84. ****************************************************************************/
  85. INT_PTR CreateDLPropertySheet( HWND hwndOwner,
  86. LPDL_INFO lpPropArrayInfo)
  87. {
  88. PROPSHEETPAGE psp;
  89. PROPSHEETHEADER psh;
  90. TCHAR szBuf[MAX_UI_STR];
  91. TCHAR szBuf2[MAX_UI_STR];
  92. ULONG ulTotal = 0;
  93. HPROPSHEETPAGE * lph = NULL;
  94. ULONG ulCount = 0;
  95. int i = 0;
  96. INT_PTR nRet = 0;
  97. ulTotal = propDLMax // Predefined ones +
  98. + lpPropArrayInfo->nPropSheetPages;
  99. lph = LocalAlloc(LMEM_ZEROINIT, sizeof(HPROPSHEETPAGE) * ulTotal);
  100. if(!lph)
  101. return FALSE;
  102. // DL
  103. psp.dwSize = sizeof(PROPSHEETPAGE);
  104. psp.dwFlags = PSP_USETITLE;
  105. psp.hInstance = hinstMapiX;
  106. psp.pszTemplate = MAKEINTRESOURCE(IDD_DISTLIST);
  107. psp.pszIcon = NULL;
  108. psp.pfnDlgProc = fnDLProc;
  109. LoadString(hinstMapiX, idsGroupTabName, szBuf, CharSizeOf(szBuf));
  110. psp.pszTitle = szBuf;
  111. psp.lParam = (LPARAM) lpPropArrayInfo;
  112. lph[ulCount] = gpfnCreatePropertySheetPage(&psp);
  113. if(lph[ulCount])
  114. ulCount++;
  115. // DL "Other"
  116. psp.dwSize = sizeof(PROPSHEETPAGE);
  117. psp.dwFlags = PSP_USETITLE;
  118. psp.hInstance = hinstMapiX;
  119. psp.pszTemplate = MAKEINTRESOURCE(IDD_DISTLIST_OTHER);
  120. psp.pszIcon = NULL;
  121. psp.pfnDlgProc = fnDLOtherProc;
  122. LoadString(hinstMapiX, idsGroupOtherTabName, szBuf, CharSizeOf(szBuf));
  123. psp.pszTitle = szBuf;
  124. psp.lParam = (LPARAM) lpPropArrayInfo;
  125. lph[ulCount] = gpfnCreatePropertySheetPage(&psp);
  126. if(lph[ulCount])
  127. ulCount++;
  128. // Start page is personal page
  129. psh.nStartPage = propGroup;
  130. // Now do the extended props if any
  131. for(i=0;i<lpPropArrayInfo->nPropSheetPages;i++)
  132. {
  133. if(lpPropArrayInfo->lphpages)
  134. {
  135. lph[ulCount] = lpPropArrayInfo->lphpages[i];
  136. ulCount++;
  137. }
  138. }
  139. /*** US dialogs get truncated on FE OSes .. we want the comctl to fix the truncation
  140. but this is only implemented in IE4.01 and beyond .. the problem with this being
  141. that wab is specifically compiled with the IE = 0x0300 so we're not pulling in the
  142. correct flag from the commctrl header .. so we will define the flag here and pray
  143. that commctrl never changes it ***/
  144. #define PSH_USEPAGELANG 0x00200000 // use frame dialog template matched to page
  145. /*** ***/
  146. psh.dwSize = sizeof(PROPSHEETHEADER);
  147. psh.dwFlags = PSH_NOAPPLYNOW;
  148. if(bIsIE401OrGreater())
  149. psh.dwFlags |= PSH_USEPAGELANG;
  150. psh.hwndParent = hwndOwner;
  151. psh.hInstance = hinstMapiX;
  152. psh.pszIcon = NULL;
  153. LoadString(hinstMapiX, IDS_DETAILS_CAPTION, szBuf2, CharSizeOf(szBuf2));
  154. psh.pszCaption = szBuf2;
  155. psh.nPages = ulCount; // ulProp //sizeof(psp) / sizeof(PROPSHEETPAGE);
  156. psh.phpage = lph;
  157. nRet = gpfnPropertySheet(&psh);
  158. if(lph)
  159. LocalFree(lph);
  160. return nRet;
  161. }
  162. typedef struct _tagIDProp
  163. {
  164. ULONG ulPropTag;
  165. int idCtl;
  166. } ID_PROP;
  167. // Control IDs corresponding to the Personal property sheet
  168. ID_PROP idPropDL[]=
  169. {
  170. {PR_DISPLAY_NAME, IDC_DISTLIST_EDIT_GROUPNAME},
  171. };
  172. const ULONG idPropDLCount = 1;
  173. ID_PROP idPropDLOther[]=
  174. {
  175. {PR_HOME_ADDRESS_STREET, IDC_DISTLIST_EDIT_ADDRESS},
  176. {PR_HOME_ADDRESS_CITY, IDC_DISTLIST_EDIT_CITY},
  177. {PR_HOME_ADDRESS_POSTAL_CODE, IDC_DISTLIST_EDIT_ZIP},
  178. {PR_HOME_ADDRESS_STATE_OR_PROVINCE, IDC_DISTLIST_EDIT_STATE},
  179. {PR_HOME_ADDRESS_COUNTRY, IDC_DISTLIST_EDIT_COUNTRY},
  180. {PR_HOME_TELEPHONE_NUMBER, IDC_DISTLIST_EDIT_PHONE},
  181. {PR_HOME_FAX_NUMBER, IDC_DISTLIST_EDIT_FAX},
  182. {PR_PERSONAL_HOME_PAGE, IDC_DISTLIST_EDIT_URL},
  183. {PR_COMMENT, IDC_DISTLIST_EDIT_NOTES},
  184. };
  185. const ULONG idPropDLOtherCount = 9;
  186. /****************************************************************************
  187. * FUNCTION: SetDLUI(HWND)
  188. *
  189. * PURPOSE: Sets up the UI for this PropSheet
  190. *
  191. ****************************************************************************/
  192. BOOL SetDLUI(HWND hDlg, int nPropSheet)
  193. {
  194. ULONG i =0;
  195. ID_PROP * lpidProp;
  196. ULONG idCount;
  197. // Set the font of all the children to the default GUI font
  198. EnumChildWindows( hDlg,
  199. SetChildDefaultGUIFont,
  200. (LPARAM) 0);
  201. //HrInitListView( hWndLV,LVS_REPORT | LVS_SORTASCENDING,FALSE);
  202. // Have to make this list view sorted
  203. if(nPropSheet == propGroup)
  204. {
  205. DWORD dwStyle;
  206. HWND hWndLV = GetDlgItem(hDlg, IDC_DISTLIST_LISTVIEW);
  207. HrInitListView( hWndLV,LVS_LIST,FALSE);
  208. dwStyle = GetWindowLong(hWndLV,GWL_STYLE);
  209. SetWindowLong(hWndLV,GWL_STYLE,dwStyle | LVS_SORTASCENDING);
  210. EnableWindow(GetDlgItem(hDlg,IDC_DISTLIST_BUTTON_PROPERTIES),FALSE);
  211. EnableWindow(GetDlgItem(hDlg,IDC_DISTLIST_BUTTON_REMOVE),FALSE);
  212. EnableWindow(hWndLV, FALSE);
  213. lpidProp = idPropDL;
  214. idCount = idPropDLCount;
  215. }
  216. else if(nPropSheet == propGroupOther)
  217. {
  218. lpidProp = idPropDLOther;
  219. idCount = idPropDLOtherCount;
  220. ShowHideMapButton(GetDlgItem(hDlg, IDC_DISTLIST_BUTTON_MAP));
  221. }
  222. else
  223. {
  224. return FALSE;
  225. }
  226. //Set max input limits on the edit fields
  227. for(i=0;i<idCount;i++)
  228. SendMessage(GetDlgItem(hDlg,lpidProp[i].idCtl),EM_SETLIMITTEXT,(WPARAM) MAX_UI_STR - 1,0);
  229. if(nPropSheet == propGroupOther)
  230. {
  231. SendMessage(GetDlgItem(hDlg,IDC_DISTLIST_EDIT_NOTES),EM_SETLIMITTEXT,(WPARAM) MAX_BUF_STR - 1,0);
  232. SetHTTPPrefix(hDlg, IDC_DISTLIST_EDIT_URL);
  233. }
  234. return TRUE;
  235. }
  236. /*
  237. -
  238. - UpdateLVCount - shows a running count of how many members are in the ListView
  239. *
  240. */
  241. void UpdateLVCount(HWND hDlg)
  242. {
  243. HWND hWndLV = GetDlgItem(hDlg, IDC_DISTLIST_LISTVIEW);
  244. HWND hWndStat = GetDlgItem(hDlg, IDC_DISTLIST_STATIC_COUNT);
  245. int nCount = ListView_GetItemCount(hWndLV);
  246. if(nCount <= 0)
  247. {
  248. ShowWindow(hWndStat, SW_HIDE);
  249. EnableWindow(GetDlgItem(hDlg,IDC_DISTLIST_BUTTON_PROPERTIES),FALSE);
  250. EnableWindow(GetDlgItem(hDlg,IDC_DISTLIST_BUTTON_REMOVE),FALSE);
  251. EnableWindow(hWndLV, FALSE);
  252. }
  253. else
  254. {
  255. TCHAR sz[MAX_PATH];
  256. TCHAR szStr[MAX_PATH];
  257. LoadString(hinstMapiX, idsGroupMemberCount, szStr, CharSizeOf(sz));
  258. wnsprintf(sz, ARRAYSIZE(sz), szStr, nCount);
  259. SetWindowText(hWndStat, sz);
  260. ShowWindow(hWndStat, SW_SHOWNORMAL);
  261. EnableWindow(GetDlgItem(hDlg,IDC_DISTLIST_BUTTON_PROPERTIES),TRUE);
  262. EnableWindow(GetDlgItem(hDlg,IDC_DISTLIST_BUTTON_REMOVE),TRUE);
  263. EnableWindow(hWndLV, TRUE);
  264. }
  265. }
  266. /****************************************************************************
  267. * FUNCTION: FillDLUI(HWND)
  268. *
  269. * PURPOSE: Fills in the dialog items on the property sheet
  270. *
  271. ****************************************************************************/
  272. BOOL FillDLUI(HWND hDlg, int nPropSheet, LPDL_INFO lpPai, BOOL * lpbChangesMade)
  273. {
  274. ULONG i = 0,j = 0;
  275. BOOL bRet = FALSE;
  276. BOOL bChangesMade = FALSE;
  277. ID_PROP * lpidProp = NULL;
  278. ULONG idPropCount = 0;
  279. ULONG ulcPropCount = 0;
  280. LPSPropValue lpPropArray = NULL;
  281. DWORD cchSize;
  282. if(lpPai->lpPropObj->lpVtbl->GetProps(lpPai->lpPropObj, NULL, MAPI_UNICODE, &ulcPropCount, &lpPropArray))
  283. goto exit;
  284. if(nPropSheet == propGroup)
  285. {
  286. idPropCount = idPropDLCount;
  287. lpidProp = idPropDL;
  288. }
  289. else if(nPropSheet == propGroupOther)
  290. {
  291. idPropCount = idPropDLOtherCount;
  292. lpidProp = idPropDLOther;
  293. }
  294. for(i=0;i<idPropCount;i++)
  295. {
  296. for(j=0;j<ulcPropCount;j++)
  297. {
  298. if(lpPropArray[j].ulPropTag == lpidProp[i].ulPropTag)
  299. SetDlgItemText(hDlg, lpidProp[i].idCtl, lpPropArray[j].Value.LPSZ);
  300. if( nPropSheet == propGroup &&
  301. lpidProp[i].idCtl == IDC_DISTLIST_EDIT_GROUPNAME &&
  302. lpPropArray[j].ulPropTag == PR_DISPLAY_NAME)
  303. {
  304. SetWindowPropertiesTitle(GetParent(hDlg), lpPropArray[j].Value.LPSZ);
  305. cchSize = lstrlen(lpPropArray[j].Value.LPSZ)+1;
  306. lpPai->lpszOldName = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*cchSize);
  307. if(lpPai->lpszOldName)
  308. StrCpyN(lpPai->lpszOldName,lpPropArray[j].Value.LPSZ,cchSize);
  309. }
  310. }
  311. }
  312. if(nPropSheet == propGroup)
  313. {
  314. HWND hWndLV = GetDlgItem(hDlg, IDC_DISTLIST_LISTVIEW);
  315. for(j=0;j<ulcPropCount;j++)
  316. {
  317. if( lpPropArray[j].ulPropTag == PR_WAB_DL_ENTRIES ||
  318. lpPropArray[j].ulPropTag == PR_WAB_DL_ONEOFFS )
  319. {
  320. // Look at each entry in the PR_WAB_DL_ENTRIES and recursively check it.
  321. for (i = 0; i < lpPropArray[j].Value.MVbin.cValues; i++)
  322. {
  323. AddWABEntryToListView(lpPai->lpIAB,
  324. hWndLV,
  325. lpPropArray[j].Value.MVbin.lpbin[i].cb,
  326. (LPENTRYID)lpPropArray[j].Value.MVbin.lpbin[i].lpb,
  327. &(lpPai->lpContentsList));
  328. }
  329. }
  330. }
  331. // Select the first item ..
  332. if (ListView_GetItemCount(hWndLV) > 0)
  333. LVSelectItem(hWndLV, 0);
  334. UpdateLVCount(hDlg);
  335. }
  336. bRet = TRUE;
  337. exit:
  338. if(lpPropArray)
  339. MAPIFreeBuffer(lpPropArray);
  340. return bRet;
  341. }
  342. extern BOOL bDoesEntryNameAlreadyExist(LPIAB lpIAB, LPTSTR lpsz);
  343. //$$////////////////////////////////////////////////////////////////////////////
  344. //
  345. // bVerifyRequiredData
  346. //
  347. // Checks that all the data we are requesting has been filled up
  348. // Returns CtrlID of the control that needs filling so we can set focus on it
  349. //
  350. /////////////////////////////////////////////////////////////////////////////////
  351. BOOL bVerifyDLRequiredData(HWND hDlg, LPIAB lpIAB, LPTSTR szOldName, int * lpCtlID)
  352. {
  353. TCHAR szBuf[2 * MAX_UI_STR];
  354. //
  355. // First check the required property (which is the GroupName)
  356. //
  357. *lpCtlID = 0;
  358. szBuf[0]='\0';
  359. GetDlgItemText(hDlg, IDC_DISTLIST_EDIT_GROUPNAME, szBuf, CharSizeOf(szBuf));
  360. TrimSpaces(szBuf);
  361. if(!lstrlen(szBuf))
  362. {
  363. ShowMessageBox(GetParent(hDlg), idsPleaseEnterGroupName, MB_ICONEXCLAMATION | MB_OK);
  364. *lpCtlID = IDC_DISTLIST_EDIT_GROUPNAME;
  365. return FALSE;
  366. }
  367. else
  368. {
  369. // Verify that this name does not already exist ..
  370. if( szOldName && lstrlen(szOldName) && // we have an old name and
  371. lstrcmp(szBuf, szOldName) && !lstrcmpi(szBuf, szOldName)) // it's just a case change don't bother looking
  372. return TRUE;
  373. if(szOldName && !lstrcmp(szBuf, szOldName))
  374. return TRUE;
  375. if(bDoesEntryNameAlreadyExist(lpIAB, szBuf))
  376. {
  377. // the name already exists .. do don't let them use it ..
  378. ShowMessageBox(GetParent(hDlg), idsEntryAlreadyInWAB, MB_ICONEXCLAMATION | MB_OK);
  379. *lpCtlID = IDC_DISTLIST_EDIT_GROUPNAME;
  380. return FALSE;
  381. }
  382. }
  383. return TRUE;
  384. }
  385. ////////////////////////////////////////////////////////////////////////////////
  386. //
  387. // GetDL from UI - reads the UI for its parameters and verifies that
  388. // all required fields are set.
  389. //
  390. // bShowMsg is true when the user presses OK and we want to force a message
  391. // otherwise bShowMsg is false
  392. //
  393. ////////////////////////////////////////////////////////////////////////////////
  394. BOOL GetDLFromUI(HWND hDlg, int nPropSheet, LPDL_INFO lpPai , BOOL bSomethingChanged, LPSPropValue * lppPropArray, LPULONG lpulcPropCount)
  395. {
  396. BOOL bRet = FALSE;
  397. TCHAR szBuf[2 * MAX_BUF_STR];
  398. LPTSTR lpszGroupName = NULL;
  399. ULONG ulcPropCount = 0,ulIndex=0;
  400. LPSPropValue lpPropArray = NULL;
  401. ULONG i =0;
  402. ID_PROP * lpidProp = NULL;
  403. ULONG idPropCount = 0;
  404. ULONG ulNotEmptyCount = 0;
  405. SCODE sc = S_OK;
  406. HRESULT hr = hrSuccess;
  407. LPRECIPIENT_INFO lpItem;
  408. *lppPropArray = NULL;
  409. *lpulcPropCount = 0;
  410. if(nPropSheet == propGroup)
  411. {
  412. idPropCount = idPropDLCount;
  413. lpidProp = idPropDL;
  414. }
  415. else if(nPropSheet == propGroupOther)
  416. {
  417. idPropCount = idPropDLOtherCount;
  418. lpidProp = idPropDLOther;
  419. }
  420. // The idea is to first count all the properties that have non-zero values
  421. // Then create a lpPropArray of that size and fill in the text from the props ..
  422. //
  423. if (!bSomethingChanged)
  424. {
  425. // nothing to do, no changes to save
  426. bRet = TRUE;
  427. goto out;
  428. }
  429. ulNotEmptyCount = 0;
  430. for(i=0;i<idPropCount;i++)
  431. {
  432. szBuf[0]='\0'; //reset
  433. GetDlgItemText(hDlg, lpidProp[i].idCtl, szBuf, CharSizeOf(szBuf));
  434. TrimSpaces(szBuf);
  435. if(lstrlen(szBuf) && lpidProp[i].ulPropTag) //some text
  436. ulNotEmptyCount++;
  437. if( lpidProp[i].idCtl == IDC_DISTLIST_EDIT_URL &&
  438. (lstrcmpi(szHTTP, szBuf)==0))
  439. ulNotEmptyCount--;
  440. }
  441. if (ulNotEmptyCount == 0)
  442. {
  443. // This prop sheet is empty ... ignore it
  444. bRet = TRUE;
  445. goto out;
  446. }
  447. ulcPropCount = ulNotEmptyCount;
  448. if(nPropSheet == propGroup && lpPai->lpContentsList)
  449. {
  450. ulcPropCount++; //For PR_WAB_DL_ENTRIES
  451. ulcPropCount++; //For PR_WAB_DL_ONEOFFS
  452. }
  453. sc = MAPIAllocateBuffer(sizeof(SPropValue) * ulcPropCount, &lpPropArray);
  454. if (sc!=S_OK)
  455. {
  456. DebugPrintError(( TEXT("Error allocating memory\n")));
  457. goto out;
  458. }
  459. ulIndex = 0; //now we reuse this variable as an index
  460. // Now read the props again and fill in the lpPropArray
  461. for(i=0;i<idPropCount;i++)
  462. {
  463. szBuf[0]='\0'; //reset
  464. GetDlgItemText(hDlg, lpidProp[i].idCtl, szBuf, CharSizeOf(szBuf));
  465. TrimSpaces(szBuf);
  466. if( lpidProp[i].idCtl == IDC_DISTLIST_EDIT_URL &&
  467. (lstrcmpi(szHTTP, szBuf)==0))
  468. continue;
  469. if(lstrlen(szBuf) && lpidProp[i].ulPropTag) //some text
  470. {
  471. ULONG nLen = (lstrlen(szBuf)+1);
  472. lpPropArray[ulIndex].ulPropTag = lpidProp[i].ulPropTag;
  473. sc = MAPIAllocateMore(sizeof(TCHAR)*nLen, lpPropArray, (LPVOID *) (&(lpPropArray[ulIndex].Value.LPSZ)));
  474. if (sc!=S_OK)
  475. {
  476. DebugPrintError(( TEXT("Error allocating memory\n")));
  477. goto out;
  478. }
  479. StrCpyN(lpPropArray[ulIndex].Value.LPSZ,szBuf,nLen);
  480. ulIndex++;
  481. }
  482. }
  483. if(nPropSheet == propGroup && lpPai->lpContentsList)
  484. {
  485. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  486. lpPropArray[ulIndex].ulPropTag = PR_WAB_DL_ENTRIES;
  487. lpPropArray[ulIndex].Value.MVbin.cValues = 0;
  488. lpPropArray[ulIndex].Value.MVbin.lpbin = NULL;
  489. lpPropArray[ulIndex+1].ulPropTag = PR_WAB_DL_ONEOFFS;
  490. lpPropArray[ulIndex+1].Value.MVbin.cValues = 0;
  491. lpPropArray[ulIndex+1].Value.MVbin.lpbin = NULL;
  492. // Now add the entry IDs to the DistList
  493. lpItem = lpPai->lpContentsList;
  494. while(lpItem)
  495. {
  496. BOOL bOneOff = (WAB_ONEOFF == IsWABEntryID(lpItem->cbEntryID, lpItem->lpEntryID, NULL, NULL, NULL, NULL, NULL));
  497. if(pt_bIsWABOpenExSession)
  498. bOneOff = FALSE;
  499. if (HR_FAILED(hr = AddPropToMVPBin( lpPropArray,
  500. bOneOff ? ulIndex+1 : ulIndex,
  501. lpItem->lpEntryID, lpItem->cbEntryID,
  502. FALSE)))
  503. {
  504. DebugPrintError(( TEXT("AddPropToMVPBin -> %x\n"), GetScode(hr)));
  505. goto out;
  506. }
  507. lpItem = lpItem->lpNext;
  508. }
  509. if(lpPropArray[ulIndex].Value.MVbin.cValues == 0)
  510. lpPropArray[ulIndex].ulPropTag = PR_NULL;
  511. if(lpPropArray[ulIndex+1].Value.MVbin.cValues == 0)
  512. lpPropArray[ulIndex+1].ulPropTag = PR_NULL;
  513. }
  514. *lppPropArray = lpPropArray;
  515. *lpulcPropCount = ulcPropCount;
  516. bRet = TRUE;
  517. out:
  518. if (!bRet)
  519. {
  520. if ((lpPropArray) && (ulcPropCount > 0))
  521. {
  522. MAPIFreeBuffer(lpPropArray);
  523. ulcPropCount = 0;
  524. }
  525. }
  526. return bRet;
  527. }
  528. /*
  529. -
  530. - SetCancelOneOffUpdateUI - sets UI for Cancels/resets any update being done in the group
  531. *
  532. */
  533. void SetCancelOneOffUpdateUI(HWND hDlg, LPPROP_ARRAY_INFO lppai, LPTSTR lpName, LPTSTR lpEmail, BOOL bCancel)
  534. {
  535. if(bCancel && lppai->ulFlags & DETAILS_EditingOneOff)
  536. {
  537. lppai->ulFlags &= ~DETAILS_EditingOneOff;
  538. lppai->sbDLEditingOneOff.cb = 0;
  539. LocalFreeAndNull((LPVOID *) (&(lppai->sbDLEditingOneOff.lpb)));
  540. }
  541. SetDlgItemText(hDlg, IDC_DISTLIST_EDIT_ADDNAME, lpName ? lpName : szEmpty);
  542. SetDlgItemText(hDlg, IDC_DISTLIST_EDIT_ADDEMAIL, lpEmail ? lpEmail : szEmpty);
  543. EnableWindow(GetDlgItem(hDlg, IDC_DISTLIST_BUTTON_UPDATECANCEL), !bCancel);
  544. ShowWindow(GetDlgItem(hDlg, IDC_DISTLIST_BUTTON_UPDATECANCEL), bCancel ? SW_HIDE : SW_SHOWNORMAL);
  545. {
  546. TCHAR sz[MAX_PATH];
  547. LoadString(hinstMapiX, bCancel ? idsConfAdd : idsConfUpdate, sz, CharSizeOf(sz));
  548. SetDlgItemText(hDlg, IDC_DISTLIST_BUTTON_ADDUPDATE, sz);
  549. }
  550. SendMessage(GetParent(hDlg), DM_SETDEFID, IDOK, 0);
  551. }
  552. /*
  553. - HrShowGroupEntryProperties - If selected entry is a one-off, shows special props on it else
  554. - cascades call down to regular call
  555. *
  556. */
  557. HRESULT HrShowGroupEntryProperties(HWND hDlg, HWND hWndLV, LPPROP_ARRAY_INFO lppai)
  558. {
  559. HRESULT hr = E_FAIL;
  560. int iItemIndex = ListView_GetSelectedCount(hWndLV);
  561. LPRECIPIENT_INFO lpItem=NULL;
  562. BOOL bOneOff = FALSE;
  563. // Open props if only 1 item is selected
  564. if (iItemIndex == 1)
  565. {
  566. // Get index of selected item
  567. if((iItemIndex = ListView_GetNextItem(hWndLV,-1,LVNI_SELECTED)) != -1)
  568. {
  569. lpItem = GetItemFromLV(hWndLV, iItemIndex);;
  570. if(lpItem && lpItem->cbEntryID != 0)
  571. {
  572. if(WAB_ONEOFF == IsWABEntryID(lpItem->cbEntryID, lpItem->lpEntryID,
  573. NULL, NULL, NULL, NULL, NULL))
  574. bOneOff = TRUE;
  575. }
  576. }
  577. }
  578. if(!bOneOff)
  579. {
  580. // use our regular property processing
  581. hr = HrShowLVEntryProperties(hWndLV, WAB_ONEOFF_NOADDBUTTON, lppai->lpIAB, NULL);
  582. }
  583. else
  584. {
  585. LPTSTR lpName = NULL, lpEmail = NULL, lpAddrType = NULL;
  586. ULONG ulMapiDataType = 0;
  587. // Deconstruct the entryid
  588. IsWABEntryID(lpItem->cbEntryID, lpItem->lpEntryID, &lpName, &lpAddrType, &lpEmail, (LPVOID *)&ulMapiDataType, NULL);
  589. // Set the flag marking that editing is in progress
  590. lppai->ulFlags |= DETAILS_EditingOneOff;
  591. // cache the item being edited so we can find it for updating
  592. LocalFreeAndNull((LPVOID *) (&((lppai->sbDLEditingOneOff).lpb)));
  593. SetSBinary(&(lppai->sbDLEditingOneOff), lpItem->cbEntryID, (LPBYTE)lpItem->lpEntryID);
  594. // [PaulHi] 3/4/99 Raid 73344
  595. // Check whether one off string data is ANSI or UNICODE
  596. if (!(ulMapiDataType & MAPI_UNICODE))
  597. {
  598. LPTSTR lptszName = ConvertAtoW((LPSTR)lpName);
  599. LPTSTR lptszAddrType = ConvertAtoW((LPSTR)lpAddrType);
  600. LPTSTR lptszEmail = ConvertAtoW((LPSTR)lpEmail);
  601. SetCancelOneOffUpdateUI(hDlg, lppai, lptszName, lptszEmail, FALSE);
  602. LocalFreeAndNull(&lptszName);
  603. LocalFreeAndNull(&lptszAddrType);
  604. LocalFreeAndNull(&lptszEmail);
  605. }
  606. else
  607. SetCancelOneOffUpdateUI(hDlg, lppai, lpName, lpEmail, FALSE);
  608. SetFocus(GetDlgItem(hDlg, IDC_DISTLIST_EDIT_ADDNAME));
  609. SendMessage(GetDlgItem(hDlg, IDC_DISTLIST_EDIT_ADDNAME), EM_SETSEL, 0, -1);
  610. hr = S_OK;
  611. }
  612. return hr;
  613. }
  614. /*
  615. -
  616. - HrAddUpdateOneOffEntryToGroup - Adds or updates a one-off entry to a group
  617. * Status of a flag determines what the operation in progress is ..
  618. *
  619. */
  620. HRESULT HrAddUpdateOneOffEntryToGroup(HWND hDlg, LPPROP_ARRAY_INFO lppai)
  621. {
  622. HRESULT hr = E_FAIL;
  623. TCHAR szName[MAX_UI_STR];
  624. TCHAR szEmail[MAX_UI_STR];
  625. ULONG cbEID = 0;
  626. LPENTRYID lpEID = NULL;
  627. HWND hWndLV = GetDlgItem(hDlg, IDC_DISTLIST_LISTVIEW);
  628. szName[0] = TEXT('\0');
  629. szEmail[0] = TEXT('\0');
  630. GetDlgItemText(hDlg, IDC_DISTLIST_EDIT_ADDNAME, szName, CharSizeOf(szName));
  631. GetDlgItemText(hDlg, IDC_DISTLIST_EDIT_ADDEMAIL, szEmail, CharSizeOf(szEmail));
  632. if(!lstrlen(szName) && !lstrlen(szEmail))
  633. {
  634. ShowMessageBox(hDlg, idsIncompleteOneoffInfo, MB_ICONEXCLAMATION);
  635. return hr;
  636. }
  637. //Check the e-mail address here
  638. if(lstrlen(szEmail) && !IsInternetAddress(szEmail, NULL))
  639. {
  640. if(IDNO == ShowMessageBox(hDlg, idsInvalidInternetAddress, MB_ICONEXCLAMATION | MB_YESNO))
  641. return hr;
  642. }
  643. if(!lstrlen(szName) && lstrlen(szEmail))
  644. StrCpyN(szName, szEmail, ARRAYSIZE(szName));
  645. //else
  646. //if(!lstrlen(szEmail) && lstrlen(szName))
  647. // StrCpyN(szEmail, szName, ARRAYSIZE(szEmail));
  648. if(!lstrlen(szEmail))
  649. szEmail[0] = TEXT('\0');
  650. if(HR_FAILED(hr = CreateWABEntryID(WAB_ONEOFF,
  651. (LPVOID)szName, (LPVOID)szSMTP, (LPVOID)szEmail,
  652. 0, 0, NULL, &cbEID, &lpEID)))
  653. return hr;
  654. if(lppai->ulFlags & DETAILS_EditingOneOff)
  655. {
  656. // This is an edit in progress .. the edit is pretty similar to the normal ADD ..
  657. // except we knock out the existing entry from the listview and add the modified entry to it
  658. int i=0, nCount = ListView_GetItemCount(hWndLV);
  659. for(i=0;i<nCount;i++)
  660. {
  661. LPRECIPIENT_INFO lpItem = GetItemFromLV(hWndLV,i);
  662. if( lpItem && lpItem->cbEntryID == lppai->sbDLEditingOneOff.cb &&
  663. !memcmp(lpItem->lpEntryID, lppai->sbDLEditingOneOff.lpb, lpItem->cbEntryID) )
  664. {
  665. // match
  666. // Select the item and then call the remove function
  667. LVSelectItem(hWndLV, i);
  668. RemoveSelectedDistListItems(hWndLV, lppai);
  669. break;
  670. }
  671. }
  672. }
  673. AddWABEntryToListView(lppai->lpIAB, hWndLV, cbEID, lpEID, &(lppai->lpContentsList));
  674. SetCancelOneOffUpdateUI(hDlg, lppai, NULL, NULL, TRUE);
  675. UpdateLVCount(hDlg);
  676. if(lpEID)
  677. MAPIFreeBuffer(lpEID);
  678. return S_OK;
  679. }
  680. enum _DLProp
  681. {
  682. dlDisplayName=0,
  683. dlDLEntries,
  684. dlDLOneOffs,
  685. dlMax
  686. };
  687. //$$//////////////////////////////////////////////////////////////////////////////
  688. //
  689. // bUpdateOldPropTagArray
  690. //
  691. // For each prop sheet that is accessed, we will update the list of old prop tags
  692. // for that sheet so that the old props can be knocked out of existing mailuser objects
  693. //
  694. //////////////////////////////////////////////////////////////////////////////////
  695. BOOL bUpdateOldDLPropTagArray(LPPROP_ARRAY_INFO lpPai, int nIndex)
  696. {
  697. LPSPropTagArray lpta = NULL;
  698. SizedSPropTagArray(3, ptaUIDetlsDL)=
  699. {
  700. 3,
  701. {
  702. PR_DISPLAY_NAME,
  703. PR_WAB_DL_ENTRIES,
  704. PR_WAB_DL_ONEOFFS,
  705. }
  706. };
  707. SizedSPropTagArray(9, ptaUIDetlsDLOther)=
  708. {
  709. 9,
  710. {
  711. PR_HOME_ADDRESS_STREET,
  712. PR_HOME_ADDRESS_CITY,
  713. PR_HOME_ADDRESS_POSTAL_CODE,
  714. PR_HOME_ADDRESS_STATE_OR_PROVINCE,
  715. PR_HOME_ADDRESS_COUNTRY,
  716. PR_HOME_TELEPHONE_NUMBER,
  717. PR_HOME_FAX_NUMBER,
  718. PR_PERSONAL_HOME_PAGE,
  719. PR_COMMENT,
  720. }
  721. };
  722. switch(nIndex)
  723. {
  724. case propGroup:
  725. lpta = (LPSPropTagArray) &ptaUIDetlsDL;
  726. break;
  727. case propGroupOther:
  728. lpta = (LPSPropTagArray) &ptaUIDetlsDLOther;
  729. break;
  730. }
  731. if(!lpta)
  732. return TRUE;
  733. if(lpPai->lpPropObj)
  734. {
  735. // Knock out these old props from the PropObject
  736. if( (lpPai->lpPropObj)->lpVtbl->DeleteProps( (lpPai->lpPropObj), lpta, NULL))
  737. return FALSE;
  738. }
  739. return TRUE;
  740. }
  741. //$$/////////////////////////////////////////////////////////////////////////
  742. //
  743. // bUpdatePropSheetData
  744. //
  745. // Every time the user switches pages, we update the globally accessible data
  746. // The sheet will get PSN_KILLACTIVE when switching pages and PSN_APPLY when ok
  747. // is pressed. A little bit of duplicated effort in the latter case but thats ok
  748. //
  749. /////////////////////////////////////////////////////////////////////////////
  750. BOOL bUpdatePropSheetData(HWND hDlg, LPDL_INFO lpPai, int nPropSheet)
  751. {
  752. BOOL bRet = TRUE;
  753. ULONG cValues = 0;
  754. LPSPropValue rgPropVals = NULL;
  755. // update old props to knock out
  756. //
  757. if (lpPai->ulOperationType != SHOW_ONE_OFF)
  758. {
  759. bUpdateOldDLPropTagArray(lpPai, nPropSheet);
  760. lpPai->bSomethingChanged = ChangedExtDisplayInfo(lpPai, lpPai->bSomethingChanged);
  761. if(lpPai->bSomethingChanged)
  762. {
  763. bRet = GetDLFromUI(hDlg, nPropSheet, lpPai, lpPai->bSomethingChanged, &rgPropVals, &cValues );
  764. if(cValues && rgPropVals)
  765. lpPai->lpPropObj->lpVtbl->SetProps(lpPai->lpPropObj, cValues, rgPropVals, NULL);
  766. }
  767. }
  768. if(rgPropVals)
  769. MAPIFreeBuffer(rgPropVals);
  770. return bRet;
  771. }
  772. #define lpPAI ((LPDL_INFO) pps->lParam)
  773. #define lpbSomethingChanged (&(lpPAI->bSomethingChanged))
  774. void UpdateAddButton(HWND hDlg)
  775. {
  776. BOOL fEnable = TRUE;
  777. WPARAM wpDefaultID = IDC_DISTLIST_BUTTON_ADDUPDATE;
  778. if (0 == GetWindowTextLength(GetDlgItem(hDlg, IDC_DISTLIST_EDIT_ADDNAME)) &&
  779. 0 == GetWindowTextLength(GetDlgItem(hDlg, IDC_DISTLIST_EDIT_ADDEMAIL)))
  780. {
  781. fEnable = FALSE;
  782. wpDefaultID = IDOK;
  783. }
  784. EnableWindow(GetDlgItem(hDlg,IDC_DISTLIST_BUTTON_ADDUPDATE), fEnable);
  785. SendMessage(hDlg, DM_SETDEFID, wpDefaultID, 0);
  786. }
  787. /*//$$***********************************************************************
  788. * FUNCTION: fnHomeProc
  789. *
  790. * PURPOSE: Callback function for handling the HOME property sheet ...
  791. *
  792. ****************************************************************************/
  793. INT_PTR CALLBACK fnDLProc(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam)
  794. {
  795. PROPSHEETPAGE * pps;
  796. BOOL bRet = FALSE;
  797. ULONG ulcPropCount = 0;
  798. int CtlID = 0; //used to determine which required field in the UI has not been set
  799. pps = (PROPSHEETPAGE *) GetWindowLongPtr(hDlg, DWLP_USER);
  800. switch(message)
  801. {
  802. case WM_INITDIALOG:
  803. SetWindowLongPtr(hDlg,DWLP_USER,lParam);
  804. pps = (PROPSHEETPAGE *) lParam;
  805. SetDLUI(hDlg, propGroup);
  806. (*lpbSomethingChanged) = FALSE;
  807. // Show Details if we need to ...
  808. if ( (lpPAI->ulOperationType == SHOW_DETAILS) ||
  809. (lpPAI->ulOperationType == SHOW_ONE_OFF) )
  810. {
  811. FillDLUI(hDlg, propGroup, lpPAI, lpbSomethingChanged);
  812. }
  813. UpdateAddButton(hDlg);
  814. return TRUE;
  815. default:
  816. if((g_msgMSWheel && message == g_msgMSWheel)
  817. // || message == WM_MOUSEWHEEL
  818. )
  819. {
  820. SendMessage(GetDlgItem(hDlg, IDC_DISTLIST_LISTVIEW), message, wParam, lParam);
  821. }
  822. break;
  823. case WM_HELP:
  824. WABWinHelp(((LPHELPINFO)lParam)->hItemHandle,
  825. g_szWABHelpFileName,
  826. HELP_WM_HELP,
  827. (DWORD_PTR)(LPSTR) rgDLHelpIDs );
  828. break;
  829. case WM_SYSCOLORCHANGE:
  830. //Forward any system changes to the list view
  831. SendMessage(GetDlgItem(hDlg, IDC_DISTLIST_LISTVIEW), message, wParam, lParam);
  832. break;
  833. case WM_CONTEXTMENU:
  834. {
  835. int id = GetDlgCtrlID((HWND)wParam);
  836. switch(id)
  837. {
  838. case IDC_DISTLIST_LISTVIEW:
  839. ShowLVContextMenu(lvDialogABTo,(HWND)wParam, NULL, lParam, NULL,lpPAI->lpIAB, NULL);
  840. break;
  841. default:
  842. WABWinHelp((HWND) wParam,
  843. g_szWABHelpFileName,
  844. HELP_CONTEXTMENU,
  845. (DWORD_PTR)(LPVOID) rgDLHelpIDs );
  846. break;
  847. }
  848. }
  849. break;
  850. case WM_COMMAND:
  851. switch(GET_WM_COMMAND_CMD(wParam,lParam)) //check the notification code
  852. {
  853. case EN_CHANGE: //some edit box changed - dont care which
  854. if(LOWORD(wParam) == IDC_DISTLIST_EDIT_ADDNAME || LOWORD(wParam) == IDC_DISTLIST_EDIT_ADDEMAIL)
  855. {
  856. UpdateAddButton(hDlg);
  857. return 0;
  858. break;
  859. }
  860. else if (lpbSomethingChanged)
  861. (*lpbSomethingChanged) = TRUE;
  862. switch(LOWORD(wParam))
  863. { //update title as necessary
  864. case IDC_DISTLIST_EDIT_GROUPNAME:
  865. {
  866. TCHAR szBuf[MAX_UI_STR];
  867. GetWindowText((HWND) lParam,szBuf,CharSizeOf(szBuf));
  868. SetWindowPropertiesTitle(GetParent(hDlg), szBuf);
  869. }
  870. break;
  871. }
  872. break;
  873. }
  874. switch(GET_WM_COMMAND_ID(wParam,lParam)) //check the notification code
  875. {
  876. default:
  877. return ProcessActionCommands((LPIAB) lpPAI->lpIAB,
  878. GetDlgItem(hDlg, IDC_DISTLIST_LISTVIEW),
  879. hDlg, message, wParam, lParam);
  880. break;
  881. case IDC_DISTLIST_BUTTON_UPDATECANCEL:
  882. SetCancelOneOffUpdateUI(hDlg, lpPAI, NULL, NULL, TRUE);
  883. break;
  884. case IDC_DISTLIST_BUTTON_ADDUPDATE:
  885. HrAddUpdateOneOffEntryToGroup(hDlg, lpPAI);
  886. break;
  887. case IDCANCEL:
  888. // This is a windows bug that prevents ESC canceling prop sheets
  889. // which have MultiLine Edit boxes KB: Q130765
  890. SendMessage(GetParent(hDlg),message,wParam,lParam);
  891. break;
  892. case IDM_LVCONTEXT_COPY:
  893. HrCopyItemDataToClipboard(hDlg, lpPAI->lpIAB, GetDlgItem(hDlg, IDC_DISTLIST_LISTVIEW));
  894. break;
  895. case IDM_LVCONTEXT_PROPERTIES:
  896. case IDC_DISTLIST_BUTTON_PROPERTIES:
  897. HrShowGroupEntryProperties(hDlg, GetDlgItem(hDlg, IDC_DISTLIST_LISTVIEW), lpPAI);
  898. break;
  899. case IDM_LVCONTEXT_DELETE:
  900. case IDC_DISTLIST_BUTTON_REMOVE:
  901. RemoveSelectedDistListItems( GetDlgItem(hDlg, IDC_DISTLIST_LISTVIEW),lpPAI);
  902. UpdateLVCount(hDlg);
  903. break;
  904. case IDC_DISTLIST_BUTTON_ADD:
  905. AddDLMembers(hDlg, GetDlgItem(hDlg, IDC_DISTLIST_LISTVIEW), lpPAI);
  906. UpdateLVCount(hDlg);
  907. break;
  908. case IDC_DISTLIST_BUTTON_ADDNEW:
  909. {
  910. HWND hWndLV = GetDlgItem(hDlg, IDC_DISTLIST_LISTVIEW);
  911. AddNewObjectToListViewEx( lpPAI->lpIAB, hWndLV, NULL, NULL,
  912. NULL,
  913. MAPI_MAILUSER,
  914. NULL, &(lpPAI->lpContentsList), NULL, NULL, NULL);
  915. UpdateLVCount(hDlg);
  916. }
  917. break;
  918. }
  919. break;
  920. case WM_NOTIFY:
  921. #ifdef WIN16 // Enable context menu for WIN16
  922. if((int) wParam == IDC_DISTLIST_LISTVIEW && ((NMHDR FAR *)lParam)->code == NM_RCLICK)
  923. {
  924. POINT pt;
  925. GetCursorPos(&pt);
  926. ShowLVContextMenu(lvDialogABTo,((NMHDR FAR *)lParam)->hwndFrom, NULL, MAKELPARAM(pt.x, pt.y), NULL,lpPAI->lpIAB, NULL);
  927. }
  928. #endif // WIN16
  929. switch(((NMHDR FAR *)lParam)->code)
  930. {
  931. case PSN_SETACTIVE: //initialize
  932. break;
  933. case PSN_KILLACTIVE: //Losing activation to another page
  934. bUpdatePropSheetData(hDlg, lpPAI, propGroup);
  935. break;
  936. case PSN_APPLY: //ok
  937. if (lpPAI->ulOperationType != SHOW_ONE_OFF)
  938. {
  939. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  940. if(pt_bDisableParent)
  941. {
  942. SetWindowLongPtr(hDlg,DWLP_MSGRESULT, TRUE);
  943. return TRUE;
  944. }
  945. if(!bVerifyDLRequiredData(hDlg, (LPIAB)lpPAI->lpIAB, lpPAI->lpszOldName, &CtlID))
  946. {
  947. if (CtlID != 0) SetFocus(GetDlgItem(hDlg,CtlID));
  948. //something failed ... abort this OK ... ie dont let them close
  949. SetWindowLongPtr(hDlg,DWLP_MSGRESULT, TRUE);
  950. return TRUE;
  951. }
  952. bUpdatePropSheetData(hDlg, lpPAI, propGroup);
  953. }
  954. lpPAI->nRetVal = DETAILS_OK;
  955. SetCancelOneOffUpdateUI(hDlg, lpPAI, NULL, NULL, TRUE);
  956. ClearListView(GetDlgItem(hDlg,IDC_DISTLIST_LISTVIEW),
  957. &(lpPAI->lpContentsList));
  958. break;
  959. case PSN_RESET: //cancel
  960. {
  961. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  962. if(pt_bDisableParent)
  963. {
  964. SetWindowLongPtr(hDlg,DWLP_MSGRESULT, TRUE);
  965. return TRUE;
  966. }
  967. }
  968. lpPAI->nRetVal = DETAILS_CANCEL;
  969. SetCancelOneOffUpdateUI(hDlg, lpPAI, NULL, NULL, TRUE);
  970. ClearListView(GetDlgItem(hDlg,IDC_DISTLIST_LISTVIEW),
  971. &(lpPAI->lpContentsList));
  972. break;
  973. case LVN_KEYDOWN:
  974. switch(wParam)
  975. {
  976. case IDC_DISTLIST_LISTVIEW:
  977. switch(((LV_KEYDOWN FAR *) lParam)->wVKey)
  978. {
  979. case VK_DELETE:
  980. SendMessage (hDlg, WM_COMMAND, (WPARAM) IDC_DISTLIST_BUTTON_REMOVE, 0);
  981. return 0;
  982. break;
  983. }
  984. break;
  985. }
  986. break;
  987. case NM_DBLCLK:
  988. switch(wParam)
  989. {
  990. case IDC_DISTLIST_LISTVIEW:
  991. SendMessage(hDlg, WM_COMMAND, IDC_DISTLIST_BUTTON_PROPERTIES,0);
  992. break;
  993. }
  994. break;
  995. case NM_CUSTOMDRAW:
  996. switch(wParam)
  997. {
  998. case IDC_DISTLIST_LISTVIEW:
  999. return ProcessLVCustomDraw(hDlg, lParam, TRUE);
  1000. break;
  1001. }
  1002. break;
  1003. }
  1004. return TRUE;
  1005. }
  1006. return bRet;
  1007. }
  1008. //$$///////////////////////////////////////////////////////////////////
  1009. //
  1010. // Removes all the items on the list view which are selected ...
  1011. //
  1012. //
  1013. //////////////////////////////////////////////////////////////////////
  1014. void RemoveSelectedDistListItems(HWND hWndLV, LPDL_INFO lpPai)
  1015. {
  1016. int iItemIndex = ListView_GetNextItem(hWndLV, -1 , LVNI_SELECTED);
  1017. int iLastItem = 0;
  1018. while(iItemIndex != -1)
  1019. {
  1020. LPRECIPIENT_INFO lpItem = GetItemFromLV(hWndLV, iItemIndex);;
  1021. if (lpItem)
  1022. {
  1023. if(lpItem->lpNext)
  1024. lpItem->lpNext->lpPrev = lpItem->lpPrev;
  1025. if(lpItem->lpPrev)
  1026. lpItem->lpPrev->lpNext = lpItem->lpNext;
  1027. if (lpPai->lpContentsList == lpItem)
  1028. lpPai->lpContentsList = lpItem->lpNext;
  1029. if (lpItem)
  1030. FreeRecipItem(&lpItem);
  1031. }
  1032. ListView_DeleteItem(hWndLV, iItemIndex);
  1033. iLastItem = iItemIndex;
  1034. iItemIndex = ListView_GetNextItem(hWndLV, -1 , LVNI_SELECTED);
  1035. }
  1036. // Select the first item ..
  1037. if (ListView_GetItemCount(hWndLV) <= 0)
  1038. {
  1039. HWND hWnd = GetParent(hWndLV);
  1040. if (hWnd)
  1041. {
  1042. EnableWindow(GetDlgItem(hWnd,IDC_DISTLIST_BUTTON_PROPERTIES),FALSE);
  1043. EnableWindow(GetDlgItem(hWnd,IDC_DISTLIST_BUTTON_REMOVE),FALSE);
  1044. }
  1045. EnableWindow(hWndLV, FALSE);
  1046. }
  1047. else
  1048. {
  1049. if(iLastItem > 0)
  1050. iLastItem--;
  1051. LVSelectItem(hWndLV, iLastItem);
  1052. }
  1053. return;
  1054. };
  1055. /***************************************************************************
  1056. //$$
  1057. Name : HrCreateAdrListFromLV
  1058. Purpose : Creates an AdrList from a List Views contents
  1059. Parameters: lpIAB = adrbook
  1060. hWndLV = hWnd of List View
  1061. lpCOntentsList = ContentsList corresponding to the LV
  1062. lppAdrList - returned AdrList ...
  1063. Returns : HRESULT
  1064. Comment :
  1065. ***************************************************************************/
  1066. HRESULT HrCreateAdrListFromLV(LPADRBOOK lpAdrBook,
  1067. HWND hWndLV,
  1068. LPADRLIST * lppAdrList)
  1069. {
  1070. HRESULT hr = E_FAIL;
  1071. ULONG nIndex = 0;
  1072. LPADRLIST lpAdrList = NULL;
  1073. SCODE sc = S_OK;
  1074. int nEntryCount=0;
  1075. LPRECIPIENT_INFO lpItem = NULL;
  1076. int i = 0;
  1077. if(!lppAdrList)
  1078. goto out;
  1079. else
  1080. *lppAdrList = NULL;
  1081. nEntryCount = ListView_GetItemCount(hWndLV);
  1082. if (nEntryCount <= 0)
  1083. {
  1084. hr = S_OK;
  1085. goto out;
  1086. }
  1087. sc = MAPIAllocateBuffer(sizeof(ADRLIST) + nEntryCount * sizeof(ADRENTRY),
  1088. &lpAdrList);
  1089. if(FAILED(sc))
  1090. {
  1091. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  1092. goto out;
  1093. }
  1094. lpAdrList->cEntries = (ULONG) nEntryCount;
  1095. nIndex = 0;
  1096. for(i=nEntryCount;i>=0;i--)
  1097. {
  1098. LPRECIPIENT_INFO lpItem = GetItemFromLV(hWndLV, i);
  1099. // Get item lParam LPRECIPIENT_INFO structure
  1100. if (lpItem)
  1101. {
  1102. LPSPropValue rgProps = NULL;
  1103. LPSPropValue lpPropArrayNew = NULL;
  1104. ULONG cValues = 0;
  1105. ULONG cValuesNew = 0;
  1106. if (lpItem->cbEntryID != 0)
  1107. {
  1108. //resolved entry
  1109. hr = HrGetPropArray(lpAdrBook,
  1110. (LPSPropTagArray) &ptaResolveDefaults,
  1111. lpItem->cbEntryID,
  1112. lpItem->lpEntryID,
  1113. MAPI_UNICODE,
  1114. &cValues,
  1115. &rgProps);
  1116. if (!HR_FAILED(hr))
  1117. {
  1118. SPropValue Prop = {0};
  1119. Prop.ulPropTag = PR_RECIPIENT_TYPE;
  1120. Prop.Value.l = MAPI_TO;
  1121. sc = ScMergePropValues( 1,
  1122. &Prop,
  1123. cValues,
  1124. rgProps,
  1125. &cValuesNew,
  1126. &lpPropArrayNew);
  1127. if (sc != S_OK)
  1128. {
  1129. // oops this failed
  1130. if (lpPropArrayNew)
  1131. MAPIFreeBuffer(lpPropArrayNew);
  1132. }
  1133. //free rgProps
  1134. if (rgProps)
  1135. MAPIFreeBuffer(rgProps);
  1136. if(cValuesNew && lpPropArrayNew)
  1137. {
  1138. lpAdrList->aEntries[nIndex].cValues = cValuesNew;
  1139. lpAdrList->aEntries[nIndex].rgPropVals = lpPropArrayNew;
  1140. nIndex++;
  1141. }
  1142. }
  1143. else
  1144. {
  1145. if(cValues && rgProps)
  1146. MAPIFreeBuffer(rgProps);
  1147. } // if(!HR_F...
  1148. } //if(lpItem->cbE...
  1149. }//if(lpItem...
  1150. } // for i...
  1151. *lppAdrList = lpAdrList;
  1152. hr = S_OK;
  1153. out:
  1154. return hr;
  1155. }
  1156. //$$////////////////////////////////////////////////////////////////////////
  1157. //
  1158. // Scans an Adrlist for dupes - only scans the first nUpto entries since
  1159. // whenever we start adding an entry, we will only check vs its peers
  1160. //
  1161. // Returns TRUE if Dupe found
  1162. // FALSE if no Dupe found
  1163. ////////////////////////////////////////////////////////////////////////////
  1164. BOOL CheckForDupes( LPADRLIST lpAdrList,
  1165. int nUpto,
  1166. LPSBinary lpsbEntryID)
  1167. {
  1168. BOOL bDupeFound = FALSE;
  1169. int i;
  1170. for(i=0;i<nUpto;i++)
  1171. {
  1172. LPSBinary lpsb = FindAdrEntryID(lpAdrList, i);
  1173. if (lpsb)
  1174. {
  1175. if(lpsb->cb == lpsbEntryID->cb)
  1176. {
  1177. if(!memcmp(lpsb->lpb, lpsbEntryID->lpb, lpsb->cb))
  1178. {
  1179. bDupeFound = TRUE;
  1180. break;
  1181. }
  1182. else if (lpsb->cb == SIZEOF_WAB_ENTRYID)
  1183. {
  1184. // sometimes we dont find the match if we just replaced an entryid
  1185. // case to DWORDS and compare
  1186. DWORD dw1 = 0;
  1187. DWORD dw2 = 0;
  1188. CopyMemory(&dw1, lpsb->lpb, SIZEOF_WAB_ENTRYID);
  1189. CopyMemory(&dw2, lpsbEntryID->lpb, SIZEOF_WAB_ENTRYID);
  1190. if(dw1 == dw2)
  1191. {
  1192. bDupeFound = TRUE;
  1193. break;
  1194. }
  1195. }
  1196. }
  1197. }
  1198. }
  1199. return bDupeFound;
  1200. }
  1201. /***************************************************************************
  1202. Name : AddDLMembers
  1203. Purpose : Shows Select Members dialog and adds selections to ListView
  1204. Parameters: hWnd = hWndParent
  1205. hWndLV hWnd of List View
  1206. lpPai = DistList Info
  1207. Returns : void
  1208. Comment :
  1209. ***************************************************************************/
  1210. void AddDLMembers(HWND hwnd, HWND hWndLV, LPDL_INFO lpPai)
  1211. {
  1212. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  1213. ADRPARM AdrParms = {0};
  1214. HRESULT hResult = hrSuccess;
  1215. LPADRLIST lpAdrList = NULL;
  1216. ULONG i = 0;
  1217. LPSBinary lpsbEntryID;
  1218. LPADRBOOK lpAdrBook = lpPai->lpIAB;
  1219. TCHAR szCaption[MAX_UI_STR];
  1220. TCHAR szWellTitle[MAX_DISPLAY_NAME_LENGTH];
  1221. TCHAR szMemberTitle[MAX_DISPLAY_NAME_LENGTH];
  1222. LPTSTR lpszDT[1];
  1223. HCURSOR hOldCur = NULL;
  1224. LoadString(hinstMapiX, idsGroupAddCaption, szCaption, CharSizeOf(szCaption));
  1225. LoadString(hinstMapiX, idsGroupAddWellButton, szWellTitle, CharSizeOf(szWellTitle));
  1226. LoadString(hinstMapiX, idsGroupDestWellsTitle, szMemberTitle, CharSizeOf(szMemberTitle));
  1227. // TBe - this is temp
  1228. AdrParms.ulFlags = DIALOG_MODAL | MAPI_UNICODE;
  1229. AdrParms.lpszCaption = szCaption;
  1230. AdrParms.cDestFields = 1;
  1231. AdrParms.lpszDestWellsTitle = szMemberTitle;
  1232. lpszDT[0]=szWellTitle;
  1233. AdrParms.lppszDestTitles = lpszDT;
  1234. hResult = HrCreateAdrListFromLV(lpAdrBook,
  1235. hWndLV,
  1236. &lpAdrList);
  1237. if(HR_FAILED(hResult))
  1238. {
  1239. // no need to fail here .. keep going
  1240. lpAdrList = NULL;
  1241. }
  1242. hResult = lpAdrBook->lpVtbl->Address(lpAdrBook,
  1243. (PULONG_PTR)&hwnd,
  1244. &AdrParms,
  1245. &lpAdrList);
  1246. if (! hResult && lpAdrList)
  1247. {
  1248. BOOL bFirstNonWABEntry = FALSE;
  1249. pt_bDisableParent = TRUE;
  1250. hOldCur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1251. // Clear out the list view ...
  1252. SendMessage(hWndLV, WM_SETREDRAW, (WPARAM) FALSE, 0);
  1253. ClearListView(hWndLV, &(lpPai->lpContentsList));
  1254. for (i = 0; i < lpAdrList->cEntries; i++)
  1255. {
  1256. if (lpsbEntryID = FindAdrEntryID(lpAdrList, i))
  1257. {
  1258. if(!CheckForDupes(lpAdrList, i, lpsbEntryID))
  1259. {
  1260. ULONG cbEID = lpsbEntryID->cb;
  1261. LPENTRYID lpEID = (LPENTRYID)lpsbEntryID->lpb;
  1262. ULONG cbNewEID = 0;
  1263. LPENTRYID lpNewEID = NULL;
  1264. // if we have picked any entries from an LDAP server, we need
  1265. // to save these entries to the WAB before we can add them to this group.
  1266. if(WAB_LDAP_MAILUSER == IsWABEntryID(cbEID,
  1267. lpEID,
  1268. NULL,NULL,NULL, NULL, NULL))
  1269. {
  1270. HRESULT hr = S_OK;
  1271. // Add this entry to the WAB
  1272. if(!bFirstNonWABEntry)
  1273. {
  1274. bFirstNonWABEntry = TRUE;
  1275. ShowMessageBox(hwnd, idsNowAddingToWAB, MB_OK | MB_ICONINFORMATION);
  1276. }
  1277. hr = HrEntryAddToWAB(lpAdrBook,
  1278. hwnd,
  1279. cbEID,
  1280. lpEID,
  1281. &cbNewEID,
  1282. &lpNewEID);
  1283. if(HR_FAILED(hr) || (!cbNewEID && !lpNewEID))
  1284. {
  1285. continue;
  1286. }
  1287. lpEID = lpNewEID;
  1288. cbEID = cbNewEID;
  1289. // if this newly added entry just replaced something already in the group,
  1290. // just go ahead and continue without changing anything else ...
  1291. {
  1292. SBinary SB = {0};
  1293. SB.cb = cbEID;
  1294. SB.lpb = (LPBYTE) lpEID;
  1295. if(CheckForDupes(lpAdrList, lpAdrList->cEntries, &SB))
  1296. {
  1297. continue;
  1298. }
  1299. }
  1300. }
  1301. if (CheckForCycle( lpAdrBook,
  1302. lpEID,
  1303. cbEID,
  1304. lpPai->lpEntryID,
  1305. lpPai->cbEntryID))
  1306. {
  1307. DebugTrace( TEXT("DLENTRY_SaveChanges found cycle\n"));
  1308. {
  1309. LPTSTR lpszGroup=NULL;
  1310. ULONG k;
  1311. for(k=0;k<lpAdrList->aEntries[i].cValues;k++)
  1312. {
  1313. if (lpAdrList->aEntries[i].rgPropVals[k].ulPropTag == PR_DISPLAY_NAME)
  1314. {
  1315. lpszGroup = lpAdrList->aEntries[i].rgPropVals[k].Value.LPSZ;
  1316. break;
  1317. }
  1318. }
  1319. if(lpszGroup)
  1320. {
  1321. // TEXT("Could not add group %s to this group because group %s already contains this Group.")
  1322. ShowMessageBoxParam(hwnd, idsCouldNotAddGroupToGroup, MB_ICONERROR, lpszGroup);
  1323. }
  1324. }
  1325. if(lpNewEID)
  1326. MAPIFreeBuffer(lpNewEID);
  1327. continue;
  1328. }
  1329. AddWABEntryToListView(lpAdrBook,
  1330. hWndLV,
  1331. cbEID,
  1332. lpEID,
  1333. &(lpPai->lpContentsList));
  1334. if(lpNewEID)
  1335. MAPIFreeBuffer(lpNewEID);
  1336. // Since LDAP entries take longer to add to the WAB, we will
  1337. // update the UI between additions if adding from LDAP so user
  1338. // knows that something is happening ...
  1339. if ((ListView_GetItemCount(hWndLV) > 0) &&
  1340. bFirstNonWABEntry )
  1341. {
  1342. EnableWindow(GetDlgItem(hwnd,IDC_DISTLIST_BUTTON_PROPERTIES),TRUE);
  1343. EnableWindow(GetDlgItem(hwnd,IDC_DISTLIST_BUTTON_REMOVE),TRUE);
  1344. EnableWindow(hWndLV, TRUE);
  1345. SendMessage(hWndLV, WM_SETREDRAW, (WPARAM) TRUE, 0);
  1346. }
  1347. }
  1348. }
  1349. }
  1350. SendMessage(hWndLV, WM_SETREDRAW, (WPARAM) TRUE, 0);
  1351. }
  1352. if (ListView_GetItemCount(hWndLV) > 0)
  1353. {
  1354. EnableWindow(GetDlgItem(hwnd,IDC_DISTLIST_BUTTON_PROPERTIES),TRUE);
  1355. EnableWindow(GetDlgItem(hwnd,IDC_DISTLIST_BUTTON_REMOVE),TRUE);
  1356. EnableWindow(hWndLV, TRUE);
  1357. }
  1358. UpdateWindow(hWndLV);
  1359. if(lpAdrList)
  1360. FreePadrlist(lpAdrList);
  1361. if(hOldCur)
  1362. SetCursor(hOldCur);
  1363. pt_bDisableParent = FALSE;
  1364. return;
  1365. }
  1366. /***************************************************************************
  1367. Name : FindAdrEntryID
  1368. Purpose : Find the PR_ENTRYID in the Nth ADRENTRY of an ADRLIST
  1369. Parameters: lpAdrList -> AdrList
  1370. index = which ADRENTRY to look at
  1371. Returns : return pointer to the SBinary structure of the ENTRYID value
  1372. Comment :
  1373. ***************************************************************************/
  1374. LPSBinary FindAdrEntryID(LPADRLIST lpAdrList, ULONG index) {
  1375. LPADRENTRY lpAdrEntry;
  1376. ULONG i;
  1377. if (lpAdrList && index < lpAdrList->cEntries) {
  1378. lpAdrEntry = &(lpAdrList->aEntries[index]);
  1379. for (i = 0; i < lpAdrEntry->cValues; i++) {
  1380. if (lpAdrEntry->rgPropVals[i].ulPropTag == PR_ENTRYID) {
  1381. return((LPSBinary)&lpAdrEntry->rgPropVals[i].Value);
  1382. }
  1383. }
  1384. }
  1385. return(NULL);
  1386. }
  1387. /*//$$***********************************************************************
  1388. * FUNCTION: fnDLOtherProc
  1389. *
  1390. * PURPOSE: Callback function for handling the OTHER property sheet ...
  1391. *
  1392. ****************************************************************************/
  1393. INT_PTR CALLBACK fnDLOtherProc(HWND hDlg,UINT message,WPARAM wParam,LPARAM lParam)
  1394. {
  1395. PROPSHEETPAGE * pps;
  1396. BOOL bRet = FALSE;
  1397. ULONG ulcPropCount = 0;
  1398. int CtlID = 0; //used to determine which required field in the UI has not been set
  1399. pps = (PROPSHEETPAGE *) GetWindowLongPtr(hDlg, DWLP_USER);
  1400. switch(message)
  1401. {
  1402. case WM_INITDIALOG:
  1403. SetWindowLongPtr(hDlg,DWLP_USER,lParam);
  1404. pps = (PROPSHEETPAGE *) lParam;
  1405. ChangeLocaleBasedTabOrder(hDlg, groupOther);
  1406. SetDLUI(hDlg, propGroupOther);
  1407. (*lpbSomethingChanged) = FALSE;
  1408. // Show Details if we need to ...
  1409. if ( (lpPAI->ulOperationType == SHOW_DETAILS) ||
  1410. (lpPAI->ulOperationType == SHOW_ONE_OFF) )
  1411. {
  1412. FillDLUI(hDlg, propGroupOther, lpPAI, lpbSomethingChanged);
  1413. }
  1414. return TRUE;
  1415. default:
  1416. if((g_msgMSWheel && message == g_msgMSWheel)
  1417. // || message == WM_MOUSEWHEEL
  1418. )
  1419. {
  1420. SendMessage(GetDlgItem(hDlg, IDC_DISTLIST_LISTVIEW), message, wParam, lParam);
  1421. }
  1422. break;
  1423. case WM_HELP:
  1424. WABWinHelp(((LPHELPINFO)lParam)->hItemHandle,
  1425. g_szWABHelpFileName,
  1426. HELP_WM_HELP,
  1427. (DWORD_PTR)(LPSTR) rgDLHelpIDs );
  1428. break;
  1429. case WM_CONTEXTMENU:
  1430. WABWinHelp((HWND) wParam,
  1431. g_szWABHelpFileName,
  1432. HELP_CONTEXTMENU,
  1433. (DWORD_PTR)(LPVOID) rgDLHelpIDs );
  1434. break;
  1435. case WM_COMMAND:
  1436. switch(GET_WM_COMMAND_CMD(wParam,lParam)) //check the notification code
  1437. {
  1438. case EN_CHANGE: //some edit box changed - dont care which
  1439. if (lpbSomethingChanged)
  1440. (*lpbSomethingChanged) = TRUE;
  1441. }
  1442. switch(GET_WM_COMMAND_ID(wParam,lParam)) //check the notification code
  1443. {
  1444. case IDCANCEL:
  1445. // This is a windows bug that prevents ESC canceling prop sheets
  1446. // which have MultiLine Edit boxes KB: Q130765
  1447. SendMessage(GetParent(hDlg),message,wParam,lParam);
  1448. break;
  1449. case IDC_DISTLIST_BUTTON_MAP:
  1450. bUpdatePropSheetData(hDlg, lpPAI, propGroupOther);
  1451. ShowExpediaMAP(hDlg, lpPAI->lpPropObj, TRUE);
  1452. break;
  1453. case IDC_DISTLIST_BUTTON_URL:
  1454. ShowURL(hDlg, IDC_DISTLIST_EDIT_URL,NULL);
  1455. break;
  1456. }
  1457. break;
  1458. case WM_NOTIFY:
  1459. switch(((NMHDR FAR *)lParam)->code)
  1460. {
  1461. case PSN_SETACTIVE: //initialize
  1462. break;
  1463. case PSN_KILLACTIVE: //Losing activation to another page
  1464. bUpdatePropSheetData(hDlg, lpPAI, propGroupOther);
  1465. break;
  1466. case PSN_APPLY: //ok
  1467. if (lpPAI->ulOperationType != SHOW_ONE_OFF)
  1468. {
  1469. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  1470. if(pt_bDisableParent)
  1471. {
  1472. SetWindowLongPtr(hDlg,DWLP_MSGRESULT, TRUE);
  1473. return TRUE;
  1474. }
  1475. bUpdatePropSheetData(hDlg, lpPAI, propGroupOther);
  1476. }
  1477. lpPAI->nRetVal = DETAILS_OK;
  1478. break;
  1479. case PSN_RESET: //cancel
  1480. {
  1481. LPPTGDATA lpPTGData=GetThreadStoragePointer();
  1482. if(pt_bDisableParent)
  1483. {
  1484. SetWindowLongPtr(hDlg,DWLP_MSGRESULT, TRUE);
  1485. return TRUE;
  1486. }
  1487. }
  1488. lpPAI->nRetVal = DETAILS_CANCEL;
  1489. break;
  1490. }
  1491. return TRUE;
  1492. }
  1493. return bRet;
  1494. }
  1495. /*
  1496. - HrAssociateOneOffGroupMembersWithContacts()
  1497. -
  1498. * Takes a group .. opens it up .. looks at all the one-off members
  1499. * in the group, tries to match them up with corresponding entries that
  1500. * have the same PR_DEFAULT_EMAIL address and for the ones that match,
  1501. * removes the one-off entry and adds the entryid of the match to the group
  1502. *
  1503. * lpsbGroupEID - EntryID of the Group
  1504. * lpDistList - already open Distribution List object .. you can pass in
  1505. * either the entryid or the already opened object. If you pass in an
  1506. * open object, this function will not call SaveChanges on it. SaveChanges
  1507. * is callers responsibility
  1508. */
  1509. HRESULT HrAssociateOneOffGroupMembersWithContacts(LPADRBOOK lpAdrBook,
  1510. LPSBinary lpsbGroupEID,
  1511. LPDISTLIST lpDistList)
  1512. {
  1513. HRESULT hr = E_FAIL;
  1514. SizedSPropTagArray(3, ptaDL)=
  1515. {
  1516. 3,
  1517. {
  1518. PR_DISPLAY_NAME,
  1519. PR_WAB_DL_ENTRIES,
  1520. PR_WAB_DL_ONEOFFS,
  1521. }
  1522. };
  1523. SizedSPropTagArray(1, ptaEmail)= { 1, { PR_EMAIL_ADDRESS } };
  1524. ULONG ulcValues = 0, i,ulCount = 0;
  1525. int j = 0;
  1526. LPSPropValue lpProps = NULL;
  1527. LPDISTLIST lpDL = NULL;
  1528. ULONG ulObjType = 0;
  1529. LPIAB lpIAB = (LPIAB)lpAdrBook;
  1530. BOOL * lpbRemove = NULL;
  1531. if(!lpDistList && (!lpsbGroupEID || !lpsbGroupEID->cb || !lpsbGroupEID->lpb) )
  1532. goto out;
  1533. if(lpDistList)
  1534. lpDL = lpDistList;
  1535. else
  1536. {
  1537. if (HR_FAILED(hr = lpAdrBook->lpVtbl->OpenEntry(lpAdrBook,
  1538. lpsbGroupEID->cb, // cbEntryID
  1539. (LPENTRYID)lpsbGroupEID->lpb, // entryid
  1540. NULL, // interface
  1541. MAPI_MODIFY, // ulFlags
  1542. &ulObjType, // returned object type
  1543. (LPUNKNOWN *)&lpDL)))
  1544. {
  1545. // Failed! Hmmm.
  1546. DebugTraceResult( TEXT("Address: IAB->OpenEntry:"), hr);
  1547. goto out;
  1548. }
  1549. Assert(lpDL);
  1550. if(ulObjType != MAPI_DISTLIST)
  1551. goto out;
  1552. }
  1553. if (HR_FAILED(hr = lpDL->lpVtbl->GetProps(lpDL,(LPSPropTagArray)&ptaDL,
  1554. MAPI_UNICODE, &ulcValues, &lpProps)))
  1555. {
  1556. DebugTraceResult( TEXT("Address: IAB->GetProps:"), hr);
  1557. goto out;
  1558. }
  1559. // Check if this one has the one-offs prop or not
  1560. if( ulcValues < dlMax ||
  1561. lpProps[dlDLOneOffs].ulPropTag != PR_WAB_DL_ONEOFFS ||
  1562. lpProps[dlDLOneOffs].Value.MVbin.cValues == 0)
  1563. goto out;
  1564. ulCount = lpProps[dlDLOneOffs].Value.MVbin.cValues;
  1565. lpbRemove = LocalAlloc(LMEM_ZEROINIT, sizeof(BOOL)*ulCount);
  1566. if(!lpbRemove)
  1567. {
  1568. hr = MAPI_E_NOT_ENOUGH_MEMORY;
  1569. goto out;
  1570. }
  1571. for(i=0;i<ulCount;i++)
  1572. {
  1573. LPSBinary lpsb = &(lpProps[dlDLOneOffs].Value.MVbin.lpbin[i]);
  1574. ULONG ulc = 0;
  1575. LPSPropValue lpsp = NULL;
  1576. lpbRemove[i]=FALSE;
  1577. if(!HR_FAILED(hr = HrGetPropArray(lpAdrBook, (LPSPropTagArray)&ptaEmail, lpsb->cb, (LPENTRYID)lpsb->lpb,
  1578. MAPI_UNICODE,
  1579. &ulc, &lpsp)))
  1580. {
  1581. if(ulc == 1 && lpsp[0].ulPropTag == PR_EMAIL_ADDRESS &&
  1582. lpsp[0].Value.LPSZ && lstrlen(lpsp[0].Value.LPSZ))
  1583. {
  1584. // got an e-mail address .. see if it resolves uniquely or not
  1585. ULONG ulMatch = 0;
  1586. LPSBinary rgsbEntryIDs = NULL;
  1587. if(!HR_FAILED(HrFindFuzzyRecordMatches(lpIAB->lpPropertyStore->hPropertyStore,
  1588. NULL,
  1589. lpsp[0].Value.LPSZ,
  1590. AB_FUZZY_FIND_EMAIL | AB_FUZZY_FAIL_AMBIGUOUS,
  1591. &ulMatch,
  1592. &rgsbEntryIDs)))
  1593. {
  1594. // Note: there is a problem with the above search is that
  1595. // [email protected] will uniquely match [email protected] since its a
  1596. // substring search used
  1597. //
  1598. if(ulMatch == 1)
  1599. {
  1600. // Single unique match .. use it
  1601. // Reset this entryid in the original DL_ONEOFF props and
  1602. // set the found entryid in the DL_ENTRIES prop
  1603. // For now, mark the one-off as having 0 size .. we will clean this up
  1604. // after we've gone through this loop once
  1605. lpbRemove[i] = TRUE;
  1606. AddPropToMVPBin(lpProps, dlDLEntries, rgsbEntryIDs[0].lpb, rgsbEntryIDs[0].cb, TRUE);
  1607. }
  1608. FreeEntryIDs(lpIAB->lpPropertyStore->hPropertyStore, ulMatch, rgsbEntryIDs);
  1609. }
  1610. }
  1611. FreeBufferAndNull(&lpsp);
  1612. }
  1613. }
  1614. // Now we've hopefully gone and changed everything, clean up the original list of oneoffs
  1615. ulCount = lpProps[dlDLOneOffs].Value.MVbin.cValues;
  1616. for(j=ulCount-1;j>=0;j--)
  1617. {
  1618. if(lpbRemove[j] == TRUE)
  1619. {
  1620. LPSBinary lpsb = &(lpProps[dlDLOneOffs].Value.MVbin.lpbin[j]);
  1621. RemovePropFromMVBin(lpProps,dlMax,dlDLOneOffs,lpsb->lpb, lpsb->cb);
  1622. }
  1623. }
  1624. // if we removed all the OneOffs from the entry, then RemovePropFromMVBin just sets
  1625. // the prop tag on the prop to be PR_NULL .. instead we need to physically knock out
  1626. // that prop from the object
  1627. if( lpProps[dlDLOneOffs].Value.MVbin.cValues == 0 ||
  1628. lpProps[dlDLOneOffs].ulPropTag == PR_NULL )
  1629. {
  1630. SizedSPropTagArray(1, tagDLOneOffs) = { 1, PR_WAB_DL_ONEOFFS };
  1631. lpDL->lpVtbl->DeleteProps(lpDL, (LPSPropTagArray) &tagDLOneOffs, NULL);
  1632. }
  1633. if (HR_FAILED(hr = lpDL->lpVtbl->SetProps(lpDL, ulcValues, lpProps, NULL)))
  1634. goto out;
  1635. if(!lpDistList)
  1636. hr = lpDL->lpVtbl->SaveChanges(lpDL, 0);
  1637. out:
  1638. if(lpDL && lpDL != lpDistList)
  1639. lpDL->lpVtbl->Release(lpDL);
  1640. FreeBufferAndNull(&lpProps);
  1641. LocalFreeAndNull(&lpbRemove);
  1642. return hr;
  1643. }