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.

866 lines
28 KiB

  1. // ----------------------------------------------------------------------------------------------------------
  2. // M A I L U T I L . C P P
  3. // ----------------------------------------------------------------------------------------------------------
  4. #include "pch.hxx"
  5. #include "demand.h"
  6. #include "resource.h"
  7. #include "mimeole.h"
  8. #include "mimeutil.h"
  9. #include "strconst.h"
  10. #include "url.h"
  11. #include "mailutil.h"
  12. #include <spoolapi.h>
  13. #include <fonts.h>
  14. #include "instance.h"
  15. #include "pop3task.h"
  16. #include <ntverp.h>
  17. #include "msgfldr.h"
  18. #include "storutil.h"
  19. #include "note.h"
  20. #include "shlwapip.h"
  21. #include <iert.h>
  22. #include "storecb.h"
  23. #include "conman.h"
  24. #include "multiusr.h"
  25. #include "ipab.h"
  26. #include "secutil.h"
  27. // ----------------------------------------------------------------------------------------------------------
  28. // Folder Dialog Info
  29. // ----------------------------------------------------------------------------------------------------------
  30. typedef struct FLDRDLG_tag
  31. {
  32. FOLDERID idFolder;
  33. BOOL fPending;
  34. CStoreDlgCB *pCallback;
  35. } FLDRDLG, *PFLDRDLG;
  36. // ----------------------------------------------------------------------------------------------------------
  37. // Prototypes
  38. // ----------------------------------------------------------------------------------------------------------
  39. INT_PTR CALLBACK MailUtil_FldrDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
  40. INT_PTR CALLBACK WebPageDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
  41. HRESULT HrDlgCreateWebPage(HWND hwndDlg);
  42. // ----------------------------------------------------------------------------------------------------------
  43. // DoFolderDialog
  44. // ----------------------------------------------------------------------------------------------------------
  45. void MailUtil_DoFolderDialog(HWND hwndParent, FOLDERID idFolder)
  46. {
  47. FLDRDLG fdlg;
  48. fdlg.idFolder = idFolder;
  49. fdlg.fPending = FALSE;
  50. fdlg.pCallback = new CStoreDlgCB;
  51. if (fdlg.pCallback == NULL)
  52. // TODO: an error message might be nice
  53. return;
  54. DialogBoxParam(g_hLocRes, MAKEINTRESOURCE(iddNewFolder), hwndParent, MailUtil_FldrDlgProc, (LPARAM)&fdlg);
  55. fdlg.pCallback->Release();
  56. }
  57. // ----------------------------------------------------------------------------------------------------------
  58. // FldrDlgProc
  59. // ----------------------------------------------------------------------------------------------------------
  60. INT_PTR CALLBACK MailUtil_FldrDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  61. {
  62. PFLDRDLG pfdlg;
  63. TCHAR sz[CCHMAX_STRINGRES];
  64. HWND hwndT;
  65. HRESULT hr;
  66. WORD id;
  67. FOLDERINFO Folder;
  68. Assert(CCHMAX_STRINGRES > CCHMAX_FOLDER_NAME);
  69. switch(msg)
  70. {
  71. case WM_INITDIALOG:
  72. pfdlg = (PFLDRDLG)lParam;
  73. Assert(pfdlg != NULL);
  74. SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM)pfdlg);
  75. hwndT = GetDlgItem(hwnd, idtxtFolderName);
  76. Assert(hwndT != NULL);
  77. SetIntlFont(hwndT);
  78. SendMessage(hwndT, EM_LIMITTEXT, CCHMAX_FOLDER_NAME, 0);
  79. LoadString(g_hLocRes, idsRenameFolderTitle, sz, ARRAYSIZE(sz));
  80. SetWindowText(hwnd, sz);
  81. hr = g_pStore->GetFolderInfo(pfdlg->idFolder, &Folder);
  82. if (!FAILED(hr))
  83. {
  84. SetWindowText(hwndT, Folder.pszName);
  85. g_pStore->FreeRecord(&Folder);
  86. }
  87. pfdlg->pCallback->Initialize(hwnd);
  88. SendMessage(hwndT, EM_SETSEL, 0, -1);
  89. CenterDialog(hwnd);
  90. return(TRUE);
  91. case WM_STORE_COMPLETE:
  92. pfdlg = (PFLDRDLG)GetDlgThisPtr(hwnd);
  93. Assert(pfdlg->fPending);
  94. pfdlg->fPending = FALSE;
  95. hr = pfdlg->pCallback->GetResult();
  96. if (hr == S_FALSE)
  97. {
  98. EndDialog(hwnd, IDCANCEL);
  99. }
  100. else if (FAILED(hr))
  101. {
  102. // No need to put up error dialog, CStoreDlgCB already did this on failed OnComplete
  103. /*
  104. AthErrorMessageW(hwnd, MAKEINTRESOURCEW(idsAthenaMail),
  105. MAKEINTRESOURCEW(idsErrRenameFld), hr);
  106. */
  107. hwndT = GetDlgItem(hwnd, idtxtFolderName);
  108. SendMessage(hwndT, EM_SETSEL, 0, -1);
  109. SetFocus(hwndT);
  110. }
  111. else
  112. {
  113. EndDialog(hwnd, IDOK);
  114. }
  115. break;
  116. case WM_COMMAND:
  117. pfdlg = (PFLDRDLG)GetDlgThisPtr(hwnd);
  118. id=GET_WM_COMMAND_ID(wParam, lParam);
  119. if (id == IDOK)
  120. {
  121. if (pfdlg->fPending)
  122. break;
  123. pfdlg->pCallback->Reset();
  124. hwndT = GetDlgItem(hwnd, idtxtFolderName);
  125. GetWindowText(hwndT, sz, ARRAYSIZE(sz));
  126. hr = g_pStore->RenameFolder(pfdlg->idFolder, sz, NOFLAGS, (IStoreCallback *)pfdlg->pCallback);
  127. if (hr == E_PENDING)
  128. {
  129. pfdlg->fPending = TRUE;
  130. }
  131. else if (FAILED(hr))
  132. {
  133. AthErrorMessageW(hwnd, MAKEINTRESOURCEW(idsAthenaMail),
  134. MAKEINTRESOURCEW(idsErrRenameFld), hr);
  135. SendMessage(hwndT, EM_SETSEL, 0, -1);
  136. SetFocus(hwndT);
  137. }
  138. else
  139. {
  140. EndDialog(hwnd, IDOK);
  141. }
  142. }
  143. else if (id==IDCANCEL)
  144. {
  145. if (pfdlg->fPending)
  146. pfdlg->pCallback->Cancel();
  147. else
  148. EndDialog(hwnd, IDCANCEL);
  149. }
  150. break;
  151. }
  152. return FALSE;
  153. }
  154. //
  155. // FUNCTION: MailUtil_OnImportAddressBook()
  156. //
  157. // PURPOSE: Calls the WAB migration code to handle import/export.
  158. //
  159. // PARAMETERS:
  160. // <in> fImport - TRUE if we should import, FALSE to export.
  161. //
  162. HRESULT MailUtil_OnImportExportAddressBook(HWND hwnd, BOOL fImport)
  163. {
  164. OFSTRUCT of;
  165. HFILE hfile;
  166. TCHAR szParam[255];
  167. LPTSTR lpParam = fImport ? _T("/import") : _T("/export");
  168. StrCpyN(szParam, lpParam, ARRAYSIZE(szParam));
  169. //MU_GetCurrentUserInfo(szParam+13, ARRAYSIZE(szParam) - 13, NULL, 0);
  170. hfile = OpenFile((TCHAR *)c_szWabMigExe, &of, OF_EXIST);
  171. if (hfile == HFILE_ERROR)
  172. return(E_FAIL);
  173. ShellExecute(hwnd, _T("Open"), of.szPathName, szParam, NULL, SW_SHOWNORMAL);
  174. return(S_OK);
  175. }
  176. HRESULT HrSendWebPageDirect(LPWSTR pwszUrl, HWND hwnd, BOOL fModal, BOOL fMail, FOLDERID folderID,
  177. BOOL fIncludeSig, IUnknown *pUnkPump, IMimeMessage *pMsg)
  178. {
  179. HRESULT hr;
  180. LPSTREAM pstm=NULL;
  181. HCURSOR hcur=0;
  182. INIT_MSGSITE_STRUCT initStruct;
  183. DWORD dwCreateFlags = OENCF_SENDIMMEDIATE|OENCF_USESTATIONERYFONT;
  184. HCHARSET hCharset;
  185. ENCODINGTYPE ietEncoding = IET_DECODED;
  186. BOOL fLittleEndian;
  187. LPSTR pszCharset = NULL;
  188. hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  189. if (!pMsg)
  190. {
  191. //We were not passed pMessage, so we need to create one.
  192. IF_FAILEXIT(hr = HrCreateMessage(&pMsg));
  193. }
  194. else
  195. {
  196. pMsg->AddRef();
  197. }
  198. IF_FAILEXIT(hr = HrCreateBasedWebPage(pwszUrl, &pstm));
  199. if (S_OK == HrIsStreamUnicode(pstm, &fLittleEndian))
  200. {
  201. if (SUCCEEDED(MimeOleFindCharset("utf-8", &hCharset)))
  202. {
  203. pMsg->SetCharset(hCharset, CSET_APPLY_ALL);
  204. }
  205. ietEncoding = IET_UNICODE;
  206. }
  207. else if((S_OK == GetHtmlCharset(pstm, &pszCharset)) && pszCharset)
  208. {
  209. if (SUCCEEDED(MimeOleFindCharset(pszCharset, &hCharset)))
  210. {
  211. pMsg->SetCharset(hCharset, CSET_APPLY_ALL);
  212. }
  213. ietEncoding = IET_INETCSET;
  214. }
  215. IF_FAILEXIT(hr = pMsg->SetTextBody(TXT_HTML, ietEncoding, NULL, pstm, NULL));
  216. initStruct.dwInitType = OEMSIT_MSG;
  217. initStruct.pMsg = pMsg;
  218. initStruct.folderID = folderID;
  219. if (!fIncludeSig)
  220. dwCreateFlags |= OENCF_NOSIGNATURE;
  221. if (fModal)
  222. dwCreateFlags |= OENCF_MODAL;
  223. if (!fMail)
  224. dwCreateFlags |= OENCF_NEWSFIRST;
  225. IF_FAILEXIT(hr = CreateAndShowNote(OENA_STATIONERY, dwCreateFlags, &initStruct, hwnd, pUnkPump));
  226. exit:
  227. if (hcur)
  228. SetCursor(hcur);
  229. ReleaseObj(pMsg);
  230. ReleaseObj(pstm);
  231. return hr;
  232. }
  233. HRESULT HrSendWebPage(HWND hwnd, BOOL fModal, BOOL fMail, FOLDERID folderID, IUnknown *pUnkPump)
  234. {
  235. HRESULT hr;
  236. LPMIMEMESSAGE pMsg=0;
  237. LPSTREAM pstm=0;
  238. INIT_MSGSITE_STRUCT initStruct;
  239. DWORD dwCreateFlags = OENCF_SENDIMMEDIATE;
  240. LPSTR pszCharset;
  241. HCHARSET hCharset;
  242. BOOL fLittleEndian;
  243. ENCODINGTYPE ietEncoding=IET_INETCSET;
  244. if(DialogBoxParam(g_hLocRes, MAKEINTRESOURCE(iddWebPage), hwnd, WebPageDlgProc, (LPARAM)&pstm)==IDCANCEL)
  245. return NOERROR;
  246. hr=HrCreateMessage(&pMsg);
  247. if (FAILED(hr))
  248. goto error;
  249. // [SBAILEY]: Raid 23209: OE: File/Send Web Page sends all pages as Latin-1 even if they aren't
  250. if (S_OK == HrIsStreamUnicode(pstm, &fLittleEndian))
  251. {
  252. if (SUCCEEDED(MimeOleFindCharset("utf-8", &hCharset)))
  253. {
  254. pMsg->SetCharset(hCharset, CSET_APPLY_ALL);
  255. }
  256. ietEncoding = IET_UNICODE;
  257. }
  258. else if (SUCCEEDED(GetHtmlCharset(pstm, &pszCharset)))
  259. {
  260. if (SUCCEEDED(MimeOleFindCharset(pszCharset, &hCharset)))
  261. {
  262. pMsg->SetCharset(hCharset, CSET_APPLY_ALL);
  263. }
  264. MemFree(pszCharset);
  265. }
  266. hr=pMsg->SetTextBody(TXT_HTML, ietEncoding, NULL, pstm, NULL);
  267. if (FAILED(hr))
  268. goto error;
  269. if (fModal)
  270. dwCreateFlags |= OENCF_MODAL;
  271. if (!fMail)
  272. dwCreateFlags |= OENCF_NEWSFIRST;
  273. initStruct.dwInitType = OEMSIT_MSG;
  274. initStruct.pMsg = pMsg;
  275. initStruct.folderID = folderID;
  276. hr = CreateAndShowNote(OENA_WEBPAGE, dwCreateFlags, &initStruct, hwnd, pUnkPump);
  277. error:
  278. ReleaseObj(pMsg);
  279. ReleaseObj(pstm);
  280. return hr;
  281. }
  282. static const HELPMAP g_rgCtxMapWebPage[] = {
  283. {idTxtWebPage, 50210},
  284. {0, 0}
  285. };
  286. INT_PTR CALLBACK WebPageDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  287. {
  288. switch(msg)
  289. {
  290. case WM_INITDIALOG:
  291. {
  292. int iTxtLength;
  293. HWND hwndEdit = GetDlgItem(hwnd, idTxtWebPage);
  294. Assert(hwndEdit);
  295. Assert(lParam!= NULL);
  296. SetWindowLongPtr(hwnd, DWLP_USER, (LPARAM)lParam);
  297. SendDlgItemMessage(hwnd, idTxtWebPage, EM_LIMITTEXT, MAX_PATH-1, NULL);
  298. SetFocus(hwndEdit);
  299. SHAutoComplete(hwndEdit, SHACF_URLALL);
  300. CenterDialog(hwnd);
  301. return FALSE;
  302. }
  303. case WM_HELP:
  304. case WM_CONTEXTMENU:
  305. return OnContextHelp(hwnd, msg, wParam, lParam, g_rgCtxMapWebPage);
  306. case WM_COMMAND:
  307. {
  308. int id = GET_WM_COMMAND_ID(wParam, lParam);
  309. HWND hwndEdit = GetDlgItem(hwnd, idTxtWebPage);
  310. switch(id)
  311. {
  312. case IDOK:
  313. if (FAILED(HrDlgCreateWebPage(hwnd)))
  314. {
  315. AthMessageBoxW(hwnd, MAKEINTRESOURCEW(idsAthenaMail),
  316. MAKEINTRESOURCEW(idsErrSendWebPageUrl), NULL, MB_OK);
  317. SendMessage(hwndEdit, EM_SETSEL, 0, -1);
  318. SetFocus(hwndEdit);
  319. return 0;
  320. }
  321. // fall thro'
  322. case IDCANCEL:
  323. EndDialog(hwnd, id);
  324. break;
  325. }
  326. }
  327. }
  328. return FALSE;
  329. }
  330. static const CHAR c_wszHTTP[] = "http://";
  331. HRESULT HrDlgCreateWebPage(HWND hwndDlg)
  332. {
  333. WCHAR wszUrl[MAX_PATH+1],
  334. wszUrlCanon[MAX_PATH + 10 + 1];
  335. DWORD cCanon = ARRAYSIZE(wszUrlCanon);
  336. LPSTREAM *ppstm = NULL;
  337. HRESULT hr = E_FAIL;
  338. HCURSOR hcur=0;
  339. *wszUrlCanon = 0;
  340. ppstm = (LPSTREAM *)GetWindowLongPtr(hwndDlg, DWLP_USER);
  341. if(!GetWindowTextWrapW(GetDlgItem(hwndDlg, idTxtWebPage), wszUrl, ARRAYSIZE(wszUrl)))
  342. goto exit;
  343. hcur = SetCursor(LoadCursor(NULL, IDC_WAIT));
  344. IF_FAILEXIT(hr = UrlApplySchemeW(wszUrl, wszUrlCanon, &cCanon, URL_APPLY_DEFAULT|URL_APPLY_GUESSSCHEME|URL_APPLY_GUESSFILE));
  345. // If UrlApplyScheme returns S_FALSE, then it thought that the original works just fine, so use original
  346. IF_FAILEXIT(hr = HrCreateBasedWebPage((S_FALSE == hr) ? wszUrl : wszUrlCanon, ppstm));
  347. exit:
  348. if (hcur)
  349. SetCursor(hcur);
  350. return hr;
  351. }
  352. HRESULT HrSaveMessageInFolder(HWND hwnd, IMessageFolder *pfldr, LPMIMEMESSAGE pMsg,
  353. MESSAGEFLAGS dwFlags, MESSAGEID *pNewMsgid, BOOL fSaveChanges)
  354. {
  355. CStoreCB *pCB;
  356. HRESULT hr;
  357. Assert(pfldr != NULL);
  358. pCB = new CStoreCB;
  359. if (pCB == NULL)
  360. return(E_OUTOFMEMORY);
  361. hr = pCB->Initialize(hwnd, MAKEINTRESOURCE(idsSavingToFolder), TRUE);
  362. if (SUCCEEDED(hr))
  363. {
  364. hr = SaveMessageInFolder((IStoreCallback *)pCB, pfldr, pMsg, dwFlags, pNewMsgid, fSaveChanges);
  365. if (hr == E_PENDING)
  366. hr = pCB->Block();
  367. pCB->Close();
  368. }
  369. pCB->Release();
  370. return(hr);
  371. }
  372. HRESULT SaveMessageInFolder(IStoreCallback *pStoreCB, IMessageFolder *pfldr,
  373. LPMIMEMESSAGE pMsg, MESSAGEFLAGS dwFlags, MESSAGEID *pNewMsgid, BOOL fSaveChanges)
  374. {
  375. // Locals
  376. HRESULT hr=S_OK;
  377. HRESULT hrWarnings=S_OK;
  378. MESSAGEID msgid;
  379. // Trace
  380. TraceCall("HrSaveMessageInFolder");
  381. // Invalid Args
  382. if (pMsg == NULL || pfldr == NULL)
  383. return TraceResult(E_INVALIDARG);
  384. // Don't save changes, then clear the dirty bit
  385. if (FALSE == fSaveChanges)
  386. MimeOleClearDirtyTree(pMsg);
  387. // Save the message
  388. IF_FAILEXIT(hr = pMsg->Commit(0));
  389. // Insert the Message
  390. hr = pfldr->SaveMessage(pNewMsgid, SAVE_MESSAGE_GENID, dwFlags, 0, pMsg, pStoreCB);
  391. exit:
  392. // Done
  393. return (hr == S_OK ? hrWarnings : hr);
  394. }
  395. HRESULT SaveMessageInFolder(IStoreCallback *pStoreCB, FOLDERID idFolder, LPMIMEMESSAGE pMsg,
  396. MESSAGEFLAGS dwFlags, MESSAGEID *pNewMsgid)
  397. {
  398. // Locals
  399. HRESULT hr;
  400. IMessageFolder *pfldr=NULL;
  401. // Open the Folder..
  402. hr = g_pStore->OpenFolder(idFolder, NULL, NOFLAGS, &pfldr);
  403. if (SUCCEEDED(hr))
  404. {
  405. hr = SaveMessageInFolder(pStoreCB, pfldr, pMsg, dwFlags, pNewMsgid, TRUE);
  406. pfldr->Release();
  407. }
  408. return hr;
  409. }
  410. HRESULT HrSaveMessageInFolder(HWND hwnd, FOLDERID idFolder, LPMIMEMESSAGE pMsg, MESSAGEFLAGS dwFlags,
  411. MESSAGEID *pNewMsgid)
  412. {
  413. // Locals
  414. HRESULT hr;
  415. IMessageFolder *pfldr=NULL;
  416. // Open the Folder..
  417. hr = g_pStore->OpenFolder(idFolder, NULL, NOFLAGS, &pfldr);
  418. if (SUCCEEDED(hr))
  419. {
  420. hr = HrSaveMessageInFolder(hwnd, pfldr, pMsg, dwFlags, pNewMsgid, TRUE);
  421. pfldr->Release();
  422. }
  423. return hr;
  424. }
  425. HRESULT HrSendMailToOutBox(HWND hwndOwner, LPMIMEMESSAGE pMsg, BOOL fSendImmediate, BOOL fNoUI, BOOL fMail)
  426. {
  427. CStoreCB *pCB;
  428. HRESULT hr;
  429. pCB = new CStoreCB;
  430. if (pCB == NULL)
  431. return(E_OUTOFMEMORY);
  432. hr = pCB->Initialize(hwndOwner, MAKEINTRESOURCE(idsSendingToOutbox), TRUE);
  433. if (SUCCEEDED(hr))
  434. {
  435. hr = SendMailToOutBox((IStoreCallback *)pCB, pMsg, fSendImmediate, fNoUI, fMail);
  436. if (hr == E_PENDING)
  437. hr = pCB->Block();
  438. pCB->Close();
  439. }
  440. pCB->Release();
  441. return(hr);
  442. }
  443. HRESULT SendMailToOutBox(IStoreCallback *pStoreCB, LPMIMEMESSAGE pMsg, BOOL fSendImmediate, BOOL fNoUI, BOOL fMail)
  444. {
  445. HRESULT hr;
  446. FOLDERINFO Outbox;
  447. const TCHAR c_szXMailerAndNewsReader[] = "Microsoft Outlook Express " VER_PRODUCTVERSION_STR;
  448. DWORD dwSendFlags = fMail ? ARF_SUBMITTED|ARF_UNSENT : ARF_SUBMITTED|ARF_UNSENT|ARF_NEWSMSG;
  449. HWND hwnd = 0;
  450. BOOL fSecure = IsSecure(pMsg);
  451. Assert(pStoreCB);
  452. pStoreCB->GetParentWindow(0, &hwnd);
  453. hr = g_pStore->GetSpecialFolderInfo(FOLDERID_LOCAL_STORE, FOLDER_OUTBOX, &Outbox);
  454. if (FAILED(hr))
  455. return hr;
  456. // make sure we never send mail with the X-Unsent header on it.
  457. pMsg->DeleteBodyProp(HBODY_ROOT, PIDTOSTR(PID_HDR_XUNSENT));
  458. if (fMail)
  459. {
  460. // pound the X-Mailer prop always for anyone going' thro' our spooler.
  461. MimeOleSetBodyPropA(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_XMAILER), NOFLAGS, c_szXMailerAndNewsReader);
  462. }
  463. else
  464. {
  465. DWORD dwLines;
  466. TCHAR rgch[12];
  467. HrComputeLineCount(pMsg, &dwLines);
  468. wnsprintf(rgch, ARRAYSIZE(rgch), "%d", dwLines);
  469. MimeOleSetBodyPropA(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_LINES), NOFLAGS, rgch);
  470. MimeOleSetBodyPropA(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_XNEWSRDR), NOFLAGS, c_szXMailerAndNewsReader);
  471. }
  472. hr = SaveMessageInFolder(pStoreCB, Outbox.idFolder, pMsg, dwSendFlags, NULL);
  473. if (FAILED(hr))
  474. goto error;
  475. // if immediate send is required, tell the spooler to pick up next cycle
  476. // or start a cycle...
  477. if (fSendImmediate)
  478. {
  479. Assert(g_pSpooler);
  480. if (fMail)
  481. g_pSpooler->StartDelivery(hwnd, NULL, FOLDERID_INVALID,
  482. DELIVER_BACKGROUND | DELIVER_QUEUE | DELIVER_MAIL_SEND | DELIVER_NOSKIP);
  483. else
  484. {
  485. PROPVARIANT var;
  486. var.vt = VT_LPSTR;
  487. hr = pMsg->GetProp(PIDTOSTR(PID_ATT_ACCOUNTID), NOFLAGS, &var);
  488. if (FAILED(hr))
  489. var.pszVal = NULL;
  490. if (S_OK == g_pConMan->CanConnect(var.pszVal))
  491. g_pSpooler->StartDelivery(hwnd, var.pszVal, FOLDERID_INVALID,
  492. DELIVER_BACKGROUND | DELIVER_NOSKIP | DELIVER_NEWS_SEND);
  493. else
  494. {
  495. // Warn the user that this message is going to live in their
  496. // outbox for all of eternity
  497. DoDontShowMeAgainDlg(hwnd, c_szDSPostInOutbox,
  498. MAKEINTRESOURCE(idsPostNewsMsg),
  499. MAKEINTRESOURCE(idsPostInOutbox),
  500. MB_OK);
  501. hr = S_FALSE;
  502. }
  503. SafeMemFree(var.pszVal);
  504. }
  505. }
  506. else if (!fNoUI)
  507. {
  508. HWND hwnd = 0;
  509. pStoreCB->GetParentWindow(0, &hwnd);
  510. AssertSz(hwnd, "How did we not get an hwnd???");
  511. // warn the user, before we close if it will be stacked in the outbox.
  512. DoDontShowMeAgainDlg(hwnd, fMail?c_szDSSendMail:c_szDSSendNews,
  513. MAKEINTRESOURCE(fMail?idsSendMail:idsPostNews),
  514. MAKEINTRESOURCE(fMail?idsMailInOutbox:idsPostInOutbox),
  515. MB_OK);
  516. }
  517. error:
  518. // Cleanup
  519. g_pStore->FreeRecord(&Outbox);
  520. return hr;
  521. }
  522. HRESULT HrSetSenderInfoUtil(IMimeMessage *pMsg, IImnAccount *pAccount, LPWABAL lpWabal, BOOL fMail, CODEPAGEID cpID, BOOL fCheckConflictOnly)
  523. {
  524. HRESULT hr = S_OK;
  525. // Don't set any info if no account.
  526. if (pAccount)
  527. {
  528. char szEMail[CCHMAX_EMAIL_ADDRESS] = "";
  529. char szName[CCHMAX_DISPLAY_NAME] = "";
  530. char szOrg[CCHMAX_ORG_NAME] = "";
  531. BOOL fUseEmailAsName = FALSE;
  532. DWORD propID;
  533. if (fCheckConflictOnly)
  534. {
  535. hr = S_OK;
  536. propID = fMail ? AP_SMTP_DISPLAY_NAME : AP_NNTP_DISPLAY_NAME;
  537. if (SUCCEEDED(pAccount->GetPropSz(propID, szName, ARRAYSIZE(szName))) && *szName)
  538. {
  539. IF_FAILEXIT(hr = HrSafeToEncodeToCPA(szName, CP_ACP, cpID));
  540. if (MIME_S_CHARSET_CONFLICT == hr)
  541. goto exit;
  542. }
  543. propID = fMail ? AP_SMTP_ORG_NAME : AP_NNTP_ORG_NAME;
  544. if (SUCCEEDED(pAccount->GetPropSz(propID, szOrg, ARRAYSIZE(szOrg))) && *szOrg)
  545. {
  546. IF_FAILEXIT(hr = HrSafeToEncodeToCPA(szOrg, CP_ACP, cpID));
  547. if (MIME_S_CHARSET_CONFLICT == hr)
  548. goto exit;
  549. }
  550. }
  551. else
  552. {
  553. hr = hrNoSender;
  554. lpWabal->DeleteRecipType(MAPI_REPLYTO);
  555. propID = fMail ? AP_SMTP_EMAIL_ADDRESS : AP_NNTP_EMAIL_ADDRESS;
  556. if (SUCCEEDED(pAccount->GetPropSz(propID, szEMail, ARRAYSIZE(szEMail))) && *szEMail)
  557. {
  558. propID = fMail ? AP_SMTP_DISPLAY_NAME : AP_NNTP_DISPLAY_NAME;
  559. // we've got enough to post
  560. if (FAILED(pAccount->GetPropSz(propID, szName, ARRAYSIZE(szName))) && *szName)
  561. fUseEmailAsName = TRUE;
  562. IF_FAILEXIT(hr = lpWabal->HrAddEntryA(fUseEmailAsName?szEMail:szName, szEMail, MAPI_ORIG));
  563. }
  564. propID = fMail ? AP_SMTP_REPLY_EMAIL_ADDRESS : AP_NNTP_REPLY_EMAIL_ADDRESS;
  565. if (SUCCEEDED(pAccount->GetPropSz(propID, szEMail, ARRAYSIZE(szEMail))) && *szEMail)
  566. IF_FAILEXIT(hr = lpWabal->HrAddEntryA((*szName)?szName:szEMail, szEMail, MAPI_REPLYTO));
  567. propID = fMail ? AP_SMTP_ORG_NAME : AP_NNTP_ORG_NAME;
  568. if (SUCCEEDED(pAccount->GetPropSz(propID, szOrg, ARRAYSIZE(szOrg))) && *szOrg)
  569. {
  570. MimeOleSetBodyPropA(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_ORG), NOFLAGS, szOrg);
  571. }
  572. }
  573. }
  574. exit:
  575. return hr;
  576. }
  577. // This function takes an existing refererences line and appends a new
  578. // references to the end removing any references necessary.
  579. // NOTE these SHOULD be char and not TCHAR.
  580. HRESULT HrCreateReferences(LPWSTR pszOrigRefs, LPWSTR pszNewRef,
  581. LPWSTR *ppszRefs)
  582. {
  583. UINT cch,
  584. cchOrig,
  585. cchNew;
  586. // Validate the arguements
  587. if (!pszNewRef || !*pszNewRef)
  588. {
  589. AssertSz(FALSE, TEXT("pszNewRef cannot be empty."));
  590. return (E_INVALIDARG);
  591. }
  592. // Figure out how long the new references line must be
  593. cchNew = lstrlenW(pszNewRef);
  594. // It's possible not to have original references if this is the first
  595. // reply to an article.
  596. if (pszOrigRefs && *pszOrigRefs)
  597. cchOrig = lstrlenW(pszOrigRefs);
  598. else
  599. cchOrig = 0;
  600. cch = cchNew + cchOrig + 1; // extra is for the separator space
  601. if (!MemAlloc((LPVOID*) ppszRefs, (cch + 1)*sizeof(WCHAR)))
  602. return (E_OUTOFMEMORY);
  603. // The line length should be < 1000 chars. If it is, this is simple
  604. if (cch <= 1000)
  605. {
  606. if (pszOrigRefs)
  607. wnsprintfW(*ppszRefs, cch+1, L"%s %s", pszOrigRefs, pszNewRef);
  608. else
  609. StrCpyNW(*ppszRefs, pszNewRef, cch+1);
  610. }
  611. // Since cch > 1000, we have some extra work to do.
  612. // We need to remove some references. The Son-of-1036 recommends to leave
  613. // the first and last three. Unless the IDs are greater than 255, we will
  614. // be able to do at least this. Otherwise, we will dump as many ids as
  615. // needed to get below the 1000 char limit.
  616. // For each ID removed, the Son-of-1036 says that we must add 3 spaces in
  617. // place of the removed ID.
  618. else
  619. {
  620. UINT cchMaxWithoutNewRef, // Max length that the orig size can be
  621. cchNewOrigSize = cchOrig; // Size of orig after deletion. Always shows final size
  622. LPWSTR pszNew = *ppszRefs,
  623. pszOld = pszOrigRefs;
  624. BOOL fCopiedFirstValidID = FALSE;
  625. *pszNew = 0;
  626. // Make sure the new ID is not too long. If it is, discard it.
  627. if (cchNew > 255)
  628. {
  629. cchNew = 0;
  630. cchMaxWithoutNewRef = 1000;
  631. }
  632. else
  633. cchMaxWithoutNewRef = 1000 - cchNew - 1; // the space between
  634. // parse the old string looking for ids
  635. // Son-of-1036 says that we must try to keep the first and the most recent
  636. // three IDs. So we will copy in the first valid ID and then follow a FIFO
  637. // algorithm until we can fit the rest of the IDs into the 1000 char limit
  638. while (pszOld && *pszOld)
  639. {
  640. // Is what is left from the original string too big for the left over buffer?
  641. if (cchNewOrigSize >= cchMaxWithoutNewRef)
  642. {
  643. UINT cchEntryLen = 0; // Size of particular entry ID.
  644. // If this is the first ID, make sure we copy into the buffer as we
  645. // get length, as well, add the additional spaces required when any
  646. // deletion will be happening. Since we only delete directly after
  647. // the first valid ID, add the required 3 spaces now
  648. if (!fCopiedFirstValidID)
  649. {
  650. while (*pszOld && *pszOld != L' ')
  651. {
  652. *pszNew++ = *pszOld++;
  653. cchEntryLen++;
  654. }
  655. *pszNew++ = L' ';
  656. *pszNew++ = L' ';
  657. *pszNew++ = L' ';
  658. cchNewOrigSize += 3;
  659. cchEntryLen += 3;
  660. }
  661. // If this in not the first ID, then just skip over it.
  662. else
  663. {
  664. while (*pszOld && *pszOld != L' ')
  665. {
  666. pszOld++;
  667. cchEntryLen++;
  668. }
  669. }
  670. // Skip over whitespace in old references between IDs that
  671. // we are deleting anyway.
  672. while (*pszOld == L' ')
  673. {
  674. pszOld++;
  675. cchNewOrigSize--;
  676. }
  677. // If we already did the first, or the current one is invalid
  678. // we need to do some fix up with sizes. And in the case that
  679. // we copied one that is not valid, we need to reset the pointer
  680. // as well as reset the size.
  681. if (fCopiedFirstValidID || (cchEntryLen > 255))
  682. {
  683. cchNewOrigSize -= cchEntryLen;
  684. // Did we copy an invalid ID?
  685. if (!fCopiedFirstValidID)
  686. pszNew -= cchEntryLen;
  687. }
  688. // If we haven't copied the first one in yet and this
  689. // ID is valid, then remember that we have at this
  690. // point copied the first valid ID.
  691. if (!fCopiedFirstValidID && (cchEntryLen <= 255))
  692. fCopiedFirstValidID = TRUE;
  693. }
  694. else
  695. {
  696. // Since we now have a orig string that will fit in the max allowed,
  697. // just rip through the rest of the orig string and copy.
  698. while (*pszOld)
  699. *pszNew++ = *pszOld++;
  700. }
  701. }
  702. // At this point, pszNew should be pointing the the char directly after
  703. // the last digit. If we add a new reference, then we need to add a space.
  704. // If we don't add a new reference, then we need to null terminate the string.
  705. if (cchNew)
  706. {
  707. // With this assignment, we can end up with 4 spaces in a row if we
  708. // deleted all references after the first valid one was copied. The
  709. // son-of-1036 only specifies minimum of 3 spaces when deleting, so
  710. // we will be OK with that, especially since the only way to get into
  711. // this situation is by forcing the references line into a strange state.
  712. *pszNew++ = L' ';
  713. pszOld = pszNewRef;
  714. while (*pszOld)
  715. *pszNew++ = *pszOld++;
  716. }
  717. // NULL terminate the string of references.
  718. *pszNew = 0;
  719. }
  720. return S_OK;
  721. }