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.

1104 lines
26 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. print.c
  5. Abstract:
  6. This module contains the print specific WINFAX API functions.
  7. Author:
  8. Wesley Witt (wesw) 29-Nov-1996
  9. Revision History:
  10. --*/
  11. #include "faxapi.h"
  12. #pragma hdrstop
  13. LPWSTR Platforms[] =
  14. {
  15. L"Windows NT x86",
  16. L"Windows NT R4000",
  17. L"Windows NT Alpha_AXP",
  18. L"Windows NT PowerPC"
  19. };
  20. LPWSTR
  21. AddFaxTag(
  22. LPWSTR TagStr,
  23. LPCWSTR FaxTag,
  24. LPCWSTR Value
  25. )
  26. {
  27. if (!Value) {
  28. return TagStr;
  29. }
  30. wcscat( TagStr, FaxTag );
  31. wcscat( TagStr, Value );
  32. return TagStr;
  33. }
  34. BOOL
  35. IsPrinterFaxPrinter(
  36. LPWSTR PrinterName
  37. )
  38. {
  39. HANDLE hPrinter = NULL;
  40. PRINTER_DEFAULTS PrinterDefaults;
  41. SYSTEM_INFO SystemInfo;
  42. DWORD Size;
  43. DWORD Rval = FALSE;
  44. LPDRIVER_INFO_2 DriverInfo = NULL;
  45. PrinterDefaults.pDatatype = NULL;
  46. PrinterDefaults.pDevMode = NULL;
  47. PrinterDefaults.DesiredAccess = PRINTER_READ;
  48. if (!OpenPrinter( PrinterName, &hPrinter, &PrinterDefaults )) {
  49. DebugPrint(( L"OpenPrinter() failed, ec=%d", GetLastError() ));
  50. return FALSE;
  51. }
  52. GetSystemInfo( &SystemInfo );
  53. Size = 4096;
  54. DriverInfo = (LPDRIVER_INFO_2) MemAlloc( Size );
  55. if (!DriverInfo) {
  56. DebugPrint(( L"Memory allocation failed, size=%d", Size ));
  57. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  58. goto exit;
  59. }
  60. Rval = GetPrinterDriver(
  61. hPrinter,
  62. Platforms[SystemInfo.wProcessorArchitecture],
  63. 2,
  64. (LPBYTE) DriverInfo,
  65. Size,
  66. &Size
  67. );
  68. if (!Rval) {
  69. DebugPrint(( L"GetPrinterDriver() failed, ec=%d", GetLastError() ));
  70. goto exit;
  71. }
  72. if (_tcscmp( DriverInfo->pName, FAX_DRIVER_NAME ) == 0) {
  73. Rval = TRUE;
  74. } else {
  75. Rval = FALSE;
  76. }
  77. exit:
  78. MemFree( DriverInfo );
  79. ClosePrinter( hPrinter );
  80. return Rval;
  81. }
  82. PVOID
  83. MyGetJob(
  84. HANDLE hPrinter,
  85. DWORD level,
  86. DWORD jobId
  87. )
  88. /*++
  89. Routine Description:
  90. Wrapper function for spooler API GetJob
  91. Arguments:
  92. hPrinter - Handle to the printer object
  93. level - Level of JOB_INFO structure interested
  94. jobId - Specifies the job ID
  95. Return Value:
  96. Pointer to a JOB_INFO structure, NULL if there is an error
  97. --*/
  98. {
  99. PBYTE pJobInfo = NULL;
  100. DWORD cbNeeded;
  101. if (!GetJob(hPrinter, jobId, level, NULL, 0, &cbNeeded) &&
  102. GetLastError() == ERROR_INSUFFICIENT_BUFFER &&
  103. (pJobInfo = MemAlloc(cbNeeded)) &&
  104. GetJob(hPrinter, jobId, level, pJobInfo, cbNeeded, &cbNeeded))
  105. {
  106. return pJobInfo;
  107. }
  108. MemFree(pJobInfo);
  109. return NULL;
  110. }
  111. LPWSTR
  112. GetCpField(
  113. HKEY hKey,
  114. LPWSTR SubKey
  115. )
  116. /*++
  117. Routine Description:
  118. Retrieves the data for a coverpage field from
  119. the registry.
  120. Arguments:
  121. hKey - Registry handle
  122. SubKey - Subkey name
  123. Return Value:
  124. Pointer to the coverpage field data.
  125. --*/
  126. {
  127. LONG rVal;
  128. DWORD RegSize;
  129. DWORD RegType;
  130. LPBYTE Buffer;
  131. rVal = RegQueryValueEx( hKey, SubKey, 0, &RegType, NULL, &RegSize );
  132. if (rVal != ERROR_SUCCESS) {
  133. return NULL;
  134. }
  135. Buffer = (LPBYTE) MemAlloc( RegSize );
  136. if (!Buffer) {
  137. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  138. return NULL;
  139. }
  140. rVal = RegQueryValueEx( hKey, SubKey, 0, &RegType, Buffer, &RegSize );
  141. if (rVal != ERROR_SUCCESS) {
  142. MemFree( Buffer );
  143. return NULL;
  144. }
  145. return (LPWSTR) Buffer;
  146. }
  147. BOOL
  148. GetCpFields(
  149. PCOVERPAGEFIELDS CpFields
  150. )
  151. /*++
  152. Routine Description:
  153. Initializes the coverpage field structure and
  154. fills in the sender information from the registry.
  155. Arguments:
  156. CpFields - Pointer to a coverpage field structure.
  157. Return Value:
  158. TRUE for success.
  159. FALSE for failure.
  160. --*/
  161. {
  162. HKEY hKey;
  163. LONG rVal;
  164. rVal = RegOpenKey(
  165. HKEY_CURRENT_USER,
  166. REGKEY_FAX_USERINFO,
  167. &hKey
  168. );
  169. if (rVal != ERROR_SUCCESS) {
  170. return FALSE;
  171. }
  172. ZeroMemory( CpFields, sizeof(COVERPAGEFIELDS) );
  173. CpFields->ThisStructSize = sizeof(COVERPAGEFIELDS);
  174. //
  175. // sender fields
  176. //
  177. CpFields->SdrName = GetCpField( hKey, REGVAL_FULLNAME );
  178. CpFields->SdrFaxNumber = GetCpField( hKey, REGVAL_FAX_NUMBER );
  179. CpFields->SdrCompany = GetCpField( hKey, REGVAL_COMPANY );
  180. CpFields->SdrAddress = GetCpField( hKey, REGVAL_ADDRESS );
  181. CpFields->SdrTitle = GetCpField( hKey, REGVAL_TITLE );
  182. CpFields->SdrDepartment = GetCpField( hKey, REGVAL_DEPT );
  183. CpFields->SdrOfficeLocation = GetCpField( hKey, REGVAL_OFFICE );
  184. CpFields->SdrHomePhone = GetCpField( hKey, REGVAL_HOME_PHONE );
  185. CpFields->SdrOfficePhone = GetCpField( hKey, REGVAL_OFFICE_PHONE );
  186. RegCloseKey( hKey );
  187. return TRUE;
  188. }
  189. VOID
  190. FreeCpFields(
  191. PCOVERPAGEFIELDS CpFields
  192. )
  193. /*++
  194. Routine Description:
  195. Frees all memory associated with a coverpage field structure.
  196. Arguments:
  197. CpFields - Pointer to a coverpage field structure.
  198. Return Value:
  199. None.
  200. --*/
  201. {
  202. DWORD i;
  203. LPBYTE *p;
  204. for (i = 0; i < NUM_INSERTION_TAGS; i++) {
  205. p = (LPBYTE *) ((ULONG_PTR)CpFields + sizeof(LPTSTR)*(i+1));
  206. if (p && *p) MemFree( *p );
  207. }
  208. }
  209. BOOL
  210. WINAPI
  211. FaxPrintCoverPageW(
  212. IN const FAX_CONTEXT_INFO *FaxContextInfo,
  213. IN const FAX_COVERPAGE_INFOW *CoverPageInfo
  214. )
  215. /*++
  216. Routine Description:
  217. Prints a coverpage into the printer DC provided.
  218. Arguments:
  219. FaxContextInfo - contains servername, Printer DC
  220. CoverPageInfo - Cover page information
  221. Return Value:
  222. TRUE for success.
  223. FALSE for failure.
  224. --*/
  225. {
  226. WCHAR CpName[MAX_PATH];
  227. WCHAR Buffer[MAX_PATH];
  228. LPWSTR p;
  229. COVERPAGEFIELDS CpFields = {0};
  230. COVDOCINFO CovDocInfo;
  231. DWORD DateTimeLen;
  232. DWORD cch;
  233. LPWSTR s;
  234. DWORD ec = 0;
  235. LPCWSTR *src;
  236. LPCWSTR *dst;
  237. DWORD i;
  238. //
  239. // do a little argument validation
  240. //
  241. if (CoverPageInfo == NULL || CoverPageInfo->SizeOfStruct != sizeof(FAX_COVERPAGE_INFOW) ||
  242. FaxContextInfo == NULL || FaxContextInfo->hDC == NULL ||
  243. FaxContextInfo->SizeOfStruct != sizeof (FAX_CONTEXT_INFOW) )
  244. {
  245. SetLastError( ERROR_INVALID_PARAMETER );
  246. return FALSE;
  247. }
  248. if (!ValidateCoverpage(CoverPageInfo->CoverPageName,
  249. FaxContextInfo->ServerName,
  250. CoverPageInfo->UseServerCoverPage,
  251. CpName)) {
  252. return FALSE;
  253. }
  254. //
  255. // get the coverpage fields
  256. //
  257. GetCpFields( &CpFields );
  258. //
  259. // fixup the recipient name
  260. //
  261. if (CoverPageInfo->RecName) {
  262. if (CoverPageInfo->RecName[0] == '\'') {
  263. wcscpy( Buffer, &CoverPageInfo->RecName[1] );
  264. Buffer[wcslen(Buffer)-1] = 0;
  265. } else {
  266. wcscpy( Buffer, CoverPageInfo->RecName );
  267. }
  268. } else {
  269. Buffer[0] = 0;
  270. }
  271. //
  272. // fill in the coverpage fields with the
  273. // data that the caller passed in
  274. //
  275. CpFields.RecName = StringDup( Buffer );
  276. CpFields.RecFaxNumber = StringDup( CoverPageInfo->RecFaxNumber );
  277. if (CpFields.RecFaxNumber) {
  278. p = wcsrchr( (LPWSTR) CpFields.RecFaxNumber, L'@' );
  279. if (p) {
  280. wcscpy( (LPWSTR) CpFields.RecFaxNumber, p+1 );
  281. }
  282. }
  283. CpFields.Subject = StringDup( CoverPageInfo->Subject );
  284. CpFields.Note = StringDup( CoverPageInfo->Note ? CoverPageInfo->Note : L"" );
  285. CpFields.NumberOfPages = StringDup( _itow( CoverPageInfo->PageCount, Buffer, 10 ) );
  286. for (i = 0;
  287. i <= ((LPBYTE)&CoverPageInfo->SdrOfficePhone-(LPBYTE)&CoverPageInfo->RecCompany)/sizeof(LPCWSTR);
  288. i++) {
  289. src = (LPCWSTR *) ((LPBYTE)&CoverPageInfo->RecCompany + (i*sizeof(LPCWSTR)));
  290. dst = (LPCWSTR *) ((LPBYTE)&CpFields.RecCompany + (i*sizeof(LPCWSTR)));
  291. if (*dst) {
  292. MemFree ( (LPBYTE) *dst ) ;
  293. }
  294. *dst = (LPCWSTR) StringDup( *src );
  295. }
  296. //
  297. // the time the fax was sent
  298. //
  299. GetLocalTime((LPSYSTEMTIME)&CoverPageInfo->TimeSent);
  300. DateTimeLen = sizeof(Buffer);
  301. s = Buffer;
  302. GetDateFormat( LOCALE_USER_DEFAULT, 0, &CoverPageInfo->TimeSent, NULL, s, DateTimeLen );
  303. cch = wcslen( s );
  304. s += cch;
  305. if (++cch < DateTimeLen) {
  306. *s++ = ' ';
  307. DateTimeLen -= cch;
  308. GetTimeFormat( LOCALE_USER_DEFAULT, 0, &CoverPageInfo->TimeSent, NULL, s, DateTimeLen );
  309. }
  310. CpFields.TimeSent = StringDup( Buffer );
  311. //
  312. // start the coverpage on a new page
  313. //
  314. StartPage( FaxContextInfo->hDC );
  315. //
  316. // print the cover page
  317. //
  318. ec = PrintCoverPage(
  319. FaxContextInfo->hDC,
  320. &CpFields,
  321. CpName,
  322. &CovDocInfo
  323. );
  324. //
  325. // end the page
  326. //
  327. EndPage( FaxContextInfo->hDC );
  328. FreeCpFields( &CpFields );
  329. if (ec != 0) {
  330. SetLastError( ec );
  331. return FALSE;
  332. }
  333. return TRUE;
  334. }
  335. BOOL
  336. WINAPI
  337. FaxPrintCoverPageA(
  338. IN const FAX_CONTEXT_INFOA *FaxContextInfo,
  339. IN const FAX_COVERPAGE_INFOA *CoverPageInfo
  340. )
  341. /*++
  342. Routine Description:
  343. Prints a coverpage into the printer DC provided.
  344. Arguments:
  345. FaxContextInfo - fax Printer context info (hdc, etc.)
  346. CoverPageInfo - Cover page information
  347. Return Value:
  348. TRUE for success.
  349. FALSE for failure.
  350. --*/
  351. {
  352. //
  353. // assume all fields between Subject and RecName are LPCTSTR's
  354. //
  355. #define COUNT_CP_FIELDS ((LPBYTE) &CoverPageInfoW.Subject - (LPBYTE)&CoverPageInfoW.RecName)/sizeof(LPCTSTR)
  356. BOOL Rval;
  357. FAX_COVERPAGE_INFOW CoverPageInfoW = {0};
  358. FAX_CONTEXT_INFOW ContextInfoW = {0};
  359. LPWSTR ServerName = NULL;
  360. LPWSTR *d;
  361. LPSTR *s;
  362. DWORD i;
  363. if (!FaxContextInfo || !CoverPageInfo ||
  364. FaxContextInfo->SizeOfStruct != sizeof(FAX_CONTEXT_INFOA) ||
  365. CoverPageInfo->SizeOfStruct != sizeof(FAX_COVERPAGE_INFOA)) {
  366. SetLastError(ERROR_INVALID_PARAMETER);
  367. return FALSE;
  368. }
  369. ContextInfoW.SizeOfStruct = sizeof(FAX_CONTEXT_INFOW);
  370. ContextInfoW.hDC = FaxContextInfo->hDC;
  371. if (FaxContextInfo->ServerName[0] != (CHAR)'\0') {
  372. ServerName = AnsiStringToUnicodeString( FaxContextInfo->ServerName );
  373. wcscpy(ContextInfoW.ServerName,ServerName);
  374. }
  375. CoverPageInfoW.SizeOfStruct = sizeof(FAX_COVERPAGE_INFOW);
  376. CoverPageInfoW.UseServerCoverPage = CoverPageInfo->UseServerCoverPage;
  377. CoverPageInfoW.PageCount = CoverPageInfo->PageCount;
  378. CoverPageInfoW.CoverPageName = AnsiStringToUnicodeString( CoverPageInfo->CoverPageName );
  379. for (i=0;i<=COUNT_CP_FIELDS;i++) {
  380. d = (LPWSTR*) ((ULONG_PTR)&CoverPageInfoW.RecName + i*sizeof(LPCWSTR));
  381. s = (LPSTR *) ((LPBYTE)&CoverPageInfo->RecName + i*sizeof(LPSTR));
  382. DebugPrint(( TEXT(" source: 0x%08x --> dest: 0x%08x \n"), s, d));
  383. *d = AnsiStringToUnicodeString( *s );
  384. }
  385. CoverPageInfoW.TimeSent = CoverPageInfo->TimeSent;
  386. CoverPageInfoW.PageCount = CoverPageInfo->PageCount;
  387. Rval = FaxPrintCoverPageW(
  388. &ContextInfoW,
  389. &CoverPageInfoW
  390. );
  391. if (CoverPageInfoW.CoverPageName) {
  392. MemFree( (LPBYTE) CoverPageInfoW.CoverPageName );
  393. }
  394. if (ServerName) {
  395. MemFree( (LPBYTE) ServerName );
  396. }
  397. for (i = 0; i < COUNT_CP_FIELDS; i++) {
  398. d = (LPWSTR *)((ULONG_PTR)&CoverPageInfoW.RecName + i*sizeof(LPWSTR));
  399. if (d && *d)MemFree( (LPBYTE)*d );
  400. }
  401. return Rval;
  402. }
  403. BOOL
  404. WINAPI
  405. FaxStartPrintJobW(
  406. IN LPCWSTR PrinterName,
  407. IN const FAX_PRINT_INFOW *PrintInfo,
  408. OUT LPDWORD FaxJobId,
  409. OUT PFAX_CONTEXT_INFO FaxContextInfo
  410. )
  411. /*++
  412. Routine Description:
  413. Starts a print job for the specified printer. This
  414. function provides functionality beyond what the caller
  415. can provide by using StartDoc(). This function disables
  416. the display of the fax send wizard and also passes along
  417. the information that would otherwise be gathered by the
  418. fax wizard ui.
  419. Arguments:
  420. PrinterName - Fax printer name (must be a fax printer)
  421. PrintInfo - Fax print information
  422. FaxJobId - Job id of the resulting print job
  423. FaxContextInfo - context information including hdc
  424. Return Value:
  425. TRUE for success.
  426. FALSE for failure.
  427. --*/
  428. {
  429. HANDLE hPrinter = NULL;
  430. PDEVMODE DevMode = NULL;
  431. PDMPRIVATE DevModePrivate = NULL;
  432. DOCINFO DocInfo;
  433. PJOB_INFO_2 JobInfo = NULL;
  434. PPRINTER_INFO_2 PrinterInfo = NULL;
  435. DWORD dwNeeded = 0;
  436. HDC hDC = NULL;
  437. INT JobId = 0;
  438. LPWSTR FaxTags = NULL;
  439. LONG Size;
  440. LPWSTR FaxPrinterName;
  441. //
  442. // do a little argument validation
  443. //
  444. if (PrintInfo == NULL || PrintInfo->SizeOfStruct != sizeof(FAX_PRINT_INFOW) ||
  445. !FaxJobId || !FaxContextInfo)
  446. {
  447. SetLastError( ERROR_INVALID_PARAMETER );
  448. return FALSE;
  449. }
  450. if (PrintInfo->OutputFileName == NULL &&
  451. (PrintInfo->RecipientNumber == NULL || PrintInfo->RecipientNumber[0] == 0))
  452. {
  453. SetLastError( ERROR_INVALID_PARAMETER );
  454. return FALSE;
  455. }
  456. if (PrintInfo->DrProfileName && PrintInfo->DrEmailAddress) {
  457. SetLastError( ERROR_INVALID_PARAMETER );
  458. return FALSE;
  459. }
  460. //
  461. // if no printer specified, assume they want a local fax printer
  462. //
  463. if (!PrinterName) {
  464. FaxPrinterName = GetFaxPrinterName();
  465. if (!FaxPrinterName) {
  466. SetLastError(ERROR_INVALID_PRINTER_NAME);
  467. return FALSE;
  468. }
  469. } else {
  470. FaxPrinterName = (LPWSTR) PrinterName;
  471. }
  472. //
  473. // verify that the printer is a fax printer, the only type allowed
  474. //
  475. if (!IsPrinterFaxPrinter( FaxPrinterName )) {
  476. SetLastError( ERROR_INVALID_PRINTER_NAME );
  477. return FALSE;
  478. }
  479. //
  480. // open the printer for normal access (this should always work)
  481. //
  482. if (!OpenPrinter( FaxPrinterName, &hPrinter, NULL )) {
  483. goto error_exit;
  484. }
  485. //
  486. // get the fax server's name if the fax printer isn't local
  487. //
  488. if (!GetPrinter(hPrinter,2,(LPBYTE)PrinterInfo,0,&dwNeeded)) {
  489. PrinterInfo = MemAlloc( dwNeeded );
  490. if (!PrinterInfo) {
  491. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  492. goto error_exit;
  493. }
  494. }
  495. if (!GetPrinter(hPrinter,2,(LPBYTE)PrinterInfo,dwNeeded,&dwNeeded)) {
  496. goto error_exit;
  497. }
  498. if (PrinterInfo->pServerName)
  499. wcscpy(FaxContextInfo->ServerName,PrinterInfo->pServerName);
  500. else
  501. FaxContextInfo->ServerName[0] = 0;
  502. //
  503. // get the required size for the DEVMODE
  504. //
  505. Size = DocumentProperties( NULL, hPrinter, NULL, NULL, NULL, 0 );
  506. if (Size <= 0) {
  507. goto error_exit;
  508. }
  509. //
  510. // allocate memory for the DEVMODE
  511. //
  512. DevMode = (PDEVMODE) MemAlloc( Size );
  513. if (!DevMode) {
  514. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  515. goto error_exit;
  516. }
  517. //
  518. // get the default document properties
  519. //
  520. if (DocumentProperties( NULL, hPrinter, NULL, DevMode, NULL, DM_OUT_BUFFER ) != IDOK) {
  521. goto error_exit;
  522. }
  523. //
  524. // be sure we are dealing with the correct DEVMODE
  525. //
  526. if (DevMode->dmDriverExtra < sizeof(DMPRIVATE)) {
  527. goto error_exit;
  528. }
  529. //
  530. // set the private DEVMODE pointer
  531. //
  532. DevModePrivate = (PDMPRIVATE) ((LPBYTE) DevMode + DevMode->dmSize);
  533. //
  534. // set the necessary stuff in the DEVMODE
  535. //
  536. DevModePrivate->sendCoverPage = FALSE;
  537. DevModePrivate->flags |= FAXDM_NO_WIZARD;
  538. DevModePrivate->flags &= ~FAXDM_DRIVER_DEFAULT;
  539. //
  540. // create the device context
  541. //
  542. hDC = CreateDC( L"WINSPOOL", FaxPrinterName, NULL, DevMode );
  543. if (!hDC) {
  544. goto error_exit;
  545. }
  546. //
  547. // set the document information
  548. //
  549. DocInfo.cbSize = sizeof(DOCINFO);
  550. DocInfo.lpszDocName = PrintInfo->DocName;
  551. DocInfo.lpszOutput = PrintInfo->OutputFileName;
  552. DocInfo.lpszDatatype = NULL;
  553. DocInfo.fwType = 0;
  554. //
  555. // start the print job
  556. //
  557. JobId = StartDoc( hDC, &DocInfo );
  558. if (JobId <= 0) {
  559. goto error_exit;
  560. }
  561. if (PrintInfo->OutputFileName == NULL) {
  562. //
  563. // HACK HACK -> pause the print job
  564. //
  565. if (FaxJobId && *FaxJobId == 0xffffffff) {
  566. SetJob( hPrinter, JobId, 0, NULL, JOB_CONTROL_PAUSE );
  567. }
  568. //
  569. // allocate memory for the fax tags
  570. //
  571. FaxTags = (LPWSTR) MemAlloc( 4096 );
  572. if (!FaxTags) {
  573. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  574. return FALSE;
  575. }
  576. //
  577. // set the job tags
  578. // this is how we communicate the information to
  579. // the print driver that would otherwise be
  580. // provided by the fax print wizard
  581. //
  582. JobInfo = MyGetJob( hPrinter, 2, JobId );
  583. if (!JobInfo) {
  584. goto error_exit;
  585. }
  586. AddFaxTag( FaxTags, FAXTAG_RECIPIENT_NUMBER, PrintInfo->RecipientNumber );
  587. AddFaxTag( FaxTags, FAXTAG_RECIPIENT_NAME, PrintInfo->RecipientName );
  588. AddFaxTag( FaxTags, FAXTAG_SENDER_NAME, PrintInfo->SenderName );
  589. AddFaxTag( FaxTags, FAXTAG_SENDER_NAME, PrintInfo->SenderName );
  590. AddFaxTag( FaxTags, FAXTAG_SENDER_COMPANY, PrintInfo->SenderCompany );
  591. AddFaxTag( FaxTags, FAXTAG_SENDER_DEPT, PrintInfo->SenderDept );
  592. AddFaxTag( FaxTags, FAXTAG_BILLING_CODE, PrintInfo->SenderBillingCode );
  593. if (PrintInfo->DrProfileName) {
  594. AddFaxTag( FaxTags, FAXTAG_PROFILE_NAME, PrintInfo->DrProfileName );
  595. AddFaxTag( FaxTags, FAXTAG_EMAIL_NAME, L"inbox" );
  596. } else if (PrintInfo->DrEmailAddress) {
  597. AddFaxTag( FaxTags, FAXTAG_PROFILE_NAME, PrintInfo->DrEmailAddress );
  598. AddFaxTag( FaxTags, FAXTAG_EMAIL_NAME, L"email" );
  599. }
  600. //
  601. // set these fields or the spooler will
  602. // return ACCESS_DENIED for a non-admin client
  603. //
  604. JobInfo->Position = JOB_POSITION_UNSPECIFIED;
  605. JobInfo->pDevMode = NULL;
  606. //
  607. // set our new fax tags
  608. //
  609. JobInfo->pParameters = FaxTags;
  610. if (!SetJob( hPrinter, JobId, 2, (LPBYTE) JobInfo, 0 )) {
  611. goto error_exit;
  612. }
  613. }
  614. //
  615. // clean up and return to the caller
  616. //
  617. ClosePrinter( hPrinter);
  618. MemFree( PrinterInfo);
  619. MemFree( DevMode );
  620. MemFree( FaxTags );
  621. MemFree( JobInfo );
  622. if (!PrinterName) {
  623. MemFree (FaxPrinterName);
  624. }
  625. if (FaxJobId) {
  626. *FaxJobId = JobId;
  627. }
  628. FaxContextInfo->hDC = hDC;
  629. return TRUE;
  630. error_exit:
  631. if (hPrinter) {
  632. ClosePrinter( hPrinter);
  633. }
  634. if (PrinterInfo) {
  635. MemFree( PrinterInfo);
  636. }
  637. if (JobId) {
  638. EndDoc( hDC );
  639. }
  640. if (hDC) {
  641. DeleteDC( hDC );
  642. }
  643. if (DevMode) {
  644. MemFree( DevMode );
  645. }
  646. if (FaxTags) {
  647. MemFree( FaxTags );
  648. }
  649. if (JobInfo) {
  650. MemFree( JobInfo );
  651. }
  652. if (!PrinterName) {
  653. MemFree (FaxPrinterName);
  654. }
  655. return FALSE;
  656. }
  657. BOOL
  658. WINAPI
  659. FaxStartPrintJobA(
  660. IN LPCSTR PrinterName,
  661. IN const FAX_PRINT_INFOA *PrintInfo,
  662. OUT LPDWORD JobId,
  663. OUT FAX_CONTEXT_INFOA *FaxContextInfo
  664. )
  665. /*++
  666. Routine Description:
  667. Starts a print job for the specified printer. This
  668. function provides functionality beyond what the caller
  669. can provide by using StartDoc(). This function disables
  670. the display of the fax send wizard and also passes along
  671. the information that would otherwise be gathered by the
  672. fax wizard ui.
  673. Arguments:
  674. PrinterName - Fax printer name (must be a fax printer)
  675. PrintInfo - Fax print information
  676. FaxJobId - Job id of the resulting print job
  677. FaxContextInfo - device context information (hdc, etc.)
  678. Return Value:
  679. TRUE for success.
  680. FALSE for failure.
  681. --*/
  682. {
  683. BOOL Rval;
  684. FAX_PRINT_INFOW PrintInfoW;
  685. FAX_CONTEXT_INFOW ContextInfoW;
  686. LPSTR ServerName;
  687. LPWSTR PrinterNameW = NULL;
  688. if (!PrintInfo || !JobId || !FaxContextInfo ||
  689. (PrintInfo->SizeOfStruct != sizeof(FAX_PRINT_INFOA))) {
  690. SetLastError(ERROR_INVALID_PARAMETER);
  691. return FALSE;
  692. }
  693. if (PrinterName) {
  694. PrinterNameW = AnsiStringToUnicodeString( PrinterName );
  695. }
  696. ZeroMemory( &ContextInfoW, sizeof(FAX_CONTEXT_INFOW) );
  697. ContextInfoW.SizeOfStruct = sizeof(FAX_CONTEXT_INFOW) ;
  698. ZeroMemory( &PrintInfoW, sizeof(FAX_PRINT_INFOW) );
  699. PrintInfoW.SizeOfStruct = sizeof(FAX_PRINT_INFOW);
  700. PrintInfoW.DocName = AnsiStringToUnicodeString( PrintInfo->DocName );
  701. PrintInfoW.RecipientName = AnsiStringToUnicodeString( PrintInfo->RecipientName );
  702. PrintInfoW.RecipientNumber = AnsiStringToUnicodeString( PrintInfo->RecipientNumber );
  703. PrintInfoW.SenderName = AnsiStringToUnicodeString( PrintInfo->SenderName );
  704. PrintInfoW.SenderCompany = AnsiStringToUnicodeString( PrintInfo->SenderCompany );
  705. PrintInfoW.SenderDept = AnsiStringToUnicodeString( PrintInfo->SenderDept );
  706. PrintInfoW.SenderBillingCode = AnsiStringToUnicodeString( PrintInfo->SenderBillingCode );
  707. PrintInfoW.DrProfileName = AnsiStringToUnicodeString( PrintInfo->DrProfileName );
  708. PrintInfoW.DrEmailAddress = AnsiStringToUnicodeString( PrintInfo->DrEmailAddress );
  709. PrintInfoW.OutputFileName = AnsiStringToUnicodeString( PrintInfo->OutputFileName );
  710. Rval = FaxStartPrintJobW(
  711. (LPWSTR) PrinterNameW,
  712. &PrintInfoW,
  713. JobId,
  714. &ContextInfoW
  715. );
  716. MemFree( (LPBYTE) PrinterNameW );
  717. MemFree( (LPBYTE) PrintInfoW.DocName );
  718. MemFree( (LPBYTE) PrintInfoW.RecipientName );
  719. MemFree( (LPBYTE) PrintInfoW.RecipientNumber );
  720. MemFree( (LPBYTE) PrintInfoW.SenderName );
  721. MemFree( (LPBYTE) PrintInfoW.SenderCompany );
  722. MemFree( (LPBYTE) PrintInfoW.SenderDept );
  723. MemFree( (LPBYTE) PrintInfoW.SenderBillingCode );
  724. ServerName = UnicodeStringToAnsiString( ContextInfoW.ServerName);
  725. if (ServerName) {
  726. strcpy(FaxContextInfo->ServerName,ServerName);
  727. }
  728. else
  729. FaxContextInfo->ServerName[0] = 0;
  730. FaxContextInfo->SizeOfStruct = sizeof(FAX_CONTEXT_INFOA);
  731. FaxContextInfo->hDC = ContextInfoW.hDC;
  732. MemFree( (LPBYTE) ServerName );
  733. return Rval;
  734. }
  735. BOOL
  736. ValidateCoverpage(
  737. LPCWSTR CoverPageName,
  738. LPCWSTR ServerName,
  739. BOOL ServerCoverpage,
  740. LPWSTR ResolvedName
  741. )
  742. /*++
  743. Routine Description:
  744. This routine tries to validate that that coverpage specified by the user actually exists where
  745. they say it does, and that it is indeed a coverpage (or a resolvable link to one)
  746. Please see the SDK for documentation on the rules for how server coverpages work, etc.
  747. Arguments:
  748. CoverpageName - contains name of coverpage
  749. ServerName - name of the server, if any (can be null)
  750. ServerCoverpage - indicates if this coverpage is on the server, or in the server location for
  751. coverpages locally
  752. ResolvedName - a pointer to buffer (should be MAX_PATH large at least) to receive the
  753. resolved coverpage name. If NULL, then this param is ignored
  754. Return Value:
  755. TRUE if coverpage can be used.
  756. FALSE if the coverpage is invalid or cannot be used.
  757. --*/
  758. {
  759. LPWSTR p;
  760. DWORD ec = 0;
  761. WCHAR CpDir[MAX_PATH];
  762. WCHAR Buffer[MAX_PATH];
  763. if (!CoverPageName) {
  764. ec = ERROR_INVALID_PARAMETER;
  765. goto exit;
  766. }
  767. wcsncpy(CpDir,CoverPageName,MAX_PATH);
  768. p = wcschr(CpDir, L'\\' );
  769. if (p) {
  770. //
  771. // the coverpage file name contains a path so just use it.
  772. //
  773. if (GetFileAttributes( CpDir ) == 0xffffffff) {
  774. ec = ERROR_FILE_NOT_FOUND;
  775. goto exit;
  776. }
  777. } else {
  778. //
  779. // the coverpage file name does not contain
  780. // a path so we must construct a full path name
  781. //
  782. if (ServerCoverpage) {
  783. if (!ServerName || ServerName[0] == 0)
  784. ec = GetServerCpDir( NULL, CpDir, sizeof(CpDir) );
  785. else
  786. ec = GetServerCpDir( ServerName, CpDir, sizeof(CpDir) );
  787. } else {
  788. ec = GetClientCpDir( CpDir, sizeof(CpDir) );
  789. }
  790. if (!ec) {
  791. ec = ERROR_FILE_NOT_FOUND;
  792. goto exit;
  793. }
  794. ec = 0;
  795. ConcatenatePaths(CpDir, CoverPageName);
  796. if (wcschr( CpDir, '.' ) == NULL) {
  797. wcscat( CpDir, CP_FILENAME_EXT );
  798. }
  799. if (GetFileAttributes( CpDir ) == 0xffffffff) {
  800. p = wcschr( CpDir, '.' );
  801. if (p) {
  802. wcscpy( p, CP_SHORTCUT_EXT );
  803. if (GetFileAttributes( CpDir ) == 0xffffffff) {
  804. ec = ERROR_FILE_NOT_FOUND;
  805. goto exit;
  806. }
  807. } else {
  808. ec = ERROR_FILE_NOT_FOUND;
  809. goto exit;
  810. }
  811. }
  812. }
  813. //
  814. // if the file is really a shortcut, then resolve it
  815. //
  816. if (IsCoverPageShortcut( CpDir )) {
  817. if (!ResolveShortcut( CpDir, Buffer )) {
  818. DebugPrint(( TEXT("Cover page file is really a link, but resolution is not possible") ));
  819. ec = ERROR_FILE_NOT_FOUND;
  820. goto exit;
  821. } else {
  822. if (ResolvedName) {
  823. wcscpy(ResolvedName,Buffer);
  824. }
  825. }
  826. } else {
  827. if (ResolvedName) {
  828. wcscpy( ResolvedName, CpDir );
  829. }
  830. }
  831. exit:
  832. if (ec) {
  833. SetLastError(ec);
  834. return FALSE;
  835. }
  836. return TRUE;
  837. }