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.

3728 lines
116 KiB

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Copyright (C) 1993-1998 Microsoft Corporation. All Rights Reserved.
  3. //
  4. // MODULE: msgview.cpp
  5. //
  6. // PURPOSE: Implements the Outlook Express view class that handles
  7. // displaying the contents of folders with messages.
  8. //
  9. #include "pch.hxx"
  10. #include "msgview.h"
  11. #include "browser.h"
  12. #include "thormsgs.h"
  13. #include "msglist.h"
  14. #include "msoedisp.h"
  15. #include "statbar.h"
  16. #include "ibodyobj.h"
  17. #include "mehost.h"
  18. #include "util.h"
  19. #include "shlwapip.h"
  20. #include "menuutil.h"
  21. #include "storutil.h"
  22. #include "ruleutil.h"
  23. #include "note.h"
  24. #include "newsutil.h"
  25. #include "menures.h"
  26. #include "ipab.h"
  27. #include "order.h"
  28. #include <inetcfg.h>
  29. #include "instance.h"
  30. /////////////////////////////////////////////////////////////////////////////
  31. // Global Data
  32. //
  33. static const char s_szMessageViewWndClass[] = TEXT("Outlook Express Message View");
  34. extern BOOL g_fBadShutdown;
  35. /////////////////////////////////////////////////////////////////////////////
  36. // Prototypes
  37. //
  38. /////////////////////////////////////////////////////////////////////////////
  39. // Message Macros
  40. //
  41. // void OnPostCreate(HWND hwnd)
  42. #define HANDLE_WM_POSTCREATE(hwnd, wParam, lParam, fn) \
  43. ((fn)(hwnd), 0L)
  44. #define FORWARD_WM_POSTCREATE(hwnd, fn) \
  45. (void)(fn)((hwnd), WM_POSTCREATE, 0L, 0L)
  46. // LRESULT OnTestGetMsgId(HWND hwnd)
  47. #define HANDLE_WM_TEST_GETMSGID(hwnd, wParam, lParam, fn) \
  48. (LRESULT)((fn)(hwnd))
  49. #define FORWARD_WM_TEST_GETMSGID(hwnd, fn) \
  50. (LRESULT)(fn)((hwnd), WM_TEST_GETMSGID, 0L, 0L)
  51. // LRESULT OnTestSaveMessage(HWND hwnd)
  52. #define HANDLE_WM_TEST_SAVEMSG(hwnd, wParam, lParam, fn) \
  53. (LRESULT)((fn)(hwnd))
  54. #define FORWARD_WM_TEST_SAVEMSG(hwnd, fn) \
  55. (LRESULT)(fn)((hwnd), WM_TEST_SAVEMSG, 0L, 0L)
  56. /////////////////////////////////////////////////////////////////////////////
  57. // Constructors, Destructors, and Initialization
  58. //
  59. CMessageView::CMessageView()
  60. {
  61. m_cRef = 1;
  62. m_hwnd = NULL;
  63. m_hwndParent = NULL;
  64. m_pBrowser = NULL;
  65. m_idFolder = FOLDERID_INVALID;
  66. m_pDropTarget = NULL;
  67. m_pMsgList = NULL;
  68. m_pMsgListCT = NULL;
  69. m_pMsgListAO = NULL;
  70. m_dwCookie = 0;
  71. m_pServer = NULL;
  72. m_pPreview = NULL;
  73. m_pPreviewCT = NULL;
  74. m_fSplitHorz = TRUE;
  75. SetRect(&m_rcSplit, 0, 0, 0, 0);
  76. m_dwSplitVertPct = 50;
  77. m_dwSplitHorzPct = 50;
  78. m_fDragging = FALSE;
  79. m_uUIState = SVUIA_DEACTIVATE;
  80. m_cUnread = 0;
  81. m_cItems = 0;
  82. m_pGroups = NULL;
  83. m_idMessageFocus = MESSAGEID_INVALID;
  84. m_pProgress = NULL;
  85. m_fNotDownloaded = FALSE;
  86. m_cLastChar = GetTickCount();
  87. m_pViewMenu = NULL;
  88. }
  89. CMessageView::~CMessageView()
  90. {
  91. SafeRelease(m_pViewMenu);
  92. if (m_pGroups != NULL)
  93. {
  94. m_pGroups->Close();
  95. m_pGroups->Release();
  96. }
  97. SafeRelease(m_pBrowser);
  98. SafeRelease(m_pMsgList);
  99. SafeRelease(m_pMsgListCT);
  100. SafeRelease(m_pMsgListAO);
  101. SafeRelease(m_pPreview);
  102. SafeRelease(m_pPreviewCT);
  103. SafeRelease(m_pProgress);
  104. SafeRelease(m_pDropTarget);
  105. Assert(NULL == m_pServer);
  106. }
  107. //
  108. // FUNCTION: CMessageView::Initialize()
  109. //
  110. // PURPOSE: Get's called to initialize the object and tell it what folder
  111. // it will be looking at.
  112. //
  113. // PARAMETERS:
  114. // [in] pidl
  115. // [in] *pFolder
  116. //
  117. // RETURN VALUE:
  118. // HRESULT
  119. //
  120. HRESULT CMessageView::Initialize(FOLDERID idFolder)
  121. {
  122. TraceCall("CMessageView::Initialize");
  123. // Copy the pidl, we'll use it later
  124. m_idFolder = idFolder;
  125. return (S_OK);
  126. }
  127. /////////////////////////////////////////////////////////////////////////////
  128. // IUnknown
  129. //
  130. HRESULT CMessageView::QueryInterface(REFIID riid, LPVOID *ppvObj)
  131. {
  132. *ppvObj = NULL;
  133. if (IsEqualIID(riid, IID_IUnknown))
  134. *ppvObj = (LPVOID) (IUnknown *) (IViewWindow *) this;
  135. else if (IsEqualIID(riid, IID_IOleWindow))
  136. *ppvObj = (LPVOID) (IViewWindow *) this;
  137. else if (IsEqualIID(riid, IID_IViewWindow))
  138. *ppvObj = (LPVOID) (IViewWindow *) this;
  139. else if (IsEqualIID(riid, IID_IMessageWindow))
  140. *ppvObj = (LPVOID) (IMessageWindow *) this;
  141. else if (IsEqualIID(riid, IID_IOleCommandTarget))
  142. *ppvObj = (LPVOID) (IOleCommandTarget *) this;
  143. else if (IsEqualIID(riid, IID_IBodyOptions))
  144. *ppvObj = (LPVOID) (IBodyOptions *) this;
  145. else if (IsEqualIID(riid, IID_IDispatch))
  146. *ppvObj = (LPVOID) (IDispatch *) this;
  147. else if (IsEqualIID(riid, DIID__MessageListEvents))
  148. *ppvObj = (LPVOID) (IDispatch *) this;
  149. else if (IsEqualIID(riid, IID_IServerInfo))
  150. *ppvObj = (LPVOID) (IServerInfo *) this;
  151. if (NULL == *ppvObj)
  152. return (E_NOINTERFACE);
  153. AddRef();
  154. return S_OK;
  155. }
  156. ULONG CMessageView::AddRef(void)
  157. {
  158. return InterlockedIncrement((LONG *) &m_cRef);
  159. }
  160. ULONG CMessageView::Release(void)
  161. {
  162. InterlockedDecrement((LONG *) &m_cRef);
  163. if (0 == m_cRef)
  164. {
  165. delete this;
  166. return (0);
  167. }
  168. return (m_cRef);
  169. }
  170. /////////////////////////////////////////////////////////////////////////////
  171. // IOleWindow
  172. //
  173. HRESULT CMessageView::GetWindow(HWND *pHwnd)
  174. {
  175. if (!pHwnd)
  176. return (E_INVALIDARG);
  177. if (m_hwnd)
  178. {
  179. *pHwnd = m_hwnd;
  180. return (S_OK);
  181. }
  182. return (E_FAIL);
  183. }
  184. HRESULT CMessageView::ContextSensitiveHelp(BOOL fEnterMode)
  185. {
  186. return (E_NOTIMPL);
  187. }
  188. /////////////////////////////////////////////////////////////////////////////
  189. // IViewWindow
  190. //
  191. //
  192. // FUNCTION: CMessageView::TranslateAccelerator()
  193. //
  194. // PURPOSE: Called by the frame window to give us first crack at messages.
  195. //
  196. // PARAMETERS:
  197. // [in] pMsg - The current message to be processed.
  198. //
  199. // RETURN VALUE:
  200. // S_OK if the message was handled here and should not be processed further.
  201. // S_FALSE if the message should continued to be processed elsewhere.
  202. //
  203. HRESULT CMessageView::TranslateAccelerator(LPMSG pMsg)
  204. {
  205. DWORD dwState = 0;
  206. // See if the Preview Pane is interested
  207. if (m_pPreview)
  208. {
  209. if (S_OK == m_pPreview->HrTranslateAccelerator(pMsg))
  210. return (S_OK);
  211. if (IsChild(m_hwnd, GetFocus()))
  212. {
  213. if (pMsg->message == WM_KEYDOWN && pMsg->wParam != VK_SPACE)
  214. m_cLastChar = GetTickCount();
  215. if (pMsg->message == WM_KEYDOWN &&
  216. pMsg->wParam == VK_SPACE &&
  217. GetTickCount() - m_cLastChar > 1000)
  218. {
  219. if (m_fNotDownloaded)
  220. {
  221. _UpdatePreviewPane(TRUE);
  222. }
  223. else if (SUCCEEDED(m_pMsgList->GetFocusedItemState(&dwState)) && dwState != 0)
  224. {
  225. if (m_pPreview->HrScrollPage()!=S_OK)
  226. m_pMsgListCT->Exec(NULL, ID_SPACE_ACCEL, 0, NULL, NULL);
  227. }
  228. else
  229. m_pMsgListCT->Exec(NULL, ID_SPACE_ACCEL, 0, NULL, NULL);
  230. return S_OK;
  231. }
  232. }
  233. }
  234. // See if the message list is interested
  235. if (m_pMsgListAO)
  236. {
  237. if (S_OK == m_pMsgListAO->TranslateAccelerator(pMsg))
  238. return (S_OK);
  239. }
  240. return (S_FALSE);
  241. }
  242. //
  243. // FUNCTION: CMessageView::UIActivate()
  244. //
  245. // PURPOSE: Called to notify the view when different activation and
  246. // deactivation events occur.
  247. //
  248. // PARAMETERS:
  249. // [in] uState - SVUIA_ACTIVATE_FOCUS, SVUIA_ACTIVATE_NOFOCUS, and
  250. // SVUIA_DEACTIVATE.
  251. //
  252. // RETURN VALUE:
  253. // Returns S_OK all the time.
  254. //
  255. HRESULT CMessageView::UIActivate(UINT uState)
  256. {
  257. if (uState != SVUIA_DEACTIVATE)
  258. {
  259. // If the focus stays within our frame, bug goes outside our view,
  260. // i.e. the folder list get's focus, then we get an
  261. // SVUIA_ACTIVATE_NOFOCUS. We need to UI Deactivate the preview
  262. // pane when this happens.
  263. if (uState == SVUIA_ACTIVATE_NOFOCUS && m_pPreview)
  264. m_pPreview->HrUIActivate(FALSE);
  265. if (m_uUIState != uState)
  266. {
  267. // Update our internal state
  268. m_uUIState = uState;
  269. // Update the toolbar state
  270. m_pBrowser->UpdateToolbar();
  271. }
  272. }
  273. else
  274. {
  275. // Only deactivate if we're not already deactivated
  276. if (m_uUIState != SVUIA_DEACTIVATE)
  277. {
  278. // Update our internal state
  279. m_uUIState = uState;
  280. }
  281. }
  282. return (S_OK);
  283. }
  284. //
  285. // FUNCTION: CMessageView::CreateViewWindow()
  286. //
  287. // PURPOSE: Called when it's time for the view to create it's window.
  288. //
  289. // PARAMETERS:
  290. // [in] pPrevView - Pointer to the previous view if there was one
  291. // [in] pBrowser - Pointer to the browser that hosts this view
  292. // [in] prcView - Initial position and size of the view
  293. // [out] pHwnd - Returns the HWND of the newly created view window
  294. //
  295. // RETURN VALUE:
  296. // S_OK if the view window was created successfully.
  297. // E_FAIL if the window couldn't be created for some reason or another.
  298. //
  299. HRESULT CMessageView::CreateViewWindow(IViewWindow *pPrevView, IAthenaBrowser *pBrowser,
  300. RECT *prcView, HWND *pHwnd)
  301. {
  302. WNDCLASS wc;
  303. // Without a browser pointer nothing will ever work.
  304. if (!pBrowser)
  305. return (E_INVALIDARG);
  306. // Hang on to the browser pointer
  307. m_pBrowser = pBrowser;
  308. m_pBrowser->AddRef();
  309. // Get the window handle of the browser
  310. m_pBrowser->GetWindow(&m_hwndParent);
  311. Assert(IsWindow(m_hwndParent));
  312. // Load our persisted settings. If this fails will just run with defaults.
  313. // _LoadSettings();
  314. // Register our window class if we haven't already
  315. if (!GetClassInfo(g_hInst, s_szMessageViewWndClass, &wc))
  316. {
  317. wc.style = 0;
  318. wc.lpfnWndProc = CMessageView::ViewWndProc;
  319. wc.cbClsExtra = 0;
  320. wc.cbWndExtra = 0;
  321. wc.hInstance = g_hInst;
  322. wc.hIcon = NULL;
  323. wc.hCursor = NULL;
  324. wc.hbrBackground = (HBRUSH) (COLOR_3DFACE + 1);
  325. wc.lpszMenuName = NULL;
  326. wc.lpszClassName = s_szMessageViewWndClass;
  327. if (!RegisterClass(&wc))
  328. return (E_FAIL);
  329. }
  330. // Create the view window
  331. m_hwnd = CreateWindowEx(WS_EX_CONTROLPARENT , s_szMessageViewWndClass, NULL,
  332. WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
  333. prcView->left, prcView->top, prcView->right - prcView->left,
  334. prcView->bottom - prcView->top, m_hwndParent, NULL,
  335. g_hInst, (LPVOID) this);
  336. if (!m_hwnd)
  337. return (E_FAIL);
  338. *pHwnd = m_hwnd;
  339. // Get the message folder object from the previous folder here.
  340. _ReuseMessageFolder(pPrevView);
  341. return (S_OK);
  342. }
  343. //
  344. // FUNCTION: CMessageView::DestroyViewWindow()
  345. //
  346. // PURPOSE: Called by the browser to destroy the view window.
  347. //
  348. // RETURN VALUE:
  349. // S_OK is returned always.
  350. //
  351. HRESULT CMessageView::DestroyViewWindow(void)
  352. {
  353. // This is of course only interesting if we actually _have_ a window to
  354. // destroy.
  355. if (m_hwnd)
  356. {
  357. // Tell the message list we're done with this folder
  358. if (m_pMsgList)
  359. {
  360. m_pMsgList->SetFolder(FOLDERID_INVALID, NULL, 0, 0, 0);
  361. }
  362. // Unadvise our connection point
  363. if (m_dwCookie)
  364. {
  365. AtlUnadvise(m_pMsgList, DIID__MessageListEvents, m_dwCookie);
  366. m_dwCookie = 0;
  367. }
  368. // $REVIEW - PreDestroyViewWindow() used to be called here to tell the subclasses
  369. // of the iminent destruction.
  370. // Set our cached HWND to NULL before destroying prevents us from
  371. // handling notifications after important stuff has been freed.
  372. HWND hwndDest = m_hwnd;
  373. m_hwnd = NULL;
  374. DestroyWindow(hwndDest);
  375. }
  376. return (S_OK);
  377. }
  378. //
  379. // FUNCTION: CMessageView::SaveViewState()
  380. //
  381. // PURPOSE: Called by the browser to give the view a chance to save it's
  382. // settings before it is destroyed.
  383. //
  384. // RETURN VALUE:
  385. // E_NOTIMPL
  386. //
  387. HRESULT CMessageView::SaveViewState(void)
  388. {
  389. FOLDERTYPE ft = GetFolderType(m_idFolder);
  390. // Tell the message list to save it's state
  391. if (m_pMsgList)
  392. {
  393. m_pMsgList->OnClose();
  394. // We also need to save any settings that might have changed
  395. FOLDER_OPTIONS fo = { 0 };
  396. fo.cbSize = sizeof(FOLDER_OPTIONS);
  397. fo.dwMask = FOM_THREAD | FOM_OFFLINEPROMPT | FOM_SHOWDELETED | FOM_SHOWREPLIES;
  398. if (SUCCEEDED(m_pMsgList->GetViewOptions(&fo)))
  399. {
  400. switch (ft)
  401. {
  402. case FOLDER_NEWS:
  403. SetDwOption(OPT_NEWS_THREAD, fo.fThread, 0, 0);
  404. break;
  405. case FOLDER_LOCAL:
  406. case FOLDER_HTTPMAIL:
  407. SetDwOption(OPT_MAIL_THREAD, fo.fThread, 0, 0);
  408. break;
  409. case FOLDER_IMAP:
  410. SetDwOption(OPT_MAIL_THREAD, fo.fThread, 0, 0);
  411. break;
  412. }
  413. SetDwOption(OPT_SHOW_DELETED, (DWORD) (fo.fDeleted), 0, 0);
  414. SetDwOption(OPT_SHOW_REPLIES, (DWORD) (fo.fReplies), 0, 0);
  415. }
  416. }
  417. // Reset the contents of the status bar
  418. CStatusBar *pStatusBar;
  419. m_pBrowser->GetStatusBar(&pStatusBar);
  420. if (pStatusBar)
  421. {
  422. pStatusBar->SetStatusText("");
  423. pStatusBar->Release();
  424. }
  425. return (S_OK);
  426. }
  427. //
  428. // FUNCTION: CMessageView::OnPopupMenu()
  429. //
  430. // PURPOSE: Called whenever the frame receives a WM_INITMENUPOPUP
  431. // notification. The view adds any menu items or sets any
  432. // check marks that are appropriate.
  433. //
  434. // PARAMETERS:
  435. // [in] hMenu - The handle of the root menu bar
  436. // [in] hMenuPopup - The handle of the specific popup menu
  437. // [in] uID - The ID of the popup menu
  438. //
  439. // RETURN VALUE:
  440. // Unused
  441. //
  442. HRESULT CMessageView::OnPopupMenu(HMENU hMenu, HMENU hMenuPopup, UINT uID)
  443. {
  444. MENUITEMINFO mii;
  445. UINT uItem;
  446. HCHARSET hCharset;
  447. // Handle our items
  448. switch (uID)
  449. {
  450. case ID_POPUP_LANGUAGE:
  451. {
  452. mii.cbSize = sizeof(MENUITEMINFO);
  453. mii.fMask = MIIM_SUBMENU;
  454. UINT uiCodepage = 0;
  455. HMENU hLangMenu = NULL;
  456. m_pPreview->HrGetCharset(&hCharset);
  457. uiCodepage = CustomGetCPFromCharset(hCharset, TRUE);
  458. if(m_pBrowser->GetLanguageMenu(&hLangMenu, uiCodepage) == S_OK)
  459. {
  460. if(IsMenu(hMenuPopup))
  461. DestroyMenu(hMenuPopup);
  462. hMenuPopup = mii.hSubMenu = hLangMenu;
  463. SetMenuItemInfo(hMenu, ID_POPUP_LANGUAGE, FALSE, &mii);
  464. }
  465. break;
  466. }
  467. case ID_POPUP_VIEW:
  468. {
  469. if (NULL == m_pViewMenu)
  470. {
  471. // Create the view menu
  472. HrCreateViewMenu(0, &m_pViewMenu);
  473. }
  474. if (NULL != m_pViewMenu)
  475. {
  476. mii.cbSize = sizeof(MENUITEMINFO);
  477. mii.fMask = MIIM_SUBMENU;
  478. if (FALSE == GetMenuItemInfo(hMenuPopup, ID_POPUP_FILTER, FALSE, &mii))
  479. {
  480. break;
  481. }
  482. // Remove the old filter submenu
  483. if(IsMenu(mii.hSubMenu))
  484. DestroyMenu(mii.hSubMenu);
  485. // Replace the view menu
  486. if (FAILED(m_pViewMenu->HrReplaceMenu(0, hMenuPopup)))
  487. {
  488. break;
  489. }
  490. }
  491. break;
  492. }
  493. case ID_POPUP_FILTER:
  494. {
  495. if (NULL != m_pViewMenu)
  496. {
  497. m_pViewMenu->UpdateViewMenu(0, hMenuPopup, m_pMsgList);
  498. }
  499. break;
  500. }
  501. }
  502. // Let the message list update it's menus
  503. if (m_pMsgList)
  504. m_pMsgList->OnPopupMenu(hMenuPopup, uID);
  505. // Let the preview pane update it's menus
  506. if (m_pPreview)
  507. m_pPreview->HrOnInitMenuPopup(hMenuPopup, uID);
  508. return (S_OK);
  509. }
  510. HRESULT CMessageView::OnFrameWindowActivate(BOOL fActivate)
  511. {
  512. if (m_pPreview)
  513. return m_pPreview->HrFrameActivate(fActivate);
  514. return (S_OK);
  515. }
  516. HRESULT CMessageView::UpdateLayout(BOOL fVisible, BOOL fHeader, BOOL fVert,
  517. BOOL fUpdate)
  518. {
  519. // If we haven't created the preview pane yet, and the call is telling
  520. // us to make it visible, then we need to initialize it first.
  521. if (!m_pPreview && fVisible)
  522. {
  523. if (!_InitPreviewPane())
  524. return (E_UNEXPECTED);
  525. }
  526. // Header on / off
  527. if (m_pPreview)
  528. {
  529. m_pPreview->HrSetStyle(fHeader ? MESTYLE_PREVIEW : MESTYLE_MINIHEADER);
  530. }
  531. // Split direction
  532. if (m_pPreview)
  533. {
  534. RECT rcClient;
  535. m_fSplitHorz = !fVert;
  536. GetClientRect(m_hwnd, &rcClient);
  537. OnSize(m_hwnd, SIZE_RESTORED, rcClient.right, rcClient.bottom);
  538. }
  539. //
  540. // [PaulHi] 6/11/99 Raid 79491
  541. // Backing out this fix that BrettM made for Raid 63739 because of problems
  542. // with security message warnings.
  543. //
  544. #if 0
  545. if (fVisible)
  546. {
  547. // if showing update the preview pane
  548. _UpdatePreviewPane();
  549. }
  550. else
  551. {
  552. // if hiding, clear the contents
  553. if (NULL != m_pPreview)
  554. m_pPreview->HrUnloadAll(NULL, 0);
  555. }
  556. #endif
  557. return (S_OK);
  558. }
  559. HRESULT CMessageView::GetMessageList(IMessageList ** ppMsgList)
  560. {
  561. HRESULT hr = S_OK;
  562. // Check incoming params
  563. if (NULL == ppMsgList)
  564. {
  565. hr = E_INVALIDARG;
  566. goto exit;
  567. }
  568. // Initialize the outgoing param
  569. *ppMsgList = NULL;
  570. // Get the message list
  571. if (NULL != m_pMsgList)
  572. {
  573. *ppMsgList = m_pMsgList;
  574. (*ppMsgList)->AddRef();
  575. }
  576. // Set the return value
  577. hr = (NULL == *ppMsgList) ? S_FALSE : S_OK;
  578. exit:
  579. return hr;
  580. }
  581. HRESULT CMessageView::GetCurCharSet(UINT *cp)
  582. {
  583. HCHARSET hCharset;
  584. if(_IsPreview())
  585. {
  586. m_pPreview->HrGetCharset(&hCharset);
  587. *cp = CustomGetCPFromCharset(hCharset, TRUE);
  588. }
  589. else
  590. *cp = GetACP();
  591. return S_OK;
  592. }
  593. //
  594. // FUNCTION: CMessageView::QueryStatus()
  595. //
  596. // PURPOSE: Called by the browser to determine if a list of commands should
  597. // should be enabled or disabled.
  598. //
  599. // PARAMETERS:
  600. // [in] pguidCmdGroup - Group the commands are part of (unused)
  601. // [in] cCmds - Number of commands to be evaluated
  602. // [in] prgCmds - List of commands
  603. // [out] pCmdText - Description text for a command
  604. //
  605. // RETURN VALUE:
  606. // HRESULT
  607. //
  608. HRESULT CMessageView::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[],
  609. OLECMDTEXT *pCmdText)
  610. {
  611. DWORD cSel;
  612. HRESULT hr;
  613. HWND hwndFocus = GetFocus();
  614. BOOL fChildFocus = (hwndFocus != NULL && IsChild(m_hwnd, hwndFocus));
  615. DWORD cFocus;
  616. DWORD *rgSelected = 0;
  617. FOLDERTYPE ftType;
  618. // Let the sub objects look first
  619. if (m_pMsgListCT)
  620. {
  621. hr = m_pMsgListCT->QueryStatus(pguidCmdGroup, cCmds, prgCmds, pCmdText);
  622. }
  623. if (_IsPreview() && m_pPreviewCT)
  624. {
  625. hr = m_pPreviewCT->QueryStatus(pguidCmdGroup, cCmds, prgCmds, pCmdText);
  626. }
  627. // Up front some work
  628. m_pMsgList->GetSelected(&cFocus, &cSel, &rgSelected);
  629. // Now loop through the commands in the prgCmds array looking for ones the
  630. // sub objects didn't handle.
  631. for (UINT i = 0; i < cCmds; i++)
  632. {
  633. if (prgCmds[i].cmdf == 0)
  634. {
  635. // If this command is from the language menu
  636. if (prgCmds[i].cmdID >= ID_LANG_FIRST && prgCmds[i].cmdID <= ID_LANG_LAST)
  637. {
  638. HCHARSET hCharset;
  639. m_pPreview->HrGetCharset(&hCharset);
  640. // Enable only the supported languages
  641. if (prgCmds[i].cmdID < (UINT) (ID_LANG_FIRST + GetIntlCharsetLanguageCount()))
  642. {
  643. #if 0
  644. if(SetMimeLanguageCheckMark(CustomGetCPFromCharset(hCharset, TRUE), prgCmds[i].cmdID - ID_LANG_FIRST))
  645. prgCmds[i].cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED | OLECMDF_NINCHED;
  646. else
  647. prgCmds[i].cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
  648. #else
  649. prgCmds[i].cmdf = OLECMDF_SUPPORTED | SetMimeLanguageCheckMark(CustomGetCPFromCharset(hCharset, TRUE), prgCmds[i].cmdID - ID_LANG_FIRST);
  650. #endif
  651. }
  652. else
  653. prgCmds[i].cmdf = OLECMDF_SUPPORTED;
  654. continue;
  655. }
  656. // if the command id from the View.Current View menu
  657. if ((ID_VIEW_FILTER_FIRST <= prgCmds[i].cmdID) && (ID_VIEW_FILTER_LAST >= prgCmds[i].cmdID))
  658. {
  659. if (NULL == m_pViewMenu)
  660. {
  661. // Create the view menu
  662. HrCreateViewMenu(0, &m_pViewMenu);
  663. }
  664. if (NULL != m_pViewMenu)
  665. {
  666. m_pViewMenu->QueryStatus(m_pMsgList, &(prgCmds[i]));
  667. }
  668. continue;
  669. }
  670. // Look to see if it's a command we provide
  671. switch (prgCmds[i].cmdID)
  672. {
  673. case ID_OPEN:
  674. {
  675. // Enabled only if the focus is in the ListView and there
  676. // is at least one item selected.
  677. m_pMsgList->GetSelectedCount(&cSel);
  678. if (cSel)
  679. prgCmds[i].cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
  680. else
  681. prgCmds[i].cmdf = OLECMDF_SUPPORTED;
  682. break;
  683. }
  684. case ID_REPLY:
  685. case ID_REPLY_ALL:
  686. {
  687. // Enabled only if the focus is in the ListView and there
  688. // is only one item selected
  689. prgCmds[i].cmdf = OLECMDF_SUPPORTED;
  690. if (cSel == 1)
  691. {
  692. // The message's body must also be downloaded
  693. LPMESSAGEINFO pInfo;
  694. if (SUCCEEDED(m_pMsgList->GetMessageInfo(rgSelected[0], &pInfo)))
  695. {
  696. if (pInfo->faStream != 0 && (0 == (pInfo->dwFlags & ARF_UNSENT)))
  697. prgCmds[i].cmdf |= OLECMDF_ENABLED;
  698. m_pMsgList->FreeMessageInfo(pInfo);
  699. }
  700. }
  701. break;
  702. }
  703. case ID_SAVE_AS:
  704. {
  705. // Enabled only if the focus is in the ListView and there
  706. // is one item selected
  707. prgCmds[i].cmdf = OLECMDF_SUPPORTED;
  708. if (_IsPreview() && (cSel == 1))
  709. {
  710. // The message's body must also be downloaded
  711. LPMESSAGEINFO pInfo;
  712. if (SUCCEEDED(m_pMsgList->GetMessageInfo(rgSelected[0], &pInfo)))
  713. {
  714. if (pInfo->faStream != 0)
  715. prgCmds[i].cmdf |= OLECMDF_ENABLED;
  716. m_pMsgList->FreeMessageInfo(pInfo);
  717. }
  718. }
  719. break;
  720. }
  721. case ID_PRINT:
  722. {
  723. // Enabled only if the focus is in the ListView and there
  724. // is more than one item selected
  725. prgCmds[i].cmdf = OLECMDF_SUPPORTED;
  726. if (_IsPreview() && cSel > 0)
  727. {
  728. // The message's body must also be downloaded
  729. LPMESSAGEINFO pInfo;
  730. if (SUCCEEDED(m_pMsgList->GetMessageInfo(rgSelected[0], &pInfo)))
  731. {
  732. if (pInfo->faStream != 0)
  733. prgCmds[i].cmdf |= OLECMDF_ENABLED;
  734. m_pMsgList->FreeMessageInfo(pInfo);
  735. }
  736. }
  737. break;
  738. }
  739. case ID_FORWARD:
  740. case ID_FORWARD_AS_ATTACH:
  741. {
  742. // Enabled only if the focus is in the ListView and there
  743. // is only one item selected
  744. prgCmds[i].cmdf = OLECMDF_SUPPORTED;
  745. if (cSel > 0)
  746. {
  747. // The message's body must also be downloaded
  748. LPMESSAGEINFO pInfo;
  749. // Default to success
  750. prgCmds[i].cmdf |= OLECMDF_ENABLED;
  751. for (DWORD iItem = 0; iItem < cSel && (prgCmds[i].cmdf & OLECMDF_ENABLED); iItem++)
  752. {
  753. if (SUCCEEDED(m_pMsgList->GetMessageInfo(rgSelected[iItem], &pInfo)))
  754. {
  755. if (pInfo->faStream == 0 || (0 != (pInfo->dwFlags & ARF_UNSENT)))
  756. {
  757. prgCmds[i].cmdf &= ~OLECMDF_ENABLED;
  758. }
  759. m_pMsgList->FreeMessageInfo(pInfo);
  760. }
  761. }
  762. }
  763. break;
  764. }
  765. case ID_REPLY_GROUP:
  766. {
  767. // Enabled only if there is one news message selected
  768. prgCmds[i].cmdf = OLECMDF_SUPPORTED;
  769. if (cSel == 1)
  770. {
  771. // The message's body must also be downloaded
  772. LPMESSAGEINFO pInfo;
  773. if (SUCCEEDED(m_pMsgList->GetMessageInfo(rgSelected[0], &pInfo)))
  774. {
  775. if (pInfo->faStream != 0 && (pInfo->dwFlags & ARF_NEWSMSG) && (0 == (pInfo->dwFlags & ARF_UNSENT)))
  776. prgCmds[i].cmdf |= OLECMDF_ENABLED;
  777. m_pMsgList->FreeMessageInfo(pInfo);
  778. }
  779. }
  780. break;
  781. }
  782. case ID_CANCEL_MESSAGE:
  783. {
  784. prgCmds[i].cmdf = OLECMDF_SUPPORTED;
  785. if (DwGetOption(OPT_CANCEL_ALL_NEWS))
  786. prgCmds[i].cmdf |= OLECMDF_ENABLED;
  787. else
  788. {
  789. if (cSel == 1)
  790. {
  791. LPMESSAGEINFO pInfo;
  792. if (SUCCEEDED(m_pMsgList->GetMessageInfo(rgSelected[0], &pInfo)))
  793. {
  794. if (NewsUtil_FCanCancel(m_idFolder, pInfo))
  795. {
  796. prgCmds[i].cmdf |= OLECMDF_ENABLED;
  797. }
  798. m_pMsgList->FreeMessageInfo(pInfo);
  799. }
  800. }
  801. }
  802. break;
  803. }
  804. case ID_POPUP_FILTER:
  805. case ID_PREVIEW_PANE:
  806. {
  807. prgCmds[i].cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
  808. break;
  809. }
  810. case ID_POPUP_LANGUAGE_DEFERRED:
  811. case ID_POPUP_LANGUAGE:
  812. case ID_POPUP_LANGUAGE_MORE:
  813. case ID_LANGUAGE:
  814. {
  815. // These are OK if the preview pane is visible and not empty
  816. if (cSel > 0 && _IsPreview())
  817. prgCmds[i].cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
  818. else
  819. prgCmds[i].cmdf = OLECMDF_SUPPORTED;
  820. break;
  821. }
  822. case ID_PREVIEW_SHOW:
  823. case ID_PREVIEW_BELOW:
  824. case ID_PREVIEW_BESIDE:
  825. case ID_PREVIEW_HEADER:
  826. {
  827. FOLDERTYPE ftType;
  828. DWORD dwOpt;
  829. LAYOUTPOS pos;
  830. BOOL fVisible;
  831. DWORD dwFlags;
  832. // Default return value
  833. prgCmds[i].cmdf = OLECMDF_SUPPORTED;
  834. // Get the folder type
  835. m_pBrowser->GetFolderType(&ftType);
  836. if (ftType == FOLDER_NEWS)
  837. dwOpt = DISPID_MSGVIEW_PREVIEWPANE_NEWS;
  838. else
  839. dwOpt = DISPID_MSGVIEW_PREVIEWPANE_MAIL;
  840. // Get the settings from the browser
  841. m_pBrowser->GetViewLayout(dwOpt, &pos, &fVisible, &dwFlags, NULL);
  842. switch (prgCmds[i].cmdID)
  843. {
  844. case ID_PREVIEW_SHOW:
  845. {
  846. // Always enabled, checked if already visible
  847. if (fVisible)
  848. prgCmds[i].cmdf |= (OLECMDF_ENABLED | OLECMDF_LATCHED);
  849. else
  850. prgCmds[i].cmdf |= OLECMDF_ENABLED;
  851. break;
  852. }
  853. case ID_PREVIEW_BESIDE:
  854. case ID_PREVIEW_BELOW:
  855. {
  856. // The command is enabled only if the preview pane
  857. // is visible.
  858. if (fVisible)
  859. prgCmds[i].cmdf |= OLECMDF_ENABLED;
  860. // If the preview pane is already beside, it should be latched etc.
  861. if ((pos == LAYOUT_POS_LEFT && prgCmds[i].cmdID == ID_PREVIEW_BESIDE) ||
  862. (pos == LAYOUT_POS_BOTTOM && prgCmds[i].cmdID == ID_PREVIEW_BELOW))
  863. prgCmds[i].cmdf |= OLECMDF_NINCHED;
  864. break;
  865. }
  866. case ID_PREVIEW_HEADER:
  867. {
  868. // Always enabled, checked if already visible
  869. if (dwFlags)
  870. prgCmds[i].cmdf |= (OLECMDF_ENABLED | OLECMDF_LATCHED);
  871. else
  872. prgCmds[i].cmdf |= OLECMDF_ENABLED;
  873. break;
  874. }
  875. }
  876. break;
  877. }
  878. case ID_REFRESH:
  879. {
  880. // Best I can tell, these are always enabled
  881. prgCmds[i].cmdf |= OLECMDF_ENABLED;
  882. break;
  883. }
  884. case ID_GET_HEADERS:
  885. {
  886. // Only in news
  887. m_pBrowser->GetFolderType(&ftType);
  888. if (ftType != FOLDER_LOCAL)
  889. prgCmds[i].cmdf |= OLECMDF_ENABLED;
  890. break;
  891. }
  892. case ID_ADD_SENDER:
  893. case ID_BLOCK_SENDER:
  894. {
  895. prgCmds[i].cmdf = OLECMDF_SUPPORTED;
  896. // Enabled only if there is only one item selected and
  897. // we have access to the from address
  898. // Not in IMAP or HTTPMAIL
  899. m_pBrowser->GetFolderType(&ftType);
  900. if (cSel == 1 &&
  901. (prgCmds[i].cmdID == ID_ADD_SENDER || (FOLDER_HTTPMAIL != ftType && FOLDER_IMAP != ftType)))
  902. {
  903. // The message's body must also be downloaded
  904. LPMESSAGEINFO pInfo;
  905. if (SUCCEEDED(m_pMsgList->GetMessageInfo(rgSelected[0], &pInfo)))
  906. {
  907. if (((NULL != pInfo->pszEmailFrom) && ('\0' != pInfo->pszEmailFrom[0])) || (0 != pInfo->faStream))
  908. prgCmds[i].cmdf |= OLECMDF_ENABLED;
  909. m_pMsgList->FreeMessageInfo(pInfo);
  910. }
  911. }
  912. break;
  913. }
  914. case ID_CREATE_RULE_FROM_MESSAGE:
  915. {
  916. prgCmds[i].cmdf = OLECMDF_SUPPORTED;
  917. // Enabled only if there is only one item selected
  918. // Not in IMAP or HTTPMAIL
  919. m_pBrowser->GetFolderType(&ftType);
  920. if ((cSel == 1) && (FOLDER_HTTPMAIL != ftType) && (FOLDER_IMAP != ftType))
  921. {
  922. LPMESSAGEINFO pInfo;
  923. if (SUCCEEDED(m_pMsgList->GetMessageInfo(rgSelected[0], &pInfo)))
  924. {
  925. prgCmds[i].cmdf |= OLECMDF_ENABLED;
  926. m_pMsgList->FreeMessageInfo(pInfo);
  927. }
  928. }
  929. break;
  930. }
  931. case ID_COMBINE_AND_DECODE:
  932. {
  933. // Enabled only if the focus is in the ListView and there
  934. // is at least one item selected.
  935. m_pMsgList->GetSelectedCount(&cSel);
  936. if (cSel > 1)
  937. prgCmds[i].cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
  938. else
  939. prgCmds[i].cmdf = OLECMDF_SUPPORTED;
  940. break;
  941. }
  942. }
  943. }
  944. }
  945. SafeMemFree(rgSelected);
  946. return (S_OK);
  947. }
  948. HRESULT CMessageView::_StoreCharsetOntoRows(HCHARSET hCharset)
  949. {
  950. // Locals
  951. HRESULT hr=S_OK;
  952. INETCSETINFO CsetInfo;
  953. IMessageTable *pTable=NULL;
  954. DWORD *rgRows=NULL;
  955. DWORD cRows=0;
  956. HCURSOR hCursor=NULL;
  957. // Trace
  958. TraceCall("CMessageView::_StoreCharsetOntoRows");
  959. // Invalid Args
  960. if (NULL == m_pMsgList || NULL == hCharset)
  961. return(TraceResult(E_INVALIDARG));
  962. // Wait Cursor
  963. hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  964. // Get charset info
  965. IF_FAILEXIT(hr = MimeOleGetCharsetInfo(hCharset, &CsetInfo));
  966. // Get selected rows
  967. IF_FAILEXIT(hr = m_pMsgList->GetSelected(NULL, &cRows, &rgRows));
  968. // Get the message table
  969. IF_FAILEXIT(hr = m_pMsgList->GetMessageTable(&pTable));
  970. // Set the Language
  971. SideAssert(SUCCEEDED(pTable->SetLanguage(cRows, rgRows, CsetInfo.cpiInternet)));
  972. exit:
  973. // Cleanup
  974. SafeRelease(pTable);
  975. SafeMemFree(rgRows);
  976. // Reset Cursor
  977. if (hCursor)
  978. SetCursor(hCursor);
  979. // Done
  980. return(hr);
  981. }
  982. //
  983. // FUNCTION: CMessageView::Exec()
  984. //
  985. // PURPOSE: Called to execute a verb that this view supports
  986. //
  987. // PARAMETERS:
  988. // [in] pguidCmdGroup - unused
  989. // [in] nCmdID - ID of the command to execute
  990. // [in] nCmdExecOpt - Options that define how the command should execute
  991. // [in] pvaIn - Any arguments for the command
  992. // [out] pvaOut - Any return values for the command
  993. //
  994. // RETURN VALUE:
  995. //
  996. //
  997. HRESULT CMessageView::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdExecOpt,
  998. VARIANTARG *pvaIn, VARIANTARG *pvaOut)
  999. {
  1000. // See if our message list wants the command
  1001. if (m_pMsgListCT)
  1002. {
  1003. if (OLECMDERR_E_NOTSUPPORTED != m_pMsgListCT->Exec(pguidCmdGroup, nCmdID, nCmdExecOpt, pvaIn, pvaOut))
  1004. return (S_OK);
  1005. }
  1006. if (m_pPreviewCT)
  1007. {
  1008. if (OLECMDERR_E_NOTSUPPORTED != m_pPreviewCT->Exec(&CMDSETID_OutlookExpress, nCmdID, nCmdExecOpt, pvaIn, pvaOut))
  1009. return (S_OK);
  1010. }
  1011. // If the sub objects didn't support the command, then we should see if
  1012. // it's one of ours
  1013. // Language menu first
  1014. if (nCmdID >= ID_LANG_FIRST && nCmdID <= ID_LANG_LAST)
  1015. {
  1016. HCHARSET hCharset = NULL;
  1017. HCHARSET hOldCharset = NULL;
  1018. HRESULT hr = S_OK;
  1019. if(!m_pPreview)
  1020. return S_OK;
  1021. m_pPreview->HrGetCharset(&hOldCharset);
  1022. hCharset = GetMimeCharsetFromMenuID(nCmdID);
  1023. if(!hCharset || (hOldCharset == hCharset))
  1024. return(S_OK);
  1025. Assert (hCharset);
  1026. if(FAILED(hr = m_pPreview->HrSetCharset(hCharset)))
  1027. {
  1028. AthMessageBoxW( m_hwnd, MAKEINTRESOURCEW(idsAthena),
  1029. MAKEINTRESOURCEW((hr == hrIncomplete)?idsViewLangMimeDBBad:idsErrViewLanguage),
  1030. NULL, MB_OK|MB_ICONEXCLAMATION);
  1031. return E_FAIL;
  1032. }
  1033. // Set the charset onto the selected rows....
  1034. _StoreCharsetOntoRows(hCharset);
  1035. // SetDefaultCharset(hCharset);
  1036. // SwitchLanguage(nCmdID, TRUE);
  1037. return (S_OK);
  1038. }
  1039. // Handle the View.Current View menu
  1040. if ((ID_VIEW_FILTER_FIRST <= nCmdID) && (ID_VIEW_FILTER_LAST >= nCmdID))
  1041. {
  1042. if (NULL == m_pViewMenu)
  1043. {
  1044. // Create the view menu
  1045. HrCreateViewMenu(0, &m_pViewMenu);
  1046. }
  1047. if (NULL != m_pViewMenu)
  1048. {
  1049. // What we get from the browser is of type VT_I8, but rules only needs filter id which
  1050. // is a dword. So changing the type here is safe. Bug# 74275
  1051. pvaIn->vt = VT_I4;
  1052. if (SUCCEEDED(m_pViewMenu->Exec(m_hwnd, nCmdID, m_pMsgList, pvaIn, pvaOut)))
  1053. {
  1054. return (S_OK);
  1055. }
  1056. }
  1057. }
  1058. // Go through the rest of the commands
  1059. switch (nCmdID)
  1060. {
  1061. case ID_OPEN:
  1062. return CmdOpen(nCmdID, nCmdExecOpt, pvaIn, pvaOut);
  1063. case ID_REPLY:
  1064. case ID_REPLY_ALL:
  1065. case ID_FORWARD:
  1066. case ID_FORWARD_AS_ATTACH:
  1067. case ID_REPLY_GROUP:
  1068. return CmdReplyForward(nCmdID, nCmdExecOpt, pvaIn, pvaOut);
  1069. case ID_CANCEL_MESSAGE:
  1070. return CmdCancelMessage(nCmdID, nCmdExecOpt, pvaIn, pvaOut);
  1071. case ID_DOWNLOAD_MESSAGE:
  1072. return CmdFillPreview(nCmdID, nCmdExecOpt, pvaIn, pvaOut);
  1073. case ID_PREVIEW_PANE:
  1074. case ID_PREVIEW_SHOW:
  1075. case ID_PREVIEW_BELOW:
  1076. case ID_PREVIEW_BESIDE:
  1077. case ID_PREVIEW_HEADER:
  1078. return CmdShowPreview(nCmdID, nCmdExecOpt, pvaIn, pvaOut);
  1079. case ID_REFRESH:
  1080. return CmdRefresh(nCmdID, nCmdExecOpt, pvaIn, pvaOut);
  1081. case ID_BLOCK_SENDER:
  1082. return CmdBlockSender(nCmdID, nCmdExecOpt, pvaIn, pvaOut);
  1083. case ID_CREATE_RULE_FROM_MESSAGE:
  1084. return CmdCreateRule(nCmdID, nCmdExecOpt, pvaIn, pvaOut);
  1085. case ID_VIEW_SOURCE:
  1086. case ID_VIEW_MSG_SOURCE:
  1087. if (m_pPreview)
  1088. return m_pPreview->HrViewSource((ID_VIEW_SOURCE==nCmdID)?MECMD_VS_HTML:MECMD_VS_MESSAGE);
  1089. else
  1090. break;
  1091. case ID_ADD_SENDER:
  1092. return CmdAddToWab(nCmdID, nCmdExecOpt, pvaIn, pvaOut);
  1093. case ID_COMBINE_AND_DECODE:
  1094. return CmdCombineAndDecode(nCmdID, nCmdExecOpt, pvaIn, pvaOut);
  1095. }
  1096. return (E_FAIL);
  1097. }
  1098. //
  1099. // FUNCTION: CMessageView::Invoke()
  1100. //
  1101. // PURPOSE: This is where we receive notifications from the message list.
  1102. //
  1103. // PARAMETERS:
  1104. // <too many to list>
  1105. //
  1106. // RETURN VALUE:
  1107. // HRESULT
  1108. //
  1109. HRESULT CMessageView::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid,
  1110. WORD wFlags, DISPPARAMS* pDispParams,
  1111. VARIANT* pVarResult, EXCEPINFO* pExcepInfo,
  1112. unsigned int* puArgErr)
  1113. {
  1114. switch (dispIdMember)
  1115. {
  1116. // Fired whenever the selection in the ListView changes
  1117. case DISPID_LISTEVENT_SELECTIONCHANGED:
  1118. {
  1119. // Need to load the preview pane with the new selected message
  1120. if (_IsPreview())
  1121. _UpdatePreviewPane();
  1122. // Tell the browser to update it's toolbar
  1123. if (m_pBrowser)
  1124. m_pBrowser->UpdateToolbar();
  1125. break;
  1126. }
  1127. // Fired whenever the ListView get's or loses focus.
  1128. case DISPID_LISTEVENT_FOCUSCHANGED:
  1129. {
  1130. // If the ListView is getting the focus, we need to UI deactivate
  1131. // the preview pane.
  1132. if (pDispParams->rgvarg[0].lVal)
  1133. {
  1134. if (m_pPreview)
  1135. {
  1136. m_pPreview->HrUIActivate(FALSE);
  1137. m_pBrowser->OnViewWindowActive(this);
  1138. }
  1139. }
  1140. break;
  1141. }
  1142. // Fired when the number of messages or unread messages changes
  1143. case DISPID_LISTEVENT_COUNTCHANGED:
  1144. {
  1145. // If we have a browser, update the status bar
  1146. if (m_pBrowser && !m_pProgress)
  1147. {
  1148. DWORD cTotal, cUnread, cOnServer;
  1149. // Readability forces me to do this
  1150. cTotal = pDispParams->rgvarg[0].lVal;
  1151. cUnread = pDispParams->rgvarg[1].lVal;
  1152. cOnServer = pDispParams->rgvarg[2].lVal;
  1153. // Got to update the status bar if there is one
  1154. CStatusBar *pStatusBar = NULL;
  1155. m_pBrowser->GetStatusBar(&pStatusBar);
  1156. if (pStatusBar)
  1157. {
  1158. TCHAR szStatus[CCHMAX_STRINGRES + 20];
  1159. TCHAR szFmt[CCHMAX_STRINGRES];
  1160. DWORD ids;
  1161. // If there are still messages on server load a different
  1162. // status string.
  1163. if (cOnServer)
  1164. {
  1165. AthLoadString(idsXMsgsYUnreadZonServ, szFmt, ARRAYSIZE(szFmt));
  1166. wnsprintf(szStatus, ARRAYSIZE(szStatus), szFmt, cTotal, cUnread, cOnServer);
  1167. }
  1168. else
  1169. {
  1170. AthLoadString(idsXMsgsYUnread, szFmt, ARRAYSIZE(szFmt));
  1171. wnsprintf(szStatus, ARRAYSIZE(szStatus), szFmt, cTotal, cUnread);
  1172. }
  1173. pStatusBar->SetStatusText(szStatus);
  1174. pStatusBar->Release();
  1175. }
  1176. // Also update the toolbar since commands like "Mark as Read" might
  1177. // change. However, we only do this if we go between zero and some or
  1178. // vice versa.
  1179. if ((m_cItems == 0 && cTotal) || (m_cItems != 0 && cTotal == 0) ||
  1180. (m_cUnread == 0 && cUnread) || (m_cUnread != 0 && cUnread == 0))
  1181. {
  1182. m_pBrowser->UpdateToolbar();
  1183. }
  1184. // Save this for next time.
  1185. m_cItems = cTotal;
  1186. m_cUnread = cUnread;
  1187. }
  1188. break;
  1189. }
  1190. // Fired when the message list want's to show status text
  1191. case DISPID_LISTEVENT_UPDATESTATUS:
  1192. {
  1193. _SetProgressStatusText(pDispParams->rgvarg->bstrVal);
  1194. break;
  1195. }
  1196. // Fired when progress happens
  1197. case DISPID_LISTEVENT_UPDATEPROGRESS:
  1198. {
  1199. CBands *pCoolbar = NULL;
  1200. // If this is a begin, then we start animating the logo
  1201. if (pDispParams->rgvarg[2].lVal == PROGRESS_STATE_BEGIN)
  1202. {
  1203. if (SUCCEEDED(m_pBrowser->GetCoolbar(&pCoolbar)))
  1204. {
  1205. pCoolbar->Invoke(idDownloadBegin, NULL);
  1206. pCoolbar->Release();
  1207. }
  1208. }
  1209. // If this is a continue, then we might get progress numbers
  1210. else if (pDispParams->rgvarg[2].lVal == PROGRESS_STATE_DEFAULT)
  1211. {
  1212. if (!m_pProgress)
  1213. {
  1214. if (m_pBrowser->GetStatusBar(&m_pProgress)==S_OK)
  1215. m_pProgress->ShowProgress(pDispParams->rgvarg[1].lVal);
  1216. }
  1217. if (m_pProgress)
  1218. m_pProgress->SetProgress(pDispParams->rgvarg[0].lVal);
  1219. }
  1220. // Or if this is an end, stop animating and clean up the status bar
  1221. else if (pDispParams->rgvarg[2].lVal == PROGRESS_STATE_END)
  1222. {
  1223. if (m_pProgress)
  1224. {
  1225. m_pProgress->HideProgress();
  1226. m_pProgress->Release();
  1227. m_pProgress = NULL;
  1228. }
  1229. if (SUCCEEDED(m_pBrowser->GetCoolbar(&pCoolbar)))
  1230. {
  1231. pCoolbar->Invoke(idDownloadEnd, NULL);
  1232. pCoolbar->Release();
  1233. }
  1234. // Reset the status bar back to it's default state
  1235. _SetDefaultStatusText();
  1236. }
  1237. break;
  1238. }
  1239. // Fired when the user double clicks an item in the ListView
  1240. case DISPID_LISTEVENT_ITEMACTIVATE:
  1241. {
  1242. CmdOpen(ID_OPEN, OLECMDEXECOPT_DONTPROMPTUSER, NULL, NULL);
  1243. break;
  1244. }
  1245. // Fired when we need to call update toolbar
  1246. case DISPID_LISTEVENT_UPDATECOMMANDSTATE:
  1247. {
  1248. PostMessage(m_hwndParent, CM_UPDATETOOLBAR, 0, 0L);
  1249. break;
  1250. }
  1251. // Fired when a message has been downloaded by the messagelist
  1252. case DISPID_LISTEVENT_ONMESSAGEAVAILABLE:
  1253. {
  1254. return _OnMessageAvailable((MESSAGEID)((LONG_PTR)pDispParams->rgvarg[0].lVal), (HRESULT)pDispParams->rgvarg[1].scode);
  1255. }
  1256. // Fired when the filter changes
  1257. case DISPID_LISTEVENT_FILTERCHANGED:
  1258. {
  1259. // If we have a browser, update the status bar
  1260. if (m_pBrowser && !m_pProgress)
  1261. {
  1262. // Got to update the status bar if there is one
  1263. CStatusBar *pStatusBar = NULL;
  1264. m_pBrowser->GetStatusBar(&pStatusBar);
  1265. if (pStatusBar)
  1266. {
  1267. pStatusBar->SetFilter((RULEID)((ULONG_PTR)pDispParams->rgvarg[0].ulVal));
  1268. pStatusBar->Release();
  1269. }
  1270. CBands* pBands;
  1271. if (m_pBrowser->GetCoolbar(&pBands) == S_OK)
  1272. {
  1273. pBands->Invoke(idNotifyFilterChange, &pDispParams->rgvarg[0].ulVal);
  1274. pBands->Release();
  1275. }
  1276. }
  1277. break;
  1278. }
  1279. case DISPID_LISTEVENT_ADURL_AVAILABLE:
  1280. {
  1281. if (m_pBrowser)
  1282. {
  1283. m_pBrowser->ShowAdBar(pDispParams->rgvarg[0].bstrVal);
  1284. }
  1285. break;
  1286. }
  1287. }
  1288. return (S_OK);
  1289. }
  1290. HRESULT CMessageView::GetMarkAsReadTime(LPDWORD pdwSecs)
  1291. {
  1292. if (!pdwSecs)
  1293. {
  1294. AssertSz(FALSE, "Null Pointer");
  1295. return (E_INVALIDARG);
  1296. }
  1297. *pdwSecs = DwGetOption(OPT_MARKASREAD);
  1298. return (S_OK);
  1299. }
  1300. HRESULT CMessageView::GetAccount(IImnAccount **ppAcct)
  1301. {
  1302. FOLDERINFO FolderInfo;
  1303. HRESULT hr = E_FAIL;
  1304. CHAR szAccountId[CCHMAX_ACCOUNT_NAME];
  1305. if (g_pStore && SUCCEEDED(g_pStore->GetFolderInfo(m_idFolder, &FolderInfo)))
  1306. {
  1307. if (SUCCEEDED(GetFolderAccountId(&FolderInfo, szAccountId, ARRAYSIZE(szAccountId)) && *szAccountId))
  1308. {
  1309. hr = g_pAcctMan->FindAccount(AP_ACCOUNT_ID, szAccountId, ppAcct);
  1310. // If local store then we can fail
  1311. if(FAILED(hr))
  1312. {
  1313. DWORD dwRow = 0;
  1314. DWORD cSel = 0;
  1315. if (SUCCEEDED(m_pMsgList->GetSelected(&dwRow, &cSel, NULL)))
  1316. {
  1317. LPMESSAGEINFO pMsgInfo;
  1318. if (SUCCEEDED(m_pMsgList->GetMessageInfo(dwRow, &pMsgInfo)))
  1319. {
  1320. hr = g_pAcctMan->FindAccount(AP_ACCOUNT_ID, pMsgInfo->pszAcctId, ppAcct);
  1321. m_pMsgList->FreeMessageInfo(pMsgInfo);
  1322. }
  1323. }
  1324. }
  1325. }
  1326. g_pStore->FreeRecord(&FolderInfo);
  1327. }
  1328. return(hr);
  1329. }
  1330. HRESULT CMessageView::GetFlags(LPDWORD pdwFlags)
  1331. {
  1332. FOLDERTYPE ftType;
  1333. if (!pdwFlags)
  1334. {
  1335. AssertSz(FALSE, "Null Pointer");
  1336. return (E_INVALIDARG);
  1337. }
  1338. *pdwFlags = BOPT_AUTOINLINE | BOPT_HTML | BOPT_INCLUDEMSG | BOPT_FROMSTORE;
  1339. if (m_pMsgList)
  1340. {
  1341. DWORD dwRow = 0;
  1342. DWORD cSel = 0;
  1343. if (SUCCEEDED(m_pMsgList->GetSelected(&dwRow, &cSel, NULL)))
  1344. {
  1345. LPMESSAGEINFO pMsgInfo;
  1346. if (cSel > 1)
  1347. *pdwFlags |= BOPT_MULTI_MSGS_SELECTED;
  1348. if (SUCCEEDED(m_pMsgList->GetMessageInfo(dwRow, &pMsgInfo)))
  1349. {
  1350. if (0 == (pMsgInfo->dwFlags & ARF_READ))
  1351. *pdwFlags |= BOPT_UNREAD;
  1352. if (0 == (pMsgInfo->dwFlags & ARF_NOSECUI))
  1353. *pdwFlags |= BOPT_SECURITYUIENABLED;
  1354. m_pMsgList->FreeMessageInfo(pMsgInfo);
  1355. }
  1356. }
  1357. }
  1358. m_pBrowser->GetFolderType(&ftType);
  1359. if (FOLDER_NEWS != ftType)
  1360. *pdwFlags |= BOPT_MAIL;
  1361. return (S_OK);
  1362. }
  1363. //
  1364. // FUNCTION: CMessageView::EventOccurred()
  1365. //
  1366. // PURPOSE: Get's hit whenever an interesting event happens in the preview
  1367. // pane.
  1368. //
  1369. // PARAMETERS:
  1370. // DWORD nCmdID
  1371. //
  1372. // RETURN VALUE:
  1373. // HRESULT
  1374. //
  1375. HRESULT CMessageView::EventOccurred(DWORD nCmdID, IMimeMessage *pMessage)
  1376. {
  1377. TraceCall("CMessageView::EventOccurred");
  1378. switch (nCmdID)
  1379. {
  1380. case MEHC_CMD_DOWNLOAD:
  1381. Assert(m_fNotDownloaded);
  1382. // If we're offline, we can make the reasonable assumption that
  1383. // the user wants to be online since they said they wanted to
  1384. // download this message.
  1385. if (g_pConMan && g_pConMan->IsGlobalOffline())
  1386. g_pConMan->SetGlobalOffline(FALSE);
  1387. _UpdatePreviewPane(TRUE);
  1388. break;
  1389. case MEHC_CMD_MARK_AS_READ:
  1390. if (m_pMsgList)
  1391. m_pMsgList->MarkRead(TRUE, 0);
  1392. break;
  1393. case MEHC_CMD_CONNECT:
  1394. if (g_pConMan)
  1395. g_pConMan->SetGlobalOffline(FALSE);
  1396. _UpdatePreviewPane();
  1397. break;
  1398. case MEHC_BTN_OPEN:
  1399. case MEHC_BTN_CONTINUE:
  1400. // Update the toolbar state
  1401. m_pBrowser->UpdateToolbar();
  1402. break;
  1403. case MEHC_UIACTIVATE:
  1404. m_pBrowser->OnViewWindowActive(this);
  1405. break;
  1406. case MEHC_CMD_PROCESS_RECEIPT:
  1407. if (m_pMsgList)
  1408. m_pMsgList->ProcessReceipt(pMessage);
  1409. break;
  1410. default:
  1411. /* AssertSz(FALSE, "CMessageView::EventOccured() - Unhandled Event."); */ // Valid situation - Warning message for S/MIME
  1412. break;
  1413. }
  1414. return (S_FALSE);
  1415. }
  1416. HRESULT CMessageView::GetFolderId(FOLDERID *pID)
  1417. {
  1418. if (pID)
  1419. {
  1420. *pID = m_idFolder;
  1421. return (S_OK);
  1422. }
  1423. return (E_INVALIDARG);
  1424. }
  1425. HRESULT CMessageView::GetMessageFolder(IMessageServer **ppServer)
  1426. {
  1427. if (m_pMsgList)
  1428. return (m_pMsgList->GetMessageServer(ppServer));
  1429. return (E_NOTIMPL);
  1430. }
  1431. /////////////////////////////////////////////////////////////////////////////
  1432. //
  1433. // Window Message Handling
  1434. //
  1435. //
  1436. // FUNCTION: CMessageView::ViewWndProc()
  1437. //
  1438. // PURPOSE: Callback handler for the view window. This function grabs the
  1439. // correct this pointer for the window and uses that to dispatch
  1440. // the message to the private message handler.
  1441. //
  1442. LRESULT CALLBACK CMessageView::ViewWndProc(HWND hwnd, UINT uMsg, WPARAM wParam,
  1443. LPARAM lParam)
  1444. {
  1445. LRESULT lResult;
  1446. CMessageView *pThis;
  1447. // WM_NCCREATE is the first message our window will receive. The lParam
  1448. // will have the pointer to the object that created this instance of the
  1449. // window.
  1450. if (uMsg == WM_NCCREATE)
  1451. {
  1452. // Save the object pointer in the window's extra bytes.
  1453. pThis = (CMessageView *) ((LPCREATESTRUCT) lParam)->lpCreateParams;
  1454. SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM) pThis);
  1455. }
  1456. else
  1457. {
  1458. // If this is any other message, we need to get the object pointer
  1459. // from the window before dispatching the message.
  1460. pThis = (CMessageView *) GetWindowLongPtr(hwnd, GWLP_USERDATA);
  1461. }
  1462. // If this ain't true, we're in trouble.
  1463. if (pThis)
  1464. {
  1465. return (pThis->_WndProc(hwnd, uMsg, wParam, lParam));
  1466. }
  1467. else
  1468. {
  1469. Assert(pThis);
  1470. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  1471. }
  1472. }
  1473. //
  1474. // FUNCTION: CMessageView::_WndProc()
  1475. //
  1476. // PURPOSE: This private message handler dispatches messages to the
  1477. // appropriate handler.
  1478. //
  1479. LRESULT CALLBACK CMessageView::_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1480. {
  1481. switch (uMsg)
  1482. {
  1483. HANDLE_MSG(hwnd, WM_CREATE, OnCreate);
  1484. HANDLE_MSG(hwnd, WM_POSTCREATE, OnPostCreate);
  1485. HANDLE_MSG(hwnd, WM_SIZE, OnSize);
  1486. HANDLE_MSG(hwnd, WM_LBUTTONDOWN, OnLButtonDown);
  1487. HANDLE_MSG(hwnd, WM_MOUSEMOVE, OnMouseMove);
  1488. HANDLE_MSG(hwnd, WM_LBUTTONUP, OnLButtonUp);
  1489. HANDLE_MSG(hwnd, WM_NOTIFY, OnNotify);
  1490. HANDLE_MSG(hwnd, WM_DESTROY, OnDestroy);
  1491. HANDLE_MSG(hwnd, WM_SETFOCUS, OnSetFocus);
  1492. HANDLE_MSG(hwnd, WM_TEST_GETMSGID, OnTestGetMsgId);
  1493. HANDLE_MSG(hwnd, WM_TEST_SAVEMSG, OnTestSaveMessage);
  1494. case WM_FOLDER_LOADED:
  1495. OnFolderLoaded(hwnd, wParam, lParam);
  1496. break;
  1497. case WM_NEW_MAIL:
  1498. // Propagate up to browser
  1499. PostMessage(m_hwndParent, WM_NEW_MAIL, 0, 0);
  1500. break;
  1501. case NVM_GETNEWGROUPS:
  1502. if (m_pGroups != NULL)
  1503. {
  1504. m_pGroups->HandleGetNewGroups();
  1505. m_pGroups->Release();
  1506. m_pGroups = NULL;
  1507. }
  1508. return(0);
  1509. case WM_UPDATE_PREVIEW:
  1510. if (m_idMessageFocus == (MESSAGEID)wParam)
  1511. {
  1512. _UpdatePreviewPane();
  1513. }
  1514. break;
  1515. case CM_OPTIONADVISE:
  1516. _OptionUpdate((DWORD) wParam);
  1517. break;
  1518. case WM_MENUSELECT:
  1519. // HANDLE_WM_MENUSELECT() has a bug that prevents popups from displaying correctly.
  1520. OnMenuSelect(hwnd, wParam, lParam);
  1521. return (0);
  1522. case WM_SYSCOLORCHANGE:
  1523. case WM_WININICHANGE:
  1524. case WM_FONTCHANGE:
  1525. if (m_pMsgList)
  1526. {
  1527. IOleWindow *pWindow;
  1528. if (SUCCEEDED(m_pMsgList->QueryInterface(IID_IOleWindow, (LPVOID *) &pWindow)))
  1529. {
  1530. HWND hwndList;
  1531. pWindow->GetWindow(&hwndList);
  1532. SendMessage(hwndList, uMsg, wParam, lParam);
  1533. pWindow->Release();
  1534. }
  1535. }
  1536. return (0);
  1537. }
  1538. return (DefWindowProc(hwnd, uMsg, wParam, lParam));
  1539. }
  1540. // PURPOSE: WM_FOLDER_LOADED message is sent when messagelist is done loading the cached headers/messages etc
  1541. void CMessageView::OnFolderLoaded(HWND hwnd, WPARAM wParam, LPARAM lParam)
  1542. {
  1543. FOLDERINFO FolderInfo;
  1544. if (g_pStore && SUCCEEDED(g_pStore->GetFolderInfo(m_idFolder, &FolderInfo)))
  1545. {
  1546. CHAR szAccountId[CCHMAX_ACCOUNT_NAME];
  1547. if (SUCCEEDED(GetFolderAccountId(&FolderInfo, szAccountId, ARRAYSIZE(szAccountId))))
  1548. {
  1549. HRESULT hr;
  1550. if (g_pConMan)
  1551. {
  1552. hr = g_pConMan->CanConnect(szAccountId);
  1553. if ((hr != S_OK) && (hr != HR_E_DIALING_INPROGRESS) && (hr != HR_E_OFFLINE))
  1554. g_pConMan->Connect(szAccountId, hwnd, TRUE);
  1555. }
  1556. }
  1557. g_pStore->FreeRecord(&FolderInfo);
  1558. }
  1559. }
  1560. //
  1561. // FUNCTION: CMessageView::OnCreate()
  1562. //
  1563. // PURPOSE: Handler for the WM_CREATE message. In return we create our
  1564. // dependant objects and initialize them.
  1565. //
  1566. // PARAMETERS:
  1567. // [in] hwnd - Handle of the window being created
  1568. // [in] lpCreateStruct - Pointer to a structure with information about the
  1569. // creation.
  1570. //
  1571. // RETURN VALUE:
  1572. // Returns FALSE if something fails and the window should not be created,
  1573. // and returns TRUE if everything works fine.
  1574. //
  1575. BOOL CMessageView::OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct)
  1576. {
  1577. HRESULT hr;
  1578. HWND hwndList;
  1579. TraceCall("CMessageView::OnCreate");
  1580. // Save the window handle
  1581. m_hwnd = hwnd;
  1582. // Create the message list object
  1583. if (!_InitMessageList())
  1584. return (FALSE);
  1585. // Create the preview pane. If it fails that's OK, we'll just
  1586. // run without it.
  1587. _InitPreviewPane();
  1588. // Get updates when options change
  1589. OptionAdvise(m_hwnd);
  1590. // For later
  1591. PostMessage(m_hwnd, WM_POSTCREATE, 0, 0);
  1592. return (TRUE);
  1593. }
  1594. //
  1595. // FUNCTION: CMessageView::OnPostCreate()
  1596. //
  1597. // PURPOSE: Notifies when the view has finished being created. Any
  1598. // initialization that takes time can happen here, like loading
  1599. // the message table etc.
  1600. //
  1601. // PARAMETERS:
  1602. // [in] hwnd - Handle of the window
  1603. //
  1604. void CMessageView::OnPostCreate(HWND hwnd)
  1605. {
  1606. HRESULT hr;
  1607. FOLDERTYPE FolderType;
  1608. FOLDERINFO fiServerNode = {0};
  1609. HRESULT hrTemp;
  1610. TraceCall("CMessageView::OnPostCreate");
  1611. if (!g_pStore)
  1612. return;
  1613. FolderType = GetFolderType(m_idFolder);
  1614. ProcessICW(hwnd, FolderType);
  1615. // BETA-2: If this is IMAP folder, check if IMAP folderlist is dirty.
  1616. // If so, prompt user to refresh folderlist
  1617. hrTemp = GetFolderServer(m_idFolder, &fiServerNode);
  1618. TraceError(hrTemp);
  1619. if (SUCCEEDED(hrTemp))
  1620. {
  1621. if (FOLDER_IMAP == FolderType)
  1622. CheckIMAPDirty(fiServerNode.pszAccountId, hwnd, fiServerNode.idFolder, NOFLAGS);
  1623. }
  1624. // Tell the Message List control to load itself
  1625. if (m_pMsgList)
  1626. {
  1627. // Tell the message list to change folders
  1628. hr = m_pMsgList->SetFolder(m_idFolder, m_pServer, FALSE, NULL, NOSTORECALLBACK);
  1629. if (FAILED(hr) && hr != E_PENDING && m_pPreview)
  1630. {
  1631. m_pPreview->LoadHtmlErrorPage(c_szErrPage_FldrFail);
  1632. }
  1633. }
  1634. if (m_pServer)
  1635. {
  1636. m_pServer->ConnectionRelease();
  1637. m_pServer->Close(MSGSVRF_HANDS_OFF_SERVER);
  1638. m_pServer->Release();
  1639. m_pServer = NULL;
  1640. }
  1641. // Create a drop target
  1642. m_pDropTarget = new CDropTarget();
  1643. if (m_pDropTarget)
  1644. {
  1645. if (SUCCEEDED(m_pDropTarget->Initialize(m_hwnd, m_idFolder)))
  1646. {
  1647. RegisterDragDrop(m_hwnd, m_pDropTarget);
  1648. }
  1649. }
  1650. if (FolderType == FOLDER_NEWS)
  1651. NewsUtil_CheckForNewGroups(hwnd, m_idFolder, &m_pGroups);
  1652. // If its HTTP folder (Should have been hotmail folder), and if we are connected we ask for the ad url.
  1653. if ((FolderType == FOLDER_HTTPMAIL) &&
  1654. (g_pConMan && (S_OK == g_pConMan->CanConnect(fiServerNode.pszAccountId))))
  1655. {
  1656. m_pMsgList->GetAdBarUrl();
  1657. }
  1658. g_pStore->FreeRecord(&fiServerNode);
  1659. }
  1660. #define SPLIT_SIZE 3
  1661. void CMessageView::OnSize(HWND hwnd, UINT state, int cxClient, int cyClient)
  1662. {
  1663. RECT rc = {0, 0, cxClient, cyClient};
  1664. int split;
  1665. // If we are displaying the preview pane, we need to split the client area
  1666. // based on the position of the split bar.
  1667. if (_IsPreview())
  1668. {
  1669. // Line the windows up based on the split direction
  1670. if (m_fSplitHorz)
  1671. {
  1672. // Determine the split height
  1673. split = (cyClient * m_dwSplitHorzPct) / 100;
  1674. // Save the rect that the split bar occupies
  1675. SetRect(&m_rcSplit, 0, split, cxClient, split + SPLIT_SIZE);
  1676. // Set the position of the preview pane
  1677. rc.top = m_rcSplit.bottom;
  1678. rc.bottom = cyClient;
  1679. if (m_pPreview)
  1680. m_pPreview->HrSetSize(&rc);
  1681. // Set the position of the message list
  1682. SetRect(&rc, -1, 0, cxClient + 2, split);
  1683. m_pMsgList->SetRect(rc);
  1684. }
  1685. else
  1686. {
  1687. // Determine the split width
  1688. split = (cxClient * m_dwSplitVertPct) / 100;
  1689. // Save the rect that the split bar occupies
  1690. SetRect(&m_rcSplit, split, 0, split + SPLIT_SIZE, cyClient);
  1691. // Set the position of the message list
  1692. rc.right = split;
  1693. m_pMsgList->SetRect(rc);
  1694. // Set the position of the preview pane
  1695. rc.left = m_rcSplit.right;
  1696. rc.right = cxClient;
  1697. if (m_pPreview)
  1698. m_pPreview->HrSetSize(&rc);
  1699. }
  1700. }
  1701. else
  1702. {
  1703. SetRect(&rc, -1, 0, cxClient + 2, cyClient);
  1704. m_pMsgList->SetRect(rc);
  1705. }
  1706. return;
  1707. }
  1708. //
  1709. // FUNCTION: CMessageView::OnLButtonDown
  1710. //
  1711. // PURPOSE: We check to see if we're over the splitter bar and if so start
  1712. // a drag operation.
  1713. //
  1714. // PARAMETERS:
  1715. // hwnd - Handle to the view window.
  1716. // fDoubleClick - TRUE if this is a double click.
  1717. // x, y - Position of the mouse in client coordinates.
  1718. // keyFlags - State of the keyboard.
  1719. //
  1720. void CMessageView::OnLButtonDown(HWND hwnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)
  1721. {
  1722. POINT pt = {x, y};
  1723. // Check to see if the mouse is over the split bar
  1724. if (_IsPreview() && PtInRect(&m_rcSplit, pt))
  1725. {
  1726. // Capture the mouse
  1727. SetCapture(m_hwnd);
  1728. // Start dragging
  1729. m_fDragging = TRUE;
  1730. }
  1731. }
  1732. //
  1733. // FUNCTION: CMessageView::OnMouseMove
  1734. //
  1735. // PURPOSE: We update any drag and drop information in response to mouse
  1736. // moves if a drag and drop is in progress.
  1737. //
  1738. // PARAMETERS:
  1739. // hwnd - Handle to the view window.
  1740. // x, y - Position of the mouse in client coordinates.
  1741. // keyFlags - State of the keyboard.
  1742. //
  1743. void CMessageView::OnMouseMove(HWND hwnd, int x, int y, UINT keyFlags)
  1744. {
  1745. HCURSOR hcur;
  1746. POINT pt = {x, y};
  1747. RECT rcClient;
  1748. // If we're dragging the split bar, update the window sizes
  1749. if (m_fDragging)
  1750. {
  1751. // Get the size of the window
  1752. GetClientRect(m_hwnd, &rcClient);
  1753. // Calculate the new split percentage
  1754. if (m_fSplitHorz)
  1755. {
  1756. // Make sure the user hasn't gone off the deep end
  1757. if (y > 32 && y < (rcClient.bottom - 32))
  1758. m_dwSplitHorzPct = (y * 100) / rcClient.bottom;
  1759. }
  1760. else
  1761. {
  1762. // Make sure the user hasn't gone off the deep end
  1763. if (x > 32 && x < (rcClient.right - 32))
  1764. m_dwSplitVertPct = (x * 100) / rcClient.right;
  1765. }
  1766. // Update the window sizes
  1767. OnSize(m_hwnd, SIZE_RESTORED, rcClient.right, rcClient.bottom);
  1768. }
  1769. else
  1770. {
  1771. // Just update the cursor
  1772. if (PtInRect(&m_rcSplit, pt))
  1773. {
  1774. if (m_fSplitHorz)
  1775. hcur = LoadCursor(NULL, MAKEINTRESOURCE(IDC_SIZENS));
  1776. else
  1777. hcur = LoadCursor(NULL, MAKEINTRESOURCE(IDC_SIZEWE));
  1778. }
  1779. else
  1780. hcur = LoadCursor(NULL, IDC_ARROW);
  1781. SetCursor(hcur);
  1782. }
  1783. }
  1784. //
  1785. // FUNCTION: CMessageView::OnLButtonUp
  1786. //
  1787. // PURPOSE: If a drag opteration is currently in progress (as determined
  1788. // by the g_fDragging variable) then this function handles
  1789. // ending the drag and updating the split position.
  1790. //
  1791. // PARAMETERS:
  1792. // hwnd - handle of the window receiving the message
  1793. // x - horizontal mouse position in client coordinates
  1794. // y - vertical mouse position in client coordinates
  1795. // keyFlags - Indicates whether various virtual keys are down
  1796. //
  1797. void CMessageView::OnLButtonUp(HWND hwnd, int x, int y, UINT keyFlags)
  1798. {
  1799. DWORD dwHeader;
  1800. DWORD dwSize;
  1801. BOOL fVisible;
  1802. DWORD dwOpt;
  1803. FOLDERTYPE ftType;
  1804. if (m_fDragging)
  1805. {
  1806. ReleaseCapture();
  1807. m_fDragging = FALSE;
  1808. // Get the old settings
  1809. m_pBrowser->GetFolderType(&ftType);
  1810. if (ftType == FOLDER_NEWS)
  1811. dwOpt = DISPID_MSGVIEW_PREVIEWPANE_NEWS;
  1812. else
  1813. dwOpt = DISPID_MSGVIEW_PREVIEWPANE_MAIL;
  1814. m_pBrowser->GetViewLayout(dwOpt, 0, &fVisible, &dwHeader, &dwSize);
  1815. // Update the new splits
  1816. if (m_fSplitHorz)
  1817. dwSize = MAKELONG(m_dwSplitHorzPct, 0);
  1818. else
  1819. dwSize = MAKELONG(0, m_dwSplitVertPct);
  1820. // Set the settings back to the browser
  1821. m_pBrowser->SetViewLayout(dwOpt, LAYOUT_POS_NA, fVisible, dwHeader, dwSize);
  1822. }
  1823. }
  1824. //
  1825. // FUNCTION: CMessageView::OnMenuSelect()
  1826. //
  1827. // PURPOSE: Put's helpful text on the status bar describing the selected
  1828. // menu item.
  1829. //
  1830. void CMessageView::OnMenuSelect(HWND hwnd, WPARAM wParam, LPARAM lParam)
  1831. {
  1832. // Let the preview pane have it first
  1833. if (m_pPreview)
  1834. {
  1835. if (S_OK == m_pPreview->HrWMMenuSelect(hwnd, wParam, lParam))
  1836. return;
  1837. }
  1838. // Handle it ourselves
  1839. CStatusBar *pStatusBar = NULL;
  1840. m_pBrowser->GetStatusBar(&pStatusBar);
  1841. HandleMenuSelect(pStatusBar, wParam, lParam);
  1842. pStatusBar->Release();
  1843. }
  1844. //
  1845. // FUNCTION: CMessageView::OnNotify
  1846. //
  1847. // PURPOSE: Processes the various notifications we receive from our child
  1848. // controls.
  1849. //
  1850. // PARAMETERS:
  1851. // hwnd - Handle of the view window.
  1852. // idCtl - identifies the control sending the notification
  1853. // pnmh - points to a NMHDR struct with more information regarding the
  1854. // notification
  1855. //
  1856. // RETURN VALUE:
  1857. // Dependant on the specific notification.
  1858. //
  1859. LRESULT CMessageView::OnNotify(HWND hwnd, int idFrom, LPNMHDR pnmhdr)
  1860. {
  1861. switch (pnmhdr->code)
  1862. {
  1863. case BDN_HEADERDBLCLK:
  1864. {
  1865. if (m_pPreview)
  1866. {
  1867. DWORD dw = 0;
  1868. BOOL f = 0;
  1869. FOLDERTYPE ftType;
  1870. DWORD dwOpt;
  1871. m_pBrowser->GetFolderType(&ftType);
  1872. if (ftType == FOLDER_NEWS)
  1873. dwOpt = DISPID_MSGVIEW_PREVIEWPANE_NEWS;
  1874. else
  1875. dwOpt = DISPID_MSGVIEW_PREVIEWPANE_MAIL;
  1876. m_pBrowser->GetViewLayout(dwOpt, 0, &f, &dw, 0);
  1877. m_pPreview->HrSetStyle(!dw ? MESTYLE_PREVIEW : MESTYLE_MINIHEADER);
  1878. m_pBrowser->SetViewLayout(dwOpt, LAYOUT_POS_NA, f, !dw, 0);
  1879. }
  1880. break;
  1881. }
  1882. case BDN_MARKASSECURE:
  1883. {
  1884. if (m_pMsgList)
  1885. {
  1886. DWORD dwRow = 0;
  1887. if (SUCCEEDED(m_pMsgList->GetSelected(&dwRow, NULL, NULL)))
  1888. m_pMsgList->MarkMessage(dwRow, MARK_MESSAGE_NOSECUI);
  1889. }
  1890. break;
  1891. }
  1892. }
  1893. return (0);
  1894. }
  1895. void CMessageView::OnDestroy(HWND hwnd)
  1896. {
  1897. if (m_pDropTarget)
  1898. {
  1899. RevokeDragDrop(hwnd);
  1900. m_pDropTarget->Release();
  1901. m_pDropTarget = 0;
  1902. }
  1903. // Stop advising for option changes
  1904. OptionUnadvise(m_hwnd);
  1905. // Release the preview pane
  1906. if (m_pPreview)
  1907. {
  1908. m_pPreview->HrUnloadAll(NULL, 0);
  1909. m_pPreview->HrClose();
  1910. }
  1911. }
  1912. void CMessageView::OnSetFocus(HWND hwnd, HWND hwndOldFocus)
  1913. {
  1914. IOleWindow *pWindow = 0;
  1915. HWND hwndList = 0;
  1916. if (m_pMsgList)
  1917. {
  1918. if (SUCCEEDED(m_pMsgList->QueryInterface(IID_IOleWindow, (LPVOID *) &pWindow)))
  1919. {
  1920. if (SUCCEEDED(pWindow->GetWindow(&hwndList)))
  1921. {
  1922. SetFocus(hwndList);
  1923. }
  1924. pWindow->Release();
  1925. }
  1926. }
  1927. }
  1928. //
  1929. // FUNCTION: CMessageView::OnTestGetMsgId()
  1930. //
  1931. // PURPOSE: This function is for the testing team. Please consult Racheli
  1932. // before modifying it in any way.
  1933. //
  1934. LRESULT CMessageView::OnTestGetMsgId(HWND hwnd)
  1935. {
  1936. DWORD cSel;
  1937. DWORD *rgSelected = NULL;
  1938. LRESULT lResult = -1;
  1939. LPMESSAGEINFO pInfo;
  1940. TraceCall("CMessageView::OnTestGetMsgId");
  1941. // Only handle this if we're in test mode
  1942. if (!DwGetOption(OPT_TEST_MODE))
  1943. return (-1);
  1944. // Get the range of selected messages
  1945. if (SUCCEEDED(m_pMsgList && m_pMsgList->GetSelected(NULL, &cSel, &rgSelected)))
  1946. {
  1947. // Get the message info for the selected row
  1948. if (cSel && SUCCEEDED(m_pMsgList->GetMessageInfo(*rgSelected, &pInfo)))
  1949. {
  1950. lResult = (LRESULT) pInfo->idMessage;
  1951. m_pMsgList->FreeMessageInfo(pInfo);
  1952. }
  1953. MemFree(&rgSelected);
  1954. }
  1955. return (lResult);
  1956. }
  1957. //
  1958. // FUNCTION: CMessageView::OnTestSaveMessage()
  1959. //
  1960. // PURPOSE: This method is for the testing team. Please consult Racheli
  1961. // before making any changes.
  1962. //
  1963. LRESULT CMessageView::OnTestSaveMessage(HWND hwnd)
  1964. {
  1965. DWORD cSel;
  1966. DWORD *rgSelected = NULL;
  1967. TCHAR szFile[MAX_PATH];
  1968. IUnknown *pUnkMessage;
  1969. IMimeMessage *pMessage = NULL;
  1970. LRESULT lResult = -1;
  1971. TraceCall("CMessageView::OnTestSaveMessage");
  1972. // Make sure we only do this in test mode
  1973. if (!DwGetOption(OPT_TEST_MODE))
  1974. return (-1);
  1975. // Get the dump file name
  1976. if (!GetOption(OPT_DUMP_FILE, szFile, ARRAYSIZE(szFile)))
  1977. return (-1);
  1978. // Get the selected range
  1979. if (SUCCEEDED(m_pMsgList->GetSelected(NULL, &cSel, &rgSelected)))
  1980. {
  1981. // Load the first selected message from the store
  1982. if (cSel && SUCCEEDED(m_pMsgList->GetMessage(*rgSelected, FALSE, FALSE, &pUnkMessage)))
  1983. {
  1984. // Get the IMimeMessage interface from the message
  1985. if (pUnkMessage && SUCCEEDED(pUnkMessage->QueryInterface(IID_IMimeMessage, (LPVOID *) &pMessage)))
  1986. {
  1987. // Save the message
  1988. HrSaveMsgToFile(pMessage, (LPTSTR) szFile);
  1989. pMessage->Release();
  1990. lResult = 0;
  1991. }
  1992. pUnkMessage->Release();
  1993. }
  1994. MemFree(rgSelected);
  1995. }
  1996. return (lResult);
  1997. }
  1998. //
  1999. // FUNCTION: CMessageView::CmdOpen()
  2000. //
  2001. // PURPOSE: Opens the selected messages.
  2002. //
  2003. // RETURN VALUE:
  2004. // HRESULT
  2005. //
  2006. HRESULT CMessageView::CmdOpen(DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut)
  2007. {
  2008. HRESULT hr;
  2009. TraceCall("CMessageView::CmdOpen");
  2010. // If more than 10 messages are selected, warn the user with a "Don't show
  2011. // me again" dialog that this could be bad.
  2012. DWORD dwSel = 0;
  2013. m_pMsgList->GetSelectedCount(&dwSel);
  2014. if (dwSel > 10)
  2015. {
  2016. TCHAR szBuffer[CCHMAX_STRINGRES];
  2017. LRESULT lResult;
  2018. AthLoadString(idsErrOpenManyMessages, szBuffer, ARRAYSIZE(szBuffer));
  2019. lResult = DoDontShowMeAgainDlg(m_hwnd, c_szRegManyMsgWarning,
  2020. MAKEINTRESOURCE(idsAthena), szBuffer,
  2021. MB_OKCANCEL);
  2022. if (IDCANCEL == lResult)
  2023. return (S_OK);
  2024. }
  2025. // Get the array of selected rows from the message list
  2026. DWORD *rgRows = NULL;
  2027. DWORD cRows = 0;
  2028. if (FAILED(hr = m_pMsgList->GetSelected(NULL, &cRows, &rgRows)))
  2029. return (hr);
  2030. // It's possible for the message list to go away while we're doing this.
  2031. // To keep us from crashing, make sure you verify it still exists during
  2032. // the loop.
  2033. LPMESSAGEINFO pInfo;
  2034. IMessageTable *pTable = NULL;
  2035. hr = m_pMsgList->GetMessageTable(&pTable);
  2036. if (SUCCEEDED(hr))
  2037. {
  2038. for (DWORD i = 0; (i < cRows && m_pMsgList != NULL); i++)
  2039. {
  2040. if (SUCCEEDED(hr = m_pMsgList->GetMessageInfo(rgRows[i], &pInfo)))
  2041. {
  2042. INIT_MSGSITE_STRUCT initStruct;
  2043. DWORD dwCreateFlags;
  2044. initStruct.initTable.pListSelect = NULL;
  2045. m_pMsgList->GetListSelector(&initStruct.initTable.pListSelect);
  2046. // Initialize note struct
  2047. initStruct.dwInitType = OEMSIT_MSG_TABLE;
  2048. initStruct.initTable.pMsgTable = pTable;
  2049. initStruct.folderID = m_idFolder;
  2050. initStruct.initTable.rowIndex = rgRows[i];
  2051. // Decide whether it is news or mail
  2052. if (pInfo->dwFlags & ARF_NEWSMSG)
  2053. dwCreateFlags = OENCF_NEWSFIRST;
  2054. else
  2055. dwCreateFlags = 0;
  2056. m_pMsgList->FreeMessageInfo(pInfo);
  2057. // Create and Open Note
  2058. hr = CreateAndShowNote(OENA_READ, dwCreateFlags, &initStruct, m_hwnd);
  2059. ReleaseObj(initStruct.initTable.pListSelect);
  2060. if (FAILED(hr))
  2061. break;
  2062. }
  2063. }
  2064. pTable->Release();
  2065. }
  2066. if (SUCCEEDED(hr) && g_pInstance)
  2067. {
  2068. FOLDERTYPE ft = GetFolderType(m_idFolder);
  2069. if (ft == FOLDER_IMAP || ft == FOLDER_LOCAL || ft == FOLDER_HTTPMAIL)
  2070. g_pInstance->UpdateTrayIcon(TRAYICONACTION_REMOVE);
  2071. }
  2072. SafeMemFree(rgRows);
  2073. return (S_OK);
  2074. }
  2075. //
  2076. // FUNCTION: CMessageView::CmdReply()
  2077. //
  2078. // PURPOSE: Replies or Reply-All's to the selected message.
  2079. //
  2080. // RETURN VALUE:
  2081. // HRESULT
  2082. //
  2083. HRESULT CMessageView::CmdReplyForward(DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut)
  2084. {
  2085. HRESULT hr;
  2086. DWORD dwFocused;
  2087. DWORD *rgRows = NULL;
  2088. DWORD cRows = 0;
  2089. OLECMD cmd;
  2090. IMessageTable *pTable = NULL;
  2091. PROPVARIANT var;
  2092. // We can hit this via accelerators. Since accelerators don't go through
  2093. // QueryStatus(), we need to make sure this should really be enabled.
  2094. cmd.cmdID = nCmdID;
  2095. cmd.cmdf = 0;
  2096. if (FAILED(QueryStatus(NULL, 1, &cmd, NULL)) || (0 == (cmd.cmdf & OLECMDF_ENABLED)))
  2097. return (S_OK);
  2098. if (m_pMsgList)
  2099. {
  2100. // Figure out which message is focused
  2101. if (SUCCEEDED(m_pMsgList->GetSelected(&dwFocused, &cRows, &rgRows)))
  2102. {
  2103. INIT_MSGSITE_STRUCT rInitSite;
  2104. DWORD dwCreateFlags;
  2105. DWORD dwAction = 0;
  2106. // Get the message table from the message list. The note will need
  2107. // this to deal with next / prev commands
  2108. hr = m_pMsgList->GetMessageTable(&pTable);
  2109. if (FAILED(hr))
  2110. goto exit;
  2111. if ((1 < cRows) && ((ID_FORWARD == nCmdID) || (ID_FORWARD_AS_ATTACH == nCmdID)))
  2112. {
  2113. IMimeMessage *pMsgFwd = NULL;
  2114. BOOL fErrorsOccured = FALSE,
  2115. fCreateNote = TRUE;
  2116. hr = HrCreateMessage(&pMsgFwd);
  2117. if (FAILED(hr))
  2118. goto exit;
  2119. // Raid 80277; Set default charset
  2120. if (NULL == g_hDefaultCharsetForMail)
  2121. ReadSendMailDefaultCharset();
  2122. pMsgFwd->SetCharset(g_hDefaultCharsetForMail, CSET_APPLY_ALL);
  2123. rInitSite.dwInitType = OEMSIT_MSG;
  2124. rInitSite.pMsg = pMsgFwd;
  2125. rInitSite.folderID = m_idFolder;
  2126. dwCreateFlags = 0;
  2127. dwAction = OENA_COMPOSE;
  2128. for (DWORD i = 0; i < cRows; i++)
  2129. {
  2130. DWORD iRow = rgRows[i];
  2131. IMimeMessage *pMsg = NULL;
  2132. // Since this command is
  2133. hr = pTable->OpenMessage(iRow, OPEN_MESSAGE_SECURE, &pMsg, NOSTORECALLBACK);
  2134. if (SUCCEEDED(hr))
  2135. {
  2136. // If this is the first message, get the account ID from it
  2137. if (i == 0)
  2138. {
  2139. var.vt = VT_LPSTR;
  2140. if (SUCCEEDED(pMsg->GetProp(PIDTOSTR(PID_ATT_ACCOUNTID), NOFLAGS, &var)))
  2141. {
  2142. pMsgFwd->SetProp(PIDTOSTR(PID_ATT_ACCOUNTID), NOFLAGS, &var);
  2143. }
  2144. }
  2145. if (FAILED(pMsgFwd->AttachObject(IID_IMimeMessage, (LPVOID)pMsg, NULL)))
  2146. fErrorsOccured = TRUE;
  2147. pMsg->Release();
  2148. }
  2149. else
  2150. fErrorsOccured = TRUE;
  2151. }
  2152. if (fErrorsOccured)
  2153. {
  2154. if(AthMessageBoxW(m_hwnd, MAKEINTRESOURCEW(idsAthenaMail),
  2155. MAKEINTRESOURCEW(idsErrorAttachingMsgsToNote), NULL, MB_OKCANCEL) == IDCANCEL)
  2156. fCreateNote = FALSE;
  2157. }
  2158. if (fCreateNote)
  2159. hr = CreateAndShowNote(dwAction, dwCreateFlags, &rInitSite, m_hwnd);
  2160. pMsgFwd->Release();
  2161. }
  2162. else
  2163. {
  2164. LPMESSAGEINFO pInfo;
  2165. // Get some information about the message
  2166. if (SUCCEEDED(hr = m_pMsgList->GetMessageInfo(dwFocused, &pInfo)))
  2167. {
  2168. // Determine if this is a news or mail message.
  2169. if (pInfo->dwFlags & ARF_NEWSMSG)
  2170. dwCreateFlags = OENCF_NEWSFIRST;
  2171. else
  2172. dwCreateFlags = 0;
  2173. // Reply or forward
  2174. if (nCmdID == ID_FORWARD)
  2175. dwAction = OENA_FORWARD;
  2176. else if (nCmdID == ID_FORWARD_AS_ATTACH)
  2177. dwAction = OENA_FORWARDBYATTACH;
  2178. else if (nCmdID == ID_REPLY)
  2179. dwAction = OENA_REPLYTOAUTHOR;
  2180. else if (nCmdID == ID_REPLY_ALL)
  2181. dwAction = OENA_REPLYALL;
  2182. else if (nCmdID == ID_REPLY_GROUP)
  2183. dwAction = OENA_REPLYTONEWSGROUP;
  2184. else
  2185. AssertSz(FALSE, "Didn't ask for a valid action");
  2186. // Fill out the initialization information
  2187. rInitSite.dwInitType = OEMSIT_MSG_TABLE;
  2188. rInitSite.initTable.pMsgTable = pTable;
  2189. rInitSite.initTable.pListSelect = NULL;
  2190. rInitSite.folderID = m_idFolder;
  2191. rInitSite.initTable.rowIndex = dwFocused;
  2192. m_pMsgList->FreeMessageInfo(pInfo);
  2193. // Create the note object
  2194. hr = CreateAndShowNote(dwAction, dwCreateFlags, &rInitSite, m_hwnd);
  2195. }
  2196. }
  2197. }
  2198. }
  2199. exit:
  2200. ReleaseObj(pTable);
  2201. SafeMemFree(rgRows);
  2202. return (S_OK);
  2203. }
  2204. HRESULT CMessageView::CmdCancelMessage(DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut)
  2205. {
  2206. HRESULT hr;
  2207. DWORD dwFocused;
  2208. DWORD *rgRows = NULL;
  2209. DWORD cRows = 0;
  2210. if (m_pMsgList)
  2211. {
  2212. // Figure out which message is focused
  2213. if (SUCCEEDED(m_pMsgList->GetSelected(&dwFocused, &cRows, &rgRows)))
  2214. {
  2215. IMessageTable *pTable = NULL;
  2216. LPMESSAGEINFO pInfo;
  2217. // Get the message table from the message list. The note will need
  2218. // this to deal with next / prev commands
  2219. hr = m_pMsgList->GetMessageTable(&pTable);
  2220. if (FAILED(hr))
  2221. goto exit;
  2222. // Get some information about the message
  2223. if (SUCCEEDED(hr = m_pMsgList->GetMessageInfo(dwFocused, &pInfo)))
  2224. {
  2225. hr = NewsUtil_HrCancelPost(m_hwnd, m_idFolder, pInfo);
  2226. m_pMsgList->FreeMessageInfo(pInfo);
  2227. }
  2228. pTable->Release();
  2229. }
  2230. }
  2231. exit:
  2232. SafeMemFree(rgRows);
  2233. return (S_OK);
  2234. }
  2235. //
  2236. // FUNCTION: CMessageView::CmdFillPreview()
  2237. //
  2238. // PURPOSE: Fills the preview pane with the selected & focused message.
  2239. //
  2240. // RETURN VALUE:
  2241. // HRESULT
  2242. //
  2243. HRESULT CMessageView::CmdFillPreview(DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut)
  2244. {
  2245. AssertSz(FALSE, "NYI");
  2246. return (E_NOTIMPL);
  2247. }
  2248. //
  2249. // FUNCTION: CMessageView::CmdShowPreview()
  2250. //
  2251. // PURPOSE: Handles updating the settings dealing with the preview pane.
  2252. //
  2253. // RETURN VALUE:
  2254. // HRESULT
  2255. //
  2256. HRESULT CMessageView::CmdShowPreview(DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut)
  2257. {
  2258. FOLDERTYPE ftType;
  2259. DWORD dwOpt;
  2260. LAYOUTPOS pos;
  2261. BOOL fVisible;
  2262. DWORD dwFlags;
  2263. // Get the folder type
  2264. m_pBrowser->GetFolderType(&ftType);
  2265. if (ftType == FOLDER_NEWS)
  2266. dwOpt = DISPID_MSGVIEW_PREVIEWPANE_NEWS;
  2267. else
  2268. dwOpt = DISPID_MSGVIEW_PREVIEWPANE_MAIL;
  2269. // Get the current settings from the browser
  2270. m_pBrowser->GetViewLayout(dwOpt, NULL, &fVisible, &dwFlags, NULL);
  2271. // Update the settings just based on the command
  2272. switch (nCmdID)
  2273. {
  2274. case ID_PREVIEW_PANE:
  2275. case ID_PREVIEW_SHOW:
  2276. {
  2277. // Set the complement of the visible bit
  2278. m_pBrowser->SetViewLayout(dwOpt, LAYOUT_POS_NA, !fVisible, dwFlags, NULL);
  2279. if (!fVisible)
  2280. {
  2281. // if showing update the preview pane
  2282. _UpdatePreviewPane();
  2283. }
  2284. else
  2285. {
  2286. // if hiding, clear the contents
  2287. m_pPreview->HrUnloadAll(NULL, 0);
  2288. }
  2289. break;
  2290. }
  2291. case ID_PREVIEW_BELOW:
  2292. {
  2293. // Update the position
  2294. m_pBrowser->SetViewLayout(dwOpt, LAYOUT_POS_BOTTOM, fVisible, dwFlags, NULL);
  2295. break;
  2296. }
  2297. case ID_PREVIEW_BESIDE:
  2298. {
  2299. // Update the position
  2300. m_pBrowser->SetViewLayout(dwOpt, LAYOUT_POS_LEFT, fVisible, dwFlags, NULL);
  2301. break;
  2302. }
  2303. case ID_PREVIEW_HEADER:
  2304. {
  2305. // Toggle the header flags
  2306. m_pBrowser->SetViewLayout(dwOpt, LAYOUT_POS_NA, fVisible, !dwFlags, NULL);
  2307. break;
  2308. }
  2309. default:
  2310. Assert(FALSE);
  2311. }
  2312. return (S_OK);
  2313. }
  2314. //
  2315. // FUNCTION: CMessageView::CmdRefresh()
  2316. //
  2317. // PURPOSE: Refreshes the contents of the message list.
  2318. //
  2319. // RETURN VALUE:
  2320. // HRESULT
  2321. //
  2322. HRESULT CMessageView::CmdRefresh(DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG* pvaIn, VARIANTARG *pvaOut)
  2323. {
  2324. HRESULT hr = E_FAIL;
  2325. FOLDERINFO FolderInfo;
  2326. TraceCall("CMessageView::CmdRefresh");
  2327. // Call into the message list now and let it refresh
  2328. if (m_pMsgListCT)
  2329. hr = m_pMsgListCT->Exec(NULL, ID_REFRESH_INNER, nCmdExecOpt, pvaIn, pvaOut);
  2330. // If we succeeded in refreshing the message list, also try to reload the
  2331. // preview pane.
  2332. _UpdatePreviewPane();
  2333. // If this is a local folder and this isn't newsonly mode, in the past we
  2334. // do a Send & Recieve.
  2335. if (FOLDER_LOCAL == GetFolderType(m_idFolder) && 0 == (g_dwAthenaMode & MODE_NEWSONLY))
  2336. PostMessage(m_hwndParent, WM_COMMAND, ID_SEND_RECEIVE, 0);
  2337. return (hr);
  2338. }
  2339. //
  2340. // FUNCTION: CMessageView::CmdBlockSender()
  2341. //
  2342. // PURPOSE: Add the sender of the selected messages to the block senders list
  2343. //
  2344. // RETURN VALUE:
  2345. // HRESULT
  2346. //
  2347. HRESULT CMessageView::CmdBlockSender(DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut)
  2348. {
  2349. HRESULT hr = S_OK;
  2350. DWORD * rgRows = NULL;
  2351. DWORD cRows = 0;
  2352. LPMESSAGEINFO pInfo = NULL;
  2353. IUnknown * pUnkMessage = NULL;
  2354. IMimeMessage * pMessage = 0;
  2355. LPSTR pszEmailFrom = NULL;
  2356. ADDRESSPROPS rSender = {0};
  2357. CHAR szRes[CCHMAX_STRINGRES];
  2358. LPSTR pszResult = NULL;
  2359. IOERule * pIRule = NULL;
  2360. BOOL fMsgInfoFreed = FALSE;
  2361. TraceCall("CMessageView::CmdBlockSender");
  2362. hr = m_pMsgList->GetSelected(NULL, &cRows, &rgRows);
  2363. if (FAILED(hr))
  2364. {
  2365. goto exit;
  2366. }
  2367. // It's possible for the message list to go away while we're doing this.
  2368. // To keep us from crashing, make sure you verify it still exists during
  2369. // the loop.
  2370. hr = m_pMsgList->GetMessageInfo(rgRows[0], &pInfo);
  2371. if (FAILED(hr))
  2372. {
  2373. goto exit;
  2374. }
  2375. // Do we already have the address?
  2376. if ((NULL != pInfo->pszEmailFrom) && ('\0' != pInfo->pszEmailFrom[0]))
  2377. {
  2378. pszEmailFrom = PszDupA(pInfo->pszEmailFrom);
  2379. if (NULL == pszEmailFrom)
  2380. {
  2381. hr = E_OUTOFMEMORY;
  2382. goto exit;
  2383. }
  2384. }
  2385. else
  2386. {
  2387. // Load that message from the store
  2388. hr = m_pMsgList->GetMessage(rgRows[0], FALSE, FALSE, &pUnkMessage);
  2389. if (FAILED(hr))
  2390. {
  2391. goto exit;
  2392. }
  2393. if (NULL == pUnkMessage)
  2394. {
  2395. hr = E_FAIL;
  2396. goto exit;
  2397. }
  2398. // Get the IMimeMessage interface from the message
  2399. hr = pUnkMessage->QueryInterface(IID_IMimeMessage, (LPVOID *) &pMessage);
  2400. if (FAILED(hr))
  2401. {
  2402. goto exit;
  2403. }
  2404. rSender.dwProps = IAP_EMAIL;
  2405. hr = pMessage->GetSender(&rSender);
  2406. if (FAILED(hr))
  2407. {
  2408. goto exit;
  2409. }
  2410. Assert(rSender.pszEmail && ISFLAGSET(rSender.dwProps, IAP_EMAIL));
  2411. if ((NULL == rSender.pszEmail) || ('\0' == rSender.pszEmail[0]))
  2412. {
  2413. hr = E_FAIL;
  2414. goto exit;
  2415. }
  2416. pszEmailFrom = PszDupA(rSender.pszEmail);
  2417. if (NULL == pszEmailFrom)
  2418. {
  2419. hr = E_OUTOFMEMORY;
  2420. goto exit;
  2421. }
  2422. // We don't need the message anymore
  2423. g_pMoleAlloc->FreeAddressProps(&rSender);
  2424. ZeroMemory(&rSender, sizeof(rSender));
  2425. SafeRelease(pMessage);
  2426. }
  2427. // Free up the info
  2428. m_pMsgList->FreeMessageInfo(pInfo);
  2429. fMsgInfoFreed = TRUE;
  2430. // Bring up the rule editor for this message
  2431. hr = RuleUtil_HrAddBlockSender((0 != (pInfo->dwFlags & ARF_NEWSMSG)) ? RULE_TYPE_NEWS : RULE_TYPE_MAIL, pszEmailFrom);
  2432. if (FAILED(hr))
  2433. {
  2434. goto exit;
  2435. }
  2436. // Load the template string
  2437. AthLoadString(idsSenderAddedPrompt, szRes, sizeof(szRes));
  2438. // Allocate the space to hold the final string
  2439. DWORD cchSize = (lstrlen(szRes) + lstrlen(pszEmailFrom) + 1);
  2440. hr = HrAlloc((VOID **) &pszResult, sizeof(*pszResult) * cchSize);
  2441. if (FAILED(hr))
  2442. {
  2443. goto exit;
  2444. }
  2445. // Build up the warning string
  2446. wnsprintf(pszResult, cchSize, szRes, pszEmailFrom);
  2447. // Show the success dialog
  2448. if (IDYES == AthMessageBox(m_hwnd, MAKEINTRESOURCE(idsAthena), pszResult, NULL, MB_YESNO | MB_ICONINFORMATION))
  2449. {
  2450. // Create a block sender rule
  2451. hr = HrBlockSendersFromFolder(m_hwnd, 0, m_idFolder, &pszEmailFrom, 1);
  2452. if (FAILED(hr))
  2453. {
  2454. goto exit;
  2455. }
  2456. }
  2457. hr = S_OK;
  2458. exit:
  2459. SafeRelease(pIRule);
  2460. SafeMemFree(pszResult);
  2461. g_pMoleAlloc->FreeAddressProps(&rSender);
  2462. SafeRelease(pMessage);
  2463. SafeRelease(pUnkMessage);
  2464. SafeMemFree(pszEmailFrom);
  2465. if (FALSE == fMsgInfoFreed)
  2466. {
  2467. m_pMsgList->FreeMessageInfo(pInfo);
  2468. }
  2469. SafeMemFree(rgRows);
  2470. if (FAILED(hr))
  2471. {
  2472. AthMessageBoxW(m_hwnd, MAKEINTRESOURCEW(idsAthena),
  2473. MAKEINTRESOURCEW(idsSenderError), NULL, MB_OK | MB_ICONERROR);
  2474. }
  2475. return (hr);
  2476. }
  2477. //
  2478. // FUNCTION: CMessageView::CmdCreateRule()
  2479. //
  2480. // PURPOSE: Add the sender of the selected messages to the block senders list
  2481. //
  2482. // RETURN VALUE:
  2483. // HRESULT
  2484. //
  2485. HRESULT CMessageView::CmdCreateRule(DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut)
  2486. {
  2487. HRESULT hr;
  2488. DWORD * rgRows = NULL;
  2489. DWORD cRows = 0;
  2490. LPMESSAGEINFO pInfo = NULL;
  2491. IUnknown * pUnkMessage = NULL;
  2492. IMimeMessage * pMessage = 0;
  2493. TraceCall("CMessageView::CmdCreateRule");
  2494. // Get the array of selected rows from the message list
  2495. if (FAILED(hr = m_pMsgList->GetSelected(NULL, &cRows, &rgRows)))
  2496. return (hr);
  2497. // It's possible for the message list to go away while we're doing this.
  2498. // To keep us from crashing, make sure you verify it still exists during
  2499. // the loop.
  2500. if (SUCCEEDED(hr = m_pMsgList->GetMessageInfo(rgRows[0], &pInfo)))
  2501. {
  2502. // Load that message from the store
  2503. if (S_OK == m_pMsgList->GetMessage(rgRows[0], FALSE, FALSE, &pUnkMessage))
  2504. {
  2505. // Get the IMimeMessage interface from the message
  2506. if (NULL != pUnkMessage)
  2507. {
  2508. pUnkMessage->QueryInterface(IID_IMimeMessage, (LPVOID *) &pMessage);
  2509. }
  2510. }
  2511. // Bring up the rule editor for this message
  2512. hr = HrCreateRuleFromMessage(m_hwnd, (0 != (pInfo->dwFlags & ARF_NEWSMSG)) ?
  2513. CRFMF_NEWS : CRFMF_MAIL, pInfo, pMessage);
  2514. }
  2515. SafeRelease(pMessage);
  2516. SafeRelease(pUnkMessage);
  2517. m_pMsgList->FreeMessageInfo(pInfo);
  2518. SafeMemFree(rgRows);
  2519. return (S_OK);
  2520. }
  2521. //
  2522. // FUNCTION: CMessageView::CmdAddToWab()
  2523. //
  2524. // PURPOSE: Add the sender of the selected messages to the WAB
  2525. //
  2526. // RETURN VALUE:
  2527. // HRESULT
  2528. //
  2529. HRESULT CMessageView::CmdAddToWab(DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut)
  2530. {
  2531. HRESULT hr = S_OK;
  2532. DWORD *rgRows = NULL;
  2533. DWORD cRows = 0;
  2534. LPMESSAGEINFO pInfo;
  2535. LPWAB pWAB = 0;
  2536. TraceCall("CMessageView::CmdAddToWab");
  2537. // Get the array of selected rows from the message list
  2538. if (FAILED(hr = m_pMsgList->GetSelected(NULL, &cRows, &rgRows)))
  2539. return (hr);
  2540. // Get the header info for the message
  2541. if (SUCCEEDED(hr = m_pMsgList->GetMessageInfo(rgRows[0], &pInfo)))
  2542. {
  2543. // Get a WAB object
  2544. if (SUCCEEDED(hr = HrCreateWabObject(&pWAB)))
  2545. {
  2546. // Add the sender to the WAB
  2547. if (FAILED(hr = pWAB->HrAddNewEntryA(pInfo->pszDisplayFrom, pInfo->pszEmailFrom)))
  2548. {
  2549. if (hr == MAPI_E_COLLISION)
  2550. AthMessageBoxW(m_hwnd, MAKEINTRESOURCEW(idsAthena), MAKEINTRESOURCEW(idsErrAddrDupe), 0, MB_OK | MB_ICONSTOP);
  2551. else
  2552. AthMessageBoxW(m_hwnd, MAKEINTRESOURCEW(idsAthena), MAKEINTRESOURCEW(idsErrAddToWabSender), 0, MB_OK | MB_ICONSTOP);
  2553. }
  2554. pWAB->Release();
  2555. }
  2556. m_pMsgList->FreeMessageInfo(pInfo);
  2557. }
  2558. SafeMemFree(rgRows);
  2559. return (S_OK);
  2560. }
  2561. //
  2562. // FUNCTION: CMessageView::CmdCombineAndDecode()
  2563. //
  2564. // PURPOSE: Combines the selected messages into a single message.
  2565. //
  2566. // RETURN VALUE:
  2567. // HRESULT
  2568. //
  2569. HRESULT CMessageView::CmdCombineAndDecode(DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut)
  2570. {
  2571. DWORD *rgRows = NULL;
  2572. DWORD cRows = 0;
  2573. CCombineAndDecode *pDecode = NULL;
  2574. HRESULT hr;
  2575. // Create the decoder object
  2576. pDecode = new CCombineAndDecode();
  2577. if (!pDecode)
  2578. return (S_OK);
  2579. // Get the array of selected rows from the message list
  2580. if (FAILED(hr = m_pMsgList->GetSelected(NULL, &cRows, &rgRows)))
  2581. return (hr);
  2582. // Get a pointer to the message table
  2583. IMessageTable *pTable = NULL;
  2584. if (SUCCEEDED(m_pMsgList->GetMessageTable(&pTable)))
  2585. {
  2586. // Initialize the decoder
  2587. pDecode->Start(m_hwnd, pTable, rgRows, cRows, m_idFolder);
  2588. }
  2589. SafeMemFree(rgRows);
  2590. pDecode->Release();
  2591. pTable->Release();
  2592. return (S_OK);
  2593. }
  2594. //
  2595. // FUNCTION: CMessageView::_SetListOptions()
  2596. //
  2597. // PURPOSE: Maps the folder that we're about to view to the correct column
  2598. // set and various options.
  2599. //
  2600. // RETURN VALUE:
  2601. // Returns S_OK if the column set was identified and set correctly. Returns
  2602. // a standard error HRESULT otherwise.
  2603. //
  2604. HRESULT CMessageView::_SetListOptions(void)
  2605. {
  2606. HRESULT hr;
  2607. BOOL fSelectFirst = FALSE;
  2608. FOLDERTYPE ft = GetFolderType(m_idFolder);
  2609. // Make sure this badboy exists
  2610. if (!m_pMsgList)
  2611. return (E_UNEXPECTED);
  2612. FOLDER_OPTIONS fo = {0};
  2613. fo.cbSize = sizeof(FOLDER_OPTIONS);
  2614. fo.dwMask = FOM_EXPANDTHREADS | FOM_SELECTFIRSTUNREAD | FOM_THREAD | FOM_MESSAGELISTTIPS | FOM_POLLTIME | FOM_COLORWATCHED | FOM_GETXHEADERS | FOM_SHOWDELETED | FOM_SHOWREPLIES;
  2615. fo.fExpandThreads = DwGetOption(OPT_AUTOEXPAND);
  2616. fo.fMessageListTips = DwGetOption(OPT_MESSAGE_LIST_TIPS);
  2617. fo.dwPollTime = DwGetOption(OPT_POLLFORMSGS);
  2618. fo.clrWatched = DwGetOption(OPT_WATCHED_COLOR);
  2619. fo.dwGetXHeaders = DwGetOption(OPT_DOWNLOADCHUNKS);
  2620. fo.fDeleted = DwGetOption(OPT_SHOW_DELETED);
  2621. fo.fReplies = DwGetOption(OPT_SHOW_REPLIES);
  2622. switch (ft)
  2623. {
  2624. case FOLDER_NEWS:
  2625. fo.fThread = DwGetOption(OPT_NEWS_THREAD);
  2626. fo.fSelectFirstUnread = TRUE;
  2627. break;
  2628. case FOLDER_LOCAL:
  2629. case FOLDER_HTTPMAIL:
  2630. fo.fThread = DwGetOption(OPT_MAIL_THREAD);
  2631. fo.fSelectFirstUnread = FALSE;
  2632. break;
  2633. case FOLDER_IMAP:
  2634. fo.fThread = DwGetOption(OPT_MAIL_THREAD);
  2635. fo.fSelectFirstUnread = FALSE;
  2636. break;
  2637. }
  2638. hr = m_pMsgList->SetViewOptions(&fo);
  2639. return (hr);
  2640. }
  2641. BOOL CMessageView::_IsPreview(void)
  2642. {
  2643. FOLDERTYPE ftType;
  2644. DWORD dwOpt;
  2645. // Get the folder type
  2646. m_pBrowser->GetFolderType(&ftType);
  2647. if (ftType == FOLDER_NEWS)
  2648. dwOpt = DISPID_MSGVIEW_PREVIEWPANE_NEWS;
  2649. else
  2650. dwOpt = DISPID_MSGVIEW_PREVIEWPANE_MAIL;
  2651. // Ask the browser if it should be on or off
  2652. BOOL f = FALSE;
  2653. if (m_pBrowser)
  2654. m_pBrowser->GetViewLayout(dwOpt, 0, &f, 0, 0);
  2655. return f;
  2656. }
  2657. BOOL CMessageView::_InitMessageList(void)
  2658. {
  2659. HWND hwndList;
  2660. // Create the message list object
  2661. if (FAILED(CreateMessageList(NULL, &m_pMsgList)))
  2662. return (FALSE);
  2663. // Initialize the message list
  2664. m_pMsgList->CreateList(m_hwnd, (IViewWindow *) this, &hwndList);
  2665. // Get the command target interface for the list
  2666. m_pMsgList->QueryInterface(IID_IOleCommandTarget, (LPVOID *) &m_pMsgListCT);
  2667. m_pMsgList->QueryInterface(IID_IOleInPlaceActiveObject, (LPVOID *) &m_pMsgListAO);
  2668. // Request Notifications
  2669. AtlAdvise(m_pMsgList, (IUnknown *)(IViewWindow *) this, DIID__MessageListEvents, &m_dwCookie);
  2670. // Set the column set for the message list
  2671. _SetListOptions();
  2672. return (TRUE);
  2673. }
  2674. //
  2675. // FUNCTION: CMessageView::_InitPreviewPane()
  2676. //
  2677. // PURPOSE: Creates the Preview Pane object and initializes it.
  2678. //
  2679. // RETURN VALUE:
  2680. // TRUE if the object was created and initialized, FALSE otherwise.
  2681. //
  2682. BOOL CMessageView::_InitPreviewPane(void)
  2683. {
  2684. CMimeEditDocHost *pDocHost = NULL;
  2685. CStatusBar *pStatusBar = NULL;
  2686. DWORD dwHeader;
  2687. LAYOUTPOS pos;
  2688. BOOL fVisible;
  2689. DWORD dwOpt;
  2690. HRESULT hr;
  2691. FOLDERTYPE ftType;
  2692. DWORD dwSize;
  2693. TraceCall("CMessageView::_InitPreviewPane");
  2694. // We only create the preview pane if it's supposed to be visible.
  2695. m_pBrowser->GetFolderType(&ftType);
  2696. if (ftType == FOLDER_NEWS)
  2697. dwOpt = DISPID_MSGVIEW_PREVIEWPANE_NEWS;
  2698. else
  2699. dwOpt = DISPID_MSGVIEW_PREVIEWPANE_MAIL;
  2700. // Get the settings from the browser
  2701. m_pBrowser->GetViewLayout(dwOpt, &pos, &fVisible, &dwHeader, &dwSize);
  2702. // Stash this info
  2703. m_dwSplitHorzPct = LOWORD(dwSize);
  2704. m_dwSplitVertPct = HIWORD(dwSize);
  2705. if (fVisible)
  2706. {
  2707. // Create the dochost
  2708. pDocHost = new CMimeEditDocHost(MEBF_OUTERCLIENTEDGE);
  2709. if (!pDocHost)
  2710. goto error;
  2711. // We want to get the IBodyObj2 interface from it.
  2712. pDocHost->QueryInterface(IID_IBodyObj2, (LPVOID *) &m_pPreview);
  2713. if (!m_pPreview)
  2714. goto error;
  2715. pDocHost->Release();
  2716. // Also get the IOleCommandTarget interface from it. If it fails, that's OK.
  2717. m_pPreview->QueryInterface(IID_IOleCommandTarget, (LPVOID *) &m_pPreviewCT);
  2718. if (m_pBrowser->GetStatusBar(&pStatusBar)==S_OK)
  2719. {
  2720. m_pPreview->HrSetStatusBar(pStatusBar);
  2721. pStatusBar->Release();
  2722. }
  2723. // Create the preview window
  2724. if (FAILED(m_pPreview->HrInit(m_hwnd, IBOF_DISPLAYTO|IBOF_TABLINKS, (IBodyOptions *) this)))
  2725. goto error;
  2726. hr = m_pPreview->HrShow(fVisible);
  2727. if (FAILED(hr))
  2728. goto error;
  2729. m_pPreview->HrSetText(MAKEINTRESOURCE(idsHTMLEmptyPreviewSel));
  2730. UpdateLayout(fVisible, dwHeader, pos == LAYOUT_POS_LEFT, FALSE);
  2731. // Give the preview pane our event sink interface
  2732. m_pPreview->SetEventSink((IMimeEditEventSink *) this);
  2733. return (TRUE);
  2734. }
  2735. error:
  2736. SafeRelease(pDocHost);
  2737. SafeRelease(m_pPreview);
  2738. return (FALSE);
  2739. }
  2740. void CMessageView::_UpdatePreviewPane(BOOL fForceDownload)
  2741. {
  2742. DWORD dwFocused;
  2743. DWORD cSelected;
  2744. DWORD *rgSelected = 0;
  2745. IUnknown *pUnkMessage = 0;
  2746. HRESULT hr;
  2747. if (m_pMsgList && m_pPreview)
  2748. {
  2749. m_idMessageFocus = MESSAGEID_INVALID;
  2750. m_fNotDownloaded = FALSE;
  2751. // Figure out which message is focused
  2752. if (SUCCEEDED(m_pMsgList->GetSelected(&dwFocused, &cSelected, &rgSelected)))
  2753. {
  2754. // If there is a focused item
  2755. if (-1 == dwFocused || 0 == cSelected)
  2756. {
  2757. m_pPreview->HrUnloadAll(idsHTMLEmptyPreviewSel, 0);
  2758. }
  2759. else
  2760. {
  2761. // Load that message from the store
  2762. hr = m_pMsgList->GetMessage(dwFocused, fForceDownload || DwGetOption(OPT_AUTOFILLPREVIEW), TRUE, &pUnkMessage);
  2763. switch (hr)
  2764. {
  2765. case MIME_E_SECURITY_CANTDECRYPT:
  2766. m_pPreview->LoadHtmlErrorPage(c_szErrPage_SMimeEncrypt);
  2767. break;
  2768. #ifdef SMIME_V3
  2769. case MIME_E_SECURITY_LABELACCESSDENIED:
  2770. case MIME_E_SECURITY_LABELACCESSCANCELLED:
  2771. case MIME_E_SECURITY_LABELCORRUPT:
  2772. m_pPreview->LoadHtmlErrorPage(c_szErrPage_SMimeLabel);
  2773. break;
  2774. #endif // SMIME_V3
  2775. case STORE_E_EXPIRED:
  2776. m_pPreview->LoadHtmlErrorPage(c_szErrPage_Expired);
  2777. break;
  2778. case STORE_E_NOBODY:
  2779. AssertSz(DwGetOption(OPT_AUTOFILLPREVIEW)==FALSE, "AutoPreview is on, download should have been started!");
  2780. if (g_pConMan->IsGlobalOffline())
  2781. m_pPreview->LoadHtmlErrorPage(c_szErrPage_Offline);
  2782. else
  2783. m_pPreview->LoadHtmlErrorPage(c_szErrPage_NotDownloaded);
  2784. m_fNotDownloaded = TRUE;
  2785. break;
  2786. case DB_E_DISKFULL:
  2787. m_pPreview->LoadHtmlErrorPage(c_szErrPage_DiskFull);
  2788. break;
  2789. case DB_S_NOTFOUND:
  2790. {
  2791. FOLDERINFO FolderInfo;
  2792. //I don't think we need this coz its being handled in callbackcanconnect
  2793. //If the message is not found in the store, we ask it to download.
  2794. if (g_pStore && SUCCEEDED(g_pStore->GetFolderInfo(m_idFolder, &FolderInfo)))
  2795. {
  2796. if(g_pConMan && !(g_pConMan->IsGlobalOffline()))
  2797. {
  2798. CHAR szAccountId[CCHMAX_ACCOUNT_NAME];
  2799. if (SUCCEEDED(GetFolderAccountId(&FolderInfo, szAccountId, ARRAYSIZE(szAccountId))))
  2800. {
  2801. if (g_pConMan->Connect(szAccountId, m_hwnd, TRUE)== S_OK)
  2802. hr = m_pMsgList->GetMessage(dwFocused, TRUE, TRUE, &pUnkMessage);
  2803. }
  2804. }
  2805. g_pStore->FreeRecord(&FolderInfo);
  2806. }
  2807. break;
  2808. }
  2809. case STORE_S_ALREADYPENDING:
  2810. case E_PENDING:
  2811. {
  2812. // if the message is being downloaded, let's store the message-id and wait for an update
  2813. LPMESSAGEINFO pInfo;
  2814. // clear the contents waiting for the new message to download
  2815. m_pPreview->HrUnloadAll(NULL, 0);
  2816. if (SUCCEEDED(m_pMsgList->GetMessageInfo(dwFocused, &pInfo)))
  2817. {
  2818. m_idMessageFocus = pInfo->idMessage;
  2819. m_pMsgList->FreeMessageInfo(pInfo);
  2820. }
  2821. break;
  2822. }
  2823. case E_NOT_ONLINE:
  2824. {
  2825. m_pPreview->LoadHtmlErrorPage(c_szErrPage_Offline);
  2826. break;
  2827. }
  2828. case S_OK:
  2829. {
  2830. // Get the IMimeMessage interface from the message
  2831. IMimeMessage *pMessage = 0;
  2832. if (pUnkMessage && SUCCEEDED(pUnkMessage->QueryInterface(IID_IMimeMessage, (LPVOID *) &pMessage)))
  2833. {
  2834. // bobn, brianv says we have to remove this...
  2835. /*if (g_dwBrowserFlags == 1)
  2836. {
  2837. LPSTR lpsz = NULL;
  2838. if (SUCCEEDED(MimeOleGetBodyPropA(pMessage, HBODY_ROOT, PIDTOSTR(PID_HDR_SUBJECT), NOFLAGS, &lpsz)))
  2839. {
  2840. if (0 == strcmp(lpsz, "Credits"))
  2841. g_dwBrowserFlags |= 2;
  2842. else
  2843. g_dwBrowserFlags = 0;
  2844. SafeMimeOleFree(lpsz);
  2845. }
  2846. }*/
  2847. if (_DoEmailBombCheck(pMessage)==S_OK)
  2848. {
  2849. // Get the load interface from the preview pane object
  2850. IPersistMime *pPersistMime = 0;
  2851. if (SUCCEEDED(m_pPreview->QueryInterface(IID_IPersistMime, (LPVOID *) &pPersistMime)))
  2852. {
  2853. DWORD dwHeader;
  2854. LAYOUTPOS pos;
  2855. BOOL fVisible;
  2856. DWORD dwOpt;
  2857. DWORD dwSize;
  2858. FOLDERTYPE ftType;
  2859. CStatusBar *pStatusBar = NULL;
  2860. // remember focus
  2861. BOOL fFocused = ((m_pPreview->HrHasFocus() == S_OK) ? TRUE : FALSE);
  2862. m_pBrowser->GetFolderType(&ftType);
  2863. if (ftType == FOLDER_NEWS)
  2864. dwOpt = DISPID_MSGVIEW_PREVIEWPANE_NEWS;
  2865. else
  2866. dwOpt = DISPID_MSGVIEW_PREVIEWPANE_MAIL;
  2867. // Get the settings from the browser
  2868. m_pBrowser->GetViewLayout(dwOpt, &pos, &fVisible, &dwHeader, &dwSize);
  2869. m_pPreview->HrResetDocument();
  2870. m_pPreview->HrSetStyle(dwHeader ? MESTYLE_PREVIEW : MESTYLE_MINIHEADER);
  2871. // Give the preview pane our event sink interface
  2872. m_pPreview->SetEventSink((IMimeEditEventSink *) this);
  2873. pPersistMime->Load(pMessage);
  2874. pPersistMime->Release();
  2875. // restore status bar
  2876. if (m_pBrowser->GetStatusBar(&pStatusBar)==S_OK)
  2877. {
  2878. m_pPreview->HrSetStatusBar(pStatusBar);
  2879. pStatusBar->Release();
  2880. }
  2881. // return focus
  2882. if(fFocused)
  2883. m_pPreview->HrSetUIActivate();
  2884. }
  2885. }
  2886. pMessage->Release();
  2887. }
  2888. pUnkMessage->Release();
  2889. break;
  2890. }
  2891. default:
  2892. m_pPreview->LoadHtmlErrorPage(c_szErrPage_GenFailure);
  2893. break;
  2894. }
  2895. }
  2896. if (rgSelected)
  2897. MemFree(rgSelected);
  2898. }
  2899. }
  2900. }
  2901. //
  2902. // FUNCTION: CMessageView::_SetProgressStatusText()
  2903. //
  2904. // PURPOSE: Takes the provided BSTR, converts it to ANSI, and smacks it
  2905. // on the status bar.
  2906. //
  2907. // PARAMETERS:
  2908. // [in] bstr - henious BSTR to put on the status bar.
  2909. //
  2910. void CMessageView::_SetProgressStatusText(BSTR bstr)
  2911. {
  2912. LPTSTR psz = NULL;
  2913. CStatusBar *pStatusBar = NULL;
  2914. m_pBrowser->GetStatusBar(&pStatusBar);
  2915. if (pStatusBar)
  2916. {
  2917. pStatusBar->SetStatusText((LPTSTR) bstr);
  2918. /*
  2919. CComBSTR cString(bstr);
  2920. // Allocate a string large enough
  2921. if (MemAlloc((LPVOID *) &psz, 2 * cString.Length()))
  2922. {
  2923. WideCharToMultiByte(CP_ACP, 0, cString, -1,
  2924. psz, 2 * cString.Length(), NULL, NULL);
  2925. pStatusBar->SetStatusText((LPTSTR) psz);
  2926. MemFree(psz);
  2927. }
  2928. */
  2929. pStatusBar->Release();
  2930. }
  2931. }
  2932. //
  2933. // FUNCTION: CMessageView::_OnMessageAvailable()
  2934. //
  2935. // PURPOSE: Fired by the listview when a message has completed downloading
  2936. // if the message is the currently selected message in the preview
  2937. // then we update it. If it is not, we ignore the notification.
  2938. // We check for downloading errors and display and appropriate message
  2939. //
  2940. // PARAMETERS:
  2941. // [in] idMessage - message id of the message that was downloaded
  2942. // [in] hrCompletion - hresult indicating possible error failure
  2943. //
  2944. HRESULT CMessageView::_OnMessageAvailable(MESSAGEID idMessage, HRESULT hrCompletion)
  2945. {
  2946. if (m_idMessageFocus != idMessage)
  2947. return S_FALSE;
  2948. switch (hrCompletion)
  2949. {
  2950. // if we get a STORE_E_EXPIRED, then reload the preview pane to show error
  2951. case S_OK:
  2952. case STORE_E_EXPIRED:
  2953. // we post a message to ourselves to update the preview pane. We do this because
  2954. // any refcounts on the IStream into the store at this point have it locked for write
  2955. // if we post, then the stack is unwound after the notifications are fired and we're in a
  2956. // good state.
  2957. PostMessage(m_hwnd, WM_UPDATE_PREVIEW, (WPARAM)idMessage, 0);
  2958. break;
  2959. case S_FALSE:
  2960. case STORE_E_OPERATION_CANCELED:
  2961. case hrUserCancel:
  2962. case IXP_E_USER_CANCEL:
  2963. // S_FALSE means the operation was canceled
  2964. if (m_idMessageFocus != MESSAGEID_INVALID)
  2965. m_pPreview->LoadHtmlErrorPage(c_szErrPage_DownloadCanceled);
  2966. break;
  2967. case STG_E_MEDIUMFULL:
  2968. m_pPreview->LoadHtmlErrorPage(c_szErrPage_DiskFull);
  2969. break;
  2970. case HR_E_USER_CANCEL_CONNECT:
  2971. case HR_E_OFFLINE:
  2972. m_pPreview->LoadHtmlErrorPage(c_szErrPage_Offline);
  2973. break;
  2974. case MIME_E_SECURITY_CANTDECRYPT:
  2975. m_pPreview->LoadHtmlErrorPage(c_szErrPage_SMimeEncrypt);
  2976. break;
  2977. #ifdef SMIME_V3
  2978. case MIME_E_SECURITY_LABELACCESSDENIED:
  2979. case MIME_E_SECURITY_LABELACCESSCANCELLED:
  2980. case MIME_E_SECURITY_LABELCORRUPT:
  2981. m_pPreview->LoadHtmlErrorPage(c_szErrPage_SMimeLabel);
  2982. break;
  2983. #endif // SMIME_V3
  2984. default:
  2985. m_pPreview->LoadHtmlErrorPage(c_szErrPage_GenFailure);
  2986. break;
  2987. }
  2988. return S_OK;
  2989. }
  2990. //
  2991. // FUNCTION: CMessageView::_DoEmailBombCheck
  2992. //
  2993. // PURPOSE: Validates to ensure that the last time we closed OE we shutdown
  2994. // correctly. If we did not shutdown correctly, we look at the msgid stamp
  2995. // that we stored in the registry for the last selected preview message
  2996. // if it was the message we are about to preview, we do not show the
  2997. // message, to prevent jscript attacks etc.
  2998. //
  2999. // PARAMETERS:
  3000. // none
  3001. //
  3002. HRESULT CMessageView::_DoEmailBombCheck(LPMIMEMESSAGE pMsg)
  3003. {
  3004. FILETIME ft;
  3005. PROPVARIANT va;
  3006. DWORD dwType,
  3007. cb;
  3008. va.vt = VT_FILETIME;
  3009. if (pMsg && pMsg->GetProp(PIDTOSTR(STR_HDR_DATE), 0, &va)==S_OK)
  3010. {
  3011. if (g_fBadShutdown)
  3012. {
  3013. g_fBadShutdown=FALSE;
  3014. cb = sizeof(FILETIME);
  3015. if (AthUserGetValue(NULL, c_szLastMsg, &dwType, (LPBYTE)&ft, &cb)==S_OK &&
  3016. (ft.dwLowDateTime == va.filetime.dwLowDateTime &&
  3017. ft.dwHighDateTime == va.filetime.dwHighDateTime))
  3018. {
  3019. // possible the same dude
  3020. m_pPreview->LoadHtmlErrorPage(c_szErrPage_MailBomb);
  3021. return S_FALSE;
  3022. }
  3023. }
  3024. AthUserSetValue(NULL, c_szLastMsg, REG_BINARY, (LPBYTE)&va.filetime, sizeof(FILETIME));
  3025. }
  3026. return S_OK;
  3027. }
  3028. void CMessageView::_OptionUpdate(DWORD dwUpdate)
  3029. {
  3030. if (m_pMsgList &&
  3031. (dwUpdate == OPT_AUTOEXPAND ||
  3032. dwUpdate == OPT_MESSAGE_LIST_TIPS ||
  3033. dwUpdate == OPT_POLLFORMSGS ||
  3034. dwUpdate == OPT_WATCHED_COLOR ||
  3035. dwUpdate == OPT_DOWNLOADCHUNKS))
  3036. {
  3037. FOLDER_OPTIONS fo = {0};
  3038. fo.cbSize = sizeof(FOLDER_OPTIONS);
  3039. fo.dwMask = FOM_EXPANDTHREADS | FOM_MESSAGELISTTIPS | FOM_POLLTIME | FOM_COLORWATCHED | FOM_GETXHEADERS;
  3040. fo.fExpandThreads = DwGetOption(OPT_AUTOEXPAND);
  3041. fo.fMessageListTips = DwGetOption(OPT_MESSAGE_LIST_TIPS);
  3042. fo.dwPollTime = DwGetOption(OPT_POLLFORMSGS);
  3043. fo.clrWatched = DwGetOption(OPT_WATCHED_COLOR);
  3044. fo.dwGetXHeaders = DwGetOption(OPT_DOWNLOADCHUNKS);
  3045. m_pMsgList->SetViewOptions(&fo);
  3046. }
  3047. }
  3048. void CMessageView::_SetDefaultStatusText(void)
  3049. {
  3050. DWORD cTotal;
  3051. DWORD cUnread;
  3052. DWORD cOnServer;
  3053. CStatusBar *pStatusBar = NULL;
  3054. TCHAR szStatus[CCHMAX_STRINGRES + 20];
  3055. TCHAR szFmt[CCHMAX_STRINGRES];
  3056. DWORD ids;
  3057. // If we don't have a browser pointer, we can't get the status bar
  3058. if (!m_pBrowser || !m_pMsgList)
  3059. return;
  3060. // Get the status bar if there is one.
  3061. m_pBrowser->GetStatusBar(&pStatusBar);
  3062. if (pStatusBar)
  3063. {
  3064. // Get the counts from the table
  3065. if (SUCCEEDED(m_pMsgList->GetMessageCounts(&cTotal, &cUnread, &cOnServer)))
  3066. {
  3067. // If there are still messages on server load a different
  3068. // status string.
  3069. if (cOnServer)
  3070. {
  3071. AthLoadString(idsXMsgsYUnreadZonServ, szFmt, ARRAYSIZE(szFmt));
  3072. wnsprintf(szStatus, ARRAYSIZE(szStatus), szFmt, cTotal, cUnread, cOnServer);
  3073. }
  3074. else
  3075. {
  3076. AthLoadString(idsXMsgsYUnread, szFmt, ARRAYSIZE(szFmt));
  3077. wnsprintf(szStatus, ARRAYSIZE(szStatus), szFmt, cTotal, cUnread);
  3078. }
  3079. pStatusBar->SetStatusText(szStatus);
  3080. // Also update the toolbar since commands like "Mark as Read" might
  3081. // change. However, we only do this if we go between zero and some or
  3082. // vice versa.
  3083. if ((m_cItems == 0 && cTotal) || (m_cItems != 0 && cTotal == 0) ||
  3084. (m_cUnread == 0 && cUnread) || (m_cUnread != 0 && cUnread == 0))
  3085. {
  3086. m_pBrowser->UpdateToolbar();
  3087. }
  3088. // Save this for next time.
  3089. m_cItems = cTotal;
  3090. m_cUnread = cUnread;
  3091. }
  3092. pStatusBar->Release();
  3093. }
  3094. }
  3095. BOOL CMessageView::_ReuseMessageFolder(IViewWindow *pPrevView)
  3096. {
  3097. IServerInfo *pInfo = NULL;
  3098. FOLDERID idPrev = FOLDERID_INVALID;
  3099. FOLDERID idServerPrev = FOLDERID_INVALID;
  3100. FOLDERID idServerCur = FOLDERID_INVALID;
  3101. BOOL fReturn = FALSE;
  3102. if (pPrevView && SUCCEEDED(pPrevView->QueryInterface(IID_IServerInfo, (LPVOID *) &pInfo)))
  3103. {
  3104. if (SUCCEEDED(pInfo->GetFolderId(&idPrev)))
  3105. {
  3106. if (SUCCEEDED(GetFolderServerId(idPrev, &idServerPrev)))
  3107. {
  3108. if (SUCCEEDED(GetFolderServerId(m_idFolder, &idServerCur)))
  3109. {
  3110. if (idServerPrev == idServerCur)
  3111. {
  3112. if (S_OK == pInfo->GetMessageFolder(&m_pServer))
  3113. {
  3114. m_pServer->ConnectionAddRef();
  3115. fReturn = TRUE;
  3116. }
  3117. }
  3118. }
  3119. }
  3120. }
  3121. pInfo->Release();
  3122. }
  3123. return (fReturn);
  3124. }