Source code of Windows XP (NT5)
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.

2380 lines
65 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. print.c
  5. Abstract:
  6. This module contains the job
  7. specific WINFAX API functions.
  8. Author:
  9. Wesley Witt (wesw) 29-Nov-1996
  10. Revision History:
  11. --*/
  12. #include "faxapi.h"
  13. #pragma hdrstop
  14. #define InchesToCM(_x) (((_x) * 254L + 50) / 100)
  15. #define CMToInches(_x) (((_x) * 100L + 127) / 254)
  16. #define LEFT_MARGIN 1 // ---|
  17. #define RIGHT_MARGIN 1 // |
  18. #define TOP_MARGIN 1 // |---> in inches
  19. #define BOTTOM_MARGIN 1 // ---|
  20. #define FAX_DISPLAY_NAME TEXT("Fax Service")
  21. static int TiffDataWidth[] = {
  22. 0, // nothing
  23. 1, // TIFF_BYTE
  24. 1, // TIFF_ASCII
  25. 2, // TIFF_SHORT
  26. 4, // TIFF_LONG
  27. 8, // TIFF_RATIONAL
  28. 1, // TIFF_SBYTE
  29. 1, // TIFF_UNDEFINED
  30. 2, // TIFF_SSHORT
  31. 4, // TIFF_SLONG
  32. 8, // TIFF_SRATIONAL
  33. 4, // TIFF_FLOAT
  34. 8, // TIFF_DOUBLE
  35. };
  36. VOID
  37. LocalSystemTimeToSystemTime(
  38. LPSYSTEMTIME LocalSystemTime,
  39. LPSYSTEMTIME SystemTime
  40. )
  41. {
  42. FILETIME LocalFileTime;
  43. FILETIME UtcFileTime;
  44. SystemTimeToFileTime( LocalSystemTime, &LocalFileTime );
  45. LocalFileTimeToFileTime( &LocalFileTime, &UtcFileTime );
  46. FileTimeToSystemTime( &UtcFileTime, SystemTime );
  47. }
  48. LPWSTR
  49. GetFaxPrinterName(
  50. VOID
  51. )
  52. {
  53. PPRINTER_INFO_2 PrinterInfo;
  54. DWORD i;
  55. DWORD Count;
  56. PrinterInfo = (PPRINTER_INFO_2) MyEnumPrinters( NULL, 2, &Count, PRINTER_ENUM_LOCAL | PRINTER_ENUM_CONNECTIONS );
  57. if (PrinterInfo == NULL) {
  58. return NULL;
  59. }
  60. for (i=0; i<Count; i++) {
  61. if (_wcsicmp( PrinterInfo[i].pDriverName, FAX_DRIVER_NAME ) == 0 &&
  62. _wcsicmp( PrinterInfo[i].pPortName, FAX_PORT_NAME ) == 0)
  63. {
  64. LPWSTR p = (LPWSTR) StringDup( PrinterInfo[i].pPrinterName );
  65. MemFree( PrinterInfo );
  66. return p;
  67. }
  68. }
  69. MemFree( PrinterInfo );
  70. return NULL;
  71. }
  72. BOOL
  73. PrintTextFile(
  74. HDC hDC,
  75. LPWSTR FileName
  76. )
  77. /*++
  78. Routine Description:
  79. Prints a file of plain text into the printer DC provided.
  80. Note: this code was stolen from notepad.
  81. Arguments:
  82. hDC - Printer DC
  83. FileName - Text file name
  84. Return Value:
  85. TRUE for success.
  86. FALSE for failure.
  87. --*/
  88. {
  89. FILE_MAPPING fmText;
  90. LPSTR BodyText = NULL;
  91. LPSTR lpLine;
  92. LPSTR pLineEOL;
  93. LPSTR pNextLine;
  94. HFONT hFont = NULL;
  95. LOGFONT logFont;
  96. BOOL PreferredFont = TRUE;
  97. HFONT hPrevFont = NULL;
  98. TEXTMETRIC tm;
  99. BOOL rVal = TRUE;
  100. INT nLinesPerPage;
  101. INT dyTop; // width of top border (pixels)
  102. INT dyBottom; // width of bottom border
  103. INT dxLeft; // width of left border
  104. INT dxRight; // width of right border
  105. INT yPrintChar; // height of a character
  106. INT tabSize; // Size of a tab for print device in device units
  107. INT yCurpos = 0;
  108. INT xCurpos = 0;
  109. INT nPixelsLeft = 0;
  110. INT guess = 0;
  111. SIZE Size; // to see if text will fit in space left
  112. INT nPrintedLines = 0;
  113. BOOL fPageStarted = FALSE;
  114. INT iPageNum = 0;
  115. INT xPrintRes; // printer resolution in x direction
  116. INT yPrintRes; // printer resolution in y direction
  117. INT yPixInch; // pixels/inch
  118. INT xPixInch; // pixels/inch
  119. INT xPixUnit; // pixels/local measurement unit
  120. INT yPixUnit; // pixels/local measurement unit
  121. BOOL fEnglish;
  122. INT Chars;
  123. INT PrevBkMode = 0;
  124. if (!MapFileOpen( FileName, TRUE, 0, &fmText )) {
  125. return FALSE;
  126. }
  127. Chars = fmText.fSize;
  128. BodyText = fmText.fPtr;
  129. lpLine = BodyText;
  130. fEnglish = GetProfileInt( L"intl", L"iMeasure", 1 );
  131. xPrintRes = GetDeviceCaps( hDC, HORZRES );
  132. yPrintRes = GetDeviceCaps( hDC, VERTRES );
  133. xPixInch = GetDeviceCaps( hDC, LOGPIXELSX );
  134. yPixInch = GetDeviceCaps( hDC, LOGPIXELSY );
  135. //
  136. // compute x and y pixels per local measurement unit
  137. //
  138. if (fEnglish) {
  139. xPixUnit= xPixInch;
  140. yPixUnit= yPixInch;
  141. } else {
  142. xPixUnit= CMToInches( xPixInch );
  143. yPixUnit= CMToInches( yPixInch );
  144. }
  145. SetMapMode( hDC, MM_TEXT );
  146. ZeroMemory(&logFont, sizeof(logFont));
  147. logFont.lfHeight = -22; // scan lines
  148. logFont.lfWeight = FW_NORMAL;
  149. logFont.lfCharSet = DEFAULT_CHARSET;
  150. logFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
  151. logFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
  152. logFont.lfQuality = DEFAULT_QUALITY;
  153. logFont.lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
  154. hFont = CreateFontIndirect(&logFont);
  155. if (!hFont) {
  156. hFont = GetStockObject( SYSTEM_FIXED_FONT );
  157. }
  158. hPrevFont = (HFONT) SelectObject( hDC, hFont );
  159. SetBkMode( hDC, TRANSPARENT );
  160. if (!GetTextMetrics( hDC, &tm )) {
  161. rVal = FALSE;
  162. goto exit;
  163. }
  164. yPrintChar = tm.tmHeight + tm.tmExternalLeading;
  165. tabSize = tm.tmAveCharWidth * 8;
  166. //
  167. // compute margins in pixels
  168. //
  169. dxLeft = LEFT_MARGIN * xPixUnit;
  170. dxRight = RIGHT_MARGIN * xPixUnit;
  171. dyTop = TOP_MARGIN * yPixUnit;
  172. dyBottom = BOTTOM_MARGIN * yPixUnit;
  173. //
  174. // Number of lines on a page with margins
  175. //
  176. nLinesPerPage = ((yPrintRes - dyTop - dyBottom) / yPrintChar);
  177. while (*lpLine) {
  178. if (*lpLine == '\r') {
  179. lpLine += 2;
  180. yCurpos += yPrintChar;
  181. nPrintedLines++;
  182. xCurpos= 0;
  183. continue;
  184. }
  185. pLineEOL = lpLine;
  186. while (*pLineEOL && *pLineEOL != '\r') pLineEOL++;
  187. do {
  188. if ((nPrintedLines == 0) && (!fPageStarted)) {
  189. StartPage( hDC );
  190. fPageStarted = TRUE;
  191. yCurpos = 0;
  192. xCurpos = 0;
  193. }
  194. if (*lpLine == '\t') {
  195. //
  196. // round up to the next tab stop
  197. // if the current position is on the tabstop, goto next one
  198. //
  199. xCurpos = ((xCurpos + tabSize) / tabSize ) * tabSize;
  200. lpLine++;
  201. } else {
  202. //
  203. // find end of line or tab
  204. //
  205. pNextLine = lpLine;
  206. while ((pNextLine != pLineEOL) && *pNextLine != '\t') pNextLine++;
  207. //
  208. // find out how many characters will fit on line
  209. //
  210. Chars = (INT)(pNextLine - lpLine);
  211. nPixelsLeft = xPrintRes - dxRight - dxLeft - xCurpos;
  212. GetTextExtentExPointA( hDC, lpLine, Chars, nPixelsLeft, &guess, NULL, &Size );
  213. if (guess) {
  214. //
  215. // at least one character fits - print
  216. //
  217. TextOutA( hDC, dxLeft+xCurpos, yCurpos+dyTop, lpLine, guess );
  218. xCurpos += Size.cx; // account for printing
  219. lpLine += guess; // printed characters
  220. } else {
  221. //
  222. // no characters fit what's left
  223. // no characters will fit in space left
  224. // if none ever will, just print one
  225. // character to keep progressing through
  226. // input file.
  227. //
  228. if (xCurpos == 0) {
  229. if( lpLine != pNextLine ) {
  230. //
  231. // print something if not null line
  232. // could use exttextout here to clip
  233. //
  234. TextOutA( hDC, dxLeft+xCurpos, yCurpos+dyTop, lpLine, 1 );
  235. lpLine++;
  236. }
  237. } else {
  238. //
  239. // perhaps the next line will get it
  240. //
  241. xCurpos = xPrintRes; // force to next line
  242. }
  243. }
  244. //
  245. // move printhead in y-direction
  246. //
  247. if ((xCurpos >= (xPrintRes - dxRight - dxLeft) ) || (lpLine == pLineEOL)) {
  248. yCurpos += yPrintChar;
  249. nPrintedLines++;
  250. xCurpos = 0;
  251. }
  252. if (nPrintedLines >= nLinesPerPage) {
  253. EndPage( hDC );
  254. fPageStarted = FALSE;
  255. nPrintedLines = 0;
  256. xCurpos = 0;
  257. yCurpos = 0;
  258. iPageNum++;
  259. }
  260. }
  261. } while( lpLine != pLineEOL );
  262. if (*lpLine == '\r') {
  263. lpLine += 1;
  264. }
  265. if (*lpLine == '\n') {
  266. lpLine += 1;
  267. }
  268. }
  269. if (fPageStarted) {
  270. EndPage( hDC );
  271. }
  272. exit:
  273. if (fmText.fPtr) {
  274. MapFileClose( &fmText, 0 );
  275. }
  276. if (hPrevFont) {
  277. SelectObject( hDC, hPrevFont );
  278. DeleteObject( hFont );
  279. }
  280. if (PrevBkMode) {
  281. SetBkMode( hDC, PrevBkMode );
  282. }
  283. return rVal;
  284. }
  285. BOOL
  286. PrintRandomDocument(
  287. LPCWSTR FaxPrinterName,
  288. LPCWSTR DocName,
  289. LPWSTR OutputFile
  290. )
  291. /*++
  292. Routine Description:
  293. Prints a document that is attached to a message
  294. Arguments:
  295. FaxPrinterName - name of the printer to print the attachment on
  296. DocName - name of the attachment document
  297. Return Value:
  298. Print job id or zero for failure.
  299. --*/
  300. {
  301. SHELLEXECUTEINFO sei;
  302. WCHAR Args[MAX_PATH];
  303. WCHAR TempPath[MAX_PATH];
  304. HANDLE hMap = NULL;
  305. HANDLE hEvent = NULL;
  306. HANDLE hMutex = NULL;
  307. HANDLE hMutexAttach = NULL;
  308. LPDWORD pJobId = NULL;
  309. DWORD JobId = 0;
  310. BOOL bSuccess = FALSE;
  311. SECURITY_ATTRIBUTES memsa,mutsa,synsa,eventsa;
  312. SECURITY_DESCRIPTOR memsd,mutsd,synsd,eventsd;
  313. //
  314. // get the temp path name and use it for the
  315. // working dir of the launched app
  316. //
  317. if (!GetTempPath( sizeof(TempPath)/sizeof(WCHAR), TempPath )) {
  318. return FALSE;
  319. }
  320. //
  321. // serialize access to this function.
  322. // this is necessary because we have to
  323. // control access to the global shared memory region and mutex
  324. //
  325. //
  326. // serialize access to this function.
  327. // this is necessary because we can't have more than one
  328. // app accessing our shared memory region and mutex
  329. //
  330. hMutexAttach = OpenMutex(MUTEX_ALL_ACCESS,FALSE,FAXRENDER_MUTEX);
  331. if (!hMutexAttach) {
  332. //
  333. // we need to open this mutex with a NULL dacl so that everyone can access this
  334. //
  335. synsa.nLength = sizeof(SECURITY_ATTRIBUTES);
  336. synsa.bInheritHandle = TRUE;
  337. synsa.lpSecurityDescriptor = &synsd;
  338. if(!InitializeSecurityDescriptor(&synsd, SECURITY_DESCRIPTOR_REVISION)) {
  339. goto exit;
  340. }
  341. if(!SetSecurityDescriptorDacl(&synsd, TRUE, (PACL)NULL, FALSE)) {
  342. goto exit;
  343. }
  344. hMutexAttach = CreateMutex(
  345. &synsa,
  346. TRUE,
  347. FAXRENDER_MUTEX
  348. );
  349. if (!hMutexAttach) {
  350. goto exit;
  351. }
  352. } else {
  353. if (WaitForSingleObject( hMutexAttach, 1000* 60 * 5) != WAIT_OBJECT_0) {
  354. //
  355. // something went wrong
  356. //
  357. CloseHandle( hMutexAttach );
  358. goto exit;
  359. }
  360. }
  361. //
  362. // note that this is serialized inside of a critical section.
  363. // we can only have one application setting this at a time or
  364. // we'll stomp on ourselves.
  365. //
  366. //
  367. // since mapispooler might be running under a different security context,
  368. // we must setup a NULL security descriptor
  369. //
  370. memsa.nLength = sizeof(SECURITY_ATTRIBUTES);
  371. memsa.bInheritHandle = TRUE;
  372. memsa.lpSecurityDescriptor = &memsd;
  373. if(!InitializeSecurityDescriptor(&memsd, SECURITY_DESCRIPTOR_REVISION)) {
  374. goto exit;
  375. }
  376. if(!SetSecurityDescriptorDacl(&memsd, TRUE, (PACL)NULL, FALSE)) {
  377. goto exit;
  378. }
  379. mutsa.nLength = sizeof(SECURITY_ATTRIBUTES);
  380. mutsa.bInheritHandle = TRUE;
  381. mutsa.lpSecurityDescriptor = &mutsd;
  382. if(!InitializeSecurityDescriptor(&mutsd, SECURITY_DESCRIPTOR_REVISION)) {
  383. goto exit;
  384. }
  385. if(!SetSecurityDescriptorDacl(&mutsd, TRUE, (PACL)NULL, FALSE)) {
  386. goto exit;
  387. }
  388. eventsa.nLength = sizeof(SECURITY_ATTRIBUTES);
  389. eventsa.bInheritHandle = TRUE;
  390. eventsa.lpSecurityDescriptor = &eventsd;
  391. if(!InitializeSecurityDescriptor(&eventsd, SECURITY_DESCRIPTOR_REVISION)) {
  392. goto exit;
  393. }
  394. if(!SetSecurityDescriptorDacl(&eventsd, TRUE, (PACL)NULL, FALSE)) {
  395. goto exit;
  396. }
  397. //
  398. // create the shared memory region for the print jobid
  399. // the jobid is filled in by the fax printer driver
  400. //
  401. hMap = CreateFileMapping(
  402. INVALID_HANDLE_VALUE,
  403. &memsa,
  404. PAGE_READWRITE | SEC_COMMIT,
  405. 0,
  406. 4096,
  407. FAXXP_MEM_NAME
  408. );
  409. if (!hMap) {
  410. goto exit;
  411. }
  412. pJobId = (LPDWORD) MapViewOfFile(
  413. hMap,
  414. FILE_MAP_WRITE,
  415. 0,
  416. 0,
  417. 0
  418. );
  419. if (!pJobId) {
  420. goto exit;
  421. }
  422. wcscpy((LPTSTR) pJobId, OutputFile);
  423. //
  424. // set the arguments to the app.
  425. // these arguments are either passed on
  426. // the command line with the /pt switch or
  427. // use as variables for substitution in the
  428. // ddeexec value in the registry.
  429. //
  430. // the values are as follows:
  431. // %1 = file name
  432. // %2 = printer name
  433. // %3 = driver name
  434. // %4 = port name
  435. //
  436. // the first argument does not need to be
  437. // supplied in the args array because it is implied,
  438. // shellexecuteex gets it from the lpFile field.
  439. // arguments 3 & 4 are left blank because they
  440. // are win31 artifacts that are not necessary
  441. // any more. each argument must be enclosed
  442. // in double quotes.
  443. //
  444. wsprintf( Args, L"\"%s\" \"\" \"\"", FaxPrinterName );
  445. //
  446. // fill in the SHELLEXECUTEINFO structure
  447. //
  448. sei.cbSize = sizeof(sei);
  449. sei.fMask = SEE_MASK_FLAG_NO_UI | SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_DDEWAIT;
  450. sei.hwnd = NULL;
  451. sei.lpVerb = L"printto";
  452. sei.lpFile = DocName;
  453. sei.lpParameters = Args;
  454. sei.lpDirectory = TempPath;
  455. sei.nShow = SW_SHOWMINNOACTIVE;
  456. sei.hInstApp = NULL;
  457. sei.lpIDList = NULL;
  458. sei.lpClass = NULL;
  459. sei.hkeyClass = NULL;
  460. sei.dwHotKey = 0;
  461. sei.hIcon = NULL;
  462. sei.hProcess = NULL;
  463. //
  464. // create the named mutex for the print driver.
  465. // this is initially unclaimed, and is claimed by the first instance
  466. // of the print driver invoked after this. We do this last in order to
  467. // avoid a situation where we catch the incorrect instance of the print driver
  468. // printing
  469. //
  470. hMutex = CreateMutex(
  471. &mutsa,
  472. FALSE,
  473. FAXXP_MUTEX_NAME
  474. );
  475. if (!hMutex) {
  476. goto exit;
  477. }
  478. //
  479. // create the named event for the print driver.
  480. // this event is signaled when the print driver is finished rendering the document
  481. //
  482. hEvent = CreateEvent(
  483. &eventsa,
  484. FALSE,
  485. FALSE,
  486. FAXXP_EVENT_NAME
  487. );
  488. if (!hEvent) {
  489. goto exit;
  490. }
  491. //
  492. // launch the app
  493. //
  494. if (!ShellExecuteEx( &sei )) {
  495. goto exit;
  496. }
  497. //
  498. // wait for the print driver to finish rendering the document
  499. //
  500. if (WaitForSingleObject( hEvent, 1000 * 60 * 5 ) != WAIT_OBJECT_0) {
  501. //
  502. // something went wrong...
  503. //
  504. goto exit;
  505. }
  506. //
  507. // wait for the print driver to exit so we can get the document
  508. //
  509. if (WaitForSingleObject( hMutex, 1000 * 60 * 5) != WAIT_OBJECT_0) {
  510. //
  511. // something went wrong
  512. //
  513. goto exit;
  514. }
  515. ReleaseMutex(hMutex);
  516. //
  517. // save the print jobid
  518. //
  519. JobId = *pJobId;
  520. bSuccess = TRUE;
  521. exit:
  522. //
  523. // clean up and leave...
  524. //
  525. if (sei.hProcess) CloseHandle( sei.hProcess );
  526. if (hEvent) CloseHandle( hEvent );
  527. if (hMutex) CloseHandle( hMutex );
  528. if (pJobId) UnmapViewOfFile( pJobId );
  529. if (hMap) CloseHandle( hMap );
  530. if (hMutexAttach) {
  531. ReleaseMutex( hMutexAttach );
  532. CloseHandle( hMutexAttach );
  533. }
  534. if (!bSuccess) {
  535. SetLastError(ERROR_INVALID_DATA);
  536. }
  537. return bSuccess;
  538. }
  539. BOOL
  540. CreateCoverpageTiffFile(
  541. IN const FAX_COVERPAGE_INFOW *CoverpageInfo,
  542. OUT LPWSTR CovTiffFile
  543. )
  544. {
  545. WCHAR TempPath[MAX_PATH];
  546. WCHAR TempFile[MAX_PATH];
  547. LPWSTR FaxPrinter;
  548. FAX_PRINT_INFOW PrintInfo;
  549. FAX_CONTEXT_INFOW ContextInfo;
  550. DWORD TmpFaxJobId;
  551. BOOL Rslt;
  552. TempFile[0] = 0;
  553. FaxPrinter = GetFaxPrinterName();
  554. if (FaxPrinter == NULL) {
  555. return FALSE;
  556. }
  557. if (!GetTempPath( sizeof(TempPath)/sizeof(WCHAR), TempPath ) ||
  558. !GetTempFileName( TempPath, L"fax", 0, TempFile ))
  559. {
  560. return FALSE;
  561. }
  562. ZeroMemory( &PrintInfo, sizeof(FAX_PRINT_INFO) );
  563. PrintInfo.SizeOfStruct = sizeof(FAX_PRINT_INFO);
  564. PrintInfo.OutputFileName = TempFile;
  565. ZeroMemory( &ContextInfo, sizeof(FAX_CONTEXT_INFOW) );
  566. ContextInfo.SizeOfStruct = sizeof(FAX_CONTEXT_INFOW);
  567. if (!FaxStartPrintJobW( FaxPrinter, &PrintInfo, &TmpFaxJobId, &ContextInfo )) {
  568. DeleteFile( TempFile );
  569. return FALSE;
  570. }
  571. Rslt = FaxPrintCoverPageW( &ContextInfo, CoverpageInfo );
  572. EndDoc( ContextInfo.hDC );
  573. DeleteDC( ContextInfo.hDC );
  574. if (!Rslt) {
  575. DeleteFile( TempFile );
  576. return FALSE;
  577. }
  578. wcscpy( CovTiffFile, TempFile );
  579. return TRUE;
  580. }
  581. BOOL
  582. CreateFinalTiffFile(
  583. IN LPWSTR FileName,
  584. OUT LPWSTR FinalTiffFile,
  585. IN const FAX_COVERPAGE_INFOW *CoverpageInfo
  586. )
  587. {
  588. WCHAR TempPath[MAX_PATH];
  589. WCHAR FullPath[MAX_PATH];
  590. WCHAR TempFile[MAX_PATH];
  591. WCHAR TiffFile[MAX_PATH];
  592. LPWSTR FaxPrinter = NULL;
  593. FAX_PRINT_INFOW PrintInfo;
  594. DWORD TmpFaxJobId;
  595. FAX_CONTEXT_INFOW ContextInfo;
  596. LPWSTR p;
  597. DWORD Flags = 0;
  598. BOOL Rslt;
  599. //
  600. // make sure that the tiff file passed in is a valid tiff file
  601. //
  602. if (!GetTempPath( sizeof(TempPath)/sizeof(WCHAR), TempPath )) {
  603. return FALSE;
  604. }
  605. if (GetTempFileName( TempPath, L"fax", 0, TempFile ) == 0 ||
  606. GetFullPathName( TempFile, sizeof(FullPath)/sizeof(WCHAR), FullPath, &p ) == 0)
  607. {
  608. return FALSE;
  609. }
  610. if (!ConvertTiffFileToValidFaxFormat( FileName, FullPath, &Flags )) {
  611. if ((Flags & TIFFCF_NOT_TIFF_FILE) == 0) {
  612. Flags = TIFFCF_NOT_TIFF_FILE;
  613. }
  614. }
  615. if (Flags & TIFFCF_NOT_TIFF_FILE) {
  616. //
  617. // try to output the source file into a tiff file,
  618. // by printing to the fax printer in "file" mode
  619. //
  620. FaxPrinter = GetFaxPrinterName();
  621. if (FaxPrinter == NULL) {
  622. DeleteFile( FullPath );
  623. SetLastError( ERROR_INVALID_FUNCTION );
  624. return FALSE;
  625. }
  626. if (!PrintRandomDocument( FaxPrinter, FileName, FullPath )) {
  627. DeleteFile( FullPath );
  628. SetLastError( ERROR_INVALID_FUNCTION );
  629. return FALSE;
  630. }
  631. wcscpy( TiffFile, FullPath );
  632. } else if (Flags & TIFFCF_UNCOMPRESSED_BITS) {
  633. if (FaxPrinter == NULL) {
  634. FaxPrinter = GetFaxPrinterName();
  635. if (FaxPrinter == NULL) {
  636. DeleteFile( FullPath );
  637. SetLastError( ERROR_INVALID_FUNCTION );
  638. return FALSE;
  639. }
  640. }
  641. if (Flags & TIFFCF_ORIGINAL_FILE_GOOD) {
  642. //
  643. // nothing at fullpath, just delete it and use the original source
  644. //
  645. DeleteFile( FullPath );
  646. wcscpy( TiffFile, FileName );
  647. } else {
  648. wcscpy( TiffFile, FullPath );
  649. }
  650. if (GetTempFileName( TempPath, L"fax", 0, TempFile ) == 0 ||
  651. GetFullPathName( TempFile, sizeof(FullPath)/sizeof(WCHAR), FullPath, &p ) == 0)
  652. {
  653. DeleteFile( TiffFile );
  654. return FALSE;
  655. }
  656. ZeroMemory( &PrintInfo, sizeof(FAX_PRINT_INFOW) );
  657. PrintInfo.SizeOfStruct = sizeof(FAX_PRINT_INFOW);
  658. PrintInfo.OutputFileName = FullPath;
  659. ZeroMemory( &ContextInfo, sizeof(FAX_CONTEXT_INFOW) );
  660. ContextInfo.SizeOfStruct = sizeof(FAX_CONTEXT_INFOW);
  661. if (!FaxStartPrintJobW( FaxPrinter, &PrintInfo, &TmpFaxJobId, &ContextInfo )) {
  662. if ((Flags & TIFFCF_ORIGINAL_FILE_GOOD) == 0) DeleteFile( TiffFile );
  663. DeleteFile( FullPath );
  664. SetLastError( ERROR_INVALID_FUNCTION );
  665. return FALSE;
  666. }
  667. Rslt = PrintTiffFile( ContextInfo.hDC, TiffFile );
  668. EndDoc( ContextInfo.hDC );
  669. DeleteDC( ContextInfo.hDC );
  670. if ((Flags & TIFFCF_ORIGINAL_FILE_GOOD) == 0) {
  671. DeleteFile( TiffFile );
  672. }
  673. if (!Rslt) {
  674. DeleteFile( FullPath );
  675. SetLastError( ERROR_INVALID_FUNCTION );
  676. return FALSE;
  677. }
  678. wcscpy( TiffFile, FullPath );
  679. } else if (Flags & TIFFCF_ORIGINAL_FILE_GOOD) {
  680. //
  681. // we didn't create anything at FullPath, just use FileName
  682. //
  683. DeleteFile( FullPath );
  684. wcscpy( TiffFile, FileName );
  685. } else {
  686. //
  687. // should never hit this case
  688. //
  689. DeleteFile( FullPath );
  690. SetLastError( ERROR_INVALID_FUNCTION );
  691. return FALSE;
  692. }
  693. //
  694. // if a coverpage is specified then print the coverpage first
  695. //
  696. if (CoverpageInfo && CoverpageInfo->CoverPageName) {
  697. if (!CreateCoverpageTiffFile( CoverpageInfo, TempFile )) {
  698. if (wcscmp(FileName,TiffFile) != 0) DeleteFile( TiffFile );
  699. DeleteFile( TempFile );
  700. return FALSE;
  701. }
  702. if (!MergeTiffFiles( TempFile, TiffFile )) {
  703. if (wcscmp(FileName,TiffFile) != 0) DeleteFile( TiffFile );
  704. DeleteFile( TempFile );
  705. return FALSE;
  706. }
  707. FileName = TempFile;
  708. } else {
  709. FileName = TiffFile;
  710. }
  711. wcscpy( FinalTiffFile, FileName );
  712. return TRUE;
  713. }
  714. BOOL
  715. CopyFileToServerQueue(
  716. IN const HANDLE FaxHandle,
  717. IN LPCWSTR TiffFile,
  718. IN LPWSTR QueueFileName
  719. )
  720. {
  721. error_status_t ec;
  722. WCHAR FullPath[MAX_PATH];
  723. //
  724. // get a file name from the fax server
  725. //
  726. ec = FAX_GetQueueFileName( FH_FAX_HANDLE(FaxHandle), QueueFileName, MAX_PATH );
  727. if (ec) {
  728. SetLastError( ec );
  729. return FALSE;
  730. }
  731. //
  732. // create the full path to the new file
  733. //
  734. if (!IsLocalFaxConnection(FaxHandle)) {
  735. //
  736. // remote file
  737. //
  738. swprintf( FullPath, FAX_QUEUE_PATH, FH_DATA(FaxHandle)->MachineName, QueueFileName );
  739. } else {
  740. //
  741. // local file
  742. //
  743. if (!GetSpecialPath( CSIDL_COMMON_APPDATA, FullPath )) {
  744. return FALSE;
  745. }
  746. ConcatenatePaths( FullPath, FAX_QUEUE_DIR );
  747. ConcatenatePaths( FullPath, QueueFileName );
  748. }
  749. //
  750. // copy the file to the fax server queue dir
  751. //
  752. if (!CopyFile( TiffFile, FullPath, FALSE )) {
  753. return FALSE;
  754. }
  755. SetFileAttributes( FullPath, (GetFileAttributes( FullPath ) & (0xFFFFFFFF^FILE_ATTRIBUTE_READONLY)) | FILE_ATTRIBUTE_NORMAL );
  756. return TRUE;
  757. }
  758. DWORD
  759. GetLineId(
  760. FARPROC LineGetId,
  761. HCALL CallHandle
  762. )
  763. {
  764. LPVARSTRING DeviceId;
  765. long rslt = 0;
  766. DWORD LineId;
  767. //
  768. // get the deviceID associated with the call handle
  769. //
  770. DeviceId = MemAlloc(sizeof(VARSTRING)+1000);
  771. if (!DeviceId) {
  772. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  773. return 0;
  774. }
  775. DeviceId->dwTotalSize=sizeof(VARSTRING) +1000;
  776. rslt = (DWORD)LineGetId(NULL,0,(HCALL) CallHandle,LINECALLSELECT_CALL,DeviceId,L"tapi/line");
  777. if (rslt < 0) {
  778. DebugPrint((TEXT("LineGetId() failed, ec = %x\n"),rslt));
  779. MemFree(DeviceId);
  780. SetLastError(ERROR_INVALID_PARAMETER);
  781. return 0;
  782. }
  783. if (DeviceId->dwStringFormat != STRINGFORMAT_BINARY ) {
  784. MemFree(DeviceId);
  785. SetLastError(ERROR_INVALID_PARAMETER);
  786. return 0;
  787. }
  788. LineId = (DWORD) *((LPBYTE)DeviceId + DeviceId->dwStringOffset);
  789. MemFree(DeviceId);
  790. return LineId;
  791. }
  792. BOOL
  793. WINAPI
  794. FaxSendDocumentW(
  795. IN HANDLE FaxHandle,
  796. IN LPCWSTR FileName,
  797. IN FAX_JOB_PARAMW *JobParams,
  798. IN const FAX_COVERPAGE_INFOW *CoverpageInfo,
  799. OUT LPDWORD FaxJobId
  800. )
  801. /*++
  802. Routine Description:
  803. Sends a FAX document to the specified recipient.
  804. This is an asychronous operation. Use FaxReportStatus
  805. to determine when the send is completed.
  806. Arguments:
  807. FaxHandle - FAX handle obtained from FaxConnectFaxServer.
  808. FileName - File containing the TIFF-F FAX document.
  809. JobParams - pointer to FAX_JOB_PARAM structure with transmission params
  810. CoverpageInfo - optional pointer to FAX_COVERPAGE_INFO structure
  811. FaxJobId - receives the Fax JobId for the job.
  812. Return Value:
  813. TRUE - Success
  814. FALSE - Failure, call GetLastError() for more error information.
  815. --*/
  816. {
  817. error_status_t ec;
  818. WCHAR QueueFileName[MAX_PATH];
  819. WCHAR ExistingFile[MAX_PATH];
  820. DWORD rc;
  821. LPWSTR p;
  822. WCHAR TiffFile[MAX_PATH];
  823. HINSTANCE hTapiLib = NULL;
  824. WCHAR TapiPath[MAX_PATH];
  825. WCHAR MutexName[64];
  826. HANDLE hLineMutex = NULL;
  827. FARPROC LineHandoff;
  828. FARPROC LineGetId;
  829. IUnknown* pDisp=NULL;
  830. ITBasicCallControl* pCallControl;
  831. ITCallInfo* pCallInfo;
  832. ITAddress* pAddressInfo;
  833. ITAddressCapabilities* pAddressCaps;
  834. CALL_STATE CallState;
  835. BSTR FaxSvcName;
  836. HRESULT hr;
  837. DWORD LineId;
  838. DWORD _JobId;
  839. DWORD Event = 0;
  840. long rslt = 0;
  841. //
  842. // argument validation
  843. //
  844. if (!ValidateFaxHandle(FaxHandle, FHT_SERVICE)) {
  845. SetLastError(ERROR_INVALID_HANDLE);
  846. return FALSE;
  847. }
  848. if (!FileName || !JobParams || JobParams->SizeOfStruct != sizeof(FAX_JOB_PARAMW)) {
  849. SetLastError(ERROR_INVALID_PARAMETER);
  850. return FALSE;
  851. }
  852. if (JobParams->ScheduleAction != JSA_NOW &&
  853. JobParams->ScheduleAction != JSA_SPECIFIC_TIME &&
  854. JobParams->ScheduleAction != JSA_DISCOUNT_PERIOD) {
  855. SetLastError(ERROR_INVALID_PARAMETER);
  856. return FALSE;
  857. }
  858. if (JobParams->DeliveryReportType != DRT_NONE &&
  859. JobParams->DeliveryReportType != DRT_EMAIL &&
  860. JobParams->DeliveryReportType != DRT_INBOX ) {
  861. SetLastError(ERROR_INVALID_PARAMETER);
  862. return FALSE;
  863. }
  864. //
  865. // make sure the file is there
  866. //
  867. rc = GetFullPathName(FileName,sizeof(ExistingFile)/sizeof(WCHAR),ExistingFile,&p);
  868. if (rc > MAX_PATH || rc == 0) {
  869. DebugPrint(( TEXT("GetFullPathName failed, ec= %d\n"),GetLastError() ));
  870. SetLastError( (rc > MAX_PATH)
  871. ? ERROR_BUFFER_OVERFLOW
  872. : GetLastError() );
  873. return FALSE;
  874. }
  875. if (GetFileAttributes(ExistingFile)==0xFFFFFFFF) {
  876. SetLastError(ERROR_FILE_NOT_FOUND);
  877. return FALSE;
  878. }
  879. //
  880. // if they want a coverpage, try to validate it
  881. //
  882. if (CoverpageInfo &&
  883. !ValidateCoverpage(CoverpageInfo->CoverPageName,
  884. IsLocalFaxConnection(FaxHandle) ? NULL : FH_DATA(FaxHandle)->MachineName,
  885. CoverpageInfo->UseServerCoverPage,
  886. NULL)) {
  887. SetLastError(ERROR_FILE_NOT_FOUND);
  888. return FALSE;
  889. }
  890. if (JobParams->CallHandle != 0 || JobParams->Reserved[0]==0xFFFF1234) {
  891. //
  892. // we don't support call handoff if it's a remote server connection
  893. //
  894. if (!IsLocalFaxConnection(FaxHandle)) {
  895. SetLastError(ERROR_INVALID_FUNCTION);
  896. return FALSE;
  897. }
  898. if (JobParams->CallHandle) {
  899. //
  900. // tapi is dynamic
  901. //
  902. ExpandEnvironmentStrings(TAPI_LIBRARY,TapiPath,MAX_PATH);
  903. hTapiLib = LoadLibrary(TapiPath);
  904. if (!hTapiLib) {
  905. SetLastError(ERROR_INVALID_LIBRARY);
  906. return FALSE;
  907. }
  908. LineHandoff = GetProcAddress(hTapiLib,"lineHandoffW");
  909. LineGetId = GetProcAddress(hTapiLib,"lineGetIDW");
  910. if (!LineHandoff || !LineGetId) {
  911. FreeLibrary(hTapiLib);
  912. SetLastError(ERROR_INVALID_FUNCTION);
  913. return FALSE;
  914. }
  915. //
  916. // get the line ID
  917. //
  918. LineId = GetLineId(LineGetId,JobParams->CallHandle);
  919. if (LineId) {
  920. JobParams->Reserved[2] = LineId;
  921. } else {
  922. FreeLibrary(hTapiLib);
  923. SetLastError(ERROR_INVALID_FUNCTION);
  924. return FALSE;
  925. }
  926. } else if (JobParams->Reserved[1]) {
  927. //
  928. // GetDeviceId from tapi3 dispinterface
  929. //
  930. pDisp = (IUnknown*) JobParams->Reserved[1];
  931. hr = pDisp->lpVtbl->QueryInterface( pDisp, &IID_ITCallInfo, (void**)&pCallInfo );
  932. if (FAILED(hr)) {
  933. SetLastError(ERROR_INVALID_PARAMETER);
  934. return FALSE;
  935. }
  936. if (FAILED(pCallInfo->lpVtbl->get_CallState(pCallInfo,&CallState))) {
  937. pCallInfo->lpVtbl->Release(pCallInfo);
  938. SetLastError(ERROR_INVALID_PARAMETER);
  939. return FALSE;
  940. }
  941. if (CallState != CS_CONNECTED) {
  942. DebugPrint(( TEXT("callstate(%d) is invalid, cannot handoff job\n"),CallState ));
  943. pCallInfo->lpVtbl->Release(pCallInfo);
  944. SetLastError(ERROR_INVALID_PARAMETER);
  945. return FALSE;
  946. }
  947. if (FAILED(pCallInfo->lpVtbl->get_Address(pCallInfo,&pAddressInfo))) {
  948. pCallInfo->lpVtbl->Release(pCallInfo);
  949. SetLastError(ERROR_INVALID_PARAMETER);
  950. return FALSE;
  951. }
  952. if (FAILED(pAddressInfo->lpVtbl->QueryInterface(pAddressInfo, &IID_ITAddressCapabilities, (void**)&pAddressCaps))) {
  953. pCallInfo->lpVtbl->Release(pCallInfo);
  954. pAddressInfo->lpVtbl->Release(pAddressInfo);
  955. SetLastError(ERROR_INVALID_PARAMETER);
  956. return FALSE;
  957. }
  958. if (FAILED(pAddressCaps->lpVtbl->get_AddressCapability( pAddressCaps, AC_LINEID, &LineId ))) {
  959. pCallInfo->lpVtbl->Release(pCallInfo);
  960. pAddressInfo->lpVtbl->Release(pAddressInfo);
  961. pAddressCaps->lpVtbl->Release(pAddressCaps);
  962. SetLastError(ERROR_INVALID_PARAMETER);
  963. return FALSE;
  964. }
  965. if (LineId == 0) {
  966. pCallInfo->lpVtbl->Release(pCallInfo);
  967. pAddressInfo->lpVtbl->Release(pAddressInfo);
  968. pAddressCaps->lpVtbl->Release(pAddressCaps);
  969. SetLastError(ERROR_INVALID_PARAMETER);
  970. return FALSE;
  971. }
  972. JobParams->Reserved[2] = LineId;
  973. pCallInfo->lpVtbl->Release(pCallInfo);
  974. pAddressInfo->lpVtbl->Release(pAddressInfo);
  975. pAddressCaps->lpVtbl->Release(pAddressCaps);
  976. } else {
  977. SetLastError(ERROR_INVALID_PARAMETER);
  978. return FALSE;
  979. }
  980. DebugPrint((TEXT("device ID = %d\n"),JobParams->Reserved[2]));
  981. //
  982. // we need a mutex to ensure fax service owns the line before calling lineHandoff
  983. //
  984. wsprintf(MutexName,L"FaxLineHandoff%d",JobParams->Reserved[2]);
  985. hLineMutex = CreateMutex(NULL,FALSE,MutexName);
  986. if (!hLineMutex) {
  987. FreeLibrary(hTapiLib);
  988. return FALSE;
  989. }
  990. } else {
  991. //
  992. // this is a normal fax...validate the fax number.
  993. //
  994. if (!JobParams->RecipientNumber) {
  995. SetLastError(ERROR_INVALID_PARAMETER);
  996. return FALSE;
  997. }
  998. }
  999. //
  1000. // make sure that the tiff file passed in is a valid tiff file
  1001. //
  1002. ZeroMemory(TiffFile,sizeof(TiffFile));
  1003. if (!CreateFinalTiffFile( (LPWSTR) ExistingFile, TiffFile, CoverpageInfo )) {
  1004. DeleteFile( TiffFile );
  1005. if (hTapiLib) {
  1006. FreeLibrary(hTapiLib);
  1007. }
  1008. if (hLineMutex) {
  1009. CloseHandle(hLineMutex);
  1010. }
  1011. SetLastError(ERROR_INVALID_DATA);
  1012. return FALSE;
  1013. }
  1014. //
  1015. // copy the file to the server's queue dir
  1016. //
  1017. if (!CopyFileToServerQueue( FaxHandle, TiffFile, QueueFileName )) {
  1018. if (hTapiLib) {
  1019. FreeLibrary(hTapiLib);
  1020. }
  1021. if (hLineMutex) {
  1022. CloseHandle(hLineMutex);
  1023. }
  1024. return FALSE;
  1025. }
  1026. //
  1027. // the passed in file should be treated as read-only
  1028. // if we created a temp file then delete it
  1029. //
  1030. if (wcscmp(ExistingFile,TiffFile) != 0) {
  1031. DeleteFile( TiffFile );
  1032. }
  1033. //
  1034. // queue the fax to be sent
  1035. //
  1036. if (JobParams->Reserved[0] != 0xffffffff)
  1037. {
  1038. JobParams->Reserved[0] = 0;
  1039. JobParams->Reserved[1] = 0;
  1040. }
  1041. if (JobParams->ScheduleAction == JSA_SPECIFIC_TIME) {
  1042. //
  1043. // convert the system time from local to utc
  1044. //
  1045. LocalSystemTimeToSystemTime( &JobParams->ScheduleTime, &JobParams->ScheduleTime );
  1046. }
  1047. ec = FAX_SendDocument( FH_FAX_HANDLE(FaxHandle), QueueFileName, JobParams, &_JobId );
  1048. if (ec) {
  1049. SetLastError( ec );
  1050. if (hTapiLib) {
  1051. FreeLibrary(hTapiLib);
  1052. }
  1053. if (hLineMutex) {
  1054. CloseHandle(hLineMutex);
  1055. }
  1056. return FALSE;
  1057. }
  1058. if (FaxJobId) {
  1059. *FaxJobId = _JobId;
  1060. }
  1061. //
  1062. // we're done if it's a normal call
  1063. //
  1064. if (JobParams->CallHandle == 0 && !pDisp) {
  1065. return TRUE;
  1066. }
  1067. //
  1068. // wait for Mutex to get signalled
  1069. //
  1070. DebugPrint((TEXT("Waiting for mutex \"FaxLineHandoff%d\""),JobParams->Reserved[2]));
  1071. Event = WaitForSingleObject(hLineMutex,INFINITE);
  1072. if (Event != WAIT_OBJECT_0 ) {
  1073. //
  1074. // bail out, we couldn't open the line?
  1075. //
  1076. }
  1077. //
  1078. // handoff the call to the fax service, FSP must change media mode appropriately
  1079. //
  1080. if (JobParams->CallHandle) {
  1081. //
  1082. // TAPI 2.0 handoff
  1083. //
  1084. DebugPrint((TEXT("Handing off call %x to faxsvc"),JobParams->CallHandle));
  1085. rslt = (long)LineHandoff(JobParams->CallHandle, FAX_DISPLAY_NAME , 0 );
  1086. FreeLibrary(hTapiLib);
  1087. CloseHandle(hLineMutex);
  1088. if (rslt != 0) {
  1089. SetLastError(rslt);
  1090. return FALSE;
  1091. }
  1092. } else {
  1093. //
  1094. // TAPI 3.0 handoff
  1095. //
  1096. pDisp->lpVtbl->QueryInterface( pDisp, &IID_ITBasicCallControl, (void**)&pCallControl );
  1097. if (FAILED(hr)) {
  1098. SetLastError(ERROR_INVALID_FUNCTION);
  1099. return FALSE;
  1100. }
  1101. FaxSvcName = SysAllocString( FAX_DISPLAY_NAME );
  1102. hr = pCallControl->lpVtbl->HandoffDirect(pCallControl,FaxSvcName);
  1103. pCallControl->lpVtbl->Release(pCallControl);
  1104. SysFreeString( FaxSvcName );
  1105. if (FAILED(hr)) {
  1106. DebugPrint((TEXT("call handoff failed, ec = %x"),hr));
  1107. return FALSE;
  1108. }
  1109. }
  1110. return TRUE;
  1111. }
  1112. WINFAXAPI
  1113. BOOL
  1114. WINAPI
  1115. FaxSendDocumentForBroadcastW(
  1116. IN HANDLE FaxHandle,
  1117. IN LPCWSTR FileName,
  1118. OUT LPDWORD FaxJobId,
  1119. IN PFAX_RECIPIENT_CALLBACKW FaxRecipientCallback,
  1120. IN LPVOID Context
  1121. )
  1122. {
  1123. error_status_t ec;
  1124. WCHAR TempFile[MAX_PATH];
  1125. WCHAR TiffFile[MAX_PATH];
  1126. WCHAR CovFileName[MAX_PATH];
  1127. WCHAR BodyFileName[MAX_PATH];
  1128. WCHAR ExistingFile[MAX_PATH];
  1129. DWORD rc;
  1130. LPWSTR p;
  1131. FAX_JOB_PARAMW JobParams;
  1132. FAX_COVERPAGE_INFOW CoverpageInfo;
  1133. DWORD TmpFaxJobId;
  1134. DWORD BcFaxJobId = 0;
  1135. DWORD i = 1;
  1136. HANDLE hTiff = NULL;
  1137. TIFF_INFO TiffInfo;
  1138. DWORD PageCount;
  1139. if (!ValidateFaxHandle(FaxHandle, FHT_SERVICE)) {
  1140. SetLastError(ERROR_INVALID_HANDLE);
  1141. return FALSE;
  1142. }
  1143. if (!FileName || !FaxRecipientCallback) {
  1144. SetLastError (ERROR_INVALID_PARAMETER);
  1145. return FALSE;
  1146. }
  1147. //
  1148. // make sure the file is there
  1149. //
  1150. rc = GetFullPathName(FileName,sizeof(ExistingFile)/sizeof(WCHAR),ExistingFile,&p);
  1151. if (rc > MAX_PATH || rc == 0) {
  1152. DebugPrint(( TEXT("GetFullPathName failed, ec= %d\n"),GetLastError() ));
  1153. SetLastError( (rc > MAX_PATH)
  1154. ? ERROR_BUFFER_OVERFLOW
  1155. : GetLastError() );
  1156. return FALSE;
  1157. }
  1158. if (GetFileAttributes(ExistingFile)==0xFFFFFFFF) {
  1159. SetLastError(ERROR_FILE_NOT_FOUND);
  1160. return FALSE;
  1161. }
  1162. ZeroMemory(TiffFile,sizeof(TiffFile));
  1163. if (!CreateFinalTiffFile( (LPWSTR) ExistingFile, TiffFile, NULL)) {
  1164. DeleteFile( TiffFile );
  1165. SetLastError(ERROR_INVALID_DATA);
  1166. return FALSE;
  1167. }
  1168. hTiff = TiffOpen( TiffFile, &TiffInfo, TRUE, FILLORDER_MSB2LSB );
  1169. if (hTiff == NULL) {
  1170. DeleteFile( TiffFile );
  1171. SetLastError(ERROR_INVALID_DATA);
  1172. return FALSE;
  1173. }
  1174. PageCount = TiffInfo.PageCount;
  1175. TiffClose( hTiff );
  1176. if (!CopyFileToServerQueue( FaxHandle, TiffFile, BodyFileName )) {
  1177. DeleteFile( TiffFile );
  1178. return FALSE;
  1179. }
  1180. //
  1181. // the passed in file should be treated as read-only
  1182. // if we created a temp file then delete it
  1183. //
  1184. if (wcscmp(ExistingFile,TiffFile) != 0) {
  1185. DeleteFile( TiffFile );
  1186. }
  1187. ZeroMemory( &JobParams, sizeof(JobParams) );
  1188. JobParams.SizeOfStruct = sizeof(JobParams);
  1189. JobParams.Reserved[0] = 0xfffffffe;
  1190. JobParams.Reserved[1] = 1;
  1191. JobParams.Reserved[2] = 0;
  1192. ec = FAX_SendDocument( FH_FAX_HANDLE(FaxHandle), BodyFileName, &JobParams, &BcFaxJobId );
  1193. if (ec) {
  1194. SetLastError( ec );
  1195. return FALSE;
  1196. }
  1197. if (FaxJobId) {
  1198. *FaxJobId = BcFaxJobId;
  1199. }
  1200. while (TRUE) {
  1201. ZeroMemory( &JobParams, sizeof(JobParams) );
  1202. JobParams.SizeOfStruct = sizeof(JobParams);
  1203. ZeroMemory( &CoverpageInfo, sizeof(CoverpageInfo) );
  1204. CoverpageInfo.SizeOfStruct = sizeof(CoverpageInfo);
  1205. if (!FaxRecipientCallback( FaxHandle, i, Context, &JobParams, &CoverpageInfo )) {
  1206. break;
  1207. }
  1208. if (JobParams.RecipientNumber == NULL) {
  1209. continue;
  1210. }
  1211. JobParams.Reserved[0] = 0xfffffffe;
  1212. JobParams.Reserved[1] = 2;
  1213. JobParams.Reserved[2] = BcFaxJobId;
  1214. CoverpageInfo.PageCount = PageCount + 1;
  1215. GetLocalTime( &CoverpageInfo.TimeSent );
  1216. if (CreateCoverpageTiffFile( &CoverpageInfo, TempFile )) {
  1217. if (CopyFileToServerQueue( FaxHandle, TempFile, CovFileName )) {
  1218. ec = FAX_SendDocument( FH_FAX_HANDLE(FaxHandle), CovFileName, &JobParams, &TmpFaxJobId );
  1219. if (ec) {
  1220. DeleteFile( TempFile );
  1221. SetLastError( ec );
  1222. return FALSE;
  1223. }
  1224. }
  1225. DeleteFile( TempFile );
  1226. } else {
  1227. ec = FAX_SendDocument( FH_FAX_HANDLE(FaxHandle), NULL, &JobParams, &TmpFaxJobId );
  1228. if (ec) {
  1229. SetLastError( ec );
  1230. return FALSE;
  1231. }
  1232. }
  1233. i += 1;
  1234. }
  1235. return TRUE;
  1236. }
  1237. BOOL
  1238. ConvertCoverpageAndJobInfo(PFAX_JOB_PARAMW JobParams,PFAX_COVERPAGE_INFOW CoverpageInfo)
  1239. {
  1240. #define MyConvertString(TargetString) if (TargetString) { \
  1241. TargetString = AnsiStringToUnicodeString((LPCSTR) TargetString); \
  1242. }
  1243. MyConvertString(JobParams->RecipientNumber);
  1244. MyConvertString(JobParams->RecipientName);
  1245. MyConvertString(JobParams->Tsid);
  1246. MyConvertString(JobParams->SenderName);
  1247. MyConvertString(JobParams->SenderDept);
  1248. MyConvertString(JobParams->SenderCompany);
  1249. MyConvertString(JobParams->BillingCode);
  1250. MyConvertString(JobParams->DeliveryReportAddress);
  1251. MyConvertString(JobParams->DocumentName);
  1252. MyConvertString(CoverpageInfo->CoverPageName);
  1253. MyConvertString(CoverpageInfo->RecName);
  1254. MyConvertString(CoverpageInfo->RecFaxNumber);
  1255. MyConvertString(CoverpageInfo->RecCompany);
  1256. MyConvertString(CoverpageInfo->RecStreetAddress);
  1257. MyConvertString(CoverpageInfo->RecCity);
  1258. MyConvertString(CoverpageInfo->RecState);
  1259. MyConvertString(CoverpageInfo->RecZip);
  1260. MyConvertString(CoverpageInfo->RecCountry);
  1261. MyConvertString(CoverpageInfo->RecTitle);
  1262. MyConvertString(CoverpageInfo->RecDepartment);
  1263. MyConvertString(CoverpageInfo->RecOfficeLocation);
  1264. MyConvertString(CoverpageInfo->RecHomePhone);
  1265. MyConvertString(CoverpageInfo->RecOfficePhone);
  1266. MyConvertString(CoverpageInfo->SdrName);
  1267. MyConvertString(CoverpageInfo->SdrFaxNumber);
  1268. MyConvertString(CoverpageInfo->SdrCompany);
  1269. MyConvertString(CoverpageInfo->SdrAddress);
  1270. MyConvertString(CoverpageInfo->SdrTitle);
  1271. MyConvertString(CoverpageInfo->SdrDepartment);
  1272. MyConvertString(CoverpageInfo->SdrOfficeLocation);
  1273. MyConvertString(CoverpageInfo->SdrHomePhone);
  1274. MyConvertString(CoverpageInfo->SdrOfficePhone);
  1275. MyConvertString(CoverpageInfo->Note);
  1276. MyConvertString(CoverpageInfo->Subject);
  1277. return TRUE;
  1278. }
  1279. BOOL
  1280. FreeCoverpageAndJobInfo(PFAX_JOB_PARAMW JobParams,PFAX_COVERPAGE_INFOW CoverpageInfo) {
  1281. #define MyFreeString(TargetString) if (TargetString) { \
  1282. MemFree( (LPBYTE) TargetString); \
  1283. }
  1284. MyFreeString(JobParams->RecipientNumber);
  1285. MyFreeString(JobParams->RecipientName);
  1286. MyFreeString(JobParams->Tsid);
  1287. MyFreeString(JobParams->SenderName);
  1288. MyFreeString(JobParams->SenderDept);
  1289. MyFreeString(JobParams->SenderCompany);
  1290. MyFreeString(JobParams->BillingCode);
  1291. MyFreeString(JobParams->DeliveryReportAddress);
  1292. MyFreeString(JobParams->DocumentName);
  1293. MyFreeString(CoverpageInfo->CoverPageName);
  1294. MyFreeString(CoverpageInfo->RecName);
  1295. MyFreeString(CoverpageInfo->RecFaxNumber);
  1296. MyFreeString(CoverpageInfo->RecCompany);
  1297. MyFreeString(CoverpageInfo->RecStreetAddress);
  1298. MyFreeString(CoverpageInfo->RecCity);
  1299. MyFreeString(CoverpageInfo->RecState);
  1300. MyFreeString(CoverpageInfo->RecZip);
  1301. MyFreeString(CoverpageInfo->RecCountry);
  1302. MyFreeString(CoverpageInfo->RecTitle);
  1303. MyFreeString(CoverpageInfo->RecDepartment);
  1304. MyFreeString(CoverpageInfo->RecOfficeLocation);
  1305. MyFreeString(CoverpageInfo->RecHomePhone);
  1306. MyFreeString(CoverpageInfo->RecOfficePhone);
  1307. MyFreeString(CoverpageInfo->SdrName);
  1308. MyFreeString(CoverpageInfo->SdrFaxNumber);
  1309. MyFreeString(CoverpageInfo->SdrCompany);
  1310. MyFreeString(CoverpageInfo->SdrAddress);
  1311. MyFreeString(CoverpageInfo->SdrTitle);
  1312. MyFreeString(CoverpageInfo->SdrDepartment);
  1313. MyFreeString(CoverpageInfo->SdrOfficeLocation);
  1314. MyFreeString(CoverpageInfo->SdrHomePhone);
  1315. MyFreeString(CoverpageInfo->SdrOfficePhone);
  1316. MyFreeString(CoverpageInfo->Note);
  1317. MyFreeString(CoverpageInfo->Subject);
  1318. return TRUE;
  1319. }
  1320. WINFAXAPI
  1321. BOOL
  1322. WINAPI
  1323. FaxSendDocumentForBroadcastA(
  1324. IN HANDLE FaxHandle,
  1325. IN LPCSTR FileNameA,
  1326. OUT LPDWORD FaxJobId,
  1327. IN PFAX_RECIPIENT_CALLBACKA FaxRecipientCallbackA,
  1328. IN LPVOID Context
  1329. )
  1330. {
  1331. error_status_t ec;
  1332. WCHAR TempFile[MAX_PATH];
  1333. WCHAR TiffFile[MAX_PATH];
  1334. WCHAR CovFileName[MAX_PATH];
  1335. WCHAR BodyFileName[MAX_PATH];
  1336. FAX_JOB_PARAMW JobParams;
  1337. FAX_COVERPAGE_INFOW CoverpageInfo;
  1338. DWORD TmpFaxJobId;
  1339. DWORD BcFaxJobId = 0;
  1340. DWORD i = 1;
  1341. HANDLE hTiff = NULL;
  1342. TIFF_INFO TiffInfo;
  1343. DWORD PageCount;
  1344. LPWSTR FileName;
  1345. if (!ValidateFaxHandle(FaxHandle, FHT_SERVICE)) {
  1346. SetLastError(ERROR_INVALID_HANDLE);
  1347. return FALSE;
  1348. }
  1349. if (!FileNameA || !FaxRecipientCallbackA) {
  1350. SetLastError(ERROR_INVALID_PARAMETER);
  1351. return FALSE;
  1352. }
  1353. FileName = AnsiStringToUnicodeString(FileNameA);
  1354. if (!CreateFinalTiffFile( FileName, TiffFile, NULL )) {
  1355. DeleteFile( TiffFile );
  1356. SetLastError(ERROR_INVALID_DATA);
  1357. return FALSE;
  1358. }
  1359. hTiff = TiffOpen( TiffFile, &TiffInfo, TRUE, FILLORDER_MSB2LSB );
  1360. if (hTiff == NULL) {
  1361. DeleteFile( TiffFile );
  1362. return FALSE;
  1363. }
  1364. PageCount = TiffInfo.PageCount;
  1365. TiffClose( hTiff );
  1366. if (!CopyFileToServerQueue( FaxHandle, TiffFile, BodyFileName )) {
  1367. DeleteFile( TiffFile );
  1368. return FALSE;
  1369. }
  1370. //
  1371. // the passed in file should be treated as read-only
  1372. // if we created a temp file then delete it
  1373. //
  1374. if (wcscmp(FileName,TiffFile) != 0) {
  1375. DeleteFile( TiffFile );
  1376. }
  1377. ZeroMemory( &JobParams, sizeof(JobParams) );
  1378. JobParams.SizeOfStruct = sizeof(JobParams);
  1379. JobParams.Reserved[0] = 0xfffffffe;
  1380. JobParams.Reserved[1] = 1;
  1381. JobParams.Reserved[2] = 0;
  1382. ec = FAX_SendDocument( FH_FAX_HANDLE(FaxHandle), BodyFileName, &JobParams, &BcFaxJobId );
  1383. if (ec) {
  1384. SetLastError( ec );
  1385. return FALSE;
  1386. }
  1387. if (FaxJobId) {
  1388. *FaxJobId = BcFaxJobId;
  1389. }
  1390. while (TRUE) {
  1391. ZeroMemory( &JobParams, sizeof(JobParams) );
  1392. JobParams.SizeOfStruct = sizeof(JobParams);
  1393. ZeroMemory( &CoverpageInfo, sizeof(CoverpageInfo) );
  1394. CoverpageInfo.SizeOfStruct = sizeof(CoverpageInfo);
  1395. if (!FaxRecipientCallbackA( FaxHandle, i, Context, (PFAX_JOB_PARAMA)&JobParams,(PFAX_COVERPAGE_INFOA) &CoverpageInfo )) {
  1396. break;
  1397. }
  1398. if (JobParams.RecipientNumber == NULL) {
  1399. continue;
  1400. }
  1401. ConvertCoverpageAndJobInfo(&JobParams,&CoverpageInfo);
  1402. JobParams.Reserved[0] = 0xfffffffe;
  1403. JobParams.Reserved[1] = 2;
  1404. JobParams.Reserved[2] = BcFaxJobId;
  1405. CoverpageInfo.PageCount = PageCount + 1;
  1406. GetLocalTime( &CoverpageInfo.TimeSent );
  1407. if (CreateCoverpageTiffFile( &CoverpageInfo, TempFile )) {
  1408. if (CopyFileToServerQueue( FaxHandle, TempFile, CovFileName )) {
  1409. ec = FAX_SendDocument( FH_FAX_HANDLE(FaxHandle), CovFileName, &JobParams, &TmpFaxJobId );
  1410. if (ec) {
  1411. DeleteFile( TempFile );
  1412. SetLastError( ec );
  1413. return FALSE;
  1414. }
  1415. }
  1416. DeleteFile( TempFile );
  1417. } else {
  1418. ec = FAX_SendDocument( FH_FAX_HANDLE(FaxHandle), NULL, &JobParams, &TmpFaxJobId );
  1419. if (ec) {
  1420. SetLastError( ec );
  1421. return FALSE;
  1422. }
  1423. }
  1424. i += 1;
  1425. FreeCoverpageAndJobInfo(&JobParams,&CoverpageInfo);
  1426. }
  1427. return TRUE;
  1428. }
  1429. BOOL
  1430. WINAPI
  1431. FaxSendDocumentA(
  1432. IN HANDLE FaxHandle,
  1433. IN LPCSTR FileName,
  1434. IN FAX_JOB_PARAMA *JobParamsA,
  1435. IN const FAX_COVERPAGE_INFOA *CoverpageInfoA,
  1436. OUT LPDWORD FaxJobId
  1437. )
  1438. /*++
  1439. Routine Description:
  1440. Sends a FAX document to the specified recipient.
  1441. This is an asychronous operation. Use FaxReportStatus
  1442. to determine when the send is completed.
  1443. Arguments:
  1444. FaxHandle - FAX handle obtained from FaxConnectFaxServer.
  1445. FileName - File containing the TIFF-F FAX document.
  1446. JobParams - pointer to FAX_JOB_PARAM structure with transmission params
  1447. CoverpageInfo - optional pointer to FAX_COVERPAGE_INFO structure
  1448. FaxJobId - receives the Fax JobId for the job.
  1449. Return Value:
  1450. TRUE - Success
  1451. FALSE - Failure, call GetLastError() for more error information.
  1452. --*/
  1453. {
  1454. error_status_t ec;
  1455. LPWSTR FileNameW;
  1456. FAX_JOB_PARAMW JobParamsW;
  1457. FAX_COVERPAGE_INFOW CoverpageInfoW;
  1458. if (!FileName || !JobParamsA || JobParamsA->SizeOfStruct != sizeof(FAX_JOB_PARAMA)) {
  1459. SetLastError(ERROR_INVALID_PARAMETER);
  1460. return FALSE;
  1461. }
  1462. if (CoverpageInfoA && CoverpageInfoA->SizeOfStruct != sizeof(FAX_COVERPAGE_INFOA)) {
  1463. SetLastError(ERROR_INVALID_DATA);
  1464. return FALSE;
  1465. }
  1466. FileNameW = AnsiStringToUnicodeString( FileName );
  1467. if (FileNameW == NULL) {
  1468. goto exit;
  1469. }
  1470. CopyMemory(&JobParamsW, JobParamsA, sizeof(FAX_JOB_PARAMA));
  1471. JobParamsW.SizeOfStruct = sizeof(FAX_JOB_PARAMW);
  1472. JobParamsW.RecipientNumber = AnsiStringToUnicodeString(JobParamsA->RecipientNumber);
  1473. JobParamsW.RecipientName = AnsiStringToUnicodeString(JobParamsA->RecipientName);
  1474. JobParamsW.Tsid = AnsiStringToUnicodeString(JobParamsA->Tsid);
  1475. JobParamsW.SenderName = AnsiStringToUnicodeString(JobParamsA->SenderName);
  1476. JobParamsW.SenderCompany = AnsiStringToUnicodeString(JobParamsA->SenderCompany);
  1477. JobParamsW.SenderDept = AnsiStringToUnicodeString(JobParamsA->SenderDept);
  1478. JobParamsW.BillingCode = AnsiStringToUnicodeString(JobParamsA->BillingCode);
  1479. JobParamsW.DeliveryReportAddress = AnsiStringToUnicodeString(JobParamsA->DeliveryReportAddress);
  1480. JobParamsW.DocumentName = AnsiStringToUnicodeString(JobParamsA->DocumentName);
  1481. if (CoverpageInfoA) {
  1482. CoverpageInfoW.SizeOfStruct = sizeof(FAX_COVERPAGE_INFOW);
  1483. CoverpageInfoW.UseServerCoverPage = CoverpageInfoA->UseServerCoverPage;
  1484. CoverpageInfoW.PageCount = CoverpageInfoA->PageCount;
  1485. CoverpageInfoW.TimeSent = CoverpageInfoA->TimeSent;
  1486. CoverpageInfoW.CoverPageName = AnsiStringToUnicodeString( CoverpageInfoA->CoverPageName );
  1487. CoverpageInfoW.RecName = AnsiStringToUnicodeString( CoverpageInfoA->RecName );
  1488. CoverpageInfoW.RecFaxNumber = AnsiStringToUnicodeString( CoverpageInfoA->RecFaxNumber );
  1489. CoverpageInfoW.RecCompany = AnsiStringToUnicodeString( CoverpageInfoA->RecCompany );
  1490. CoverpageInfoW.RecStreetAddress = AnsiStringToUnicodeString( CoverpageInfoA->RecStreetAddress );
  1491. CoverpageInfoW.RecCity = AnsiStringToUnicodeString( CoverpageInfoA->RecCity );
  1492. CoverpageInfoW.RecState = AnsiStringToUnicodeString( CoverpageInfoA->RecState );
  1493. CoverpageInfoW.RecZip = AnsiStringToUnicodeString( CoverpageInfoA->RecZip );
  1494. CoverpageInfoW.RecCountry = AnsiStringToUnicodeString( CoverpageInfoA->RecCountry );
  1495. CoverpageInfoW.RecTitle = AnsiStringToUnicodeString( CoverpageInfoA->RecTitle );
  1496. CoverpageInfoW.RecDepartment = AnsiStringToUnicodeString( CoverpageInfoA->RecDepartment );
  1497. CoverpageInfoW.RecOfficeLocation = AnsiStringToUnicodeString( CoverpageInfoA->RecOfficeLocation );
  1498. CoverpageInfoW.RecHomePhone = AnsiStringToUnicodeString( CoverpageInfoA->RecHomePhone );
  1499. CoverpageInfoW.RecOfficePhone = AnsiStringToUnicodeString( CoverpageInfoA->RecOfficePhone );
  1500. CoverpageInfoW.SdrName = AnsiStringToUnicodeString( CoverpageInfoA->SdrName );
  1501. CoverpageInfoW.SdrFaxNumber = AnsiStringToUnicodeString( CoverpageInfoA->SdrFaxNumber );
  1502. CoverpageInfoW.SdrCompany = AnsiStringToUnicodeString( CoverpageInfoA->SdrCompany );
  1503. CoverpageInfoW.SdrAddress = AnsiStringToUnicodeString( CoverpageInfoA->SdrAddress );
  1504. CoverpageInfoW.SdrTitle = AnsiStringToUnicodeString( CoverpageInfoA->SdrTitle );
  1505. CoverpageInfoW.SdrDepartment = AnsiStringToUnicodeString( CoverpageInfoA->SdrDepartment );
  1506. CoverpageInfoW.SdrOfficeLocation = AnsiStringToUnicodeString( CoverpageInfoA->SdrOfficeLocation );
  1507. CoverpageInfoW.SdrHomePhone = AnsiStringToUnicodeString( CoverpageInfoA->SdrHomePhone );
  1508. CoverpageInfoW.SdrOfficePhone = AnsiStringToUnicodeString( CoverpageInfoA->SdrOfficePhone );
  1509. CoverpageInfoW.Note = AnsiStringToUnicodeString( CoverpageInfoA->Note );
  1510. CoverpageInfoW.Subject = AnsiStringToUnicodeString( CoverpageInfoA->Subject );
  1511. }
  1512. if (FaxSendDocumentW( FaxHandle,
  1513. FileNameW,
  1514. &JobParamsW,
  1515. CoverpageInfoA ? &CoverpageInfoW : NULL,
  1516. FaxJobId )) {
  1517. ec = 0;
  1518. } else {
  1519. ec = GetLastError();
  1520. }
  1521. exit:
  1522. MemFree( (LPBYTE) FileNameW );
  1523. MemFree( (LPBYTE) JobParamsW.RecipientNumber );
  1524. MemFree( (LPBYTE) JobParamsW.RecipientName );
  1525. MemFree( (LPBYTE) JobParamsW.Tsid );
  1526. MemFree( (LPBYTE) JobParamsW.SenderName );
  1527. MemFree( (LPBYTE) JobParamsW.SenderDept );
  1528. MemFree( (LPBYTE) JobParamsW.SenderCompany );
  1529. MemFree( (LPBYTE) JobParamsW.BillingCode );
  1530. MemFree( (LPBYTE) JobParamsW.DeliveryReportAddress );
  1531. MemFree( (LPBYTE) JobParamsW.DocumentName );
  1532. if (CoverpageInfoA) {
  1533. MemFree( (LPBYTE) CoverpageInfoW.CoverPageName );
  1534. MemFree( (LPBYTE) CoverpageInfoW.RecName );
  1535. MemFree( (LPBYTE) CoverpageInfoW.RecFaxNumber );
  1536. MemFree( (LPBYTE) CoverpageInfoW.RecCompany );
  1537. MemFree( (LPBYTE) CoverpageInfoW.RecStreetAddress );
  1538. MemFree( (LPBYTE) CoverpageInfoW.RecCity );
  1539. MemFree( (LPBYTE) CoverpageInfoW.RecState );
  1540. MemFree( (LPBYTE) CoverpageInfoW.RecZip );
  1541. MemFree( (LPBYTE) CoverpageInfoW.RecCountry );
  1542. MemFree( (LPBYTE) CoverpageInfoW.RecTitle );
  1543. MemFree( (LPBYTE) CoverpageInfoW.RecDepartment );
  1544. MemFree( (LPBYTE) CoverpageInfoW.RecOfficeLocation );
  1545. MemFree( (LPBYTE) CoverpageInfoW.RecHomePhone );
  1546. MemFree( (LPBYTE) CoverpageInfoW.RecOfficePhone );
  1547. MemFree( (LPBYTE) CoverpageInfoW.SdrName );
  1548. MemFree( (LPBYTE) CoverpageInfoW.SdrFaxNumber );
  1549. MemFree( (LPBYTE) CoverpageInfoW.SdrCompany );
  1550. MemFree( (LPBYTE) CoverpageInfoW.SdrAddress );
  1551. MemFree( (LPBYTE) CoverpageInfoW.SdrTitle );
  1552. MemFree( (LPBYTE) CoverpageInfoW.SdrDepartment );
  1553. MemFree( (LPBYTE) CoverpageInfoW.SdrOfficeLocation );
  1554. MemFree( (LPBYTE) CoverpageInfoW.SdrHomePhone );
  1555. MemFree( (LPBYTE) CoverpageInfoW.SdrOfficePhone );
  1556. MemFree( (LPBYTE) CoverpageInfoW.Note );
  1557. MemFree( (LPBYTE) CoverpageInfoW.Subject );
  1558. }
  1559. if (ec) {
  1560. SetLastError( ec );
  1561. return FALSE;
  1562. }
  1563. return TRUE;
  1564. }
  1565. BOOL
  1566. WINAPI
  1567. FaxAbort(
  1568. IN HANDLE FaxHandle,
  1569. IN DWORD JobId
  1570. )
  1571. /*++
  1572. Routine Description:
  1573. Abort the specified FAX job. All outstanding FAX
  1574. operations are terminated.
  1575. Arguments:
  1576. FaxHandle - FAX Server handle obtained from FaxConnectFaxServer.
  1577. JobId - job id.
  1578. Return Value:
  1579. TRUE - Success
  1580. FALSE - Failure, call GetLastError() for more error information.
  1581. --*/
  1582. {
  1583. error_status_t ec;
  1584. //
  1585. // argument validation
  1586. //
  1587. if (!ValidateFaxHandle(FaxHandle, FHT_SERVICE)) {
  1588. SetLastError(ERROR_INVALID_HANDLE);
  1589. return FALSE;
  1590. }
  1591. ec = FAX_Abort( (handle_t) FH_FAX_HANDLE(FaxHandle),(DWORD) JobId );
  1592. if (ec) {
  1593. SetLastError( ec );
  1594. return FALSE;
  1595. }
  1596. return TRUE;
  1597. }
  1598. BOOL
  1599. WINAPI
  1600. FaxEnumJobsW(
  1601. IN HANDLE FaxHandle,
  1602. OUT PFAX_JOB_ENTRYW *JobEntryBuffer,
  1603. OUT LPDWORD JobsReturned
  1604. )
  1605. {
  1606. PFAX_JOB_ENTRYW JobEntry;
  1607. error_status_t ec;
  1608. DWORD BufferSize = 0;
  1609. DWORD i;
  1610. DWORD Size;
  1611. if (!ValidateFaxHandle(FaxHandle, FHT_SERVICE)) {
  1612. SetLastError(ERROR_INVALID_HANDLE);
  1613. return FALSE;
  1614. }
  1615. if (!JobEntryBuffer || !JobsReturned) {
  1616. SetLastError(ERROR_INVALID_PARAMETER);
  1617. return FALSE;
  1618. }
  1619. *JobEntryBuffer = NULL;
  1620. *JobsReturned = 0;
  1621. Size = 0;
  1622. ec = FAX_EnumJobs( FH_FAX_HANDLE(FaxHandle), (LPBYTE*)JobEntryBuffer, &Size, JobsReturned );
  1623. if (ec) {
  1624. SetLastError( ec );
  1625. return FALSE;
  1626. }
  1627. JobEntry = (PFAX_JOB_ENTRYW) *JobEntryBuffer;
  1628. for (i=0; i<*JobsReturned; i++) {
  1629. FixupStringPtr( JobEntryBuffer, JobEntry[i].UserName );
  1630. FixupStringPtr( JobEntryBuffer, JobEntry[i].RecipientNumber );
  1631. FixupStringPtr( JobEntryBuffer, JobEntry[i].RecipientName );
  1632. FixupStringPtr( JobEntryBuffer, JobEntry[i].DocumentName );
  1633. FixupStringPtr( JobEntryBuffer, JobEntry[i].Tsid );
  1634. FixupStringPtr( JobEntryBuffer, JobEntry[i].SenderName );
  1635. FixupStringPtr( JobEntryBuffer, JobEntry[i].SenderCompany );
  1636. FixupStringPtr( JobEntryBuffer, JobEntry[i].SenderDept );
  1637. FixupStringPtr( JobEntryBuffer, JobEntry[i].BillingCode );
  1638. FixupStringPtr( JobEntryBuffer, JobEntry[i].DeliveryReportAddress );
  1639. }
  1640. return TRUE;
  1641. }
  1642. BOOL
  1643. WINAPI
  1644. FaxEnumJobsA(
  1645. IN HANDLE FaxHandle,
  1646. OUT PFAX_JOB_ENTRYA *JobEntryBuffer,
  1647. OUT LPDWORD JobsReturned
  1648. )
  1649. {
  1650. PFAX_JOB_ENTRYW JobEntry;
  1651. DWORD i;
  1652. if (!FaxEnumJobsW( FaxHandle, (PFAX_JOB_ENTRYW *)JobEntryBuffer, JobsReturned)) {
  1653. return FALSE;
  1654. }
  1655. JobEntry = (PFAX_JOB_ENTRYW) *JobEntryBuffer;
  1656. for (i=0; i<*JobsReturned; i++) {
  1657. ConvertUnicodeStringInPlace( (LPCWSTR) JobEntry[i].UserName );
  1658. ConvertUnicodeStringInPlace( (LPCWSTR) JobEntry[i].RecipientNumber );
  1659. ConvertUnicodeStringInPlace( (LPCWSTR) JobEntry[i].RecipientName );
  1660. ConvertUnicodeStringInPlace( (LPCWSTR) JobEntry[i].DocumentName );
  1661. ConvertUnicodeStringInPlace( (LPCWSTR) JobEntry[i].Tsid );
  1662. ConvertUnicodeStringInPlace( (LPCWSTR) JobEntry[i].SenderName );
  1663. ConvertUnicodeStringInPlace( (LPCWSTR) JobEntry[i].SenderCompany );
  1664. ConvertUnicodeStringInPlace( (LPCWSTR) JobEntry[i].SenderDept );
  1665. ConvertUnicodeStringInPlace( (LPCWSTR) JobEntry[i].BillingCode );
  1666. ConvertUnicodeStringInPlace( (LPCWSTR) JobEntry[i].DeliveryReportAddress );
  1667. }
  1668. return TRUE;
  1669. }
  1670. BOOL
  1671. WINAPI
  1672. FaxSetJobW(
  1673. IN HANDLE FaxHandle,
  1674. IN DWORD JobId,
  1675. IN DWORD Command,
  1676. IN const FAX_JOB_ENTRYW *JobEntry
  1677. )
  1678. /*++
  1679. Routine Description:
  1680. set job status information for a requested JobId
  1681. Note that this is the fax server JobId, not a spooler job ID.
  1682. Arguments:
  1683. FaxHandle - FAX handle obtained from FaxConnectFaxServer
  1684. JobId - Fax service Job ID
  1685. Command - JC_* constant for controlling the job
  1686. JobEntry - pointer to Buffer holding the job information
  1687. Return Value:
  1688. ERROR_SUCCESS for success, otherwise a WIN32 error code.
  1689. --*/
  1690. {
  1691. error_status_t ec;
  1692. //
  1693. // argument validation
  1694. //
  1695. //if (!FaxHandle || !JobEntry || Command > JC_RESTART || Command == JC_UNKNOWN || JobId != JobEntry->JobId) {
  1696. if (!ValidateFaxHandle(FaxHandle, FHT_SERVICE)) {
  1697. SetLastError(ERROR_INVALID_HANDLE);
  1698. return FALSE;
  1699. }
  1700. if (!JobEntry || Command > JC_RESTART || Command == JC_UNKNOWN) {
  1701. SetLastError (ERROR_INVALID_PARAMETER);
  1702. return FALSE;
  1703. }
  1704. ec = FAX_SetJob( FH_FAX_HANDLE(FaxHandle), JobId, Command, JobEntry );
  1705. if (ec) {
  1706. SetLastError( ec );
  1707. return FALSE;
  1708. }
  1709. return TRUE;
  1710. }
  1711. BOOL
  1712. WINAPI
  1713. FaxSetJobA(
  1714. IN HANDLE FaxHandle,
  1715. IN DWORD JobId,
  1716. IN DWORD Command,
  1717. IN const FAX_JOB_ENTRYA *JobEntryA
  1718. )
  1719. /*++
  1720. Routine Description:
  1721. set job status information for a requested JobId
  1722. Note that this is the fax server JobId, not a spooler job ID.
  1723. Arguments:
  1724. FaxHandle - FAX handle obtained from FaxConnectFaxServer
  1725. JobId - Fax service Job ID
  1726. Command - JC_* constant for controlling the job
  1727. JobEntryA - pointer to Buffer holding the job information
  1728. Return Value:
  1729. ERROR_SUCCESS for success, otherwise a WIN32 error code.
  1730. --*/
  1731. {
  1732. FAX_JOB_ENTRYW JobEntryW;
  1733. error_status_t ec = 0;
  1734. if (!JobEntryA) {
  1735. SetLastError(ERROR_INVALID_PARAMETER);
  1736. return FALSE;
  1737. }
  1738. JobEntryW.SizeOfStruct = sizeof(FAX_JOB_ENTRYW);
  1739. JobEntryW.JobId = JobEntryA->JobId;
  1740. JobEntryW.UserName = AnsiStringToUnicodeString(JobEntryA->UserName);
  1741. JobEntryW.JobType = JobEntryA->JobType;
  1742. JobEntryW.QueueStatus = JobEntryA->QueueStatus;
  1743. JobEntryW.Status = JobEntryA->Status;
  1744. JobEntryW.PageCount = JobEntryA->PageCount;
  1745. JobEntryW.RecipientNumber = AnsiStringToUnicodeString(JobEntryA->RecipientNumber);
  1746. JobEntryW.RecipientName = AnsiStringToUnicodeString(JobEntryA->RecipientName);
  1747. JobEntryW.Tsid = AnsiStringToUnicodeString(JobEntryA->Tsid);
  1748. JobEntryW.SenderName = AnsiStringToUnicodeString(JobEntryA->SenderName);
  1749. JobEntryW.SenderCompany = AnsiStringToUnicodeString(JobEntryA->SenderCompany);
  1750. JobEntryW.SenderDept = AnsiStringToUnicodeString(JobEntryA->SenderDept);
  1751. JobEntryW.BillingCode = AnsiStringToUnicodeString(JobEntryA->BillingCode);
  1752. JobEntryW.ScheduleAction = JobEntryA->ScheduleAction;
  1753. JobEntryW.ScheduleTime = JobEntryA->ScheduleTime;
  1754. JobEntryW.DeliveryReportType = JobEntryA->DeliveryReportType;
  1755. JobEntryW.DeliveryReportAddress = AnsiStringToUnicodeString(JobEntryA->DeliveryReportAddress);
  1756. JobEntryW.DocumentName = AnsiStringToUnicodeString(JobEntryA->DocumentName);
  1757. if (!FaxSetJobW( FaxHandle, JobId, Command, &JobEntryW) ) {
  1758. ec = GetLastError();
  1759. }
  1760. MemFree( (LPBYTE) JobEntryW.UserName);
  1761. MemFree( (LPBYTE) JobEntryW.RecipientNumber );
  1762. MemFree( (LPBYTE) JobEntryW.RecipientName );
  1763. MemFree( (LPBYTE) JobEntryW.Tsid );
  1764. MemFree( (LPBYTE) JobEntryW.SenderName );
  1765. MemFree( (LPBYTE) JobEntryW.SenderDept );
  1766. MemFree( (LPBYTE) JobEntryW.SenderCompany );
  1767. MemFree( (LPBYTE) JobEntryW.BillingCode );
  1768. MemFree( (LPBYTE) JobEntryW.DeliveryReportAddress );
  1769. MemFree( (LPBYTE) JobEntryW.DocumentName );
  1770. if (ec != 0) {
  1771. SetLastError(ec);
  1772. return FALSE;
  1773. }
  1774. return TRUE;
  1775. }
  1776. BOOL
  1777. WINAPI
  1778. FaxGetJobW(
  1779. IN HANDLE FaxHandle,
  1780. IN DWORD JobId,
  1781. IN PFAX_JOB_ENTRYW *JobEntryBuffer
  1782. )
  1783. /*++
  1784. Routine Description:
  1785. Returns job status information for a requested JobId
  1786. Note that this is the fax server JobId, not a spooler job ID.
  1787. Arguments:
  1788. FaxHandle - FAX handle obtained from FaxConnectFaxServer
  1789. JobId - Fax service Job ID
  1790. JobEntryBuffer - Buffer to hold the job information
  1791. Return Value:
  1792. ERROR_SUCCESS for success, otherwise a WIN32 error code.
  1793. --*/
  1794. {
  1795. error_status_t ec = 0;
  1796. PFAX_JOB_ENTRY JobEntry;
  1797. DWORD JobEntrySize = 0;
  1798. //
  1799. // parameter validation
  1800. //
  1801. if (!ValidateFaxHandle(FaxHandle, FHT_SERVICE)) {
  1802. SetLastError(ERROR_INVALID_HANDLE);
  1803. return FALSE;
  1804. }
  1805. if (!JobEntryBuffer) {
  1806. SetLastError(ERROR_INVALID_PARAMETER);
  1807. return FALSE;
  1808. }
  1809. *JobEntryBuffer = NULL;
  1810. ec = FAX_GetJob( FH_FAX_HANDLE(FaxHandle), JobId, (char **) JobEntryBuffer , &JobEntrySize );
  1811. if (ec) {
  1812. SetLastError( ec );
  1813. return FALSE;
  1814. }
  1815. JobEntry = (PFAX_JOB_ENTRY) *JobEntryBuffer;
  1816. FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntry->UserName);
  1817. FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntry->RecipientNumber );
  1818. FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntry->RecipientName );
  1819. FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntry->Tsid );
  1820. FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntry->SenderName );
  1821. FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntry->SenderDept );
  1822. FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntry->SenderCompany );
  1823. FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntry->BillingCode );
  1824. FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntry->DeliveryReportAddress );
  1825. FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntry->DocumentName );
  1826. return TRUE;
  1827. }
  1828. BOOL
  1829. WINAPI
  1830. FaxGetJobA(
  1831. IN HANDLE FaxHandle,
  1832. IN DWORD JobId,
  1833. IN PFAX_JOB_ENTRYA *JobEntryBuffer
  1834. )
  1835. /*++
  1836. Routine Description:
  1837. Returns job status information for a requested JobId
  1838. Note that this is the fax server JobId, not a spooler job ID.
  1839. Arguments:
  1840. FaxHandle - FAX handle obtained from FaxConnectFaxServer
  1841. JobId - Fax service Job ID
  1842. JobEntryBuffer - Buffer to hold the job information
  1843. Return Value:
  1844. ERROR_SUCCESS for success, otherwise a WIN32 error code.
  1845. --*/
  1846. {
  1847. PFAX_JOB_ENTRYW JobEntryW;
  1848. DWORD JobEntrySize = 0;
  1849. error_status_t ec = 0;
  1850. if (!ValidateFaxHandle(FaxHandle, FHT_SERVICE)) {
  1851. SetLastError(ERROR_INVALID_HANDLE);
  1852. return FALSE;
  1853. }
  1854. if (!JobEntryBuffer) {
  1855. SetLastError(ERROR_INVALID_PARAMETER);
  1856. return FALSE;
  1857. }
  1858. *JobEntryBuffer = NULL;
  1859. ec = FAX_GetJob( FH_FAX_HANDLE(FaxHandle), JobId, (char **) JobEntryBuffer,&JobEntrySize );
  1860. if (ec) {
  1861. JobEntryBuffer = NULL;
  1862. SetLastError(ec);
  1863. return FALSE;
  1864. }
  1865. //
  1866. // convert to Ansi
  1867. //
  1868. JobEntryW = (PFAX_JOB_ENTRYW) *JobEntryBuffer;
  1869. FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntryW->UserName);
  1870. FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntryW->RecipientNumber );
  1871. FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntryW->RecipientName );
  1872. FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntryW->Tsid );
  1873. FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntryW->SenderName );
  1874. FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntryW->SenderDept );
  1875. FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntryW->SenderCompany );
  1876. FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntryW->BillingCode );
  1877. FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntryW->DeliveryReportAddress );
  1878. FixupStringPtr (JobEntryBuffer, (LPCWSTR) JobEntryW->DocumentName );
  1879. ConvertUnicodeStringInPlace( (LPCWSTR)JobEntryW->UserName);
  1880. ConvertUnicodeStringInPlace( (LPCWSTR)JobEntryW->RecipientNumber );
  1881. ConvertUnicodeStringInPlace( (LPCWSTR)JobEntryW->RecipientName );
  1882. ConvertUnicodeStringInPlace( (LPCWSTR)JobEntryW->Tsid );
  1883. ConvertUnicodeStringInPlace( (LPCWSTR)JobEntryW->SenderName );
  1884. ConvertUnicodeStringInPlace( (LPCWSTR)JobEntryW->SenderDept );
  1885. ConvertUnicodeStringInPlace( (LPCWSTR)JobEntryW->SenderCompany );
  1886. ConvertUnicodeStringInPlace( (LPCWSTR)JobEntryW->BillingCode );
  1887. ConvertUnicodeStringInPlace( (LPCWSTR)JobEntryW->DeliveryReportAddress );
  1888. ConvertUnicodeStringInPlace( (LPCWSTR)JobEntryW->DocumentName );
  1889. return TRUE;
  1890. }
  1891. BOOL
  1892. WINAPI
  1893. FaxGetPageData(
  1894. IN HANDLE FaxHandle,
  1895. IN DWORD JobId,
  1896. OUT LPBYTE *Buffer,
  1897. OUT LPDWORD BufferSize,
  1898. OUT LPDWORD ImageWidth,
  1899. OUT LPDWORD ImageHeight
  1900. )
  1901. {
  1902. error_status_t ec;
  1903. if (!ValidateFaxHandle(FaxHandle, FHT_SERVICE)) {
  1904. SetLastError(ERROR_INVALID_HANDLE);
  1905. return FALSE;
  1906. }
  1907. if (!Buffer || !BufferSize || !ImageWidth || !ImageHeight) {
  1908. SetLastError(ERROR_INVALID_PARAMETER);
  1909. return FALSE;
  1910. }
  1911. *Buffer = NULL;
  1912. *BufferSize = 0;
  1913. *ImageWidth = 0;
  1914. *ImageHeight = 0;
  1915. ec = FAX_GetPageData( FH_FAX_HANDLE(FaxHandle), JobId, Buffer, BufferSize, ImageWidth, ImageHeight );
  1916. if (ec) {
  1917. SetLastError( ec );
  1918. return FALSE;
  1919. }
  1920. return TRUE;
  1921. }