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.

2864 lines
85 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. faxdoc.cpp
  5. Abstract:
  6. This module contains all code necessary to print an
  7. exchange message as a fax document.
  8. Author:
  9. Wesley Witt (wesw) 13-Aug-1996
  10. Revision History:
  11. 20/10/99 -danl-
  12. Connect to appropriate server, get basenote from windir
  13. dd/mm/yy -author-
  14. description
  15. --*/
  16. #include "faxxp.h"
  17. #include "emsabtag.h"
  18. #include "mapiutil.h"
  19. #include "debugex.h"
  20. #include <set>
  21. using namespace std;
  22. #pragma hdrstop
  23. struct CRecipCmp
  24. {
  25. /*
  26. Comparison operator 'less'
  27. Compare two FAX_PERSONAL_PROFILEs by recipient's name and fax number
  28. */
  29. bool operator()(LPCFAX_PERSONAL_PROFILE lpcRecipient1,
  30. LPCFAX_PERSONAL_PROFILE lpcRecipient2) const
  31. {
  32. bool bRes = false;
  33. int nFaxNumberCpm = 0;
  34. if(!lpcRecipient1 ||
  35. !lpcRecipient2 ||
  36. !lpcRecipient1->lptstrFaxNumber ||
  37. !lpcRecipient2->lptstrFaxNumber)
  38. {
  39. Assert(false);
  40. return bRes;
  41. }
  42. nFaxNumberCpm = _tcscmp(lpcRecipient1->lptstrFaxNumber, lpcRecipient2->lptstrFaxNumber);
  43. if(nFaxNumberCpm < 0)
  44. {
  45. bRes = true;
  46. }
  47. else if(nFaxNumberCpm == 0)
  48. {
  49. //
  50. // The fax numbers are same
  51. // lets compare the names
  52. //
  53. if(lpcRecipient1->lptstrName && lpcRecipient2->lptstrName)
  54. {
  55. bRes = (_tcsicmp(lpcRecipient1->lptstrName, lpcRecipient2->lptstrName) < 0);
  56. }
  57. else
  58. {
  59. bRes = (lpcRecipient1->lptstrName < lpcRecipient2->lptstrName);
  60. }
  61. }
  62. return bRes;
  63. }
  64. };
  65. typedef set<LPCFAX_PERSONAL_PROFILE, CRecipCmp> RECIPIENTS_SET;
  66. // prototypes
  67. LPTSTR ConvertAStringToTString(LPCSTR lpcstrSource);
  68. extern "C"
  69. BOOL MergeTiffFiles(
  70. LPTSTR BaseTiffFile,
  71. LPTSTR NewTiffFile
  72. );
  73. extern "C"
  74. BOOL PrintRandomDocument(
  75. LPCTSTR FaxPrinterName,
  76. LPCTSTR DocName,
  77. LPTSTR OutputFile
  78. );
  79. PVOID
  80. CXPLogon::MyGetPrinter(
  81. LPTSTR PrinterName,
  82. DWORD Level
  83. )
  84. /*++
  85. Routine Description:
  86. Gets the printer data for a specific printer
  87. Arguments:
  88. PrinterName - Name of the desired printer
  89. Return Value:
  90. Pointer to a printer info structure or NULL for failure.
  91. --*/
  92. {
  93. DBG_ENTER(TEXT("CXPLogon::MyGetPrinter"));
  94. PVOID PrinterInfo = NULL;
  95. HANDLE hPrinter = NULL;
  96. DWORD Bytes;
  97. PRINTER_DEFAULTS PrinterDefaults;
  98. PrinterDefaults.pDatatype = NULL;
  99. PrinterDefaults.pDevMode = NULL;
  100. PrinterDefaults.DesiredAccess = PRINTER_ACCESS_USE;
  101. if (!OpenPrinter( PrinterName, &hPrinter, &PrinterDefaults ))
  102. {
  103. CALL_FAIL (GENERAL_ERR, TEXT("OpenPrinter"),::GetLastError());
  104. goto exit;
  105. }
  106. if ((!GetPrinter( hPrinter, Level, NULL, 0, &Bytes )) && (::GetLastError() != ERROR_INSUFFICIENT_BUFFER))
  107. {
  108. // we just want to know how much memory we need, so we pass NULL and 0,
  109. // this way, the function will fail, but will return us the number of
  110. // bytes required in Bytes
  111. CALL_FAIL (GENERAL_ERR, TEXT("GetPrinter"), ::GetLastError());
  112. goto exit;
  113. }
  114. PrinterInfo = (LPPRINTER_INFO_2) MemAlloc( Bytes );
  115. if (!PrinterInfo)
  116. {
  117. goto exit;
  118. }
  119. if (!GetPrinter( hPrinter, Level, (LPBYTE) PrinterInfo, Bytes, &Bytes ))
  120. {
  121. MemFree(PrinterInfo);
  122. PrinterInfo = NULL;
  123. goto exit;
  124. }
  125. exit:
  126. if(hPrinter)
  127. {
  128. ClosePrinter( hPrinter );
  129. }
  130. return PrinterInfo;
  131. }
  132. static BOOL
  133. GetFaxTempFileName(
  134. OUT LPTSTR lpstrTempName,
  135. IN DWORD dwOutStrSize
  136. )
  137. /*++
  138. Routine Description:
  139. Generates a temporal file with prefix 'fax' in directory
  140. designated for temporal files.
  141. Arguments:
  142. [OUT] lpstrTempName - Output paramter. Pointer to the temporal file name.
  143. The buffer should be MAX_PATH characters.
  144. [IN] dwOutStrSize - Size of buffer lpstrTempName in TCHARs
  145. Return Value:
  146. TRUE if success, FALSE otherwise
  147. --*/
  148. {
  149. BOOL bRes = TRUE;
  150. DBG_ENTER(TEXT("GetFaxTempFileName"),bRes);
  151. TCHAR strTempPath[MAX_PATH] = {0};
  152. TCHAR strTempFile[MAX_PATH] = {0};
  153. DWORD ec = ERROR_SUCCESS; // LastError for this function.
  154. Assert(lpstrTempName);
  155. if (!GetTempPath( sizeof(strTempPath)/sizeof(TCHAR), strTempPath ))
  156. {
  157. ec=::GetLastError();
  158. goto Exit;
  159. }
  160. if (GetTempFileName( strTempPath, _T("fax"), 0, strTempFile ) == 0)
  161. {
  162. ec=::GetLastError();
  163. goto Exit;
  164. }
  165. //
  166. //Copy the source string and leave space for the NULL char
  167. //
  168. _tcsncpy(lpstrTempName, strTempFile, dwOutStrSize-1);
  169. Exit:
  170. if (ERROR_SUCCESS != ec)
  171. {
  172. SetLastError(ec);
  173. bRes = FALSE;
  174. }
  175. return bRes;
  176. }
  177. BOOL
  178. CXPLogon::PrintRichText(
  179. HWND hWndRichEdit,
  180. HDC hDC
  181. )
  182. /*++
  183. Routine Description:
  184. Prints the rich text contained in a rich text
  185. window into a DC.
  186. Arguments:
  187. hWndRichEdit - Window handle for the rich text window
  188. hDC - Printer device context
  189. Return Value:
  190. None.
  191. --*/
  192. {
  193. BOOL bRet = FALSE;
  194. DBG_ENTER(TEXT("CXPLogon::PrintRichText"), bRet);
  195. FORMATRANGE fr;
  196. LONG lTextOut;
  197. LONG lTextCurr;
  198. RECT rcTmp;
  199. fr.hdc = hDC;
  200. fr.hdcTarget = hDC;
  201. fr.chrg.cpMin = 0;
  202. fr.chrg.cpMax = -1;
  203. //
  204. // Set page rect to phys page size in twips
  205. //
  206. fr.rcPage.top = 0;
  207. fr.rcPage.left = 0;
  208. fr.rcPage.right = MulDiv(GetDeviceCaps(hDC, PHYSICALWIDTH),
  209. 1440,
  210. GetDeviceCaps(hDC, LOGPIXELSX));
  211. fr.rcPage.bottom = MulDiv(GetDeviceCaps(hDC, PHYSICALHEIGHT),
  212. 1440,
  213. GetDeviceCaps(hDC, LOGPIXELSY));
  214. //
  215. // Set up 3/4" horizontal and 1" vertical margins, but leave a minimum of 1"
  216. // printable space in each direction. Otherwise, use full page.
  217. //
  218. fr.rc = fr.rcPage; // start with full page
  219. if (fr.rcPage.right > 2*3*1440/4 + 1440)
  220. {
  221. fr.rc.right -= (fr.rc.left = 3*1440/4);
  222. }
  223. if (fr.rcPage.bottom > 3*1440)
  224. {
  225. fr.rc.bottom -= (fr.rc.top = 1440);
  226. }
  227. //
  228. // save the formatting rectangle
  229. //
  230. rcTmp = fr.rc;
  231. if (!SetMapMode( hDC, MM_TEXT ))
  232. {
  233. CALL_FAIL (GENERAL_ERR, TEXT("SetMapMode"), ::GetLastError());
  234. goto error;
  235. }
  236. lTextOut = 0;
  237. lTextCurr = 0;
  238. while (TRUE)
  239. {
  240. //
  241. // Just measure the text
  242. //
  243. lTextOut = (LONG)SendMessage( hWndRichEdit, EM_FORMATRANGE, FALSE, (LPARAM) &fr );
  244. if(lTextOut <= lTextCurr)
  245. {
  246. //
  247. // The end of the text
  248. //
  249. break;
  250. }
  251. lTextCurr = lTextOut;
  252. if (StartPage( hDC ) <= 0)
  253. {
  254. CALL_FAIL (GENERAL_ERR, TEXT("StartPage"), ::GetLastError());
  255. goto error;
  256. }
  257. //
  258. // Render the page
  259. //
  260. lTextOut = (LONG)SendMessage( hWndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM) &fr );
  261. if (EndPage( hDC ) <= 0)
  262. {
  263. CALL_FAIL (GENERAL_ERR, TEXT("EndPage"), ::GetLastError());
  264. goto error;
  265. }
  266. fr.chrg.cpMin = lTextOut;
  267. fr.chrg.cpMax = -1;
  268. //
  269. // EM_FORMATRANGE tends to modify fr.rc.bottom, reset here
  270. //
  271. fr.rc = rcTmp;
  272. }
  273. bRet = TRUE;
  274. error:
  275. //
  276. // flush the cache
  277. //
  278. SendMessage( hWndRichEdit, EM_FORMATRANGE, TRUE, (LPARAM) NULL );
  279. return bRet;
  280. }
  281. DWORD
  282. CXPLogon::PrintPlainText(
  283. HDC hDC,
  284. LPSTREAM lpstmT,
  285. LPTSTR tszSubject,
  286. PFAXXP_CONFIG FaxConfig
  287. )
  288. /*++
  289. Routine Description:
  290. Prints a stream of plain text into the printer DC provided.
  291. Note: this code was stolen from notepad.
  292. Arguments:
  293. hDC - Printer DC
  294. lpstmT - Stream pointer for rich text.
  295. tszSubject - Subject
  296. FaxConfig - Fax configuration data
  297. Return Value:
  298. ERROR_SUCCESS - if success
  299. Error IDS_... code if failed.
  300. --*/
  301. {
  302. DWORD rVal = ERROR_SUCCESS;
  303. LPTSTR BodyText = NULL;
  304. LPTSTR lpLine;
  305. LPTSTR pLineEOL;
  306. LPTSTR pNextLine;
  307. HRESULT hResult;
  308. HFONT hFont = NULL;
  309. HFONT hPrevFont = NULL;
  310. TEXTMETRIC tm;
  311. INT nLinesPerPage;
  312. INT dyTop; // width of top border (pixels)
  313. INT dyBottom; // width of bottom border
  314. INT dxLeft; // width of left border
  315. INT dxRight; // width of right border
  316. INT yPrintChar; // height of a character
  317. INT tabSize; // Size of a tab for print device in device units
  318. INT yCurpos = 0;
  319. INT xCurpos = 0;
  320. INT nPixelsLeft = 0;
  321. INT guess = 0;
  322. SIZE Size; // to see if text will fit in space left
  323. INT nPrintedLines = 0;
  324. BOOL fPageStarted = FALSE;
  325. INT iPageNum = 0;
  326. INT xPrintRes; // printer resolution in x direction
  327. INT yPrintRes; // printer resolution in y direction
  328. INT yPixInch; // pixels/inch
  329. INT xPixInch; // pixels/inch
  330. INT xPixUnit; // pixels/local measurement unit
  331. INT yPixUnit; // pixels/local measurement unit
  332. BOOL fEnglish;
  333. DWORD Chars=0;
  334. DWORD dwBodyLen=0;
  335. DWORD dwSubjectLen=0;
  336. STATSTG Stats;
  337. INT PrevBkMode = 0;
  338. DBG_ENTER(TEXT("CXPLogon::PrintPlainText"),rVal);
  339. Assert(hDC);
  340. Assert(FaxConfig);
  341. if(lpstmT)
  342. {
  343. hResult = lpstmT->Stat( &Stats, 0 );
  344. if (FAILED(hResult))
  345. {
  346. rVal = IDS_CANT_ACCESS_MSG_DATA;
  347. goto exit;
  348. }
  349. dwBodyLen = (INT) Stats.cbSize.QuadPart;
  350. }
  351. if(tszSubject)
  352. {
  353. dwSubjectLen = _tcslen(tszSubject);
  354. }
  355. BodyText = (LPTSTR) MemAlloc(dwSubjectLen * sizeof(TCHAR) + dwBodyLen + 4 );
  356. if (!BodyText)
  357. {
  358. rVal = IDS_OUT_OF_MEM;
  359. goto exit;
  360. }
  361. if(tszSubject)
  362. {
  363. _tcscpy(BodyText, tszSubject);
  364. lpLine = _tcsninc(BodyText, dwSubjectLen);
  365. }
  366. else
  367. {
  368. lpLine = BodyText;
  369. }
  370. if(lpstmT)
  371. {
  372. hResult = lpstmT->Read( (LPVOID)lpLine, dwBodyLen, (LPDWORD) &dwBodyLen );
  373. if (FAILED(hResult))
  374. {
  375. rVal = IDS_CANT_ACCESS_MSG_DATA;
  376. goto exit;
  377. }
  378. }
  379. lpLine = BodyText;
  380. Chars = _tcslen(lpLine);
  381. //
  382. // check if the body is not empty
  383. // if the message length is shorter then 32(arbitrary number)
  384. // and all the carachters are control or space.
  385. //
  386. if(Chars < 32)
  387. {
  388. BOOL bEmpty = TRUE;
  389. TCHAR* pTchar = lpLine;
  390. for(DWORD dw = 0; dw < Chars; ++dw)
  391. {
  392. if(!_istspace(*pTchar) && !_istcntrl(*pTchar))
  393. {
  394. bEmpty = FALSE;
  395. break;
  396. }
  397. pTchar = _tcsinc(pTchar);
  398. }
  399. if(bEmpty)
  400. {
  401. rVal = IDS_NO_MSG_BODY;
  402. goto exit;
  403. }
  404. }
  405. fEnglish = GetProfileInt( _T("intl"), _T("iMeasure"), 1 );
  406. xPrintRes = GetDeviceCaps( hDC, HORZRES );
  407. yPrintRes = GetDeviceCaps( hDC, VERTRES );
  408. xPixInch = GetDeviceCaps( hDC, LOGPIXELSX );
  409. yPixInch = GetDeviceCaps( hDC, LOGPIXELSY );
  410. //
  411. // compute x and y pixels per local measurement unit
  412. //
  413. if (fEnglish)
  414. {
  415. xPixUnit= xPixInch;
  416. yPixUnit= yPixInch;
  417. }
  418. else
  419. {
  420. xPixUnit= CMToInches( xPixInch );
  421. yPixUnit= CMToInches( yPixInch );
  422. }
  423. SetMapMode( hDC, MM_TEXT );
  424. //
  425. // match font size to the device point size
  426. //
  427. FaxConfig->FontStruct.lfHeight = -MulDiv(FaxConfig->FontStruct.lfHeight, yPixInch, 72);
  428. hFont = CreateFontIndirect( &FaxConfig->FontStruct );
  429. hPrevFont = (HFONT) SelectObject( hDC, hFont );
  430. SetBkMode( hDC, TRANSPARENT );
  431. if (!GetTextMetrics( hDC, &tm ))
  432. {
  433. rVal = IDS_CANT_PRINT_BODY;
  434. goto exit;
  435. }
  436. yPrintChar = tm.tmHeight + tm.tmExternalLeading;
  437. tabSize = tm.tmAveCharWidth * 8;
  438. //
  439. // compute margins in pixels
  440. //
  441. dxLeft = LEFT_MARGIN * xPixUnit;
  442. dxRight = RIGHT_MARGIN * xPixUnit;
  443. dyTop = TOP_MARGIN * yPixUnit;
  444. dyBottom = BOTTOM_MARGIN * yPixUnit;
  445. //
  446. // Number of lines on a page with margins
  447. //
  448. nLinesPerPage = ((yPrintRes - dyTop - dyBottom) / yPrintChar);
  449. while (*lpLine)
  450. {
  451. if ( _tcsncmp(lpLine,TEXT("\r"),1) == 0 )
  452. {
  453. lpLine = _tcsninc(lpLine,2);
  454. yCurpos += yPrintChar;
  455. nPrintedLines++;
  456. xCurpos= 0;
  457. continue;
  458. }
  459. pLineEOL = lpLine;
  460. pLineEOL = _tcschr(pLineEOL,TEXT('\r'));
  461. do
  462. {
  463. if ((nPrintedLines == 0) && (!fPageStarted))
  464. {
  465. StartPage( hDC );
  466. fPageStarted = TRUE;
  467. yCurpos = 0;
  468. xCurpos = 0;
  469. }
  470. if ( _tcsncmp(lpLine,TEXT("\t"),1) == 0 )
  471. {
  472. //
  473. // round up to the next tab stop
  474. // if the current position is on the tabstop, goto next one
  475. //
  476. xCurpos = ((xCurpos + tabSize) / tabSize ) * tabSize;
  477. lpLine = _tcsinc(lpLine);
  478. }
  479. else
  480. {
  481. //
  482. // find end of line or tab
  483. //
  484. pNextLine = lpLine;
  485. while (*pNextLine &&
  486. (pNextLine != pLineEOL) &&
  487. ( _tcsncmp(pNextLine,TEXT("\t"),1) ) )
  488. {
  489. pNextLine = _tcsinc(pNextLine);
  490. }
  491. //
  492. // find out how many characters will fit on line
  493. //
  494. Chars = (INT)(pNextLine - lpLine);
  495. nPixelsLeft = xPrintRes - dxRight - dxLeft - xCurpos;
  496. GetTextExtentExPoint( hDC, lpLine, Chars, nPixelsLeft, &guess, NULL, &Size );
  497. if (guess)
  498. {
  499. //
  500. // at least one character fits - print
  501. //
  502. TextOut( hDC, dxLeft+xCurpos, yCurpos+dyTop, lpLine, guess );
  503. xCurpos += Size.cx; // account for printing
  504. lpLine = _tcsninc(lpLine,guess);// printed characters
  505. }
  506. else
  507. {
  508. //
  509. // no characters fit what's left
  510. // no characters will fit in space left
  511. // if none ever will, just print one
  512. // character to keep progressing through
  513. // input file.
  514. //
  515. if (xCurpos == 0)
  516. {
  517. if( lpLine != pNextLine )
  518. {
  519. //
  520. // print something if not null line
  521. // could use exttextout here to clip
  522. //
  523. TextOut( hDC, dxLeft+xCurpos, yCurpos+dyTop, lpLine, 1 );
  524. lpLine = _tcsinc(lpLine);
  525. }
  526. }
  527. else
  528. {
  529. //
  530. // perhaps the next line will get it
  531. //
  532. xCurpos = xPrintRes; // force to next line
  533. }
  534. }
  535. //
  536. // move printhead in y-direction
  537. //
  538. if ((xCurpos >= (xPrintRes - dxRight - dxLeft) ) || (lpLine == pLineEOL))
  539. {
  540. yCurpos += yPrintChar;
  541. nPrintedLines++;
  542. xCurpos = 0;
  543. }
  544. if (nPrintedLines >= nLinesPerPage)
  545. {
  546. EndPage( hDC );
  547. fPageStarted = FALSE;
  548. nPrintedLines = 0;
  549. xCurpos = 0;
  550. yCurpos = 0;
  551. iPageNum++;
  552. }
  553. }
  554. } while (*lpLine && (lpLine != pLineEOL));
  555. if ( _tcsncmp(lpLine,TEXT("\r"),1) == 0 )
  556. {
  557. lpLine = _tcsinc(lpLine);
  558. }
  559. if ( _tcsncmp(lpLine,TEXT("\n"),1) == 0 )
  560. {
  561. lpLine = _tcsinc(lpLine);
  562. }
  563. }
  564. if (fPageStarted)
  565. {
  566. EndPage( hDC );
  567. }
  568. exit:
  569. MemFree( BodyText );
  570. if (hPrevFont)
  571. {
  572. SelectObject( hDC, hPrevFont );
  573. DeleteObject( hFont );
  574. }
  575. if (PrevBkMode)
  576. {
  577. SetBkMode( hDC, PrevBkMode );
  578. }
  579. return rVal;
  580. }
  581. extern "C"
  582. DWORD CALLBACK
  583. EditStreamRead(
  584. DWORD_PTR dwCookie,
  585. OUT LPBYTE pbBuff,
  586. LONG cb,
  587. LONG *pcb
  588. )
  589. /*++
  590. Routine Description:
  591. Wrapper function for the IStream read method.
  592. This function is used to read rich text from
  593. an exchange stream.
  594. Arguments:
  595. dwCookie - This pointer for the IStream object
  596. pbBuff - Pointer to the data buffer
  597. cb - Size of the data buffer
  598. pcb - Returned byte count
  599. Return Value:
  600. Return code from IStream::Read
  601. --*/
  602. {
  603. return ((LPSTREAM)dwCookie)->Read( pbBuff, cb, (ULONG*) pcb );
  604. }
  605. DWORD
  606. CXPLogon::PrintAttachmentToFile(
  607. IN LPMESSAGE pMsgObj,
  608. IN PFAXXP_CONFIG pFaxConfig,
  609. OUT LPTSTR * lpptstrOutAttachments
  610. )
  611. /*++
  612. Routine Description:
  613. Prints all attachments to the output file, by itearating
  614. over the attachment table
  615. Arguments:
  616. pMsgObj - Pointer to message object. Used to get an attachmnet table
  617. pFaxConfig - Pointer to fax configuration
  618. lpptstrOutAttachments - Name of the output tiff file. The string should be empty
  619. Return Value:
  620. 0 - if success
  621. Last error code from if failed.
  622. Comments:
  623. If this function succeeded it allocates a memory for *lpptstrOutAttachments
  624. and creates a temporal file *lpptstrOutAttachments.
  625. It's up to user to free both these allocations, by
  626. DeleteFile(*lpptstrOutAttachments);
  627. MemFree(*lpptstrOutAttachments);
  628. --*/
  629. {
  630. DWORD rVal = 0;
  631. DBG_ENTER(TEXT("CXPLogon::PrintAttachmentToFile"),rVal);
  632. LPSPropValue pPropsAttachTable = NULL;
  633. LPSPropValue pPropsAttach = NULL;
  634. LPMAPITABLE AttachmentTable = NULL;
  635. LPSRowSet pAttachmentRows = NULL;
  636. LPATTACH lpAttach = NULL;
  637. LPSTREAM lpstmA = NULL;
  638. LPTSTR AttachFileName = NULL;
  639. TCHAR TempPath[MAX_PATH];
  640. TCHAR TempFile[MAX_PATH];
  641. TCHAR DocFile[MAX_PATH];
  642. HANDLE hFile = INVALID_HANDLE_VALUE;
  643. LPTSTR DocType = NULL;
  644. LPSTR p = NULL;
  645. BOOL DeleteAttachFile = FALSE;
  646. LPTSTR FileName = NULL;
  647. BOOL AllAttachmentsGood = TRUE;
  648. TCHAR strTempTiffFile[MAX_PATH] = {0};
  649. TCHAR strMergedTiffFile[MAX_PATH] = {0};
  650. HRESULT hResult = S_OK;
  651. DWORD i = 0;
  652. ULONG PropCount = 0;
  653. DWORD Bytes;
  654. LPTSTR lptstrTempStr = NULL;
  655. Assert(lpptstrOutAttachments);
  656. Assert(*lpptstrOutAttachments == NULL);
  657. //
  658. // get the attachment table, if it is available
  659. //
  660. hResult = pMsgObj->GetAttachmentTable( 0, &AttachmentTable );
  661. if (HR_SUCCEEDED(hResult))
  662. {
  663. hResult = HrAddColumns(
  664. AttachmentTable,
  665. (LPSPropTagArray) &sptAttachTableProps,
  666. gpfnAllocateBuffer,
  667. gpfnFreeBuffer
  668. );
  669. if (HR_SUCCEEDED(hResult))
  670. {
  671. hResult = HrQueryAllRows(
  672. AttachmentTable,
  673. NULL,
  674. NULL,
  675. NULL,
  676. 0,
  677. &pAttachmentRows
  678. );
  679. if (FAILED(hResult))
  680. {
  681. pAttachmentRows = NULL;
  682. }
  683. else
  684. {
  685. if (pAttachmentRows->cRows == 0)
  686. {
  687. FreeProws( pAttachmentRows );
  688. pAttachmentRows = NULL;
  689. }
  690. }
  691. }
  692. }
  693. if (pAttachmentRows)
  694. {
  695. //
  696. // this loop verifies that each document's attachment registration
  697. // supports the printto verb.
  698. //
  699. AllAttachmentsGood = TRUE;
  700. for (i = 0; i < pAttachmentRows->cRows; ++i)
  701. {
  702. pPropsAttachTable = pAttachmentRows->aRow[i].lpProps;
  703. lpAttach = NULL;
  704. pPropsAttach = NULL;
  705. if (pPropsAttachTable[MSG_ATTACH_METHOD].Value.ul == NO_ATTACHMENT)
  706. {
  707. goto next_attachment1;
  708. }
  709. //
  710. // open the attachment
  711. //
  712. hResult = pMsgObj->OpenAttach( pPropsAttachTable[MSG_ATTACH_NUM].Value.ul, NULL, MAPI_BEST_ACCESS, &lpAttach );
  713. if (FAILED(hResult))
  714. {
  715. AllAttachmentsGood = FALSE;
  716. goto next_attachment1;
  717. }
  718. //
  719. // get the attachment properties
  720. //
  721. hResult = lpAttach->GetProps(
  722. (LPSPropTagArray) &sptAttachProps,
  723. 0,
  724. &PropCount,
  725. &pPropsAttach
  726. );
  727. if (FAILED(hResult))
  728. {
  729. AllAttachmentsGood = FALSE;
  730. goto next_attachment1;
  731. }
  732. //
  733. // try to get the extension if the file.
  734. // this indicates what type of dicument it is.
  735. // if we cannot get the document type then it is
  736. // impossible to print the document.
  737. //
  738. if (DocType)
  739. {
  740. MemFree( DocType );
  741. DocType = NULL;
  742. }
  743. if (PROP_TYPE(pPropsAttach[MSG_ATTACH_EXTENSION].ulPropTag) == PT_ERROR)
  744. {
  745. if (PROP_TYPE(pPropsAttach[MSG_ATTACH_LFILENAME].ulPropTag) != PT_ERROR)
  746. {
  747. p = strrchr( pPropsAttach[MSG_ATTACH_LFILENAME].Value.lpszA, '.' );
  748. if (p)
  749. {
  750. DocType = ConvertAStringToTString( p );
  751. if(!DocType)
  752. {
  753. rVal = IDS_OUT_OF_MEM;
  754. goto exit;
  755. }
  756. }
  757. }
  758. else if (PROP_TYPE(pPropsAttach[MSG_ATTACH_FILENAME].ulPropTag) != PT_ERROR)
  759. {
  760. p = strrchr( pPropsAttach[MSG_ATTACH_FILENAME].Value.lpszA, '.' );
  761. if (p)
  762. {
  763. DocType = ConvertAStringToTString( p );
  764. if(!DocType)
  765. {
  766. rVal = IDS_OUT_OF_MEM;
  767. goto exit;
  768. }
  769. }
  770. }
  771. }
  772. else
  773. {
  774. DocType = ConvertAStringToTString( pPropsAttach[MSG_ATTACH_EXTENSION].Value.lpszA );
  775. if(!DocType)
  776. {
  777. rVal = IDS_OUT_OF_MEM;
  778. goto exit;
  779. }
  780. }
  781. if (!DocType)
  782. {
  783. AllAttachmentsGood = FALSE;
  784. goto next_attachment1;
  785. }
  786. Bytes = sizeof(TempFile);
  787. rVal = RegQueryValue( HKEY_CLASSES_ROOT, DocType, TempFile, (PLONG) &Bytes );
  788. if ((rVal != ERROR_SUCCESS) && (rVal != ERROR_INVALID_DATA))
  789. {
  790. VERBOSE (DBG_MSG, TEXT("File Type: %s: isn't associated to any application"), DocType);
  791. AllAttachmentsGood = FALSE;
  792. goto next_attachment1;
  793. }
  794. wsprintf( TempPath, _T("%s\\shell\\printto\\command"), TempFile );
  795. Bytes = sizeof(TempFile);
  796. rVal = RegQueryValue( HKEY_CLASSES_ROOT, TempPath, TempFile, (PLONG) &Bytes );
  797. if ((rVal != ERROR_SUCCESS) && (rVal != ERROR_INVALID_DATA))
  798. {
  799. VERBOSE (DBG_MSG, TEXT("File extension \"*%s\" doesn't have the PrintTo verb"), DocType);
  800. AllAttachmentsGood = FALSE;
  801. goto next_attachment1;
  802. }
  803. next_attachment1:
  804. if (lpAttach)
  805. {
  806. lpAttach->Release();
  807. }
  808. if (pPropsAttach)
  809. {
  810. MAPIFreeBuffer( pPropsAttach );
  811. pPropsAttach = NULL;
  812. }
  813. }
  814. if (!AllAttachmentsGood)
  815. {
  816. rVal = IDS_BAD_ATTACHMENTS;
  817. goto exit;
  818. }
  819. for (i = 0; i < pAttachmentRows->cRows; ++i)
  820. {
  821. pPropsAttachTable = pAttachmentRows->aRow[i].lpProps;
  822. lpAttach = NULL;
  823. pPropsAttach = NULL;
  824. if (pPropsAttachTable[MSG_ATTACH_METHOD].Value.ul == NO_ATTACHMENT)
  825. {
  826. goto next_attachment2;
  827. }
  828. //
  829. // open the attachment
  830. //
  831. hResult = pMsgObj->OpenAttach( pPropsAttachTable[MSG_ATTACH_NUM].Value.ul, NULL, MAPI_BEST_ACCESS, &lpAttach );
  832. if (FAILED(hResult))
  833. {
  834. goto next_attachment2;
  835. }
  836. //
  837. // get the attachment properties
  838. //
  839. hResult = lpAttach->GetProps(
  840. (LPSPropTagArray) &sptAttachProps,
  841. 0,
  842. &PropCount,
  843. &pPropsAttach
  844. );
  845. if (FAILED(hResult))
  846. {
  847. goto next_attachment2;
  848. }
  849. //
  850. // try to get the extension if the file.
  851. // this indicates what type of dicument it is.
  852. // if we cannot get the document type then it is
  853. // impossible to print the document.
  854. //
  855. if (DocType)
  856. {
  857. MemFree( DocType );
  858. DocType = NULL;
  859. }
  860. if (PROP_TYPE(pPropsAttach[MSG_ATTACH_EXTENSION].ulPropTag) == PT_ERROR)
  861. {
  862. if (PROP_TYPE(pPropsAttach[MSG_ATTACH_LFILENAME].ulPropTag) != PT_ERROR)
  863. {
  864. p = strrchr( pPropsAttach[MSG_ATTACH_LFILENAME].Value.lpszA, '.' );
  865. if (p)
  866. {
  867. DocType = ConvertAStringToTString( p );
  868. if(!DocType)
  869. {
  870. rVal = IDS_OUT_OF_MEM;
  871. goto exit;
  872. }
  873. }
  874. }
  875. else if (PROP_TYPE(pPropsAttach[MSG_ATTACH_FILENAME].ulPropTag) != PT_ERROR)
  876. {
  877. p = strrchr( pPropsAttach[MSG_ATTACH_FILENAME].Value.lpszA, '.' );
  878. if (p)
  879. {
  880. DocType = ConvertAStringToTString( p );
  881. if(!DocType)
  882. {
  883. rVal = IDS_OUT_OF_MEM;
  884. goto exit;
  885. }
  886. }
  887. }
  888. }
  889. else
  890. {
  891. DocType = ConvertAStringToTString( pPropsAttach[MSG_ATTACH_EXTENSION].Value.lpszA );
  892. if(!DocType)
  893. {
  894. rVal = IDS_OUT_OF_MEM;
  895. goto exit;
  896. }
  897. }
  898. if (!DocType)
  899. {
  900. goto next_attachment2;
  901. }
  902. lpstmA = NULL;
  903. AttachFileName = NULL;
  904. DeleteAttachFile = FALSE;
  905. //
  906. // get the attached file name
  907. //
  908. if (FileName)
  909. MemFree(FileName);
  910. if (PROP_TYPE(pPropsAttach[MSG_ATTACH_PATHNAME].ulPropTag) != PT_ERROR)
  911. {
  912. FileName = ConvertAStringToTString(pPropsAttach[MSG_ATTACH_PATHNAME].Value.lpszA);
  913. if(!FileName)
  914. {
  915. rVal = IDS_OUT_OF_MEM;
  916. goto exit;
  917. }
  918. }
  919. else
  920. {
  921. FileName = NULL;
  922. }
  923. if (FileName)
  924. {
  925. AttachFileName = StringDup( FileName );
  926. if(!AttachFileName)
  927. {
  928. rVal = IDS_OUT_OF_MEM;
  929. goto exit;
  930. }
  931. }
  932. //
  933. // get the stream object
  934. //
  935. switch( pPropsAttach[MSG_ATTACH_METHOD].Value.ul )
  936. {
  937. case ATTACH_BY_VALUE:
  938. hResult = lpAttach->OpenProperty(
  939. PR_ATTACH_DATA_BIN,
  940. &IID_IStream,
  941. 0,
  942. 0,
  943. (LPUNKNOWN*) &lpstmA
  944. );
  945. if (FAILED(hResult))
  946. {
  947. goto next_attachment2;
  948. }
  949. break;
  950. case ATTACH_EMBEDDED_MSG:
  951. case ATTACH_OLE:
  952. hResult = lpAttach->OpenProperty(
  953. PR_ATTACH_DATA_OBJ,
  954. &IID_IStreamDocfile,
  955. 0,
  956. 0,
  957. (LPUNKNOWN*) &lpstmA
  958. );
  959. if (FAILED(hResult))
  960. {
  961. hResult = lpAttach->OpenProperty(
  962. PR_ATTACH_DATA_BIN,
  963. &IID_IStreamDocfile,
  964. 0,
  965. 0,
  966. (LPUNKNOWN*) &lpstmA
  967. );
  968. if (FAILED(hResult))
  969. {
  970. hResult = lpAttach->OpenProperty(
  971. PR_ATTACH_DATA_OBJ,
  972. &IID_IStorage,
  973. 0,
  974. 0,
  975. (LPUNKNOWN*) &lpstmA
  976. );
  977. if (FAILED(hResult))
  978. {
  979. goto next_attachment2;
  980. }
  981. }
  982. }
  983. break;
  984. }
  985. if (lpstmA)
  986. {
  987. DWORD dwSize = GetTempPath( sizeof(TempPath)/sizeof(TCHAR) , TempPath );
  988. Assert( dwSize != 0);
  989. GetTempFileName( TempPath, _T("Fax"), 0, TempFile );
  990. hFile = CreateFile(
  991. TempFile,
  992. GENERIC_READ | GENERIC_WRITE,
  993. 0,
  994. NULL,
  995. CREATE_ALWAYS,
  996. 0,
  997. NULL
  998. );
  999. if (hFile != INVALID_HANDLE_VALUE)
  1000. {
  1001. #define BLOCK_SIZE (64*1024)
  1002. LPBYTE StrmData;
  1003. DWORD BytesWrite;
  1004. StrmData = (LPBYTE) MemAlloc( BLOCK_SIZE );
  1005. if(!StrmData)
  1006. {
  1007. rVal = IDS_OUT_OF_MEM;
  1008. goto exit;
  1009. }
  1010. do
  1011. {
  1012. hResult = lpstmA->Read( StrmData, BLOCK_SIZE, &Bytes );
  1013. if (FAILED(hResult))
  1014. {
  1015. break;
  1016. }
  1017. WriteFile( hFile, StrmData, Bytes, &BytesWrite, NULL );
  1018. } while (Bytes == BLOCK_SIZE);
  1019. CloseHandle( hFile );
  1020. if(StrmData)
  1021. {
  1022. MemFree( StrmData );
  1023. StrmData = NULL;
  1024. }
  1025. if (AttachFileName)
  1026. {
  1027. MemFree( AttachFileName );
  1028. AttachFileName = NULL;
  1029. }
  1030. _tcscpy( DocFile, TempFile );
  1031. lptstrTempStr = _tcsrchr( DocFile, '.' );
  1032. if (lptstrTempStr)
  1033. {
  1034. _tcscpy( lptstrTempStr, DocType );
  1035. MoveFile( TempFile, DocFile );
  1036. AttachFileName = StringDup( DocFile );
  1037. if(!AttachFileName)
  1038. {
  1039. rVal = IDS_OUT_OF_MEM;
  1040. goto exit;
  1041. }
  1042. }
  1043. else
  1044. {
  1045. AttachFileName = StringDup( TempFile );
  1046. if(!AttachFileName)
  1047. {
  1048. rVal = IDS_OUT_OF_MEM;
  1049. goto exit;
  1050. }
  1051. }
  1052. DeleteAttachFile = TRUE;
  1053. }
  1054. lpstmA->Release();
  1055. }
  1056. if (AttachFileName)
  1057. {
  1058. if (!GetFaxTempFileName(strTempTiffFile, ARR_SIZE(strTempTiffFile)))
  1059. {
  1060. rVal = IDS_BAD_ATTACHMENTS;//GetLastError();
  1061. goto exit;
  1062. }
  1063. //
  1064. // print the attachment
  1065. //
  1066. if (!PrintRandomDocument( pFaxConfig->PrinterName,
  1067. AttachFileName,
  1068. strTempTiffFile))
  1069. {
  1070. CALL_FAIL (GENERAL_ERR, TEXT("PrintRandomDocument"), ::GetLastError());
  1071. rVal = IDS_BAD_ATTACHMENTS;//GetLastError();
  1072. if (!DeleteFile( strTempTiffFile ))
  1073. {
  1074. CALL_FAIL (GENERAL_ERR, TEXT("DeleteFile"), ::GetLastError());
  1075. }
  1076. goto exit;
  1077. }
  1078. if (strMergedTiffFile[0] != 0)
  1079. {
  1080. //
  1081. // merge the attachments
  1082. //
  1083. if (!MergeTiffFiles( strMergedTiffFile,
  1084. strTempTiffFile))
  1085. {
  1086. CALL_FAIL (GENERAL_ERR, TEXT("MergeTiffFiles"), ::GetLastError());
  1087. rVal = IDS_BAD_ATTACHMENTS;//GetLastError();
  1088. if (!DeleteFile( strTempTiffFile ))
  1089. {
  1090. CALL_FAIL (GENERAL_ERR, TEXT("DeleteFile"), ::GetLastError());
  1091. }
  1092. goto exit;
  1093. }
  1094. if (!DeleteFile( strTempTiffFile ))
  1095. {
  1096. CALL_FAIL (GENERAL_ERR, TEXT("DeleteFile"), ::GetLastError());
  1097. }
  1098. }
  1099. else
  1100. { // copies a first attachment
  1101. _tcscpy(strMergedTiffFile,strTempTiffFile);
  1102. }
  1103. if (DeleteAttachFile)
  1104. {
  1105. if (!DeleteFile( AttachFileName ))
  1106. {
  1107. CALL_FAIL (GENERAL_ERR, TEXT("DeleteFile"), ::GetLastError());
  1108. }
  1109. }
  1110. if(AttachFileName)
  1111. {
  1112. MemFree( AttachFileName );
  1113. AttachFileName = NULL;
  1114. }
  1115. }
  1116. next_attachment2:
  1117. if (lpAttach)
  1118. {
  1119. lpAttach->Release();
  1120. }
  1121. if (pPropsAttach)
  1122. {
  1123. MAPIFreeBuffer( pPropsAttach );
  1124. pPropsAttach = NULL;
  1125. }
  1126. }
  1127. }
  1128. else
  1129. {
  1130. //
  1131. // no attachments
  1132. //
  1133. rVal = IDS_NO_MSG_ATTACHMENTS;
  1134. }
  1135. if (strMergedTiffFile[0] != 0)
  1136. {
  1137. if (!(*lpptstrOutAttachments = StringDup(strMergedTiffFile)))
  1138. {
  1139. rVal = IDS_OUT_OF_MEM;
  1140. }
  1141. }
  1142. exit:
  1143. if (FileName)
  1144. {
  1145. MemFree( FileName );
  1146. }
  1147. if (DocType)
  1148. {
  1149. MemFree( DocType );
  1150. }
  1151. if (pAttachmentRows)
  1152. {
  1153. FreeProws( pAttachmentRows );
  1154. }
  1155. if (AttachmentTable)
  1156. {
  1157. AttachmentTable->Release();
  1158. }
  1159. if (AttachFileName)
  1160. {
  1161. MemFree( AttachFileName );
  1162. }
  1163. return rVal;
  1164. }
  1165. DWORD
  1166. CXPLogon::PrintMessageToFile(
  1167. IN LPSTREAM lpstmT,
  1168. IN BOOL UseRichText,
  1169. IN PFAXXP_CONFIG pFaxConfig,
  1170. IN LPTSTR tszSubject,
  1171. OUT LPTSTR* lpptstrOutDocument
  1172. )
  1173. /*++
  1174. Routine Description:
  1175. Prints the message body to the output file.
  1176. Arguments:
  1177. lpstmT - Pointer to the message body stream
  1178. UseRichText - boolean value. TRUE if the message is in Rich format,
  1179. FALSE - if this is a plain text
  1180. pFaxConfig - Pointer to fax configuration (used by plain text printing)
  1181. tszSubject - Subject
  1182. lpptstrOutDocument - Name of the output tiff file. The string should be empty
  1183. Return Value:
  1184. ERROR_SUCCESS - if success
  1185. Error IDS_... code if failed.
  1186. Comments:
  1187. If this function succeeded it allocates a memory for *lpptstrOutDocument
  1188. and creates a temporal file *lpptstrOutDocument.
  1189. It's up to user to free both these allocations, by
  1190. DeleteFile(*lpptstrOutDocument);
  1191. MemFree(*lpptstrOutDocument);
  1192. --*/
  1193. {
  1194. DWORD rVal = ERROR_SUCCESS;
  1195. LARGE_INTEGER BigZero = {0};
  1196. LPSTREAM lpstm = NULL;
  1197. HRESULT hResult;
  1198. HWND hWndRichEdit = NULL;
  1199. HDC hDC = NULL;
  1200. EDITSTREAM es = {0};
  1201. TCHAR strOutputTiffFile[MAX_PATH] = {0};
  1202. TCHAR DocName[64];
  1203. TCHAR tszSubjectFormat[64];
  1204. TCHAR* ptszSubjectText = NULL;
  1205. DWORD dwSubjectSize = 0;
  1206. DOCINFO docInfo =
  1207. {
  1208. sizeof(DOCINFO),
  1209. NULL,
  1210. NULL,
  1211. NULL,
  1212. 0,
  1213. };
  1214. DBG_ENTER(TEXT("CXPLogon::PrintMessageToFile"),rVal);
  1215. Assert(pFaxConfig);
  1216. Assert(lpptstrOutDocument);
  1217. Assert(*lpptstrOutDocument==NULL);
  1218. if (!(hDC = CreateDC( NULL,
  1219. pFaxConfig->PrinterName,
  1220. NULL,
  1221. NULL)))
  1222. {
  1223. CALL_FAIL (GENERAL_ERR, TEXT("CreateDC"), ::GetLastError());
  1224. rVal = IDS_CANT_PRINT_BODY;
  1225. goto exit;
  1226. }
  1227. LoadString(g_hResource, IDS_MESSAGE_DOC_NAME, DocName, sizeof(DocName) / sizeof(DocName[0]));
  1228. docInfo.lpszDocName = DocName;
  1229. if (!GetFaxTempFileName(strOutputTiffFile, ARR_SIZE(strOutputTiffFile)))
  1230. {
  1231. rVal = IDS_CANT_PRINT_BODY;
  1232. goto exit;
  1233. }
  1234. docInfo.lpszOutput = strOutputTiffFile ;
  1235. docInfo.lpszDatatype = _T("RAW");
  1236. if (StartDoc(hDC, &docInfo) <= 0)
  1237. {
  1238. CALL_FAIL (GENERAL_ERR, TEXT("StartDoc"), ::GetLastError());
  1239. rVal = IDS_CANT_PRINT_BODY;
  1240. goto exit;
  1241. }
  1242. //
  1243. // position the stream to the beginning
  1244. //
  1245. if(lpstmT)
  1246. {
  1247. hResult = lpstmT->Seek( BigZero, STREAM_SEEK_SET, NULL );
  1248. if (HR_FAILED (hResult))
  1249. {
  1250. rVal = IDS_CANT_ACCESS_MSG_DATA;
  1251. goto exit;
  1252. }
  1253. }
  1254. if(!pFaxConfig->UseCoverPage && tszSubject && _tcslen(tszSubject))
  1255. {
  1256. //
  1257. // get subject string
  1258. //
  1259. dwSubjectSize = _tcslen(tszSubject) * sizeof(TCHAR) + sizeof(tszSubjectFormat);
  1260. ptszSubjectText = (TCHAR*)MemAlloc(dwSubjectSize);
  1261. if(!ptszSubjectText)
  1262. {
  1263. rVal = IDS_OUT_OF_MEM;
  1264. goto exit;
  1265. }
  1266. if(!LoadString(g_hResource, IDS_SUBJECT_FORMAT, tszSubjectFormat, sizeof(tszSubjectFormat) / sizeof(tszSubjectFormat[0])))
  1267. {
  1268. Assert(FALSE);
  1269. CALL_FAIL (GENERAL_ERR, TEXT("LoadString"), ::GetLastError());
  1270. _tcscpy(tszSubjectFormat, TEXT("%s"));
  1271. }
  1272. _stprintf(ptszSubjectText, tszSubjectFormat, tszSubject);
  1273. dwSubjectSize = _tcslen(ptszSubjectText);
  1274. }
  1275. if (UseRichText)
  1276. {
  1277. if(lpstmT)
  1278. {
  1279. hResult = WrapCompressedRTFStream( lpstmT, 0, &lpstm );
  1280. if (HR_FAILED (hResult))
  1281. {
  1282. rVal = IDS_CANT_ACCESS_MSG_DATA;
  1283. goto exit;
  1284. }
  1285. }
  1286. hWndRichEdit = CreateWindowEx(
  1287. 0, // extended window style
  1288. TEXT("RICHEDIT"), // registered class name
  1289. TEXT(""), // window name
  1290. ES_MULTILINE, // window style
  1291. 0, // horizontal position of window
  1292. 0, // vertical position of window
  1293. 0, // window width
  1294. 0, // window height
  1295. NULL, // handle to parent or owner window
  1296. NULL, // menu handle or child identifier
  1297. g_hModule, // handle to application instance
  1298. NULL); // window-creation data
  1299. if (!hWndRichEdit)
  1300. {
  1301. CALL_FAIL (GENERAL_ERR, TEXT("CreateWindowEx"), ::GetLastError());
  1302. rVal = IDS_CANT_PRINT_BODY;
  1303. goto exit;
  1304. }
  1305. if(ptszSubjectText && _tcslen(ptszSubjectText))
  1306. {
  1307. //
  1308. // add subject to body
  1309. //
  1310. SendMessage(hWndRichEdit,
  1311. WM_SETTEXT,
  1312. 0,
  1313. (LPARAM)ptszSubjectText);
  1314. //
  1315. // Set the subject's font
  1316. //
  1317. CHARFORMAT CharFormat = {0};
  1318. CharFormat.cbSize = sizeof (CHARFORMAT);
  1319. CharFormat.dwMask = CFM_BOLD |
  1320. CFM_CHARSET |
  1321. CFM_FACE |
  1322. CFM_ITALIC |
  1323. CFM_SIZE |
  1324. CFM_STRIKEOUT |
  1325. CFM_UNDERLINE;
  1326. CharFormat.dwEffects = ((FW_BOLD <= pFaxConfig->FontStruct.lfWeight) ? CFE_BOLD : 0) |
  1327. ((pFaxConfig->FontStruct.lfItalic) ? CFE_ITALIC : 0) |
  1328. ((pFaxConfig->FontStruct.lfStrikeOut) ? CFE_STRIKEOUT : 0) |
  1329. ((pFaxConfig->FontStruct.lfUnderline) ? CFE_UNDERLINE : 0);
  1330. //
  1331. // Height is already in point size.
  1332. //
  1333. CharFormat.yHeight = abs ( pFaxConfig->FontStruct.lfHeight );
  1334. //
  1335. // Convert point to twip
  1336. //
  1337. CharFormat.yHeight *= 20;
  1338. CharFormat.bCharSet = pFaxConfig->FontStruct.lfCharSet;
  1339. CharFormat.bPitchAndFamily = pFaxConfig->FontStruct.lfPitchAndFamily;
  1340. lstrcpyn (CharFormat.szFaceName, pFaxConfig->FontStruct.lfFaceName, LF_FACESIZE);
  1341. SendMessage(hWndRichEdit,
  1342. EM_SETCHARFORMAT,
  1343. SCF_ALL, // Apply font formatting to all the control's text
  1344. (LPARAM)&CharFormat); // New font settings
  1345. //
  1346. // Place insertion point at the end of the subject text
  1347. // See MSDN under "HOWTO: Place a Caret After Edit-Control Text"
  1348. //
  1349. SendMessage(hWndRichEdit,
  1350. EM_SETSEL,
  1351. MAKELONG(0xffff,0xffff),
  1352. MAKELONG(0xffff,0xffff));
  1353. }
  1354. if(lpstm)
  1355. {
  1356. es.pfnCallback = EditStreamRead;
  1357. es.dwCookie = (DWORD_PTR) lpstm;
  1358. SendMessage(hWndRichEdit,
  1359. EM_STREAMIN,
  1360. SF_RTF | SFF_SELECTION | SFF_PLAINRTF,
  1361. (LPARAM) &es);
  1362. }
  1363. //
  1364. // Check if the body is not empty.
  1365. // If the message length is shorter then 32 (arbitrary number)
  1366. // and all the characters are control or space.
  1367. //
  1368. TCHAR tszText[32] = {0};
  1369. DWORD dwTextSize;
  1370. if (!GetWindowText(hWndRichEdit, tszText, sizeof(tszText)/sizeof(tszText[0])-1))
  1371. {
  1372. if (ERROR_INSUFFICIENT_BUFFER == ::GetLastError ())
  1373. {
  1374. //
  1375. // Subject + Body are longer than 31 characters.
  1376. // We're assuming they have valid printable text and
  1377. // that this is not an empty message.
  1378. //
  1379. goto DoPrintRichText;
  1380. }
  1381. //
  1382. // This is another type of error
  1383. //
  1384. rVal = ::GetLastError ();
  1385. CALL_FAIL (GENERAL_ERR, TEXT("GetWindowText"), rVal);
  1386. goto exit;
  1387. }
  1388. dwTextSize = _tcslen(tszText);
  1389. if(dwTextSize < sizeof(tszText)/sizeof(tszText[0])-2)
  1390. {
  1391. BOOL bEmpty = TRUE;
  1392. TCHAR* pTchar = tszText;
  1393. for(DWORD dw = 0; dw < dwTextSize; ++dw)
  1394. {
  1395. if(!_istspace(*pTchar) && !_istcntrl(*pTchar))
  1396. {
  1397. bEmpty = FALSE;
  1398. break;
  1399. }
  1400. pTchar = _tcsinc(pTchar);
  1401. }
  1402. if(bEmpty)
  1403. {
  1404. rVal = IDS_NO_MSG_BODY;
  1405. goto exit;
  1406. }
  1407. }
  1408. DoPrintRichText:
  1409. if (!PrintRichText(hWndRichEdit, hDC))
  1410. {
  1411. rVal = IDS_CANT_PRINT_BODY;
  1412. goto exit;
  1413. }
  1414. }
  1415. else
  1416. {
  1417. rVal = PrintPlainText(hDC, lpstmT, ptszSubjectText, pFaxConfig);
  1418. if (rVal)
  1419. {
  1420. goto exit;
  1421. }
  1422. }
  1423. // closes DC
  1424. if (EndDoc(hDC) <=0)
  1425. {
  1426. Assert(FALSE); // better not to be here
  1427. goto exit;
  1428. }
  1429. if (!DeleteDC(hDC))
  1430. {
  1431. Assert(FALSE); // better not to be here
  1432. goto exit;
  1433. }
  1434. hDC = NULL;
  1435. if (strOutputTiffFile[0] != 0)
  1436. {
  1437. if (!(*lpptstrOutDocument = StringDup(strOutputTiffFile)))
  1438. {
  1439. rVal = IDS_OUT_OF_MEM; //ERROR_NOT_ENOUGH_MEMORY;
  1440. goto exit;
  1441. }
  1442. VERBOSE (DBG_MSG, TEXT("Attachment File is %s:"), *lpptstrOutDocument);
  1443. }
  1444. rVal = ERROR_SUCCESS;
  1445. exit:
  1446. if (lpstm)
  1447. {
  1448. lpstm->Release();
  1449. }
  1450. if (hDC)
  1451. {
  1452. DeleteDC(hDC);
  1453. }
  1454. MemFree(ptszSubjectText);
  1455. if(ERROR_SUCCESS != rVal && _tcslen(strOutputTiffFile))
  1456. {
  1457. if (!DeleteFile( strOutputTiffFile ))
  1458. {
  1459. CALL_FAIL (GENERAL_ERR, TEXT("DeleteFile"), ::GetLastError());
  1460. }
  1461. }
  1462. return rVal;
  1463. }
  1464. DWORD
  1465. CXPLogon::PrintFaxDocumentToFile(
  1466. IN LPMESSAGE pMsgObj,
  1467. IN LPSTREAM lpstmT,
  1468. IN BOOL UseRichText,
  1469. IN PFAXXP_CONFIG pFaxConfig,
  1470. IN LPTSTR tszSubject,
  1471. OUT LPTSTR* lpptstrMessageFileName
  1472. )
  1473. /*++
  1474. Routine Description:
  1475. Runs printing of the message body and attachments to the output file.
  1476. Arguments:
  1477. pMsgObj - Pointer to the message object
  1478. lpstmT - Pointer to the message body stream
  1479. UseRichText - boolean value. TRUE if the message is in Rich format,
  1480. FALSE - if this is a plain text
  1481. pFaxConfig - Pointer to fax configuration (used by plain text printing)
  1482. tszSubject - Subject
  1483. lpptstrMessageFileName - Name of the output tiff file. The string should be empty
  1484. Return Value:
  1485. 0 - if success
  1486. Error code if failed.
  1487. Comments:
  1488. If this function succeeded it returns an allocated memory for
  1489. *lpptstrMessageFileName and a temporal file *lpptstrMessageFileName.
  1490. It's up to user to free both these allocations, by
  1491. DeleteFile(*lpptstrMessageFileName);
  1492. MemFree(*lpptstrMessageFileName);
  1493. --*/
  1494. {
  1495. DWORD rVal = 0;
  1496. LPTSTR lptstrAttachmentsTiff = NULL;
  1497. BOOL bAttachment = TRUE;
  1498. BOOL bBody = TRUE;
  1499. DBG_ENTER(TEXT("CXPLogon::PrintFaxDocumentToFile"),rVal);
  1500. Assert(lpptstrMessageFileName);
  1501. Assert(*lpptstrMessageFileName == NULL);
  1502. //
  1503. // prints attachments
  1504. //
  1505. rVal = PrintAttachmentToFile(pMsgObj,
  1506. pFaxConfig,
  1507. &lptstrAttachmentsTiff);
  1508. if(rVal)
  1509. {
  1510. if(IDS_NO_MSG_ATTACHMENTS == rVal)
  1511. {
  1512. rVal = 0;
  1513. bAttachment = FALSE;
  1514. }
  1515. else
  1516. {
  1517. CALL_FAIL (GENERAL_ERR, TEXT("PrintAttachmentToFile"), 0);
  1518. goto error;
  1519. }
  1520. }
  1521. //
  1522. // prints the body
  1523. //
  1524. rVal = PrintMessageToFile(lpstmT,
  1525. UseRichText,
  1526. pFaxConfig,
  1527. tszSubject,
  1528. lpptstrMessageFileName);
  1529. if(rVal)
  1530. {
  1531. if(IDS_NO_MSG_BODY == rVal)
  1532. {
  1533. rVal = 0;
  1534. bBody = FALSE;
  1535. }
  1536. else
  1537. {
  1538. CALL_FAIL (GENERAL_ERR, TEXT("PrintMessageToFile"), 0);
  1539. goto error;
  1540. }
  1541. }
  1542. if(!bBody && !bAttachment)
  1543. {
  1544. rVal = IDS_EMPTY_MESSAGE;
  1545. goto error;
  1546. }
  1547. if (!*lpptstrMessageFileName) // empty body
  1548. {
  1549. if (lptstrAttachmentsTiff) // the message contains attachments
  1550. {
  1551. if (!(*lpptstrMessageFileName = StringDup(lptstrAttachmentsTiff)))
  1552. {
  1553. rVal = IDS_OUT_OF_MEM;
  1554. goto error;
  1555. }
  1556. }
  1557. }
  1558. else // the message contains body
  1559. {
  1560. if (lptstrAttachmentsTiff) // the message contains attachments
  1561. {
  1562. // merges message and attachements
  1563. if (!MergeTiffFiles( *lpptstrMessageFileName, lptstrAttachmentsTiff))
  1564. {
  1565. rVal = IDS_CANT_PRINT_BODY;
  1566. goto error;
  1567. }
  1568. // deletes attachements
  1569. if(!DeleteFile(lptstrAttachmentsTiff))
  1570. {
  1571. VERBOSE (DBG_MSG, TEXT("DeleteFile Failed in xport\\faxdoc.cpp"));
  1572. }
  1573. MemFree(lptstrAttachmentsTiff);
  1574. lptstrAttachmentsTiff = NULL;
  1575. }
  1576. }
  1577. return rVal;
  1578. error:
  1579. if (lptstrAttachmentsTiff)
  1580. {
  1581. if(!DeleteFile(lptstrAttachmentsTiff))
  1582. {
  1583. VERBOSE (DBG_MSG, TEXT("DeleteFile Failed in xport\\faxdoc.cpp"));
  1584. }
  1585. MemFree(lptstrAttachmentsTiff);
  1586. lptstrAttachmentsTiff = NULL;
  1587. }
  1588. if (*lpptstrMessageFileName)
  1589. {
  1590. if(!DeleteFile(*lpptstrMessageFileName))
  1591. {
  1592. VERBOSE (DBG_MSG, TEXT("DeleteFile Failed in xport\\faxdoc.cpp"));
  1593. }
  1594. MemFree(*lpptstrMessageFileName);
  1595. *lpptstrMessageFileName = NULL;
  1596. }
  1597. return rVal;
  1598. }
  1599. DWORD
  1600. CXPLogon::SendFaxDocument(
  1601. LPMESSAGE pMsgObj,
  1602. LPSTREAM lpstmT,
  1603. BOOL UseRichText,
  1604. LPSPropValue pMsgProps,
  1605. LPSRowSet pRecipRows,
  1606. LPDWORD lpdwRecipientsLimit
  1607. )
  1608. /*++
  1609. Routine Description:
  1610. Prints an exchange message and attachments to the fax printer.
  1611. Arguments:
  1612. pMsgObj - Pointer to message object
  1613. lpstmT - Stream pointer for rich text.
  1614. UseRichText - boolean value. TRUE if the message is in Rich format,
  1615. FALSE - if this is a plain text
  1616. pMsgProps - Message properties (those that are defined in sptPropsForHeader)
  1617. pRecipRows - Properties of recipients
  1618. lpdwRecipientsLimit - recieves the recipietns limit in case of failure. '0' means no limit
  1619. Return Value:
  1620. Zero for success, otherwise error code.
  1621. --*/
  1622. {
  1623. DWORD dwRetVal = 0;
  1624. PPRINTER_INFO_2 PrinterInfo = NULL;
  1625. PRINTER_DEFAULTS PrinterDefaults;
  1626. HANDLE hPrinter = NULL;
  1627. DWORD ec = 0;
  1628. HRESULT hResult = S_OK;
  1629. EDITSTREAM es = {0};
  1630. LPPROFSECT pProfileObj = NULL;
  1631. ULONG PropCount = 0;
  1632. ULONG PropMsgCount = 0;
  1633. LPSPropValue pProps = NULL;
  1634. LPSPropValue pPropsMsg = NULL;
  1635. FAXXP_CONFIG FaxConfig = {0};
  1636. MAPINAMEID NameIds[NUM_FAX_MSG_PROPS];
  1637. MAPINAMEID *pNameIds[NUM_FAX_MSG_PROPS] = {
  1638. &NameIds[0],
  1639. &NameIds[1],
  1640. &NameIds[2],
  1641. &NameIds[3],
  1642. &NameIds[4],
  1643. &NameIds[5]};
  1644. LPSPropTagArray MsgPropTags = NULL;
  1645. HKEY hKey = 0;
  1646. DWORD RegSize = 0;
  1647. DWORD RegType = 0;
  1648. DWORD CountPrinters = 0;
  1649. LPTSTR lptstrRecipientName = NULL ;
  1650. LPTSTR lptstrRecipientNumber = NULL ;
  1651. LPTSTR lptstrRecName = NULL ;
  1652. LPTSTR lptstrRecFaxNumber = NULL ;
  1653. LPTSTR lptstrSubject = NULL ;
  1654. LPTSTR lptszServerName = NULL;
  1655. LPTSTR lptstrDocumentFileName = NULL;
  1656. HANDLE FaxServer = NULL;
  1657. FAX_COVERPAGE_INFO_EX CovInfo = {0};
  1658. FAX_PERSONAL_PROFILE SenderProfile = {0};
  1659. FAX_JOB_PARAM_EX JobParamsEx = {0};
  1660. PFAX_PERSONAL_PROFILE pRecipients = NULL;
  1661. DWORDLONG dwlParentJobId = 0;
  1662. DWORDLONG* lpdwlRecipientJobIds = NULL;
  1663. BOOL bRslt = FALSE;
  1664. LPSPropValue pRecipProps = NULL;
  1665. DWORD dwRecipient = 0;
  1666. TCHAR strCoverpageName[MAX_PATH] = {0};
  1667. BOOL bServerBased = TRUE;
  1668. DWORD dwRecipientNumber = 0;
  1669. DWORD dwRights = 0; //access rights of fax sender
  1670. LPADRBOOK lpAdrBook = NULL;
  1671. LPTSTR lpstrSenderSMTPAdr = NULL;//sender's SMTP adr, including "SMTP:" prefix
  1672. LPTSTR lpstrSMTPPrefix = NULL;
  1673. LPTSTR lpstrSenderAdr = NULL;//sender's SMTP adr. without prefix
  1674. ULONG cValues = 0;
  1675. ULONG ulObjType = NULL;
  1676. LPMAILUSER pMailUser = NULL;
  1677. LPSPropValue lpPropValue = NULL;
  1678. ULONG i, j;
  1679. BOOL bGotSenderAdr = FALSE;
  1680. LPTSTR lptstrCPFullPath = NULL;
  1681. LPTSTR lptstrCPName = NULL;
  1682. DWORD dwError = 0;
  1683. BOOL bResult = FALSE;
  1684. DWORD dwReceiptsOptions = DRT_NONE;
  1685. RECIPIENTS_SET setRecip; // Recipients set used to remove the duplications
  1686. SizedSPropTagArray(1, sptPropxyAddrProp) = {1, PR_EMS_AB_PROXY_ADDRESSES_A};
  1687. DWORD dwRecipientsLimit = 0;
  1688. DBG_ENTER(TEXT("CXPLogon::SendFaxDocument"), dwRetVal);
  1689. //
  1690. // *****************************
  1691. // get the fax config properties
  1692. // *****************************
  1693. //
  1694. hResult = m_pSupObj->OpenProfileSection(
  1695. &g_FaxGuid,
  1696. MAPI_MODIFY,
  1697. &pProfileObj
  1698. );
  1699. if (HR_FAILED (hResult))
  1700. {
  1701. CALL_FAIL (GENERAL_ERR, TEXT("OpenProfileSection"), hResult);
  1702. dwRetVal = IDS_CANT_ACCESS_PROFILE;
  1703. goto exit;
  1704. }
  1705. hResult = pProfileObj->GetProps(
  1706. (LPSPropTagArray) &sptFaxProps,
  1707. 0,
  1708. &PropCount,
  1709. &pProps
  1710. );
  1711. if ((FAILED(hResult))||(hResult == ResultFromScode(MAPI_W_ERRORS_RETURNED)) )
  1712. {
  1713. CALL_FAIL (GENERAL_ERR, TEXT("GetProps"), hResult);
  1714. dwRetVal = IDS_INTERNAL_ERROR;
  1715. goto exit;
  1716. }
  1717. FaxConfig.PrinterName = StringDup( (LPTSTR)pProps[PROP_FAX_PRINTER_NAME].Value.bin.lpb );
  1718. if(! FaxConfig.PrinterName)
  1719. {
  1720. dwRetVal = IDS_OUT_OF_MEM;
  1721. goto exit;
  1722. }
  1723. FaxConfig.CoverPageName = StringDup( (LPTSTR)pProps[PROP_COVERPAGE_NAME].Value.bin.lpb );
  1724. if(! FaxConfig.CoverPageName)
  1725. {
  1726. dwRetVal = IDS_OUT_OF_MEM;
  1727. goto exit;
  1728. }
  1729. FaxConfig.UseCoverPage = pProps[PROP_USE_COVERPAGE].Value.ul;
  1730. FaxConfig.ServerCoverPage = pProps[PROP_SERVER_COVERPAGE].Value.ul;
  1731. CopyMemory(
  1732. &FaxConfig.FontStruct,
  1733. pProps[PROP_FONT].Value.bin.lpb,
  1734. pProps[PROP_FONT].Value.bin.cb
  1735. );
  1736. FaxConfig.SendSingleReceipt= pProps[PROP_SEND_SINGLE_RECEIPT].Value.ul;
  1737. FaxConfig.bAttachFax = pProps[PROP_ATTACH_FAX].Value.ul;
  1738. //
  1739. // *************************************
  1740. // now get the message config properties
  1741. // *************************************
  1742. //
  1743. NameIds[MSGPI_FAX_PRINTER_NAME].lpguid = (LPGUID)&PS_PUBLIC_STRINGS;
  1744. NameIds[MSGPI_FAX_PRINTER_NAME].ulKind = MNID_STRING;
  1745. NameIds[MSGPI_FAX_PRINTER_NAME].Kind.lpwstrName = MSGPS_FAX_PRINTER_NAME;
  1746. NameIds[MSGPI_FAX_COVERPAGE_NAME].lpguid = (LPGUID)&PS_PUBLIC_STRINGS;
  1747. NameIds[MSGPI_FAX_COVERPAGE_NAME].ulKind = MNID_STRING;
  1748. NameIds[MSGPI_FAX_COVERPAGE_NAME].Kind.lpwstrName = MSGPS_FAX_COVERPAGE_NAME;
  1749. NameIds[MSGPI_FAX_USE_COVERPAGE].lpguid = (LPGUID)&PS_PUBLIC_STRINGS;
  1750. NameIds[MSGPI_FAX_USE_COVERPAGE].ulKind = MNID_STRING;
  1751. NameIds[MSGPI_FAX_USE_COVERPAGE].Kind.lpwstrName = MSGPS_FAX_USE_COVERPAGE;
  1752. NameIds[MSGPI_FAX_SERVER_COVERPAGE].lpguid = (LPGUID)&PS_PUBLIC_STRINGS;
  1753. NameIds[MSGPI_FAX_SERVER_COVERPAGE].ulKind = MNID_STRING;
  1754. NameIds[MSGPI_FAX_SERVER_COVERPAGE].Kind.lpwstrName = MSGPS_FAX_SERVER_COVERPAGE;
  1755. NameIds[MSGPI_FAX_SEND_SINGLE_RECEIPT].lpguid = (LPGUID)&PS_PUBLIC_STRINGS;
  1756. NameIds[MSGPI_FAX_SEND_SINGLE_RECEIPT].ulKind = MNID_STRING;
  1757. NameIds[MSGPI_FAX_SEND_SINGLE_RECEIPT].Kind.lpwstrName = MSGPS_FAX_SEND_SINGLE_RECEIPT;
  1758. NameIds[MSGPI_FAX_ATTACH_FAX].lpguid = (LPGUID)&PS_PUBLIC_STRINGS;
  1759. NameIds[MSGPI_FAX_ATTACH_FAX].ulKind = MNID_STRING;
  1760. NameIds[MSGPI_FAX_ATTACH_FAX].Kind.lpwstrName = MSGPS_FAX_ATTACH_FAX;
  1761. hResult = pMsgObj->GetIDsFromNames( (ULONG) NUM_FAX_MSG_PROPS, pNameIds, MAPI_CREATE, &MsgPropTags );
  1762. if (HR_FAILED(hResult))
  1763. {
  1764. if(hResult == MAPI_E_NOT_ENOUGH_MEMORY)
  1765. {
  1766. dwRetVal = IDS_OUT_OF_MEM;
  1767. }
  1768. else
  1769. {
  1770. dwRetVal = IDS_INTERNAL_ERROR;
  1771. }
  1772. CALL_FAIL (GENERAL_ERR, TEXT("GetIDsFromNames"), hResult);
  1773. goto exit;
  1774. }
  1775. MsgPropTags->aulPropTag[MSGPI_FAX_PRINTER_NAME] = PROP_TAG( PT_BINARY, PROP_ID(MsgPropTags->aulPropTag[MSGPI_FAX_PRINTER_NAME]));
  1776. MsgPropTags->aulPropTag[MSGPI_FAX_COVERPAGE_NAME] = PROP_TAG( PT_BINARY, PROP_ID(MsgPropTags->aulPropTag[MSGPI_FAX_COVERPAGE_NAME]));
  1777. MsgPropTags->aulPropTag[MSGPI_FAX_USE_COVERPAGE] = PROP_TAG( PT_LONG, PROP_ID(MsgPropTags->aulPropTag[MSGPI_FAX_USE_COVERPAGE]));
  1778. MsgPropTags->aulPropTag[MSGPI_FAX_SERVER_COVERPAGE] = PROP_TAG( PT_LONG, PROP_ID(MsgPropTags->aulPropTag[MSGPI_FAX_SERVER_COVERPAGE]));
  1779. MsgPropTags->aulPropTag[MSGPI_FAX_SEND_SINGLE_RECEIPT] = PROP_TAG( PT_LONG, PROP_ID(MsgPropTags->aulPropTag[MSGPI_FAX_SEND_SINGLE_RECEIPT]));
  1780. MsgPropTags->aulPropTag[MSGPI_FAX_ATTACH_FAX] = PROP_TAG( PT_LONG, PROP_ID(MsgPropTags->aulPropTag[MSGPI_FAX_ATTACH_FAX]));
  1781. hResult = pMsgObj->GetProps( MsgPropTags, 0, &PropMsgCount, &pPropsMsg );
  1782. if(hResult == ResultFromScode(MAPI_W_ERRORS_RETURNED))
  1783. {
  1784. VERBOSE (DBG_MSG, TEXT("GetProps in SendFaxDocument returned MAPI_W_ERRORS_RETURNED"));
  1785. }
  1786. if (FAILED(hResult))
  1787. //
  1788. // happens if user did not press ok on the "fax attributes" DlgBox - it's not an error!
  1789. //
  1790. {
  1791. CALL_FAIL (GENERAL_ERR, TEXT("GetProps"), hResult);
  1792. hResult = S_OK;
  1793. }
  1794. //
  1795. //prefer the config props defined for the message (if they exist) on those defined for the fax.
  1796. //
  1797. if (PROP_TYPE(pPropsMsg[MSGPI_FAX_PRINTER_NAME].ulPropTag) != PT_ERROR)
  1798. {
  1799. MemFree( FaxConfig.PrinterName );
  1800. FaxConfig.PrinterName = StringDup((LPTSTR)pPropsMsg[MSGPI_FAX_PRINTER_NAME].Value.bin.lpb);
  1801. if(! FaxConfig.PrinterName)
  1802. {
  1803. dwRetVal = IDS_OUT_OF_MEM;
  1804. goto exit;
  1805. }
  1806. }
  1807. if (PROP_TYPE(pPropsMsg[MSGPI_FAX_COVERPAGE_NAME].ulPropTag) != PT_ERROR)
  1808. {
  1809. MemFree( FaxConfig.CoverPageName);
  1810. FaxConfig.CoverPageName = StringDup((LPTSTR)pPropsMsg[MSGPI_FAX_COVERPAGE_NAME].Value.bin.lpb);
  1811. if(! FaxConfig.CoverPageName)
  1812. {
  1813. dwRetVal = IDS_OUT_OF_MEM;
  1814. goto exit;
  1815. }
  1816. }
  1817. if (PROP_TYPE(pPropsMsg[MSGPI_FAX_USE_COVERPAGE].ulPropTag) != PT_ERROR)
  1818. {
  1819. FaxConfig.UseCoverPage = pPropsMsg[MSGPI_FAX_USE_COVERPAGE].Value.ul;
  1820. }
  1821. if (PROP_TYPE(pPropsMsg[MSGPI_FAX_SERVER_COVERPAGE].ulPropTag) != PT_ERROR)
  1822. {
  1823. FaxConfig.ServerCoverPage = pPropsMsg[MSGPI_FAX_SERVER_COVERPAGE].Value.ul;
  1824. }
  1825. if (PROP_TYPE(pPropsMsg[MSGPI_FAX_SEND_SINGLE_RECEIPT].ulPropTag) != PT_ERROR)
  1826. {
  1827. FaxConfig.SendSingleReceipt = pPropsMsg[MSGPI_FAX_SEND_SINGLE_RECEIPT].Value.ul;
  1828. }
  1829. if (PROP_TYPE(pPropsMsg[MSGPI_FAX_ATTACH_FAX].ulPropTag) != PT_ERROR)
  1830. {
  1831. FaxConfig.bAttachFax = pPropsMsg[MSGPI_FAX_ATTACH_FAX].Value.ul;
  1832. }
  1833. if (PROP_TYPE(pMsgProps[MSG_SUBJECT].ulPropTag) != PT_ERROR)
  1834. {
  1835. lptstrSubject = ConvertAStringToTString(pMsgProps[MSG_SUBJECT].Value.lpszA);
  1836. if(! lptstrSubject)
  1837. {
  1838. dwRetVal = IDS_OUT_OF_MEM;
  1839. goto exit;
  1840. }
  1841. }
  1842. //
  1843. // ******************************************
  1844. // open the printer, and create the tiff file
  1845. // ******************************************
  1846. //
  1847. //
  1848. // open the printer - first try to get info on the printer in FaxConfig,
  1849. // if you fail, search all the printers until the first fax printer is found.
  1850. //
  1851. PrinterInfo = (PPRINTER_INFO_2) MyGetPrinter( FaxConfig.PrinterName, 2 );
  1852. if (NULL == PrinterInfo)
  1853. {
  1854. // if the chosen printer is not accessable, try to locate another SharedFax printer
  1855. PrinterInfo = (PPRINTER_INFO_2) MyEnumPrinters( NULL, 2, &CountPrinters );
  1856. if (NULL != PrinterInfo)
  1857. {
  1858. for (i=0; i<(int)CountPrinters; i++)
  1859. {
  1860. if (_tcscmp( PrinterInfo[i].pDriverName, FAX_DRIVER_NAME ) == 0)
  1861. {
  1862. break;
  1863. }
  1864. }
  1865. }
  1866. else
  1867. {
  1868. CountPrinters = i = 0; //no printers were found
  1869. }
  1870. if (i == (int)CountPrinters) //if there are no printers, or none of them is a fax printer
  1871. {
  1872. dwRetVal = IDS_NO_FAX_PRINTER;
  1873. goto exit;
  1874. }
  1875. //
  1876. // if a SharedFax printer was found, update it as the printer that we'll send the fax threw
  1877. //
  1878. MemFree( FaxConfig.PrinterName );
  1879. FaxConfig.PrinterName = StringDup( PrinterInfo[i].pPrinterName );
  1880. if(! FaxConfig.PrinterName)
  1881. {
  1882. dwRetVal = IDS_OUT_OF_MEM;
  1883. goto exit;
  1884. }
  1885. MemFree( PrinterInfo );
  1886. PrinterInfo = (PPRINTER_INFO_2) MyGetPrinter( FaxConfig.PrinterName, 2 );
  1887. if (NULL == PrinterInfo)
  1888. {
  1889. dwRetVal = IDS_CANT_ACCESS_PRINTER;
  1890. goto exit;
  1891. }
  1892. }
  1893. PrinterDefaults.pDatatype = NULL;
  1894. PrinterDefaults.pDevMode = NULL;
  1895. PrinterDefaults.DesiredAccess = PRINTER_ACCESS_USE;
  1896. if (!OpenPrinter( FaxConfig.PrinterName, &hPrinter, &PrinterDefaults ))
  1897. {
  1898. dwRetVal = IDS_CANT_ACCESS_PRINTER;
  1899. goto exit;
  1900. }
  1901. dwRetVal = PrintFaxDocumentToFile( pMsgObj,
  1902. lpstmT,
  1903. UseRichText,
  1904. &FaxConfig ,
  1905. lptstrSubject,
  1906. &lptstrDocumentFileName);
  1907. if (IDS_EMPTY_MESSAGE == dwRetVal)
  1908. {
  1909. //
  1910. // The message is empty. This is not really an error.
  1911. //
  1912. dwRetVal = 0;
  1913. if(!FaxConfig.UseCoverPage)
  1914. {
  1915. //
  1916. // If the message is empty and no cover page is specified there is
  1917. // nothing more to do.
  1918. //
  1919. goto exit;
  1920. }
  1921. }
  1922. if(dwRetVal)
  1923. {
  1924. goto exit;
  1925. }
  1926. VERBOSE (DBG_MSG, TEXT("Final Tiff is %s:"), lptstrDocumentFileName);
  1927. //
  1928. // **************************************
  1929. // initializes sender and recipients info
  1930. // **************************************
  1931. //
  1932. //
  1933. // sender's info
  1934. //
  1935. SenderProfile.dwSizeOfStruct = sizeof(SenderProfile);
  1936. hResult = FaxGetSenderInformation(&SenderProfile);
  1937. if(S_OK != hResult)
  1938. {
  1939. CALL_FAIL (GENERAL_ERR, TEXT("FaxGetSenderInformation"), hResult);
  1940. if (HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER) == hResult)
  1941. {
  1942. dwRetVal = IDS_INTERNAL_ERROR;
  1943. }
  1944. else if (HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY) == hResult )
  1945. {
  1946. dwRetVal = IDS_OUT_OF_MEM;
  1947. goto exit;
  1948. }
  1949. }
  1950. //
  1951. // recipients' info
  1952. // pRecipRows includes rows coresponding only to recipients that their PR_RESPONSIBILITY == FALSE
  1953. //
  1954. dwRecipientNumber = pRecipRows->cRows;
  1955. pRecipients = (PFAX_PERSONAL_PROFILE)MemAlloc(sizeof(FAX_PERSONAL_PROFILE) * dwRecipientNumber);
  1956. if(! pRecipients)
  1957. {
  1958. dwRetVal = IDS_OUT_OF_MEM;
  1959. goto exit;
  1960. }
  1961. ZeroMemory(pRecipients, sizeof(FAX_PERSONAL_PROFILE) * dwRecipientNumber);
  1962. dwRecipient = 0;
  1963. for (DWORD dwRecipRow=0; dwRecipRow < pRecipRows->cRows ; ++dwRecipRow)
  1964. {
  1965. pRecipProps = pRecipRows->aRow[dwRecipRow].lpProps;
  1966. lptstrRecipientName = ConvertAStringToTString(pRecipProps[RECIP_NAME].Value.lpszA);
  1967. if(! lptstrRecipientName)
  1968. {
  1969. dwRetVal = IDS_OUT_OF_MEM;
  1970. goto exit;
  1971. }
  1972. lptstrRecipientNumber = ConvertAStringToTString(pRecipProps[RECIP_EMAIL_ADR].Value.lpszA);
  1973. if(! lptstrRecipientNumber)
  1974. {
  1975. dwRetVal = IDS_OUT_OF_MEM;
  1976. goto exit;
  1977. }
  1978. if(_tcsstr(lptstrRecipientName, lptstrRecipientNumber))
  1979. {
  1980. //
  1981. // PR_EMAIL_ADDRESS_A is substring of PR_DISPLAY_NAME_A
  1982. // so we suppose that PR_DISPLAY_NAME_A was not specified.
  1983. // Try to get the recipient name from PR_EMAIL_ADDRESS_A
  1984. //
  1985. MemFree( lptstrRecipientName );
  1986. lptstrRecipientName = NULL;
  1987. }
  1988. //
  1989. // finds a fax number from the name string,
  1990. // e.g. "Fax Number@+14 (2) 324324" --> +14 (2) 324324)
  1991. //
  1992. LPTSTR pRecipientNumber = _tcschr(lptstrRecipientNumber, '@');
  1993. if (pRecipientNumber)
  1994. {
  1995. //
  1996. //if there was a @, increment the pointer to point to the next char after it.
  1997. //
  1998. *pRecipientNumber = '\0';
  1999. pRecipientNumber = _tcsinc(pRecipientNumber);
  2000. if(!lptstrRecipientName)
  2001. {
  2002. lptstrRecipientName = StringDup(lptstrRecipientNumber);
  2003. if(! lptstrRecipientName)
  2004. {
  2005. dwRetVal = IDS_OUT_OF_MEM;
  2006. goto exit;
  2007. }
  2008. }
  2009. }
  2010. else
  2011. {
  2012. //
  2013. //if there's no @ in the string, it's OK as it was.
  2014. //
  2015. pRecipientNumber = lptstrRecipientNumber;
  2016. }
  2017. //
  2018. // initializes recipient info
  2019. //
  2020. pRecipients[dwRecipient].dwSizeOfStruct = sizeof(FAX_PERSONAL_PROFILE);
  2021. pRecipients[dwRecipient].lptstrFaxNumber = StringDup(pRecipientNumber);
  2022. if(! pRecipients[dwRecipient].lptstrFaxNumber)
  2023. {
  2024. dwRetVal = IDS_OUT_OF_MEM;
  2025. goto exit;
  2026. }
  2027. if(lptstrRecipientName)
  2028. {
  2029. pRecipients[dwRecipient].lptstrName = StringDup(lptstrRecipientName);
  2030. if(! pRecipients[dwRecipient].lptstrName)
  2031. {
  2032. dwRetVal = IDS_OUT_OF_MEM;
  2033. goto exit;
  2034. }
  2035. }
  2036. __try
  2037. {
  2038. //
  2039. // Insert all the recipients into a set.
  2040. // If there are any duplications insert() failes
  2041. //
  2042. if(setRecip.insert(&pRecipients[dwRecipient]).second == true)
  2043. {
  2044. ++dwRecipient;
  2045. }
  2046. else
  2047. {
  2048. //
  2049. // Such recipients already exists
  2050. //
  2051. MemFree(pRecipients[dwRecipient].lptstrName);
  2052. pRecipients[dwRecipient].lptstrName = NULL;
  2053. MemFree(pRecipients[dwRecipient].lptstrFaxNumber);
  2054. pRecipients[dwRecipient].lptstrFaxNumber = NULL;
  2055. }
  2056. }
  2057. __except (EXCEPTION_EXECUTE_HANDLER)
  2058. {
  2059. dwRetVal = IDS_OUT_OF_MEM;
  2060. goto exit;
  2061. }
  2062. if(lptstrRecipientName)
  2063. {
  2064. MemFree( lptstrRecipientName );
  2065. lptstrRecipientName = NULL;
  2066. }
  2067. if(lptstrRecipientNumber)
  2068. {
  2069. MemFree( lptstrRecipientNumber );
  2070. lptstrRecipientNumber = NULL;
  2071. }
  2072. } // for
  2073. //
  2074. // Update the recipient number to the actual size without duplications
  2075. //
  2076. dwRecipientNumber = dwRecipient;
  2077. //
  2078. // *******************
  2079. // get cover page info
  2080. // *******************
  2081. //
  2082. if (FaxConfig.UseCoverPage)
  2083. {
  2084. bServerBased = FaxConfig.ServerCoverPage;
  2085. if(bServerBased)
  2086. {
  2087. _tcscpy(strCoverpageName,FaxConfig.CoverPageName);
  2088. }
  2089. else
  2090. {
  2091. //
  2092. // this is a personal CP, we have to add to it's name the full UNC path
  2093. //
  2094. TCHAR CpDir[MAX_PATH] = {0};
  2095. TCHAR* pCpName = NULL;
  2096. bResult = GetClientCpDir( CpDir, sizeof(CpDir) / sizeof(CpDir[0]));
  2097. if(! bResult)
  2098. {
  2099. CALL_FAIL(GENERAL_ERR, TEXT("GetClientCpDir"), ::GetLastError());
  2100. dwRetVal = IDS_INTERNAL_ERROR;
  2101. goto exit;
  2102. }
  2103. _tcscat(CpDir,FaxConfig.CoverPageName);
  2104. if((_tcslen(CpDir)/sizeof(TCHAR) + _tcslen(FAX_COVER_PAGE_FILENAME_EXT)/sizeof(TCHAR) + 1) > MAX_PATH)
  2105. {
  2106. dwRetVal = IDS_INTERNAL_ERROR;
  2107. goto exit;
  2108. }
  2109. _tcscat(CpDir, FAX_COVER_PAGE_FILENAME_EXT);
  2110. _tcscpy(strCoverpageName, CpDir);
  2111. }
  2112. VERBOSE (DBG_MSG, TEXT("Sending Fax with Coverpage: %s"), strCoverpageName);
  2113. //
  2114. // initializes a cover page info
  2115. //
  2116. CovInfo.dwSizeOfStruct = sizeof( FAX_COVERPAGE_INFO_EX);
  2117. CovInfo.dwCoverPageFormat = FAX_COVERPAGE_FMT_COV;
  2118. CovInfo.lptstrCoverPageFileName = strCoverpageName;
  2119. //if it's not a server's CP, should include exact path to the CP file
  2120. CovInfo.bServerBased = bServerBased ;
  2121. CovInfo.lptstrNote = NULL;
  2122. CovInfo.lptstrSubject = lptstrSubject;
  2123. }
  2124. else
  2125. {
  2126. //
  2127. // no cover page
  2128. //
  2129. CovInfo.dwSizeOfStruct = sizeof( FAX_COVERPAGE_INFO_EX);
  2130. CovInfo.dwCoverPageFormat = FAX_COVERPAGE_FMT_COV_SUBJECT_ONLY;
  2131. CovInfo.lptstrSubject = lptstrSubject;
  2132. }
  2133. //
  2134. // *************************
  2135. // connect to the fax server
  2136. // *************************
  2137. //
  2138. if (!GetServerNameFromPrinterInfo(PrinterInfo ,&lptszServerName ) ||
  2139. !FaxConnectFaxServer(lptszServerName,&FaxServer))
  2140. {
  2141. CALL_FAIL (GENERAL_ERR, TEXT("FaxConnectFaxServer"), ::GetLastError());
  2142. dwRetVal = IDS_CANT_ACCESS_SERVER;
  2143. goto exit;
  2144. }
  2145. VERBOSE (DBG_MSG, TEXT("Connected to Fax Server: %s"), lptszServerName);
  2146. //
  2147. // *****************************
  2148. // initialize the job parameters
  2149. // *****************************
  2150. //
  2151. JobParamsEx.dwSizeOfStruct = sizeof( FAX_JOB_PARAM_EX);
  2152. VERBOSE (DBG_MSG, TEXT("******************JobParamsEx:***********************"));
  2153. //
  2154. // get the sender's SMTP address
  2155. // pMsgProps hold PropsForHeader properties, including PR_SENDER_ENTRYID
  2156. //
  2157. hResult = m_pSupObj->OpenAddressBook(NULL, 0, &lpAdrBook);
  2158. if (FAILED(hResult))
  2159. {
  2160. CALL_FAIL (GENERAL_ERR, TEXT("OpenAddressBook"), ::GetLastError());
  2161. }
  2162. else
  2163. {
  2164. hResult = lpAdrBook->OpenEntry(
  2165. pMsgProps[MSG_SENDER_ENTRYID].Value.bin.cb,
  2166. (LPENTRYID)pMsgProps[MSG_SENDER_ENTRYID].Value.bin.lpb,
  2167. NULL,
  2168. 0,
  2169. &ulObjType,
  2170. (LPUNKNOWN*)&pMailUser
  2171. );
  2172. if (FAILED(hResult))
  2173. {
  2174. CALL_FAIL (GENERAL_ERR, TEXT("OpenEntry"), ::GetLastError());
  2175. }
  2176. else
  2177. {
  2178. hResult = pMailUser->GetProps(
  2179. (LPSPropTagArray)&sptPropxyAddrProp,
  2180. 0,
  2181. &cValues,
  2182. &lpPropValue
  2183. );
  2184. if (!HR_SUCCEEDED(hResult) ||
  2185. PT_ERROR == PROP_TYPE(lpPropValue->ulPropTag))
  2186. {
  2187. //
  2188. // We either failed to get the property or the property retrieved has some error.
  2189. // If we're unable to locate sender's address, we won't be sending a Delivry Receipt,
  2190. // but we won't fail the sending.
  2191. //
  2192. CALL_FAIL (GENERAL_ERR, TEXT("GetProps from MailUser failed, no receipt will be sent!"), hResult);
  2193. }
  2194. else
  2195. {
  2196. //
  2197. //loop through the proxy multivalue property
  2198. //
  2199. for(j=0;j<lpPropValue->Value.MVszA.cValues; j++)
  2200. {
  2201. lpstrSenderSMTPAdr = ConvertAStringToTString(lpPropValue->Value.MVszA.lppszA[j]);
  2202. if(! lpstrSenderSMTPAdr)
  2203. {
  2204. dwRetVal = IDS_OUT_OF_MEM;
  2205. goto exit;
  2206. }
  2207. //
  2208. // check if address begins with "SMTP:":
  2209. // function returns pointer to begining of second param.'s appearance in first param.
  2210. // if it does not appear, returns NULL
  2211. //
  2212. lpstrSMTPPrefix = _tcsstr(lpstrSenderSMTPAdr, TEXT("SMTP:"));
  2213. if( lpstrSenderSMTPAdr == lpstrSMTPPrefix)
  2214. {
  2215. //
  2216. // Remove this prefix from it, and store it in JobParamsEx.
  2217. //
  2218. lpstrSenderAdr = lpstrSenderSMTPAdr + _tcslen(TEXT("SMTP:"));
  2219. JobParamsEx.lptstrReceiptDeliveryAddress = _tcsdup(lpstrSenderAdr);
  2220. if(! JobParamsEx.lptstrReceiptDeliveryAddress)
  2221. {
  2222. dwRetVal = IDS_OUT_OF_MEM;
  2223. goto exit;
  2224. }
  2225. bGotSenderAdr = TRUE;
  2226. VERBOSE(DBG_MSG, TEXT("Receipt delivery address is %s"), JobParamsEx.lptstrReceiptDeliveryAddress);
  2227. break;
  2228. }
  2229. }
  2230. }
  2231. }
  2232. }
  2233. //
  2234. // when to send, sort of delivery receipt
  2235. //
  2236. JobParamsEx.dwScheduleAction = JSA_NOW;
  2237. if(!FaxGetReceiptsOptions(FaxServer, &dwReceiptsOptions))
  2238. {
  2239. CALL_FAIL(GENERAL_ERR, TEXT("FaxGetReceiptsOptions"), ::GetLastError());
  2240. }
  2241. JobParamsEx.dwReceiptDeliveryType = DRT_NONE;
  2242. if (bGotSenderAdr && (dwReceiptsOptions & DRT_EMAIL))
  2243. {
  2244. if (TRUE == FaxConfig.SendSingleReceipt)
  2245. {
  2246. JobParamsEx.dwReceiptDeliveryType = DRT_EMAIL | DRT_GRP_PARENT;
  2247. }
  2248. else
  2249. {
  2250. JobParamsEx.dwReceiptDeliveryType = DRT_EMAIL;
  2251. }
  2252. if (FaxConfig.bAttachFax)
  2253. {
  2254. JobParamsEx.dwReceiptDeliveryType |= DRT_ATTACH_FAX;
  2255. }
  2256. }
  2257. VERBOSE(DBG_MSG, TEXT("Receipt Delivery Type = %ld"), JobParamsEx.dwReceiptDeliveryType);
  2258. //
  2259. // priority
  2260. //
  2261. if (pMsgProps[MSG_IMPORTANCE].ulPropTag == PR_IMPORTANCE)
  2262. {
  2263. if(FALSE == (FaxAccessCheckEx(FaxServer, MAXIMUM_ALLOWED, &dwRights)))
  2264. {
  2265. if((hResult = ::GetLastError()) != ERROR_SUCCESS)
  2266. {
  2267. CALL_FAIL(GENERAL_ERR, TEXT("FaxAccessCheckEx"), hResult);
  2268. dwRetVal = IDS_CANT_ACCESS_PROFILE;
  2269. goto exit;
  2270. }
  2271. }
  2272. //
  2273. //try to give the sender the prio he asked for. if it's not allowed, try a lower prio.
  2274. //
  2275. switch(pMsgProps[MSG_IMPORTANCE].Value.l)
  2276. {
  2277. case (IMPORTANCE_HIGH):
  2278. if ((FAX_ACCESS_SUBMIT_HIGH & dwRights) == FAX_ACCESS_SUBMIT_HIGH)
  2279. {
  2280. JobParamsEx.Priority = FAX_PRIORITY_TYPE_HIGH;
  2281. break;
  2282. }
  2283. //fall through
  2284. case (IMPORTANCE_NORMAL):
  2285. if ((FAX_ACCESS_SUBMIT_NORMAL & dwRights) == FAX_ACCESS_SUBMIT_NORMAL)
  2286. {
  2287. JobParamsEx.Priority = FAX_PRIORITY_TYPE_NORMAL;
  2288. break;
  2289. }
  2290. //fall through
  2291. case (IMPORTANCE_LOW):
  2292. if ((FAX_ACCESS_SUBMIT & dwRights) == FAX_ACCESS_SUBMIT)
  2293. {
  2294. JobParamsEx.Priority = FAX_PRIORITY_TYPE_LOW;
  2295. }
  2296. else
  2297. {
  2298. VERBOSE(ASSERTION_FAILED, TEXT("xport\\faxdoc.cpp\\SendFaxDocument: user has no access rights!"));
  2299. //the user has no right to submit faxes, at any priority!
  2300. dwRetVal = IDS_NO_SUBMIT_RITHTS;
  2301. goto exit;
  2302. }
  2303. break;
  2304. default:
  2305. VERBOSE(ASSERTION_FAILED, TEXT("xport\\faxdoc.cpp\\SendFaxDocument: message importance has undefined value"));
  2306. ASSERTION_FAILURE
  2307. }
  2308. }
  2309. else
  2310. {
  2311. VERBOSE(ASSERTION_FAILED, TEXT("xport\\faxdoc.cpp\\SendFaxDocument: Message had no importance property value!"));
  2312. dwRetVal = IDS_INTERNAL_ERROR;
  2313. ASSERTION_FAILURE;
  2314. goto exit;
  2315. }
  2316. VERBOSE(DBG_MSG, TEXT("Message Priority is %ld (0=low, 1=normal, 2=high)"), JobParamsEx.Priority );
  2317. //
  2318. // doc name, number of pages,
  2319. //
  2320. TCHAR DocName[64];
  2321. LoadString(g_hResource, IDS_MESSAGE_DOC_NAME, DocName, sizeof(DocName) / sizeof (DocName[0]));
  2322. JobParamsEx.lptstrDocumentName = DocName;
  2323. JobParamsEx.dwPageCount = 0; //means the server will count the number of pages in the job
  2324. lpdwlRecipientJobIds = (DWORDLONG*)MemAlloc(sizeof(DWORDLONG)*dwRecipientNumber);
  2325. if(! lpdwlRecipientJobIds)
  2326. {
  2327. dwRetVal = IDS_OUT_OF_MEM;
  2328. goto exit;
  2329. }
  2330. //
  2331. // ************
  2332. // Send the fax
  2333. // ************
  2334. //
  2335. bRslt= FaxSendDocumentEx(
  2336. FaxServer,
  2337. (LPCTSTR) lptstrDocumentFileName,
  2338. &CovInfo,
  2339. &SenderProfile,
  2340. dwRecipientNumber,
  2341. pRecipients,
  2342. &JobParamsEx,
  2343. &dwlParentJobId,
  2344. lpdwlRecipientJobIds
  2345. );
  2346. if (!bRslt)
  2347. {
  2348. hResult = ::GetLastError();
  2349. CALL_FAIL (GENERAL_ERR, TEXT("FaxSendDocumentEx"), hResult);
  2350. // maybe we should swich possible retruned values from SendFaxDocEx,
  2351. // and choose a more informative IDS
  2352. switch(hResult)
  2353. {
  2354. case ERROR_NOT_ENOUGH_MEMORY:
  2355. dwRetVal = IDS_OUT_OF_MEM;
  2356. break;
  2357. case ERROR_NO_SYSTEM_RESOURCES:
  2358. dwRetVal = IDS_INTERNAL_ERROR;
  2359. break;
  2360. case ERROR_CANT_ACCESS_FILE:
  2361. dwRetVal = IDS_PERSONAL_CP_FORBIDDEN;
  2362. break;
  2363. case ERROR_BAD_FORMAT:
  2364. dwRetVal = IDS_BAD_CANNONICAL_ADDRESS;
  2365. break;
  2366. case FAX_ERR_RECIPIENTS_LIMIT:
  2367. dwRetVal = IDS_RECIPIENTS_LIMIT;
  2368. if (!FaxGetRecipientsLimit(FaxServer, &dwRecipientsLimit))
  2369. {
  2370. CALL_FAIL (GENERAL_ERR, TEXT("FaxGetRecipientsLimit"), ::GetLastError());
  2371. }
  2372. break;
  2373. default:
  2374. dwRetVal = IDS_CANT_PRINT;
  2375. break;
  2376. }
  2377. goto exit;
  2378. }
  2379. FaxClose(FaxServer);
  2380. FaxServer = NULL;
  2381. dwRetVal = 0;
  2382. exit:
  2383. if(lpAdrBook)
  2384. {
  2385. lpAdrBook->Release();
  2386. }
  2387. if(pMailUser)
  2388. {
  2389. pMailUser->Release();
  2390. }
  2391. if (FaxServer)
  2392. {
  2393. FaxClose(FaxServer);
  2394. }
  2395. if (pRecipients)
  2396. {
  2397. for (dwRecipient=0; dwRecipient<dwRecipientNumber ; dwRecipient++)
  2398. {
  2399. if (pRecipients[dwRecipient].lptstrName)
  2400. {
  2401. MemFree (pRecipients[dwRecipient].lptstrName);
  2402. }
  2403. if (pRecipients[dwRecipient].lptstrFaxNumber)
  2404. {
  2405. MemFree(pRecipients[dwRecipient].lptstrFaxNumber);
  2406. }
  2407. }
  2408. MemFree(pRecipients);
  2409. pRecipients = NULL;
  2410. }
  2411. if (pProfileObj)
  2412. {
  2413. pProfileObj->Release();
  2414. }
  2415. if (pProps)
  2416. {
  2417. MAPIFreeBuffer( pProps );
  2418. }
  2419. if (MsgPropTags)
  2420. {
  2421. MAPIFreeBuffer( MsgPropTags );
  2422. }
  2423. if (pPropsMsg)
  2424. {
  2425. MAPIFreeBuffer( pPropsMsg );
  2426. }
  2427. if (hPrinter)
  2428. {
  2429. ClosePrinter( hPrinter );
  2430. }
  2431. if (PrinterInfo)
  2432. {
  2433. MemFree( PrinterInfo );
  2434. }
  2435. if (FaxConfig.PrinterName)
  2436. {
  2437. MemFree( FaxConfig.PrinterName );
  2438. }
  2439. if (FaxConfig.CoverPageName)
  2440. {
  2441. MemFree( FaxConfig.CoverPageName );
  2442. }
  2443. if (lptstrRecipientName)
  2444. {
  2445. MemFree(lptstrRecipientName);
  2446. }
  2447. if (lptstrRecipientNumber)
  2448. {
  2449. MemFree(lptstrRecipientNumber);
  2450. }
  2451. if (lptstrRecName)
  2452. {
  2453. MemFree(lptstrRecName);
  2454. }
  2455. if (lptstrRecFaxNumber)
  2456. {
  2457. MemFree(lptstrRecFaxNumber);
  2458. }
  2459. if (lptstrSubject)
  2460. {
  2461. MemFree(lptstrSubject);
  2462. }
  2463. if (lptstrDocumentFileName)
  2464. {
  2465. DeleteFile(lptstrDocumentFileName);
  2466. MemFree(lptstrDocumentFileName);
  2467. }
  2468. if (lpdwlRecipientJobIds)
  2469. {
  2470. MemFree(lpdwlRecipientJobIds);
  2471. }
  2472. if (lptszServerName)
  2473. {
  2474. MemFree(lptszServerName);
  2475. }
  2476. FaxFreeSenderInformation(&SenderProfile);
  2477. *lpdwRecipientsLimit = dwRecipientsLimit;
  2478. return dwRetVal;
  2479. }