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.

526 lines
14 KiB

  1. /*
  2. * w e l l s . c p p
  3. *
  4. * Purpose:
  5. * implments name checking and stuff for the wells
  6. *
  7. * Author:brettm
  8. *
  9. * Ported to C++ and modified for Athena from Capone src
  10. */
  11. #include <pch.hxx>
  12. #include <resource.h>
  13. #include <richedit.h>
  14. #include <ipab.h>
  15. #include <addrlist.h>
  16. #include "addrobj.h"
  17. #include "wells.h"
  18. #include "header.h"
  19. #include <ourguid.h>
  20. ASSERTDATA
  21. HRESULT CAddrWells::HrInit(ULONG cWells, HWND *rgHwnd, ULONG *rgRecipType)
  22. {
  23. if(cWells<=0 || rgHwnd==NULL || rgRecipType==NULL)
  24. return E_INVALIDARG;
  25. Assert(m_rgHwnd==NULL);
  26. Assert(m_rgRecipType==NULL);
  27. Assert(m_cWells==0);
  28. if(!MemAlloc((LPVOID *)&m_rgHwnd, sizeof(HWND)*cWells))
  29. return E_OUTOFMEMORY;
  30. if(!MemAlloc((LPVOID *)&m_rgRecipType, sizeof(ULONG)*cWells))
  31. return E_OUTOFMEMORY;
  32. CopyMemory(m_rgHwnd, rgHwnd, sizeof(HWND)*cWells);
  33. CopyMemory(m_rgRecipType, rgRecipType, sizeof(ULONG)*cWells);
  34. m_cWells=cWells;
  35. return NOERROR;
  36. }
  37. HRESULT CAddrWells::HrSetWabal(LPWABAL lpWabal)
  38. {
  39. Assert(lpWabal);
  40. if(!lpWabal)
  41. return E_INVALIDARG;
  42. ReleaseObj(m_lpWabal);
  43. m_lpWabal=lpWabal;
  44. m_lpWabal->AddRef();
  45. return NOERROR;
  46. }
  47. HRESULT CAddrWells::HrCheckNames(HWND hwnd, ULONG uFlags)
  48. {
  49. HRESULT hr=NOERROR;
  50. ULONG ulWell;
  51. HCURSOR hcur;
  52. BOOL fDirty=FALSE;
  53. if(!m_lpWabal)
  54. return E_FAIL;
  55. // This optimization will only occur in the office envelope
  56. // on autosave. In most cases, the ResolveNames in the header
  57. // will stop before calling down to this level. For the other
  58. // minority cases, we should leave this code in.
  59. for(ulWell=0; ulWell<m_cWells; ulWell++)
  60. if(Edit_GetModify(m_rgHwnd[ulWell]))
  61. {
  62. fDirty=TRUE;
  63. break;
  64. }
  65. if(!fDirty)
  66. return NOERROR;
  67. hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  68. // clear the current list
  69. m_lpWabal->Reset();
  70. for(ulWell=0; ulWell<m_cWells; ulWell++)
  71. if(Edit_GetModify(m_rgHwnd[ulWell]))
  72. hr=HrAddNamesToList(m_rgHwnd[ulWell], m_rgRecipType[ulWell]);
  73. if(!(uFlags&CNF_DONTRESOLVE))
  74. {
  75. if(uFlags&CNF_SILENTRESOLVEUI)
  76. hr=m_lpWabal->HrResolveNames(NULL, FALSE);
  77. else
  78. hr=m_lpWabal->HrResolveNames(hwnd, TRUE);
  79. HrDisplayWells(hwnd);
  80. }
  81. if(hcur)
  82. SetCursor(hcur);
  83. return hr;
  84. }
  85. HRESULT CAddrWells::HrDisplayWells(HWND hwnd)
  86. {
  87. HRESULT hr=E_FAIL;
  88. HCURSOR hcursor;
  89. HWND hwndBlock;
  90. ULONG ulWell;
  91. if (m_lpWabal)
  92. {
  93. hcursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  94. // brettm: hack taken from Capone. LockUpdateWindow doesn't work for the
  95. // richedit, so we block paints by covering the edit controls with a
  96. // paint-swallowing window until we're done...
  97. hwndBlock=HwndStartBlockingPaints(hwnd);
  98. // empty the wells...
  99. for(ulWell=0; ulWell<m_cWells; ulWell++)
  100. SetWindowText(m_rgHwnd[ulWell], NULL);
  101. hr=HrAddRecipientsToWells();
  102. StopBlockingPaints(hwndBlock);
  103. if (hcursor)
  104. SetCursor(hcursor);
  105. }
  106. return hr;
  107. }
  108. CAddrWells::CAddrWells()
  109. {
  110. m_lpWabal = 0;
  111. m_rgHwnd = NULL;
  112. m_rgRecipType = NULL;
  113. m_cWells = 0;
  114. };
  115. CAddrWells::~CAddrWells()
  116. {
  117. ReleaseObj(m_lpWabal);
  118. if(m_rgRecipType)
  119. MemFree(m_rgRecipType);
  120. if(m_rgHwnd)
  121. MemFree(m_rgHwnd);
  122. };
  123. HRESULT CAddrWells::HrAddNamesToList(HWND hwndWell, LONG lRecipType)
  124. {
  125. ULONG iOb;
  126. ULONG cOb;
  127. REOBJECT reobj = {0};
  128. HRESULT hr;
  129. PHCI phci;
  130. LPRICHEDITOLE preole;
  131. LPPERSIST ppersist = NULL;
  132. LPWSTR pwszText = NULL;
  133. DWORD cch;
  134. Assert(IsWindow(hwndWell));
  135. // if the edit is not dirty, we're done
  136. if(!Edit_GetModify(hwndWell))
  137. return S_OK;
  138. phci = (HCI*)GetWindowLongPtr(hwndWell, GWLP_USERDATA);
  139. Assert(phci);
  140. preole = phci->preole;
  141. Assert(preole);
  142. m_hwndWell = hwndWell;
  143. m_cchBuf = 0;
  144. m_fTruncated = FALSE;
  145. m_lRecipType = lRecipType;
  146. reobj.cbStruct = sizeof(reobj);
  147. cOb = preole->GetObjectCount();
  148. for (iOb = 0; iOb < cOb; iOb++)
  149. {
  150. LPADRINFO pAdrInfo=NULL;
  151. IF_FAILEXIT(hr = preole->GetObject(iOb, &reobj, REO_GETOBJ_POLEOBJ));
  152. IF_FAILEXIT(hr = reobj.poleobj->QueryInterface(IID_IPersist, (LPVOID *)&ppersist));
  153. #ifdef DEBUG
  154. AssertValidAddrObject(reobj.poleobj);
  155. #endif
  156. // HrGetAdrInfo doesn't alloc memory.
  157. IF_FAILEXIT(hr = ((CAddrObj *)ppersist)->HrGetAdrInfo(&pAdrInfo));
  158. // set the new recipient type...
  159. pAdrInfo->lRecipType=lRecipType;
  160. IF_FAILEXIT(hr = m_lpWabal->HrAddEntry(pAdrInfo));
  161. SafeRelease(ppersist);
  162. SafeRelease(reobj.poleobj);
  163. }
  164. // now we add in all the unresolved names...
  165. cch = GetRichEditTextLen(m_hwndWell) + 1;
  166. if (0 == cch)
  167. return (S_FALSE);
  168. IF_NULLEXIT(MemAlloc((LPVOID*)&pwszText, cch * sizeof(WCHAR)));
  169. GetRichEditText(m_hwndWell, pwszText, cch, FALSE, phci->pDoc);
  170. hr = UnresolvedText(pwszText, cch - 1);
  171. // Add whatever is left after the last semicolon
  172. if (SUCCEEDED(hr))
  173. HrAddUnresolvedName();
  174. exit:
  175. if(m_fTruncated) // warn if we trucated an address
  176. MessageBeep(MB_OK);
  177. ReleaseObj(reobj.poleobj);
  178. ReleaseObj(ppersist);
  179. MemFree(pwszText);
  180. return hr;
  181. }
  182. HRESULT CAddrWells::OnFontChange()
  183. {
  184. ULONG ulWell;
  185. for(ulWell=0; ulWell<m_cWells; ulWell++)
  186. _UpdateFont(m_rgHwnd[ulWell]);
  187. return S_OK;
  188. }
  189. HRESULT CAddrWells::_UpdateFont(HWND hwndWell)
  190. {
  191. ULONG iOb;
  192. ULONG cOb;
  193. REOBJECT rObject={0};
  194. IRichEditOle *pREOle;
  195. IOleInPlaceSite *pIPS;
  196. LPPERSIST pPersist = NULL;
  197. rObject.cbStruct = sizeof(REOBJECT);
  198. // walk the ole objects and send them an font-update
  199. if (SendMessage(hwndWell, EM_GETOLEINTERFACE, 0, (LPARAM) &pREOle))
  200. {
  201. cOb = pREOle->GetObjectCount();
  202. for (iOb = 0; iOb < cOb; iOb++)
  203. {
  204. if (pREOle->GetObject(iOb, &rObject, REO_GETOBJ_POLEOBJ)==S_OK)
  205. {
  206. if (rObject.poleobj->QueryInterface(IID_IPersist, (LPVOID *)&pPersist)==S_OK)
  207. {
  208. ((CAddrObj *)pPersist)->OnFontChange();
  209. pPersist->Release();
  210. }
  211. rObject.poleobj->Release();
  212. }
  213. }
  214. pREOle->Release();
  215. }
  216. InvalidateRect(hwndWell, NULL, TRUE);
  217. return S_OK;
  218. }
  219. HRESULT CAddrWells::HrAddUnresolvedName()
  220. {
  221. HRESULT hr = S_OK;
  222. // strip any trailing white-space
  223. while(m_cchBuf > 0 && (m_rgwch[m_cchBuf - 1] == L' '
  224. || m_rgwch[m_cchBuf - 1] == L'\t'))
  225. --m_cchBuf;
  226. if (m_cchBuf)
  227. {
  228. // there is something in the buffer...
  229. m_rgwch[m_cchBuf] = L'\0';
  230. hr = m_lpWabal->HrAddUnresolved(m_rgwch, m_lRecipType);
  231. m_cchBuf = 0;
  232. }
  233. return hr;
  234. }
  235. HRESULT CAddrWells::UnresolvedText(LPWSTR pwszText, LONG cch)
  236. {
  237. HRESULT hr = S_OK;
  238. // The algorithm below will strip spaces off of the
  239. // beginning and end of each name
  240. while (cch)
  241. {
  242. cch--;
  243. // On some versions of richedit, 0xfffc is inserted in the text
  244. // where there is a addrObj present. So just skip over that.
  245. if ((L'\t' == *pwszText) || (0xfffc == *pwszText))
  246. *pwszText = L' ';
  247. if (*pwszText == L';' || *pwszText == L'\r'|| *pwszText == L',')
  248. {
  249. hr = HrAddUnresolvedName();
  250. if (S_OK != hr)
  251. goto err;
  252. }
  253. else
  254. {
  255. if ((*pwszText != L' ' && *pwszText != L'\n' && *pwszText != L'\r')
  256. || m_cchBuf > 0)
  257. {
  258. if (m_cchBuf < ARRAYSIZE(m_rgwch) - 1)
  259. m_rgwch[m_cchBuf++] = *pwszText;
  260. else
  261. // Truncation has occurred so I want to beep
  262. m_fTruncated = TRUE;
  263. }
  264. }
  265. ++pwszText;
  266. }
  267. err:
  268. return hr;
  269. }
  270. enum
  271. {
  272. mapiTo=0,
  273. mapiCc,
  274. mapiFrom,
  275. mapiReplyTo,
  276. mapiBcc,
  277. mapiMax
  278. };
  279. HRESULT CAddrWells::HrAddRecipientsToWells()
  280. {
  281. HRESULT hr;
  282. ADRINFO AdrInfo;
  283. HWND hwnd;
  284. HWND hwndMap[mapiMax]={0};
  285. ULONG ulWell;
  286. Assert(m_lpWabal);
  287. // walk the list of entries, and add them to the well...
  288. // build mapping to MAPI_TO -> hwnd if available to make the lookup quicker..
  289. for(ulWell=0; ulWell<m_cWells; ulWell++)
  290. {
  291. switch(m_rgRecipType[ulWell])
  292. {
  293. case MAPI_TO:
  294. hwndMap[mapiTo]=m_rgHwnd[ulWell];
  295. break;
  296. case MAPI_CC:
  297. hwndMap[mapiCc]=m_rgHwnd[ulWell];
  298. break;
  299. case MAPI_BCC:
  300. hwndMap[mapiBcc]=m_rgHwnd[ulWell];
  301. break;
  302. case MAPI_REPLYTO:
  303. hwndMap[mapiReplyTo]=m_rgHwnd[ulWell];
  304. break;
  305. case MAPI_ORIG:
  306. hwndMap[mapiFrom]=m_rgHwnd[ulWell];
  307. break;
  308. }
  309. }
  310. if(m_lpWabal->FGetFirst(&AdrInfo))
  311. {
  312. do
  313. {
  314. hwnd=0;
  315. switch(AdrInfo.lRecipType)
  316. {
  317. case MAPI_TO:
  318. hwnd=hwndMap[mapiTo];
  319. break;
  320. case MAPI_CC:
  321. hwnd=hwndMap[mapiCc];
  322. break;
  323. case MAPI_ORIG:
  324. hwnd=hwndMap[mapiFrom];
  325. break;
  326. case MAPI_BCC:
  327. hwnd=hwndMap[mapiBcc];
  328. break;
  329. case MAPI_REPLYTO:
  330. hwnd=hwndMap[mapiReplyTo];
  331. break;
  332. default:
  333. AssertSz(0, "Unsupported RECIPTYPE in AdrList");
  334. }
  335. if(hwnd && IsWindow(hwnd))
  336. {
  337. hr = HrAddRecipientToWell(hwnd, &AdrInfo, TRUE);
  338. if(FAILED(hr))
  339. return hr;
  340. }
  341. }
  342. while(m_lpWabal->FGetNext(&AdrInfo));
  343. }
  344. return NOERROR;
  345. }
  346. /*
  347. * HrAddRecipientToWell
  348. *
  349. * Purpose:
  350. * This function adds a recipient to a recipient well.
  351. *
  352. * Parameters:
  353. * hwndEdit hwnd of the recipient well to add the
  354. * recipient to
  355. * pae pointer to an ADRENTRY
  356. * fAddSemi whether to add a semicolon between entries
  357. * fCopyEntry whether to copy the ADRENTRY or just use it
  358. *
  359. * Returns:
  360. * scode
  361. */
  362. HRESULT HrAddRecipientToWell(HWND hwndEdit, LPADRINFO lpAdrInfo, BOOL fAddSemi)
  363. {
  364. HRESULT hr = S_OK;
  365. CAddrObj *pAddrObj = NULL;
  366. INT cch;
  367. REOBJECT reobj = {0};
  368. PHCI phci;
  369. LPRICHEDITOLE preole;
  370. Assert(IsWindow(hwndEdit));
  371. Assert(lpAdrInfo);
  372. phci = (HCI*)GetWindowLongPtr(hwndEdit, GWLP_USERDATA);
  373. Assert(phci);
  374. preole = phci->preole;
  375. Assert(preole);
  376. if(lpAdrInfo->fResolved)
  377. {
  378. // Initialize the object information structure
  379. reobj.cbStruct = sizeof(reobj);
  380. reobj.cp = REO_CP_SELECTION;
  381. reobj.clsid = CLSID_AddrObject;
  382. reobj.dwFlags = REO_BELOWBASELINE|REO_INVERTEDSELECT|
  383. REO_DYNAMICSIZE|REO_DONTNEEDPALETTE;
  384. reobj.dvaspect = DVASPECT_CONTENT;
  385. IF_FAILEXIT(hr = preole->GetClientSite(&reobj.polesite));
  386. IF_NULLEXIT(pAddrObj = new CAddrObj());
  387. IF_FAILEXIT(hr = pAddrObj->HrSetAdrInfo(lpAdrInfo));
  388. }
  389. if (fAddSemi && (cch = GetRichEditTextLen(hwndEdit)))
  390. {
  391. Edit_SetSel(hwndEdit, cch, cch);
  392. HdrSetRichEditText(hwndEdit, L"; ", TRUE);
  393. }
  394. if (!lpAdrInfo->fResolved)
  395. {
  396. // Its an unresolved name
  397. AssertSz(lpAdrInfo->lpwszDisplay, "Recipient must have a Display Name");
  398. HdrSetRichEditText(hwndEdit, lpAdrInfo->lpwszDisplay, TRUE);
  399. }
  400. else
  401. {
  402. // Its a resolved name
  403. IF_FAILEXIT(hr = pAddrObj->QueryInterface(IID_IOleObject, (LPVOID *)&reobj.poleobj));
  404. IF_FAILEXIT(hr = reobj.poleobj->SetClientSite(reobj.polesite));
  405. IF_FAILEXIT(hr = preole->InsertObject(&reobj));
  406. }
  407. exit:
  408. ReleaseObj(reobj.poleobj);
  409. ReleaseObj(reobj.polesite);
  410. ReleaseObj(pAddrObj);
  411. return hr;
  412. }
  413. HRESULT CAddrWells::HrSelectNames(HWND hwnd, int iFocus, BOOL fNews)
  414. {
  415. HRESULT hr;
  416. ULONG ulWell;
  417. m_lpWabal->Reset();
  418. for(ulWell=0; ulWell<m_cWells; ulWell++)
  419. if(Edit_GetModify(m_rgHwnd[ulWell]))
  420. hr=HrAddNamesToList(m_rgHwnd[ulWell], m_rgRecipType[ulWell]);
  421. hr=m_lpWabal->HrPickNames(hwnd, m_rgRecipType, m_cWells, iFocus, fNews);
  422. if(FAILED(hr))
  423. goto error;
  424. hr=HrDisplayWells(hwnd);
  425. if(FAILED(hr))
  426. goto error;
  427. error:
  428. return hr;
  429. }