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.

2253 lines
62 KiB

  1. // ==============================================================================
  2. // 3/2/96 - Attachment Manager Class Implementation (sbailey & brents)
  3. // ==============================================================================
  4. #include "pch.hxx"
  5. #include "strconst.h"
  6. #include <mimeole.h>
  7. #include "mimeutil.h"
  8. #include "mimeolep.h"
  9. #include "attman.h"
  10. #include <error.h>
  11. #include <resource.h>
  12. #include "header.h"
  13. #include "note.h"
  14. #include <thormsgs.h>
  15. #include <shlwapi.h>
  16. #include <shlwapip.h>
  17. #include "fonts.h"
  18. #include "secutil.h"
  19. #include <mailnews.h>
  20. #include <multiusr.h>
  21. #include <menures.h>
  22. #include <menuutil.h>
  23. #include <demand.h> // must be last!
  24. #include "mirror.h"
  25. // for dialog idc's
  26. #include "fexist.h"
  27. /*
  28. * c o n s t a n t s
  29. */
  30. #define CNUMICONSDEFAULT 10
  31. #define CACHE_GROW_SIZE 10
  32. #define MAX_ATTACH_PIXEL_HEIGHT 100
  33. /*
  34. * m a c r o s
  35. */
  36. /*
  37. * t y p e s
  38. *
  39. */
  40. /*
  41. * c o n s t a n t s
  42. *
  43. */
  44. /*
  45. * g l o b a l s
  46. *
  47. */
  48. /*
  49. * p r o t o t y p e s
  50. *
  51. */
  52. // ==============================================================================
  53. // CAttMan::CAttMan
  54. // ==============================================================================
  55. CAttMan::CAttMan ()
  56. {
  57. DOUT ("CAttMan::CAttMan");
  58. m_pMsg = NULL;
  59. m_himlSmall = NULL;
  60. m_himlLarge = NULL;
  61. m_cRef = 1;
  62. m_hwndList = NULL;
  63. m_hwndParent=NULL;
  64. m_cfAccept = CF_NULL;
  65. m_dwDragType = 0;
  66. m_grfKeyState = 0;
  67. m_dwEffect = 0;
  68. m_cxMaxText = 0;
  69. m_cyHeight = 0;
  70. m_fReadOnly = 0;
  71. m_fDirty = FALSE;
  72. m_fDragSource = FALSE;
  73. m_fDropTargetRegister=FALSE;
  74. m_fShowingContext = 0;
  75. m_fRightClick = 0;
  76. m_fWarning = 1;
  77. m_fSafeOnly = TRUE;
  78. m_rgpAttach=NULL;
  79. m_cAttach=0;
  80. m_cAlloc=0;
  81. m_iVCard = -1;
  82. m_fDeleteVCards = FALSE;
  83. m_szUnsafeAttachList = NULL;
  84. m_cUnsafeAttach = 0;
  85. }
  86. // ==============================================================================
  87. // CAttMan::~CAttMan
  88. // ==============================================================================
  89. CAttMan::~CAttMan ()
  90. {
  91. DOUT ("CAttMan::~CAttMan");
  92. if (m_himlSmall)
  93. ImageList_Destroy (m_himlSmall);
  94. if (m_himlLarge)
  95. ImageList_Destroy (m_himlLarge);
  96. if (m_szUnsafeAttachList != NULL)
  97. SafeMemFree(m_szUnsafeAttachList);
  98. SafeRelease (m_pMsg);
  99. }
  100. // ==============================================================================
  101. // CAttMan::AddRef
  102. // ==============================================================================
  103. ULONG CAttMan::AddRef()
  104. {
  105. DOUT ("CAttMan::AddRef () Ref Count=%d", m_cRef);
  106. return ++m_cRef;
  107. }
  108. // ==============================================================================
  109. // CAttMan::Release
  110. // ==============================================================================
  111. ULONG CAttMan::Release()
  112. {
  113. ULONG ulCount = --m_cRef;
  114. DOUT ("CAttMan::Release () Ref Count=%d", ulCount);
  115. if (!ulCount)
  116. delete this;
  117. return ulCount;
  118. }
  119. HRESULT STDMETHODCALLTYPE CAttMan::QueryInterface(REFIID riid, void **ppvObj)
  120. {
  121. *ppvObj = NULL; // set to NULL, in case we fail.
  122. if (IsEqualIID(riid, IID_IUnknown))
  123. *ppvObj = (void*)this;
  124. // else if (IsEqualIID(riid, IID_IDropTarget))
  125. // *ppvObj = (void*)(IDropTarget*)this;
  126. else if (IsEqualIID(riid, IID_IDropSource))
  127. *ppvObj = (void*)(IDropSource*)this;
  128. else
  129. return E_NOINTERFACE;
  130. AddRef();
  131. return NOERROR;
  132. }
  133. HRESULT CAttMan::HrGetAttachCount(ULONG *pcAttach)
  134. {
  135. Assert(pcAttach);
  136. //*pcAttach = m_cAttach;
  137. *pcAttach = ListView_GetItemCount(m_hwndList);
  138. return S_OK;
  139. }
  140. ULONG CAttMan::GetUnsafeAttachCount()
  141. {
  142. return m_cUnsafeAttach;
  143. }
  144. LPTSTR CAttMan::GetUnsafeAttachList()
  145. {
  146. return m_szUnsafeAttachList;
  147. }
  148. HRESULT CAttMan::HrUnload()
  149. {
  150. HRESULT hr;
  151. SafeRelease (m_pMsg);
  152. if (m_hwndList)
  153. ListView_DeleteAllItems(m_hwndList);
  154. hr=HrFreeAllData();
  155. if (FAILED(hr))
  156. goto error;
  157. error:
  158. return hr;
  159. }
  160. HRESULT CAttMan::HrInit(HWND hwnd, BOOL fReadOnly, BOOL fDeleteVCards, BOOL fAllowUnsafe)
  161. {
  162. m_fReadOnly = !!fReadOnly;
  163. m_hwndParent = hwnd;
  164. m_fDeleteVCards = !!fDeleteVCards;
  165. m_fSafeOnly = !fAllowUnsafe;
  166. return HrCreateListView(hwnd);
  167. }
  168. HRESULT CAttMan::HrClearDirtyFlag()
  169. {
  170. m_fDirty=FALSE;
  171. return S_OK;
  172. }
  173. HRESULT CAttMan::HrIsDirty()
  174. {
  175. return m_fDirty?S_OK:S_FALSE;
  176. }
  177. HRESULT CAttMan::GetTabStopArray(HWND *rgTSArray, int *pcArrayCount)
  178. {
  179. Assert(rgTSArray);
  180. Assert(pcArrayCount);
  181. Assert(*pcArrayCount > 0);
  182. *rgTSArray = m_hwndList;
  183. *pcArrayCount = 1;
  184. return S_OK;
  185. }
  186. HRESULT CAttMan::HrCreateListView(HWND hwnd)
  187. {
  188. HRESULT hr;
  189. DWORD dwFlags;
  190. dwFlags = 0;//DwGetOption(OPT_ATTACH_VIEW_STYLE);
  191. dwFlags |= WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|WS_TABSTOP|LVS_AUTOARRANGE|
  192. LVS_SMALLICON|LVS_NOSCROLL|LVS_SHAREIMAGELISTS;
  193. m_hwndList = CreateWindowExWrapW(WS_EX_CLIENTEDGE,
  194. WC_LISTVIEWW,
  195. L"",
  196. dwFlags,
  197. 0,0,0,0,
  198. hwnd,
  199. (HMENU)idwAttachWell,
  200. g_hInst,
  201. NULL);
  202. if(!m_hwndList)
  203. return E_OUTOFMEMORY;
  204. // Init image list
  205. hr=HrInitImageLists();
  206. if(FAILED(hr))
  207. goto error;
  208. #if 0
  209. // if we're not readonly, register ourselves as a drop target...
  210. if(!m_fReadOnly)
  211. {
  212. hr=CoLockObjectExternal((LPDROPTARGET)this, TRUE, FALSE);
  213. if (FAILED(hr))
  214. goto error;
  215. hr=RegisterDragDrop(m_hwndList, (LPDROPTARGET)this);
  216. if (FAILED(hr))
  217. goto error;
  218. m_fDropTargetRegister=TRUE;
  219. }
  220. #endif
  221. error:
  222. return hr;
  223. }
  224. HRESULT CAttMan::HrBuildAttachList()
  225. {
  226. HRESULT hr = S_OK;
  227. ULONG cAttach=0,
  228. uAttach;
  229. LPHBODY rghAttach=0;
  230. Assert(m_pMsg != NULL);
  231. // secure receipt is not attachment and we don't need to show .DAT file as attachment.
  232. if(CheckSecReceipt(m_pMsg) == S_OK)
  233. return hr;
  234. //GetAttachmentCount(m_pMsg, &cAttach);
  235. hr=m_pMsg->GetAttachments(&cAttach, &rghAttach);
  236. if (FAILED(hr))
  237. goto error;
  238. for(uAttach=0; uAttach<cAttach; uAttach++)
  239. {
  240. hr=HrAddData(rghAttach[uAttach]);
  241. if (FAILED(hr))
  242. goto error;
  243. }
  244. error:
  245. SafeMimeOleFree(rghAttach);
  246. return hr;
  247. }
  248. // Only expected to be used during initialization with original m_pMsg
  249. HRESULT CAttMan::HrFillListView()
  250. {
  251. HRESULT hr;
  252. ULONG uAttach;
  253. CComBSTR bstrUnsafeAttach;
  254. Assert (m_hwndList && IsWindow(m_hwndList) && m_pMsg);
  255. hr = HrCheckVCard();
  256. if (FAILED(hr))
  257. goto error;
  258. if (m_cAttach==0) // nothing to do
  259. return NOERROR;
  260. if(m_iVCard >= 0)
  261. ListView_SetItemCount(m_hwndList, m_cAttach - 1);
  262. else
  263. ListView_SetItemCount(m_hwndList, m_cAttach);
  264. if (m_szUnsafeAttachList != NULL)
  265. SafeMemFree(m_szUnsafeAttachList);
  266. m_cUnsafeAttach = 0;
  267. // walk the attachment data list and add them to the listview
  268. for(uAttach=0; uAttach<m_cAlloc; uAttach++)
  269. {
  270. // if there is one and only one vcare in the read note, don't add it to list view,
  271. // header will show it as a stamp.
  272. if (m_rgpAttach[uAttach] && uAttach!=(ULONG)m_iVCard)
  273. {
  274. hr=HrAddToList(m_rgpAttach[uAttach], TRUE);
  275. if (hr == S_FALSE)
  276. {
  277. if (bstrUnsafeAttach.Length() > 0)
  278. bstrUnsafeAttach.Append(L",");
  279. bstrUnsafeAttach.Append(m_rgpAttach[uAttach]->szFileName);
  280. m_cUnsafeAttach++;
  281. }
  282. if (FAILED(hr))
  283. goto error;
  284. }
  285. }
  286. error:
  287. if (m_cUnsafeAttach)
  288. m_szUnsafeAttachList = PszToANSI(CP_ACP, bstrUnsafeAttach.m_str);
  289. #ifdef DEBUG
  290. if(m_iVCard >= 0)
  291. AssertSz(m_cAttach-1==(ULONG)ListView_GetItemCount(m_hwndList)+m_cUnsafeAttach, "Something failed creating the attachmentlist");
  292. else
  293. AssertSz(m_cAttach==(ULONG)ListView_GetItemCount(m_hwndList)+m_cUnsafeAttach, "Something failed creating the attachmentlist");
  294. #endif
  295. return hr;
  296. }
  297. // tells the note header if there is a vcard it wants.
  298. HRESULT CAttMan::HrFVCard()
  299. {
  300. return (m_iVCard >= 0) ? S_OK : S_FALSE;
  301. }
  302. // note header needs this function to show the property of the vcard
  303. // which is shown as a stamp on the header.
  304. HRESULT CAttMan::HrShowVCardProp()
  305. {
  306. Assert(m_iVCard >= 0);
  307. return HrDoVerb(m_rgpAttach[m_iVCard], ID_OPEN);
  308. }
  309. // checks if we have one and only one vcard in the attachment.
  310. HRESULT CAttMan::HrCheckVCard()
  311. {
  312. HRESULT hr = NOERROR;
  313. ULONG uAttach;
  314. m_iVCard = -1;
  315. // this is only for read note. Since preview doesn't call this function,
  316. // we can check m_fReadOnly to see if it's a read note.
  317. if(!m_fReadOnly)
  318. return hr;
  319. for(uAttach=0; uAttach<m_cAlloc; uAttach++)
  320. {
  321. if (m_rgpAttach[uAttach])
  322. {
  323. if(StrStrIW(PathFindExtensionW((m_rgpAttach[uAttach])->szFileName), L".vcf"))
  324. {
  325. if(m_iVCard >= 0)
  326. {
  327. // there are more than one vcards, we quit.
  328. m_iVCard = -1;
  329. break;
  330. }
  331. else
  332. m_iVCard = uAttach;
  333. }
  334. }
  335. }
  336. return hr;
  337. }
  338. HRESULT CAttMan::HrCheckVCardExists(BOOL fMail)
  339. {
  340. HRESULT hr = S_FALSE;
  341. ULONG uAttach;
  342. TCHAR szVCardName[MAX_PATH];
  343. LPWSTR szVCardNameW = NULL;
  344. if(m_fReadOnly)
  345. return hr;
  346. *szVCardName = 0;
  347. if(fMail)
  348. GetOption(OPT_MAIL_VCARDNAME, szVCardName, MAX_PATH);
  349. else
  350. GetOption(OPT_NEWS_VCARDNAME, szVCardName, MAX_PATH);
  351. if (*szVCardName != '\0')
  352. {
  353. szVCardNameW = PszToUnicode(CP_ACP, szVCardName);
  354. if (szVCardNameW)
  355. {
  356. for(uAttach=0; uAttach<m_cAlloc; uAttach++)
  357. {
  358. if (m_rgpAttach[uAttach])
  359. {
  360. if(0 == StrCmpNIW((m_rgpAttach[uAttach])->szFileName, szVCardNameW, lstrlenW(szVCardNameW)))
  361. {
  362. hr = S_OK;
  363. break;
  364. }
  365. }
  366. }
  367. MemFree(szVCardNameW);
  368. }
  369. else
  370. TraceResult(hr = E_OUTOFMEMORY);
  371. }
  372. return hr;
  373. }
  374. /*
  375. *
  376. * HrInitImageLists
  377. *
  378. * Create an image list and assign it to our listview.
  379. * to contain iicons number of icons
  380. *
  381. */
  382. HRESULT CAttMan::HrInitImageLists()
  383. {
  384. UINT flags = ILC_MASK;
  385. Assert(m_hwndList && IsWindow(m_hwndList));
  386. Assert(!m_himlLarge);
  387. Assert(!m_himlSmall);
  388. if(IS_WINDOW_RTL_MIRRORED(m_hwndList))
  389. {
  390. flags |= ILC_MIRROR ;
  391. }
  392. m_himlLarge = ImageList_Create( GetSystemMetrics(SM_CXICON),
  393. GetSystemMetrics(SM_CYICON),
  394. flags, CNUMICONSDEFAULT, 0);
  395. if(!m_himlLarge)
  396. return E_OUTOFMEMORY;
  397. m_himlSmall = ImageList_Create( GetSystemMetrics(SM_CXSMICON),
  398. GetSystemMetrics(SM_CYSMICON),
  399. flags, CNUMICONSDEFAULT, 0);
  400. if(!m_himlSmall)
  401. return E_OUTOFMEMORY;
  402. ListView_SetImageList(m_hwndList, m_himlSmall, LVSIL_SMALL);
  403. ListView_SetImageList(m_hwndList, m_himlLarge, LVSIL_NORMAL);
  404. return NOERROR;
  405. }
  406. //
  407. // HrAddToList
  408. //
  409. // adds an attachment to the LV,
  410. // if count was 0 then send a message to parent
  411. // to redraw.
  412. //
  413. HRESULT CAttMan::HrAddToList(LPATTACHDATA pAttach, BOOL fIniting)
  414. {
  415. LV_ITEMW lvi ={0};
  416. INT iPos;
  417. HICON hIcon=0;
  418. RECT rc;
  419. Assert(m_hwndList != NULL);
  420. Assert(pAttach != NULL);
  421. Assert(m_himlSmall != NULL);
  422. Assert(m_himlLarge != NULL);
  423. // don't show attachments which are deemed unsafe
  424. if (m_fReadOnly && m_fSafeOnly && !(pAttach->fSafe))
  425. return S_FALSE;
  426. // if this is the first item
  427. // we need to send a message to parent
  428. lvi.mask = LVIF_PARAM|LVIF_TEXT|LVIF_IMAGE|LVIF_STATE;
  429. lvi.stateMask = 0;
  430. lvi.pszText = L"";
  431. lvi.lParam = (LPARAM)pAttach;
  432. // get icons for image list
  433. if (fIniting)
  434. {
  435. SideAssert(HrGetAttachIcon(m_pMsg, pAttach->hAttach, FALSE, &hIcon)==S_OK);
  436. lvi.iImage = ImageList_AddIcon(m_himlSmall, hIcon);
  437. DestroyIcon(hIcon);
  438. SideAssert(HrGetAttachIcon(m_pMsg, pAttach->hAttach, TRUE, &hIcon)==S_OK);
  439. ImageList_AddIcon(m_himlLarge, hIcon);
  440. DestroyIcon(hIcon);
  441. }
  442. else
  443. {
  444. SideAssert(HrGetAttachIconByFile(pAttach->szFileName, FALSE, &hIcon)==S_OK);
  445. lvi.iImage = ImageList_AddIcon(m_himlSmall, hIcon);
  446. DestroyIcon(hIcon);
  447. SideAssert(HrGetAttachIconByFile(pAttach->szFileName, TRUE, &hIcon)==S_OK);
  448. ImageList_AddIcon(m_himlLarge, hIcon);
  449. DestroyIcon(hIcon);
  450. }
  451. lvi.pszText = pAttach->szDisplay;
  452. iPos = (INT) SendMessage(m_hwndList, LVM_INSERTITEMW, 0, (LPARAM)(LV_ITEMW*)(&lvi));
  453. if (-1 == iPos)
  454. return E_FAIL;
  455. // Must set to LVS_ICON then reset to LVS_SMALLICON
  456. // to get SMALLICONs to come up arranged.
  457. DWORD dwStyle = GetWindowStyle(m_hwndList);
  458. if ((dwStyle & LVS_TYPEMASK) == LVS_SMALLICON)
  459. {
  460. SetWindowLong(m_hwndList, GWL_STYLE, (dwStyle & ~LVS_TYPEMASK)|LVS_ICON);
  461. SetWindowLong(m_hwndList, GWL_STYLE, (dwStyle & ~LVS_TYPEMASK)|LVS_SMALLICON);
  462. }
  463. return S_OK;
  464. }
  465. BOOL CAttMan::WMNotify(int idFrom, NMHDR *pnmhdr)
  466. {
  467. DOUTLL( DOUTL_ATTMAN, 2, "CAttMan :: WMNotify( ), %d", idFrom );
  468. if (idFrom!=idwAttachWell)
  469. return FALSE;
  470. switch (pnmhdr->code)
  471. {
  472. case LVN_KEYDOWN:
  473. {
  474. LV_KEYDOWN *pnkd = ((LV_KEYDOWN *)pnmhdr);
  475. switch (pnkd->wVKey)
  476. {
  477. case VK_DELETE:
  478. if (!m_fReadOnly)
  479. HrRemoveAttachments();
  480. break;
  481. case VK_INSERT:
  482. if (!m_fReadOnly)
  483. HrInsertFile();
  484. break;
  485. case VK_RETURN:
  486. case VK_EXECUTE:
  487. HrExecFile(ID_OPEN);
  488. break;
  489. }
  490. break;
  491. }
  492. case LVN_BEGINDRAG:
  493. case LVN_BEGINRDRAG:
  494. m_dwDragType = (pnmhdr->code==LVN_BEGINDRAG?MK_LBUTTON:MK_RBUTTON);
  495. HrBeginDrag();
  496. return TRUE;
  497. case NM_DBLCLK:
  498. HrDblClick(idFrom, pnmhdr);
  499. return TRUE;
  500. }
  501. return FALSE;
  502. }
  503. //================================================================
  504. //
  505. // BOOL CAttMan :: OnBeginDrag( )
  506. //
  507. // Purpose: We have received a message that a drag has begun.
  508. //================================================================
  509. HRESULT CAttMan::HrBeginDrag()
  510. {
  511. DWORD dwEffect;
  512. IDataObject *pDataObj=0;
  513. PDATAOBJINFO pdoi = 0;
  514. HRESULT hr;
  515. Assert(m_hwndList);
  516. // BROKEN: this is busted. Creating the tempfile on a dragstart is broken, we should package these better.
  517. hr=HrBuildHDrop(&pdoi);
  518. if (FAILED(hr))
  519. goto error;
  520. hr = CreateDataObject(pdoi, 1, (PFNFREEDATAOBJ)FreeAthenaDataObj, &pDataObj);
  521. if (FAILED(hr))
  522. {
  523. SafeMemFree(pdoi);
  524. goto error;
  525. }
  526. if (m_fReadOnly)
  527. dwEffect = DROPEFFECT_COPY;
  528. else
  529. dwEffect = DROPEFFECT_MOVE|DROPEFFECT_COPY;
  530. // prevent source drags in the body...
  531. m_fDragSource = TRUE;
  532. hr=DoDragDrop((LPDATAOBJECT)pDataObj, (LPDROPSOURCE)this, dwEffect, &dwEffect);
  533. m_fDragSource = FALSE;
  534. if (FAILED(hr))
  535. goto error;
  536. // ok, now lets see if the operation was a move, if so we need to
  537. // delete the source.
  538. if( !m_fReadOnly && (dwEffect & DROPEFFECT_MOVE))
  539. hr=HrRemoveAttachments();
  540. error:
  541. ReleaseObj(pDataObj);
  542. return hr;
  543. }
  544. //================================================================
  545. //
  546. // BOOL CAttMan :: WMContextMenu( )
  547. //
  548. // Displays one of two menus for the lisview.
  549. // Menu is selected depending if items are highlighted.
  550. //
  551. // returns: TRUE => success.
  552. //
  553. //================================================================
  554. BOOL CAttMan::WMContextMenu( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
  555. {
  556. HMENU hMenu=NULL;
  557. INT cSel;
  558. BOOL fEnable,
  559. fRet = FALSE;
  560. LV_ITEMW lvi;
  561. WCHAR szCommand[MAX_PATH];
  562. DWORD dwPos;
  563. // was it for us?
  564. if ((HWND)wParam != m_hwndList)
  565. goto cleanup;
  566. Assert(m_hwndList);
  567. cSel = ListView_GetSelectedCount(m_hwndList);
  568. hMenu = LoadPopupMenu(IDR_ATTACHMENT_POPUP);
  569. if(!hMenu)
  570. goto cleanup;
  571. // commands that are enabled if only one attachment is selected
  572. fEnable = (cSel == 1);
  573. EnableMenuItem(hMenu, ID_PRINT, MF_BYCOMMAND | (fEnable? MF_ENABLED:MF_GRAYED));
  574. EnableMenuItem(hMenu, ID_QUICK_VIEW, MF_BYCOMMAND | (fEnable? MF_ENABLED:MF_GRAYED));
  575. // enabled in readonly mode and if there is only one attach selected
  576. EnableMenuItem(hMenu, ID_SAVE_ATTACH_AS, MF_BYCOMMAND | ((fEnable && m_fReadOnly)? MF_ENABLED:MF_GRAYED));
  577. // enabled if any attachments selected
  578. EnableMenuItem(hMenu, ID_OPEN, MF_BYCOMMAND | (cSel > 0? MF_ENABLED:MF_GRAYED));
  579. // enabled only in readonly mode
  580. EnableMenuItem(hMenu, ID_SAVE_ATTACHMENTS, MF_BYCOMMAND | (m_fReadOnly? MF_ENABLED:MF_GRAYED));
  581. // enabled only in compose mode
  582. EnableMenuItem(hMenu, ID_ADD, MF_BYCOMMAND | (!m_fReadOnly? MF_ENABLED:MF_GRAYED));
  583. // enabled only in compose mode if there is a valid selection
  584. EnableMenuItem(hMenu, ID_REMOVE, MF_BYCOMMAND | (!m_fReadOnly && cSel > 0? MF_ENABLED:MF_GRAYED));
  585. if ((fIsNT5()) || (IsOS(OS_MILLENNIUM)))
  586. {
  587. // On Both these platforms, Quick View is not supported.
  588. DeleteMenu(hMenu, ID_QUICK_VIEW, MF_BYCOMMAND);
  589. }
  590. else
  591. {
  592. // Disable Quick View if QVIEW.EXE does not exist
  593. GetSystemDirectoryWrapW(szCommand, ARRAYSIZE(szCommand));
  594. StrCatBuffW(szCommand, L"\\VIEWERS\\QUIKVIEW.EXE", ARRAYSIZE(szCommand));
  595. if ((UINT)GetFileAttributesWrapW(szCommand) == (UINT)-1)
  596. {
  597. EnableMenuItem (hMenu, ID_QUICK_VIEW, MF_GRAYED);
  598. }
  599. }
  600. // bold the first non-grey item
  601. MenuUtil_SetPopupDefault(hMenu, ID_OPEN);
  602. // RAID $2129: disable print verb for .eml files
  603. // $49436 - also disable for .lnks
  604. if (cSel==1)
  605. {
  606. LPWSTR pszExt;
  607. lvi.iItem = ListView_GetSelFocused(m_hwndList);
  608. lvi.mask = LVIF_PARAM;
  609. if (SendMessage(m_hwndList, LVM_GETITEMW, 0, (LPARAM)(LV_ITEMW*)(&lvi)))
  610. {
  611. pszExt = PathFindExtensionW(((LPATTACHDATA)lvi.lParam)->szFileName);
  612. if (pszExt && (StrCmpIW(pszExt, c_wszEmlExt)==0 ||
  613. StrCmpIW(pszExt, c_wszNwsExt)==0 ||
  614. StrCmpIW(pszExt, L".lnk")==0))
  615. EnableMenuItem( hMenu, ID_PRINT, MF_GRAYED);
  616. }
  617. }
  618. dwPos=GetMessagePos();
  619. fRet = TrackPopupMenuEx(
  620. hMenu,
  621. TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON,
  622. LOWORD(dwPos),
  623. HIWORD(dwPos),
  624. hwnd,
  625. NULL);
  626. cleanup:
  627. if(hMenu)
  628. DestroyMenu(hMenu);
  629. return fRet;
  630. }
  631. HRESULT CAttMan::HrDblClick(int idFrom, NMHDR *pnmhdr)
  632. {
  633. DWORD dwPos;
  634. POINT pt;
  635. LV_HITTESTINFO lvhti;
  636. LV_ITEMW lvi;
  637. Assert(m_hwndList);
  638. // Find out where the cursor was
  639. dwPos = GetMessagePos();
  640. pt.x = LOWORD(dwPos);
  641. pt.y = HIWORD(dwPos);
  642. ScreenToClient( m_hwndList, &pt);
  643. lvhti.pt = pt;
  644. if(ListView_HitTest(m_hwndList, &lvhti) != -1)
  645. {
  646. // return 1 here, we passed the HitTest
  647. lvi.iItem = lvhti.iItem;
  648. lvi.mask = LVIF_PARAM;
  649. if (SendMessage(m_hwndList, LVM_GETITEMW, 0, (LPARAM)(LV_ITEMW*)(&lvi)))
  650. return HrDoVerb((LPATTACHDATA)lvi.lParam, ID_OPEN);
  651. }
  652. return S_OK;
  653. }
  654. HRESULT CAttMan::HrGetHeight(INT cxWidth, ULONG *pcy)
  655. {
  656. DWORD dwDims;
  657. LONG cCount;
  658. if (!pcy || cxWidth<=0)
  659. return E_INVALIDARG;
  660. *pcy=0;
  661. cCount = ListView_GetItemCount(m_hwndList);
  662. if (0 == cCount)
  663. *pcy = 0;
  664. else
  665. {
  666. dwDims = ListView_ApproximateViewRect(m_hwndList, cxWidth, 0, cCount);
  667. *pcy = HIWORD(dwDims);
  668. }
  669. return S_OK;
  670. }
  671. HRESULT CAttMan::HrSwitchView(DWORD dwView)
  672. {
  673. DWORD dwStyle = GetWindowStyle(m_hwndList);
  674. WORD ToolbarStyleLookup[]= { LVS_ICON,
  675. LVS_REPORT,
  676. LVS_SMALLICON,
  677. LVS_LIST };
  678. Assert(m_hwndList);
  679. // convert index into lisview style
  680. dwView = ToolbarStyleLookup[dwView];
  681. if ((LVS_ICON != dwView) && (LVS_SMALLICON != dwView))
  682. dwView = LVS_ICON;
  683. // don't change to the same view
  684. if ((dwStyle & LVS_TYPEMASK) != dwView)
  685. {
  686. SetWindowLong(m_hwndList, GWL_STYLE, (dwStyle & ~LVS_TYPEMASK)|dwView);
  687. HrResizeParent();
  688. SetDwOption(OPT_ATTACH_VIEW_STYLE, dwView, NULL, 0);
  689. }
  690. return S_OK;
  691. }
  692. HRESULT CAttMan::HrSetSize(RECT *prc)
  693. {
  694. Assert(IsWindow( m_hwndList ));
  695. Assert(prc);
  696. DWORD dwStyle = GetWindowStyle(m_hwndList),
  697. dwPosFlags;
  698. ULONG cAttMan = 0;
  699. HrGetAttachCount(&cAttMan);
  700. if (cAttMan == 1)
  701. SetWindowLong(m_hwndList, GWL_STYLE, dwStyle | LVS_NOSCROLL);
  702. else
  703. SetWindowLong(m_hwndList, GWL_STYLE, dwStyle & ~LVS_NOSCROLL);
  704. dwPosFlags = (cAttMan > 0) ? SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOCOPYBITS|SWP_SHOWWINDOW:
  705. SWP_HIDEWINDOW;
  706. SetWindowPos(m_hwndList, NULL, prc->left, prc->top, prc->right-prc->left, prc->bottom-prc->top, dwPosFlags);
  707. return S_OK;
  708. }
  709. BOOL CAttMan::WMCommand(HWND hwndCmd, INT id, WORD wCmd)
  710. {
  711. // verbs depending on listview mode
  712. if (m_hwndList)
  713. {
  714. switch(id)
  715. {
  716. case ID_SELECT_ALL:
  717. if(GetFocus()!=m_hwndList)
  718. return FALSE;
  719. ListView_SelectAll(m_hwndList);
  720. return TRUE;
  721. case ID_ADD:
  722. HrInsertFile();
  723. return TRUE;
  724. case ID_REMOVE:
  725. HrRemoveAttachments();
  726. return TRUE;
  727. case ID_OPEN:
  728. case ID_QUICK_VIEW:
  729. case ID_PRINT:
  730. case ID_SAVE_ATTACH_AS:
  731. HrExecFile(id);
  732. return TRUE;
  733. case ID_INSERT_ATTACHMENT:
  734. HrInsertFile();
  735. return TRUE;
  736. }
  737. }
  738. return FALSE;
  739. }
  740. //===================================================
  741. //
  742. // HrRemoveAttachment
  743. //
  744. // Purpose:
  745. // Removes an attachment from the ListView
  746. //
  747. // Arguments:
  748. // ili - index of attachment in listview to remove
  749. // fDelete - should we remove it from list
  750. //
  751. // Returns:
  752. ///
  753. //===================================================
  754. HRESULT CAttMan::HrRemoveAttachment(int ili)
  755. {
  756. LV_ITEMW lvi;
  757. LPATTACHDATA lpAttach=0;
  758. HRESULT hr=S_OK;
  759. ULONG uAttach;
  760. Assert( m_hwndList );
  761. lvi.mask = LVIF_PARAM;
  762. lvi.iSubItem = 0;
  763. lvi.iItem = ili;
  764. if (!SendMessage(m_hwndList, LVM_GETITEMW, 0, (LPARAM)(LV_ITEMW*)(&lvi)))
  765. {
  766. AssertSz(0, "Attempting to remove an item that is not there");
  767. return E_FAIL; // item does not exist!!!!
  768. }
  769. lpAttach = (LPATTACHDATA)lvi.lParam;
  770. if(!lpAttach)
  771. return E_FAIL;
  772. // find it and kill it from the list
  773. for (uAttach=0; uAttach<m_cAlloc; uAttach++)
  774. {
  775. if (m_rgpAttach[uAttach]==lpAttach)
  776. {
  777. HrFreeAttachData(m_rgpAttach[uAttach]);
  778. m_rgpAttach[uAttach] = NULL;
  779. break;
  780. }
  781. }
  782. // if we actually removed the attachment, make sure we're dirty
  783. m_fDirty = TRUE;
  784. ListView_DeleteItem(m_hwndList, ili);
  785. return hr;
  786. }
  787. /*
  788. * CAttMan::HrDeleteAttachments
  789. *
  790. * Purpose:
  791. * Prompts user to confirm deletion, if IDYES -> blow them away
  792. *
  793. */
  794. HRESULT CAttMan::HrDeleteAttachments()
  795. {
  796. if (AthMessageBoxW( m_hwndParent,
  797. MAKEINTRESOURCEW(idsAthena),
  798. MAKEINTRESOURCEW(idsAttConfirmDeletion),
  799. NULL, MB_YESNO|MB_ICONEXCLAMATION )==IDNO)
  800. return NOERROR;
  801. return HrRemoveAttachments();
  802. }
  803. /*
  804. * CAttMan :: HrRemoveAttachments
  805. *
  806. * Purpose:
  807. * Removes all selected attachments from the Well.
  808. *
  809. * Arguments:
  810. *
  811. */
  812. HRESULT CAttMan::HrRemoveAttachments()
  813. {
  814. HRESULT hr=NOERROR;
  815. HWND hwnd;
  816. int ili,
  817. iNext,
  818. nPos,
  819. nCount;
  820. Assert(m_hwndList);
  821. while ((ili=ListView_GetNextItem(m_hwndList, -1, LVNI_SELECTED|LVNI_ALL))!=-1)
  822. {
  823. iNext = ili;
  824. hr=HrRemoveAttachment(ili);
  825. if (FAILED(hr))
  826. goto error;
  827. }
  828. if ((nCount=ListView_GetItemCount(m_hwndList))==0)
  829. {
  830. // if there are no attachments left, we need to size the well to 0. and setfocus
  831. // to someother control
  832. m_cyHeight = 0;
  833. HrResizeParent();
  834. if (hwnd = GetNextDlgTabItem(m_hwndParent, m_hwndList, TRUE))
  835. SetFocus(hwnd);
  836. }
  837. else
  838. {
  839. HrResizeParent();
  840. if (iNext<nCount)
  841. nPos = (iNext?iNext-1:iNext);
  842. else
  843. nPos = nCount - 1;
  844. ListView_SelectItem(m_hwndList, nPos);
  845. }
  846. error:
  847. return hr;
  848. }
  849. HRESULT CAttMan::HrResizeParent()
  850. {
  851. RECT rc;
  852. NMHDR nmhdr;
  853. Assert(m_hwndList);
  854. nmhdr.hwndFrom=m_hwndList;
  855. nmhdr.idFrom=GetDlgCtrlID(m_hwndList);
  856. nmhdr.code=ATTN_RESIZEPARENT;
  857. SendMessage(GetParent(m_hwndList), WM_NOTIFY, nmhdr.idFrom, (LPARAM)&nmhdr);
  858. return S_OK;
  859. }
  860. HRESULT GetLastAttachmentPath(LPWSTR pszDefaultDir, DWORD cchSize)
  861. {
  862. HRESULT hr = S_OK;
  863. DWORD dwType;
  864. DWORD cbSize = (cchSize * sizeof(pszDefaultDir[0]));
  865. pszDefaultDir[0] = 0;
  866. DWORD dwError = SHGetValueW(MU_GetCurrentUserHKey(), NULL, L"Attachment Path", &dwType, (void *) pszDefaultDir, &cbSize);
  867. hr = HRESULT_FROM_WIN32(dwError);
  868. return hr;
  869. }
  870. HRESULT SetLastAttachmentPath(LPCWSTR pszDefaultDir)
  871. {
  872. HRESULT hr = S_OK;
  873. DWORD cbSize = ((lstrlenW(pszDefaultDir)+1) * sizeof(pszDefaultDir[0]));
  874. DWORD dwError = SHSetValueW(MU_GetCurrentUserHKey(), NULL, L"Attachment Path", REG_SZ, (void *) pszDefaultDir, cbSize);
  875. hr = HRESULT_FROM_WIN32(dwError);
  876. return hr;
  877. }
  878. #define CCH_INSERTFILE 4096
  879. typedef struct tagATTMANCUSTOM {
  880. BOOL fShortcut;
  881. WCHAR szFiles[CCH_INSERTFILE];
  882. WORD nFileOffset;
  883. } ATTMANCUSTOM;
  884. HRESULT CAttMan::HrInsertFile()
  885. {
  886. OPENFILENAMEW ofn;
  887. HRESULT hr;
  888. WCHAR rgch[MAX_PATH],
  889. pszOpenFileName[CCH_INSERTFILE],
  890. szDefaultDir[MAX_PATH];
  891. ATTMANCUSTOM rCustom;
  892. Assert(m_hwndList);
  893. *pszOpenFileName = 0;
  894. ZeroMemory(&ofn, sizeof(ofn));
  895. AthLoadStringW(idsAllFilesFilter, rgch, MAX_PATH);
  896. ReplaceCharsW(rgch, _T('|'), _T('\0'));
  897. ofn.lStructSize = sizeof(OPENFILENAME);
  898. ofn.hwndOwner = m_hwndParent;
  899. ofn.hInstance = g_hLocRes;
  900. ofn.lpstrFilter = rgch;
  901. ofn.nFilterIndex = 1;
  902. ofn.lpstrFile = pszOpenFileName;
  903. ofn.nMaxFile = CCH_INSERTFILE;
  904. ofn.lpstrInitialDir = szDefaultDir; //current dir
  905. ofn.Flags = OFN_HIDEREADONLY |
  906. OFN_EXPLORER |
  907. OFN_ALLOWMULTISELECT |
  908. OFN_FILEMUSTEXIST |
  909. OFN_NOCHANGEDIR |
  910. OFN_ENABLEHOOK |
  911. OFN_ENABLETEMPLATE |
  912. OFN_NODEREFERENCELINKS;
  913. ofn.lpTemplateName = MAKEINTRESOURCEW(iddInsertFile);
  914. ofn.lpfnHook = (LPOFNHOOKPROC)InsertFileDlgHookProc;
  915. ofn.lCustData = (LONG_PTR)&rCustom;
  916. if (FAILED(GetLastAttachmentPath(szDefaultDir, ARRAYSIZE(szDefaultDir))) ||
  917. !PathFileExistsW(szDefaultDir))
  918. {
  919. ofn.lpstrInitialDir = NULL;
  920. }
  921. rCustom.szFiles[0] = 0;
  922. rCustom.fShortcut = FALSE;
  923. rCustom.nFileOffset = 0;
  924. // NB: OK button in dialog hook take's care of inserting the attachment.
  925. hr = HrAthGetFileNameW(&ofn, TRUE);
  926. if (SUCCEEDED(hr))
  927. {
  928. WCHAR sz[MAX_PATH];
  929. LPWSTR pszT;
  930. BOOL fShortCut = rCustom.fShortcut,
  931. fUseCustom = (rCustom.szFiles[0]),
  932. fSingleAttach;
  933. // We only generate custom stuff if we have more than one file
  934. fSingleAttach = fUseCustom ? FALSE : (ofn.nFileOffset < lstrlenW(pszOpenFileName));
  935. if (fSingleAttach)
  936. {
  937. StrCpyNW(szDefaultDir, pszOpenFileName, ARRAYSIZE(szDefaultDir));
  938. PathRemoveFileSpecW(szDefaultDir);
  939. SetLastAttachmentPath(szDefaultDir);
  940. // in single-file case, no null between path and filename
  941. hr = HrAddAttachment(pszOpenFileName, NULL, fShortCut);
  942. }
  943. else
  944. {
  945. LPWSTR pszPath;
  946. if (fUseCustom)
  947. {
  948. pszPath = rCustom.szFiles;
  949. pszT = pszPath + rCustom.nFileOffset;
  950. }
  951. else
  952. {
  953. pszPath = pszOpenFileName;
  954. pszT = pszPath + ofn.nFileOffset;
  955. }
  956. SetLastAttachmentPath(pszPath);
  957. while (TRUE)
  958. {
  959. PathCombineW(sz, pszPath, pszT);
  960. hr = HrAddAttachment(sz, NULL, fShortCut);
  961. if (hr != S_OK)
  962. break;
  963. pszT = pszT + lstrlenW(pszT) + 1;
  964. if (*pszT == 0)
  965. break;
  966. }
  967. }
  968. }
  969. return(hr);
  970. }
  971. /*
  972. * HrAddAttachment
  973. *
  974. * adds a file attachment to the list from a stream or filename
  975. *
  976. *
  977. */
  978. HRESULT CAttMan::HrAddAttachment(LPWSTR lpszPathName, LPSTREAM pstm, BOOL fShortCut)
  979. {
  980. ULONG cbSize=0;
  981. HRESULT hr = S_OK;
  982. HBODY hAttach=0;
  983. LPATTACHDATA pAttach;
  984. WCHAR szLinkPath[MAX_PATH];
  985. LPWSTR pszFileNameToUse;
  986. *szLinkPath = 0;
  987. if(fShortCut)
  988. {
  989. hr = CreateNewShortCut(lpszPathName, szLinkPath, ARRAYSIZE(szLinkPath));
  990. if (FAILED(hr))
  991. return hr;
  992. }
  993. pszFileNameToUse = *szLinkPath ? szLinkPath : lpszPathName;
  994. hr=HrAddData(pszFileNameToUse, pstm, &pAttach);
  995. if (FAILED(hr))
  996. return hr;
  997. hr=HrAddToList(pAttach, FALSE);
  998. if (FAILED(hr))
  999. goto error;
  1000. if (ListView_GetItemCount(m_hwndList) == 1)
  1001. {
  1002. // if we went from 0->1 then select the first item
  1003. ListView_SelectItem(m_hwndList, 0);
  1004. }
  1005. // Adding a new attachment makes us dirty
  1006. m_fDirty = TRUE;
  1007. HrResizeParent();
  1008. error:
  1009. return hr;
  1010. }
  1011. /*
  1012. *
  1013. * HRESULT CAttMan::HrExecFile
  1014. *
  1015. * handles one of these verbs against an attachment:
  1016. *
  1017. * ID_OPEN: - Launch use m_lpMsg
  1018. * ID_QUICK_VIEW: - NYI
  1019. * ID_PRINT: - NYI
  1020. * ID_SAVE_AS: - NYI
  1021. *
  1022. * returns 1 if handled.
  1023. *
  1024. */
  1025. HRESULT CAttMan::HrExecFile(int iVerb)
  1026. {
  1027. LV_ITEMW lvi;
  1028. HRESULT hr=E_FAIL;
  1029. if (!ListView_GetSelectedCount(m_hwndList))
  1030. return NOERROR; // nothing to do...
  1031. lvi.mask = LVIF_PARAM;
  1032. lvi.iSubItem = 0;
  1033. lvi.iItem = -1;
  1034. // cycle through all the selected attachments
  1035. while ((lvi.iItem = ListView_GetNextItem(m_hwndList, lvi.iItem, LVNI_SELECTED | LVNI_ALL)) != -1)
  1036. {
  1037. SendMessage(m_hwndList, LVM_GETITEMW, 0, (LPARAM)(LV_ITEMW*)(&lvi));
  1038. switch(iVerb)
  1039. {
  1040. case ID_SAVE_ATTACH_AS:
  1041. case ID_OPEN:
  1042. case ID_PRINT:
  1043. case ID_QUICK_VIEW:
  1044. return HrDoVerb((LPATTACHDATA)lvi.lParam, iVerb);
  1045. default:
  1046. AssertSz(0, "Verb not supported");
  1047. }
  1048. }
  1049. return hr;
  1050. }
  1051. // ==============================================================================
  1052. //
  1053. // FUNCTION: CAttMan :: FDropFiles()
  1054. //
  1055. // Purpose: this method is called with a HDROP, the files
  1056. // have been droped. This method assumes
  1057. //
  1058. // ==============================================================================
  1059. HRESULT CAttMan::HrDropFiles(HDROP hDrop, BOOL fMakeLinks)
  1060. {
  1061. WCHAR wszFile[_MAX_PATH];
  1062. UINT cFiles;
  1063. UINT iFile;
  1064. HCURSOR hcursor;
  1065. BOOL fFirstDirectory = TRUE,
  1066. fLinkDirectories = FALSE;
  1067. HRESULT hr = S_OK;
  1068. hcursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1069. // Let's work through the files given to us
  1070. cFiles = DragQueryFileWrapW(hDrop, (UINT) -1, NULL, 0);
  1071. for (iFile = 0; iFile < cFiles; ++iFile)
  1072. {
  1073. DragQueryFileWrapW(hDrop, iFile, wszFile, _MAX_PATH);
  1074. if (!fMakeLinks && PathIsDirectoryW(wszFile))
  1075. {
  1076. // can link to a directory, but not drop one.
  1077. if (fFirstDirectory)
  1078. {
  1079. int id;
  1080. // Tell the user that he's been a bad user
  1081. id = AthMessageBoxW(m_hwndParent,
  1082. MAKEINTRESOURCEW(idsAthena),
  1083. MAKEINTRESOURCEW(idsDropLinkDirs),
  1084. NULL,
  1085. MB_ICONEXCLAMATION | MB_SETFOREGROUND | MB_YESNOCANCEL);
  1086. if (id==IDCANCEL)
  1087. return E_FAIL;
  1088. if (id == IDYES)
  1089. fLinkDirectories = TRUE;
  1090. fFirstDirectory = FALSE;
  1091. }
  1092. if (fLinkDirectories)
  1093. hr = HrAddAttachment(wszFile, NULL, TRUE);
  1094. }
  1095. else
  1096. hr = HrAddAttachment(wszFile, NULL, fMakeLinks);
  1097. }
  1098. if (FAILED(hr))
  1099. {
  1100. AthMessageBoxW(m_hwndParent,
  1101. MAKEINTRESOURCEW(idsAthena),
  1102. MAKEINTRESOURCEW(idsErrDDFileNotFound),
  1103. NULL, MB_ICONEXCLAMATION|MB_SETFOREGROUND|MB_OK);
  1104. }
  1105. SetCursor(hcursor);
  1106. return S_OK;
  1107. }
  1108. HRESULT CAttMan::HrDropFileDescriptor(LPDATAOBJECT pDataObj, BOOL fLink)
  1109. {
  1110. HCURSOR hcursor;
  1111. BOOL fFirstDirectory = TRUE,
  1112. fLinkDirectories = FALSE,
  1113. fUnicode = TRUE,
  1114. fIsDirectory;
  1115. SCODE sc = S_OK;
  1116. LPWSTR pwszFileName = NULL;
  1117. HRESULT hr = S_OK;
  1118. STGMEDIUM stgmedDesc;
  1119. FILEGROUPDESCRIPTORA *pfgdA = NULL;
  1120. FILEDESCRIPTORA *pfdA = NULL;
  1121. FILEGROUPDESCRIPTORW *pfgdW = NULL;
  1122. FILEDESCRIPTORW *pfdW = NULL;
  1123. UINT uiNumFiles,
  1124. uiCurrFile;
  1125. FORMATETC fetcFileDescA =
  1126. {(CLIPFORMAT)(CF_FILEDESCRIPTORA), NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  1127. FORMATETC fetcFileDescW =
  1128. {(CLIPFORMAT)(CF_FILEDESCRIPTORW), NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  1129. FORMATETC fetcFileContents =
  1130. {(CLIPFORMAT)(CF_FILECONTENTS), NULL, DVASPECT_CONTENT, -1, TYMED_ISTREAM|
  1131. TYMED_HGLOBAL};
  1132. hcursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1133. ZeroMemory(&stgmedDesc, sizeof(STGMEDIUM));
  1134. hr = pDataObj->GetData(&fetcFileDescW, &stgmedDesc);
  1135. if (SUCCEEDED(hr))
  1136. {
  1137. pfgdW = (LPFILEGROUPDESCRIPTORW)GlobalLock(stgmedDesc.hGlobal);
  1138. uiNumFiles = pfgdW->cItems;
  1139. pfdW = &pfgdW->fgd[0];
  1140. }
  1141. else
  1142. {
  1143. IF_FAILEXIT(hr = pDataObj->GetData(&fetcFileDescA, &stgmedDesc));
  1144. fUnicode = FALSE;
  1145. pfgdA = (LPFILEGROUPDESCRIPTORA)GlobalLock(stgmedDesc.hGlobal);
  1146. uiNumFiles = pfgdA->cItems;
  1147. pfdA = &pfgdA->fgd[0];
  1148. }
  1149. // Loop through the contents
  1150. for (uiCurrFile = 0; uiCurrFile < uiNumFiles; ++uiCurrFile)
  1151. {
  1152. if (fUnicode)
  1153. {
  1154. fIsDirectory = (pfdW->dwFlags & FD_ATTRIBUTES) &&
  1155. (pfdW->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
  1156. IF_NULLEXIT(pwszFileName = PszDupW(pfdW->cFileName));
  1157. ++pfdW;
  1158. }
  1159. else
  1160. {
  1161. fIsDirectory = (pfdA->dwFlags & FD_ATTRIBUTES) &&
  1162. (pfdA->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
  1163. IF_NULLEXIT(pwszFileName = PszToUnicode(CP_ACP, pfdA->cFileName));
  1164. ++pfdA;
  1165. }
  1166. // if we have a directory, there's no contents for it, just filename, so let's
  1167. // see if the user wants us to make a link...
  1168. if (!fLink && fIsDirectory)
  1169. {
  1170. if(fFirstDirectory)
  1171. {
  1172. int id;
  1173. // Tell the user that he's been a bad user
  1174. id=AthMessageBoxW(m_hwndParent,
  1175. MAKEINTRESOURCEW(idsAthena),
  1176. MAKEINTRESOURCEW(idsDropLinkDirs),
  1177. NULL,
  1178. MB_ICONEXCLAMATION|MB_SETFOREGROUND|MB_YESNOCANCEL);
  1179. if(id==IDCANCEL)
  1180. {
  1181. hr=NOERROR;
  1182. goto exit;
  1183. }
  1184. fLinkDirectories = (id == IDYES);
  1185. fFirstDirectory = FALSE;
  1186. }
  1187. if(fLinkDirectories)
  1188. hr=HrInsertFileFromStgMed(pwszFileName, NULL, TRUE);
  1189. }
  1190. else
  1191. {
  1192. // Since we have the UNICODE filename with pwszFileName, we don't
  1193. // need to worry about making sure stgmedContents is UNICODE.
  1194. STGMEDIUM stgmedContents;
  1195. ZeroMemory(&stgmedContents, sizeof(STGMEDIUM));
  1196. fetcFileContents.lindex = uiCurrFile;
  1197. IF_FAILEXIT(hr = pDataObj->GetData(&fetcFileContents, &stgmedContents));
  1198. switch (stgmedContents.tymed)
  1199. {
  1200. case TYMED_HGLOBAL:
  1201. case TYMED_ISTREAM:
  1202. hr=HrInsertFileFromStgMed(pwszFileName, &stgmedContents, fLink);
  1203. break;
  1204. default:
  1205. AssertSz(FALSE, "Unexpected TYMED");
  1206. break;
  1207. }
  1208. ReleaseStgMedium(&stgmedContents);
  1209. }
  1210. SafeMemFree(pwszFileName);
  1211. }
  1212. exit:
  1213. SetCursor(hcursor);
  1214. if (pfgdA || pfgdW)
  1215. GlobalUnlock(stgmedDesc.hGlobal);
  1216. MemFree(pwszFileName);
  1217. ReleaseStgMedium(&stgmedDesc);
  1218. return hr;
  1219. }
  1220. static const HELPMAP g_rgCtxMapMailGeneral[] = {
  1221. {chx2, IDH_INSERT_ATTACHMENT_MAKE_SHORTCUT},
  1222. {0,0}};
  1223. BOOL CALLBACK CAttMan::InsertFileDlgHookProc(HWND hwnd, UINT msg, WPARAM wParam,LPARAM lParam)
  1224. {
  1225. char szTemp[MAX_PATH];
  1226. HRESULT hr;
  1227. switch (msg)
  1228. {
  1229. case WM_INITDIALOG:
  1230. {
  1231. HWND hwndParent = GetParent(hwnd);
  1232. SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)(((LPOPENFILENAME)lParam)->lCustData));
  1233. // Bug 1073: Replace the "Open" button with "Attach"
  1234. if (AthLoadString(idsAttach, szTemp, ARRAYSIZE(szTemp)))
  1235. SetDlgItemText(hwndParent, IDOK, szTemp);
  1236. if (AthLoadString(idsInsertAttachment, szTemp, ARRAYSIZE(szTemp)))
  1237. SetWindowText(hwndParent, szTemp);
  1238. CenterDialog( hwnd );
  1239. return TRUE;
  1240. }
  1241. case WM_HELP:
  1242. case WM_CONTEXTMENU:
  1243. return OnContextHelp(hwnd, msg, wParam, lParam, g_rgCtxMapMailGeneral);
  1244. case WM_NOTIFY:
  1245. {
  1246. if (CDN_FILEOK == ((LPNMHDR)lParam)->code)
  1247. {
  1248. AssertSz(sizeof(OPENFILENAMEW) == sizeof(OPENFILENAMEA), "Win9x will give us OPENFILENAMEA");
  1249. OPENFILENAMEW *pofn = ((OFNOTIFYW*)lParam)->lpOFN;
  1250. AssertSz(pofn, "Why didn't we get a OPENFILENAMEA struct???");
  1251. ATTMANCUSTOM *pCustom = (ATTMANCUSTOM*)(pofn->lCustData);
  1252. pCustom->fShortcut = IsDlgButtonChecked(hwnd, chx2);
  1253. // If we are ANSI and we have mutiple files, then we need to
  1254. // convert the entire filepath and pass it back up to our
  1255. // caller since shlwapi doesn't handle multiple files during conversion
  1256. if (!IsWindowUnicode(hwnd))
  1257. {
  1258. LPSTR pszSrc = (LPSTR)pofn->lpstrFile;
  1259. LPWSTR pszDest = pCustom->szFiles;
  1260. WORD nFilePathLen = (WORD) lstrlen(pszSrc);
  1261. if (pofn->nFileOffset > nFilePathLen)
  1262. {
  1263. pCustom->nFileOffset = nFilePathLen + 1;
  1264. int nChars = ARRAYSIZE(pCustom->szFiles);
  1265. while (*pszSrc && (nChars>0))
  1266. {
  1267. DWORD cLenAndNull = lstrlen(pszSrc) + 1;
  1268. DWORD cchWideAndNull = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,
  1269. pszSrc, cLenAndNull,
  1270. pszDest, nChars);
  1271. // Since the original buffers (custom and lpstrFile) were both static
  1272. // sized arrays of the same length, we know that pszDest will never be
  1273. // accessed beyond its end.
  1274. pszSrc += cLenAndNull;
  1275. pszDest += cchWideAndNull;
  1276. nChars -= cchWideAndNull;
  1277. }
  1278. //bobn: 75453 not copying second null
  1279. *pszDest=0;
  1280. }
  1281. }
  1282. return TRUE;
  1283. }
  1284. }
  1285. }
  1286. return FALSE;
  1287. }
  1288. HRESULT CAttMan::HrUpdateToolbar(HWND hwndToolbar)
  1289. {
  1290. if (GetFocus() == m_hwndList)
  1291. {
  1292. // if we have focus, kill the edit cut|copy paste btns
  1293. EnableDisableEditToolbar(hwndToolbar, 0);
  1294. }
  1295. return S_OK;
  1296. }
  1297. HRESULT CAttMan::HrInsertFileFromStgMed(LPWSTR pwszFileName, LPSTGMEDIUM pstgmed, BOOL fMakeLinks)
  1298. {
  1299. HRESULT hr=NOERROR;
  1300. LPSTREAM pStmToFree = NULL,
  1301. pAttachStm = NULL;
  1302. if(!pstgmed)
  1303. {
  1304. AssertSz(fMakeLinks, "this should always be true if there is no stgmedium!");
  1305. fMakeLinks = TRUE;
  1306. }
  1307. else
  1308. switch (pstgmed->tymed)
  1309. {
  1310. case TYMED_HGLOBAL:
  1311. hr=CreateStreamOnHGlobal(pstgmed->hGlobal, TRUE, &pStmToFree);
  1312. if(SUCCEEDED(hr))
  1313. {
  1314. // NULL out the hglobal do it doesn't get free'd
  1315. pstgmed->hGlobal=NULL;
  1316. pAttachStm = pStmToFree;
  1317. }
  1318. break;
  1319. case TYMED_ISTREAM:
  1320. pAttachStm = pstgmed->pstm;
  1321. break;
  1322. default:
  1323. AssertSz(FALSE, "unexpected tymed");
  1324. hr = E_UNEXPECTED;
  1325. break;
  1326. }
  1327. if (SUCCEEDED(hr))
  1328. hr = HrAddAttachment(pwszFileName, pAttachStm, fMakeLinks);
  1329. ReleaseObj(pStmToFree);
  1330. return hr;
  1331. }
  1332. HRESULT CAttMan::HrBuildHDrop(PDATAOBJINFO *ppdoi)
  1333. {
  1334. LPDROPFILES lpDrop=0;
  1335. LPWSTR *rgpwszTemp=NULL,
  1336. pwszPath;
  1337. LPSTR *rgpszTemp=NULL,
  1338. pszPath;
  1339. int cFiles,
  1340. i;
  1341. LV_ITEMW lvi;
  1342. ULONG cb;
  1343. HRESULT hr = S_OK;
  1344. LPATTACHDATA lpAttach;
  1345. // Since win9x can't handle unicode names, the fWide parameter in the
  1346. // DROPFILES struct is ignored. So in the win9x case, we need to do
  1347. // special conversions here when building the HDROP. One thing to note,
  1348. // the temp files that are generated on win9x will already be safe for
  1349. // the system code page. The temp file names might differ from the actual
  1350. // file name, but the temp file name will be ok.
  1351. BOOL fWinNT = (VER_PLATFORM_WIN32_NT == g_OSInfo.dwPlatformId);
  1352. if(!ppdoi)
  1353. return TraceResult(E_INVALIDARG);
  1354. *ppdoi=NULL;
  1355. cFiles=ListView_GetSelectedCount(m_hwndList);
  1356. if(!cFiles)
  1357. return TraceResult(E_FAIL); // nothing to build
  1358. lvi.mask = LVIF_PARAM;
  1359. lvi.iSubItem = 0;
  1360. lvi.iItem=-1;
  1361. // Walk the list and find out how much space we need.
  1362. if (fWinNT)
  1363. {
  1364. IF_NULLEXIT(MemAlloc((LPVOID *)&rgpwszTemp, sizeof(LPWSTR)*cFiles));
  1365. ZeroMemory(rgpwszTemp, sizeof(LPWSTR)*cFiles);
  1366. }
  1367. else
  1368. {
  1369. IF_NULLEXIT(MemAlloc((LPVOID *)&rgpszTemp, sizeof(LPSTR)*cFiles));
  1370. ZeroMemory(rgpszTemp, sizeof(LPSTR)*cFiles);
  1371. }
  1372. cFiles = 0;
  1373. cb = sizeof(DROPFILES);
  1374. while(((lvi.iItem=ListView_GetNextItem(m_hwndList, lvi.iItem,
  1375. LVNI_SELECTED|LVNI_ALL))!=-1))
  1376. {
  1377. if (!SendMessage(m_hwndList, LVM_GETITEMW, 0, (LPARAM)(LV_ITEMW*)(&lvi)))
  1378. {
  1379. hr=E_FAIL;
  1380. goto exit;
  1381. }
  1382. if (!(lpAttach=(LPATTACHDATA)lvi.lParam))
  1383. {
  1384. hr=E_FAIL;
  1385. goto exit;
  1386. }
  1387. IF_FAILEXIT(hr = HrGetTempFile(lpAttach));
  1388. if (fWinNT)
  1389. {
  1390. rgpwszTemp[cFiles] = lpAttach->szTempFile;
  1391. cb+=(lstrlenW(rgpwszTemp[cFiles++]) + 1)*sizeof(WCHAR);
  1392. }
  1393. else
  1394. {
  1395. rgpszTemp[cFiles] = PszToANSI(CP_ACP, lpAttach->szTempFile);
  1396. cb+=(lstrlen(rgpszTemp[cFiles++]) + 1)*sizeof(CHAR);
  1397. }
  1398. }
  1399. //double-null term at end.
  1400. if (fWinNT)
  1401. cb+=sizeof(WCHAR);
  1402. else
  1403. cb+=sizeof(CHAR);
  1404. // Allocate the buffer and fill it in.
  1405. IF_NULLEXIT(MemAlloc((LPVOID*) &lpDrop, cb));
  1406. ZeroMemory(lpDrop, cb);
  1407. lpDrop->pFiles = sizeof(DROPFILES);
  1408. lpDrop->fWide = fWinNT;
  1409. // Fill in the path names.
  1410. if (fWinNT)
  1411. {
  1412. pwszPath = (LPWSTR)((BYTE *)lpDrop + sizeof(DROPFILES));
  1413. PWSTR pwszEnd = (LPWSTR)((BYTE *)lpDrop + cb);
  1414. for(i=0; i<cFiles; i++)
  1415. {
  1416. StrCpyNW(pwszPath, rgpwszTemp[i], (DWORD)(pwszEnd-pwszPath));
  1417. pwszPath += lstrlenW(rgpwszTemp[i])+1;
  1418. }
  1419. }
  1420. else
  1421. {
  1422. pszPath = (LPSTR)((BYTE *)lpDrop + sizeof(DROPFILES));
  1423. PSTR pszEnd = (LPSTR)((BYTE *)lpDrop + cb);
  1424. for(i=0; i<cFiles; i++)
  1425. {
  1426. StrCpyN(pszPath, rgpszTemp[i], (DWORD)(pszEnd-pszPath));
  1427. pszPath += lstrlen(rgpszTemp[i])+1;
  1428. }
  1429. }
  1430. // Now allocate the DATAOBJECTINFO struct
  1431. IF_NULLEXIT(MemAlloc((LPVOID*) ppdoi, sizeof(DATAOBJINFO)));
  1432. SETDefFormatEtc((*ppdoi)->fe, CF_HDROP, TYMED_HGLOBAL);
  1433. (*ppdoi)->pData = (LPVOID) lpDrop;
  1434. (*ppdoi)->cbData = cb;
  1435. // Don't free the dropfiles struct
  1436. lpDrop = NULL;
  1437. exit:
  1438. MemFree(lpDrop);
  1439. MemFree(rgpwszTemp);
  1440. if (rgpszTemp)
  1441. {
  1442. for(i=0; i<cFiles; i++)
  1443. MemFree(rgpszTemp[i]);
  1444. MemFree(rgpszTemp);
  1445. }
  1446. return TraceResult(hr);
  1447. }
  1448. /*
  1449. * IDropSource::
  1450. */
  1451. HRESULT CAttMan::QueryContinueDrag(BOOL fEscapePressed, DWORD grfKeyState)
  1452. {
  1453. DOUTL(8, "IDS::QueryContDrag()");
  1454. if(fEscapePressed)
  1455. return ResultFromScode(DRAGDROP_S_CANCEL);
  1456. if(!(grfKeyState & m_dwDragType))
  1457. return ResultFromScode(DRAGDROP_S_DROP);
  1458. return NOERROR;
  1459. }
  1460. HRESULT CAttMan::GiveFeedback(DWORD dwEffect)
  1461. {
  1462. DOUTL(8, "IDS::GiveFeedback()");
  1463. return ResultFromScode(DRAGDROP_S_USEDEFAULTCURSORS);
  1464. }
  1465. /*
  1466. * HrGetRequiredAction()
  1467. *
  1468. * Purpose: this method is called in response to a
  1469. * drag with the right mouse clicked rather
  1470. * than the left. A context menu is displayed
  1471. */
  1472. HRESULT CAttMan::HrGetRequiredAction(DWORD *pdwEffect, POINTL pt)
  1473. {
  1474. // Pop up the context menu.
  1475. //
  1476. HMENU hMenu;
  1477. UINT idCmd;
  1478. HRESULT hr = E_FAIL;
  1479. *pdwEffect = DROPEFFECT_NONE;
  1480. Assert(m_hwndList);
  1481. hMenu = LoadPopupMenu(IDR_ATTACHMENT_DRAGDROP_POPUP);
  1482. if (!hMenu)
  1483. goto cleanup;
  1484. MenuUtil_SetPopupDefault(hMenu, ID_MOVE);
  1485. idCmd = TrackPopupMenuEx(hMenu, TPM_RETURNCMD|TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_RIGHTBUTTON,
  1486. pt.x, pt.y, m_hwndList, NULL);
  1487. switch(idCmd)
  1488. {
  1489. case ID_MOVE:
  1490. *pdwEffect = DROPEFFECT_MOVE;
  1491. break;
  1492. case ID_COPY:
  1493. *pdwEffect = DROPEFFECT_COPY;
  1494. break;
  1495. case ID_CREATE_SHORTCUT:
  1496. *pdwEffect = DROPEFFECT_LINK;
  1497. break;
  1498. default:
  1499. // cancelled
  1500. goto cleanup;
  1501. }
  1502. hr = S_OK;
  1503. cleanup:
  1504. if(hMenu)
  1505. DestroyMenu(hMenu);
  1506. return hr;
  1507. }
  1508. /*
  1509. * It is critical that any client of the Attman calls HrClose to drop it's refcounts.
  1510. *
  1511. */
  1512. HRESULT CAttMan::HrClose()
  1513. {
  1514. HrUnload();
  1515. #if 0
  1516. if(m_fDropTargetRegister)
  1517. {
  1518. Assert(m_hwndList && IsWindow(m_hwndList));
  1519. RevokeDragDrop(m_hwndList);
  1520. CoLockObjectExternal((LPUNKNOWN)(LPDROPTARGET)this, FALSE, TRUE);
  1521. }
  1522. #endif
  1523. return S_OK;
  1524. }
  1525. //Adds a new attach to m_rgpAttach and places the new attach in a proper hole
  1526. HRESULT CAttMan::HrAllocNewEntry(LPATTACHDATA pAttach)
  1527. {
  1528. ULONG uAttach;
  1529. if (m_cAlloc==m_cAttach)
  1530. {
  1531. DOUTL(4, "HrGrowAttachStruct:: Growing Table");
  1532. // grow time!!
  1533. m_cAlloc+=CACHE_GROW_SIZE;
  1534. if (!MemRealloc((LPVOID *)&m_rgpAttach, sizeof(LPATTACHDATA)*m_cAlloc))
  1535. return E_OUTOFMEMORY;
  1536. // zeroinit new memory
  1537. ZeroMemory(&m_rgpAttach[m_cAttach], sizeof(LPATTACHDATA)*CACHE_GROW_SIZE);
  1538. }
  1539. // find a hole to put the new data into
  1540. for (uAttach=0; uAttach<m_cAlloc; uAttach++)
  1541. if (m_rgpAttach[uAttach]==NULL)
  1542. {
  1543. m_rgpAttach[uAttach]=pAttach;
  1544. break;
  1545. }
  1546. AssertSz(uAttach!=m_cAlloc, "Woah! we went off the end!");
  1547. m_cAttach++;
  1548. return S_OK;
  1549. }
  1550. // Only used when the function is adding attachs from a IMimeMessage
  1551. HRESULT CAttMan::HrAddData(HBODY hAttach)
  1552. {
  1553. LPATTACHDATA pAttach=0;
  1554. LPMIMEBODY pBody=0;
  1555. HRESULT hr;
  1556. Assert(hAttach);
  1557. Assert(m_pMsg);
  1558. hr = HrAttachDataFromBodyPart(m_pMsg, hAttach, &pAttach);
  1559. if (!FAILED(hr))
  1560. {
  1561. if (m_fDeleteVCards && StrStrIW(PathFindExtensionW(pAttach->szFileName), L".vcf"))
  1562. return S_OK;
  1563. hr = HrAllocNewEntry(pAttach);
  1564. if (!FAILED(hr))
  1565. return S_OK; // don't free pAttach as it's owned by the table now
  1566. MemFree(pAttach);
  1567. }
  1568. return S_OK;
  1569. }
  1570. // Only used when the function is adding attachs from outside of an IMimeMessage
  1571. HRESULT CAttMan::HrAddData(LPWSTR lpszPathName, LPSTREAM pstm, LPATTACHDATA *ppAttach)
  1572. {
  1573. LPATTACHDATA pAttach;
  1574. HRESULT hr;
  1575. hr = HrAttachDataFromFile(pstm, lpszPathName, &pAttach);
  1576. if (!FAILED(hr))
  1577. {
  1578. hr = HrAllocNewEntry(pAttach);
  1579. if (!FAILED(hr))
  1580. {
  1581. if (ppAttach)
  1582. *ppAttach=pAttach;
  1583. return S_OK; // don't free pAttach as it's owned by the table now
  1584. }
  1585. MemFree(pAttach);
  1586. }
  1587. return hr;
  1588. }
  1589. HRESULT CAttMan::HrFreeAllData()
  1590. {
  1591. ULONG uAttach;
  1592. for (uAttach=0; uAttach<m_cAlloc; uAttach++)
  1593. if (m_rgpAttach[uAttach])
  1594. {
  1595. HrFreeAttachData(m_rgpAttach[uAttach]);
  1596. m_rgpAttach[uAttach] = NULL;
  1597. }
  1598. SafeMemFree(m_rgpAttach);
  1599. m_cAlloc=0;
  1600. m_cAttach=0;
  1601. m_iVCard = -1;
  1602. if (m_szUnsafeAttachList != NULL)
  1603. SafeMemFree(m_szUnsafeAttachList);
  1604. m_cUnsafeAttach = 0;
  1605. return NOERROR;
  1606. }
  1607. HRESULT CAttMan::HrDoVerb(LPATTACHDATA lpAttach, INT nVerb)
  1608. {
  1609. HRESULT hr;
  1610. ULONG uVerb = AV_MAX;
  1611. if (!lpAttach)
  1612. return E_INVALIDARG;
  1613. switch (nVerb)
  1614. {
  1615. case ID_SAVE_ATTACH_AS:
  1616. uVerb = AV_SAVEAS;
  1617. break;
  1618. case ID_OPEN:
  1619. uVerb = AV_OPEN;
  1620. break;
  1621. case ID_PRINT:
  1622. uVerb = AV_PRINT;
  1623. break;
  1624. case ID_QUICK_VIEW:
  1625. uVerb = AV_QUICKVIEW;
  1626. break;
  1627. default:
  1628. AssertSz(0, "BAD ARGUMENT");
  1629. return E_INVALIDARG;
  1630. }
  1631. hr = HrDoAttachmentVerb(m_hwndParent, uVerb, m_pMsg, lpAttach);
  1632. if (FAILED(hr) && hr!=hrUserCancel)
  1633. AthMessageBoxW(m_hwndParent,
  1634. MAKEINTRESOURCEW(idsAthena),
  1635. MAKEINTRESOURCEW(idsErrCmdFailed),
  1636. NULL, MB_OK|MB_ICONEXCLAMATION);
  1637. return hr;
  1638. }
  1639. //////////////////////////////////////////////////////////////////////////////
  1640. // IPersistMime::Load
  1641. HRESULT CAttMan::Load(LPMIMEMESSAGE pMsg)
  1642. {
  1643. HRESULT hr;
  1644. if(!pMsg)
  1645. return E_INVALIDARG;
  1646. HrUnload();
  1647. ReplaceInterface(m_pMsg, pMsg);
  1648. hr=HrBuildAttachList();
  1649. if (FAILED(hr))
  1650. goto error;
  1651. hr=HrFillListView();
  1652. if (ListView_GetItemCount(m_hwndList) > 0)
  1653. {
  1654. // if we went from 0->1 then select the first item
  1655. ListView_SelectItem(m_hwndList, 0);
  1656. }
  1657. HrResizeParent();
  1658. m_fDirty = FALSE;
  1659. error:
  1660. return hr;
  1661. }
  1662. HRESULT CAttMan::CheckAttachNameSafeWithCP(CODEPAGEID cpID)
  1663. {
  1664. LPATTACHDATA *currAttach = m_rgpAttach;
  1665. HRESULT hr = S_OK;
  1666. for (ULONG uAttach = 0; uAttach<m_cAlloc; uAttach++, currAttach++)
  1667. {
  1668. if (*currAttach)
  1669. {
  1670. IF_FAILEXIT(hr = HrSafeToEncodeToCP((*currAttach)->szFileName, cpID));
  1671. if (MIME_S_CHARSET_CONFLICT == hr)
  1672. goto exit;
  1673. }
  1674. }
  1675. exit:
  1676. return hr;
  1677. }
  1678. // IPersistMime::Save
  1679. HRESULT CAttMan::Save(LPMIMEMESSAGE pMsg, DWORD dwFlags)
  1680. {
  1681. ULONG uAttach;
  1682. LPATTACHDATA *currAttach = m_rgpAttach;
  1683. HRESULT hr = S_OK;
  1684. for (uAttach=0; uAttach<m_cAlloc; uAttach++)
  1685. {
  1686. if (*currAttach)
  1687. {
  1688. HBODY currHAttach = (*currAttach)->hAttach;
  1689. LPMIMEMESSAGEW pMsgW = NULL;
  1690. LPWSTR pszFileName = (*currAttach)->szFileName;
  1691. LPSTREAM lpStrmPlaceHolder = (*currAttach)->pstm,
  1692. lpstrm = NULL;
  1693. BOOL fAttachFile = TRUE;
  1694. if (SUCCEEDED(pMsg->QueryInterface(IID_IMimeMessageW, (LPVOID*)&pMsgW)))
  1695. {
  1696. //If attachment at load time (i.e. from m_pMsg)
  1697. if (currHAttach)
  1698. {
  1699. LPMIMEBODY pBody = NULL;
  1700. if (S_OK == m_pMsg->BindToObject(currHAttach, IID_IMimeBody, (LPVOID *)&pBody))
  1701. {
  1702. if (pBody->GetData(IET_INETCSET, &lpstrm)==S_OK)
  1703. lpStrmPlaceHolder = lpstrm;
  1704. else
  1705. fAttachFile = FALSE;
  1706. ReleaseObj(pBody);
  1707. }
  1708. }
  1709. //If attachment was added after load time
  1710. if (!fAttachFile || FAILED(pMsgW->AttachFileW(pszFileName, lpStrmPlaceHolder, NULL)))
  1711. hr = E_FAIL;
  1712. ReleaseObj(lpstrm);
  1713. ReleaseObj(pMsgW);
  1714. }
  1715. else
  1716. hr = E_FAIL;
  1717. }
  1718. currAttach++;
  1719. }
  1720. if (FAILED(hr))
  1721. {
  1722. if (AthMessageBoxW( m_hwndParent,
  1723. MAKEINTRESOURCEW(idsAthena),
  1724. MAKEINTRESOURCEW(idsSendWithoutAttach),
  1725. NULL, MB_YESNO|MB_ICONEXCLAMATION )==IDYES)
  1726. hr = S_OK;
  1727. else
  1728. hr = MAPI_E_USER_CANCEL;
  1729. }
  1730. return hr;
  1731. }
  1732. // IPersist::GetClassID
  1733. HRESULT CAttMan::GetClassID(CLSID *pClsID)
  1734. {
  1735. //TODO: If ever expose, should return a valid ID
  1736. return E_NOTIMPL;
  1737. }
  1738. HRESULT CAttMan::HrSaveAs(LPATTACHDATA lpAttach)
  1739. {
  1740. HRESULT hr = S_OK;
  1741. OPENFILENAMEW ofn;
  1742. WCHAR szTitle[CCHMAX_STRINGRES],
  1743. szFilter[CCHMAX_STRINGRES],
  1744. szFile[MAX_PATH];
  1745. *szFile=0;
  1746. *szFilter=0;
  1747. *szTitle=0;
  1748. Assert (*lpAttach->szFileName);
  1749. StrCpyNW(szFile, lpAttach->szFileName, MAX_PATH);
  1750. ZeroMemory (&ofn, sizeof (ofn));
  1751. ofn.lStructSize = sizeof (ofn);
  1752. ofn.hwndOwner = m_hwndParent;
  1753. AthLoadStringW(idsFilterAttSave, szFilter, ARRAYSIZE(szFilter));
  1754. ReplaceCharsW(szFilter, _T('|'), _T('\0'));
  1755. ofn.lpstrFilter = szFilter;
  1756. ofn.nFilterIndex = 1;
  1757. ofn.lpstrFile = szFile;
  1758. ofn.nMaxFile = ARRAYSIZE(szFile);
  1759. AthLoadStringW(idsSaveAttachmentAs, szTitle, ARRAYSIZE(szTitle));
  1760. ofn.lpstrTitle = szTitle;
  1761. ofn.Flags = OFN_NOCHANGEDIR | OFN_NOREADONLYRETURN | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
  1762. // Show SaveAs Dialog
  1763. if (HrAthGetFileNameW(&ofn, FALSE) != S_OK)
  1764. {
  1765. hr = hrUserCancel;
  1766. goto error;
  1767. }
  1768. // Verify the Attachment's Stream
  1769. hr=HrSave(lpAttach->hAttach, szFile);
  1770. if (FAILED(hr))
  1771. goto error;
  1772. error:
  1773. return hr;
  1774. }
  1775. HRESULT CAttMan::HrGetTempFile(LPATTACHDATA lpAttach)
  1776. {
  1777. HRESULT hr;
  1778. if (*lpAttach->szTempFile)
  1779. return S_OK;
  1780. // Since win9x can't handle filenames very well, let's try to handle this
  1781. // by converting the temp names to something workable in win9x.
  1782. if (VER_PLATFORM_WIN32_NT == g_OSInfo.dwPlatformId)
  1783. {
  1784. if (!FBuildTempPathW(lpAttach->szFileName, lpAttach->szTempFile, ARRAYSIZE(lpAttach->szTempFile), FALSE))
  1785. {
  1786. hr = E_FAIL;
  1787. goto error;
  1788. }
  1789. }
  1790. else
  1791. {
  1792. // Since we are on win95, the temp path will never be bad ANSI. Don't need to bother
  1793. // converting to ANSI and back to UNICODE
  1794. BOOL fSucceeded = FBuildTempPathW(lpAttach->szFileName, lpAttach->szTempFile, ARRAYSIZE(lpAttach->szTempFile), FALSE);
  1795. if (!fSucceeded)
  1796. {
  1797. hr = E_FAIL;
  1798. goto error;
  1799. }
  1800. }
  1801. if (lpAttach->hAttach == NULL && lpAttach->pstm)
  1802. {
  1803. // if no attachment, but just stream data
  1804. hr = WriteStreamToFileW(lpAttach->pstm, lpAttach->szTempFile, CREATE_NEW, GENERIC_WRITE);
  1805. }
  1806. else
  1807. {
  1808. hr=HrSave(lpAttach->hAttach, lpAttach->szTempFile);
  1809. }
  1810. if (FAILED(hr))
  1811. goto error;
  1812. error:
  1813. if (FAILED(hr))
  1814. {
  1815. // Null out temp file as we didn't really create it
  1816. *(lpAttach->szTempFile)=0;
  1817. }
  1818. return hr;
  1819. }
  1820. HRESULT CAttMan::HrCleanTempFile(LPATTACHDATA lpAttach)
  1821. {
  1822. if ((lpAttach->szTempFile) && ('\0' != lpAttach->szTempFile[0]))
  1823. {
  1824. // If the file was launched, don't delete the temp file if the process still has it open
  1825. if (lpAttach->hProcess)
  1826. {
  1827. DWORD dwState = WaitForSingleObject (lpAttach->hProcess, 0);
  1828. if (dwState == WAIT_OBJECT_0)
  1829. DeleteFileWrapW(lpAttach->szTempFile);
  1830. }
  1831. else
  1832. DeleteFileWrapW(lpAttach->szTempFile);
  1833. }
  1834. *lpAttach->szTempFile = NULL;
  1835. lpAttach->hProcess=NULL;
  1836. return NOERROR;
  1837. }
  1838. HRESULT CAttMan::HrSave(HBODY hAttach, LPWSTR lpszFileName)
  1839. {
  1840. IMimeBodyW *pBody = NULL;
  1841. HRESULT hr;
  1842. hr = m_pMsg->BindToObject(hAttach, IID_IMimeBodyW, (LPVOID *)&pBody);
  1843. if (SUCCEEDED(hr))
  1844. hr = pBody->SaveToFileW(IET_INETCSET, lpszFileName);
  1845. ReleaseObj(pBody);
  1846. return hr;
  1847. }
  1848. HRESULT CAttMan::HrCmdEnabled(UINT idm, LPBOOL pbEnable)
  1849. {
  1850. Assert (pbEnable);
  1851. return S_FALSE;
  1852. }
  1853. HRESULT CAttMan::HrIsDragSource()
  1854. {
  1855. return (m_fDragSource ? S_OK : S_FALSE);
  1856. }