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.

7280 lines
208 KiB

  1. /*
  2. * b o d y . c p p
  3. *
  4. * Purpose:
  5. * base class implementation of Body object. Derrives from CDocHost to host the trident
  6. * control.
  7. *
  8. * History
  9. * August '96: brettm - created
  10. *
  11. * Copyright (C) Microsoft Corp. 1995, 1996.
  12. */
  13. #include <pch.hxx>
  14. #include "dllmain.h"
  15. #include <shfusion.h>
  16. #include "resource.h"
  17. #include "strconst.h"
  18. #include "htmlstr.h"
  19. #include "mimeolep.h"
  20. #include "mimeutil.h"
  21. #include "htiframe.h" // ITargetFrame2
  22. #include "htiface.h" // ITargetFramePriv
  23. #include "vervec.h" // IVersion*
  24. #include "triutil.h"
  25. #include "util.h"
  26. // #include "dochost.h"
  27. #ifdef PLUSPACK
  28. #include "htmlsp.h"
  29. #endif //PLUSPACK
  30. #include "body.h"
  31. #include "bodyutil.h"
  32. #include "oleutil.h"
  33. #include "secmgr.h"
  34. #include "mhtml.h"
  35. #include "fmtbar.h"
  36. #include "fontcash.h"
  37. #include "attmenu.h"
  38. #include "saveatt.h"
  39. #include "frames.h"
  40. #include "richedit.h"
  41. #include "viewsrc.h"
  42. #include "spell.h"
  43. #include "tags.h"
  44. #include "optary.h"
  45. #include "shlwapip.h"
  46. #include <icutil.h>
  47. #include <demand.h>
  48. ASSERTDATA
  49. /*
  50. * m a c r o s
  51. */
  52. #define SetMenuItem(hmenu, id, fOn) EnableMenuItem(hmenu, id, (fOn)?MF_ENABLED:MF_DISABLED|MF_GRAYED);
  53. /*
  54. * c o n s t a n t s
  55. */
  56. #define BKGRNDSPELL_TICKTIME 100
  57. #define AUTODETECT_CHUNK 16384
  58. #define AUTODETECT_TICKTIME 200
  59. #define AUTODETECT_TIMEOUT 10
  60. //#define USE_ABORT_TIMER
  61. #define idTimerAutoDetect 110
  62. #define idTimerBkgrndSpell 111
  63. static WCHAR c_szMailToW[] =L"mailto:",
  64. c_szOECmdW[] =L"oecmd:",
  65. c_szHttpW[] =L"http://",
  66. c_szFileW[] =L"file://";
  67. #define CX_LABEL_PADDING 4
  68. #define CY_LINE_PADDING 4
  69. #define COLOR_HEADER COLOR_3DFACE
  70. #define COLOR_HEADERTXT COLOR_BTNTEXT
  71. #define COLOR_HEADERFOCUS COLOR_HIGHLIGHT
  72. #define COLOR_HEADERTXTFOCUS COLOR_HIGHLIGHTTEXT
  73. #define SMALLHEADERHEIGHT 3
  74. #define CX_PANEICON 30
  75. #define CY_PANEICON 30
  76. #define CY_PANEPADDING (2*GetSystemMetrics(SM_CYBORDER))
  77. #define CX_PANEPADDING (2*GetSystemMetrics(SM_CXBORDER))
  78. enum
  79. {
  80. IBTF_INSERTATEND = 0x0001,
  81. IBTF_URLHIGHLIGHT = 0x0002
  82. };
  83. #define idcTabs 999
  84. #define idcSrcEdit 998
  85. #define HDRTXT_BOLD 0x01
  86. #define HDRTXT_SYSTEMFONT 0x02
  87. /*
  88. * t y p e d e f s
  89. */
  90. class CVerHost :
  91. public IVersionHost
  92. {
  93. public:
  94. CVerHost();
  95. virtual ~CVerHost();
  96. // IUnknown
  97. virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID, LPVOID FAR *);
  98. virtual ULONG STDMETHODCALLTYPE AddRef();
  99. virtual ULONG STDMETHODCALLTYPE Release();
  100. // IVersionHost
  101. virtual HRESULT STDMETHODCALLTYPE QueryUseLocalVersionVector(BOOL *fUseLocal);
  102. virtual HRESULT STDMETHODCALLTYPE QueryVersionVector(IVersionVector *pVersion);
  103. private:
  104. ULONG m_cRef;
  105. };
  106. /*
  107. * g l o b a l s
  108. */
  109. static const TCHAR c_szCaretSpanTag[] = "<SPAN id=\"__#Ath#CaretPos__\">&nbsp;</SPAN>",
  110. c_szCaretSpan[] = "__#Ath#CaretPos__",
  111. c_szSignatureSpanTag[] = "&nbsp;<SPAN id=\"__#Ath#SignaturePos__\"></SPAN>&nbsp;",
  112. c_szSignatureSpan[] = "__#Ath#SignaturePos__",
  113. c_szSigPrefix[] = "\r\n-- \r\n";
  114. /*
  115. * f u n c t i o n p r o t y p e s
  116. */
  117. HRESULT CALLBACK FreeDataObj(PDATAOBJINFO pDataObjInfo, DWORD celt);
  118. HRESULT HrSniffUrlForRfc822(LPWSTR pszUrlW);
  119. /*
  120. * f u n c t i o n s
  121. */
  122. //+---------------------------------------------------------------
  123. //
  124. // Member: CBody
  125. //
  126. // Synopsis:
  127. //
  128. //---------------------------------------------------------------
  129. CBody::CBody()
  130. {
  131. m_dwReadyState = READYSTATE_UNINITIALIZED;
  132. m_pszUrlW = NULL;
  133. m_pMsg = NULL;
  134. m_pMsgW = NULL;
  135. m_pDoc = NULL;
  136. m_hCharset=NULL;
  137. m_dwNotify=0;
  138. m_pTempFileUrl=NULL;
  139. m_pParentDocHostUI=NULL;
  140. m_pParentCmdTarget=NULL;
  141. m_pParentInPlaceSite=0;
  142. m_pParentInPlaceFrame=0;
  143. m_fPlainMode=FALSE;
  144. m_uHdrStyle = MESTYLE_NOHEADER ;
  145. m_pszLayout = NULL;
  146. m_pszFrom = 0;
  147. m_pszTo = 0;
  148. m_pszCc = 0;
  149. m_pszSubject = 0;
  150. m_fEmpty = 1;
  151. m_fMessageParsed=0;
  152. m_fDirty=0;
  153. m_fDesignMode=0;
  154. m_fAutoDetect=0;
  155. m_fOnImage=0;
  156. m_fTabLinks=0;
  157. m_pFmtBar=NULL;
  158. m_fLoading=1;
  159. m_fForceCharsetLoad=FALSE;
  160. m_pRangeIgnoreSpell=0;
  161. m_pFontCache=0;
  162. m_pDocActiveObj = 0;
  163. m_pAttMenu=NULL;
  164. m_hwndBtnBar=NULL;
  165. m_hIml=0;
  166. m_hImlHot=0;
  167. m_cVisibleBtns=0;
  168. m_pAttMenu=NULL;
  169. m_pSecMgr = NULL;
  170. m_hwndTab=NULL;
  171. m_hwndSrc=NULL;
  172. m_uSrcView = 0;
  173. m_pSrcView=NULL;
  174. m_fSrcTabs = 0;
  175. m_fReloadingSrc = FALSE;
  176. m_pSpell = 0;
  177. m_fBkgrndSpelling = FALSE;
  178. m_cchTotal = 0;
  179. m_dwFontCacheNotify = 0;
  180. m_fWasDirty = 0;
  181. m_pDispContext=0;
  182. m_dwContextItem=0;
  183. m_pstmHtmlSrc=NULL;
  184. m_pHashExternal = NULL;
  185. m_dwAutoTicks = 0;
  186. m_pAutoStartPtr = 0;
  187. m_fIgnoreAccel = 0;
  188. #ifdef PLUSPACK
  189. m_pBkgSpeller = NULL;
  190. #endif //PLUSPACK
  191. }
  192. //+---------------------------------------------------------------
  193. //
  194. // Member: CBody
  195. //
  196. // Synopsis:
  197. //
  198. //---------------------------------------------------------------
  199. CBody::~CBody()
  200. {
  201. Assert (m_pDispContext==NULL);
  202. SafeRelease(m_pAttMenu);
  203. SafeRelease(m_pParentInPlaceSite);
  204. SafeRelease(m_pParentInPlaceFrame);
  205. SafeRelease(m_pFmtBar);
  206. SafeRelease(m_pRangeIgnoreSpell);
  207. SafeRelease(m_pFontCache);
  208. SafeRelease(m_pSecMgr);
  209. SafeRelease(m_pSrcView);
  210. SafeRelease(m_pstmHtmlSrc);
  211. SafeRelease(m_pHashExternal);
  212. SafeRelease(m_pAutoStartPtr);
  213. Assert(m_pMsg==NULL);
  214. Assert(m_pMsgW==NULL);
  215. Assert(m_pTempFileUrl==NULL);
  216. Assert(m_pszFrom == 0);
  217. Assert(m_pszTo == 0);
  218. Assert(m_pszCc == 0);
  219. Assert(m_pszSubject == 0);
  220. SafeMemFree(m_pszLayout);
  221. if (m_hIml)
  222. ImageList_Destroy(m_hIml);
  223. if (m_hImlHot)
  224. ImageList_Destroy(m_hImlHot);
  225. }
  226. //+---------------------------------------------------------------
  227. //
  228. // Member: Init
  229. //
  230. // Synopsis: pHostInfo is used to set parent's sites and frames.
  231. // the parent inplace site is sent notifications on activation etc
  232. //
  233. //---------------------------------------------------------------
  234. HRESULT CBody::Init(HWND hwndParent, DWORD dwFlags, LPRECT prc, PBODYHOSTINFO pHostInfo)
  235. {
  236. HRESULT hr;
  237. TraceCall("CBody::Init");
  238. if (pHostInfo)
  239. {
  240. ReplaceInterface(m_pParentInPlaceSite, pHostInfo->pInPlaceSite);
  241. ReplaceInterface(m_pParentInPlaceFrame, pHostInfo->pInPlaceFrame);
  242. ReplaceInterface(m_pDocActiveObj, pHostInfo->pDoc);
  243. if (m_pParentInPlaceSite)
  244. {
  245. // get the dochostUIhandler to delegate to when setparent sites is called
  246. Assert(m_pParentDocHostUI==NULL);
  247. Assert(m_pParentCmdTarget==NULL);
  248. m_pParentInPlaceSite->QueryInterface(IID_IDocHostUIHandler, (LPVOID *)&m_pParentDocHostUI);
  249. m_pParentInPlaceSite->QueryInterface(IID_IOleCommandTarget, (LPVOID *)&m_pParentCmdTarget);
  250. }
  251. }
  252. m_dwStyle=dwFlags;
  253. hr = CDocHost::Init(hwndParent, dwFlags&MEBF_OUTERCLIENTEDGE, prc);
  254. if (FAILED(hr))
  255. goto error;
  256. hr = HrCreateFormatBar(m_hwnd, idcFmtBar, dwFlags&MEBF_FORMATBARSEP, &m_pFmtBar);
  257. if (FAILED(hr))
  258. goto error;
  259. // fire-up trident at init time
  260. hr = EnsureLoaded();
  261. error:
  262. return hr;
  263. }
  264. //+---------------------------------------------------------------
  265. //
  266. // Member: Close
  267. //
  268. // Synopsis:
  269. //
  270. //---------------------------------------------------------------
  271. HRESULT CBody::Close()
  272. {
  273. IConnectionPoint *pCP;
  274. TraceCall("CBody::Close");
  275. UnloadAll();
  276. RegisterLoadNotify(FALSE);
  277. #ifdef PLUSPACK
  278. SafeRelease(m_pBkgSpeller);
  279. #endif //PLUSPACK
  280. #ifdef BACKGROUNDSPELL
  281. if (m_pSpell && m_fBkgrndSpelling)
  282. {
  283. m_pSpell->HrRegisterKeyPressNotify(FALSE);
  284. KillTimer(m_hwnd, idTimerBkgrndSpell); // done. Stop the timer
  285. }
  286. #endif // BACKGROUNDSPELL
  287. // [email protected] - moved this from destructor - 31463 & 36253
  288. if(m_pSpell)
  289. m_pSpell->CloseSpeller();
  290. SafeRelease(m_pSpell);
  291. SafeRelease(m_pFmtBar);
  292. SafeRelease(m_pDoc);
  293. SafeRelease(m_pParentCmdTarget);
  294. SafeRelease(m_pParentDocHostUI);
  295. SafeRelease(m_pParentInPlaceSite);
  296. SafeRelease(m_pParentInPlaceFrame);
  297. SafeRelease(m_pDocActiveObj);
  298. if (m_pFontCache &&
  299. m_pFontCache->QueryInterface(IID_IConnectionPoint, (LPVOID *)&pCP)==S_OK)
  300. {
  301. pCP->Unadvise(m_dwFontCacheNotify);
  302. pCP->Release();
  303. }
  304. SafeRelease(m_pFontCache);
  305. CloseDocObj();
  306. if (m_hwnd)
  307. {
  308. DestroyWindow(m_hwnd);
  309. m_hwnd=NULL;
  310. }
  311. return S_OK;
  312. }
  313. //+---------------------------------------------------------------
  314. //
  315. // Member: WndProc
  316. //
  317. // Synopsis:
  318. //
  319. //---------------------------------------------------------------
  320. LRESULT CBody::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  321. {
  322. HWND hwndT;
  323. switch (msg)
  324. {
  325. case WM_WININICHANGE:
  326. case WM_DISPLAYCHANGE:
  327. case WM_SYSCOLORCHANGE:
  328. case WM_QUERYNEWPALETTE:
  329. case WM_PALETTECHANGED:
  330. if (m_pFmtBar &&
  331. m_pFmtBar->GetWindow(&hwndT)==S_OK)
  332. SendMessage(hwndT, msg, wParam, lParam);
  333. break;
  334. case WM_LBUTTONDOWN:
  335. if (!m_fFocus)
  336. SetFocus(m_hwnd);
  337. break;
  338. case WM_KILLFOCUS:
  339. case WM_SETFOCUS:
  340. OnFocus(msg==WM_SETFOCUS);
  341. break;
  342. case WM_SIZE:
  343. // since we do blit stuff we invalidate here
  344. InvalidateRect(m_hwnd, NULL, FALSE);
  345. break;
  346. case WM_ERASEBKGND:
  347. OnEraseBkgnd((HDC)wParam);
  348. return TRUE;
  349. case WM_CREATE:
  350. if (FAILED(OnWMCreate()))
  351. return -1;
  352. break;
  353. case WM_TIMER:
  354. if (wParam == idTimerAutoDetect)
  355. {
  356. AutoDetectTimer();
  357. return 0;
  358. }
  359. #ifdef BACKGROUNDSPELL
  360. if (wParam == idTimerBkgrndSpell)
  361. {
  362. if (m_pSpell)
  363. m_pSpell->HrBkgrndSpellTimer();
  364. return 0;
  365. }
  366. #endif // BACKGROUNDSPELL
  367. if (m_pSrcView &&
  368. m_pSrcView->OnTimer(wParam)==S_OK)
  369. return 0;
  370. break;
  371. case WM_COMMAND:
  372. if(OnWMCommand(
  373. GET_WM_COMMAND_HWND(wParam, lParam),
  374. GET_WM_COMMAND_ID(wParam, lParam),
  375. GET_WM_COMMAND_CMD(wParam, lParam))==S_OK)
  376. return 0;
  377. break;
  378. case WM_NOTIFY:
  379. return WMNotify(wParam, (NMHDR*)lParam);
  380. case WM_PAINT:
  381. if (OnPaint()==S_OK)
  382. return 0;
  383. break;
  384. }
  385. return CDocHost::WndProc(hwnd, msg, wParam, lParam);
  386. }
  387. //+---------------------------------------------------------------
  388. //
  389. // Member: QueryInterface
  390. //
  391. // Synopsis:
  392. //
  393. //---------------------------------------------------------------
  394. HRESULT CBody::QueryInterface(REFIID riid, LPVOID FAR *lplpObj)
  395. {
  396. TraceCall("CBody::QueryInterface");
  397. if(!lplpObj)
  398. return E_INVALIDARG;
  399. *lplpObj = NULL;
  400. if (IsEqualIID(riid, IID_IUnknown))
  401. *lplpObj = (IUnknown *)(IPropertyNotifySink *)this;
  402. else if (IsEqualIID(riid, IID_IPropertyNotifySink))
  403. *lplpObj = (IPropertyNotifySink *)this;
  404. else if (IsEqualIID(riid, IID_IDocHostUIHandler))
  405. *lplpObj = (IDocHostUIHandler*) this;
  406. else if (IsEqualIID(riid, IID_IPersistMime))
  407. *lplpObj = (IPersistMime*) this;
  408. else if (IsEqualIID(riid, IID_ITargetFramePriv))
  409. *lplpObj = (ITargetFramePriv*) this;
  410. else if (IsEqualIID(riid, IID_IPersistMoniker))
  411. *lplpObj = (LPVOID)(IPersistMoniker *)this;
  412. else if (IsEqualIID(riid, IID_IFontCacheNotify))
  413. *lplpObj = (LPVOID)(IFontCacheNotify *)this;
  414. #if 0
  415. else if (IsEqualIID(riid, IID_IDispatch))
  416. *lplpObj = (LPVOID)(IDispatch *)this;
  417. #endif
  418. else
  419. return CDocHost::QueryInterface(riid, lplpObj);
  420. AddRef();
  421. return NOERROR;
  422. }
  423. //+---------------------------------------------------------------
  424. //
  425. // Member: AddRef
  426. //
  427. // Synopsis:
  428. //
  429. //---------------------------------------------------------------
  430. ULONG CBody::AddRef()
  431. {
  432. TraceCall("CBody::AddRef");
  433. return CDocHost::AddRef();
  434. }
  435. //+---------------------------------------------------------------
  436. //
  437. // Member: Release
  438. //
  439. // Synopsis:
  440. //
  441. //---------------------------------------------------------------
  442. ULONG CBody::Release()
  443. {
  444. TraceCall("CBody::Release");
  445. return CDocHost::Release();
  446. }
  447. //+---------------------------------------------------------------
  448. //
  449. // Member: QueryService
  450. //
  451. // Synopsis:
  452. //
  453. //---------------------------------------------------------------
  454. HRESULT CBody::QueryService(REFGUID guidService, REFIID riid, LPVOID *ppvObject)
  455. {
  456. HRESULT hr=E_FAIL;
  457. IServiceProvider *pSP;
  458. IVersionHost *pVersion;
  459. //DebugPrintInterface(riid, "CBody::QueryService");
  460. // delegate to the mimeedit host first
  461. if (m_pParentInPlaceSite)
  462. {
  463. if (m_pParentInPlaceSite->QueryInterface(IID_IServiceProvider, (LPVOID *)&pSP)==S_OK)
  464. {
  465. hr = pSP->QueryService(guidService, riid, ppvObject);
  466. pSP->Release();
  467. if (hr==S_OK)
  468. return S_OK;
  469. }
  470. }
  471. if (IsEqualGUID(guidService, SID_SInternetSecurityManager))
  472. {
  473. if (!m_pSecMgr)
  474. CreateSecurityManger(m_pParentCmdTarget, &m_pSecMgr);
  475. if (m_pSecMgr)
  476. return m_pSecMgr->QueryInterface(riid, ppvObject);
  477. }
  478. else if (IsEqualGUID(guidService, IID_ITargetFrame2))
  479. return QueryInterface(riid, ppvObject);
  480. else if (IsEqualGUID(guidService, SID_SVersionHost) && IsEqualIID(riid, IID_IVersionHost))
  481. {
  482. pVersion = new CVerHost();
  483. if (!pVersion)
  484. return E_OUTOFMEMORY;
  485. *ppvObject = (LPVOID)(IVersionHost *)pVersion;
  486. return S_OK;
  487. }
  488. return CDocHost::QueryService(guidService, riid, ppvObject);
  489. }
  490. // *** IDocHostUIHandler ***
  491. //+---------------------------------------------------------------
  492. //
  493. // Member: GetHostInfo
  494. //
  495. // Synopsis:
  496. //
  497. //---------------------------------------------------------------
  498. HRESULT CBody::GetHostInfo( DOCHOSTUIINFO* pInfo )
  499. {
  500. HRESULT hr;
  501. TraceCall("CBody::GetHostInfo");
  502. if (m_pParentDocHostUI)
  503. {
  504. // see if parent dochostUIhandler want's to handle. If not they will return _DODEFAULT
  505. hr = m_pParentDocHostUI->GetHostInfo(pInfo);
  506. if (hr != MIMEEDIT_E_DODEFAULT)
  507. return hr;
  508. }
  509. pInfo->dwDoubleClick = DOCHOSTUIDBLCLK_DEFAULT;
  510. pInfo->dwFlags = DOCHOSTUIFLAG_DIV_BLOCKDEFAULT|DOCHOSTUIFLAG_OPENNEWWIN|
  511. DOCHOSTUIFLAG_ACTIVATE_CLIENTHIT_ONLY|
  512. DOCHOSTUIFLAG_IME_ENABLE_RECONVERSION |
  513. DOCHOSTUIFLAG_CODEPAGELINKEDFONTS;
  514. //This sets the flags that match the browser's encoding
  515. fGetBrowserUrlEncoding(&pInfo->dwFlags);
  516. if (!(m_dwStyle & MEBF_INNERCLIENTEDGE))
  517. pInfo->dwFlags |= DOCHOSTUIFLAG_NO3DBORDER;
  518. if (m_dwStyle & MEBF_NOSCROLL)
  519. pInfo->dwFlags |= DOCHOSTUIFLAG_SCROLL_NO;
  520. return S_OK;
  521. }
  522. //+---------------------------------------------------------------
  523. //
  524. // Member: ShowUI
  525. //
  526. // Synopsis:
  527. //
  528. //---------------------------------------------------------------
  529. HRESULT CBody::ShowUI(DWORD dwID, IOleInPlaceActiveObject *pActiveObject,
  530. IOleCommandTarget *pCommandTarget,
  531. IOleInPlaceFrame *pFrame,
  532. IOleInPlaceUIWindow *pDoc)
  533. {
  534. HRESULT hr;
  535. TraceCall("CBody::ShowUI");
  536. if (m_pParentDocHostUI)
  537. {
  538. // see if parent dochostUIhandler want's to handle. If not they will return _DODEFAULT
  539. hr = m_pParentDocHostUI->ShowUI(dwID, pActiveObject, pCommandTarget, pFrame, pDoc);
  540. if (hr != MIMEEDIT_E_DODEFAULT)
  541. return hr;
  542. }
  543. return S_OK;
  544. }
  545. //+---------------------------------------------------------------
  546. //
  547. // Member: HideUI
  548. //
  549. // Synopsis:
  550. //
  551. //---------------------------------------------------------------
  552. HRESULT CBody::HideUI(void)
  553. {
  554. HRESULT hr;
  555. TraceCall("CBody::HideUI");
  556. if (m_pParentDocHostUI)
  557. {
  558. // see if parent dochostUIhandler want's to handle. If not they will return _DODEFAULT
  559. hr = m_pParentDocHostUI->HideUI();
  560. if (hr != MIMEEDIT_E_DODEFAULT)
  561. return hr;
  562. }
  563. return S_OK;
  564. }
  565. //+---------------------------------------------------------------
  566. //
  567. // Member: UpdateUI
  568. //
  569. // Synopsis:
  570. //
  571. //---------------------------------------------------------------
  572. HRESULT CBody::UpdateUI(void)
  573. {
  574. HRESULT hr;
  575. TraceCall("CBody::UpdateUI");
  576. if (m_pParentDocHostUI)
  577. {
  578. // see if parent dochostUIhandler want's to handle. If not they will return _DODEFAULT
  579. hr = m_pParentDocHostUI->UpdateUI();
  580. if (hr != MIMEEDIT_E_DODEFAULT)
  581. return hr;
  582. }
  583. return S_OK;
  584. }
  585. //+---------------------------------------------------------------
  586. //
  587. // Member: EnableModeless
  588. //
  589. // Synopsis:
  590. //
  591. //---------------------------------------------------------------
  592. HRESULT CBody::EnableModeless(BOOL fEnable)
  593. {
  594. HRESULT hr;
  595. TraceCall("CBody::EnableModeless");
  596. if (m_pParentDocHostUI)
  597. {
  598. // see if parent dochostUIhandler want's to handle. If not they will return _DODEFAULT
  599. hr = m_pParentDocHostUI->EnableModeless(fEnable);
  600. if (hr != MIMEEDIT_E_DODEFAULT)
  601. return hr;
  602. }
  603. return E_NOTIMPL;
  604. }
  605. //+---------------------------------------------------------------
  606. //
  607. // Member: OnDocWindowActivate
  608. //
  609. // Synopsis:
  610. //
  611. //---------------------------------------------------------------
  612. HRESULT CBody::OnDocWindowActivate(BOOL fActivate)
  613. {
  614. HRESULT hr;
  615. TraceCall("CBody::OnDocWindowActivate");
  616. if (m_pParentDocHostUI)
  617. {
  618. // see if parent dochostUIhandler want's to handle. If not they will return _DODEFAULT
  619. hr = m_pParentDocHostUI->OnDocWindowActivate(fActivate);
  620. if (hr != MIMEEDIT_E_DODEFAULT)
  621. return hr;
  622. }
  623. return S_OK;
  624. }
  625. //+---------------------------------------------------------------
  626. //
  627. // Member: OnFrameWindowActivate
  628. //
  629. // Synopsis:
  630. //
  631. //---------------------------------------------------------------
  632. HRESULT CBody::OnFrameWindowActivate(BOOL fActivate)
  633. {
  634. HRESULT hr;
  635. TraceCall("CBody::OnFrameWindowActivate");
  636. if (m_pParentDocHostUI)
  637. {
  638. // see if parent dochostUIhandler want's to handle. If not they will return _DODEFAULT
  639. hr = m_pParentDocHostUI->OnFrameWindowActivate(fActivate);
  640. if (hr != MIMEEDIT_E_DODEFAULT)
  641. return hr;
  642. }
  643. return S_OK;
  644. }
  645. //+---------------------------------------------------------------
  646. //
  647. // Member: ResizeBorder
  648. //
  649. // Synopsis:
  650. //
  651. //---------------------------------------------------------------
  652. HRESULT CBody::ResizeBorder(LPCRECT prcBorder,
  653. IOleInPlaceUIWindow* pUIWindow,
  654. BOOL fRameWindow)
  655. {
  656. HRESULT hr;
  657. TraceCall("CBody::ResizeBorder");
  658. if (m_pParentDocHostUI)
  659. {
  660. // see if parent dochostUIhandler want's to handle. If not they will return _DODEFAULT
  661. hr = m_pParentDocHostUI->ResizeBorder(prcBorder, pUIWindow, fRameWindow);
  662. if (hr != MIMEEDIT_E_DODEFAULT)
  663. return hr;
  664. }
  665. return E_NOTIMPL;
  666. }
  667. //+---------------------------------------------------------------
  668. //
  669. // Member: ShowContextMenu
  670. //
  671. // Synopsis:
  672. //
  673. //---------------------------------------------------------------
  674. HRESULT CBody::ShowContextMenu( DWORD dwID,
  675. POINT *pptPosition,
  676. IUnknown *pcmdtReserved,
  677. IDispatch *pDispatchObjectHit)
  678. {
  679. HRESULT hr;
  680. HMENU hMenu=0;
  681. INT id;
  682. IHTMLTxtRange *pTxtRange=0;
  683. #ifdef PLUSPACK
  684. ISpellingSuggestions * pSuggestions = NULL;
  685. IMarkupPointer * pPointerLeft = NULL;
  686. IMarkupPointer * pPointerRight = NULL;
  687. IMarkupServices * pMarkupServices = NULL;
  688. IDisplayPointer * pDispPointer = NULL;
  689. IDisplayServices * pDisplayServices = NULL;
  690. IHTMLElement * pElement = NULL;
  691. IHTMLBodyElement * pBody = NULL;
  692. IHTMLTxtRange *pRange = NULL;
  693. IHTMLWindow2 *pWindow = NULL;
  694. IHTMLEventObj *pEvent = NULL;
  695. IHTMLSelectionObject * pSelection = NULL;
  696. VARIANT_BOOL fInSquiggle = VARIANT_FALSE;
  697. VARIANT var;
  698. BSTR bstrSuggestion = NULL;
  699. BSTR bstrWord = NULL;
  700. BSTR bstrSelectionType = NULL;
  701. TCHAR szAnsiSuggestion[256];
  702. INT cch;
  703. BOOL fRepeatWord;
  704. LONG lCount = 0;
  705. MENUITEMINFO mii = {0};
  706. LONG lButton;
  707. int i;
  708. #else
  709. BOOL fSpellSuggest=FALSE;
  710. #endif //PLUSPACK
  711. TraceCall("CBody::ShowContextMenu");
  712. if (m_pParentDocHostUI)
  713. {
  714. // see if parent dochostUIhandler want's to handle. If not they will return _DODEFAULT
  715. hr = m_pParentDocHostUI->ShowContextMenu(dwID, pptPosition, pcmdtReserved, pDispatchObjectHit);
  716. if (hr != MIMEEDIT_E_DODEFAULT)
  717. return hr;
  718. }
  719. Assert(m_lpOleObj && m_hwnd);
  720. m_dwContextItem = dwID;
  721. #ifdef PLUSPACK
  722. hr = GetSelection(&pTxtRange);
  723. // Background spell context menu
  724. if(m_fDesignMode && m_pBkgSpeller && m_pDoc)
  725. {
  726. // Check for squiggle
  727. //
  728. CHECKHR(hr = m_pBkgSpeller->IsInSquiggle(pTxtRange, &fInSquiggle) );
  729. if (fInSquiggle)
  730. { //only if we have a suggestion
  731. // Get suggestions
  732. //
  733. CHECKHR(hr = m_pBkgSpeller->GetSpellingSuggestions(pTxtRange, FALSE, &pSuggestions) );
  734. //
  735. // Create the context menu
  736. //
  737. if (!(hMenu = LoadPopupMenu(idmrCtxtSpellSuggest)))
  738. {
  739. hr = TraceResult(E_FAIL);
  740. goto exit;
  741. }
  742. /* CHECKHR(hr = pSuggestions->get_IsDoubleWord(&fRepeatWord) );
  743. if (fRepeatWord)
  744. {
  745. // if (!AppendMenuA(hMenu, MF_STRING, IDM_DELETEWORD, "&Delete Repeated Word"))
  746. // goto exit;
  747. }
  748. else
  749. { */
  750. //
  751. // Fill with suggestions
  752. //
  753. CHECKHR(hr = pSuggestions->get_Count(&lCount) );
  754. if (lCount < 1)
  755. {
  756. if (!AppendMenuA(hMenu, MF_DISABLED | MF_GRAYED, 1, "(no suggestions)"))
  757. goto exit;
  758. }
  759. else
  760. {
  761. V_VT(&var) = VT_I4;
  762. for (i = 0; (i <= lCount) && ((i + idmSuggest0) <= idmSuggest4); ++i)
  763. {
  764. V_I4(&var) = i + 1; // get_Item starts from 1
  765. SysFreeString(bstrSuggestion);
  766. bstrSuggestion = NULL;
  767. CHECKHR(hr = pSuggestions->get_Item(&var, &bstrSuggestion));
  768. cch = WideCharToMultiByte(0, 0, bstrSuggestion, SysStringLen(bstrSuggestion), szAnsiSuggestion, ARRAYSIZE(szAnsiSuggestion), NULL, NULL);
  769. if (!cch)
  770. goto exit;
  771. szAnsiSuggestion[cch] = 0;
  772. // Initialize the menu info
  773. mii.cbSize = sizeof(mii);
  774. mii.fMask = MIIM_ID | MIIM_TYPE;
  775. mii.fType = MFT_STRING;
  776. mii.fState = MFS_ENABLED;
  777. mii.wID = i + idmSuggest0;
  778. mii.dwTypeData = szAnsiSuggestion;
  779. mii.cch = lstrlen(szAnsiSuggestion);
  780. if(!InsertMenuItem(hMenu, 0, TRUE, &mii))
  781. // if (!AppendMenuA(hMenu, MF_STRING, i + idmSuggest0, szAnsiSuggestion))
  782. goto exit;
  783. }
  784. }
  785. // if (!AppendMenuA(hMenu, MF_SEPARATOR, 0, NULL))
  786. // goto exit;
  787. // if (!AppendMenuA(hMenu, MF_STRING, IDM_IGNOREWORD, "&Ignore All"))
  788. // goto exit;
  789. }
  790. }
  791. #endif //PLUSPACK
  792. #ifdef BACKGROUNDSPELL
  793. if (m_pSpell && m_fBkgrndSpelling)
  794. {
  795. HRESULT hr;
  796. hr = GetSelection(&pTxtRange);
  797. if (pTxtRange)
  798. {
  799. if (m_pSpell->HrHasSquiggle(pTxtRange)==S_OK)
  800. {
  801. if (!(hMenu = LoadPopupMenu(idmrCtxtSpellSuggest)))
  802. {
  803. hr = TraceResult(E_FAIL);
  804. goto exit;
  805. }
  806. hr = m_pSpell->HrInsertMenu(hMenu, pTxtRange);
  807. if (FAILED(hr))
  808. goto exit;
  809. fSpellSuggest = TRUE;
  810. }
  811. }
  812. }
  813. #endif // BACKGROUNDSPELL
  814. #ifdef PLUSPACK
  815. if (!fInSquiggle)
  816. #else
  817. if (!fSpellSuggest)
  818. #endif //PLUSPACK
  819. {
  820. if (!(hMenu = LoadPopupMenu(m_fDesignMode?idmrCtxtEditMode:idmrCtxtBrowseMode)))
  821. {
  822. hr = TraceResult(E_FAIL);
  823. goto exit;
  824. }
  825. if (!m_fDesignMode)
  826. {
  827. // if in browse mode, query the host to see if we can provider add to WAB and
  828. // add to fave menu items
  829. if (dwID == CONTEXT_MENU_ANCHOR)
  830. {
  831. AppendAnchorItems(hMenu, pDispatchObjectHit);
  832. }
  833. else
  834. {
  835. // remove the CopyShortCut command if it's not an anchor
  836. RemoveMenu(hMenu, idmCopyShortcut, MF_BYCOMMAND);
  837. // remove the SaveTargetAs command if it's not an anchor
  838. RemoveMenu(hMenu, idmSaveTargetAs, MF_BYCOMMAND);
  839. }
  840. if (dwID != CONTEXT_MENU_IMAGE)
  841. EnableMenuItem(hMenu, idmSavePicture, MF_BYCOMMAND|MF_GRAYED);
  842. }
  843. else
  844. {
  845. // if in editmode, trident does not pass dwID==CONTEXT_MENU_ANCHOR so we have to
  846. // test to see if the selection in an anchor to set this. It may fix this in the future
  847. // so code for both cases
  848. if (dwID==0 && GetSelectedAnchor(NULL)==S_OK)
  849. dwID = CONTEXT_MENU_ANCHOR;
  850. #ifdef FOLLOW_LINK
  851. // if edit-mode, and not on an anchor, hide the openlink menu command
  852. if (dwID != CONTEXT_MENU_ANCHOR)
  853. RemoveMenu(hMenu, idmOpenLink, MF_BYCOMMAND);
  854. #endif
  855. }
  856. m_fOnImage = !!(dwID == CONTEXT_MENU_IMAGE);
  857. UpdateContextMenu(hMenu, (dwID == CONTEXT_MENU_IMAGE || dwID == CONTEXT_MENU_ANCHOR), pDispatchObjectHit);
  858. }
  859. id = (INT)TrackPopupMenu(
  860. hMenu,
  861. TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD,
  862. pptPosition->x,
  863. pptPosition->y,
  864. 0,
  865. GetParent(m_hwnd),
  866. NULL);
  867. // we have to use TPM_RETURNCMD here as we need to process the command-id before returning from this
  868. // function, other wise trident will be confused about the object being clicked on.
  869. #ifdef PLUSPACK
  870. if (pTxtRange && id!=0 && m_pBkgSpeller && fInSquiggle)
  871. {
  872. //
  873. // Handle command
  874. //
  875. switch (id)
  876. {
  877. case idmIgnoreAll:
  878. CHECKHR(hr = m_pBkgSpeller->IgnoreWord(pTxtRange) );
  879. break;
  880. /*case IDM_DELETEWORD:
  881. {
  882. SysFreeString(bstrSuggestion);
  883. bstrSuggestion = SysAllocString(L"");
  884. CHECKHR(hr = pTxtRange->put_text(bstrSuggestion) );
  885. break;
  886. } */
  887. case idmIgnore:
  888. {
  889. //
  890. // mark this as clean
  891. //
  892. CHECKHR(hr = m_pBkgSpeller->MarkRegion(pTxtRange, VARIANT_FALSE) );
  893. break;
  894. }
  895. default:
  896. if ((id - idmSuggest0) <= lCount)
  897. {
  898. V_I4(&var) = id - idmSuggest0 + 1; // get_Item starts from 1
  899. SysFreeString(bstrSuggestion);
  900. bstrSuggestion = NULL;
  901. CHECKHR(hr = pSuggestions->get_Item(&var, &bstrSuggestion) );
  902. CHECKHR(hr = pTxtRange->put_text(bstrSuggestion) );
  903. /* {
  904. CHAR szBuf[MAX_PATH] = {0};
  905. BSTR bstr=0;
  906. BSTR bstrPut=0;
  907. LPSTR pch=0;
  908. INT i=0;
  909. cch = WideCharToMultiByte(0, 0, bstrSuggestion, SysStringLen(bstrSuggestion), szAnsiSuggestion, 255, NULL, NULL);
  910. szAnsiSuggestion[cch] = '\0';
  911. pch = szAnsiSuggestion;
  912. StrCpyN(szBuf, pch, ARRAYSIZE(szBuf));
  913. if (SUCCEEDED(pTxtRange->get_text(&bstr)) && bstr)
  914. {
  915. LPSTR pszText = 0;
  916. if (SUCCEEDED(HrBSTRToLPSZ(CP_ACP, bstr, &pszText)) && pszText)
  917. {
  918. LPSTR psz;
  919. INT nSpaces=0;
  920. psz = StrChrI(pszText, ' ');
  921. if(psz)
  922. {
  923. nSpaces = (INT) (&pszText[lstrlen(pszText)] - psz);
  924. Assert(nSpaces>=0);
  925. for(int i=0; i<(nSpaces-1); i++)
  926. StrCatBuff(szBuf, "&nbsp;", ARRAYSIZE(szBuf));
  927. if (nSpaces>0)
  928. StrCatBuff(szBuf, " ", ARRAYSIZE(szBuf));
  929. }
  930. hr = HrLPSZToBSTR(szBuf, &bstrPut);
  931. SafeMemFree(pszText);
  932. }
  933. SafeSysFreeString(bstr);
  934. }
  935. if (bstrPut)
  936. {
  937. pTxtRange->pasteHTML(bstrPut);
  938. SafeSysFreeString(bstrPut);
  939. }
  940. }*/
  941. break;
  942. }
  943. }
  944. hr = S_OK;
  945. goto exit;
  946. }
  947. #else
  948. if (pTxtRange && id!=0 && m_pSpell && fSpellSuggest && m_pSpell->OnWMCommand(id, pTxtRange)==S_OK)
  949. goto exit;
  950. #endif //PLUSPACK
  951. // stuff the IDispatch object, so our WMCommand handler can use it
  952. if (m_pDispContext = pDispatchObjectHit)
  953. pDispatchObjectHit->AddRef();
  954. if(id != 0)
  955. OnWMCommand(NULL, id, 0);
  956. exit:
  957. SafeRelease(m_pDispContext);
  958. #ifdef PLUSPACK
  959. SysFreeString(bstrSuggestion);
  960. SysFreeString(bstrWord);
  961. SysFreeString(bstrSelectionType);
  962. #endif //PLUSPACK
  963. if (hMenu)
  964. DestroyMenu(hMenu);
  965. #ifdef PLUSPACK
  966. SafeRelease(pSuggestions);
  967. SafeRelease(pPointerLeft);
  968. SafeRelease(pPointerRight);
  969. SafeRelease(pMarkupServices);
  970. SafeRelease(pDispPointer);
  971. SafeRelease(pDisplayServices);
  972. SafeRelease(pElement);
  973. SafeRelease(pBody);
  974. SafeRelease(pSelection);
  975. SafeRelease(pWindow);
  976. SafeRelease(pRange);
  977. SafeRelease(pEvent);
  978. #endif //PLUSPACK
  979. ReleaseObj(pTxtRange);
  980. m_dwContextItem = 0;
  981. return S_OK;
  982. }
  983. //+---------------------------------------------------------------
  984. //
  985. // Member: GetDropTarget
  986. //
  987. // Synopsis:
  988. //
  989. //---------------------------------------------------------------
  990. HRESULT CBody::GetDropTarget(IDropTarget *pDropTarget, IDropTarget **ppDropTarget)
  991. {
  992. HRESULT hr;
  993. TraceCall("CBody::GetDropTarget");
  994. if (m_pParentDocHostUI)
  995. {
  996. // see if parent dochostUIhandler want's to handle. If not they will return _DODEFAULT
  997. hr = m_pParentDocHostUI->GetDropTarget(pDropTarget, ppDropTarget);
  998. if (hr != MIMEEDIT_E_DODEFAULT)
  999. return hr;
  1000. }
  1001. return E_NOTIMPL;
  1002. }
  1003. //+---------------------------------------------------------------
  1004. //
  1005. // Member: GetExternal
  1006. //
  1007. // Synopsis:
  1008. //
  1009. //---------------------------------------------------------------
  1010. HRESULT CBody::GetExternal(IDispatch **ppDispatch)
  1011. {
  1012. HRESULT hr;
  1013. TraceCall("CBody::GetExternal");
  1014. if (m_pParentDocHostUI)
  1015. {
  1016. // see if parent dochostUIhandler want's to handle. If not they will return _DODEFAULT
  1017. hr = m_pParentDocHostUI->GetExternal(ppDispatch);
  1018. if (hr != MIMEEDIT_E_DODEFAULT)
  1019. return hr;
  1020. }
  1021. return E_NOTIMPL;
  1022. }
  1023. //+---------------------------------------------------------------
  1024. //
  1025. // Member: TranslateUrl
  1026. //
  1027. // Synopsis:
  1028. //
  1029. //---------------------------------------------------------------
  1030. HRESULT CBody::TranslateUrl(DWORD dwTranslate, OLECHAR *pwszUrlIn, OLECHAR **ppwszUrlOut)
  1031. {
  1032. HRESULT hr=S_OK;
  1033. LPSTR pszUrlIn=NULL;
  1034. LPSTR pszBodyUrl=NULL;
  1035. LPSTR pszFilePath=NULL;
  1036. LPSTR pszUrlOut=NULL;
  1037. LPSTR pszFree=NULL;
  1038. LPSTR pszGenFName=NULL;
  1039. LPSTR pszParameters=NULL;
  1040. LPSTR pszCommandLine=NULL;
  1041. CHAR szBuffer[MAX_PATH];
  1042. HBODY hBody;
  1043. IMimeBody *pBody=NULL;
  1044. IStream *pStream=NULL;
  1045. PROPVARIANT rVariant;
  1046. HANDLE hFile=INVALID_HANDLE_VALUE;
  1047. ULONG cbTotal;
  1048. CHAR szFilePath[MAX_PATH + MAX_PATH];
  1049. ULONG cch;
  1050. BOOL fReturnAbort=FALSE;
  1051. LPTEMPFILEINFO pTempFile;
  1052. SHELLEXECUTEINFO rExecute;
  1053. DWORD cc = 0;
  1054. TraceCall("CBody::TranslateUrl");
  1055. if (m_pParentDocHostUI)
  1056. {
  1057. // see if parent dochostUIhandler want's to handle. If not they will return _DODEFAULT
  1058. hr = m_pParentDocHostUI->TranslateUrl(dwTranslate, pwszUrlIn, ppwszUrlOut);
  1059. if (hr != MIMEEDIT_E_DODEFAULT)
  1060. return hr;
  1061. }
  1062. // Init
  1063. *ppwszUrlOut = NULL;
  1064. if (NULL == pwszUrlIn || NULL == ppwszUrlOut)
  1065. return TraceResult(E_INVALIDARG);
  1066. // No Message Object
  1067. if ((NULL == m_pMsg) || (NULL == m_pMsgW))
  1068. return S_FALSE;
  1069. // If pwszUrlIn is not already an mhtml: url
  1070. if (StrCmpNIW(pwszUrlIn, L"mhtml:", 6) != 0)
  1071. return S_FALSE;
  1072. // Convert To ANSI
  1073. pszUrlIn = PszToANSI(CP_ACP, pwszUrlIn);
  1074. if (!pszUrlIn)
  1075. {
  1076. hr = E_OUTOFMEMORY;
  1077. goto error;
  1078. }
  1079. // UnEscape the Url
  1080. hr = UrlUnescapeA(pszUrlIn, NULL, NULL, URL_UNESCAPE_INPLACE);
  1081. if (FAILED(hr))
  1082. goto error;
  1083. // Split It
  1084. hr = MimeOleParseMhtmlUrl(pszUrlIn, NULL, &pszBodyUrl);
  1085. if (FAILED(hr))
  1086. goto error;
  1087. // Resolve the body url
  1088. hr = m_pMsg->ResolveURL(NULL, NULL, pszBodyUrl, 0, &hBody);
  1089. if (FAILED(hr))
  1090. goto error;
  1091. // Get an IMimeBody
  1092. hr = m_pMsg->BindToObject(hBody, IID_IMimeBody, (LPVOID *)&pBody);
  1093. if (FAILED(hr))
  1094. goto error;
  1095. // Abort
  1096. fReturnAbort = TRUE;
  1097. // If HTML, then write the entire message source to a temp file and return an mhtml url
  1098. if (pBody->IsContentType(STR_CNT_TEXT, STR_SUB_HTML) == S_OK)
  1099. {
  1100. // Get ixplorer.exe path
  1101. GetExePath(c_szIexploreExe, szBuffer, ARRAYSIZE(szBuffer), FALSE);
  1102. // Set command line
  1103. pszCommandLine = szBuffer;
  1104. // Get a Stream
  1105. hr = m_pMsg->GetMessageSource(&pStream, 0);
  1106. if (FAILED(hr))
  1107. goto error;
  1108. // Init Variant
  1109. rVariant.vt = VT_LPSTR;
  1110. // Get a filename from the message object
  1111. hr = m_pMsg->GetProp(PIDTOSTR(PID_ATT_GENFNAME), 0, &rVariant);
  1112. if (FAILED(hr))
  1113. goto error;
  1114. // Save pszFilePath
  1115. pszGenFName = rVariant.pszVal;
  1116. // Create temp file
  1117. hr = CreateTempFile(pszGenFName, c_szMHTMLExt, &pszFilePath, &hFile);
  1118. if (FAILED(hr))
  1119. goto error;
  1120. // Write the stream to a file
  1121. hr = WriteStreamToFileHandle(pStream, hFile, &cbTotal);
  1122. if (FAILED(hr))
  1123. goto error;
  1124. // Build: mhtml:(pszFilePath)!pszBodyUrl
  1125. cc = lstrlen(c_szMHTMLColon) + lstrlen(c_szFileUrl) + lstrlen(pszFilePath) + 1 + lstrlen(pszBodyUrl) + 1;
  1126. pszParameters = PszAllocA(cc);
  1127. if (!pszParameters)
  1128. {
  1129. hr = E_OUTOFMEMORY;
  1130. goto error;
  1131. }
  1132. // Build pszParameters
  1133. wnsprintf(pszParameters, cc, "%s%s%s!%s", c_szMHTMLColon, c_szFileUrl, pszFilePath, pszBodyUrl);
  1134. }
  1135. // Otherwise, dump the body data to a temp file and return a url to it
  1136. else
  1137. {
  1138. // Get a Stream
  1139. hr = pBody->GetData(IET_INETCSET, &pStream);
  1140. if (FAILED(hr))
  1141. goto error;
  1142. // Set sizeof szFilePath
  1143. cch = ARRAYSIZE(szFilePath);
  1144. // If cid:
  1145. if (StrCmpNIA(pszBodyUrl, "cid:", 4) == 0 || FAILED(PathCreateFromUrlA(pszBodyUrl, szFilePath, &cch, 0)))
  1146. {
  1147. // Init Variant
  1148. rVariant.vt = VT_LPSTR;
  1149. // Get a filename from the message object
  1150. hr = pBody->GetProp(PIDTOSTR(PID_ATT_GENFNAME), 0, &rVariant);
  1151. if (FAILED(hr))
  1152. goto error;
  1153. // Save pszFilePath
  1154. pszGenFName = rVariant.pszVal;
  1155. // Create temp file
  1156. hr = CreateTempFile(pszGenFName, NULL, &pszFilePath, &hFile);
  1157. if (FAILED(hr))
  1158. goto error;
  1159. }
  1160. else
  1161. {
  1162. // Create temp file
  1163. hr = CreateTempFile(szFilePath, NULL, &pszFilePath, &hFile);
  1164. if (FAILED(hr))
  1165. goto error;
  1166. }
  1167. // Write the stream to a file
  1168. hr = WriteStreamToFileHandle(pStream, hFile, &cbTotal);
  1169. if (FAILED(hr))
  1170. goto error;
  1171. // Build: file://(pszFilePath)
  1172. cc = lstrlen(c_szFileUrl) + lstrlen(pszFilePath) + 1;
  1173. pszUrlOut = PszAllocA(cc);
  1174. if (FAILED(hr))
  1175. goto error;
  1176. // Build pszUrlOut
  1177. wnsprintf(pszUrlOut, cc, "%s%s", c_szFileUrl, pszFilePath);
  1178. // Set the pszCommandLine
  1179. pszCommandLine = pszUrlOut;
  1180. }
  1181. // Close the file - the file must get closed here (i.e. after the call to MimeOleCleanupTempFiles)
  1182. FlushFileBuffers(hFile);
  1183. CloseHandle(hFile);
  1184. hFile = INVALID_HANDLE_VALUE;
  1185. // Is this file safe to run ?
  1186. hr = MimeEditIsSafeToRun(m_hwnd, pszFilePath, FALSE);
  1187. if (FAILED(hr))
  1188. goto error;
  1189. // SaveAs
  1190. if (MIMEEDIT_S_OPENFILE == hr)
  1191. {
  1192. // Locals
  1193. OPENFILENAME ofn;
  1194. TCHAR szTitle[CCHMAX_STRINGRES];
  1195. TCHAR szFilter[CCHMAX_STRINGRES];
  1196. TCHAR szFile[MAX_PATH];
  1197. // Init
  1198. *szFile=0;
  1199. *szFilter=0;
  1200. *szTitle=0;
  1201. // Copy filename
  1202. StrCpyN(szFile, pszFilePath, ARRAYSIZE(szFile));
  1203. // Init Open file structure
  1204. ZeroMemory (&ofn, sizeof(OPENFILENAME));
  1205. ofn.lStructSize = sizeof(OPENFILENAME);
  1206. ofn.hwndOwner = m_hwnd;
  1207. LoadString(g_hLocRes, idsFilterAttSave, szFilter, sizeof(szFilter));
  1208. ReplaceChars(szFilter, '|', '\0');
  1209. ofn.lpstrFilter = szFilter;
  1210. ofn.nFilterIndex = 1;
  1211. ofn.lpstrFile = szFile;
  1212. ofn.nMaxFile = sizeof (szFile);
  1213. LoadString(g_hLocRes, idsSaveAttachmentAs, szTitle, sizeof(szTitle));
  1214. ofn.lpstrTitle = szTitle;
  1215. ofn.Flags = OFN_NOCHANGEDIR | OFN_NOREADONLYRETURN | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
  1216. // Show SaveAs Dialog
  1217. if (HrAthGetFileName(&ofn, FALSE) == S_OK)
  1218. {
  1219. // If the same...
  1220. if (lstrcmpi(pszFilePath, szFile) == 0)
  1221. {
  1222. // Just free pszfilePath so that we don't delete it
  1223. SafeMemFree(pszFilePath);
  1224. }
  1225. // Copy the file - Overwrite
  1226. else
  1227. CopyFile(pszFilePath, szFile, FALSE);
  1228. }
  1229. // Done
  1230. goto error;
  1231. }
  1232. // Must be trying to execute the file
  1233. hr = MimeEditVerifyTrust(m_hwnd, PathFindFileName(pszFilePath), pszFilePath);
  1234. if (FAILED(hr))
  1235. goto error;
  1236. // Setup the Shell Execute Structure
  1237. ZeroMemory (&rExecute, sizeof(SHELLEXECUTEINFO));
  1238. rExecute.cbSize = sizeof(SHELLEXECUTEINFO);
  1239. rExecute.fMask = SEE_MASK_NOCLOSEPROCESS;
  1240. rExecute.hwnd = m_hwnd;
  1241. rExecute.nShow = SW_SHOWNORMAL;
  1242. rExecute.lpFile = pszCommandLine;
  1243. rExecute.lpVerb = NULL;
  1244. rExecute.lpParameters = pszParameters;
  1245. // Execute the File
  1246. TraceInfoSideAssert((0 != ShellExecuteEx(&rExecute)), _MSG("ShellExecuteEx failed - GetLastError() = %d\n", GetLastError()));
  1247. // Add the temp file to the list
  1248. if (SUCCEEDED(AppendTempFileList(&m_pTempFileUrl, pszFilePath, rExecute.hProcess)))
  1249. pszFilePath = NULL;
  1250. error:
  1251. // Cleanup
  1252. SafeRelease(pBody);
  1253. SafeRelease(pStream);
  1254. SafeMemFree(pszUrlIn);
  1255. SafeMemFree(pszBodyUrl);
  1256. SafeMemFree(pszFree);
  1257. SafeMemFree(pszUrlOut);
  1258. SafeMemFree(pszGenFName);
  1259. SafeMemFree(pszParameters);
  1260. // Close the file - the file must get closed here (i.e. after the call to MimeOleCleanupTempFiles)
  1261. if (INVALID_HANDLE_VALUE != hFile)
  1262. CloseHandle(hFile);
  1263. // If we still have pszFilePath, delete the file
  1264. if (pszFilePath)
  1265. {
  1266. DeleteFile(pszFilePath);
  1267. g_pMalloc->Free(pszFilePath);
  1268. }
  1269. // Done
  1270. return (TRUE == fReturnAbort) ? E_ABORT : S_FALSE;
  1271. }
  1272. //+---------------------------------------------------------------
  1273. //
  1274. // Member: FilterDataObject
  1275. //
  1276. // Synopsis:
  1277. //
  1278. //---------------------------------------------------------------
  1279. HRESULT CBody::FilterDataObject(IDataObject *pDO, IDataObject **ppDORet)
  1280. {
  1281. IDataObject *pDataObjNew = NULL;
  1282. HRESULT hr = S_FALSE;
  1283. STGMEDIUM stgmed;
  1284. DATAOBJINFO* pInfo = 0;
  1285. DATAOBJINFO* pInfoCopy = 0;
  1286. FORMATETC fetc = {0};
  1287. LPBYTE pCopy=0;
  1288. INT i, j, cFormats=0;
  1289. USHORT cfFormat[2] =
  1290. {CF_TEXT, CF_UNICODETEXT};
  1291. LPBYTE lpsz[2]={0};
  1292. ULONG lStreamLength[2]={0};
  1293. TraceCall("CBody::FilterDataObject");
  1294. if (m_pParentDocHostUI)
  1295. {
  1296. // see if parent dochostUIhandler want's to handle. If not they will return _DODEFAULT
  1297. hr = m_pParentDocHostUI->FilterDataObject(pDO, ppDORet);
  1298. if (hr != MIMEEDIT_E_DODEFAULT)
  1299. return hr;
  1300. }
  1301. if (!m_fPlainMode || !m_fDesignMode)
  1302. return S_FALSE;
  1303. if (pDO==NULL || ppDORet==NULL)
  1304. return S_FALSE;
  1305. *ppDORet = NULL;
  1306. for (i=0; i<ARRAYSIZE(cfFormat); i++)
  1307. {
  1308. // get the plain-text
  1309. fetc.cfFormat=cfFormat[i];
  1310. fetc.dwAspect=DVASPECT_CONTENT;
  1311. fetc.tymed=TYMED_HGLOBAL;
  1312. fetc.lindex=0;
  1313. hr=pDO->QueryGetData(&fetc);
  1314. if(FAILED(hr))
  1315. continue;
  1316. ZeroMemory(&stgmed, sizeof(stgmed));
  1317. hr=pDO->GetData(&fetc, &stgmed);
  1318. if(FAILED(hr))
  1319. goto cleanloop;
  1320. Assert(stgmed.hGlobal);
  1321. // make a copy of the plain text string.
  1322. pCopy = (LPBYTE)GlobalLock(stgmed.hGlobal);
  1323. if (!pCopy)
  1324. {
  1325. hr=E_FAIL;
  1326. goto cleanloop;
  1327. }
  1328. if(fetc.cfFormat == CF_TEXT)
  1329. lStreamLength[i] = lstrlen((LPSTR)pCopy) + 1;
  1330. else
  1331. lStreamLength[i] = sizeof(WCHAR) * (lstrlenW((LPWSTR)pCopy)+1);
  1332. if (!MemAlloc((LPVOID*)&lpsz[i], lStreamLength[i]))
  1333. {
  1334. hr = E_OUTOFMEMORY;
  1335. goto cleanloop;
  1336. }
  1337. CopyMemory(lpsz[i], pCopy, lStreamLength[i]);
  1338. GlobalUnlock(stgmed.hGlobal);
  1339. cFormats++;
  1340. cleanloop:
  1341. // addref the pUnk as it will be release in releasestgmed
  1342. if(stgmed.pUnkForRelease)
  1343. stgmed.pUnkForRelease->AddRef();
  1344. ReleaseStgMedium(&stgmed);
  1345. if(FAILED(hr))
  1346. goto error;
  1347. }
  1348. if(cFormats == 0)
  1349. {
  1350. hr = E_FAIL;
  1351. goto error;
  1352. }
  1353. if (!MemAlloc((LPVOID*)&pInfo, sizeof(DATAOBJINFO)*cFormats))
  1354. {
  1355. hr = E_OUTOFMEMORY;
  1356. goto error;
  1357. }
  1358. ZeroMemory(pInfo, sizeof(DATAOBJINFO)*cFormats);
  1359. j = 0;
  1360. for(i=0; i<ARRAYSIZE(cfFormat); i++)
  1361. {
  1362. if(lpsz[i] != 0)
  1363. {
  1364. SETDefFormatEtc(pInfo[j].fe, cfFormat[i], TYMED_HGLOBAL);
  1365. pInfo[j].pData = lpsz[i];
  1366. pInfo[j].cbData = lStreamLength[i];
  1367. j++;
  1368. }
  1369. }
  1370. Assert(j == cFormats);
  1371. hr = CreateDataObject(pInfo, cFormats, (PFNFREEDATAOBJ)FreeDataObj, &pDataObjNew);
  1372. if (FAILED(hr))
  1373. goto error;
  1374. //CDataObject will free this now it accepted it
  1375. for(i=0; i<ARRAYSIZE(cfFormat); i++)
  1376. lpsz[i]=NULL;
  1377. pInfo=NULL;
  1378. *ppDORet = pDataObjNew;
  1379. pDataObjNew = NULL;
  1380. error:
  1381. for(i=0; i<ARRAYSIZE(cfFormat); i++)
  1382. SafeMemFree(lpsz[i]);
  1383. SafeMemFree(pInfo);
  1384. ReleaseObj(pDataObjNew);
  1385. return hr;
  1386. }
  1387. //+---------------------------------------------------------------
  1388. //
  1389. // Member: TranslateAccelerator
  1390. //
  1391. // Synopsis:
  1392. // Trident calls the host first before handling an
  1393. // accelerator. If we return S_OK, it assumes we handled
  1394. // it and carries on. If we return S_FALSE it assumes
  1395. // we don't care, and it will do it's own action
  1396. //
  1397. //---------------------------------------------------------------
  1398. HRESULT CBody::TranslateAccelerator(LPMSG lpMsg, const GUID *pguidCmdGroup, DWORD nCmdID)
  1399. {
  1400. HRESULT hr;
  1401. TraceCall("CBody::TranslateAccelerator");
  1402. if (m_pParentDocHostUI)
  1403. {
  1404. // see if parent dochostUIhandler want's to handle. If not they will return _DODEFAULT
  1405. hr = m_pParentDocHostUI->TranslateAccelerator(lpMsg, pguidCmdGroup, nCmdID);
  1406. if (hr != MIMEEDIT_E_DODEFAULT)
  1407. return hr;
  1408. }
  1409. // commands which are always available
  1410. switch (nCmdID)
  1411. {
  1412. case 0:
  1413. case IDM_CUT:
  1414. case IDM_COPY:
  1415. case IDM_PASTE:
  1416. case IDM_PASTEINSERT:
  1417. case IDM_DELETE:
  1418. case IDM_DELETEWORD:
  1419. case IDM_SELECTALL:
  1420. case IDM_UNDO:
  1421. case IDM_REDO:
  1422. case IDM_CHANGECASE:
  1423. case IDM_NONBREAK:
  1424. return S_FALSE;
  1425. }
  1426. // commands only available in HTML edit mode
  1427. if (!m_fPlainMode)
  1428. {
  1429. switch (nCmdID)
  1430. {
  1431. case IDM_BOLD:
  1432. case IDM_UNDERLINE:
  1433. case IDM_ITALIC:
  1434. case IDM_REMOVEFORMAT:
  1435. case IDM_CENTERALIGNPARA:
  1436. case IDM_LEFTALIGNPARA:
  1437. case IDM_RIGHTALIGNPARA:
  1438. case IDM_REMOVEPARAFORMAT:
  1439. case IDM_APPLYNORMAL:
  1440. return S_FALSE;
  1441. }
  1442. }
  1443. if (nCmdID)
  1444. m_fIgnoreAccel = 1;
  1445. return S_OK;
  1446. }
  1447. //+---------------------------------------------------------------
  1448. //
  1449. // Member: GetOptionKeyPath
  1450. //
  1451. // Synopsis:
  1452. //
  1453. //---------------------------------------------------------------
  1454. HRESULT CBody::GetOptionKeyPath(LPOLESTR * pstrKey, DWORD dw)
  1455. {
  1456. HRESULT hr;
  1457. TCHAR rgch[MAX_PATH];
  1458. TraceCall("CBody::GetOptionKeyPath");
  1459. if (m_pParentDocHostUI)
  1460. {
  1461. // see if parent dochostUIhandler want's to handle. If not they will return _DODEFAULT
  1462. hr = m_pParentDocHostUI->GetOptionKeyPath(pstrKey, dw);
  1463. if (hr==S_OK)
  1464. {
  1465. WideCharToMultiByte(CP_ACP, 0, (WCHAR*)*pstrKey, -1, rgch, ARRAYSIZE(rgch), NULL, NULL);
  1466. CreateFontCache(rgch);
  1467. }
  1468. if (hr != MIMEEDIT_E_DODEFAULT)
  1469. return hr;
  1470. }
  1471. CreateFontCache(NULL);
  1472. return E_NOTIMPL;
  1473. }
  1474. //+---------------------------------------------------------------
  1475. //
  1476. // Member: EnsureLoaded
  1477. //
  1478. // Synopsis:
  1479. //
  1480. //---------------------------------------------------------------
  1481. HRESULT CBody::EnsureLoaded()
  1482. {
  1483. HRESULT hr=NOERROR;
  1484. TraceCall("CBody::EnsureLoaded");
  1485. if (!m_lpOleObj)
  1486. {
  1487. hr=CDocHost::CreateDocObj((LPCLSID)&CLSID_HTMLDocument);
  1488. if(FAILED(hr))
  1489. goto error;
  1490. hr = CDocHost::Show();
  1491. if(FAILED(hr))
  1492. goto error;
  1493. Assert (!m_pDoc);
  1494. hr = m_lpOleObj->QueryInterface(IID_IHTMLDocument2, (LPVOID *)&m_pDoc);
  1495. if (FAILED(hr))
  1496. goto error;
  1497. hr = RegisterLoadNotify(TRUE);
  1498. if (FAILED(hr))
  1499. goto error;
  1500. if (m_pFmtBar)
  1501. m_pFmtBar->SetCommandTarget(m_pCmdTarget);
  1502. }
  1503. error:
  1504. return hr;
  1505. }
  1506. //+---------------------------------------------------------------
  1507. //
  1508. // Member: RegisterLoadNotify
  1509. //
  1510. // Synopsis:
  1511. //
  1512. //---------------------------------------------------------------
  1513. HRESULT CBody::RegisterLoadNotify(BOOL fRegister)
  1514. {
  1515. IConnectionPointContainer *pCPContainer;
  1516. IConnectionPoint *pCP;
  1517. HRESULT hr=E_FAIL;
  1518. TraceCall("CBody::RegisterLoadNotify");
  1519. if (!m_pDoc)
  1520. return E_FAIL;
  1521. if (m_pDoc)
  1522. {
  1523. hr = m_pDoc->QueryInterface(IID_IConnectionPointContainer, (LPVOID *)&pCPContainer);
  1524. if (!FAILED(hr))
  1525. {
  1526. hr = pCPContainer->FindConnectionPoint(IID_IPropertyNotifySink, &pCP);
  1527. if (!FAILED(hr))
  1528. {
  1529. if (fRegister)
  1530. {
  1531. Assert(m_dwNotify == 0);
  1532. hr = pCP->Advise((IPropertyNotifySink *)this, &m_dwNotify);
  1533. }
  1534. else
  1535. {
  1536. if (m_dwNotify)
  1537. {
  1538. hr = pCP->Unadvise(m_dwNotify);
  1539. m_dwNotify=0;
  1540. }
  1541. }
  1542. pCP->Release();
  1543. }
  1544. pCPContainer->Release();
  1545. }
  1546. }
  1547. return hr;
  1548. }
  1549. //+---------------------------------------------------------------
  1550. //
  1551. // Member: OnChanged
  1552. //
  1553. // Synopsis:
  1554. //
  1555. //---------------------------------------------------------------
  1556. HRESULT CBody::OnChanged(DISPID dispid)
  1557. {
  1558. TraceCall("CBody::OnChanged");
  1559. if (dispid == DISPID_READYSTATE)
  1560. OnReadyStateChanged();
  1561. return S_OK;
  1562. }
  1563. //+---------------------------------------------------------------
  1564. //
  1565. // Member: OnRequestEdit
  1566. //
  1567. // Synopsis:
  1568. //
  1569. //---------------------------------------------------------------
  1570. HRESULT CBody::OnRequestEdit (DISPID dispid)
  1571. {
  1572. TraceCall("CBody::OnRequestEdit");
  1573. return S_OK;
  1574. }
  1575. //+---------------------------------------------------------------
  1576. //
  1577. // Member: OnReadyStateChanged
  1578. //
  1579. // Synopsis:
  1580. //
  1581. //---------------------------------------------------------------
  1582. void CBody::OnReadyStateChanged()
  1583. {
  1584. HRESULT hr = S_OK;
  1585. VARIANT Var;
  1586. IDispatch * pdisp;
  1587. TraceCall("CBody::OnReadyStateChanged");
  1588. if (NULL == m_lpOleObj)
  1589. return;
  1590. if (m_lpOleObj->QueryInterface(IID_IDispatch, (void **)&pdisp)==S_OK)
  1591. {
  1592. if (GetDispProp(pdisp, DISPID_READYSTATE, 0, &Var, NULL)==S_OK)
  1593. {
  1594. // maybe either I4 or I2
  1595. Assert (Var.vt == VT_I4 || Var.vt == VT_I2);
  1596. // we get the ready state so we can warn about sending while downloading
  1597. m_dwReadyState = Var.lVal;
  1598. }
  1599. pdisp->Release();
  1600. }
  1601. }
  1602. //+---------------------------------------------------------------
  1603. //
  1604. // Member: OnDocumentReady
  1605. //
  1606. // Synopsis:
  1607. //
  1608. //---------------------------------------------------------------
  1609. void CBody::OnDocumentReady()
  1610. {
  1611. DWORD dwFlags;
  1612. // quick-scan for CID's not requested before ParseComplete
  1613. if (m_fLoading && !m_fReloadingSrc)
  1614. SearchForCIDUrls();
  1615. // send a notification up to the parent
  1616. if (m_pParentCmdTarget)
  1617. m_pParentCmdTarget->Exec(&CMDSETID_MimeEditHost, MEHOSTCMDID_ONPARSECOMPLETE, 0, NULL, NULL);
  1618. if (m_fAutoDetect)
  1619. StartAutoDetect();
  1620. #ifdef PLUSPACK
  1621. // Test for new Trident backgound spell check
  1622. if(m_fDesignMode && !m_pBkgSpeller && m_pDoc)
  1623. {
  1624. HRESULT hr = S_OK;
  1625. IHTMLElement * pElement = NULL;
  1626. IHTMLBodyElement * pBodyElement = NULL;
  1627. IHTMLTxtRange * pRange = NULL;
  1628. //
  1629. // Create the speller
  1630. //
  1631. CHECKHR(hr = CoCreateInstance(CLSID_HTMLSpell, NULL, CLSCTX_INPROC_SERVER,
  1632. IID_IHTMLSpell, (LPVOID*)&m_pBkgSpeller));
  1633. //
  1634. // Attach the speller
  1635. //
  1636. CHECKHR(hr = m_pDoc->get_body(&pElement));
  1637. CHECKHR(hr = m_pBkgSpeller->SetDoc(m_pDoc) );
  1638. CHECKHR(hr = m_pBkgSpeller->Attach(pElement) );
  1639. //
  1640. // Mark current content as clean
  1641. //
  1642. CHECKHR(hr = pElement->QueryInterface(IID_IHTMLBodyElement, (LPVOID *)&pBodyElement) );
  1643. CHECKHR(hr = pBodyElement->createTextRange(&pRange) );
  1644. CHECKHR(hr = m_pBkgSpeller->MarkRegion((IDispatch *)pRange, TRUE /* fSpellable */) );
  1645. exit:
  1646. // just cannot load background speller...
  1647. if(FAILED(hr))
  1648. Assert(FALSE);
  1649. SafeRelease(pRange);
  1650. SafeRelease(pBodyElement);
  1651. SafeRelease(pElement);
  1652. // return; //(S_OK);
  1653. }
  1654. #endif //PLUSPACK
  1655. #ifdef BACKGROUNDSPELL
  1656. HrCreateSpeller(TRUE);
  1657. #endif // BACKGROUNDSPELL
  1658. if (m_fLoading && !m_fReloadingSrc)
  1659. {
  1660. // OnDocumentReady can be called >1 times during a load. We use m_fLoading to keep track so
  1661. // we only do this init once.
  1662. // paste in the reply header and auto-text on the first download notification.
  1663. if (m_fDesignMode)
  1664. {
  1665. if (m_fForceCharsetLoad)
  1666. {
  1667. TCHAR rgchCset[CCHMAX_CSET_NAME];
  1668. if (SUCCEEDED(HrGetMetaTagName(m_hCharset, rgchCset, ARRAYSIZE(rgchCset))))
  1669. {
  1670. BSTR bstr;
  1671. if (SUCCEEDED(HrLPSZToBSTR(rgchCset, &bstr)))
  1672. {
  1673. m_pDoc->put_charset(bstr);
  1674. SysFreeString(bstr);
  1675. }
  1676. }
  1677. }
  1678. // if the host wants to to not send images that originate from an external source
  1679. // then tag them as such now.
  1680. if (GetHostFlags(&dwFlags)==S_OK &&
  1681. !(dwFlags & MEO_FLAGS_SENDEXTERNALIMGSRC))
  1682. {
  1683. SafeRelease(m_pHashExternal);
  1684. HashExternalReferences(m_pDoc, m_pMsg, &m_pHashExternal);
  1685. }
  1686. if (!m_fPlainMode)
  1687. {
  1688. SetHostComposeFont();
  1689. SetWindowBgColor(FALSE);
  1690. }
  1691. }
  1692. PasteReplyHeader();
  1693. PasteAutoText();
  1694. ClearUndoStack();
  1695. ClearDirtyFlag();
  1696. // if we get a load notify and we're the previewpane, show the attachment clip
  1697. if (m_uHdrStyle == MESTYLE_PREVIEW)
  1698. {
  1699. UpdateBtnBar();
  1700. UpdatePreviewLabels();
  1701. }
  1702. m_fLoading=0;
  1703. }
  1704. m_fMessageParsed=1;
  1705. m_fReloadingSrc=FALSE;
  1706. }
  1707. //+---------------------------------------------------------------
  1708. //
  1709. // Member: SetRect
  1710. //
  1711. // Synopsis:
  1712. //
  1713. //---------------------------------------------------------------
  1714. HRESULT CBody::SetRect(LPRECT prc)
  1715. {
  1716. TraceCall("CBody::SetRect");
  1717. SetWindowPos(m_hwnd, NULL, prc->left, prc->top, prc->right-prc->left, prc->bottom-prc->top, SWP_NOZORDER);
  1718. return S_OK;
  1719. }
  1720. //+---------------------------------------------------------------
  1721. //
  1722. // Member: GetRect
  1723. //
  1724. // Synopsis:
  1725. //
  1726. //---------------------------------------------------------------
  1727. HRESULT CBody::GetRect(LPRECT prcView)
  1728. {
  1729. TraceCall("CBody::GetRect");
  1730. if (prcView == NULL)
  1731. return E_INVALIDARG;
  1732. Assert (IsWindow(m_hwnd));
  1733. GetClientRect(m_hwnd, prcView);
  1734. return S_OK;
  1735. }
  1736. //+---------------------------------------------------------------
  1737. //
  1738. // Member: UIActivate
  1739. //
  1740. // Synopsis:
  1741. //
  1742. //---------------------------------------------------------------
  1743. HRESULT CBody::UIActivate(BOOL fUIActivate)
  1744. {
  1745. TraceCall("CBody::UIActivate");
  1746. if(!m_pDocView)
  1747. return S_OK;
  1748. return m_pDocView->UIActivate(fUIActivate);
  1749. }
  1750. //+---------------------------------------------------------------
  1751. //
  1752. // Member: Exec
  1753. //
  1754. // Synopsis:
  1755. //
  1756. //---------------------------------------------------------------
  1757. HRESULT CBody::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut)
  1758. {
  1759. TraceCall("CBody::Exec");
  1760. if (pguidCmdGroup &&
  1761. IsEqualGUID(CMDSETID_Forms3, *pguidCmdGroup))
  1762. {
  1763. if (nCmdID == IDM_PARSECOMPLETE)
  1764. {
  1765. OnDocumentReady();
  1766. return S_OK;
  1767. }
  1768. }
  1769. if (pguidCmdGroup==NULL)
  1770. {
  1771. switch (nCmdID)
  1772. {
  1773. case OLECMDID_UPDATECOMMANDS:
  1774. UpdateCommands();
  1775. break;
  1776. }
  1777. }
  1778. return CDocHost::Exec(pguidCmdGroup, nCmdID, nCmdExecOpt, pvaIn, pvaOut);
  1779. }
  1780. //+---------------------------------------------------------------
  1781. //
  1782. // Member: GetClassID
  1783. //
  1784. // Synopsis:
  1785. //
  1786. //---------------------------------------------------------------
  1787. HRESULT CBody::GetClassID(CLSID *pCLSID)
  1788. {
  1789. TraceCall("CBody::GetClassID");
  1790. *pCLSID = CLSID_MimeEdit;
  1791. return NOERROR;
  1792. }
  1793. //+---------------------------------------------------------------
  1794. //
  1795. // Member: Load
  1796. //
  1797. // Synopsis:
  1798. //
  1799. //---------------------------------------------------------------
  1800. HRESULT CBody::Load(IMimeMessage *pMsg)
  1801. {
  1802. BODYINITDATA biData;
  1803. TraceCall("CBody::Load");
  1804. if (pMsg == NULL)
  1805. return TraceResult(E_INVALIDARG);
  1806. biData.dwType = BI_MESSAGE;
  1807. biData.pMsg = pMsg;
  1808. return LoadFromData(&biData);
  1809. }
  1810. //+---------------------------------------------------------------
  1811. //
  1812. // Member: Save
  1813. //
  1814. // Synopsis:
  1815. //
  1816. //---------------------------------------------------------------
  1817. HRESULT CBody::Save(IMimeMessage *pMsg, DWORD dwFlags)
  1818. {
  1819. HRESULT hr;
  1820. DWORD dwMHTMLFlags=0,
  1821. dwHostFlags;
  1822. TraceCall("CBody::Save");
  1823. if (pMsg==NULL)
  1824. return E_INVALIDARG;
  1825. if (!m_lpOleObj)
  1826. return CO_E_NOT_SUPPORTED;
  1827. if (m_uSrcView != MEST_EDIT)
  1828. return TraceResult(MIMEEDIT_E_CANNOTSAVEWHILESOURCEEDITING);
  1829. if (!((dwFlags & PMS_HTML) || (dwFlags & PMS_TEXT)))
  1830. return TraceResult(MIMEEDIT_E_ILLEGALBODYFORMAT);
  1831. // if trident is not yet done parsing the HTML, we cannot safely save from the tree.
  1832. if (!m_fMessageParsed)
  1833. return MIMEEDIT_E_CANNOTSAVEUNTILPARSECOMPLETE;
  1834. if(dwFlags & PMS_HTML)
  1835. dwMHTMLFlags |= MECD_HTML;
  1836. if(dwFlags & PMS_TEXT)
  1837. dwMHTMLFlags |= MECD_PLAINTEXT;
  1838. if ((GetHostFlags(&dwHostFlags)==S_OK) &&
  1839. (dwHostFlags & MEO_FLAGS_SENDIMAGES))
  1840. dwMHTMLFlags |= MECD_ENCODEIMAGES|MECD_ENCODESOUNDS|MECD_ENCODEVIDEO|MECD_ENCODEPLUGINS;
  1841. // turn off sound-playing during a save
  1842. EnableSounds(FALSE);
  1843. hr = SaveAsMHTML(m_pDoc, dwMHTMLFlags, m_pMsg, pMsg, m_pHashExternal);
  1844. EnableSounds(TRUE);
  1845. // if save was sucessful, but we haven't yet had a readystate complete notify then
  1846. // bubble a warning backup to give the user a chance to cancel.
  1847. if (hr==S_OK)
  1848. {
  1849. if (m_dwReadyState != READYSTATE_COMPLETE)
  1850. hr = MIMEEDIT_W_DOWNLOADNOTCOMPLETE;
  1851. else
  1852. ClearDirtyFlag(); // clear dirty flag if OK with no warnings.
  1853. }
  1854. return hr;
  1855. }
  1856. HRESULT CBody::Load(BOOL fFullyAvailable, IMoniker *pMoniker, IBindCtx *pBindCtx, DWORD grfMode)
  1857. {
  1858. IMimeMessage *pMsg=0;
  1859. IPersistMoniker *pMsgMon=0;
  1860. HRESULT hr;
  1861. BODYINITDATA biData;
  1862. LPWSTR pszUrlW=0;
  1863. if (!pMoniker)
  1864. return E_INVALIDARG;
  1865. if (pMoniker->GetDisplayName(NULL, NULL, &pszUrlW)==S_OK &&
  1866. HrSniffUrlForRfc822(pszUrlW)==S_OK)
  1867. {
  1868. // if its a message moniker, load via IMimeMessage
  1869. hr = CoCreateInstance(CLSID_IMimeMessage, NULL, CLSCTX_INPROC_SERVER, IID_IMimeMessage, (LPVOID *)&pMsg);
  1870. if (FAILED(hr))
  1871. goto error;
  1872. hr = pMsg->QueryInterface(IID_IPersistMoniker, (LPVOID*)&pMsgMon);
  1873. if (FAILED(hr))
  1874. goto error;
  1875. hr = pMsgMon->Load(fFullyAvailable, pMoniker, pBindCtx, grfMode);
  1876. if (FAILED(hr))
  1877. goto error;
  1878. biData.dwType = BI_MESSAGE;
  1879. biData.pMsg = pMsg;
  1880. }
  1881. else
  1882. {
  1883. biData.dwType = BI_MONIKER;
  1884. biData.pmk = pMoniker;
  1885. }
  1886. hr = LoadFromData(&biData);
  1887. error:
  1888. SafeRelease(pMsg);
  1889. SafeRelease(pMsgMon);
  1890. SafeMemFree(pszUrlW);
  1891. return hr;
  1892. }
  1893. //+---------------------------------------------------------------
  1894. //
  1895. // Member: IsDirty
  1896. //
  1897. // Synopsis:
  1898. //
  1899. //---------------------------------------------------------------
  1900. HRESULT CBody::IsDirty()
  1901. {
  1902. IPersistStreamInit *ppsi;
  1903. HRESULT hr=S_FALSE;
  1904. TraceCall("CBody::IsDirty");
  1905. // if we're not on the source-tab, use the old dirty-state
  1906. // if we're on richedit, make sure to see if source changes there
  1907. switch (m_uSrcView)
  1908. {
  1909. case MEST_SOURCE:
  1910. Assert (m_pSrcView);
  1911. return m_pSrcView->IsDirty();
  1912. case MEST_PREVIEW:
  1913. return m_fWasDirty ?S_OK:S_FALSE;
  1914. }
  1915. if (m_lpOleObj &&
  1916. m_lpOleObj->QueryInterface(IID_IPersistStreamInit, (LPVOID *)&ppsi)==S_OK)
  1917. {
  1918. hr = ppsi->IsDirty();
  1919. ppsi->Release();
  1920. }
  1921. return hr;
  1922. }
  1923. //+---------------------------------------------------------------
  1924. //
  1925. // Member: LoadStream
  1926. //
  1927. // Synopsis:
  1928. //
  1929. //---------------------------------------------------------------
  1930. HRESULT CBody::LoadStream(LPSTREAM pstm)
  1931. {
  1932. HRESULT hr;
  1933. BODYINITDATA biData;
  1934. IMimeMessage *pMsg;
  1935. TraceCall("CBody::LoadStream");
  1936. if (pstm == NULL)
  1937. return TraceResult(E_INVALIDARG);
  1938. // convert RFC822 stream into message
  1939. hr = MimeOleCreateMessage(NULL, &pMsg);
  1940. if (!FAILED(hr))
  1941. {
  1942. hr = pMsg->Load(pstm);
  1943. if (!FAILED(hr))
  1944. {
  1945. biData.dwType = BI_MESSAGE;
  1946. biData.pMsg = pMsg;
  1947. hr = LoadFromData(&biData);
  1948. }
  1949. pMsg->Release();
  1950. }
  1951. return hr;
  1952. }
  1953. //+---------------------------------------------------------------
  1954. //
  1955. // Member: LoadFromData
  1956. //
  1957. // Synopsis:
  1958. //
  1959. //---------------------------------------------------------------
  1960. HRESULT CBody::LoadFromData(LPBODYINITDATA pbiData)
  1961. {
  1962. HRESULT hr;
  1963. LPMONIKER pmk=0;
  1964. IMimeMessage *pMsg;
  1965. DWORD dwMsgFlags;
  1966. TraceCall("CBody::LoadFromData");
  1967. AssertSz(pbiData &&
  1968. ( (pbiData->dwType == BI_MESSAGE && pbiData->pMsg) ||
  1969. (pbiData->dwType == BI_MONIKER && pbiData->pmk)),
  1970. "Caller should be validating params");
  1971. Assert (m_lpOleObj);
  1972. // make sure we're unloaded in case of failure
  1973. UnloadAll();
  1974. switch (pbiData->dwType)
  1975. {
  1976. case BI_MESSAGE:
  1977. {
  1978. WEBPAGEOPTIONS rOptions;
  1979. BOOL fIncludeMsg;
  1980. BOOL fDisplayingHtmlHelp = FALSE;
  1981. BOOL fGotHtmlHelpCharset = FALSE;
  1982. VARIANTARG va;
  1983. pMsg = pbiData->pMsg;
  1984. Assert(pMsg);
  1985. if(SUCCEEDED(m_pParentCmdTarget->Exec(&CMDSETID_MimeEditHost, MEHOSTCMDID_HTML_HELP, 0, NULL, &va)))
  1986. fDisplayingHtmlHelp = (va.boolVal == VARIANT_TRUE);
  1987. if(fDisplayingHtmlHelp)
  1988. {
  1989. IStream *pStream=NULL;
  1990. LPSTR pszCharset=NULL;
  1991. if(SUCCEEDED(pMsg->GetTextBody(TXT_HTML, IET_INETCSET, &pStream, NULL)))
  1992. {
  1993. if(SUCCEEDED(GetHtmlCharset(pStream, &pszCharset)))
  1994. {
  1995. if(SUCCEEDED(MimeOleFindCharset(pszCharset, &m_hCharset)))
  1996. fGotHtmlHelpCharset = TRUE;
  1997. MemFree(pszCharset);
  1998. }
  1999. pStream->Release();
  2000. }
  2001. }
  2002. if(!fGotHtmlHelpCharset)
  2003. {
  2004. // set the character set for use by the preview pane, painting etc
  2005. IF_FAILEXIT(hr = pMsg->GetCharset(&m_hCharset));
  2006. }
  2007. Assert(m_hCharset);
  2008. GetWebPageOptions(&rOptions, &fIncludeMsg);
  2009. if (m_fReloadingSrc || fIncludeMsg)
  2010. {
  2011. // only do autodetection if a plain-text message. this will occur if the
  2012. // message is plain-text only or the host is denying HTML.
  2013. if ( (pMsg->GetFlags(&dwMsgFlags)==S_OK) &&
  2014. (!(dwMsgFlags & IMF_HTML) || !(rOptions.dwFlags & WPF_HTML)))
  2015. m_fAutoDetect = 1;
  2016. // add NOMETACHASET as we setup a HTML load options now
  2017. rOptions.dwFlags |= WPF_NOMETACHARSET;
  2018. IF_FAILEXIT(hr = pMsg->CreateWebPage(NULL, &rOptions, 0, &pmk));
  2019. pmk->GetDisplayName(NULL, NULL, &m_pszUrlW);
  2020. IF_FAILEXIT(hr = LoadFromMoniker(pmk, m_hCharset));
  2021. }
  2022. else
  2023. {
  2024. m_fForceCharsetLoad = TRUE;
  2025. }
  2026. IF_FAILEXIT(hr = pMsg->QueryInterface(IID_IMimeMessageW, (LPVOID*)&m_pMsgW));
  2027. ReplaceInterface(m_pMsg, pMsg);
  2028. break;
  2029. }
  2030. case BI_MONIKER:
  2031. IF_FAILEXIT(hr = LoadFromMoniker(pbiData->pmk, NULL));
  2032. pbiData->pmk->GetDisplayName(NULL, NULL, &m_pszUrlW);
  2033. break;
  2034. }
  2035. if (m_uHdrStyle == MESTYLE_PREVIEW)
  2036. UpdatePreviewLabels();
  2037. m_fEmpty=0;
  2038. exit:
  2039. ReleaseObj(pmk);
  2040. return hr;
  2041. }
  2042. //+---------------------------------------------------------------
  2043. //
  2044. // Member: CreateBodyObject
  2045. //
  2046. // Synopsis:
  2047. //
  2048. //---------------------------------------------------------------
  2049. HRESULT CreateBodyObject(HWND hwnd, DWORD dwFlags, LPRECT prc, PBODYHOSTINFO pHostInfo, LPBODYOBJ *ppBodyObj)
  2050. {
  2051. CBody *pBody;
  2052. HRESULT hr;
  2053. TraceCall("CreateBodyObject");
  2054. pBody = new CBody();
  2055. if (!pBody)
  2056. return TraceResult(E_OUTOFMEMORY);
  2057. hr = pBody->Init(hwnd, dwFlags, prc, pHostInfo);
  2058. if (FAILED(hr))
  2059. {
  2060. TraceResult(hr);
  2061. goto error;
  2062. }
  2063. *ppBodyObj = pBody;
  2064. pBody->AddRef();
  2065. error:
  2066. pBody->Release();
  2067. return hr;
  2068. }
  2069. //+---------------------------------------------------------------
  2070. //
  2071. // Member: UrlHighlight
  2072. //
  2073. // Synopsis:
  2074. //
  2075. //---------------------------------------------------------------
  2076. HRESULT CBody::UrlHighlight(IHTMLTxtRange *pRange)
  2077. {
  2078. IOleCommandTarget *pCmdTarget=NULL;
  2079. VARIANT_BOOL boolVal;
  2080. TraceCall("UrlHighlight");
  2081. if (!pRange)
  2082. return E_INVALIDARG;
  2083. // calling IDM_AUTODETECT will mark the tree dirty, this is bad for replying to plaintext
  2084. // messages etc. To fix this we preserve the dirty between calls.
  2085. boolVal = IsDirty()==S_OK?VARIANT_TRUE:VARIANT_FALSE;
  2086. if (pRange->QueryInterface(IID_IOleCommandTarget, (LPVOID *)&pCmdTarget)==S_OK)
  2087. {
  2088. pCmdTarget->Exec(&CMDSETID_Forms3, IDM_AUTODETECT, NULL, NULL, NULL);
  2089. pCmdTarget->Release();
  2090. HrSetDirtyFlagImpl(m_pDoc, boolVal);
  2091. }
  2092. return S_OK;
  2093. }
  2094. HRESULT CBody::StartAutoDetect()
  2095. {
  2096. m_cchTotal=0;
  2097. m_cchStart=0;
  2098. SetTimer(m_hwnd, idTimerAutoDetect, AUTODETECT_TICKTIME, NULL);
  2099. return S_OK;
  2100. }
  2101. HRESULT CBody::AutoDetectTimer()
  2102. {
  2103. LONG cch=0;
  2104. IMimeBody *pBody;
  2105. IMarkupPointer *pEndPtr=NULL;
  2106. DWORD dwPercent;
  2107. WCHAR wsz[CCHMAX_STRINGRES],
  2108. wszFmt[CCHMAX_STRINGRES],
  2109. wsz2[CCHMAX_STRINGRES];
  2110. LPWSTR pszW;
  2111. HBODY hBody;
  2112. HRESULT hr;
  2113. TraceCall("AutoDetectTimer");
  2114. // if mouse has capture, then ignore this timer-tick as user might be scrolling etc.
  2115. if (GetCapture())
  2116. return S_OK;
  2117. // turn of the timer, in case it takes a while
  2118. KillTimer(m_hwnd, idTimerAutoDetect);
  2119. // we try and give a rough %age estimate if autodetect is taking forever
  2120. // we get the total size of the plain-stream and divide the auto detect
  2121. // chunk into it. If we overflow, we sit at 100% for a while. Also, we don't show
  2122. // a %age until we've hit at least 2 auto detect timers (ie. a big document)
  2123. if (m_cchStart == AUTODETECT_CHUNK * 2)
  2124. {
  2125. // time to start showing progress.
  2126. Assert (m_cchTotal == 0);
  2127. if (m_pMsg->GetTextBody(TXT_PLAIN, IET_DECODED, NULL, &hBody)==S_OK)
  2128. {
  2129. if (m_pMsg->BindToObject(hBody, IID_IMimeBody, (LPVOID *)&pBody)==S_OK)
  2130. {
  2131. pBody->GetEstimatedSize(IET_BINARY, &m_cchTotal);
  2132. pBody->Release();
  2133. }
  2134. }
  2135. }
  2136. *wsz = 0;
  2137. LoadStringWrapW(g_hLocRes, idsSearchHLink, wsz, ARRAYSIZE(wsz));
  2138. if (m_cchTotal &&
  2139. LoadStringWrapW(g_hLocRes, idsSearchHLinkPC, wszFmt, ARRAYSIZE(wszFmt)))
  2140. {
  2141. dwPercent = ( m_cchStart * 100 / m_cchTotal );
  2142. if (dwPercent > 100)
  2143. dwPercent = 100;
  2144. wnsprintfW(wsz2, ARRAYSIZE(wsz2), wszFmt, dwPercent);
  2145. StrCatBuffW(wsz, wsz2, ARRAYSIZE(wsz));
  2146. }
  2147. SetStatusText(wsz);
  2148. m_fAutoDetect = 0;
  2149. if (m_pAutoStartPtr == NULL)
  2150. {
  2151. // create a starting pointer cache it incase we
  2152. // do chunking
  2153. hr = _CreateRangePointer(&m_pAutoStartPtr);
  2154. if (FAILED(hr))
  2155. goto error;
  2156. }
  2157. // create an end pointer
  2158. hr = _CreateRangePointer(&pEndPtr);
  2159. if (FAILED(hr))
  2160. goto error;
  2161. // set the end poniter to the start pointer
  2162. hr = pEndPtr->MoveToPointer(m_pAutoStartPtr);
  2163. if (FAILED(hr))
  2164. goto error;
  2165. // increment the end pointer by the amount to detect
  2166. cch = AUTODETECT_CHUNK;
  2167. hr = _MovePtrByCch(pEndPtr, &cch);
  2168. if (FAILED(hr))
  2169. goto error;
  2170. m_cchStart += cch;
  2171. hr = _UrlHighlightBetweenPtrs(m_pAutoStartPtr, pEndPtr);
  2172. if (FAILED(hr))
  2173. goto error;
  2174. // there must be more to detect, so set the timer
  2175. if (cch >= AUTODETECT_CHUNK)
  2176. {
  2177. m_fAutoDetect = 1;
  2178. // move the cached start pointer to the current end pointer
  2179. hr = m_pAutoStartPtr->MoveToPointer(pEndPtr);
  2180. if (FAILED(hr))
  2181. goto error;
  2182. }
  2183. error:
  2184. if (m_fAutoDetect)
  2185. SetTimer(m_hwnd, idTimerAutoDetect, AUTODETECT_TICKTIME, NULL);
  2186. else
  2187. {
  2188. SetStatusText(NULL);
  2189. SafeRelease(m_pAutoStartPtr);
  2190. }
  2191. ReleaseObj(pEndPtr);
  2192. return hr;
  2193. }
  2194. HRESULT CBody::_MovePtrByCch(IMarkupPointer *pPtr, LONG *pcp)
  2195. {
  2196. HRESULT hr;
  2197. LONG cch,
  2198. cchDone=0;
  2199. MARKUP_CONTEXT_TYPE ctxt;
  2200. do
  2201. {
  2202. cch = *pcp - cchDone ;
  2203. hr = pPtr->Right(TRUE, &ctxt, NULL, &cch, NULL);
  2204. if (!FAILED(hr))
  2205. cchDone += cch;
  2206. }
  2207. while ( !FAILED(hr) &&
  2208. ctxt != CONTEXT_TYPE_None &&
  2209. cchDone < *pcp);
  2210. *pcp = cchDone;
  2211. return cchDone ? S_OK : E_FAIL;
  2212. }
  2213. HRESULT CBody::_CreateRangePointer(IMarkupPointer **ppPtr)
  2214. {
  2215. IMarkupServices *pMarkupServices=0;
  2216. IMarkupPointer *pPtr=0;
  2217. IHTMLBodyElement *pBodyElem=0;
  2218. IHTMLElement *pElem=0;
  2219. HRESULT hr;
  2220. if (ppPtr == NULL)
  2221. return E_INVALIDARG;
  2222. *ppPtr = 0;
  2223. // get a markup services object
  2224. hr = m_pDoc->QueryInterface(IID_IMarkupServices, (void **) &pMarkupServices);
  2225. if (FAILED(hr))
  2226. goto error;
  2227. hr = pMarkupServices->CreateMarkupPointer(&pPtr);
  2228. if (FAILED(hr))
  2229. goto error;
  2230. // get the body element
  2231. hr = GetBodyElement(&pBodyElem);
  2232. if (FAILED(hr))
  2233. goto error;
  2234. // get right interface
  2235. hr = pBodyElem->QueryInterface(IID_IHTMLElement, (LPVOID *)&pElem);
  2236. if (FAILED(hr))
  2237. goto error;
  2238. // move start pointer to after begining of <BODY> tag
  2239. hr = pPtr->MoveAdjacentToElement(pElem, ELEM_ADJ_AfterBegin);
  2240. if (FAILED(hr))
  2241. goto error;
  2242. // hand back pointers
  2243. *ppPtr = pPtr;
  2244. pPtr = NULL;
  2245. error:
  2246. ReleaseObj(pElem);
  2247. ReleaseObj(pBodyElem);
  2248. ReleaseObj(pMarkupServices);
  2249. ReleaseObj(pPtr);
  2250. return hr;
  2251. }
  2252. HRESULT CBody::_UrlHighlightBetweenPtrs(IMarkupPointer *pStartPtr, IMarkupPointer *pEndPtr)
  2253. {
  2254. IMarkupServices *pMarkupServices=0;
  2255. IHTMLTxtRange *pRange=0;
  2256. HRESULT hr;
  2257. // get a markup services object
  2258. hr = m_pDoc->QueryInterface(IID_IMarkupServices, (void **) &pMarkupServices);
  2259. if (FAILED(hr))
  2260. goto error;
  2261. // create a text range
  2262. hr = CreateRange(&pRange);
  2263. if (FAILED(hr))
  2264. goto error;
  2265. // use markup services to move pointers to range
  2266. hr = pMarkupServices->MoveRangeToPointers(pStartPtr, pEndPtr, pRange);
  2267. if (FAILED(hr))
  2268. goto error;
  2269. // autodetect range
  2270. hr = UrlHighlight(pRange);
  2271. if (FAILED(hr))
  2272. goto error;
  2273. error:
  2274. ReleaseObj(pMarkupServices);
  2275. ReleaseObj(pRange);
  2276. return hr;
  2277. }
  2278. //+---------------------------------------------------------------
  2279. //
  2280. // Member: StopAutoDetect
  2281. //
  2282. // Synopsis:
  2283. //
  2284. //---------------------------------------------------------------
  2285. HRESULT CBody::StopAutoDetect()
  2286. {
  2287. TraceCall("CBody::StopAutoDetect");
  2288. if (m_fAutoDetect)
  2289. {
  2290. m_fAutoDetect = 0;
  2291. KillTimer(m_hwnd, idTimerAutoDetect);
  2292. TraceInfo("AutoDetect: CANCELED");
  2293. }
  2294. return S_OK;
  2295. }
  2296. //+---------------------------------------------------------------
  2297. //
  2298. // Member: UnloadAll
  2299. //
  2300. // Synopsis:
  2301. //
  2302. //---------------------------------------------------------------
  2303. HRESULT CBody::UnloadAll()
  2304. {
  2305. TraceCall("CBody::UnloadAll");
  2306. StopAutoDetect();
  2307. InvalidateRect(m_hwnd, NULL, TRUE);
  2308. if (!m_fEmpty)
  2309. {
  2310. if (m_lpOleObj)
  2311. HrInitNew(m_lpOleObj);
  2312. // if unloading due to a tab-switch in source-view
  2313. // don't blow away our restriction hash
  2314. if (!m_fReloadingSrc)
  2315. SafeRelease(m_pHashExternal);
  2316. SafeRelease(m_pAttMenu);
  2317. SafeRelease(m_pMsg);
  2318. SafeRelease(m_pMsgW);
  2319. SafeRelease(m_pRangeIgnoreSpell);
  2320. SafeRelease(m_pAutoStartPtr);
  2321. SafeCoTaskMemFree(m_pszUrlW);
  2322. SafeFreeTempFileList(m_pTempFileUrl);
  2323. SafeMimeOleFree(m_pszSubject);
  2324. SafeMimeOleFree(m_pszTo);
  2325. SafeMimeOleFree(m_pszCc);
  2326. SafeMimeOleFree(m_pszFrom);
  2327. // if unloading, clear button-bar
  2328. if (m_uHdrStyle == MESTYLE_PREVIEW)
  2329. UpdateBtnBar();
  2330. m_dwReadyState = READYSTATE_UNINITIALIZED;
  2331. m_fMessageParsed = 0;
  2332. m_fEmpty = 1;
  2333. m_hCharset = NULL;
  2334. }
  2335. m_fLoading =1;
  2336. return S_OK;
  2337. }
  2338. //+---------------------------------------------------------------
  2339. //
  2340. // Member: LoadFromMoniker
  2341. //
  2342. // Synopsis:
  2343. //
  2344. //---------------------------------------------------------------
  2345. HRESULT CBody::LoadFromMoniker(IMoniker *pmk, HCHARSET hCharset)
  2346. {
  2347. HRESULT hr=E_FAIL;
  2348. LPPERSISTMONIKER pPMoniker=0;
  2349. LPBC pbc=0;
  2350. IHtmlLoadOptions *phlo;
  2351. DWORD uCodePage=0;
  2352. INETCSETINFO CsetInfo;
  2353. TraceCall("CBody::LoadFromMoniker");
  2354. Assert (m_lpOleObj);
  2355. hr=m_lpOleObj->QueryInterface(IID_IPersistMoniker, (LPVOID *)&pPMoniker);
  2356. if(FAILED(hr))
  2357. {
  2358. TraceResult(hr);
  2359. goto error;
  2360. }
  2361. hr=CreateBindCtx(0, &pbc);
  2362. if(FAILED(hr))
  2363. {
  2364. TraceResult(hr);
  2365. goto error;
  2366. }
  2367. if (hCharset)
  2368. {
  2369. // caller wants to override document charset
  2370. if (MimeOleGetCharsetInfo(hCharset, &CsetInfo)==S_OK)
  2371. uCodePage = CsetInfo.cpiInternet;
  2372. if (uCodePage &&
  2373. CoCreateInstance(CLSID_HTMLLoadOptions, NULL, CLSCTX_INPROC_SERVER,
  2374. IID_IHtmlLoadOptions, (void**)&phlo)==S_OK)
  2375. {
  2376. if (SUCCEEDED(phlo->SetOption(HTMLLOADOPTION_CODEPAGE,
  2377. &uCodePage, sizeof(uCodePage))))
  2378. pbc->RegisterObjectParam(L"__HTMLLOADOPTIONS", phlo);
  2379. phlo->Release();
  2380. }
  2381. }
  2382. hr=pPMoniker->Load(TRUE, pmk, pbc, STGM_READWRITE);
  2383. if(FAILED(hr))
  2384. {
  2385. TraceResult(hr);
  2386. goto error;
  2387. }
  2388. error:
  2389. ReleaseObj(pPMoniker);
  2390. ReleaseObj(pbc);
  2391. return hr;
  2392. }
  2393. //+---------------------------------------------------------------
  2394. //
  2395. // Member: OnFrameActivate
  2396. //
  2397. // Synopsis:
  2398. //
  2399. //---------------------------------------------------------------
  2400. HRESULT CBody::OnFrameActivate(BOOL fActivate)
  2401. {
  2402. TraceCall("CBody::OnFrameActivate");
  2403. if (m_pInPlaceActiveObj)
  2404. m_pInPlaceActiveObj->OnFrameWindowActivate(fActivate);
  2405. // enable/disable sounds on frame activation
  2406. EnableSounds(fActivate);
  2407. return S_OK;
  2408. }
  2409. BOOL CBody::IsEmpty()
  2410. {
  2411. BOOL fEmpty = FALSE;
  2412. if (!m_fDesignMode)
  2413. {
  2414. if (m_fEmpty)
  2415. fEmpty = TRUE;
  2416. }
  2417. /*
  2418. ** We need to come up with a good way to test if the text is
  2419. ** empty. The test below always returns FALSE because of an nbsp
  2420. ** that is in the text. If a better algorithm can be found, then
  2421. ** we can reimplement this. The case that will hit this is posting
  2422. ** a news note without any text. This should generate a TRUE.
  2423. else
  2424. {
  2425. IHTMLElement *pElem=0;
  2426. IHTMLTxtRange *pTxtRangeBegin = NULL,
  2427. *pTxtRangeEnd = NULL;
  2428. m_pDoc->get_body(&pElem);
  2429. if (pElem)
  2430. {
  2431. if (SUCCEEDED(CreateRange(&pTxtRangeBegin)))
  2432. {
  2433. pTxtRangeBegin->collapse(VARIANT_TRUE);
  2434. if (SUCCEEDED(CreateRange(&pTxtRangeEnd)))
  2435. {
  2436. pTxtRangeEnd->collapse(VARIANT_FALSE);
  2437. VARIANT_BOOL varBool = VARIANT_FALSE;
  2438. if (SUCCEEDED(pTxtRangeBegin->isEqual(pTxtRangeEnd, &varBool)) && (VARIANT_TRUE == varBool))
  2439. fEmpty = TRUE;
  2440. pTxtRangeEnd->Release();
  2441. }
  2442. pTxtRangeBegin->Release();
  2443. }
  2444. pElem->Release();
  2445. }
  2446. }
  2447. */
  2448. return fEmpty;
  2449. }
  2450. //+---------------------------------------------------------------
  2451. //
  2452. // Member: CBody::PrivateQueryStatus
  2453. //
  2454. // Synopsis: Private IOleCmdTarget called from the outer document
  2455. // to implement CDoc::CmdTarget
  2456. //
  2457. //---------------------------------------------------------------
  2458. HRESULT CBody::PrivateQueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText)
  2459. {
  2460. ULONG uCmd;
  2461. HRESULT hr=E_FAIL;
  2462. OLECMD *pCmd;
  2463. ULONG uCmdDisable;
  2464. static const UINT c_rgcmdIdNoPlain[] =
  2465. {
  2466. IDM_INDENT, IDM_OUTDENT, IDM_FONT, IDM_BLOCKFMT, IDM_IMAGE,
  2467. IDM_HORIZONTALLINE, IDM_UNLINK, IDM_HYPERLINK
  2468. };
  2469. TraceCall("CBody::PrivateQueryStatus");
  2470. if (m_uSrcView != MEST_EDIT &&
  2471. m_pSrcView &&
  2472. m_pSrcView->QueryStatus(pguidCmdGroup, cCmds, prgCmds, pCmdText)==S_OK)
  2473. return S_OK;
  2474. if (pguidCmdGroup == NULL)
  2475. {
  2476. if (m_pCmdTarget)
  2477. hr = m_pCmdTarget->QueryStatus(pguidCmdGroup, cCmds, prgCmds, pCmdText);
  2478. for (uCmd=0; uCmd < cCmds; uCmd++)
  2479. {
  2480. pCmd = &prgCmds[uCmd];
  2481. switch(pCmd->cmdID)
  2482. {
  2483. case OLECMDID_PRINT:
  2484. // if we have no m_pMsg, disable the print verb
  2485. if (!m_pMsg)
  2486. pCmd->cmdf=OLECMDF_SUPPORTED;
  2487. break;
  2488. case OLECMDID_FIND:
  2489. pCmd->cmdf=OLECMDF_ENABLED|OLECMDF_SUPPORTED;
  2490. hr = S_OK;
  2491. break;
  2492. case OLECMDID_SPELL:
  2493. pCmd->cmdf=OLECMDF_SUPPORTED;
  2494. if ((m_uSrcView == MEST_EDIT) && FCheckSpellAvail(m_pParentCmdTarget))
  2495. pCmd->cmdf |= OLECMDF_ENABLED;
  2496. hr = S_OK;
  2497. break;
  2498. }
  2499. }
  2500. // delegate standard group to trident
  2501. }
  2502. else if (IsEqualGUID(*pguidCmdGroup, CMDSETID_Forms3))
  2503. {
  2504. // delegate Forms3 group to trident
  2505. if (m_pCmdTarget)
  2506. hr = m_pCmdTarget->QueryStatus(pguidCmdGroup, cCmds, prgCmds, pCmdText);
  2507. // post-process triden't query status and disable commands that are not
  2508. // available in plain-text mode
  2509. if (m_fPlainMode)
  2510. {
  2511. for (uCmd=0; uCmd < cCmds; uCmd++)
  2512. {
  2513. for (uCmdDisable = 0; uCmdDisable < ARRAYSIZE(c_rgcmdIdNoPlain); uCmdDisable++)
  2514. {
  2515. if (c_rgcmdIdNoPlain[uCmdDisable] == prgCmds[uCmd].cmdID)
  2516. {
  2517. // if enabled, disable it
  2518. prgCmds[uCmd].cmdf &= ~OLECMDF_ENABLED;
  2519. break;
  2520. }
  2521. }
  2522. }
  2523. }
  2524. }
  2525. else if (IsEqualGUID(*pguidCmdGroup, CMDSETID_MimeEdit))
  2526. {
  2527. for (uCmd=0; uCmd < cCmds; uCmd++)
  2528. {
  2529. pCmd = &prgCmds[uCmd];
  2530. pCmd->cmdf = OLECMDF_SUPPORTED;
  2531. switch(pCmd->cmdID)
  2532. {
  2533. case MECMDID_TABLINKS:
  2534. case MECMDID_APPLYDOCUMENT:
  2535. case MECMDID_SAVEASSTATIONERY:
  2536. case MECMDID_DIRTY:
  2537. case MECMDID_INSERTTEXTFILE:
  2538. case MECMDID_FORMATFONT:
  2539. case MECMDID_SETTEXT:
  2540. case MECMDID_DOWNGRADEPLAINTEXT:
  2541. case MECMDID_CHARSET:
  2542. case MECMDID_ROT13:
  2543. case MECMDID_INSERTTEXT:
  2544. case MECMDID_INSERTHTML:
  2545. case MECMDID_BACKGROUNDCOLOR:
  2546. case MECMDID_STYLE:
  2547. case MECMDID_CANENCODETEXT:
  2548. pCmd->cmdf|=OLECMDF_ENABLED;
  2549. break;
  2550. case MECMDID_SHOWSOURCETABS:
  2551. if (!m_fPlainMode)
  2552. {
  2553. // source-editing only available in plain-text mode
  2554. pCmd->cmdf|=OLECMDF_ENABLED;
  2555. if (m_fSrcTabs)
  2556. pCmd->cmdf|=OLECMDF_LATCHED;
  2557. }
  2558. break;
  2559. case MECMDID_EMPTY:
  2560. pCmd->cmdf|=OLECMDF_ENABLED;
  2561. if (IsEmpty())
  2562. pCmd->cmdf|=OLECMDF_LATCHED;
  2563. break;
  2564. case MECMDID_EDITHTML:
  2565. pCmd->cmdf|=OLECMDF_ENABLED;
  2566. if (!m_fPlainMode)
  2567. pCmd->cmdf|=OLECMDF_LATCHED;
  2568. break;
  2569. case MECMDID_EDITMODE:
  2570. pCmd->cmdf|=OLECMDF_ENABLED;
  2571. if (m_fDesignMode)
  2572. pCmd->cmdf|=OLECMDF_LATCHED;
  2573. break;
  2574. case MECMDID_SAVEATTACHMENTS:
  2575. EnsureAttMenu();
  2576. if (m_pAttMenu &&
  2577. m_pAttMenu->HasEnabledAttach()==S_OK)
  2578. pCmd->cmdf|=OLECMDF_ENABLED;
  2579. break;
  2580. case MECMDID_FORMATPARAGRAPH:
  2581. if (!m_fPlainMode)
  2582. pCmd->cmdf|=OLECMDF_ENABLED;
  2583. break;
  2584. default:
  2585. // not a recognised command
  2586. pCmd->cmdf = 0;
  2587. break;
  2588. }
  2589. }
  2590. hr = S_OK;
  2591. }
  2592. else
  2593. hr = OLECMDERR_E_UNKNOWNGROUP;
  2594. return hr;
  2595. }
  2596. //+---------------------------------------------------------------
  2597. //
  2598. // Member: CBody::PrivateExec
  2599. //
  2600. // Synopsis: Private IOleCmdTarget called from the outer document
  2601. // to implement CDoc::CmdTarget
  2602. //
  2603. //---------------------------------------------------------------
  2604. HRESULT CBody::PrivateExec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut)
  2605. {
  2606. HRESULT hr=E_FAIL;
  2607. TraceCall("CBody::PrivateExec");
  2608. if (m_uSrcView != MEST_EDIT &&
  2609. m_pSrcView &&
  2610. m_pSrcView->Exec(pguidCmdGroup, nCmdID, nCmdExecOpt, pvaIn, pvaOut)==S_OK)
  2611. return S_OK;
  2612. if (pguidCmdGroup == NULL || IsEqualGUID(*pguidCmdGroup, CMDSETID_Forms3) || IsEqualGUID(*pguidCmdGroup, CGID_ShellDocView))
  2613. {
  2614. switch (nCmdID)
  2615. {
  2616. case OLECMDID_SPELL:
  2617. {
  2618. VARIANTARG va;
  2619. // tell trident we are bringing up a modal dialog
  2620. // by calling PrivateEnableModeless
  2621. if (!m_pSpell) //no background spellchecking
  2622. HrCreateSpeller(FALSE);
  2623. if (m_pSpell)
  2624. {
  2625. PrivateEnableModeless(FALSE);
  2626. #ifdef BACKGROUNDSPELL
  2627. if (m_fBkgrndSpelling)
  2628. KillTimer(m_hwnd, idTimerBkgrndSpell);
  2629. #endif // BACKGROUNDSPELL
  2630. hr = m_pSpell->HrSpellChecking(m_pRangeIgnoreSpell, m_hwnd, (OLECMDEXECOPT_DONTPROMPTUSER==nCmdExecOpt)?TRUE:FALSE);
  2631. #ifdef BACKGROUNDSPELL
  2632. if (m_fBkgrndSpelling)
  2633. SetTimer(m_hwnd, idTimerBkgrndSpell, BKGRNDSPELL_TICKTIME, NULL);
  2634. #endif // BACKGROUNDSPELL
  2635. PrivateEnableModeless(TRUE);
  2636. }
  2637. }
  2638. return hr;
  2639. case OLECMDID_PRINT:
  2640. return Print(nCmdExecOpt!=OLECMDEXECOPT_DONTPROMPTUSER, pvaIn);
  2641. case OLECMDID_REFRESH:
  2642. return m_pCmdTarget ? m_pCmdTarget->Exec(&CMDSETID_Forms3, IDM_REFRESH, OLECMDEXECOPT_DODEFAULT, NULL, NULL) : E_FAIL;
  2643. case OLECMDID_FIND:
  2644. // Trident has own private Find, map OLE find to this.
  2645. return m_pCmdTarget ? m_pCmdTarget->Exec(&CMDSETID_Forms3, IDM_FIND, OLECMDEXECOPT_DODEFAULT, NULL, NULL) : E_FAIL;
  2646. }
  2647. // delegate standard commands and trident commandset we don't handle
  2648. // to trident
  2649. return m_pCmdTarget?m_pCmdTarget->Exec(pguidCmdGroup, nCmdID, nCmdExecOpt, pvaIn, pvaOut):E_NOTIMPL;
  2650. }
  2651. else if (IsEqualGUID(*pguidCmdGroup, CMDSETID_MimeEdit))
  2652. {
  2653. hr = E_INVALIDARG;
  2654. switch (nCmdID)
  2655. {
  2656. case MECMDID_SETSOURCETAB:
  2657. if (pvaIn && pvaIn->vt == VT_I4)
  2658. return SetSourceTabs(pvaIn->lVal);
  2659. else if (pvaOut)
  2660. {
  2661. pvaOut->vt = VT_I4;
  2662. pvaOut->lVal = m_fSrcTabs ? m_uSrcView : MEST_EDIT;
  2663. return S_OK;
  2664. }
  2665. return E_INVALIDARG;
  2666. case MECMDID_TABLINKS:
  2667. if (pvaIn && pvaIn->vt == VT_BOOL)
  2668. {
  2669. m_fTabLinks = (pvaIn->boolVal == VARIANT_TRUE);
  2670. return S_OK;
  2671. }
  2672. return E_INVALIDARG;
  2673. case MECMDID_SAVEATTACHMENTS:
  2674. return SaveAttachments();
  2675. case MECMDID_INSERTBGSOUND:
  2676. return InsertBackgroundSound();
  2677. case MECMDID_BACKGROUNDIMAGE:
  2678. if (pvaIn && pvaIn->vt == VT_BSTR)
  2679. return SetBackgroundImage(m_pDoc, pvaIn->bstrVal);
  2680. if (pvaOut)
  2681. {
  2682. pvaOut->vt = VT_BSTR;
  2683. return GetBackgroundImage(m_pDoc, &pvaOut->bstrVal);
  2684. }
  2685. return E_INVALIDARG;
  2686. case MECMDID_SHOWSOURCETABS:
  2687. if (pvaIn && pvaIn->vt == VT_BOOL)
  2688. {
  2689. ShowSourceTabs(pvaIn->boolVal == VARIANT_TRUE);
  2690. return S_OK;
  2691. }
  2692. return E_INVALIDARG;
  2693. case MECMDID_APPLYDOCUMENT:
  2694. return ApplyDocumentVerb(pvaIn);
  2695. case MECMDID_SAVEASSTATIONERY:
  2696. return SaveAsStationery(pvaIn, pvaOut);
  2697. case MECMDID_DIRTY:
  2698. if (pvaIn &&
  2699. pvaIn->vt == VT_BOOL)
  2700. {
  2701. return HrSetDirtyFlagImpl(m_pDoc, pvaIn->boolVal==VARIANT_TRUE);
  2702. }
  2703. else if (pvaOut)
  2704. {
  2705. pvaOut->vt = VT_BOOL;
  2706. pvaOut->boolVal = IsDirty()==S_OK?VARIANT_TRUE:VARIANT_FALSE;
  2707. return S_OK;
  2708. }
  2709. break;
  2710. case MECMDID_FORMATPARAGRAPH:
  2711. return HrFormatParagraph();
  2712. break;
  2713. case MECMDID_EMPTY:
  2714. if (pvaOut)
  2715. {
  2716. pvaOut->vt = VT_BOOL;
  2717. pvaOut->boolVal = (IsEmpty() ? VARIANT_TRUE : VARIANT_FALSE);
  2718. return S_OK;
  2719. }
  2720. break;
  2721. case MECMDID_DOWNGRADEPLAINTEXT:
  2722. return DowngradeToPlainText(pvaIn ? (pvaIn->vt == VT_BOOL ? (pvaIn->boolVal == VARIANT_TRUE) : NULL ): NULL );
  2723. case MECMDID_CHARSET:
  2724. if (pvaIn &&
  2725. pvaIn->vt == VT_I8)
  2726. {
  2727. return SetCharset((HCHARSET)pvaIn->ullVal);
  2728. }
  2729. else if (pvaOut)
  2730. {
  2731. pvaOut->vt = VT_I8;
  2732. pvaOut->ullVal = (ULONGLONG)m_hCharset;
  2733. return S_OK;
  2734. }
  2735. break;
  2736. case MECMDID_FORMATFONT:
  2737. return FormatFont();
  2738. case MECMDID_PREVIEWFORMAT:
  2739. if (pvaIn &&
  2740. pvaIn->vt == VT_BSTR)
  2741. {
  2742. SafeMemFree(m_pszLayout);
  2743. HrBSTRToLPSZ(CP_ACP, pvaIn->bstrVal, &m_pszLayout);
  2744. RecalcPreivewHeight(NULL);
  2745. Resize();
  2746. return S_OK;
  2747. }
  2748. break;
  2749. case MECMDID_INSERTTEXTFILE:
  2750. return InsertFile((pvaIn && pvaIn->vt==VT_BSTR) ? pvaIn->bstrVal : NULL);
  2751. case MECMDID_VIEWSOURCE:
  2752. if (pvaIn &&
  2753. pvaIn->vt == VT_I4)
  2754. {
  2755. ViewSource(pvaIn->lVal == MECMD_VS_MESSAGE);
  2756. return S_OK;
  2757. }
  2758. break;
  2759. case MECMDID_STYLE:
  2760. if (pvaIn &&
  2761. pvaIn->vt == VT_I4)
  2762. return SetStyle(pvaIn->lVal);
  2763. if (pvaOut)
  2764. {
  2765. pvaOut->vt=VT_I4;
  2766. pvaOut->lVal = m_uHdrStyle;
  2767. return S_OK;
  2768. }
  2769. break;
  2770. case MECMDID_ROT13:
  2771. if (pvaIn == NULL && pvaOut == NULL)
  2772. {
  2773. DoRot13();
  2774. return S_OK;
  2775. }
  2776. break;
  2777. case MECMDID_INSERTTEXT:
  2778. case MECMDID_INSERTHTML:
  2779. if (pvaIn && pvaIn->vt == VT_BSTR)
  2780. {
  2781. return InsertTextAtCaret(pvaIn->bstrVal, MECMDID_INSERTHTML == nCmdID, FALSE);
  2782. }
  2783. break;
  2784. case MECMDID_BACKGROUNDCOLOR:
  2785. if (pvaIn && VT_I4 == pvaIn->vt)
  2786. return SetBackgroundColor(pvaIn->ulVal);
  2787. else if (pvaOut)
  2788. {
  2789. pvaOut->vt = VT_I4;
  2790. return GetBackgroundColor(&(pvaOut->ulVal));
  2791. }
  2792. break;
  2793. case MECMDID_EDITHTML:
  2794. if (pvaIn &&
  2795. pvaIn->vt == VT_BOOL)
  2796. {
  2797. return SetPlainTextMode(pvaIn->boolVal!=VARIANT_TRUE);
  2798. }
  2799. else if (pvaOut)
  2800. {
  2801. pvaOut->vt = VT_BOOL;
  2802. pvaOut->boolVal = m_fPlainMode?VARIANT_FALSE:VARIANT_TRUE;
  2803. return S_OK;
  2804. }
  2805. break;
  2806. case MECMDID_EDITMODE:
  2807. if (pvaIn &&
  2808. pvaIn->vt == VT_BOOL)
  2809. {
  2810. return SetDesignMode(pvaIn->boolVal==VARIANT_TRUE);
  2811. }
  2812. else if (pvaOut)
  2813. {
  2814. pvaOut->vt = VT_BOOL;
  2815. pvaOut->boolVal = m_fDesignMode?VARIANT_TRUE:VARIANT_FALSE;
  2816. return S_OK;
  2817. }
  2818. return E_INVALIDARG;
  2819. case MECMDID_SETTEXT:
  2820. if (pvaIn==NULL || pvaIn->vt != VT_BSTR)
  2821. return E_INVALIDARG;
  2822. return SetDocumentText(pvaIn->bstrVal);
  2823. case MECMDID_CANENCODETEXT:
  2824. if (!pvaIn || pvaIn->vt != VT_UI4)
  2825. return E_INVALIDARG;
  2826. return SafeToEncodeText(pvaIn->lVal);
  2827. default:
  2828. hr = E_NOTIMPL;
  2829. }
  2830. }
  2831. return hr;
  2832. }
  2833. HRESULT CBody::PrivateTranslateAccelerator(LPMSG lpmsg)
  2834. {
  2835. HRESULT hr=S_FALSE;
  2836. BOOL fTabbing=FALSE;
  2837. HWND hwndFocus;
  2838. // first of all, see if the formatbar is taking it...
  2839. if (m_fUIActive &&
  2840. m_uHdrStyle==MESTYLE_FORMATBAR &&
  2841. m_pFmtBar &&
  2842. m_pFmtBar->TranslateAcclerator(lpmsg)==S_OK)
  2843. return S_OK;
  2844. if (m_pSrcView &&
  2845. m_uSrcView == MEST_SOURCE)
  2846. {
  2847. return m_pSrcView->TranslateAccelerator(lpmsg);
  2848. }
  2849. // if trident is not in-place active, don't pass accelerators
  2850. if(!m_pInPlaceActiveObj)
  2851. return S_FALSE;
  2852. if (!m_fFocus)
  2853. {
  2854. // if trident doesn't have focus, make sure it's not a child
  2855. // of trident before blocking
  2856. hwndFocus = GetFocus();
  2857. if (hwndFocus == NULL ||
  2858. !IsChild(m_hwndDocObj, hwndFocus))
  2859. return S_FALSE;
  2860. }
  2861. // if Trident has focus and we get a TAB key in edit mode, we snag it and
  2862. // insert a tab ourselves
  2863. if (m_fFocus &&
  2864. lpmsg->message == WM_KEYDOWN &&
  2865. lpmsg->wParam == VK_TAB &&
  2866. m_fDesignMode &&
  2867. !(GetKeyState(VK_SHIFT)&0x8000))
  2868. {
  2869. // plain-tab with no shift in design mode inserts a tag
  2870. InsertTextAtCaret((BSTR)c_bstr_TabChar, FALSE, TRUE);
  2871. return S_OK;
  2872. }
  2873. if (lpmsg->message == WM_KEYDOWN)
  2874. {
  2875. if (lpmsg->wParam == VK_F6)
  2876. return S_FALSE;
  2877. if (lpmsg->wParam == VK_TAB)
  2878. {
  2879. if (!(m_fTabLinks))
  2880. return S_FALSE;
  2881. // if this control want's link-tabbing...
  2882. fTabbing=TRUE;
  2883. m_fCycleFocus=0;
  2884. }
  2885. }
  2886. // trident snags EVERYTHING. even non-keystrokes, only pass them keys...
  2887. if(lpmsg->message >= WM_KEYFIRST && lpmsg->message <= WM_KEYLAST)
  2888. {
  2889. hr=m_pInPlaceActiveObj->TranslateAccelerator(lpmsg);
  2890. if (m_fIgnoreAccel)
  2891. {
  2892. m_fIgnoreAccel = 0;
  2893. return S_FALSE;
  2894. }
  2895. if (fTabbing && m_fCycleFocus)
  2896. return S_FALSE;
  2897. }
  2898. return hr;
  2899. }
  2900. //+---------------------------------------------------------------
  2901. //
  2902. // Member: CBody::PrivateQueryService
  2903. //
  2904. // Synopsis: Private QueryService called from the outer document
  2905. // to implement CDoc::IServiceProvider
  2906. //
  2907. //---------------------------------------------------------------
  2908. HRESULT CBody::PrivateQueryService(REFGUID guidService, REFIID riid, LPVOID *ppvObject)
  2909. {
  2910. HRESULT hr;
  2911. TraceCall("CBody::PrivateQueryService");
  2912. if (!m_pDoc)
  2913. return E_UNEXPECTED;
  2914. if (IsEqualGUID(guidService, IID_IHTMLDocument2) &&
  2915. IsEqualGUID(riid, IID_IHTMLDocument2))
  2916. {
  2917. *ppvObject = (LPVOID)m_pDoc;
  2918. m_pDoc->AddRef();
  2919. return S_OK;
  2920. }
  2921. // RAID 12020. Needed to be able to get at DocHostUI for drop stuff
  2922. else if (IsEqualGUID(guidService, IID_IDocHostUIHandler) &&
  2923. IsEqualGUID(riid, IID_IDocHostUIHandler))
  2924. {
  2925. *ppvObject = (LPVOID)(IDocHostUIHandler*)this;
  2926. AddRef();
  2927. return S_OK;
  2928. }
  2929. return E_NOINTERFACE;
  2930. }
  2931. //+---------------------------------------------------------------
  2932. //
  2933. // Member: CBody::SetDesignMode
  2934. //
  2935. // Synopsis:
  2936. //
  2937. //---------------------------------------------------------------
  2938. HRESULT CBody::SetDesignMode(BOOL fOn)
  2939. {
  2940. HRESULT hr;
  2941. TraceCall("CBody::SetDesignMode");
  2942. if (fOn == m_fDesignMode) // bitfield!
  2943. return S_OK;
  2944. Assert (m_pCmdTarget);
  2945. Assert (m_lpOleObj);
  2946. hr = m_pCmdTarget->Exec(&CMDSETID_Forms3,
  2947. (fOn?IDM_EDITMODE:IDM_BROWSEMODE),
  2948. MSOCMDEXECOPT_DONTPROMPTUSER,
  2949. NULL, NULL);
  2950. if (!FAILED(hr))
  2951. {
  2952. m_fDesignMode = !!fOn; // bitfield
  2953. if (fOn)
  2954. {
  2955. SetHostComposeFont();
  2956. }
  2957. }
  2958. return hr;
  2959. }
  2960. HRESULT CBody::SetPlainTextMode(BOOL fOn)
  2961. {
  2962. VARIANTARG va;
  2963. BSTR bstr=0;
  2964. m_fPlainMode=fOn;
  2965. va.bstrVal = NULL;
  2966. if (!fOn &&
  2967. m_pParentCmdTarget)
  2968. m_pParentCmdTarget->Exec(&CMDSETID_MimeEditHost, MEHOSTCMDID_COMPOSE_FONT, OLECMDEXECOPT_DODEFAULT, NULL, &va);
  2969. SetComposeFont(va.bstrVal); //va.bstrVal could be NULL to turn compose font OFF
  2970. SysFreeString(va.bstrVal);
  2971. if (fOn)
  2972. {
  2973. // if going to plain-text mode, remove the tabs
  2974. ShowSourceTabs(FALSE);
  2975. }
  2976. else
  2977. {
  2978. // if going from plain-text > html, then exec a remove formatting command
  2979. // so that the new compose font is applied
  2980. IHTMLTxtRange *pTxtRange;
  2981. IOleCommandTarget *pCmdTarget;
  2982. if (!FAILED(CreateRange(&pTxtRange)))
  2983. {
  2984. if (!FAILED(pTxtRange->QueryInterface(IID_IOleCommandTarget, (LPVOID *)&pCmdTarget)))
  2985. {
  2986. pCmdTarget->Exec(&CMDSETID_Forms3, IDM_REMOVEFORMAT, OLECMDEXECOPT_DODEFAULT, NULL, NULL);
  2987. pCmdTarget->Release();
  2988. }
  2989. pTxtRange->Release();
  2990. }
  2991. }
  2992. return S_OK;
  2993. }
  2994. //+---------------------------------------------------------------
  2995. //
  2996. // Member: DeleteElement
  2997. //
  2998. // Synopsis:
  2999. //
  3000. //---------------------------------------------------------------
  3001. HRESULT CBody::DeleteElement(IHTMLElement *pElem)
  3002. {
  3003. HRESULT hr=E_INVALIDARG;
  3004. TraceCall("CBody::DeleteElement");
  3005. if (pElem)
  3006. hr = pElem->put_outerHTML(NULL);
  3007. return hr;
  3008. }
  3009. //+---------------------------------------------------------------
  3010. //
  3011. // Member: ReplaceElement
  3012. //
  3013. // Synopsis:
  3014. //
  3015. //---------------------------------------------------------------
  3016. HRESULT CBody::ReplaceElement(LPCTSTR pszName, BSTR bstrPaste, BOOL fHtml)
  3017. {
  3018. IHTMLElement *pElem;
  3019. HRESULT hr;
  3020. TraceCall("CBody::HrReplaceElement");
  3021. if (!FAILED(hr = GetElement(pszName, &pElem)))
  3022. {
  3023. if (fHtml)
  3024. hr = pElem->put_outerHTML(bstrPaste);
  3025. else
  3026. hr = pElem->put_outerText(bstrPaste);
  3027. pElem->Release();
  3028. }
  3029. return hr;
  3030. }
  3031. //+---------------------------------------------------------------
  3032. //
  3033. // Member: SelectElement
  3034. //
  3035. // Synopsis:
  3036. //
  3037. //---------------------------------------------------------------
  3038. HRESULT CBody::SelectElement(IHTMLElement *pElem, BOOL fScrollIntoView)
  3039. {
  3040. IHTMLTxtRange *pRange;
  3041. HRESULT hr;
  3042. VARIANT v;
  3043. TraceCall("CBody::SelectElement");
  3044. if (pElem == NULL)
  3045. return TraceResult(E_INVALIDARG);
  3046. if (!FAILED(hr=CreateRangeFromElement(pElem, &pRange)))
  3047. {
  3048. pRange->collapse(VARIANT_TRUE);
  3049. pRange->select();
  3050. if (fScrollIntoView)
  3051. pRange->scrollIntoView(VARIANT_TRUE);
  3052. pRange->Release();
  3053. }
  3054. return hr;
  3055. }
  3056. //+---------------------------------------------------------------
  3057. //
  3058. // Member: CreateRangeFromElement
  3059. //
  3060. // Synopsis:
  3061. //
  3062. //---------------------------------------------------------------
  3063. HRESULT CBody::CreateRangeFromElement(IHTMLElement *pElem, IHTMLTxtRange **ppRange)
  3064. {
  3065. HRESULT hr;
  3066. IHTMLTxtRange *pRange;
  3067. TraceCall("CBody::CreateRangeFromElement");
  3068. Assert (pElem && ppRange);
  3069. if (!FAILED(hr = CreateRange(&pRange)))
  3070. {
  3071. if (!FAILED(hr = pRange->moveToElementText(pElem)))
  3072. {
  3073. *ppRange = pRange;
  3074. pRange->AddRef();
  3075. }
  3076. pRange->Release();
  3077. }
  3078. return hr;
  3079. }
  3080. //+---------------------------------------------------------------
  3081. //
  3082. // Member: HrCreateRange
  3083. //
  3084. // Synopsis:
  3085. //
  3086. //---------------------------------------------------------------
  3087. HRESULT CBody::CreateRange(IHTMLTxtRange **ppRange)
  3088. {
  3089. IHTMLBodyElement *pBodyElem=0;
  3090. HRESULT hr=E_FAIL;
  3091. TraceCall("CBody::HrCreateRange");
  3092. Assert (ppRange);
  3093. *ppRange = NULL;
  3094. if (!FAILED(GetBodyElement(&pBodyElem)))
  3095. {
  3096. pBodyElem->createTextRange(ppRange);
  3097. if (*ppRange)
  3098. hr = S_OK;
  3099. pBodyElem->Release();
  3100. }
  3101. return hr;
  3102. }
  3103. //+---------------------------------------------------------------
  3104. //
  3105. // Member: CBody::GetSelection
  3106. //
  3107. // Synopsis:
  3108. //
  3109. //---------------------------------------------------------------
  3110. HRESULT CBody::GetSelection(IHTMLTxtRange **ppRange)
  3111. {
  3112. IHTMLSelectionObject *pSel=0;
  3113. IHTMLTxtRange *pTxtRange=0;
  3114. IDispatch *pID=0;
  3115. HRESULT hr=E_FAIL;
  3116. TraceCall("CBody::GetSelection");
  3117. if (ppRange == NULL)
  3118. return TraceResult(E_INVALIDARG);
  3119. *ppRange = NULL;
  3120. if(m_pDoc)
  3121. {
  3122. m_pDoc->get_selection(&pSel);
  3123. if (pSel)
  3124. {
  3125. pSel->createRange(&pID);
  3126. if (pID)
  3127. {
  3128. hr = pID->QueryInterface(IID_IHTMLTxtRange, (LPVOID *)ppRange);
  3129. pID->Release();
  3130. }
  3131. pSel->Release();
  3132. }
  3133. }
  3134. return hr;
  3135. }
  3136. //+---------------------------------------------------------------
  3137. //
  3138. // Member: CBody::GetSelection
  3139. //
  3140. // Synopsis:
  3141. //
  3142. //---------------------------------------------------------------
  3143. HRESULT CBody::GetElement(LPCTSTR pszName, IHTMLElement **ppElem)
  3144. {
  3145. TraceCall("CBody::GetElement");
  3146. return ::HrGetElementImpl(m_pDoc, pszName, ppElem);
  3147. }
  3148. //+---------------------------------------------------------------
  3149. //
  3150. // Member: CBody::GetSelection
  3151. //
  3152. // Synopsis:
  3153. //
  3154. //---------------------------------------------------------------
  3155. HRESULT CBody::GetBodyElement(IHTMLBodyElement **ppBody)
  3156. {
  3157. TraceCall("CBody::GetBodyElement");
  3158. return ::HrGetBodyElement(m_pDoc, ppBody);
  3159. }
  3160. //+---------------------------------------------------------------
  3161. //
  3162. // Member: CBody::Print
  3163. //
  3164. // Synopsis:
  3165. //
  3166. //---------------------------------------------------------------
  3167. HRESULT CBody::Print(BOOL fPrompt, VARIANTARG *pvaIn)
  3168. {
  3169. VARIANTARG va;
  3170. SAFEARRAY *psa = NULL;
  3171. SAFEARRAYBOUND rgsaBound[1];
  3172. LONG l;
  3173. BSTR bstrFooter = NULL,
  3174. bstrHeader = NULL,
  3175. bstrUrl = NULL;
  3176. HRESULT hr;
  3177. VARIANT v;
  3178. LPSTREAM pstm = NULL;
  3179. BOOL fMHtml = FALSE;
  3180. HBODY hBody;
  3181. WCHAR wsz[CCHMAX_STRINGRES];
  3182. LPWSTR pwszUser = NULL;
  3183. TraceCall("CBody::Print");
  3184. if (m_pCmdTarget==NULL)
  3185. return TraceResult(E_UNEXPECTED);
  3186. // if we're printing an MHTML message, print by URL so that cid:'s print
  3187. // NB: this is a loss of fidelity.
  3188. if (m_pMsg)
  3189. fMHtml = (MimeOleGetRelatedSection(m_pMsg, FALSE, &hBody, NULL)==S_OK) && m_pszUrlW;
  3190. rgsaBound[0].lLbound = 0;
  3191. rgsaBound[0].cElements = fMHtml ? 4 : 3;
  3192. IF_NULLEXIT(psa = SafeArrayCreate(VT_VARIANT, 1, rgsaBound));
  3193. va.vt = VT_ARRAY|VT_BYREF;
  3194. va.parray = psa;
  3195. *wsz = 0;
  3196. SideAssert(LoadStringWrapW(g_hLocRes, idsPrintHeader, wsz, ARRAYSIZE(wsz)));
  3197. IF_NULLEXIT(bstrHeader = SysAllocString(wsz));
  3198. v.vt = VT_BSTR;
  3199. v.bstrVal = bstrHeader;
  3200. // don't show the <TITLE> tag on the header
  3201. l=0;
  3202. IF_FAILEXIT(hr = SafeArrayPutElement(psa, &l, &v));
  3203. *wsz = 0;
  3204. SideAssert(LoadStringWrapW(g_hLocRes, idsPrintFooter, wsz, ARRAYSIZE(wsz)));
  3205. // we want footer to have only date, not URL.
  3206. IF_NULLEXIT(bstrFooter = SysAllocString(wsz));
  3207. v.vt = VT_BSTR;
  3208. v.bstrVal = bstrFooter;
  3209. // FOOTER
  3210. l=1;
  3211. IF_FAILEXIT(hr = SafeArrayPutElement(psa, &l, &v));
  3212. if (m_pMsg)
  3213. {
  3214. if (pvaIn && pvaIn->vt == VT_BSTR)
  3215. pwszUser = pvaIn->bstrVal;
  3216. IF_FAILEXIT(hr = GetHeaderTable(m_pMsgW, pwszUser, HDR_TABLE, &pstm));
  3217. HrRewindStream(pstm);
  3218. // ISTREAM containing table
  3219. v.vt = VT_UNKNOWN;
  3220. v.punkVal = (LPUNKNOWN)pstm;
  3221. l=2;
  3222. IF_FAILEXIT(hr = SafeArrayPutElement(psa, &l, &v));
  3223. if (fMHtml)
  3224. {
  3225. bstrUrl = SysAllocString(m_pszUrlW);
  3226. v.vt = VT_BSTR;
  3227. v.bstrVal = bstrUrl;
  3228. l=3;
  3229. IF_FAILEXIT(hr = SafeArrayPutElement(psa, &l, &v));
  3230. }
  3231. }
  3232. hr = m_pCmdTarget->Exec(NULL, OLECMDID_PRINT,
  3233. (fPrompt)?(OLECMDEXECOPT_PROMPTUSER):(OLECMDEXECOPT_DONTPROMPTUSER), &va, NULL);
  3234. IF_FAILEXIT(hr);
  3235. exit:
  3236. SysFreeString(bstrFooter);
  3237. SysFreeString(bstrHeader);
  3238. SysFreeString(bstrUrl);
  3239. if (psa)
  3240. SafeArrayDestroy(psa);
  3241. ReleaseObj(pstm);
  3242. return hr;
  3243. }
  3244. //+---------------------------------------------------------------
  3245. //
  3246. // Member: CBody::OnWMCommand
  3247. //
  3248. // Synopsis:
  3249. //
  3250. //---------------------------------------------------------------
  3251. HRESULT CBody::OnWMCommand(HWND hwnd, int id, WORD wCmd)
  3252. {
  3253. DWORD nCmdId=0,
  3254. nCmdIdTrident=0,
  3255. nCmdIdOESecure=0;
  3256. POINT pt;
  3257. VARIANTARG va;
  3258. VARIANTARG *pvaIn=0,
  3259. *pvaOut=0;
  3260. TraceCall("CBody::OnWMCommand");
  3261. if (m_pSrcView &&
  3262. m_pSrcView->OnWMCommand(hwnd, id, wCmd)==S_OK)
  3263. return S_OK;
  3264. if (m_pFmtBar &&
  3265. m_pFmtBar->OnWMCommand(hwnd, id, wCmd)==S_OK)
  3266. return S_OK;
  3267. if (!m_pCmdTarget)
  3268. return S_FALSE;
  3269. switch (id)
  3270. {
  3271. case idmPaneEncryption:
  3272. case idmPaneBadEncryption:
  3273. if (PointFromButton(id, &pt)==S_OK)
  3274. {
  3275. va.vt = VT_BYREF;
  3276. va.byref = &pt;
  3277. pvaIn = &va;
  3278. nCmdIdOESecure = OECSECCMD_ENCRYPTED;
  3279. }
  3280. break;
  3281. case idmPaneBadSigning:
  3282. case idmPaneSigning:
  3283. if (PointFromButton(id, &pt)==S_OK)
  3284. {
  3285. va.vt = VT_BYREF;
  3286. va.byref = &pt;
  3287. pvaIn = &va;
  3288. nCmdIdOESecure = OECSECCMD_SIGNED;
  3289. }
  3290. break;
  3291. case idmPaneVCard:
  3292. if (m_pAttMenu)
  3293. m_pAttMenu->LaunchVCard(m_hwnd);
  3294. break;
  3295. #ifdef FOLLOW_LINK
  3296. case idmOpenLink:
  3297. nCmdIdTrident = IDM_FOLLOWLINKN;
  3298. break;
  3299. #endif
  3300. case idmCopy:
  3301. nCmdId = OLECMDID_COPY;
  3302. break;
  3303. case idmSaveTargetAs:
  3304. nCmdIdTrident = IDM_SAVETARGET;
  3305. break;
  3306. case idmCopyShortcut:
  3307. nCmdIdTrident = IDM_COPYSHORTCUT;
  3308. break;
  3309. case idmCut:
  3310. nCmdId = OLECMDID_CUT;
  3311. break;
  3312. case idmPaste:
  3313. nCmdId = OLECMDID_PASTE;
  3314. break;
  3315. case idmSelectAll:
  3316. nCmdId = OLECMDID_SELECTALL;
  3317. break;
  3318. case idmUndo:
  3319. nCmdId = OLECMDID_UNDO;
  3320. break;
  3321. case idmRedo:
  3322. nCmdId = OLECMDID_REDO;
  3323. break;
  3324. case idmAddToFavorites:
  3325. AddToFavorites();
  3326. return S_OK;
  3327. case idmAddToWAB:
  3328. AddToWab();
  3329. return S_OK;
  3330. case idmSaveBackground:
  3331. nCmdIdTrident = IDM_SAVEBACKGROUND;
  3332. break;
  3333. case idmSavePicture:
  3334. _OnSaveImage();
  3335. break;
  3336. case idmFmtLeft:
  3337. nCmdIdTrident = IDM_JUSTIFYLEFT;
  3338. break;
  3339. case idmFmtCenter:
  3340. nCmdIdTrident = IDM_JUSTIFYCENTER;
  3341. break;
  3342. case idmFmtRight:
  3343. nCmdIdTrident = IDM_JUSTIFYRIGHT;
  3344. break;
  3345. case idmFmtNumbers:
  3346. nCmdIdTrident = IDM_ORDERLIST;
  3347. break;
  3348. case idmFmtBullets:
  3349. nCmdIdTrident = IDM_UNORDERLIST;
  3350. break;
  3351. case idmFmtBlockDirLTR:
  3352. nCmdIdTrident = IDM_BLOCKDIRLTR;
  3353. break;
  3354. case idmFmtBlockDirRTL:
  3355. nCmdIdTrident = IDM_BLOCKDIRRTL;
  3356. break;
  3357. case idmFmtFontDlg:
  3358. return FormatFont();
  3359. case idmFmtParagraphDlg:
  3360. return HrFormatParagraph();
  3361. case idmProperties:
  3362. nCmdIdTrident = DwChooseProperties();
  3363. if (nCmdIdTrident==0)
  3364. {
  3365. return DoHostProperties();
  3366. }
  3367. break;
  3368. }
  3369. if(nCmdId)
  3370. {
  3371. m_pCmdTarget->Exec(NULL, nCmdId, OLECMDEXECOPT_DODEFAULT, pvaIn, pvaOut);
  3372. return S_OK;
  3373. }
  3374. if(nCmdIdTrident)
  3375. {
  3376. m_pCmdTarget->Exec(&CMDSETID_Forms3, nCmdIdTrident, OLECMDEXECOPT_DODEFAULT, pvaIn, pvaOut);
  3377. return S_OK;
  3378. }
  3379. if (nCmdIdOESecure && m_pParentCmdTarget)
  3380. {
  3381. // delegate security commands to the host
  3382. m_pParentCmdTarget->Exec(&CMDSETID_OESecurity, nCmdIdOESecure, OLECMDEXECOPT_DODEFAULT, pvaIn, pvaOut);
  3383. return S_OK;
  3384. }
  3385. return S_FALSE;
  3386. }
  3387. //+---------------------------------------------------------------
  3388. //
  3389. // Member: CBody::UpdateContextMenu
  3390. //
  3391. // Synopsis:
  3392. //
  3393. //---------------------------------------------------------------
  3394. HRESULT CBody::UpdateContextMenu(HMENU hmenuEdit, BOOL fEnableProperties, IDispatch *pDisp)
  3395. {
  3396. OLECMD rgTridentCmds[]= {{IDM_FIND, 0},
  3397. {IDM_SAVEBACKGROUND, 0},
  3398. {IDM_COPYSHORTCUT, 0},
  3399. {IDM_SAVETARGET, 0}};
  3400. OLECMD rgStdCmds[]= {{OLECMDID_CUT, 0},
  3401. {OLECMDID_COPY, 0},
  3402. {OLECMDID_PASTE, 0},
  3403. {OLECMDID_SELECTALL, 0},
  3404. {OLECMDID_UNDO, 0},
  3405. {OLECMDID_REDO, 0}};
  3406. int rgidsStd[]= {idmCut,
  3407. idmCopy,
  3408. idmPaste,
  3409. idmSelectAll,
  3410. idmUndo,
  3411. idmRedo};
  3412. int rgidsTrident[]= {idmFindText,
  3413. idmSaveBackground,
  3414. idmCopyShortcut,
  3415. idmSaveTargetAs};
  3416. OLECMD rgFmtCmds[]= {{IDM_INDENT, 0}, // careful about ordering!!
  3417. {IDM_OUTDENT, 0},
  3418. {IDM_FONT, 0}};
  3419. int rgFmtidm[] = {idmFmtIncreaseIndent, // careful about ordering!!
  3420. idmFmtDecreaseIndent,
  3421. idmFmtFontDlg};
  3422. OLECMD rgHostCmds[]= {{OLECMDID_PROPERTIES, 0}};
  3423. int rgHostidm[]= {idmProperties};
  3424. UINT ustate;
  3425. int i,
  3426. id;
  3427. BSTR bstrHref=NULL;
  3428. BOOL fBadLink = FALSE;
  3429. IHTMLAnchorElement *pAE;
  3430. TraceCall("CBody::UpdateContextMenu");
  3431. if (!m_pCmdTarget || !hmenuEdit)
  3432. return E_INVALIDARG;
  3433. if (pDisp &&
  3434. pDisp->QueryInterface(IID_IHTMLAnchorElement, (LPVOID *)&pAE)==S_OK)
  3435. {
  3436. pAE->get_href(&bstrHref);
  3437. if (bstrHref &&
  3438. StrCmpNIW(bstrHref, c_szOECmdW, ARRAYSIZE(c_szOECmdW)-sizeof(WCHAR))==0)
  3439. fBadLink = TRUE;
  3440. pAE->Release();
  3441. }
  3442. m_pCmdTarget->QueryStatus(NULL, sizeof(rgStdCmds)/sizeof(OLECMD), rgStdCmds, NULL);
  3443. for (i=0; i<sizeof(rgStdCmds)/sizeof(OLECMD); i++)
  3444. SetMenuItem(hmenuEdit, rgidsStd[i], rgStdCmds[i].cmdf & OLECMDF_ENABLED);
  3445. m_pCmdTarget->QueryStatus(&CMDSETID_Forms3, sizeof(rgTridentCmds)/sizeof(OLECMD), rgTridentCmds, NULL);
  3446. for (i=0; i<sizeof(rgTridentCmds)/sizeof(OLECMD); i++)
  3447. {
  3448. ustate = rgTridentCmds[i].cmdf & OLECMDF_ENABLED;
  3449. if (rgidsTrident[i] == idmSaveTargetAs || rgidsTrident[i] == idmCopyShortcut)
  3450. ustate = ustate && !fBadLink;
  3451. SetMenuItem(hmenuEdit, rgidsTrident[i], ustate);
  3452. }
  3453. // set the formatting commands. The are only available when we have focus and we are editing an HTML document
  3454. if (m_fFocus && !m_fPlainMode)
  3455. m_pCmdTarget->QueryStatus(&CMDSETID_Forms3, sizeof(rgFmtCmds)/sizeof(OLECMD), rgFmtCmds, NULL);
  3456. ustate = !m_fPlainMode ? MF_ENABLED : (MF_DISABLED|MF_GRAYED);
  3457. EnableMenuItem(hmenuEdit, idmFmtParagraphDlg, ustate);
  3458. for(i=0; i<sizeof(rgFmtCmds)/sizeof(OLECMD); i++)
  3459. {
  3460. ustate = (rgFmtCmds[i].cmdf&OLECMDF_ENABLED ? MF_ENABLED: MF_DISABLED|MF_GRAYED) | MF_BYCOMMAND;
  3461. EnableMenuItem(hmenuEdit, rgFmtidm[i], ustate);
  3462. ustate = (rgFmtCmds[i].cmdf&OLECMDF_LATCHED?MF_CHECKED:MF_UNCHECKED) | MF_BYCOMMAND;
  3463. CheckMenuItem(hmenuEdit, rgFmtidm[i], ustate);
  3464. }
  3465. if (m_pParentCmdTarget)
  3466. m_pParentCmdTarget->QueryStatus(NULL, sizeof(rgHostCmds)/sizeof(OLECMD), rgHostCmds, NULL);
  3467. // if we are handling idmProperties then override the host state
  3468. if (fEnableProperties)
  3469. rgHostCmds[0].cmdf = OLECMDF_ENABLED;
  3470. for(i=0; i<sizeof(rgHostCmds)/sizeof(OLECMD); i++)
  3471. SetMenuItem(hmenuEdit, rgHostidm[i], rgHostCmds[i].cmdf & OLECMDF_ENABLED);
  3472. SysFreeString(bstrHref);
  3473. return S_OK;
  3474. }
  3475. //+---------------------------------------------------------------
  3476. //
  3477. // Member: CBody::AppendAnchorItems
  3478. //
  3479. // Synopsis:
  3480. //
  3481. //---------------------------------------------------------------
  3482. HRESULT CBody::AppendAnchorItems(HMENU hMenu, IDispatch *pDisp)
  3483. {
  3484. BSTR bstr=0;
  3485. TCHAR rgch[CCHMAX_STRINGRES];
  3486. HRESULT hr=S_OK;
  3487. IHTMLAnchorElement *pAE;
  3488. OLECMD rgHostCmds[]={ {MEHOSTCMDID_ADD_TO_ADDRESSBOOK, 0},
  3489. {MEHOSTCMDID_ADD_TO_FAVORITES, 0}};
  3490. TraceCall("CBody::AppendAnchorItems");
  3491. if (!pDisp)
  3492. return S_OK;
  3493. // if no parent cmdtarget, can't do these verbs anyway
  3494. if (m_pParentCmdTarget &&
  3495. m_pParentCmdTarget->QueryStatus(&CMDSETID_MimeEditHost, sizeof(rgHostCmds)/sizeof(OLECMD), rgHostCmds, NULL)==S_OK)
  3496. {
  3497. if (pDisp->QueryInterface(IID_IHTMLAnchorElement, (LPVOID *)&pAE)==S_OK)
  3498. {
  3499. hr = pAE->get_href(&bstr);
  3500. pAE->Release();
  3501. }
  3502. if (bstr)
  3503. {
  3504. *rgch = 0;
  3505. // If "mailto:" is in bstr then add it to wab; If "http:" is in bstr, add it to favorites
  3506. if (rgHostCmds[0].cmdf & OLECMDF_ENABLED &&
  3507. StrCmpNIW(bstr, c_szMailToW, ARRAYSIZE(c_szMailToW)-sizeof(WCHAR))==0)
  3508. {
  3509. SideAssert(LoadString(g_hLocRes, idsAddToWAB, rgch, sizeof(rgch)/sizeof(TCHAR)));
  3510. AppendMenu(hMenu, MF_SEPARATOR, 0, 0);
  3511. AppendMenu(hMenu, MF_STRING, idmAddToWAB, rgch);
  3512. RemoveMenu(hMenu, idmSaveTargetAs, MF_BYCOMMAND); // no point on a mailto: url
  3513. }
  3514. else if (rgHostCmds[1].cmdf & OLECMDF_ENABLED &&
  3515. (StrCmpNIW(bstr, c_szHttpW, ARRAYSIZE(c_szHttpW)-sizeof(WCHAR))==0 ||
  3516. StrCmpNIW(bstr, c_szFileW, ARRAYSIZE(c_szFileW)-sizeof(WCHAR))==0 ))
  3517. {
  3518. SideAssert(LoadString(g_hLocRes, idsAddToFavorites, rgch, sizeof(rgch)/sizeof(TCHAR)));
  3519. AppendMenu(hMenu, MF_SEPARATOR, 0, 0);
  3520. AppendMenu(hMenu, MF_STRING, idmAddToFavorites, rgch);
  3521. }
  3522. SysFreeString(bstr);
  3523. }
  3524. }
  3525. return hr;
  3526. }
  3527. //+---------------------------------------------------------------
  3528. //
  3529. // Member: CBody::GetSelectedAnchor
  3530. //
  3531. // Synopsis:
  3532. //
  3533. //---------------------------------------------------------------
  3534. HRESULT CBody::GetSelectedAnchor(BSTR* pbstr)
  3535. {
  3536. HRESULT hr;
  3537. IHTMLTxtRange *pTxtRange;
  3538. IHTMLAnchorElement *pAE;
  3539. IHTMLElement *pElemParent;
  3540. TraceCall("CBody::GetSelectedAnchor");
  3541. if (pbstr)
  3542. *pbstr=NULL;
  3543. hr = GetSelection(&pTxtRange);
  3544. if (!FAILED(hr))
  3545. {
  3546. hr = pTxtRange->parentElement(&pElemParent);
  3547. if (!FAILED(hr))
  3548. {
  3549. hr = pElemParent->QueryInterface(IID_IHTMLAnchorElement, (LPVOID *)&pAE);
  3550. if (!FAILED(hr))
  3551. {
  3552. if (pbstr)
  3553. hr = pAE->get_href(pbstr);
  3554. pAE->Release();
  3555. }
  3556. pElemParent->Release();
  3557. }
  3558. pTxtRange->Release();
  3559. }
  3560. return hr;
  3561. }
  3562. //+---------------------------------------------------------------
  3563. //
  3564. // Member: CBody::AddToWab
  3565. //
  3566. // Synopsis:
  3567. //
  3568. //---------------------------------------------------------------
  3569. HRESULT CBody::AddToWab()
  3570. {
  3571. BSTR bstr=0,
  3572. bstrOut;
  3573. HRESULT hr=E_FAIL;
  3574. WCHAR *pszW;
  3575. VARIANTARG va;
  3576. IHTMLAnchorElement *pAE;
  3577. TraceCall("CBody::AddToWab");
  3578. if (!m_pParentCmdTarget)
  3579. return TraceResult(E_UNEXPECTED);
  3580. if (m_pDispContext &&
  3581. m_pDispContext->QueryInterface(IID_IHTMLAnchorElement, (LPVOID *)&pAE)==S_OK)
  3582. {
  3583. pAE->get_href(&bstr);
  3584. pAE->Release();
  3585. }
  3586. if (bstr)
  3587. {
  3588. // double check this is a mailto:
  3589. if (StrCmpNIW(bstr, c_szMailToW, ARRAYSIZE(c_szMailToW)-sizeof(WCHAR))==0)
  3590. {
  3591. pszW = bstr + (ARRAYSIZE(c_szMailToW)-1);
  3592. bstrOut = SysAllocString(pszW);
  3593. if (bstrOut)
  3594. {
  3595. va.vt = VT_BSTR;
  3596. va.bstrVal = bstrOut;
  3597. hr = m_pParentCmdTarget->Exec(&CMDSETID_MimeEditHost, MEHOSTCMDID_ADD_TO_ADDRESSBOOK, OLECMDEXECOPT_DODEFAULT, &va, NULL);
  3598. SysFreeString(bstrOut);
  3599. }
  3600. else
  3601. hr = TraceResult(E_OUTOFMEMORY);
  3602. }
  3603. SysFreeString(bstr);
  3604. }
  3605. return hr;
  3606. }
  3607. //+---------------------------------------------------------------
  3608. //
  3609. // Member: CBody::AddToFavorites
  3610. //
  3611. // Synopsis:
  3612. //
  3613. //---------------------------------------------------------------
  3614. HRESULT CBody::AddToFavorites()
  3615. {
  3616. SAFEARRAY *psa=NULL;
  3617. SAFEARRAYBOUND rgsaBound[1];
  3618. BSTR bstrURL=NULL,
  3619. bstrDescr=NULL;
  3620. HRESULT hr=E_FAIL;
  3621. VARIANTARG va;
  3622. IHTMLAnchorElement *pAE=NULL;
  3623. IHTMLElement *pE=NULL;
  3624. LONG l;
  3625. TraceCall("CBody::AddToFavorites");
  3626. if (!m_pParentCmdTarget)
  3627. return TraceResult(E_UNEXPECTED);
  3628. if (m_pDispContext &&
  3629. m_pDispContext->QueryInterface(IID_IHTMLElement, (LPVOID *)&pE)==S_OK)
  3630. {
  3631. pE->get_innerText(&bstrDescr);
  3632. pE->Release();
  3633. }
  3634. if (m_pDispContext &&
  3635. m_pDispContext->QueryInterface(IID_IHTMLAnchorElement, (LPVOID *)&pAE)==S_OK)
  3636. {
  3637. pAE->get_href(&bstrURL);
  3638. pAE->Release();
  3639. }
  3640. if (bstrURL)
  3641. {
  3642. if(!bstrDescr)
  3643. bstrDescr=SysAllocString(bstrURL);
  3644. rgsaBound[0].lLbound = 0;
  3645. rgsaBound[0].cElements = 2;
  3646. IF_NULLEXIT(psa = SafeArrayCreate(VT_BSTR, 1, rgsaBound));
  3647. va.vt = VT_ARRAY|VT_BSTR;
  3648. va.parray = psa;
  3649. l=0;
  3650. IF_FAILEXIT(hr = SafeArrayPutElement(psa, &l, bstrDescr));
  3651. l=1;
  3652. IF_FAILEXIT(hr = SafeArrayPutElement(psa, &l, bstrURL));
  3653. IF_FAILEXIT(hr = m_pParentCmdTarget->Exec(&CMDSETID_MimeEditHost, MEHOSTCMDID_ADD_TO_FAVORITES, OLECMDEXECOPT_DODEFAULT, &va, NULL));
  3654. }
  3655. exit:
  3656. SysFreeString(bstrDescr);
  3657. SysFreeString(bstrURL);
  3658. if(psa)
  3659. SafeArrayDestroy(psa);
  3660. return hr;
  3661. }
  3662. //+---------------------------------------------------------------
  3663. //
  3664. // Member: CBody::GetWebPageOptions
  3665. //
  3666. // Synopsis:
  3667. //
  3668. //---------------------------------------------------------------
  3669. HRESULT CBody::GetWebPageOptions(WEBPAGEOPTIONS *pOptions, BOOL *pfIncludeMsg)
  3670. {
  3671. VARIANTARG va;
  3672. DWORD dwFlags;
  3673. TraceCall("GetWebPageOptions");
  3674. // set defaults for IN params
  3675. pOptions->cbSize = sizeof(WEBPAGEOPTIONS);
  3676. pOptions->dwFlags = WPF_HTML|WPF_AUTOINLINE;
  3677. pOptions->dwDelay = 5000;
  3678. pOptions->wchQuote = NULL;
  3679. if (pfIncludeMsg)
  3680. *pfIncludeMsg=TRUE;
  3681. // callback to Host for real options
  3682. if (m_pParentCmdTarget)
  3683. {
  3684. if (GetHostFlags(&dwFlags)==S_OK)
  3685. {
  3686. BOOL fSecurityForcesHTMLOff = FALSE;
  3687. VARIANTARG va = {0};
  3688. va.vt = VT_BOOL;
  3689. va.boolVal = VARIANT_FALSE;
  3690. // read msgs all have the autoinline flag set so we use that along with the option setting to determine
  3691. // if html should be disabled
  3692. if (SUCCEEDED(m_pParentCmdTarget->Exec(&CMDSETID_MimeEditHost, MEHOSTCMDID_IS_READ_IN_TEXT_ONLY, OLECMDEXECOPT_DODEFAULT, NULL, &va)))
  3693. fSecurityForcesHTMLOff = (VARIANT_TRUE == va.boolVal) && (dwFlags & MEO_FLAGS_AUTOINLINE);
  3694. // convert MEHOST_* flags to WPF_*
  3695. pOptions->dwFlags = 0;
  3696. if (!fSecurityForcesHTMLOff && (dwFlags & MEO_FLAGS_HTML))
  3697. pOptions->dwFlags |= WPF_HTML;
  3698. if (dwFlags & MEO_FLAGS_AUTOINLINE)
  3699. pOptions->dwFlags |= WPF_AUTOINLINE;
  3700. if (dwFlags & MEO_FLAGS_SLIDESHOW)
  3701. pOptions->dwFlags |= WPF_SLIDESHOW;
  3702. if ((!(dwFlags & MEO_FLAGS_INCLUDEMSG)) && pfIncludeMsg)
  3703. *pfIncludeMsg = FALSE;
  3704. }
  3705. if (m_pParentCmdTarget->Exec(&CMDSETID_MimeEditHost, MEHOSTCMDID_QUOTE_CHAR, OLECMDEXECOPT_DODEFAULT, NULL, &va)==S_OK)
  3706. pOptions->wchQuote = (WCHAR)va.lVal;
  3707. if (m_pParentCmdTarget->Exec(&CMDSETID_MimeEditHost, MEHOSTCMDID_SLIDESHOW_DELAY, OLECMDEXECOPT_DODEFAULT, NULL, &va)==S_OK)
  3708. pOptions->dwDelay = (WCHAR)va.lVal;
  3709. }
  3710. return S_OK;
  3711. }
  3712. //+---------------------------------------------------------------
  3713. //
  3714. // Member: ViewSource
  3715. //
  3716. // Synopsis:
  3717. //
  3718. //---------------------------------------------------------------
  3719. HRESULT CBody::ViewSource(BOOL fMessage)
  3720. {
  3721. TraceCall("CBody::ViewSource");
  3722. if (fMessage)
  3723. MimeEditViewSource(m_hwnd, m_pMsg);
  3724. else
  3725. {
  3726. if (m_pCmdTarget)
  3727. m_pCmdTarget->Exec(&CMDSETID_Forms3, IDM_VIEWSOURCE, OLECMDEXECOPT_DODEFAULT, NULL, NULL);
  3728. }
  3729. return S_OK;
  3730. }
  3731. //+---------------------------------------------------------------
  3732. //
  3733. // Member: OnUIDeactivate
  3734. //
  3735. // Synopsis:
  3736. //
  3737. //---------------------------------------------------------------
  3738. HRESULT CBody::OnUIDeactivate(BOOL fUndoable)
  3739. {
  3740. HRESULT hr;
  3741. TraceCall("CBody::OnUIDeactivate");
  3742. hr = CDocHost::OnUIDeactivate(fUndoable);;
  3743. if (m_pParentInPlaceSite)
  3744. m_pParentInPlaceSite->OnUIDeactivate(fUndoable);
  3745. if (m_pParentInPlaceFrame)
  3746. m_pParentInPlaceFrame->SetActiveObject(NULL, NULL);
  3747. if (m_pFmtBar)
  3748. m_pFmtBar->Update();
  3749. return hr;
  3750. }
  3751. //+---------------------------------------------------------------
  3752. //
  3753. // Member: OnUIActivate
  3754. //
  3755. // Synopsis:
  3756. //
  3757. //---------------------------------------------------------------
  3758. HRESULT CBody::OnUIActivate()
  3759. {
  3760. HRESULT hr;
  3761. TraceCall("CBody::OnUIActivate");
  3762. hr = CDocHost::OnUIActivate();
  3763. if (m_pParentInPlaceSite)
  3764. m_pParentInPlaceSite->OnUIActivate();
  3765. if (m_pParentInPlaceFrame)
  3766. m_pParentInPlaceFrame->SetActiveObject(m_pDocActiveObj, NULL);
  3767. if (m_pFmtBar)
  3768. m_pFmtBar->Update();
  3769. return hr;
  3770. }
  3771. //+---------------------------------------------------------------
  3772. //
  3773. // Member: SetStatusText
  3774. //
  3775. // Synopsis:
  3776. //
  3777. //---------------------------------------------------------------
  3778. HRESULT CBody::SetStatusText(LPCOLESTR pszW)
  3779. {
  3780. LPWSTR pszTempW;
  3781. TraceCall("CDocHost::SetStatusText");
  3782. // bug #2137. This is a nasty hack. If we get a statusbar update
  3783. // with mid://xxx#bookmark then we tear off the mid://xxx portion
  3784. // to show the name more cleanly.
  3785. // the right fix is for trident to add handling for displaying urls to
  3786. // call IInternetInfo::ParseUrl with PARSE_URL_FRIENDLY
  3787. if (pszW &&
  3788. StrCmpNIW(pszW, L"mid:", 4) == 0 &&
  3789. (pszTempW = StrPBrkW(pszW, L"#")))
  3790. pszW = pszTempW;
  3791. if (m_pParentInPlaceFrame)
  3792. m_pParentInPlaceFrame->SetStatusText(pszW);
  3793. return CDocHost::SetStatusText(pszW);;
  3794. }
  3795. //+---------------------------------------------------------------
  3796. //
  3797. // Member: DoRot13
  3798. //
  3799. // Synopsis:
  3800. //
  3801. //---------------------------------------------------------------
  3802. HRESULT CBody::DoRot13()
  3803. {
  3804. IHTMLTxtRange *pTxtRange;
  3805. HRESULT hr;
  3806. BSTR bstr;
  3807. LPWSTR lpszW;
  3808. ULONG cb;
  3809. hr = CreateRange(&pTxtRange);
  3810. if (!FAILED(hr))
  3811. {
  3812. hr=pTxtRange->get_text(&bstr);
  3813. if (!FAILED(hr))
  3814. {
  3815. cb=SysStringLen(bstr);
  3816. while(cb--)
  3817. {
  3818. register WCHAR chW;
  3819. chW=bstr[cb];
  3820. if (chW >= 'a' && chW <= 'z')
  3821. bstr[cb] = 'a' + (((chW - 'a') + 13) % 26);
  3822. else if (chW >= 'A' && chW <= 'Z')
  3823. bstr[cb] = 'A' + (((chW - 'A') + 13) % 26);
  3824. }
  3825. hr=pTxtRange->put_text(bstr);
  3826. SysFreeString(bstr);
  3827. }
  3828. pTxtRange->Release();
  3829. }
  3830. return hr;
  3831. }
  3832. void CBody::OutputHeaderText(HDC hdc, LPWSTR psz, int *pcxPos, int cyPos, int cxMax, ULONG uFlags)
  3833. {
  3834. static int yLabel = 0;
  3835. int cch,
  3836. cyOffset = 0;
  3837. SIZE size;
  3838. RECT rc;
  3839. WCHAR szRes[CCHMAX_STRINGRES];
  3840. HFONT hFont;
  3841. if (IS_INTRESOURCE(psz))
  3842. {
  3843. LoadStringWrapW(g_hLocRes, PtrToUlong(psz), szRes, ARRAYSIZE(szRes));
  3844. psz = szRes;
  3845. }
  3846. cch = lstrlenW(psz);
  3847. if (m_pFontCache &&
  3848. m_pFontCache->GetFont((uFlags & HDRTXT_BOLD)?FNT_SYS_ICON_BOLD:FNT_SYS_ICON, (uFlags & HDRTXT_SYSTEMFONT )? NULL : m_hCharset, &hFont)==S_OK)
  3849. SelectObject(hdc, hFont);
  3850. GetTextExtentPoint32AthW(hdc, psz, cch, &size, DT_NOPREFIX);
  3851. // bobn: Raid 84705 We need to make sure that the fields line up
  3852. if(yLabel && !(uFlags & (HDRTXT_BOLD|HDRTXT_SYSTEMFONT)))
  3853. {
  3854. cyOffset = yLabel - size.cy;
  3855. }
  3856. rc.top = cyPos + ((cyOffset < (-2))? (-2) : cyOffset); // bobn: Raid 84705 We need to make sure that the fields line up
  3857. rc.left = *pcxPos;
  3858. rc.right = min(*pcxPos + size.cx + 1, cxMax);
  3859. rc.bottom = cyPos + size.cy + cyOffset; // bobn: Raid 84705 We need to make sure that the fields line up
  3860. DrawTextExWrapW(hdc, psz, cch, &rc, DT_NOPREFIX | DT_WORD_ELLIPSIS, NULL);
  3861. *pcxPos=rc.right;
  3862. // bobn: Raid 84705 We need to make sure that the fields line up
  3863. if (uFlags & (HDRTXT_BOLD|HDRTXT_SYSTEMFONT))
  3864. {
  3865. yLabel = size.cy;
  3866. }
  3867. }
  3868. /*
  3869. * control strings:
  3870. * &s - Subject: &c - Cc:
  3871. * &t - To: &d - Date:
  3872. * &f - From:
  3873. *
  3874. */
  3875. HRESULT CBody::OnPaint()
  3876. {
  3877. HDC hdc,
  3878. hdcMem;
  3879. PAINTSTRUCT ps;
  3880. RECT rc,
  3881. rcBtnBar;
  3882. int idc;
  3883. SIZE sze;
  3884. HBITMAP hbmMem;
  3885. HGDIOBJ hbmOld;
  3886. int cx,
  3887. cxLabels,
  3888. cy,
  3889. cxPos,
  3890. cyPos,
  3891. cyLine;
  3892. int iBackColor,
  3893. iTextColor;
  3894. LPSTR pszFmt;
  3895. LPSTR psz,
  3896. pszLast;
  3897. HFONT hFont;
  3898. if (m_uHdrStyle == MESTYLE_PREVIEW ||
  3899. m_uHdrStyle == MESTYLE_MINIHEADER)
  3900. {
  3901. hdc=BeginPaint(m_hwnd, &ps);
  3902. hdcMem = CreateCompatibleDC(hdc);
  3903. idc=SaveDC(hdcMem);
  3904. // select font so cyLine is accurate
  3905. if (m_pFontCache &&
  3906. m_pFontCache->GetFont(FNT_SYS_ICON_BOLD, NULL, &hFont)==S_OK)
  3907. SelectObject(hdcMem, hFont);
  3908. GetClientRect(m_hwnd, &rc);
  3909. cx = rc.right;
  3910. cxLabels = cx - (GetSystemMetrics(SM_CXBORDER)*2); // account for client-edge
  3911. cy = lGetClientHeight();
  3912. if (m_cVisibleBtns)
  3913. {
  3914. // trim cx if buttons are shown
  3915. Assert(IsWindow(m_hwndBtnBar));
  3916. GetClientRect(m_hwndBtnBar, &rcBtnBar);
  3917. cxLabels -= rcBtnBar.right;
  3918. }
  3919. hbmMem = CreateCompatibleBitmap(hdc, cx, cy);
  3920. hbmOld = SelectObject(hdcMem, (HGDIOBJ)hbmMem);
  3921. if (m_fFocus)
  3922. {
  3923. iBackColor = COLOR_HEADERFOCUS;
  3924. iTextColor = COLOR_HEADERTXTFOCUS;
  3925. }
  3926. else
  3927. {
  3928. iBackColor = COLOR_HEADER;
  3929. iTextColor = COLOR_HEADERTXT;
  3930. }
  3931. FillRect(hdcMem, &rc, GetSysColorBrush(iBackColor));
  3932. cxPos = CX_LABEL_PADDING;
  3933. cyPos = CY_LINE_PADDING;
  3934. SetBkMode(hdcMem, OPAQUE);
  3935. SetBkColor(hdcMem, GetSysColor(iBackColor));
  3936. SetTextColor(hdcMem, GetSysColor (iTextColor));
  3937. cyLine = lGetLineHeight(hdcMem);
  3938. if (m_uHdrStyle == MESTYLE_PREVIEW)
  3939. {
  3940. // if we want the full preview header, let's render the text
  3941. pszFmt = m_pszLayout;
  3942. pszLast = pszFmt;
  3943. while (*pszFmt)
  3944. {
  3945. if (*pszFmt == '&')
  3946. {
  3947. // control character
  3948. pszFmt++;
  3949. switch (*pszFmt)
  3950. {
  3951. case 'f':
  3952. case 'F':
  3953. // from field
  3954. if (*pszFmt=='f' || (m_pszFrom&& *m_pszFrom))
  3955. {
  3956. OutputHeaderText(hdcMem, MAKEINTRESOURCEW(idsFromField), &cxPos, cyPos, cxLabels, HDRTXT_BOLD|HDRTXT_SYSTEMFONT);
  3957. cxPos+=CX_LABEL_PADDING;
  3958. }
  3959. if (m_pszFrom)
  3960. OutputHeaderText(hdcMem, m_pszFrom, &cxPos, cyPos, cxLabels, 0);
  3961. cxPos+=2*CX_LABEL_PADDING;
  3962. break;
  3963. case 's':
  3964. case 'S':
  3965. if (*pszFmt=='s' || (m_pszSubject && *m_pszSubject))
  3966. {
  3967. OutputHeaderText(hdcMem, MAKEINTRESOURCEW(idsSubjectField), &cxPos, cyPos, cxLabels, HDRTXT_BOLD|HDRTXT_SYSTEMFONT);
  3968. cxPos+=CX_LABEL_PADDING;
  3969. }
  3970. if (m_pszSubject)
  3971. OutputHeaderText(hdcMem, m_pszSubject, &cxPos, cyPos, cxLabels, 0);
  3972. cxPos+=2*CX_LABEL_PADDING;
  3973. break;
  3974. case 'c':
  3975. case 'C':
  3976. if (*pszFmt=='c' || (m_pszCc && *m_pszCc))
  3977. {
  3978. OutputHeaderText(hdcMem, MAKEINTRESOURCEW(idsCcField), &cxPos, cyPos, cxLabels, HDRTXT_BOLD|HDRTXT_SYSTEMFONT);
  3979. cxPos+=CX_LABEL_PADDING;
  3980. }
  3981. if (m_pszCc)
  3982. OutputHeaderText(hdcMem, m_pszCc, &cxPos, cyPos, cxLabels, 0);
  3983. cxPos+=2*CX_LABEL_PADDING;
  3984. break;
  3985. case 't':
  3986. case 'T':
  3987. if (*pszFmt=='t' || (m_pszTo && *m_pszTo))
  3988. {
  3989. OutputHeaderText(hdcMem, MAKEINTRESOURCEW(idsToField), &cxPos, cyPos, cxLabels, HDRTXT_BOLD|HDRTXT_SYSTEMFONT);
  3990. cxPos+=CX_LABEL_PADDING;
  3991. }
  3992. if (m_pszTo)
  3993. OutputHeaderText(hdcMem, m_pszTo, &cxPos, cyPos, cxLabels, 0);
  3994. cxPos+=2*CX_LABEL_PADDING;
  3995. break;
  3996. case 'b':
  3997. // &b is a line break
  3998. cxPos = CX_LABEL_PADDING;
  3999. cyPos += cyLine + 2; // bobn: Arbitrary pad so that we don't clip to the line below
  4000. break;
  4001. }
  4002. }
  4003. pszFmt++;
  4004. }
  4005. if (!m_fFocus)
  4006. {
  4007. // if we don't have focus, paint a 3d edge
  4008. rc.top = 0;
  4009. rc.left = 0;
  4010. rc.right = cx;
  4011. rc.bottom = m_cyPreview;
  4012. DrawEdge(hdcMem, &rc, BDR_RAISEDINNER, BF_RECT);
  4013. }
  4014. }
  4015. BitBlt(hdc, 0, 0, cx, cy, hdcMem, 0, 0, SRCCOPY);
  4016. if (!m_lpOleObj)
  4017. {
  4018. HBRUSH hBrush = SelectBrush(hdc, GetSysColorBrush(COLOR_WINDOW));
  4019. GetClientRect(m_hwnd, &rc);
  4020. GetDocObjSize(&rc);
  4021. PatBlt(hdc, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, PATCOPY);
  4022. SelectBrush(hdc, hBrush);
  4023. }
  4024. SelectObject(hdcMem, hbmOld);
  4025. RestoreDC(hdcMem, idc);
  4026. DeleteObject(hbmMem);
  4027. DeleteDC(hdcMem);
  4028. EndPaint(m_hwnd, &ps);
  4029. return S_OK;
  4030. }
  4031. else
  4032. if (!m_lpOleObj)
  4033. {
  4034. HDC hdc;
  4035. PAINTSTRUCT ps;
  4036. RECT rc;
  4037. HBRUSH hBrush;
  4038. GetClientRect(m_hwnd, &rc);
  4039. GetDocObjSize(&rc);
  4040. hdc = BeginPaint(m_hwnd, &ps);
  4041. if (m_dwStyle & MEBF_INNERCLIENTEDGE)
  4042. DrawEdge(hdc, &rc, EDGE_SUNKEN, BF_RECT|BF_ADJUST);
  4043. hBrush = SelectBrush(hdc, GetSysColorBrush(COLOR_WINDOW));
  4044. PatBlt(hdc, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, PATCOPY);
  4045. SelectBrush(hdc, hBrush);
  4046. EndPaint(m_hwnd, &ps);
  4047. return S_OK;
  4048. }
  4049. return S_FALSE;
  4050. }
  4051. LONG CBody::lGetLineHeight(HDC hdc)
  4052. {
  4053. HFONT hfontOld=0,
  4054. hFont;
  4055. TEXTMETRIC tm;
  4056. if (hdc)
  4057. GetTextMetrics(hdc, &tm);
  4058. else
  4059. {
  4060. // Calculate the height of the line: based on the height of the bold font
  4061. hdc=GetDC(NULL);
  4062. if (m_pFontCache &&
  4063. m_pFontCache->GetFont(FNT_SYS_ICON, NULL, &hFont)==S_OK)
  4064. hfontOld = (HFONT)SelectObject(hdc, hFont);
  4065. GetTextMetrics(hdc, &tm);
  4066. // Set things back
  4067. if (hfontOld)
  4068. SelectObject(hdc, hfontOld);
  4069. ReleaseDC(NULL, hdc);
  4070. }
  4071. return tm.tmHeight;
  4072. }
  4073. HRESULT CBody::RecalcPreivewHeight(HDC hdc)
  4074. {
  4075. ULONG cLines=1;
  4076. LPSTR psz;
  4077. RECT rc;
  4078. // default
  4079. if (!m_pszLayout)
  4080. m_pszLayout = PszDup("&f&t&C&b&s");
  4081. // cruise thro' the preview layout string and figure out how many line high we are and the
  4082. // physical pixel height of those lines in the current font
  4083. if (psz = m_pszLayout)
  4084. while (*psz)
  4085. {
  4086. if (*psz == '&' && *(psz+1) == 'b')
  4087. cLines++;
  4088. psz++;
  4089. }
  4090. m_cyPreview = cLines * lGetLineHeight(hdc);
  4091. m_cyPreview+=2*CY_LINE_PADDING; // padding
  4092. if (m_hwndBtnBar)
  4093. {
  4094. // if the button bar is show, account for it.
  4095. GetClientRect(m_hwndBtnBar, &rc);
  4096. rc.bottom+= (2*GetSystemMetrics(SM_CYBORDER)); // factor client edge
  4097. m_cyPreview = max (m_cyPreview, (ULONG)rc.bottom);
  4098. }
  4099. return S_OK;
  4100. }
  4101. HRESULT CBody::GetDocObjSize(LPRECT prc)
  4102. {
  4103. if(!prc)
  4104. return E_INVALIDARG;
  4105. if (m_uSrcView == MEST_EDIT)
  4106. prc->top+=lGetClientHeight();
  4107. if (m_fSrcTabs)
  4108. prc->top+=4;
  4109. if (m_fSrcTabs)
  4110. {
  4111. RECT rc={0};
  4112. Assert (m_hwndTab);
  4113. if (TabCtrl_GetItemRect(m_hwndTab, 0, &rc))
  4114. prc->bottom -= (rc.bottom - rc.top) + 2;
  4115. InflateRect(prc, -4, -4);
  4116. }
  4117. // make sure we don't make a nonsense rect.
  4118. if(prc->bottom<prc->top)
  4119. prc->bottom=prc->top;
  4120. return NOERROR;
  4121. }
  4122. HRESULT CBody::UpdatePreviewLabels()
  4123. {
  4124. HRESULT hr = S_OK;
  4125. SafeMemFree(m_pszSubject);
  4126. SafeMemFree(m_pszTo);
  4127. SafeMemFree(m_pszCc);
  4128. SafeMemFree(m_pszFrom);
  4129. if (m_pMsgW)
  4130. {
  4131. m_pMsgW->GetAddressFormatW(IAT_CC, AFT_DISPLAY_FRIENDLY, &m_pszCc);
  4132. m_pMsgW->GetAddressFormatW(IAT_FROM, AFT_DISPLAY_FRIENDLY, &m_pszFrom);
  4133. if (FAILED(m_pMsgW->GetAddressFormatW(IAT_TO, AFT_DISPLAY_FRIENDLY, &m_pszTo)))
  4134. MimeOleGetBodyPropW(m_pMsgW, HBODY_ROOT, PIDTOSTR(PID_HDR_NEWSGROUPS), NOFLAGS, &m_pszTo);
  4135. MimeOleGetBodyPropW(m_pMsgW, HBODY_ROOT, PIDTOSTR(PID_HDR_SUBJECT), NOFLAGS, &m_pszSubject);
  4136. }
  4137. InvalidateRect(m_hwnd, NULL, TRUE);
  4138. return hr;
  4139. }
  4140. HRESULT CBody::OnFocus(BOOL fGotFocus)
  4141. {
  4142. if (m_uHdrStyle == MESTYLE_PREVIEW || m_uHdrStyle == MESTYLE_MINIHEADER)
  4143. {
  4144. InvalidateRect(m_hwnd, NULL, TRUE);
  4145. if (m_hwndBtnBar)
  4146. InvalidateRect(m_hwndBtnBar, NULL, TRUE);
  4147. }
  4148. return CDocHost::OnFocus(fGotFocus);
  4149. }
  4150. HRESULT CBody::OnEraseBkgnd(HDC hdc)
  4151. {
  4152. RECT rc;
  4153. GetClientRect(m_hwnd, &rc);
  4154. rc.bottom = lGetClientHeight();
  4155. FillRect(hdc, &rc, GetSysColorBrush(m_fFocus?COLOR_HEADERFOCUS:COLOR_HEADER));
  4156. return S_OK;
  4157. }
  4158. HRESULT CBody::SetStyle(ULONG uStyle)
  4159. {
  4160. if (uStyle == m_uHdrStyle)
  4161. return S_OK;
  4162. m_uHdrStyle = uStyle;
  4163. ShowFormatBar(uStyle == MESTYLE_FORMATBAR);
  4164. ShowPreview(uStyle == MESTYLE_PREVIEW);
  4165. Resize();
  4166. return S_OK;
  4167. }
  4168. LONG CBody::lGetClientHeight()
  4169. {
  4170. HWND hwndFmtbar;
  4171. RECT rc;
  4172. // even if we don't have a big header, leave a thin
  4173. // line for users to click
  4174. switch (m_uHdrStyle)
  4175. {
  4176. case MESTYLE_PREVIEW:
  4177. return m_cyPreview;
  4178. case MESTYLE_MINIHEADER:
  4179. return SMALLHEADERHEIGHT;
  4180. case MESTYLE_FORMATBAR:
  4181. hwndFmtbar = GetDlgItem(m_hwnd, idcFmtBar);
  4182. if (hwndFmtbar)
  4183. {
  4184. GetClientRect(hwndFmtbar, &rc);
  4185. return rc.bottom-rc.top;
  4186. }
  4187. break;
  4188. }
  4189. return 0;
  4190. }
  4191. HRESULT CBody::Resize()
  4192. {
  4193. RECT rc;
  4194. GetClientRect(m_hwnd, &rc);
  4195. WMSize(rc.right-rc.left, rc.bottom-rc.top);
  4196. InvalidateRect(m_hwnd, NULL, TRUE);
  4197. return S_OK;
  4198. }
  4199. HRESULT CBody::SetCharset(HCHARSET hCharset)
  4200. {
  4201. HRESULT hr=S_OK;
  4202. BSTR bstr;
  4203. TCHAR rgchCset[CCHMAX_CSET_NAME];
  4204. if (hCharset == NULL)
  4205. return E_INVALIDARG;
  4206. if (m_hCharset == hCharset)
  4207. return S_OK;
  4208. if (!m_pDoc)
  4209. return E_UNEXPECTED;
  4210. if (m_fDesignMode)
  4211. {
  4212. // if we're in edit-mode, then we can't reload the document, so we use the trident object
  4213. // model to tell it the charset we want...
  4214. hr = HrGetMetaTagName(hCharset, rgchCset, ARRAYSIZE(rgchCset));
  4215. if (!FAILED(hr))
  4216. {
  4217. hr = HrLPSZToBSTR(rgchCset, &bstr);
  4218. if (!FAILED(hr))
  4219. {
  4220. // this will cause trident to reload with a new meta tag, if the user has changed the charset
  4221. // on the view|language menu
  4222. hr=m_pDoc->put_charset(bstr);
  4223. if (!FAILED(hr))
  4224. {
  4225. // all went well - switch the language
  4226. m_hCharset = hCharset;
  4227. }
  4228. SysFreeString(bstr);
  4229. }
  4230. }
  4231. else
  4232. {
  4233. // if lookup in mime database fails, return a good error
  4234. hr = MIMEEDIT_E_CHARSETNOTFOUND;
  4235. }
  4236. }
  4237. else
  4238. {
  4239. // if we're in browse mode, let the base class take care of reloading the document
  4240. if (m_pMsg)
  4241. {
  4242. hr = m_pMsg->SetCharset(hCharset, CSET_APPLY_ALL);
  4243. if (!FAILED(hr))
  4244. {
  4245. IMimeMessage *pMsg=m_pMsg;
  4246. pMsg->AddRef();
  4247. hr = Load(pMsg);
  4248. pMsg->Release();
  4249. }
  4250. }
  4251. }
  4252. return hr;
  4253. }
  4254. HRESULT CBody::PrivateEnableModeless(BOOL fEnable)
  4255. {
  4256. if (m_pInPlaceActiveObj)
  4257. m_pInPlaceActiveObj->EnableModeless(fEnable);
  4258. return S_OK;
  4259. }
  4260. HRESULT CBody::ClearDirtyFlag()
  4261. {
  4262. return HrSetDirtyFlagImpl(m_pDoc, FALSE);
  4263. }
  4264. DWORD CBody::DwChooseProperties()
  4265. {
  4266. DWORD dwRet=0;
  4267. // if we are on an image
  4268. if(m_fOnImage)
  4269. {
  4270. m_fOnImage = 0;
  4271. return IDM_IMAGE;
  4272. }
  4273. // if we are on an anchor
  4274. if (GetSelectedAnchor(NULL)==S_OK)
  4275. return IDM_HYPERLINK;
  4276. return 0;
  4277. }
  4278. HRESULT CBody::ShowFormatBar(BOOL fOn)
  4279. {
  4280. Assert (m_pFmtBar); // created in Init
  4281. if (fOn)
  4282. return m_pFmtBar->Show();
  4283. else
  4284. return m_pFmtBar->Hide();
  4285. }
  4286. void CBody::WMSize(int cxBody, int cyBody)
  4287. {
  4288. RECT rc,
  4289. rcBar;
  4290. switch (m_uHdrStyle)
  4291. {
  4292. case MESTYLE_FORMATBAR:
  4293. if (m_hwnd)
  4294. {
  4295. HWND hwndFmtbar = GetDlgItem(m_hwnd, idcFmtBar);
  4296. if (hwndFmtbar)
  4297. {
  4298. // if the format bar is on adjust the window rect accordingly
  4299. GetClientRect(hwndFmtbar, &rc);
  4300. SetWindowPos(hwndFmtbar, NULL, m_fSrcTabs?4:0, m_fSrcTabs?4:0, cxBody-(m_fSrcTabs?8:0), rc.bottom-rc.top, SWP_NOACTIVATE|SWP_NOZORDER);
  4301. }
  4302. }
  4303. break;
  4304. case MESTYLE_PREVIEW:
  4305. // center toolbar in the preview header and right-align it (note: account for the client edge we paint)
  4306. if (m_hwndBtnBar)
  4307. {
  4308. GetClientRect(m_hwndBtnBar, &rcBar);
  4309. SetWindowPos(m_hwndBtnBar, NULL, cxBody - rcBar.right - (GetSystemMetrics(SM_CXBORDER)*2), (m_cyPreview - rcBar.bottom)/2, 0, 0,SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOZORDER|SWP_NOSIZE);
  4310. }
  4311. break;
  4312. }
  4313. if (m_fSrcTabs)
  4314. {
  4315. RECT rc;
  4316. Assert (m_hwndTab);
  4317. GetClientRect(m_hwnd, &rc);
  4318. GetDocObjSize(&rc);
  4319. SetWindowPos(m_hwndTab, HWND_BOTTOM, 0, 0, cxBody, cyBody, SWP_NOACTIVATE);
  4320. if (m_pSrcView)
  4321. m_pSrcView->SetRect(&rc);
  4322. }
  4323. CDocHost::WMSize(cxBody, cyBody);
  4324. }
  4325. HRESULT CBody::InsertTextAtCaret(BSTR bstr, BOOL fHtml, BOOL fMoveCaretToEnd)
  4326. {
  4327. IHTMLTxtRange *pTxtRange=0;
  4328. HRESULT hr=E_FAIL;
  4329. if (!FAILED(hr = GetSelection(&pTxtRange)))
  4330. {
  4331. if(fHtml)
  4332. hr=pTxtRange->pasteHTML(bstr);
  4333. else
  4334. hr=pTxtRange->put_text(bstr);
  4335. pTxtRange->collapse( fMoveCaretToEnd ? VARIANT_FALSE : VARIANT_TRUE);
  4336. pTxtRange->select();
  4337. pTxtRange->Release();
  4338. }
  4339. return hr;
  4340. }
  4341. HRESULT CBody::UpdateCommands()
  4342. {
  4343. IHTMLTxtRange *pTxtRange=0;
  4344. if (m_pFmtBar)
  4345. m_pFmtBar->Update();
  4346. if (m_pParentCmdTarget)
  4347. m_pParentCmdTarget->Exec(NULL, OLECMDID_UPDATECOMMANDS, 0, NULL, NULL);
  4348. return S_OK;
  4349. }
  4350. LRESULT CBody::WMNotify(WPARAM wParam, NMHDR* pnmhdr)
  4351. {
  4352. HFONT hFont;
  4353. LRESULT lRet;
  4354. if (m_pSrcView &&
  4355. m_pSrcView->OnWMNotify(wParam, pnmhdr, &lRet)==S_OK)
  4356. return lRet;
  4357. switch (wParam)
  4358. {
  4359. case idcTabs:
  4360. switch (pnmhdr->code)
  4361. {
  4362. case TCN_SELCHANGE:
  4363. ShowSourceView(TabCtrl_GetCurSel(m_hwndTab));
  4364. break;
  4365. case TCN_SELCHANGING:
  4366. if (m_fReloadingSrc)
  4367. {
  4368. // while loading, prevent switching of tabs
  4369. MessageBeep(MB_ICONSTOP);
  4370. return TRUE;
  4371. }
  4372. break;
  4373. }
  4374. break;
  4375. case idcFmtBar:
  4376. switch (pnmhdr->code)
  4377. {
  4378. case FBN_GETMENUFONT:
  4379. hFont = 0;
  4380. if (m_pFontCache)
  4381. m_pFontCache->GetFont(FNT_SYS_MENU, NULL, &hFont);
  4382. return (LPARAM)hFont;
  4383. case FBN_BODYSETFOCUS:
  4384. UIActivate(FALSE);
  4385. UIActivate(TRUE);
  4386. return 0;
  4387. case FBN_BODYHASFOCUS:
  4388. return m_fFocus;
  4389. }
  4390. break;
  4391. case idcBtnBar:
  4392. switch (pnmhdr->code)
  4393. {
  4394. case NM_RCLICK:
  4395. if (((NMCLICK *)pnmhdr)->dwItemSpec == idmPanePaperclip)
  4396. ShowAttachMenu(TRUE);
  4397. break;
  4398. case TBN_DROPDOWN:
  4399. if (((TBNOTIFY *)pnmhdr)->iItem == idmPanePaperclip)
  4400. ShowAttachMenu(FALSE);
  4401. break;
  4402. }
  4403. break;
  4404. }
  4405. return 0;
  4406. }
  4407. HRESULT CBody::SetHostComposeFont()
  4408. {
  4409. VARIANTARG va;
  4410. va.bstrVal = NULL;
  4411. if (m_pParentCmdTarget)
  4412. m_pParentCmdTarget->Exec(&CMDSETID_MimeEditHost, MEHOSTCMDID_COMPOSE_FONT, OLECMDEXECOPT_DODEFAULT, NULL, &va);
  4413. SetComposeFont(va.bstrVal);
  4414. SysFreeString(va.bstrVal);
  4415. return S_OK;
  4416. }
  4417. HRESULT CBody::SetComposeFont(BSTR bstr)
  4418. {
  4419. VARIANTARG va;
  4420. va.vt = VT_BOOL;
  4421. va.boolVal = bstr?VARIANT_TRUE:VARIANT_FALSE;
  4422. if (m_pCmdTarget)
  4423. {
  4424. // turn OFF HTML-Edit mode if bstr==NULL
  4425. m_pCmdTarget->Exec(&CMDSETID_Forms3, IDM_HTMLEDITMODE, OLECMDEXECOPT_DODEFAULT, &va, NULL);
  4426. if (bstr)
  4427. {
  4428. va.vt = VT_BSTR;
  4429. va.bstrVal = bstr;
  4430. m_pCmdTarget->Exec(&CMDSETID_Forms3, IDM_COMPOSESETTINGS, OLECMDEXECOPT_DODEFAULT, &va, NULL);
  4431. }
  4432. }
  4433. return S_OK;
  4434. }
  4435. HRESULT CBody::ClearUndoStack()
  4436. {
  4437. IOleUndoManager *pUndoManager;
  4438. IServiceProvider *pSP;
  4439. HRESULT hr;
  4440. if (!m_lpOleObj)
  4441. return E_FAIL;
  4442. if (!FAILED(hr=m_lpOleObj->QueryInterface(IID_IServiceProvider, (LPVOID *)&pSP)))
  4443. {
  4444. if (!FAILED(hr = pSP->QueryService(SID_SOleUndoManager, IID_IOleUndoManager, (LPVOID *)&pUndoManager)))
  4445. {
  4446. hr = pUndoManager->DiscardFrom(NULL);
  4447. pUndoManager->Release();
  4448. }
  4449. pSP->Release();
  4450. }
  4451. return hr;
  4452. }
  4453. HRESULT CBody::DowngradeToPlainText(BOOL fForceFixedFont)
  4454. {
  4455. IHTMLElement *pElem=0;
  4456. IHTMLStyle *pStyle=0;
  4457. IHTMLTxtRange *pTxtRange;
  4458. BSTR bstr=0;
  4459. m_pDoc->get_body(&pElem);
  4460. if (pElem)
  4461. {
  4462. pElem->get_innerText(&bstr); // might be NULL if only images
  4463. pElem->put_innerText(bstr);
  4464. HrRemoveStyleSheets(m_pDoc);
  4465. HrRemoveBackground(m_pDoc);
  4466. SetWindowBgColor(TRUE); // force back to default color
  4467. SysFreeString(bstr);
  4468. if (fForceFixedFont)
  4469. {
  4470. // add <STYLE: font-family: monospace> to the body tag
  4471. pElem->get_style(&pStyle);
  4472. if (pStyle)
  4473. {
  4474. pStyle->put_fontFamily((BSTR)c_bstr_MonoSpace);
  4475. pStyle->Release();
  4476. }
  4477. }
  4478. if (m_fDesignMode)
  4479. {
  4480. // set caret at start
  4481. if (!FAILED(CreateRange(&pTxtRange)))
  4482. {
  4483. pTxtRange->collapse(VARIANT_TRUE);
  4484. pTxtRange->select();
  4485. pTxtRange->Release();
  4486. }
  4487. }
  4488. pElem->Release();
  4489. }
  4490. ClearUndoStack();
  4491. return S_OK;
  4492. }
  4493. // Returns MIME_S_CHARSET_CONFLICT if can't convert
  4494. HRESULT CBody::SafeToEncodeText(ULONG ulCodePage)
  4495. {
  4496. HRESULT hr = S_OK;
  4497. IHTMLElement *pElem = NULL;
  4498. BSTR bstr = NULL;
  4499. DWORD dwTemp = 0;
  4500. INT cbIn;
  4501. m_pDoc->get_body(&pElem);
  4502. if (pElem)
  4503. {
  4504. pElem->get_innerText(&bstr);
  4505. if (NULL != bstr)
  4506. {
  4507. cbIn = SysStringByteLen(bstr);
  4508. IF_FAILEXIT(hr = ConvertINetString(&dwTemp, CP_UNICODE, ulCodePage, (LPCSTR)bstr, &cbIn, NULL, NULL));
  4509. if (S_FALSE == hr)
  4510. hr = MIME_S_CHARSET_CONFLICT;
  4511. }
  4512. }
  4513. exit:
  4514. ReleaseObj(pElem);
  4515. SysFreeString(bstr);
  4516. return hr;
  4517. }
  4518. HRESULT CBody::SetDocumentText(BSTR bstr)
  4519. {
  4520. IHTMLTxtRange *pTxtRange;
  4521. HRESULT hr;
  4522. if (!m_lpOleObj)
  4523. return CO_E_NOT_SUPPORTED;
  4524. hr = CreateRange(&pTxtRange);
  4525. if (!FAILED(hr))
  4526. {
  4527. hr=pTxtRange->pasteHTML(bstr);
  4528. if (!FAILED(hr))
  4529. {
  4530. ClearDirtyFlag();
  4531. // we not empty anymore
  4532. m_fEmpty=FALSE;
  4533. }
  4534. pTxtRange->Release();
  4535. }
  4536. return hr;
  4537. }
  4538. HRESULT CBody::FormatFont()
  4539. {
  4540. return m_pCmdTarget?m_pCmdTarget->Exec(&CMDSETID_Forms3, IDM_FONT, OLECMDEXECOPT_DODEFAULT, NULL, NULL):E_FAIL;
  4541. }
  4542. HRESULT CBody::PasteReplyHeader()
  4543. {
  4544. HRESULT hr=S_OK;
  4545. ULONG uHdrStyle=0;
  4546. LPSTREAM pstm;
  4547. DWORD dwFlags=0,
  4548. dwHdr;
  4549. IHTMLTxtRange *pRange;
  4550. IOleCommandTarget *pCmdTarget;
  4551. VARIANTARG va;
  4552. if (m_pParentCmdTarget)
  4553. {
  4554. if (m_pParentCmdTarget->Exec(&CMDSETID_MimeEditHost, MEHOSTCMDID_HEADER_TYPE, 0, NULL, &va)==S_OK)
  4555. uHdrStyle = va.lVal;
  4556. GetHostFlags(&dwFlags);
  4557. }
  4558. if ((uHdrStyle != MEHEADER_NONE) &&
  4559. (dwFlags & MEO_FLAGS_INCLUDEMSG))
  4560. {
  4561. // check to see if the rootstream inserted the auto reply header placeholder
  4562. // if so, replace it
  4563. Assert ((uHdrStyle & MEHEADER_NEWS) || (uHdrStyle & MEHEADER_MAIL));
  4564. dwHdr = HDR_PADDING|(dwFlags&MEO_FLAGS_HTML?HDR_HTML:HDR_PLAIN);
  4565. if (uHdrStyle & MEHEADER_NEWS)
  4566. dwHdr |= HDR_NEWSSTYLE;
  4567. if (uHdrStyle & MEHEADER_FORCE_ENGLISH)
  4568. dwHdr |= HDR_HARDCODED;
  4569. pstm = NULL;
  4570. if (SUCCEEDED(hr=GetHeaderTable(m_pMsgW, NULL, dwHdr, &pstm)))
  4571. {
  4572. BSTR bstr;
  4573. if (SUCCEEDED(hr = HrIStreamWToBSTR(pstm, &bstr)))
  4574. {
  4575. // paste reply-headers at the top of the message
  4576. InsertBodyText(bstr, IBTF_URLHIGHLIGHT);
  4577. SysFreeString(bstr);
  4578. }
  4579. pstm->Release();
  4580. }
  4581. if (dwFlags & MEO_FLAGS_BLOCKQUOTE)
  4582. {
  4583. // block quote the text
  4584. if (SUCCEEDED(CreateRange(&pRange)))
  4585. {
  4586. if (SUCCEEDED(pRange->QueryInterface(IID_IOleCommandTarget, (LPVOID *)&pCmdTarget)))
  4587. {
  4588. if (pCmdTarget->Exec(&CMDSETID_Forms3, IDM_INDENT, NULL, NULL, NULL)==S_OK)
  4589. {
  4590. if (m_pParentCmdTarget &&
  4591. m_pParentCmdTarget->Exec(&CMDSETID_MimeEditHost, MEHOSTCMDID_REPLY_TICK_COLOR, 0, 0, &va)==S_OK)
  4592. FormatBlockQuote((COLORREF)va.lVal);
  4593. }
  4594. pCmdTarget->Release();
  4595. }
  4596. pRange->Release();
  4597. }
  4598. }
  4599. if (dwFlags & MEO_FLAGS_DONTSPELLCHECKQUOTED)
  4600. CreateRange(&m_pRangeIgnoreSpell);
  4601. }
  4602. return hr;
  4603. }
  4604. HRESULT CBody::InsertBodyText(BSTR bstrPaste, DWORD dwFlags)
  4605. {
  4606. IHTMLElement *pElem;
  4607. IHTMLBodyElement *pBodyElem;
  4608. HRESULT hr=E_FAIL;
  4609. if (!FAILED(GetBodyElement(&pBodyElem)))
  4610. {
  4611. if (!FAILED(pBodyElem->QueryInterface(IID_IHTMLElement, (LPVOID *)&pElem)))
  4612. {
  4613. hr = pElem->insertAdjacentHTML((BSTR)(dwFlags & IBTF_INSERTATEND ?c_bstr_BeforeEnd:c_bstr_AfterBegin), bstrPaste);
  4614. IHTMLTxtRange *pRange;
  4615. LONG cch;
  4616. if (!FAILED(hr) && (dwFlags & IBTF_URLHIGHLIGHT))
  4617. {
  4618. if (CreateRangeFromElement(pElem, &pRange)==S_OK)
  4619. {
  4620. if (!FAILED(pRange->collapse(VARIANT_TRUE)))
  4621. {
  4622. if (!FAILED(pRange->moveEnd((BSTR)c_bstr_Character, (LONG)SysStringLen(bstrPaste), (LPLONG)&cch)) && cch!=0)
  4623. UrlHighlight(pRange);
  4624. }
  4625. pRange->Release();
  4626. }
  4627. }
  4628. pElem->Release();
  4629. }
  4630. pBodyElem->Release();
  4631. }
  4632. return hr;
  4633. }
  4634. HRESULT CBody::FormatBlockQuote(COLORREF crTextColor)
  4635. {
  4636. HRESULT hr;
  4637. IHTMLElementCollection *pCollect;
  4638. IHTMLStyle *pStyle=0;
  4639. IHTMLElement *pElem;
  4640. ULONG cItems;
  4641. TCHAR rgch[CCHMAX_STRINGRES];
  4642. BSTR bstr;
  4643. VARIANT v;
  4644. if (!FAILED(HrGetCollectionOf(m_pDoc, (BSTR)c_bstr_BLOCKQUOTE, &pCollect)))
  4645. {
  4646. cItems = (int)UlGetCollectionCount(pCollect);
  4647. if (cItems > 0 &&
  4648. !FAILED(HrGetCollectionItem(pCollect, 0, IID_IHTMLElement, (LPVOID *)&pElem)))
  4649. {
  4650. pElem->get_style(&pStyle);
  4651. if (pStyle)
  4652. {
  4653. // set the style on the elemen
  4654. // .replyTick { border-left:solid ; border-left-width: 4;
  4655. // border-color: #0000ff; padding-left: 5;
  4656. // margin-left: 5}
  4657. // 5/19/98: fix margin on nesting:
  4658. // padding-right: 0, margin-right:0
  4659. wnsprintf(rgch, ARRAYSIZE(rgch), "solid 2 #%02x%02x%02x", GetRValue(crTextColor), GetGValue(crTextColor), GetBValue(crTextColor));
  4660. if (HrLPSZToBSTR(rgch, &bstr)==S_OK)
  4661. {
  4662. pStyle->put_borderLeft(bstr);
  4663. SysFreeString(bstr);
  4664. }
  4665. // set the padding and the margin
  4666. v.vt = VT_I4;
  4667. v.lVal = 5;
  4668. pStyle->put_paddingLeft(v);
  4669. pStyle->put_marginLeft(v);
  4670. v.lVal = 0;
  4671. pStyle->put_paddingRight(v);
  4672. pStyle->put_marginRight(v);
  4673. pStyle->Release();
  4674. }
  4675. // first dude in the collection should be the one at the root of the tree
  4676. pElem->Release();
  4677. }
  4678. pCollect->Release();
  4679. }
  4680. return S_OK;
  4681. }
  4682. HRESULT CBody::GetAutoText(BSTR *pbstr, BOOL *pfTop)
  4683. {
  4684. HRESULT hr;
  4685. BOOL fSig;
  4686. ULONG uSigOpt;
  4687. TCHAR rgchAutoText[4096]; // buffer big enough to build autotext into
  4688. VARIANTARG va;
  4689. if (!m_pParentCmdTarget)
  4690. return E_FAIL;
  4691. if (pfTop)
  4692. *pfTop = TRUE;
  4693. *rgchAutoText = 0;
  4694. va.vt = VT_I4;
  4695. va.lVal = MESIG_AUTO;
  4696. fSig = (m_pParentCmdTarget->Exec(&CMDSETID_MimeEditHost, MEHOSTCMDID_SIGNATURE_ENABLED, 0, &va, NULL)==S_OK);
  4697. if (fSig &&
  4698. m_pParentCmdTarget->Exec(&CMDSETID_MimeEditHost, MEHOSTCMDID_SIGNATURE_OPTIONS, 0, NULL, &va)==S_OK)
  4699. {
  4700. Assert(va.vt==VT_I4);
  4701. uSigOpt = va.lVal;
  4702. }
  4703. /*
  4704. let's build a BSTR of the HTML we want to insert.
  4705. <DIV>
  4706. <SPAN id=\"__CaretPos__\"><BR></SPAN>
  4707. </DIV>
  4708. <DIV>
  4709. <SPAN id="__Signature__"></SPAN>
  4710. </DIV>
  4711. */
  4712. StrCatBuff(rgchAutoText, c_szHtml_DivOpen, ARRAYSIZE(rgchAutoText));
  4713. StrCatBuff(rgchAutoText, c_szCaretSpanTag, ARRAYSIZE(rgchAutoText));
  4714. StrCatBuff(rgchAutoText, c_szHtml_DivClose, ARRAYSIZE(rgchAutoText));
  4715. if (fSig)
  4716. {
  4717. StrCatBuff(rgchAutoText, c_szHtml_DivOpen, ARRAYSIZE(rgchAutoText));
  4718. StrCatBuff(rgchAutoText, c_szSignatureSpanTag, ARRAYSIZE(rgchAutoText));
  4719. StrCatBuff(rgchAutoText, c_szHtml_DivClose, ARRAYSIZE(rgchAutoText));
  4720. }
  4721. if (pfTop && fSig && uSigOpt & MESIGOPT_BOTTOM)
  4722. *pfTop = FALSE;
  4723. // can use ACP for this conversion as we know all the text is lowansi
  4724. return HrLPSZToBSTR(rgchAutoText, pbstr);
  4725. }
  4726. HRESULT CBody::PasteAutoText()
  4727. {
  4728. HRESULT hr=S_OK;
  4729. LPSTREAM pstm;
  4730. DWORD dwFlags=0;
  4731. BSTR bstrAutoText=0,
  4732. bstrSig=0;
  4733. IHTMLElement *pElem;
  4734. BOOL fPasteAtTop=TRUE;
  4735. DWORD dwSigOpt=0;
  4736. VARIANTARG va;
  4737. /*
  4738. For AutoText, we search for a <SPAN> tag that indicates where the caret should be.
  4739. To find the caret, we use the following rules
  4740. 1. look for "_AthCaret" this is used by a stationery author to set the caret for the stationery
  4741. 2. look for "__Ath_AutoCaret" this is inserted by the rootstream it maybe at the top or bottom (sigopts)
  4742. of the document. It should always be present if autotext is needed
  4743. when we find the caret, we insert the auto-text stream we build (contains compose font and/or signature) and
  4744. put the caret at the start of this.
  4745. */
  4746. GetHostFlags(&dwFlags);
  4747. if (dwFlags & MEO_FLAGS_AUTOTEXT &&
  4748. !FAILED(GetAutoText(&bstrAutoText, &fPasteAtTop)))
  4749. {
  4750. // try a stationery-authored caret
  4751. if (FAILED(ReplaceElement("_AthCaret", bstrAutoText, TRUE)))
  4752. {
  4753. // if there wasn't one, then put at start or end of the body
  4754. // depending on signature
  4755. InsertBodyText(bstrAutoText, fPasteAtTop ? 0:IBTF_INSERTATEND);
  4756. }
  4757. va.vt = VT_I4;
  4758. va.lVal = MESIG_AUTO;
  4759. // let's try and insert the signature now.
  4760. if (m_pParentCmdTarget &&
  4761. (m_pParentCmdTarget->Exec(&CMDSETID_MimeEditHost, MEHOSTCMDID_SIGNATURE_ENABLED, 0, &va, NULL)==S_OK) &&
  4762. (m_pParentCmdTarget->Exec(&CMDSETID_MimeEditHost, MEHOSTCMDID_SIGNATURE_OPTIONS, 0, NULL, &va)==S_OK) &&
  4763. va.vt==VT_I4)
  4764. {
  4765. dwSigOpt = va.lVal;
  4766. if (m_pParentCmdTarget->Exec(&CMDSETID_MimeEditHost, MEHOSTCMDID_SIGNATURE, 0, NULL, &va)==S_OK &&
  4767. va.vt==VT_BSTR)
  4768. {
  4769. bstrSig = va.bstrVal;
  4770. // sleazy v2. workaround. Trident pulled out the springloader font code from
  4771. // CElem::put_outerText, so plain-signatures etc no longer go in in the
  4772. // compose font. We fix this by inserting an &nbsp after the signature span
  4773. // (if there is one) then we can select the nbsp; and paste at that range.
  4774. if (!FAILED(GetElement(c_szSignatureSpan, &pElem)))
  4775. {
  4776. IHTMLTxtRange *pRange;
  4777. if (CreateRangeFromElement(pElem, &pRange)==S_OK)
  4778. {
  4779. // small change. Now we put in &nbsp;<SPAN>&nbsp; we move the range to
  4780. // the span and then expand it a char left and right. This range includes the span
  4781. // do it get's nuked when we paste.
  4782. LONG cch;
  4783. SideAssert(pRange->moveEnd((BSTR)c_bstr_Character, 1, &cch)==S_OK && cch==1);
  4784. SideAssert(pRange->moveStart((BSTR)c_bstr_Character, -1, &cch)==S_OK && cch==-1);
  4785. if (dwSigOpt & MESIGOPT_HTML)
  4786. pRange->pasteHTML(bstrSig);
  4787. else
  4788. {
  4789. if(dwSigOpt & MESIGOPT_PREFIX)
  4790. {
  4791. BSTR bstrPrefix;
  4792. // if a prefix is required (for news), then append one
  4793. if (HrLPSZToBSTR(c_szSigPrefix, &bstrPrefix)==S_OK)
  4794. {
  4795. pRange->put_text(bstrPrefix);
  4796. pRange->collapse(VARIANT_FALSE);
  4797. SysFreeString(bstrPrefix);
  4798. }
  4799. }
  4800. pRange->put_text(bstrSig);
  4801. }
  4802. pRange->Release();
  4803. }
  4804. pElem->Release();
  4805. }
  4806. SysFreeString(bstrSig);
  4807. }
  4808. }
  4809. // if we sucessfully pasted, set the caret at the span marker we
  4810. // just pasted
  4811. if (!FAILED(GetElement(c_szCaretSpan, &pElem)))
  4812. {
  4813. SelectElement(pElem, TRUE);
  4814. DeleteElement(pElem);
  4815. pElem->Release();
  4816. }
  4817. SysFreeString(bstrAutoText);
  4818. }
  4819. return S_OK;
  4820. }
  4821. HRESULT CBody::GetHostFlags(LPDWORD pdwFlags)
  4822. {
  4823. VARIANTARG va;
  4824. HRESULT hr=E_FAIL;
  4825. *pdwFlags = 0;
  4826. if (m_pParentCmdTarget &&
  4827. !FAILED(hr = m_pParentCmdTarget->Exec(&CMDSETID_MimeEditHost, MEHOSTCMDID_FLAGS, 0, NULL, &va)))
  4828. *pdwFlags = va.lVal;
  4829. return hr;
  4830. }
  4831. HRESULT CBody::GetBackgroundColor(DWORD *pdwColor)
  4832. {
  4833. HRESULT hr;
  4834. IHTMLBodyElement *pBodyElem=0;
  4835. VARIANT var;
  4836. TCHAR *lpszColor = NULL;
  4837. var.vt = VT_BSTR;
  4838. var.bstrVal = NULL;
  4839. hr = GetBodyElement(&pBodyElem);
  4840. if (FAILED(hr))
  4841. goto error;
  4842. hr = pBodyElem->get_bgColor(&var);
  4843. if (FAILED(hr))
  4844. goto error;
  4845. if (var.bstrVal)
  4846. {
  4847. hr = HrBSTRToLPSZ(CP_ACP, var.bstrVal, &lpszColor);
  4848. if (FAILED(hr))
  4849. goto error;
  4850. // get_bgColor returns format "#RRGGBB"
  4851. // Only send in "RRGGBB" part of the string
  4852. GetRGBFromString(pdwColor, lpszColor+1);
  4853. }
  4854. else
  4855. *pdwColor = 0x00FFFFFF | GetSysColor(COLOR_WINDOW);
  4856. error:
  4857. ReleaseObj(pBodyElem);
  4858. SafeMemFree(lpszColor);
  4859. SysFreeString(var.bstrVal);
  4860. return hr;
  4861. }
  4862. HRESULT CBody::SetBackgroundColor(DWORD dwColor)
  4863. {
  4864. HRESULT hr;
  4865. IHTMLBodyElement *pBodyElem=0;
  4866. VARIANT var;
  4867. TCHAR szColor[7]; //"#RRGGBB\0"
  4868. BSTR bstrColor = NULL;
  4869. GetStringRGB(dwColor, szColor);
  4870. hr = HrLPSZToBSTR(szColor, &bstrColor);
  4871. if (FAILED(hr))
  4872. goto error;
  4873. var.vt = VT_BSTR;
  4874. var.bstrVal = bstrColor;
  4875. hr = GetBodyElement(&pBodyElem);
  4876. if (FAILED(hr))
  4877. goto error;
  4878. hr = pBodyElem->put_bgColor(var);
  4879. error:
  4880. ReleaseObj(pBodyElem);
  4881. SysFreeString(bstrColor);
  4882. return hr;
  4883. }
  4884. HRESULT CBody::SetWindowBgColor(BOOL fForce)
  4885. {
  4886. HRESULT hr;
  4887. IHTMLBodyElement *pBodyElem=0;
  4888. CHAR szBuf[MAX_PATH] = {0};
  4889. DWORD dColors = 0;
  4890. VARIANT v1, v2;
  4891. v1.vt = VT_BSTR;
  4892. v1.bstrVal = NULL;
  4893. v2.vt = VT_BSTR;
  4894. v2.bstrVal = NULL;
  4895. hr = GetBodyElement(&pBodyElem);
  4896. if (FAILED(hr))
  4897. goto error;
  4898. hr=pBodyElem->get_bgColor(&v1);
  4899. if (FAILED(hr))
  4900. goto error;
  4901. if(NULL != v1.bstrVal && !fForce)
  4902. goto error;
  4903. dColors = GetSysColor(COLOR_WINDOW);
  4904. GetStringRGB(dColors, szBuf);
  4905. hr=HrLPSZToBSTR(szBuf, &(v2.bstrVal));
  4906. if (FAILED(hr))
  4907. goto error;
  4908. hr=pBodyElem->put_bgColor(v2);
  4909. if (FAILED(hr))
  4910. goto error;
  4911. error:
  4912. ReleaseObj(pBodyElem);
  4913. SysFreeString(v1.bstrVal);
  4914. SysFreeString(v2.bstrVal);
  4915. return hr;
  4916. }
  4917. #define CCBMAX_FRAMESEARCH 4096
  4918. HRESULT CBody::InsertFile(BSTR bstrFileName)
  4919. {
  4920. OPENFILENAMEW ofn;
  4921. WCHAR wszFile[MAX_PATH],
  4922. wszTitle[CCHMAX_STRINGRES],
  4923. wszFilter[100],
  4924. wszDefExt[30];
  4925. BYTE pbHtml[CCBMAX_FRAMESEARCH];
  4926. HRESULT hr;
  4927. LPSTREAM pstm = NULL;
  4928. DWORD dwFlags=0;
  4929. BOOL fHtml;
  4930. ULONG cb=0;
  4931. if (!m_lpOleObj)
  4932. IF_FAILEXIT(hr = E_FAIL);
  4933. *wszFile = 0;
  4934. *wszTitle = 0;
  4935. *wszFilter = 0;
  4936. *wszDefExt = 0;
  4937. // Load Res Strings
  4938. GetHostFlags(&dwFlags);
  4939. if (bstrFileName)
  4940. {
  4941. // if we have a filename, let's use that else prompt for one
  4942. StrCpyNW(wszFile, (LPWSTR)bstrFileName, ARRAYSIZE(wszFile));
  4943. }
  4944. else
  4945. {
  4946. LoadStringWrapW(g_hLocRes, dwFlags&MEO_FLAGS_HTML?idsTextOrHtmlFileFilter:idsTextFileFilter, wszFilter, ARRAYSIZE(wszFilter));
  4947. ReplaceCharsW(wszFilter, L'|', L'\0');
  4948. LoadStringWrapW(g_hLocRes, idsDefTextExt, wszDefExt, ARRAYSIZE(wszDefExt));
  4949. LoadStringWrapW(g_hLocRes, idsInsertTextTitle, wszTitle, ARRAYSIZE(wszTitle));
  4950. // Setup Save file struct
  4951. ZeroMemory (&ofn, sizeof (ofn));
  4952. ofn.lStructSize = sizeof (ofn);
  4953. ofn.hwndOwner = m_hwnd;
  4954. ofn.lpstrFilter = wszFilter;
  4955. ofn.nFilterIndex = 1;
  4956. ofn.lpstrFile = wszFile;
  4957. ofn.nMaxFile = ARRAYSIZE(wszFile);
  4958. ofn.lpstrTitle = wszTitle;
  4959. ofn.lpstrDefExt = wszDefExt;
  4960. ofn.Flags = OFN_FILEMUSTEXIST|OFN_HIDEREADONLY|OFN_NOCHANGEDIR;
  4961. // Show OpenFile Dialog
  4962. if (!GetOpenFileNameWrapW(&ofn))
  4963. return NOERROR;
  4964. }
  4965. if (*wszFile==NULL)
  4966. IF_FAILEXIT(hr = E_FAIL);
  4967. IF_FAILEXIT(hr=OpenFileStreamW(wszFile, OPEN_EXISTING, GENERIC_READ, &pstm));
  4968. fHtml = (dwFlags&MEO_FLAGS_HTML)&&FIsHTMLFileW(wszFile);
  4969. if (fHtml)
  4970. {
  4971. BOOL fFrames = FALSE;
  4972. BOOL fLittleEndian;
  4973. // if html, do a quick scan of the first 2k for a frameset
  4974. pstm->Read(pbHtml, sizeof(pbHtml) - 2, &cb);
  4975. pbHtml[cb] = 0;
  4976. pbHtml[cb+1] = 0;
  4977. // if we found a frameset tag, warn the user
  4978. if (S_OK == HrIsStreamUnicode(pstm, &fLittleEndian))
  4979. {
  4980. if(StrStrIW((WCHAR*)pbHtml, L"<FRAMESET"))
  4981. fFrames = TRUE;
  4982. }
  4983. else if (StrStrI((CHAR*)pbHtml, "<FRAMESET"))
  4984. fFrames = TRUE;
  4985. if (fFrames)
  4986. AthMessageBoxW(m_hwnd, MAKEINTRESOURCEW(idsInsertTextTitle), MAKEINTRESOURCEW(idsErrInsertFileHasFrames), NULL, MB_OK);
  4987. }
  4988. IF_FAILEXIT(hr=InsertStreamAtCaret(pstm, fHtml));
  4989. exit:
  4990. ReleaseObj(pstm);
  4991. return hr;
  4992. }
  4993. HRESULT CBody::InsertStreamAtCaret(LPSTREAM pstm, BOOL fHtml)
  4994. {
  4995. BSTR bstr;
  4996. HRESULT hr;
  4997. UINT uiCodePage = 0 ;
  4998. INETCSETINFO CsetInfo ;
  4999. LPSTR pszCharset=NULL;
  5000. HCHARSET hCharset=NULL;
  5001. IStream *pstm2;
  5002. HrRewindStream(pstm);
  5003. if (fHtml)
  5004. {
  5005. if (SUCCEEDED(MimeOleCreateVirtualStream(&pstm2)))
  5006. {
  5007. if (SUCCEEDED(HrCopyStream(pstm, pstm2, 0)))
  5008. {
  5009. // if HTML then try and SNIFF the charset from the document
  5010. if (GetHtmlCharset(pstm2, &pszCharset)==S_OK)
  5011. {
  5012. MimeOleFindCharset(pszCharset, &hCharset);
  5013. MemFree(pszCharset);
  5014. }
  5015. }
  5016. // Free up the stream
  5017. pstm2->Release();
  5018. }
  5019. }
  5020. // if nothing so far, try the message-charset
  5021. if (!hCharset)
  5022. hCharset = m_hCharset;
  5023. if (hCharset)
  5024. {
  5025. // get CodePage from HCHARSET
  5026. MimeOleGetCharsetInfo(hCharset,&CsetInfo);
  5027. uiCodePage = CsetInfo.cpiInternet;
  5028. }
  5029. hr=HrIStreamToBSTR(uiCodePage ? uiCodePage : GetACP(), pstm, &bstr);
  5030. if (!(FAILED(hr)))
  5031. {
  5032. hr = InsertTextAtCaret(bstr, fHtml, TRUE);
  5033. SysFreeString(bstr);
  5034. }
  5035. return hr;
  5036. }
  5037. HRESULT CALLBACK FreeDataObj(PDATAOBJINFO pDataObjInfo, DWORD celt)
  5038. {
  5039. // Loop through the data and free it all
  5040. if (pDataObjInfo)
  5041. {
  5042. for (DWORD i = 0; i < celt; i++)
  5043. SafeMemFree(pDataObjInfo[i].pData);
  5044. SafeMemFree(pDataObjInfo);
  5045. }
  5046. return S_OK;
  5047. }
  5048. HRESULT CBody::CreateFontCache(LPCSTR pszTridentKey)
  5049. {
  5050. VARIANTARG va;
  5051. HRESULT hr=S_OK;
  5052. IConnectionPoint *pCP;
  5053. // time to try and create a font cache. First of all, ask the host if he has one already that we should use
  5054. // if so, we're done. If not, create based on pszTridentKey. If this is NULL we use the IE regkey
  5055. if (m_pFontCache)
  5056. return S_OK;
  5057. if (m_pParentCmdTarget &&
  5058. m_pParentCmdTarget->Exec(&CMDSETID_MimeEditHost, MEHOSTCMDID_FONTCACHE, 0, NULL, &va)==S_OK &&
  5059. va.vt == VT_UNKNOWN)
  5060. {
  5061. ReplaceInterface(m_pFontCache, (IFontCache *)va.punkVal);
  5062. (va.punkVal)->Release();
  5063. goto done;
  5064. }
  5065. if(g_lpIFontCache)
  5066. {
  5067. ReplaceInterface(m_pFontCache, g_lpIFontCache);
  5068. goto done;
  5069. }
  5070. done:
  5071. if (m_pFontCache &&
  5072. m_pFontCache->QueryInterface(IID_IConnectionPoint, (LPVOID *)&pCP)==S_OK)
  5073. {
  5074. pCP->Advise((IUnknown *)(IFontCacheNotify *)this, &m_dwFontCacheNotify);
  5075. pCP->Release();
  5076. }
  5077. RecalcPreivewHeight(NULL);
  5078. return hr;
  5079. }
  5080. HRESULT CBody::DoHostProperties()
  5081. {
  5082. return m_pParentCmdTarget?m_pParentCmdTarget->Exec(NULL, OLECMDID_PROPERTIES, 0, NULL, NULL):E_FAIL;
  5083. }
  5084. HRESULT CBody::SaveAsStationery(VARIANTARG *pvaIn, VARIANTARG *pvaOut)
  5085. {
  5086. BSTR bstr=0;
  5087. LPSTREAM pstm=0,
  5088. pstmImage=0;
  5089. LPSTR lpsz,
  5090. lpszName;
  5091. TCHAR rgch[MAX_PATH],
  5092. sz[MAX_PATH+CCHMAX_STRINGRES],
  5093. rgchRes[CCHMAX_STRINGRES],
  5094. rgchExt[10];
  5095. TCHAR rgchUrl[MAX_PATH],
  5096. rgchPath[MAX_PATH];
  5097. OPENFILENAME ofn;
  5098. TCHAR szFile[MAX_PATH];
  5099. TCHAR szTitle[CCHMAX_STRINGRES];
  5100. TCHAR szFilter[100];
  5101. HRESULT hr;
  5102. LPSTR pszOpenFilePath=NULL;
  5103. WCHAR rgchW[MAX_PATH];
  5104. TraceCall("CBody::SaveAsStationery");
  5105. *rgchUrl=0;
  5106. *rgchPath = 0;
  5107. *szFile = 0;
  5108. *szFilter = 0;
  5109. LoadString(g_hLocRes, idsHtmlFileFilter, szFilter, sizeof(szFilter));
  5110. ReplaceChars(szFilter, '|', '\0');
  5111. LoadString(g_hLocRes, idsSaveAsStationery, szTitle, sizeof(szTitle));
  5112. if (pvaIn && pvaIn->vt==VT_BSTR)
  5113. {
  5114. // if we get passed in an initial path to save into, then use it
  5115. if (WideCharToMultiByte(CP_ACP, 0, (WCHAR*)pvaIn->bstrVal, -1, rgchPath, ARRAYSIZE(rgchPath), NULL, NULL))
  5116. pszOpenFilePath = rgchPath;
  5117. }
  5118. // Setup Save file struct
  5119. ZeroMemory (&ofn, sizeof (ofn));
  5120. ofn.lStructSize = sizeof (ofn);
  5121. ofn.hwndOwner = m_hwnd;
  5122. ofn.lpstrFilter = szFilter;
  5123. ofn.nFilterIndex = 1;
  5124. ofn.lpstrFile = szFile;
  5125. ofn.nMaxFile = sizeof (szFile);
  5126. ofn.lpstrTitle = szTitle;
  5127. ofn.lpstrInitialDir = rgchPath;
  5128. ofn.Flags = OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
  5129. // Show OpenFile Dialog
  5130. if (!GetSaveFileName(&ofn) || *szFile==NULL)
  5131. return MIMEEDIT_E_USERCANCEL;
  5132. StrCpyN(rgchPath, szFile, ARRAYSIZE(rgchPath));
  5133. rgchPath[ofn.nFileOffset] = NULL;
  5134. lpszName = &szFile[ofn.nFileOffset];
  5135. if (ofn.nFileExtension)
  5136. {
  5137. if(szFile[ofn.nFileExtension-1] == '.')
  5138. szFile[ofn.nFileExtension-1]=NULL;
  5139. }
  5140. if (FAILED(MimeOleCreateVirtualStream(&pstm)))
  5141. return E_OUTOFMEMORY;
  5142. HrGetStyleTag(m_pDoc, &bstr);
  5143. pstm->Write(c_szHtml_HtmlOpenCR, lstrlen(c_szHtml_HtmlOpenCR), 0);
  5144. if (bstr)
  5145. {
  5146. pstm->Write(c_szHtml_HeadOpenCR, lstrlen(c_szHtml_HeadOpenCR), 0);
  5147. if (HrBSTRToLPSZ(CP_ACP, bstr, &lpsz)==S_OK)
  5148. {
  5149. pstm->Write(lpsz, lstrlen(lpsz), 0);
  5150. MemFree(lpsz);
  5151. }
  5152. pstm->Write(c_szHtml_HeadCloseCR, lstrlen(c_szHtml_HeadCloseCR), 0);
  5153. }
  5154. SysFreeString(bstr);
  5155. if (GetBackgroundImage(m_pDoc, &bstr)==S_OK)
  5156. {
  5157. if (HrBSTRToLPSZ(CP_ACP, bstr, &lpsz)==S_OK)
  5158. {
  5159. if (HrBindToUrl(lpsz, &pstmImage)!=S_OK)
  5160. HrFindUrlInMsg(m_pMsg, lpsz, FINDURL_SEARCH_RELATED_ONLY, &pstmImage);
  5161. if (pstmImage)
  5162. {
  5163. StrCpyN(rgchUrl, lpszName, ARRAYSIZE(rgchUrl));
  5164. // append an extension
  5165. if (HrSniffStreamFileExt(pstmImage, &lpsz)==S_OK)
  5166. {
  5167. StrCatBuff(rgchUrl, lpsz, ARRAYSIZE(rgchUrl));
  5168. SafeMimeOleFree(lpsz);
  5169. }
  5170. StrCpyN(rgch, rgchPath, ARRAYSIZE(rgch));
  5171. StrCatBuff(rgch, rgchUrl, ARRAYSIZE(rgch));
  5172. if (PathFileExists(rgch))
  5173. {
  5174. if (!LoadString(g_hLocRes, idsWarnFileExist, rgchRes, ARRAYSIZE(rgchRes)))
  5175. {
  5176. hr = E_OUTOFMEMORY;
  5177. goto error;
  5178. }
  5179. wnsprintf(sz, ARRAYSIZE(sz), rgchRes, rgch);
  5180. // the file exists, warn the dude
  5181. if (AthMessageBox(m_hwnd, MAKEINTRESOURCE(idsSaveAsStationery), sz, NULL, MB_YESNO|MB_DEFBUTTON2|MB_ICONEXCLAMATION )!=IDYES)
  5182. {
  5183. hr = S_OK;
  5184. goto error;
  5185. }
  5186. }
  5187. WriteStreamToFile(pstmImage, rgch, CREATE_ALWAYS, GENERIC_WRITE);
  5188. pstmImage->Release();
  5189. }
  5190. MemFree(lpsz);
  5191. }
  5192. SysFreeString(bstr);
  5193. }
  5194. if (*rgchUrl)
  5195. {
  5196. // output the body tag with background image
  5197. wnsprintf(rgch, ARRAYSIZE(rgch), c_szHtml_BodyOpenBgCR, rgchUrl);
  5198. pstm->Write(rgch, lstrlen(rgch), 0);
  5199. }
  5200. else
  5201. {
  5202. // reference point for BUG 31874
  5203. if (AthMessageBoxW(m_hwnd, MAKEINTRESOURCEW(idsSaveAsStationery), MAKEINTRESOURCEW(idsWarnBoringStationery), NULL, MB_YESNO|MB_DEFBUTTON2|MB_ICONEXCLAMATION )!=IDYES)
  5204. {
  5205. hr=MIMEEDIT_E_USERCANCEL;
  5206. goto error;
  5207. }
  5208. pstm->Write(c_szHtml_BodyOpenNbspCR, lstrlen(c_szHtml_BodyOpenNbspCR), 0);
  5209. }
  5210. pstm->Write(c_szHtml_BodyCloseCR, lstrlen(c_szHtml_BodyCloseCR), 0);
  5211. pstm->Write(c_szHtml_HtmlCloseCR, lstrlen(c_szHtml_HtmlCloseCR), 0);
  5212. StrCpyN(rgch, rgchPath, ARRAYSIZE(rgch));
  5213. StrCatBuff(rgch, lpszName, ARRAYSIZE(rgch));
  5214. StrCatBuff(rgch, ".htm", ARRAYSIZE(rgch));
  5215. WriteStreamToFile(pstm, rgch, CREATE_ALWAYS, GENERIC_WRITE);
  5216. if (pvaOut)
  5217. {
  5218. // if set, the caller wants the actual filename that was written, so convert rgch to a BSTR
  5219. pvaOut->vt = VT_BSTR;
  5220. pvaOut->bstrVal = NULL;
  5221. HrLPSZToBSTR(rgch, &pvaOut->bstrVal);
  5222. }
  5223. error:
  5224. ReleaseObj(pstm);
  5225. return hr;
  5226. }
  5227. HRESULT CBody::TagUnreferencedImages()
  5228. {
  5229. ULONG uImage,
  5230. cImages;
  5231. IHTMLElementCollection *pCollect;
  5232. IHTMLBodyElement *pBody;
  5233. IUnknown *pUnk;
  5234. BSTR bstr;
  5235. CHAR szUrl[INTERNET_MAX_URL_LENGTH];
  5236. // BUG: we can't use the image collection, as it shows images up multiple times
  5237. // for NAV compatibility. Have to filter the 'all' collection on "IMG" tags.
  5238. if (HrGetCollectionOf(m_pDoc, (BSTR)c_bstr_IMG, &pCollect)==S_OK)
  5239. {
  5240. cImages = UlGetCollectionCount(pCollect);
  5241. for (uImage=0; uImage<cImages; uImage++)
  5242. {
  5243. if (HrGetCollectionItem(pCollect, uImage, IID_IUnknown, (LPVOID *)&pUnk)==S_OK)
  5244. {
  5245. if (HrGetMember(pUnk, (BSTR)c_bstr_SRC, VARIANT_FALSE, &bstr)==S_OK)
  5246. {
  5247. if (WideCharToMultiByte(CP_ACP, 0, bstr, -1, szUrl, INTERNET_MAX_URL_LENGTH, NULL, NULL) &&
  5248. HrFindUrlInMsg(m_pMsg, szUrl, FINDURL_SEARCH_RELATED_ONLY, NULL)!=S_OK)
  5249. {
  5250. // this URL was not in the message, let's tag it as a NOSEND url
  5251. HrSetMember(pUnk, (BSTR)c_bstr_NOSEND, (BSTR)c_bstr_1);
  5252. }
  5253. SysFreeString(bstr);
  5254. }
  5255. pUnk->Release();
  5256. }
  5257. }
  5258. pCollect->Release();
  5259. }
  5260. // if the background is not included tag as NOSEND
  5261. if (!FAILED(GetBodyElement(&pBody)))
  5262. {
  5263. if (!FAILED(GetBackgroundImage(m_pDoc, &bstr)))
  5264. {
  5265. if (WideCharToMultiByte(CP_ACP, 0, bstr, -1, szUrl, INTERNET_MAX_URL_LENGTH, NULL, NULL) &&
  5266. HrFindUrlInMsg(m_pMsg, szUrl, FINDURL_SEARCH_RELATED_ONLY, NULL)!=S_OK)
  5267. {
  5268. HrSetMember(pBody, (BSTR)c_bstr_NOSEND, (BSTR)c_bstr_1);
  5269. }
  5270. SysFreeString(bstr);
  5271. }
  5272. pBody->Release();
  5273. }
  5274. return S_OK;
  5275. }
  5276. HRESULT CBody::FindFrameDownwards(LPCWSTR pszTargetName, DWORD dwFlags, IUnknown **ppunkTargetFrame)
  5277. {
  5278. if (ppunkTargetFrame)
  5279. *ppunkTargetFrame=NULL;
  5280. return E_NOTIMPL;
  5281. }
  5282. HRESULT CBody::FindFrameInContext(LPCWSTR pszTargetName, IUnknown *punkContextFrame, DWORD dwFlags, IUnknown **ppunkTargetFrame)
  5283. {
  5284. return DoFindFrameInContext(m_lpOleObj, (IUnknown *)(IPropertyNotifySink *)this,
  5285. pszTargetName, punkContextFrame, dwFlags, ppunkTargetFrame);
  5286. }
  5287. HRESULT CBody::OnChildFrameActivate(IUnknown *pUnkChildFrame)
  5288. {
  5289. return S_OK;
  5290. }
  5291. HRESULT CBody::OnChildFrameDeactivate(IUnknown *pUnkChildFrame)
  5292. {
  5293. return S_OK;
  5294. }
  5295. HRESULT CBody::NavigateHack(DWORD grfHLNF,LPBC pbc, IBindStatusCallback *pibsc, LPCWSTR pszTargetName, LPCWSTR pszUrl, LPCWSTR pszLocation)
  5296. {
  5297. return E_NOTIMPL;
  5298. }
  5299. HRESULT CBody::FindBrowserByIndex(DWORD dwID,IUnknown **ppunkBrowser)
  5300. {
  5301. if (ppunkBrowser)
  5302. *ppunkBrowser=NULL;
  5303. return E_NOTIMPL;
  5304. }
  5305. HRESULT CBody::ApplyDocumentVerb(VARIANTARG *pvaIn)
  5306. {
  5307. HRESULT hr;
  5308. IHTMLDocument2 *pDoc=0;
  5309. TraceCall("CBody::ApplyDocumentVerb");
  5310. if(pvaIn && pvaIn->vt==VT_UNKNOWN && pvaIn->punkVal)
  5311. pvaIn->punkVal->QueryInterface(IID_IHTMLDocument2, (LPVOID *)&pDoc);
  5312. hr = ApplyDocument(pDoc);
  5313. ReleaseObj(pDoc);
  5314. return hr;
  5315. }
  5316. HRESULT CBody::ApplyDocument(IHTMLDocument2 *pDocStationery)
  5317. {
  5318. HRESULT hr;
  5319. TraceCall("CBody::ApplyDocument");
  5320. if(pDocStationery)
  5321. {
  5322. hr = HrCopyStyleSheets(pDocStationery, m_pDoc);
  5323. if (!FAILED(hr))
  5324. hr = HrCopyBackground(pDocStationery, m_pDoc);
  5325. }
  5326. else
  5327. {
  5328. hr = HrRemoveStyleSheets(m_pDoc);
  5329. if (!FAILED(hr))
  5330. hr = HrRemoveBackground(m_pDoc);
  5331. }
  5332. return hr;
  5333. }
  5334. HRESULT CBody::OnWMCreate()
  5335. {
  5336. RecalcPreivewHeight(NULL);
  5337. return S_OK;
  5338. }
  5339. static const TBBUTTON g_rgBtnBarButtons[] = {
  5340. { itbBadSign, idmPaneBadSigning, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0, 2 },
  5341. { itbSigning, idmPaneSigning, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0, 0 },
  5342. { itbEncryption,idmPaneEncryption, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0, 1 },
  5343. { itbBadEnc, idmPaneBadEncryption, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0, 3 },
  5344. { itbVCard, idmPaneVCard, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0, 4 },
  5345. { itbPaperclip, idmPanePaperclip, TBSTATE_ENABLED, TBSTYLE_DROPDOWN, {0,0}, 0, 5 },
  5346. };
  5347. HRESULT CBody::InitToolbar()
  5348. {
  5349. TCHAR rgch[CCHMAX_STRINGRES];
  5350. DWORD dwBtnSize;
  5351. if (!m_hwndBtnBar)
  5352. {
  5353. Assert (!m_hIml);
  5354. Assert (!m_hImlHot);
  5355. m_hwndBtnBar = CreateWindowEx(0, TOOLBARCLASSNAME, NULL,
  5356. TBSTYLE_TRANSPARENT|TBSTYLE_FLAT|TBSTYLE_TOOLTIPS|WS_CHILD|WS_CLIPSIBLINGS|CCS_NODIVIDER|CCS_NORESIZE|CCS_NOPARENTALIGN,
  5357. 0, 0, 32, 100, m_hwnd, (HMENU)idcBtnBar, g_hInst, NULL);
  5358. if (!m_hwndBtnBar)
  5359. return E_FAIL;
  5360. m_hIml = ImageList_LoadImage(g_hLocRes, MAKEINTRESOURCE(idbPaneBar32), CX_PANEICON, 0, RGB(255, 0, 255), IMAGE_BITMAP, LR_LOADMAP3DCOLORS|LR_CREATEDIBSECTION);
  5361. if (!m_hIml)
  5362. return E_OUTOFMEMORY;
  5363. SendMessage(m_hwndBtnBar, TB_SETIMAGELIST, 0, (LPARAM)m_hIml);
  5364. m_hImlHot = ImageList_LoadImage(g_hLocRes, MAKEINTRESOURCE(idbPaneBar32Hot), CX_PANEICON, 0, RGB(255, 0, 255), IMAGE_BITMAP, LR_LOADMAP3DCOLORS|LR_CREATEDIBSECTION);
  5365. if (!m_hImlHot)
  5366. return E_OUTOFMEMORY;
  5367. SendMessage(m_hwndBtnBar, TB_SETHOTIMAGELIST, 0, (LPARAM)m_hImlHot);
  5368. SendMessage(m_hwndBtnBar, TB_SETMAXTEXTROWS, 0, 0L);
  5369. SendMessage(m_hwndBtnBar, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
  5370. SendMessage(m_hwndBtnBar, TB_ADDBUTTONS, ARRAYSIZE(g_rgBtnBarButtons), (LPARAM)g_rgBtnBarButtons);
  5371. if (LoadString(g_hLocRes, idsBtnBarTTList, rgch, ARRAYSIZE(rgch)))
  5372. {
  5373. ReplaceChars(rgch, '|', '\0');
  5374. SendMessage(m_hwndBtnBar, TB_ADDSTRING, 0, (LPARAM)rgch);
  5375. }
  5376. m_cVisibleBtns = 0;
  5377. // set the initial height of the toolbar, based on the button size
  5378. dwBtnSize = (DWORD) SendMessage(m_hwndBtnBar, TB_GETBUTTONSIZE, 0, 0);
  5379. SetWindowPos(m_hwndBtnBar, NULL, 0, 0, 0, HIWORD(dwBtnSize), SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOZORDER|SWP_NOMOVE);
  5380. // now that we have setup the button height, recalc the preview header height
  5381. RecalcPreivewHeight(NULL);
  5382. Resize();
  5383. }
  5384. return S_OK;
  5385. }
  5386. HRESULT CBody::UpdateButtons()
  5387. {
  5388. ULONG dwBtnSize,
  5389. uBtn;
  5390. OLECMD rgSecureCmds[]={{OECSECCMD_ENCRYPTED, 0},
  5391. {OECSECCMD_SIGNED, 0}};
  5392. RECT rc;
  5393. int cxBar;
  5394. Assert (m_hwndBtnBar);
  5395. // hide all the buttons
  5396. m_cVisibleBtns=0;
  5397. for (uBtn = 0; uBtn < ARRAYSIZE(g_rgBtnBarButtons); uBtn++)
  5398. SendMessage(m_hwndBtnBar, TB_HIDEBUTTON, g_rgBtnBarButtons[uBtn].idCommand, MAKELONG(TRUE, 0));
  5399. // turn on the applicable buttons.
  5400. if (m_pAttMenu && m_pAttMenu->HasAttach()==S_OK)
  5401. {
  5402. SendMessage(m_hwndBtnBar, TB_HIDEBUTTON, idmPanePaperclip, MAKELONG(FALSE, 0));
  5403. m_cVisibleBtns++;
  5404. }
  5405. if (m_pAttMenu && m_pAttMenu->HasVCard()==S_OK)
  5406. {
  5407. SendMessage(m_hwndBtnBar, TB_HIDEBUTTON, idmPaneVCard, MAKELONG(FALSE, 0));
  5408. m_cVisibleBtns++;
  5409. }
  5410. // see if the host supports our private S/Mime functionality
  5411. // we query the host for the security state of the message, this can take one of 3 forms for both
  5412. // signed and ecrypted: (none, good or bad) represented by (OLECMDF_INVISIBLE, OLECMDF_ENABLED, and OLECMDF_DISABLED)
  5413. // respectivley
  5414. if (m_pParentCmdTarget)
  5415. {
  5416. if (m_pParentCmdTarget->QueryStatus(&CMDSETID_OESecurity, ARRAYSIZE(rgSecureCmds), rgSecureCmds, NULL)==S_OK)
  5417. {
  5418. if (rgSecureCmds[0].cmdf & OLECMDF_SUPPORTED && !(rgSecureCmds[0].cmdf & OLECMDF_INVISIBLE))
  5419. {
  5420. SendMessage(m_hwndBtnBar, TB_HIDEBUTTON, rgSecureCmds[0].cmdf & OLECMDF_ENABLED ? idmPaneEncryption : idmPaneBadEncryption, MAKELONG(FALSE, 0));
  5421. m_cVisibleBtns++;
  5422. }
  5423. if (rgSecureCmds[1].cmdf & OLECMDF_SUPPORTED && !(rgSecureCmds[1].cmdf & OLECMDF_INVISIBLE))
  5424. {
  5425. SendMessage(m_hwndBtnBar, TB_HIDEBUTTON, rgSecureCmds[1].cmdf & OLECMDF_ENABLED ? idmPaneSigning : idmPaneBadSigning, MAKELONG(FALSE, 0));
  5426. m_cVisibleBtns++;
  5427. }
  5428. }
  5429. }
  5430. // size the toolbar based on the number of visible buttons
  5431. dwBtnSize = (DWORD) SendMessage(m_hwndBtnBar, TB_GETBUTTONSIZE, 0, 0);
  5432. cxBar = LOWORD(dwBtnSize)*m_cVisibleBtns;
  5433. GetClientRect(m_hwnd, &rc);
  5434. AssertSz(m_cyPreview >= HIWORD(dwBtnSize), "preview header is too small for the button bar");
  5435. SetWindowPos(m_hwndBtnBar, NULL, rc.right - cxBar, (m_cyPreview - HIWORD(dwBtnSize))/2, LOWORD(dwBtnSize)*m_cVisibleBtns, HIWORD(dwBtnSize),SWP_NOACTIVATE|SWP_NOOWNERZORDER|SWP_NOZORDER|SWP_SHOWWINDOW);
  5436. return S_OK;
  5437. }
  5438. HRESULT CBody::ShowAttachMenu(BOOL fRightClick)
  5439. {
  5440. POINT pt;
  5441. PointFromButton(idmPanePaperclip, &pt);
  5442. if (m_pAttMenu && m_pAttMenu->HasAttach()==S_OK)
  5443. m_pAttMenu->Show(m_hwnd, &pt, fRightClick);
  5444. return S_OK;
  5445. }
  5446. HRESULT CBody::ShowPreview(BOOL fOn)
  5447. {
  5448. if (fOn)
  5449. {
  5450. UpdatePreviewLabels();
  5451. // if user turns on the preview pane after loaded, then defer-create the attachment menu
  5452. if (m_fMessageParsed)
  5453. UpdateBtnBar();
  5454. }
  5455. if (m_hwndBtnBar)
  5456. ShowWindow(m_hwndBtnBar, fOn?SW_SHOW:SW_HIDE);
  5457. return S_OK;
  5458. }
  5459. HRESULT CBody::PointFromButton(int idm, POINT *ppt)
  5460. {
  5461. RECT rc;
  5462. if (!SendMessage(m_hwndBtnBar, TB_GETRECT, idm, (LPARAM)&rc))
  5463. return E_FAIL;
  5464. ppt->x = rc.right;
  5465. ppt->y = rc.bottom;
  5466. ClientToScreen(m_hwndBtnBar, ppt);
  5467. return S_OK;
  5468. }
  5469. HRESULT CBody::UpdateBtnBar()
  5470. {
  5471. HRESULT hr;
  5472. // create the attachment menu. This will be destroyed on every load/unload to reflect the new state of the
  5473. // message
  5474. if (!m_pAttMenu && m_pMsg)
  5475. {
  5476. hr = EnsureAttMenu();
  5477. if (FAILED(hr))
  5478. goto error;
  5479. }
  5480. // make sure the button bar is created. This will be created once per preview pane
  5481. hr = InitToolbar();
  5482. if (FAILED(hr))
  5483. goto error;
  5484. hr = UpdateButtons();
  5485. error:
  5486. return hr;
  5487. }
  5488. HRESULT CBody::EnsureAttMenu()
  5489. {
  5490. HRESULT hr=S_OK;
  5491. if (!m_pAttMenu && m_pMsg)
  5492. {
  5493. m_pAttMenu = new CAttMenu();
  5494. if (!m_pAttMenu)
  5495. return E_OUTOFMEMORY;
  5496. hr = m_pAttMenu->Init(m_pMsg, m_pFontCache, m_pParentInPlaceFrame, m_pParentCmdTarget);
  5497. if (FAILED(hr))
  5498. goto error;
  5499. }
  5500. error:
  5501. return hr;
  5502. }
  5503. HRESULT HrSniffUrlForRfc822(LPWSTR pszUrlW)
  5504. {
  5505. LPWSTR lpszW;
  5506. HRESULT hr = S_FALSE;
  5507. if (!FAILED(FindMimeFromData(NULL, pszUrlW, NULL, NULL, NULL, NULL, &lpszW, 0)))
  5508. {
  5509. if (StrCmpW(lpszW, L"message/rfc822")==0)
  5510. hr = S_OK;
  5511. CoTaskMemFree(lpszW);
  5512. }
  5513. return hr;
  5514. }
  5515. HRESULT CBody::SaveAttachments()
  5516. {
  5517. return SaveAttachmentsWithPath(m_hwnd, m_pParentCmdTarget, m_pMsg);
  5518. }
  5519. HRESULT CBody::InsertBackgroundSound()
  5520. {
  5521. ULONG cRepeat;
  5522. BSTR bstrUrl;
  5523. BGSOUNDDLG rBGSound;
  5524. rBGSound.wszUrl[0]=0; // null string
  5525. rBGSound.cRepeat = 1; // default to 1 repeat
  5526. if (GetBackgroundSound(m_pDoc, &rBGSound.cRepeat, &bstrUrl)==S_OK)
  5527. {
  5528. StrCpyNW(rBGSound.wszUrl, bstrUrl, ARRAYSIZE(rBGSound.wszUrl));
  5529. SysFreeString(bstrUrl);
  5530. }
  5531. if (S_OK == DoBackgroundSoundDlg(m_hwnd, &rBGSound))
  5532. {
  5533. bstrUrl = SysAllocString(rBGSound.wszUrl);
  5534. if (bstrUrl)
  5535. {
  5536. SetBackgroundSound(m_pDoc, rBGSound.cRepeat, bstrUrl);
  5537. SysFreeString(bstrUrl);
  5538. }
  5539. }
  5540. return S_OK;
  5541. }
  5542. HRESULT CBody::EnableSounds(BOOL fOn)
  5543. {
  5544. VARIANTARG va;
  5545. va.vt = VT_I4;
  5546. va.lVal = fOn;
  5547. if (m_pCmdTarget)
  5548. m_pCmdTarget->Exec(&CMDSETID_Forms3, IDM_ENABLE_INTERACTION, NULL, &va, NULL);
  5549. return S_OK;
  5550. }
  5551. HRESULT CBody::ShowSourceTabs(BOOL fOn)
  5552. {
  5553. TC_ITEM tci;
  5554. HFONT hFont;
  5555. TCHAR rgch[CCHMAX_STRINGRES];
  5556. WNDCLASSEX wc;
  5557. int i;
  5558. if (fOn == m_fSrcTabs)
  5559. return S_OK;
  5560. if (!fOn && m_hwndTab)
  5561. {
  5562. // if turning off, make sure we got back to edit-mode
  5563. SetSourceTabs(MEST_EDIT);
  5564. }
  5565. if (m_hwndTab)
  5566. { // already created
  5567. ShowWindow(m_hwndTab, fOn?SW_SHOW:SW_HIDE);
  5568. goto exit;
  5569. }
  5570. m_hwndTab = CreateWindowEx(0,
  5571. WC_TABCONTROL,
  5572. NULL,
  5573. WS_CHILD|WS_TABSTOP|WS_VISIBLE|TCS_BOTTOM|TCS_FIXEDWIDTH,
  5574. 0, 0, 0, 0,
  5575. m_hwnd,
  5576. (HMENU)idcTabs,
  5577. g_hLocRes,
  5578. NULL);
  5579. if (!m_hwndTab)
  5580. return E_FAIL;
  5581. tci.mask = TCIF_TEXT;
  5582. for (i=MEST_EDIT; i<=MEST_PREVIEW; i++)
  5583. {
  5584. LoadString(g_hLocRes, idsEditTab+i, rgch, ARRAYSIZE(rgch));
  5585. tci.pszText = rgch;
  5586. TabCtrl_InsertItem(m_hwndTab, i, &tci);
  5587. }
  5588. if (m_pFontCache &&
  5589. m_pFontCache->GetFont(FNT_SYS_ICON, NULL, &hFont)==S_OK)
  5590. SendMessage(m_hwndTab, WM_SETFONT, (WPARAM)hFont, 0);
  5591. exit:
  5592. m_fSrcTabs = fOn;
  5593. Resize();
  5594. return S_OK;
  5595. }
  5596. HRESULT CBody::ShowSourceView(ULONG uSrcView)
  5597. {
  5598. IStream *pstm;
  5599. BOOL fFocus;
  5600. HRESULT hr=S_OK;
  5601. if (m_uSrcView == uSrcView) // noop
  5602. return S_OK;
  5603. /* store information about the current state. we care about
  5604. - who has focus
  5605. - caching the IStream of 'current' HTML
  5606. - dirty states
  5607. */
  5608. switch (m_uSrcView)
  5609. {
  5610. case MEST_EDIT:
  5611. // if switching away from edit-mode remember the dirty state
  5612. m_fWasDirty = IsDirty() == S_OK;
  5613. fFocus = m_fUIActive;
  5614. SafeRelease(m_pstmHtmlSrc);
  5615. GetBodyStream(m_pDoc, TRUE, &m_pstmHtmlSrc);
  5616. break;
  5617. case MEST_PREVIEW:
  5618. // m_pstmHtml is not saved from this mode, assume the previous setting
  5619. AssertSz(m_pstmHtmlSrc, "This should be set from a previous switch");
  5620. fFocus = m_fUIActive;
  5621. break;
  5622. case MEST_SOURCE:
  5623. // if switching away from source-mode remember the dirty state
  5624. Assert (m_pSrcView);
  5625. SafeRelease(m_pstmHtmlSrc);
  5626. m_pSrcView->Save(&m_pstmHtmlSrc);
  5627. m_fWasDirty = m_pSrcView->IsDirty() == S_OK;
  5628. fFocus = m_pSrcView->HasFocus()==S_OK;
  5629. break;
  5630. }
  5631. m_pDocView->UIActivate(FALSE);
  5632. // at this point m_pstmSrcHtml contains the new HTML source
  5633. switch (uSrcView)
  5634. {
  5635. case MEST_EDIT:
  5636. /* when switching to edit mode.
  5637. - reload trident
  5638. - ensure design-mode
  5639. - restore focus
  5640. - restore dirty state
  5641. - hide source-view (if shown)
  5642. */
  5643. SetDesignMode(TRUE);
  5644. _ReloadWithHtmlSrc(m_pstmHtmlSrc);
  5645. HrSetDirtyFlagImpl(m_pDoc, !!m_fWasDirty);
  5646. if (fFocus)
  5647. m_pDocView->UIActivate(TRUE);
  5648. if (m_pSrcView)
  5649. m_pSrcView->Show(FALSE, FALSE);
  5650. m_pDocView->Show(TRUE);
  5651. break;
  5652. case MEST_PREVIEW:
  5653. /* when switching to preview mode.
  5654. - reload trident
  5655. - ensure design-mode is OFF
  5656. - restore focus
  5657. - restore dirty state
  5658. - hide source-view (if shown)
  5659. */
  5660. SetDesignMode(FALSE);
  5661. _ReloadWithHtmlSrc(m_pstmHtmlSrc);
  5662. if (fFocus)
  5663. m_pDocView->UIActivate(TRUE);
  5664. if (m_pSrcView)
  5665. m_pSrcView->Show(FALSE, FALSE);
  5666. m_pDocView->Show(TRUE);
  5667. break;
  5668. case MEST_SOURCE:
  5669. /* when switching to source mode.
  5670. - defer-create the source view window (if needed)
  5671. - hide trident
  5672. - restore focus
  5673. - restore dirty state */
  5674. hr = _EnsureSrcView();
  5675. if (FAILED(hr))
  5676. goto error;
  5677. Assert (m_pSrcView);
  5678. m_pSrcView->Show(TRUE, IsColorSourceEditing()==S_OK);
  5679. m_pSrcView->Load(m_pstmHtmlSrc);
  5680. m_pSrcView->SetDirty(m_fWasDirty);
  5681. m_pDocView->Show(FALSE);
  5682. // restore focus
  5683. if (fFocus)
  5684. m_pSrcView->SetFocus();
  5685. break;
  5686. }
  5687. ShowFormatBar(uSrcView == MEST_EDIT && m_uHdrStyle == MESTYLE_FORMATBAR);
  5688. m_uSrcView = uSrcView;
  5689. Resize();
  5690. error:
  5691. return hr;
  5692. }
  5693. HRESULT CBody::SetSourceTabs(ULONG ulTab)
  5694. {
  5695. int rgNext[3] = {MEST_SOURCE, MEST_PREVIEW, MEST_EDIT},
  5696. rgPrev[3] = {MEST_PREVIEW, MEST_EDIT, MEST_SOURCE};
  5697. if (!m_fSrcTabs) // do nothing if not in source-tab-mode
  5698. return E_UNEXPECTED;
  5699. switch (ulTab)
  5700. {
  5701. case MEST_NEXT:
  5702. ulTab = rgNext[m_uSrcView];
  5703. break;
  5704. case MEST_PREVIOUS:
  5705. ulTab = rgPrev[m_uSrcView];
  5706. break;
  5707. case MEST_EDIT:
  5708. case MEST_SOURCE:
  5709. case MEST_PREVIEW:
  5710. break;
  5711. default:
  5712. return E_INVALIDARG;
  5713. }
  5714. Assert (((int) ulTab) >= MEST_EDIT && ((int) ulTab) <= MEST_PREVIEW);
  5715. ShowSourceView(ulTab);
  5716. TabCtrl_SetCurSel(m_hwndTab, ulTab);
  5717. return S_OK;
  5718. }
  5719. HRESULT CBody::IsColorSourceEditing()
  5720. {
  5721. VARIANTARG va;
  5722. if (m_pParentCmdTarget &&
  5723. m_pParentCmdTarget->Exec(&CMDSETID_MimeEditHost, MEHOSTCMDID_SOURCEEDIT_FLAGS, 0, NULL, &va)==S_OK &&
  5724. va.vt == VT_I4 &&
  5725. !(va.lVal & MESRCFLAGS_COLOR))
  5726. return S_FALSE;
  5727. return S_OK;
  5728. }
  5729. HRESULT CBody::HrCreateSpeller(BOOL fBkgrnd)
  5730. {
  5731. HRESULT hr;
  5732. VARIANTARG va;
  5733. if (m_pSpell)
  5734. return NOERROR;
  5735. #ifndef BACKGROUNDSPELL
  5736. // just to make sure background spelling is disabled
  5737. Assert(!fBkgrnd);
  5738. fBkgrnd = FALSE;
  5739. #endif // !BACKGROUNDSPELL
  5740. if (m_fDesignMode && m_pDoc && m_pParentCmdTarget && FCheckSpellAvail(m_pParentCmdTarget) &&
  5741. SUCCEEDED(m_pParentCmdTarget->Exec(&CMDSETID_MimeEditHost, MEHOSTCMDID_SPELL_OPTIONS, OLECMDEXECOPT_DODEFAULT, NULL, &va)))
  5742. {
  5743. if (((V_I4(&va) & MESPELLOPT_CHECKONTYPE) && fBkgrnd) || !fBkgrnd)
  5744. m_pSpell = new CSpell(m_pDoc, m_pParentCmdTarget, V_I4(&va));
  5745. }
  5746. if (m_pSpell)
  5747. {
  5748. if (!m_pSpell->OpenSpeller())
  5749. {
  5750. SafeRelease(m_pSpell);
  5751. return E_FAIL;
  5752. }
  5753. #ifdef BACKGROUNDSPELL
  5754. if (fBkgrnd)
  5755. {
  5756. SetTimer(m_hwnd, idTimerBkgrndSpell, BKGRNDSPELL_TICKTIME, NULL);
  5757. m_pSpell->HrRegisterKeyPressNotify(TRUE);
  5758. m_fBkgrndSpelling = TRUE;
  5759. }
  5760. #endif // BACKGROUNDSPELL
  5761. }
  5762. return m_pSpell ? NOERROR : E_FAIL;
  5763. }
  5764. HRESULT CBody::OnPreFontChange()
  5765. {
  5766. return S_OK;
  5767. }
  5768. HRESULT CBody::OnPostFontChange()
  5769. {
  5770. HFONT hFont;
  5771. RecalcPreivewHeight(NULL);
  5772. Resize();
  5773. // update the tabfont
  5774. if (m_hwndTab &&
  5775. m_pFontCache &&
  5776. m_pFontCache->GetFont(FNT_SYS_ICON, NULL, &hFont)==S_OK)
  5777. SendMessage(m_hwndTab, WM_SETFONT, (WPARAM)hFont, 0);
  5778. return S_OK;
  5779. }
  5780. extern BOOL g_fCanEditBiDi;
  5781. HRESULT CBody::HrFormatParagraph()
  5782. {
  5783. OLECMD rgCmds[]= { {IDM_JUSTIFYLEFT, 0}, // careful about ordering!!
  5784. {IDM_JUSTIFYRIGHT, 0},
  5785. {IDM_JUSTIFYCENTER, 0},
  5786. {IDM_JUSTIFYFULL, 0},
  5787. {IDM_ORDERLIST, 0},
  5788. {IDM_UNORDERLIST, 0},
  5789. {IDM_BLOCKDIRLTR, 0},
  5790. {IDM_BLOCKDIRRTL, 0}};
  5791. int rgidm[] = { idmFmtLeft, // careful about ordering!!
  5792. idmFmtRight,
  5793. idmFmtCenter,
  5794. idmFmtJustify,
  5795. idmFmtNumbers,
  5796. idmFmtBullets,
  5797. idmFmtBlockDirLTR,
  5798. idmFmtBlockDirRTL};
  5799. PARAPROP ParaProp;
  5800. int i;
  5801. if(FAILED(m_pCmdTarget->QueryStatus(&CMDSETID_Forms3, sizeof(rgCmds)/sizeof(OLECMD), rgCmds, NULL)))
  5802. return E_FAIL;
  5803. memset(&ParaProp, 0, sizeof(PARAPROP));
  5804. for(i = 0; i < 4; i++)
  5805. if(rgCmds[i].cmdf&OLECMDF_LATCHED)
  5806. ParaProp.group[0].iID=rgidm[i];
  5807. ParaProp.group[1].iID = idmFmtBulletsNone;
  5808. for(i = 4; i < 6; i++)
  5809. if(rgCmds[i].cmdf&OLECMDF_LATCHED)
  5810. ParaProp.group[1].iID=rgidm[i];
  5811. for(i = 6; i < 8; i++)
  5812. if(rgCmds[i].cmdf&OLECMDF_LATCHED)
  5813. ParaProp.group[2].iID=rgidm[i];
  5814. if(DialogBoxParam(g_hLocRes, MAKEINTRESOURCE(iddFormatPara), m_hwnd, FmtParaDlgProc, (LPARAM)&ParaProp)==IDOK)
  5815. {
  5816. // Dir attribute implies direction.
  5817. // lets change it first
  5818. for(i = g_fCanEditBiDi? 2 : 1; i > -1; i--)
  5819. if(ParaProp.group[i].bChanged)
  5820. {
  5821. OnWMCommand(m_hwnd, ParaProp.group[i].iID, 0);
  5822. }
  5823. }
  5824. return S_OK;
  5825. }
  5826. //+---------------------------------------------------------------
  5827. //
  5828. // Member: SearchForCIDUrls
  5829. //
  5830. // Synopsis: added to support MSPHONE. They send documents with
  5831. // multipart/related CID:foo.wav files, the URLs are renderd
  5832. // using an Active-Movive control embedded in the HTML.
  5833. // Trident never fires pluggable protocol requests for the
  5834. // urls and so we don't flag the attachments as rendered. Here we
  5835. // walk the document and try and find any CID's that are referenced
  5836. // in the HTML. APP requests get fired when the page goes oncomplete and
  5837. // the activex controls are activated.
  5838. //---------------------------------------------------------------
  5839. HRESULT CBody::SearchForCIDUrls()
  5840. {
  5841. HBODY hBody;
  5842. IMimeEditTagCollection *pCollect;
  5843. ULONG cFetched;
  5844. IMimeEditTag *pTag;
  5845. BSTR bstrSrc;
  5846. LPSTR pszUrlA,
  5847. pszBodyA;
  5848. // nothing todo if there is no multipart/related section
  5849. if (m_pMsg == NULL ||
  5850. MimeOleGetRelatedSection(m_pMsg, FALSE, &hBody, NULL)!=S_OK)
  5851. return S_OK;
  5852. // active-movie controls (for MSPHONE)
  5853. if (CreateActiveMovieCollection(m_pDoc, &pCollect)==S_OK)
  5854. {
  5855. pCollect->Reset();
  5856. while (pCollect->Next(1, &pTag, &cFetched)==S_OK && cFetched==1)
  5857. {
  5858. if (pTag->GetSrc(&bstrSrc)==S_OK)
  5859. {
  5860. pszUrlA = PszToANSI(CP_ACP, bstrSrc);
  5861. if (pszUrlA)
  5862. {
  5863. // if it's an MHTML: url then we have to fixup to get the cid:
  5864. // as ResolveURL won't recognize it
  5865. if (StrCmpNIA(pszUrlA, "mhtml:", 6)==0)
  5866. {
  5867. if (!FAILED(MimeOleParseMhtmlUrl(pszUrlA, NULL, &pszBodyA)))
  5868. {
  5869. // pszBody pszUrlA is guarnteed to be smaller
  5870. StrCpyN(pszUrlA, pszBodyA, lstrlen(pszUrlA)+1);
  5871. SafeMimeOleFree(pszBodyA);
  5872. }
  5873. }
  5874. m_pMsg->ResolveURL(NULL, NULL, pszUrlA, URL_RESOLVE_RENDERED, NULL);
  5875. MemFree(pszUrlA);
  5876. }
  5877. SysFreeString(bstrSrc);
  5878. }
  5879. pTag->Release();
  5880. }
  5881. pCollect->Release();
  5882. }
  5883. return S_OK;
  5884. }
  5885. HRESULT CBody::_ReloadWithHtmlSrc(IStream *pstm)
  5886. {
  5887. IMimeMessage *pMsg;
  5888. // if we're currently in HTML view, save the changes and reload trident
  5889. if (m_pMsg && pstm)
  5890. {
  5891. pMsg = m_pMsg;
  5892. pMsg->AddRef();
  5893. pMsg->SetTextBody(TXT_HTML, IET_INETCSET, NULL, pstm, NULL);
  5894. m_fReloadingSrc = TRUE;
  5895. Load(pMsg);
  5896. m_fLoading = FALSE;
  5897. pMsg->Release();
  5898. }
  5899. return S_OK;
  5900. }
  5901. HRESULT CBody::_EnsureSrcView()
  5902. {
  5903. HRESULT hr=S_OK;
  5904. if (!m_pSrcView)
  5905. {
  5906. m_pSrcView = new CMsgSource();
  5907. if (!m_pSrcView)
  5908. {
  5909. hr = E_OUTOFMEMORY;
  5910. goto error;
  5911. }
  5912. hr = m_pSrcView->Init(m_hwnd, idcSrcEdit, (IOleCommandTarget *)this);
  5913. if (FAILED(hr))
  5914. goto error;
  5915. }
  5916. error:
  5917. return hr;
  5918. }
  5919. /*
  5920. * Function: _OnSaveImage
  5921. *
  5922. * Purpose:
  5923. * if we're doing a SaveAs on an image, trident will not show the correct options in the save-as dialog
  5924. * unless the image is in the cache. For auto-inlined images, we changed the behaviour for OE5 to show
  5925. * them thro' the pluggable protocol. This is a hack to preload the cache with the pluggable protocol to
  5926. * the image. Note that we also need to delete the cache entry as the full URL is not persitable across sessions.
  5927. * ie: given the mhtml://mid:xxxxx!foobar.gif the mid: generated number is reused across OE sessions.
  5928. *
  5929. */
  5930. HRESULT CBody::_OnSaveImage()
  5931. {
  5932. IHTMLImgElement *pImg;
  5933. BSTR bstr=NULL;
  5934. LPSTR pszUrlA=NULL;
  5935. LPSTREAM pstm=NULL;
  5936. HRESULT hrCached=E_FAIL;
  5937. // try and get the image URL (m_pDispContext points to the object the context menu is acting on)
  5938. if (m_pDispContext &&
  5939. m_pDispContext->QueryInterface(IID_IHTMLImgElement, (LPVOID *)&pImg)==S_OK)
  5940. {
  5941. pImg->get_src(&bstr);
  5942. if (bstr)
  5943. {
  5944. pszUrlA = PszToANSI(CP_ACP, bstr);
  5945. SysFreeString(bstr);
  5946. }
  5947. pImg->Release();
  5948. }
  5949. // if this URL is in the mutlipart/related secion
  5950. if (!FAILED(HrFindUrlInMsg(m_pMsg, pszUrlA, 0, &pstm)))
  5951. {
  5952. DeleteUrlCacheEntryA(pszUrlA);
  5953. hrCached = CreateCacheFileFromStream(pszUrlA, pstm);
  5954. pstm->Release();
  5955. }
  5956. Assert (m_pCmdTarget);
  5957. m_pCmdTarget->Exec(&CMDSETID_Forms3, IDM_SAVEPICTURE, OLECMDEXECOPT_DODEFAULT, NULL, NULL);
  5958. // if we successfully cached this URL, be sure to remove it once the save is complete.
  5959. if (SUCCEEDED(hrCached))
  5960. DeleteUrlCacheEntryA(pszUrlA);
  5961. MemFree(pszUrlA);
  5962. return S_OK;
  5963. }
  5964. CVerHost::CVerHost()
  5965. {
  5966. m_cRef=1;
  5967. }
  5968. CVerHost::~CVerHost()
  5969. {
  5970. }
  5971. HRESULT CVerHost::QueryInterface(REFIID riid, LPVOID FAR *lplpObj)
  5972. {
  5973. if(!lplpObj)
  5974. return E_INVALIDARG;
  5975. *lplpObj = NULL;
  5976. if (IsEqualIID(riid, IID_IUnknown) || IsEqualIID(riid, IID_IVersionHost))
  5977. *lplpObj = (IVersionHost *) this;
  5978. else
  5979. return E_NOINTERFACE;
  5980. AddRef();
  5981. return NOERROR;
  5982. }
  5983. ULONG CVerHost::AddRef()
  5984. {
  5985. return ++m_cRef;
  5986. }
  5987. ULONG CVerHost::Release()
  5988. {
  5989. if (--m_cRef==0)
  5990. {
  5991. delete this;
  5992. return 0;
  5993. }
  5994. return m_cRef;
  5995. }
  5996. HRESULT CVerHost::QueryUseLocalVersionVector(BOOL *fUseLocal)
  5997. {
  5998. *fUseLocal = TRUE;
  5999. return S_OK;
  6000. }
  6001. HRESULT CVerHost::QueryVersionVector(IVersionVector *pVersion)
  6002. {
  6003. if (pVersion == NULL)
  6004. return E_INVALIDARG;
  6005. return pVersion->SetVersion(L"VML", NULL);
  6006. }