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.

2418 lines
53 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. print.c
  5. Abstract:
  6. This module handles the FAX receive case.
  7. Author:
  8. Wesley Witt (wesw) 24-April-1996
  9. Revision History:
  10. --*/
  11. #include "faxsvc.h"
  12. #pragma hdrstop
  13. #define INTERNAL 1
  14. #include "common.h"
  15. PFAX_PRINTER_INFO FaxPrinterInfo;
  16. DWORD FaxPrinters;
  17. PHANDLE FaxPrinterNotifyHandles;
  18. DWORD HandleCount;
  19. HANDLE SpoolerProcessHandle;
  20. DWORD SpoolerProcessIdx;
  21. DWORD ReservedHandles;
  22. HANDLE DirtyTimerHandle = INVALID_HANDLE_VALUE;
  23. DWORD DirtyTimerIdx;
  24. HANDLE ModemTimerHandle = INVALID_HANDLE_VALUE;
  25. DWORD ModemTimerIdx;
  26. extern DWORD FaxDirtyDays;
  27. extern HANDLE FaxServerEvent;
  28. LPTSTR PrintPlatforms[] =
  29. {
  30. TEXT("Windows NT x86"),
  31. TEXT("Windows NT R4000"),
  32. TEXT("Windows NT Alpha_AXP"),
  33. TEXT("Windows NT PowerPC")
  34. };
  35. WORD PrinterFieldType1[] =
  36. {
  37. JOB_NOTIFY_FIELD_STATUS
  38. };
  39. WORD PrinterFieldType2[] =
  40. {
  41. PRINTER_NOTIFY_FIELD_PRINTER_NAME
  42. };
  43. PRINTER_NOTIFY_OPTIONS_TYPE PrinterNotifyOptionsType[] =
  44. {
  45. {
  46. JOB_NOTIFY_TYPE,
  47. 0,
  48. 0,
  49. 0,
  50. sizeof(PrinterFieldType1) / sizeof(WORD),
  51. PrinterFieldType1
  52. },
  53. {
  54. PRINTER_NOTIFY_TYPE,
  55. 0,
  56. 0,
  57. 0,
  58. sizeof(PrinterFieldType2) / sizeof(WORD),
  59. PrinterFieldType2
  60. }
  61. };
  62. PRINTER_NOTIFY_OPTIONS PrinterNotifyOptions =
  63. {
  64. 2,
  65. 0,
  66. sizeof(PrinterNotifyOptionsType) / sizeof(PRINTER_NOTIFY_OPTIONS_TYPE),
  67. PrinterNotifyOptionsType
  68. };
  69. BOOL
  70. AddPortExW(
  71. LPWSTR pName,
  72. DWORD Level,
  73. LPBYTE pBuffer,
  74. LPWSTR pMonitorName
  75. );
  76. VOID
  77. CleanDirtyQueues(
  78. VOID
  79. );
  80. PVOID
  81. MyEnumPrinters(
  82. LPTSTR pServerName,
  83. DWORD level,
  84. PDWORD pcPrinters
  85. )
  86. /*++
  87. Routine Description:
  88. Wrapper function for spooler API EnumPrinters
  89. Arguments:
  90. pServerName - Specifies the name of the print server
  91. level - Level of PRINTER_INFO_x structure
  92. pcPrinters - Returns the number of printers enumerated
  93. Return Value:
  94. Pointer to an array of PRINTER_INFO_x structures
  95. NULL if there is an error
  96. --*/
  97. {
  98. PBYTE pPrinterInfo = NULL;
  99. DWORD cb;
  100. if (! EnumPrinters(PRINTER_ENUM_LOCAL,
  101. pServerName,
  102. level,
  103. NULL,
  104. 0,
  105. &cb,
  106. pcPrinters) &&
  107. GetLastError() == ERROR_INSUFFICIENT_BUFFER &&
  108. (pPrinterInfo = MemAlloc(cb)) &&
  109. EnumPrinters(PRINTER_ENUM_LOCAL,
  110. pServerName,
  111. level,
  112. pPrinterInfo,
  113. cb,
  114. &cb,
  115. pcPrinters))
  116. {
  117. return pPrinterInfo;
  118. }
  119. MemFree(pPrinterInfo);
  120. return NULL;
  121. }
  122. PVOID
  123. MyEnumPorts(
  124. LPTSTR pServerName,
  125. DWORD level,
  126. PDWORD pcPorts
  127. )
  128. /*++
  129. Routine Description:
  130. Wrapper function for spooler API EnumPrinters
  131. Arguments:
  132. pServerName - Specifies the name of the print server
  133. level - Level of PRINTER_INFO_x structure
  134. pcPrinters - Returns the number of printers enumerated
  135. Return Value:
  136. Pointer to an array of PRINTER_INFO_x structures
  137. NULL if there is an error
  138. --*/
  139. {
  140. PBYTE pPortInfo = NULL;
  141. DWORD cb;
  142. if (! EnumPorts( NULL, level, NULL, 0, &cb, pcPorts ) &&
  143. GetLastError() == ERROR_INSUFFICIENT_BUFFER &&
  144. (pPortInfo = MemAlloc(cb)) &&
  145. EnumPorts( NULL, level, pPortInfo, cb, &cb, pcPorts ))
  146. {
  147. return pPortInfo;
  148. }
  149. MemFree( pPortInfo );
  150. return NULL;
  151. }
  152. PVOID
  153. MyGetJob(
  154. HANDLE hPrinter,
  155. DWORD level,
  156. DWORD jobId
  157. )
  158. /*++
  159. Routine Description:
  160. Wrapper function for spooler API GetJob
  161. Arguments:
  162. hPrinter - Handle to the printer object
  163. level - Level of JOB_INFO structure interested
  164. jobId - Specifies the job ID
  165. Return Value:
  166. Pointer to a JOB_INFO structure, NULL if there is an error
  167. --*/
  168. {
  169. PBYTE pJobInfo = NULL;
  170. DWORD cbNeeded;
  171. if (!GetJob(hPrinter, jobId, level, NULL, 0, &cbNeeded) &&
  172. GetLastError() == ERROR_INSUFFICIENT_BUFFER &&
  173. (pJobInfo = MemAlloc(cbNeeded)) &&
  174. GetJob(hPrinter, jobId, level, pJobInfo, cbNeeded, &cbNeeded))
  175. {
  176. return pJobInfo;
  177. }
  178. MemFree(pJobInfo);
  179. return NULL;
  180. }
  181. DWORD
  182. GetPrinterDataDWord(
  183. HANDLE hPrinter,
  184. PWSTR pRegKey,
  185. DWORD defaultValue
  186. )
  187. /*++
  188. Routine Description:
  189. Retrieve a DWORD value under PrinterData registry key
  190. Arguments:
  191. hPrinter - Specifies the printer in question
  192. pRegKey - Specifies the name of registry value
  193. defaultValue - Specifies the default value to be used if no data exists in registry
  194. Return Value:
  195. Current value for the requested registry key
  196. --*/
  197. {
  198. DWORD value, type, cb;
  199. if (GetPrinterData(hPrinter,
  200. pRegKey,
  201. &type,
  202. (PBYTE) &value,
  203. sizeof(value),
  204. &cb) == ERROR_SUCCESS)
  205. {
  206. return value;
  207. }
  208. return defaultValue;
  209. }
  210. LPTSTR
  211. GetPrinterDataStr(
  212. HANDLE hPrinter,
  213. LPTSTR pRegKey
  214. )
  215. /*++
  216. Routine Description:
  217. Get a string value from the PrinterData registry key
  218. Arguments:
  219. hPrinter - Identifies the printer object
  220. pRegKey - Specifies the name of registry value
  221. Return Value:
  222. pBuffer
  223. --*/
  224. {
  225. DWORD type, cb;
  226. PVOID pBuffer = NULL;
  227. //
  228. // We should really pass NULL for pData parameter here. But to workaround
  229. // a bug in the spooler API GetPrinterData, we must pass in a valid pointer here.
  230. //
  231. if (GetPrinterData( hPrinter, pRegKey, &type, (PBYTE) &type, 0, &cb ) == ERROR_MORE_DATA &&
  232. (pBuffer = MemAlloc( cb )) &&
  233. GetPrinterData( hPrinter, pRegKey, &type, pBuffer, cb, &cb ) == ERROR_SUCCESS &&
  234. (type == REG_SZ || type == REG_MULTI_SZ || type == REG_EXPAND_SZ))
  235. {
  236. return pBuffer;
  237. }
  238. DebugPrint(( TEXT("Couldn't get printer data string %ws: %d\n"), pRegKey, GetLastError() ));
  239. MemFree( pBuffer );
  240. return NULL;
  241. }
  242. BOOL
  243. DeletePortInternal(
  244. HANDLE hPrinter,
  245. LPTSTR PortName
  246. )
  247. {
  248. BOOL Rval = TRUE;
  249. BOOL PortFound = FALSE;
  250. DWORD i;
  251. LPPRINTER_INFO_2 PrinterInfo = NULL;
  252. LPTSTR p;
  253. LPTSTR s2;
  254. LPTSTR s;
  255. if ((!GetPrinter( hPrinter, 2, NULL, 0, &i )) && (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) {
  256. DebugPrint(( TEXT("GetPrinter() failed, ec=%d"), GetLastError() ));
  257. Rval = FALSE;
  258. goto exit;
  259. }
  260. PrinterInfo = (LPPRINTER_INFO_2) MemAlloc( i );
  261. if (!PrinterInfo) {
  262. DebugPrint(( TEXT("MemAlloc() failed, size=%d"), i ));
  263. Rval = FALSE;
  264. goto exit;
  265. }
  266. if (!GetPrinter( hPrinter, 2, (LPBYTE) PrinterInfo, i, &i )) {
  267. DebugPrint(( TEXT("GetPrinter() failed, ec=%d"), GetLastError() ));
  268. Rval = FALSE;
  269. goto exit;
  270. }
  271. p = PrinterInfo->pPortName;
  272. while (p && *p) {
  273. s = _tcschr( p, TEXT(',') );
  274. if (s) {
  275. s2 = s;
  276. *s = 0;
  277. } else {
  278. s2 = NULL;
  279. }
  280. if (_tcscmp( p, PortName ) == 0) {
  281. PortFound = TRUE;
  282. if (s2) {
  283. _tcscpy( p, s2+1 );
  284. } else {
  285. *p = 0;
  286. break;
  287. }
  288. } else {
  289. p += _tcslen(p);
  290. if (s2) {
  291. *s2 = TEXT(',');
  292. p += 1;
  293. }
  294. }
  295. }
  296. if (PortFound) {
  297. if (!SetPrinter( hPrinter, 2, (LPBYTE) PrinterInfo, 0 )) {
  298. DebugPrint(( TEXT("SetPrinter() failed, ec=%d"), GetLastError() ));
  299. goto exit;
  300. }
  301. }
  302. exit:
  303. MemFree( PrinterInfo );
  304. return Rval;
  305. }
  306. BOOL
  307. DeletePrinterPort(
  308. LPTSTR PortName
  309. )
  310. {
  311. BOOL Rval = TRUE;
  312. DWORD i;
  313. PPRINTER_INFO_2 PrinterInfo = NULL;
  314. DWORD PrinterCount;
  315. PRINTER_DEFAULTS PrinterDefaults;
  316. HANDLE hPrinter;
  317. PrinterInfo = MyEnumPrinters( NULL, 2, &PrinterCount );
  318. if (!PrinterInfo) {
  319. DebugPrint(( TEXT("MyEnumPrinters() failed, ec=%d"), GetLastError() ));
  320. return FALSE;
  321. }
  322. //
  323. // first remove the port name from the list
  324. // associated with each fax printer. this is
  325. // necessary because the DeletePort() api will
  326. // not work if the port is associated with a
  327. // printer
  328. //
  329. for (i=0; i<PrinterCount; i++) {
  330. if (_tcsicmp( PrinterInfo[i].pDriverName, FAX_DRIVER_NAME ) == 0) {
  331. PrinterDefaults.pDatatype = NULL;
  332. PrinterDefaults.pDevMode = NULL;
  333. PrinterDefaults.DesiredAccess = PRINTER_ALL_ACCESS;
  334. if (!OpenPrinter( PrinterInfo[i].pPrinterName, &hPrinter, &PrinterDefaults )) {
  335. DebugPrint(( TEXT("OpenPrinter() failed, ec=%d"), GetLastError() ));
  336. continue;
  337. }
  338. if (!DeletePortInternal( hPrinter, PortName )) {
  339. Rval = FALSE;
  340. }
  341. ClosePrinter( hPrinter );
  342. }
  343. }
  344. MemFree( PrinterInfo );
  345. //
  346. // next, if the port was dis-associated from all
  347. // printers, then ask the spooler to delete it.
  348. //
  349. if (Rval) {
  350. DeletePort( NULL, NULL, PortName );
  351. }
  352. return Rval;
  353. }
  354. BOOL
  355. IsValidPort(
  356. PPORT_INFO_2 PortInfo,
  357. DWORD PortCount,
  358. LPTSTR PortName
  359. )
  360. {
  361. DWORD i;
  362. for (i=0; i<PortCount; i++) {
  363. if (_tcscmp( PortName, PortInfo[i].pPortName ) == 0) {
  364. return TRUE;
  365. }
  366. }
  367. return FALSE;
  368. }
  369. BOOL
  370. AddPrinterPort(
  371. LPTSTR PortName
  372. )
  373. {
  374. BOOL Rval = TRUE;
  375. DWORD i;
  376. PORT_INFO_1W PortInfo;
  377. PPRINTER_INFO_2 PrinterInfo = NULL;
  378. PPRINTER_INFO_2 ThisPrinterInfo = NULL;
  379. DWORD PrinterCount;
  380. LPTSTR p,s;
  381. PPORT_INFO_2 PortInfo2 = NULL;
  382. DWORD PortCount;
  383. LPTSTR NewPort = NULL;
  384. PRINTER_DEFAULTS PrinterDefaults;
  385. HANDLE hPrinter;
  386. DWORD Bytes;
  387. PortInfo.pName = PortName;
  388. Rval = AddPortExW(
  389. NULL,
  390. 1,
  391. (LPBYTE) &PortInfo,
  392. FAX_MONITOR_NAME
  393. );
  394. if (!Rval) {
  395. DebugPrint(( TEXT("AddPortExW() failed, ec=%d"), GetLastError() ));
  396. Rval = FALSE;
  397. goto exit;
  398. }
  399. PortInfo2 = (PPORT_INFO_2) MyEnumPorts( NULL, 2, &PortCount );
  400. if (!PortInfo2) {
  401. DebugPrint(( TEXT("MyEnumPorts() failed, ec=%d"), GetLastError() ));
  402. Rval = FALSE;
  403. goto exit;
  404. }
  405. PrinterInfo = MyEnumPrinters( NULL, 2, &PrinterCount );
  406. if (!PrinterInfo) {
  407. DebugPrint(( TEXT("MyEnumPrinters() failed, ec=%d"), GetLastError() ));
  408. Rval = FALSE;
  409. goto exit;
  410. }
  411. for (i=0; i<PrinterCount; i++) {
  412. if (_tcsicmp( PrinterInfo[i].pDriverName, FAX_DRIVER_NAME ) == 0) {
  413. MemFree( NewPort );
  414. NewPort = MemAlloc( StringSize( PrinterInfo[i].pPortName ) + StringSize( PortName ) + 4 );
  415. if (!NewPort) {
  416. DebugPrint(( TEXT("Could not allocate memory for NewPort") ));
  417. Rval = FALSE;
  418. goto exit;
  419. }
  420. _tcscpy( NewPort, PortName );
  421. p = PrinterInfo[i].pPortName;
  422. while( p && *p ) {
  423. s = _tcschr( p, TEXT(',') );
  424. if (s) {
  425. *s = 0;
  426. }
  427. if (IsValidPort( PortInfo2, PortCount, p )) {
  428. if (*NewPort) {
  429. _tcscat( NewPort, TEXT(",") );
  430. }
  431. _tcscat( NewPort, p );
  432. }
  433. if (s) {
  434. *s = TEXT(',');
  435. p = s + 1;
  436. } else {
  437. break;
  438. }
  439. }
  440. PrinterDefaults.pDatatype = NULL;
  441. PrinterDefaults.pDevMode = NULL;
  442. PrinterDefaults.DesiredAccess = PRINTER_ALL_ACCESS;
  443. if (!OpenPrinter( PrinterInfo[i].pPrinterName, &hPrinter, &PrinterDefaults )) {
  444. DebugPrint(( TEXT("OpenPrinter() failed, ec=%d"), GetLastError() ));
  445. Rval = FALSE;
  446. goto exit;
  447. }
  448. if ((!GetPrinter( hPrinter, 2, NULL, 0, &Bytes )) && (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) {
  449. DebugPrint(( TEXT("GetPrinter() failed, ec=%d"), GetLastError() ));
  450. Rval = FALSE;
  451. goto exit;
  452. }
  453. MemFree( ThisPrinterInfo );
  454. ThisPrinterInfo = (LPPRINTER_INFO_2) MemAlloc( Bytes );
  455. if (!ThisPrinterInfo) {
  456. DebugPrint(( TEXT("MemAlloc() failed, size=%d"), Bytes ));
  457. Rval = FALSE;
  458. goto exit;
  459. }
  460. if (!GetPrinter( hPrinter, 2, (LPBYTE) ThisPrinterInfo, Bytes, &Bytes )) {
  461. DebugPrint(( TEXT("GetPrinter() failed, ec=%d"), GetLastError() ));
  462. Rval = FALSE;
  463. goto exit;
  464. }
  465. ThisPrinterInfo->pPortName = NewPort;
  466. if (!SetPrinter( hPrinter, 2, (LPBYTE) ThisPrinterInfo, 0 )) {
  467. DebugPrint(( TEXT("SetPrinter() failed, ec=%d"), GetLastError() ));
  468. Rval = FALSE;
  469. goto exit;
  470. }
  471. ClosePrinter( hPrinter );
  472. }
  473. }
  474. exit:
  475. MemFree( ThisPrinterInfo );
  476. MemFree( PrinterInfo );
  477. MemFree( PortInfo2 );
  478. MemFree( NewPort );
  479. return Rval;
  480. }
  481. BOOL
  482. CreateNullPrintJobs(
  483. PJOB_ENTRY JobEntry
  484. )
  485. /*++
  486. Routine Description:
  487. Creates a NULL print job on each FAX printer in the
  488. system. This is necessary to that status information
  489. is displayed for incoming fax jobs.
  490. Arguments:
  491. JobEntry - Pointer to a FAX job entry.
  492. Return Value:
  493. TRUE - The print jobs are all created.
  494. FALSE - Some or all of the print jobs were not created.
  495. --*/
  496. {
  497. DWORD i;
  498. DOC_INFO_1 DocInfo;
  499. BOOL Rval = TRUE;
  500. PRINTER_DEFAULTS PrinterDefaults;
  501. //
  502. // loop thru the printers and create a job on each one
  503. //
  504. EnterCriticalSection( &CsJob );
  505. for (i=0; i<FaxPrinters; i++) {
  506. //
  507. // create the print job
  508. //
  509. DocInfo.pDocName = GetString( IDS_SERVER_NAME );
  510. DocInfo.pOutputFile = NULL;
  511. DocInfo.pDatatype = 0;
  512. PrinterDefaults.pDatatype = NULL;
  513. PrinterDefaults.pDevMode = NULL;
  514. PrinterDefaults.DesiredAccess = PRINTER_ALL_ACCESS;
  515. if (!OpenPrinter( FaxPrinterInfo[i].PrinterName, &JobEntry->hPrinter[i], &PrinterDefaults )) {
  516. DebugPrint(( TEXT("OpenPrinter() failed, ec=%d"), GetLastError() ));
  517. Rval = FALSE;
  518. goto exit;
  519. }
  520. JobEntry->PrintJobIds[i] = StartDocPrinter(
  521. JobEntry->hPrinter[i],
  522. 1,
  523. (LPBYTE) &DocInfo
  524. );
  525. if (JobEntry->PrintJobIds[i]) {
  526. DebugPrint((TEXT("Started receive print JobId %d"), JobEntry->PrintJobIds[i]));
  527. //
  528. // pause the job so nothing really happens
  529. //
  530. if (!SetJob( FaxPrinterInfo[i].hPrinter, JobEntry->PrintJobIds[i], 0, NULL, JOB_CONTROL_PAUSE )) {
  531. DebugPrint(( TEXT("SetJob() failed, ec=%d"), GetLastError() ));
  532. }
  533. //
  534. // set the initial status string
  535. //
  536. SetPrintJobStatus(
  537. JobEntry->hPrinter[i],
  538. JobEntry->PrintJobIds[i],
  539. FPS_INITIALIZING,
  540. NULL,
  541. -1
  542. );
  543. } else {
  544. DebugPrint(( TEXT("StartDocPrinter() failed, ec=%d"), GetLastError() ));
  545. Rval = FALSE;
  546. }
  547. }
  548. exit:
  549. LeaveCriticalSection( &CsJob );
  550. return Rval;
  551. }
  552. BOOL
  553. DeleteNullPrintJobs(
  554. PFAX_PRINTER_INFO RecvFaxPrinterInfo
  555. )
  556. /*++
  557. Routine Description:
  558. Deletes the NULL print jobs for all FAX printers
  559. on the system.
  560. Arguments:
  561. RecvFaxPrinterInfo - Pointer to array of structs holding printer handles to close.
  562. Return Value:
  563. TRUE - The print jobs are all deleted.
  564. FALSE - Some or all of the print jobs were not deleted.
  565. --*/
  566. {
  567. DWORD i;
  568. BOOL Rval = TRUE;
  569. DWORD JobId;
  570. HANDLE hPrinter;
  571. EnterCriticalSection( &CsJob );
  572. for (i=0; i<FaxPrinters; i++) {
  573. JobId = RecvFaxPrinterInfo[i].PrintJobId;
  574. hPrinter = RecvFaxPrinterInfo[i].hPrinter;
  575. if (!SetJob(
  576. hPrinter,
  577. JobId,
  578. 0,
  579. NULL,
  580. JOB_CONTROL_CANCEL
  581. )) {
  582. DebugPrint(( TEXT("SetJob() failed, ec=%d"), GetLastError() ));
  583. Rval = FALSE;
  584. }
  585. DebugPrint((TEXT("Ended receive print JobId %d"), JobId));
  586. if (!EndDocPrinter( hPrinter )) {
  587. DebugPrint(( TEXT("EndDocPrinter() failed, ec=%d"), GetLastError() ));
  588. }
  589. ClosePrinter( hPrinter );
  590. }
  591. LeaveCriticalSection( &CsJob );
  592. return Rval;
  593. }
  594. BOOL
  595. EnableSpoolerPort(
  596. LPTSTR PortName,
  597. BOOL Enable
  598. )
  599. /*++
  600. Routine Description:
  601. Enables or disables a spooler port.
  602. Arguments:
  603. PortName - Name of the port to be changes
  604. Enable - TRUE = enable, FAlSE = disable
  605. Return Value:
  606. TRUE - The port status is changed.
  607. FALSE - The port status is not changed.
  608. --*/
  609. {
  610. PORT_INFO_3 PortInfo;
  611. //
  612. // change the spooler's port status
  613. //
  614. PortInfo.dwStatus = 0;
  615. PortInfo.pszStatus = NULL,
  616. PortInfo.dwSeverity = Enable ? PORT_STATUS_TYPE_INFO : PORT_STATUS_TYPE_ERROR;
  617. if (!SetPort( NULL, PortName, 3, (LPBYTE) &PortInfo )) {
  618. DebugPrint(( TEXT("SetPort() failed, ec=%d"), GetLastError() ));
  619. return FALSE;
  620. }
  621. return TRUE;
  622. }
  623. BOOL
  624. SetPrintJobCompleted(
  625. HANDLE hPrinter,
  626. DWORD PrintJobId
  627. )
  628. /*++
  629. Routine Description:
  630. Causes the spooler to complete a print job.
  631. The result is the print job is removed from the
  632. print queue.
  633. Arguments:
  634. PrinterName - Name of the printer that owns the job
  635. PrintJobId - Id of the job to be restarted
  636. Return Value:
  637. TRUE - The print job is completed.
  638. FALSE - The print job is not completed.
  639. --*/
  640. {
  641. if (!PrintJobId) {
  642. DebugPrint(( TEXT("SetPrintJobCompleted() failed: 0x%d"), PrintJobId ));
  643. return FALSE;
  644. }
  645. DebugPrint((TEXT("Setting job status for job %d - JOB_CONTROL_SENT_TO_PRINTER"), PrintJobId));
  646. if (!SetJob(
  647. hPrinter,
  648. PrintJobId,
  649. 0,
  650. NULL,
  651. JOB_CONTROL_SENT_TO_PRINTER
  652. )) {
  653. DebugPrint(( TEXT("SetJob() failed: 0x%08x"), GetLastError() ));
  654. return FALSE;
  655. }
  656. return TRUE;
  657. }
  658. BOOL
  659. SetPrintJobPaused(
  660. HANDLE hPrinter,
  661. DWORD PrintJobId
  662. )
  663. /*++
  664. Routine Description:
  665. Causes the spooler to pause a print job.
  666. Arguments:
  667. PrinterName - Name of the printer that owns the job
  668. PrintJobId - Id of the job to be restarted
  669. Return Value:
  670. TRUE - The print job is paused.
  671. FALSE - The print job is not paused.
  672. --*/
  673. {
  674. if (!PrintJobId) {
  675. DebugPrint(( TEXT("SetPrintJobPaused() failed: 0x%d"), PrintJobId ));
  676. return FALSE;
  677. }
  678. DebugPrint((TEXT("Setting job status for job %d - JOB_CONTROL_PAUSE"), PrintJobId));
  679. if (!SetJob(
  680. hPrinter,
  681. PrintJobId,
  682. 0,
  683. NULL,
  684. JOB_CONTROL_PAUSE
  685. )) {
  686. DebugPrint(( TEXT("SetJob() failed: 0x%08x"), GetLastError() ));
  687. return FALSE;
  688. }
  689. return TRUE;
  690. }
  691. BOOL
  692. ArchivePrintJob(
  693. HANDLE hPrinter,
  694. LPTSTR FaxFileName,
  695. DWORDLONG SendTime,
  696. PFAX_DEV_STATUS FaxStatus,
  697. PFAX_SEND FaxSend
  698. )
  699. /*++
  700. Routine Description:
  701. Archive a tiff file that has been sent by copying the file to an archive
  702. directory.
  703. Arguments:
  704. FaxFileName - Name of the file to archive
  705. Return Value:
  706. TRUE - The copy was made.
  707. FALSE - The copy was not made.
  708. --*/
  709. {
  710. BOOL rVal = FALSE;
  711. DWORD ByteCount;
  712. LPTSTR ArchiveDirStr = NULL;
  713. LPTSTR ArchiveDir = NULL;
  714. LPTSTR ArchiveFileName = NULL;
  715. MS_TAG_INFO MsTagInfo;
  716. WCHAR wcZero = L'\0';
  717. if (!GetPrinterDataDWord( hPrinter, PRNDATA_ARCHIVEFLAG, 0 )) {
  718. return TRUE;
  719. }
  720. ArchiveDirStr = GetPrinterDataStr( hPrinter, PRNDATA_ARCHIVEDIR );
  721. if (!ArchiveDirStr) {
  722. goto exit;
  723. }
  724. //
  725. // get the dir name
  726. //
  727. ByteCount = ExpandEnvironmentStrings( ArchiveDirStr, ArchiveDir, 0 );
  728. ArchiveDir = MemAlloc( ByteCount * sizeof(TCHAR) );
  729. if (!ArchiveDir) {
  730. goto exit;
  731. }
  732. ExpandEnvironmentStrings( ArchiveDirStr, ArchiveDir, ByteCount );
  733. //
  734. // be sure that the dir exists
  735. //
  736. MakeDirectory( ArchiveDir );
  737. //
  738. // get the file name
  739. //
  740. ByteCount = (ByteCount + 20) * sizeof(TCHAR);
  741. ArchiveFileName = MemAlloc( ByteCount );
  742. if (!ArchiveFileName) {
  743. goto exit;
  744. }
  745. rVal = GenerateUniqueFileName( ArchiveDir, ArchiveFileName, ByteCount );
  746. if (rVal) {
  747. rVal = CopyFile( FaxFileName, ArchiveFileName, FALSE );
  748. //
  749. // add the microsoft fax tags to the file
  750. // this is necessary ONLY when we archive the
  751. // file when doing a send. if we are not
  752. // archiving the file then it is deleted, so
  753. // adding the tags is not necessary.
  754. //
  755. if (rVal) {
  756. MsTagInfo.RecipName = NULL;
  757. if (FaxSend->ReceiverName && (FaxSend->ReceiverName[0] != wcZero) ) {
  758. MsTagInfo.RecipName = FaxSend->ReceiverName;
  759. }
  760. MsTagInfo.RecipNumber = NULL;
  761. if (FaxSend->ReceiverNumber && (FaxSend->ReceiverNumber[0] != wcZero) ) {
  762. MsTagInfo.RecipNumber = FaxSend->ReceiverNumber;
  763. }
  764. MsTagInfo.SenderName = NULL;
  765. if (FaxSend->CallerName && (FaxSend->CallerName[0] != wcZero) ) {
  766. MsTagInfo.SenderName = FaxSend->CallerName;
  767. }
  768. MsTagInfo.Routing = NULL;
  769. if (FaxStatus->RoutingInfo && (FaxStatus->RoutingInfo[0] != wcZero) ) {
  770. MsTagInfo.Routing = FaxStatus->RoutingInfo;
  771. }
  772. MsTagInfo.CallerId = NULL;
  773. if (FaxStatus->CallerId && (FaxStatus->CallerId[0] != wcZero) ) {
  774. MsTagInfo.CallerId = FaxStatus->CallerId;
  775. }
  776. MsTagInfo.Csid = NULL;
  777. if (FaxStatus->CSI && (FaxStatus->CSI[0] != wcZero) ) {
  778. MsTagInfo.Csid = FaxStatus->CSI;
  779. }
  780. MsTagInfo.Tsid = NULL;
  781. if (FaxSend->CallerNumber && (FaxSend->CallerNumber[0] != wcZero) ) {
  782. MsTagInfo.Tsid = FaxSend->CallerNumber;
  783. }
  784. MsTagInfo.FaxTime = SendTime;
  785. TiffAddMsTags( ArchiveFileName, &MsTagInfo );
  786. }
  787. }
  788. if (rVal) {
  789. FaxLog(
  790. FAXLOG_CATEGORY_OUTBOUND,
  791. FAXLOG_LEVEL_MAX,
  792. 2,
  793. MSG_FAX_ARCHIVE_SUCCESS,
  794. FaxFileName,
  795. ArchiveFileName
  796. );
  797. } else {
  798. FaxLog(
  799. FAXLOG_CATEGORY_OUTBOUND,
  800. FAXLOG_LEVEL_MIN,
  801. 3,
  802. MSG_FAX_ARCHIVE_FAILED,
  803. FaxFileName,
  804. ArchiveFileName,
  805. GetLastErrorText(GetLastError())
  806. );
  807. }
  808. exit:
  809. MemFree( ArchiveDirStr );
  810. MemFree( ArchiveDir );
  811. MemFree( ArchiveFileName );
  812. return rVal;
  813. }
  814. BOOL
  815. RestartPrintJob(
  816. HANDLE hPrinter,
  817. DWORD PrintJobId
  818. )
  819. /*++
  820. Routine Description:
  821. Causes a print job to be restarted.
  822. Arguments:
  823. hPrinter - Handle to printer that owns the job
  824. PrintJobId - Id of the job to be restarted
  825. Return Value:
  826. TRUE - The print job is restarted
  827. FALSE - The print job is not restarted
  828. --*/
  829. {
  830. PJOB_INFO_2 pJobInfo;
  831. SYSTEMTIME SystemTime;
  832. DWORD Minutes;
  833. if (!PrintJobId) {
  834. return FALSE;
  835. }
  836. DebugPrint((TEXT("Setting job status for job %d - JOB_CONTROL_RESTART"), PrintJobId));
  837. pJobInfo = (PJOB_INFO_2) MyGetJob( hPrinter, 2, PrintJobId );
  838. if (pJobInfo == NULL) {
  839. return FALSE;
  840. }
  841. GetSystemTime(&SystemTime);
  842. // wait a couple of minutes to restart the job
  843. Minutes = SystemTime.wHour * MINUTES_PER_HOUR + SystemTime.wMinute;
  844. Minutes += 2;
  845. Minutes %= MINUTES_PER_DAY;
  846. pJobInfo->StartTime = Minutes;
  847. if (!SetJob(
  848. hPrinter,
  849. PrintJobId,
  850. 2,
  851. (LPBYTE) pJobInfo,
  852. JOB_CONTROL_RESTART
  853. )) {
  854. DebugPrint(( TEXT("SetJob() failed: 0x%08x"), GetLastError() ));
  855. MemFree( pJobInfo );
  856. return FALSE;
  857. }
  858. MemFree( pJobInfo );
  859. return TRUE;
  860. }
  861. BOOL
  862. SetPrintJobStatus(
  863. HANDLE hPrinter,
  864. DWORD PrintJobId,
  865. DWORD Status,
  866. LPTSTR PhoneNumber,
  867. INT PageCount
  868. )
  869. /*++
  870. Routine Description:
  871. Changes the status string for a print job.
  872. Arguments:
  873. PrinterName - Name of the printer that owns the job
  874. PrintJobId - Id of the job to be restarted
  875. Status - Status is
  876. Return Value:
  877. TRUE - The status is changed.
  878. FALSE - The status is NOT changed.
  879. --*/
  880. {
  881. LPJOB_INFO_1 JobInfo = NULL;
  882. LPTSTR StatusString = NULL;
  883. BOOL Rval = FALSE;
  884. DWORD BytesNeeded;
  885. DWORD Size;
  886. if ((!GetJob(
  887. hPrinter,
  888. PrintJobId,
  889. 1,
  890. NULL,
  891. 0,
  892. &BytesNeeded )) && GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
  893. DebugPrint(( TEXT("SetPrintJobStatus GetJob(0) JobId %d failed: 0x%08x"), PrintJobId, GetLastError() ));
  894. goto exit;
  895. }
  896. Size = BytesNeeded;
  897. BytesNeeded += 256;
  898. JobInfo = (LPJOB_INFO_1) MemAlloc( BytesNeeded );
  899. if (!JobInfo) {
  900. DebugPrint(( TEXT("MemAlloc() failed: 0x%08x"), BytesNeeded ));
  901. goto exit;
  902. }
  903. if (!GetJob(
  904. hPrinter,
  905. PrintJobId,
  906. 1,
  907. (LPBYTE) JobInfo,
  908. Size,
  909. &Size
  910. )) {
  911. DebugPrint(( TEXT("SetPrintJobStatus GetJob(1) JobId %d failed: 0x%08x"), PrintJobId, GetLastError() ));
  912. goto exit;
  913. }
  914. StatusString = GetString( Status );
  915. if (StatusString) {
  916. JobInfo->pStatus = (LPTSTR) ((LPBYTE)JobInfo + Size);
  917. if (Status == FS_DIALING || Status == FS_TRANSMITTING) {
  918. _stprintf( JobInfo->pStatus, StatusString, PhoneNumber );
  919. } else {
  920. _tcscpy( JobInfo->pStatus, StatusString );
  921. }
  922. }
  923. if (PageCount != -1) {
  924. JobInfo->PagesPrinted = (DWORD) PageCount;
  925. }
  926. DebugPrint((TEXT("Setting job status for job %d - %s"), PrintJobId, StatusString));
  927. if (!SetJob(
  928. hPrinter,
  929. PrintJobId,
  930. 1,
  931. (LPBYTE) JobInfo,
  932. 0
  933. )) {
  934. DebugPrint(( TEXT("SetJob() failed: 0x%08x"), GetLastError() ));
  935. goto exit;
  936. }
  937. Rval = TRUE;
  938. exit:
  939. if (JobInfo) {
  940. MemFree( JobInfo );
  941. }
  942. return Rval;
  943. }
  944. BOOL
  945. IsPrinterFaxPrinter(
  946. LPTSTR PrinterName
  947. )
  948. /*++
  949. Routine Description:
  950. Determines if a printer is a fax printer.
  951. Arguments:
  952. PrinterName - Name of the printer
  953. Return Value:
  954. TRUE for success.
  955. FALSE for failure.
  956. --*/
  957. {
  958. HANDLE hPrinter = NULL;
  959. PRINTER_DEFAULTS PrinterDefaults;
  960. SYSTEM_INFO SystemInfo;
  961. DWORD Size;
  962. DWORD Rval = FALSE;
  963. LPDRIVER_INFO_2 DriverInfo = NULL;
  964. PrinterDefaults.pDatatype = NULL;
  965. PrinterDefaults.pDevMode = NULL;
  966. PrinterDefaults.DesiredAccess = PRINTER_READ;
  967. if (!OpenPrinter( PrinterName, &hPrinter, &PrinterDefaults )) {
  968. DebugPrint(( TEXT("OpenPrinter(%d) failed, ec=%d"), __LINE__, GetLastError() ));
  969. return FALSE;
  970. }
  971. GetSystemInfo( &SystemInfo );
  972. Size = 4096;
  973. DriverInfo = (LPDRIVER_INFO_2) MemAlloc( Size );
  974. if (!DriverInfo) {
  975. DebugPrint(( TEXT("Memory allocation failed, size=%d"), Size ));
  976. goto exit;
  977. }
  978. Rval = GetPrinterDriver(
  979. hPrinter,
  980. PrintPlatforms[SystemInfo.wProcessorArchitecture],
  981. 2,
  982. (LPBYTE) DriverInfo,
  983. Size,
  984. &Size
  985. );
  986. if (!Rval) {
  987. DebugPrint(( TEXT("GetPrinterDriver() failed, ec=%d"), GetLastError() ));
  988. goto exit;
  989. }
  990. if (_tcscmp( DriverInfo->pName, FAX_DRIVER_NAME ) == 0) {
  991. Rval = TRUE;
  992. } else {
  993. Rval = FALSE;
  994. }
  995. exit:
  996. MemFree( DriverInfo );
  997. ClosePrinter( hPrinter );
  998. return Rval;
  999. }
  1000. BOOL
  1001. RefreshPrinterInfo(
  1002. VOID
  1003. )
  1004. /*++
  1005. Routine Description:
  1006. This function allocates the necessary data structures
  1007. to track the fax printers on the server. The data
  1008. structures are then populated with the necessary data.
  1009. Arguments:
  1010. None.
  1011. Return Value:
  1012. TRUE for success.
  1013. FALSE for failure.
  1014. --*/
  1015. {
  1016. DWORD PrinterCount;
  1017. PPRINTER_INFO_2 PrinterInfo;
  1018. DWORD i;
  1019. DWORD j;
  1020. HANDLE hPrinter;
  1021. HANDLE hNotify;
  1022. PRINTER_DEFAULTS PrinterDefaults;
  1023. BOOL Rval = FALSE;
  1024. EnterCriticalSection( &CsJob );
  1025. //
  1026. // close all handles and release all memory
  1027. //
  1028. if (FaxPrinterInfo) {
  1029. for (i=0; i<FaxPrinters+1; i++) {
  1030. FindClosePrinterChangeNotification( FaxPrinterInfo[i].hNotify );
  1031. ClosePrinter( FaxPrinterInfo[i].hPrinter );
  1032. MemFree( FaxPrinterInfo[i].PrinterName );
  1033. }
  1034. }
  1035. MemFree( FaxPrinterInfo );
  1036. MemFree( FaxPrinterNotifyHandles );
  1037. FaxPrinterInfo = NULL;
  1038. FaxPrinterNotifyHandles = NULL;
  1039. FaxPrinters = 0;
  1040. HandleCount = 0;
  1041. //
  1042. // enumerate all of the printers on this server
  1043. //
  1044. PrinterInfo = MyEnumPrinters( NULL, 2, &PrinterCount );
  1045. if (!PrinterInfo) {
  1046. PrinterCount = 0;
  1047. }
  1048. //
  1049. // count the fax printers
  1050. //
  1051. for (i=0; i<PrinterCount; i++) {
  1052. //
  1053. // is this a fax printer??
  1054. //
  1055. if (_tcsicmp( PrinterInfo[i].pDriverName, FAX_DRIVER_NAME ) == 0) {
  1056. FaxPrinters += 1;
  1057. }
  1058. }
  1059. //
  1060. // allocate the fax printer info structures
  1061. //
  1062. FaxPrinterInfo = (PFAX_PRINTER_INFO) MemAlloc( (FaxPrinters+1) * sizeof(FAX_PRINTER_INFO) );
  1063. if (!FaxPrinterInfo) {
  1064. DebugPrint(( TEXT("Memory allocation failed\n") ));
  1065. goto exit;
  1066. }
  1067. ZeroMemory( FaxPrinterInfo, (FaxPrinters+1) * sizeof(FAX_PRINTER_INFO) );
  1068. //
  1069. // get a server handle
  1070. //
  1071. PrinterDefaults.pDatatype = NULL;
  1072. PrinterDefaults.pDevMode = NULL;
  1073. PrinterDefaults.DesiredAccess = SERVER_ALL_ACCESS;
  1074. if (!OpenPrinter( NULL, &hPrinter, &PrinterDefaults )) {
  1075. DebugPrint(( TEXT("OpenPrinter() failed, ec=%d"), GetLastError() ));
  1076. goto exit;
  1077. }
  1078. hNotify = FindFirstPrinterChangeNotification(
  1079. hPrinter,
  1080. PRINTER_CHANGE_ADD_PRINTER | PRINTER_CHANGE_DELETE_PRINTER,
  1081. 0,
  1082. &PrinterNotifyOptions
  1083. );
  1084. if (hNotify == INVALID_HANDLE_VALUE) {
  1085. ClosePrinter ( hPrinter );
  1086. DebugPrint(( TEXT("FindFirstPrinterChangeNotification() failed, ec=%d"), GetLastError() ));
  1087. goto exit;
  1088. }
  1089. FaxPrinterInfo[FaxPrinters].hPrinter = hPrinter;
  1090. FaxPrinterInfo[FaxPrinters].hNotify = hNotify;
  1091. FaxPrinterInfo[FaxPrinters].PrinterName = NULL;
  1092. //
  1093. // set the notification function for all fax printers
  1094. //
  1095. PrinterDefaults.pDatatype = NULL;
  1096. PrinterDefaults.pDevMode = NULL;
  1097. PrinterDefaults.DesiredAccess = PRINTER_ALL_ACCESS;
  1098. for (i=0,j=0; i<PrinterCount; i++) {
  1099. //
  1100. // is this a fax printer??
  1101. //
  1102. if (_tcsicmp( PrinterInfo[i].pDriverName, FAX_DRIVER_NAME ) == 0) {
  1103. if (!OpenPrinter( PrinterInfo[i].pPrinterName, &hPrinter, &PrinterDefaults )) {
  1104. DebugPrint(( TEXT("OpenPrinter() failed, ec=%d"), GetLastError() ));
  1105. goto exit;
  1106. }
  1107. hNotify = FindFirstPrinterChangeNotification(
  1108. hPrinter,
  1109. PRINTER_CHANGE_DELETE_JOB,
  1110. 0,
  1111. &PrinterNotifyOptions
  1112. );
  1113. if (hNotify == INVALID_HANDLE_VALUE) {
  1114. DebugPrint(( TEXT("FindFirstPrinterChangeNotification() failed, ec=%d"), GetLastError() ));
  1115. goto exit;
  1116. }
  1117. FaxPrinterInfo[j].hPrinter = hPrinter;
  1118. FaxPrinterInfo[j].hNotify = hNotify;
  1119. FaxPrinterInfo[j].PrinterName = StringDup( PrinterInfo[i].pPrinterName );
  1120. j += 1;
  1121. }
  1122. }
  1123. ReservedHandles = (SpoolerProcessHandle == NULL) ? 3 : 4;
  1124. HandleCount = FaxPrinters + ReservedHandles;
  1125. FaxPrinterNotifyHandles = (PHANDLE) MemAlloc( HandleCount * sizeof(HANDLE) );
  1126. if (!FaxPrinterNotifyHandles) {
  1127. DebugPrint(( TEXT("Memory allocation failed\n") ));
  1128. return FALSE;
  1129. }
  1130. for (i=0; i<HandleCount-ReservedHandles+1; i++) {
  1131. FaxPrinterNotifyHandles[i] = FaxPrinterInfo[i].hNotify;
  1132. }
  1133. if (SpoolerProcessHandle) {
  1134. SpoolerProcessIdx = i;
  1135. FaxPrinterNotifyHandles[i++] = SpoolerProcessHandle;
  1136. }
  1137. //
  1138. // initialize the dirty days queue cleaner timer
  1139. //
  1140. if (DirtyTimerHandle == INVALID_HANDLE_VALUE) {
  1141. DirtyTimerIdx = i;
  1142. DirtyTimerHandle = CreateWaitableTimer( NULL, FALSE, NULL );
  1143. if (DirtyTimerHandle == INVALID_HANDLE_VALUE) {
  1144. DebugPrint(( TEXT("CreateWaitableTimer failed ec=%d"), GetLastError() ));
  1145. } else {
  1146. LARGE_INTEGER DueTime;
  1147. LONG lPeriod = MILLISECONDS_PER_SECOND * SECONDS_PER_HOUR; // once per hour
  1148. DueTime.QuadPart = 0;
  1149. if( !SetWaitableTimer( DirtyTimerHandle, &DueTime, lPeriod, NULL, NULL, FALSE ) ) {
  1150. DebugPrint(( TEXT("SetWaitableTimer failed ec=%d"), GetLastError() ));
  1151. }
  1152. FaxPrinterNotifyHandles[i] = DirtyTimerHandle;
  1153. }
  1154. } else {
  1155. DirtyTimerIdx = i;
  1156. FaxPrinterNotifyHandles[i] = DirtyTimerHandle;
  1157. }
  1158. i += 1;
  1159. //
  1160. // initialize the modem delayed initialization timer
  1161. //
  1162. if (ModemTimerHandle == INVALID_HANDLE_VALUE) {
  1163. ModemTimerIdx = i;
  1164. ModemTimerHandle = CreateWaitableTimer( NULL, FALSE, NULL );
  1165. if (ModemTimerHandle == INVALID_HANDLE_VALUE) {
  1166. DebugPrint(( TEXT("CreateWaitableTimer failed ec=%d"), GetLastError() ));
  1167. } else {
  1168. LARGE_INTEGER DueTime;
  1169. LONG lPeriod = MILLISECONDS_PER_SECOND * 15;
  1170. DueTime.QuadPart = 0;
  1171. if( !SetWaitableTimer( ModemTimerHandle, &DueTime, lPeriod, NULL, NULL, FALSE ) ) {
  1172. DebugPrint(( TEXT("SetWaitableTimer failed ec=%d"), GetLastError() ));
  1173. }
  1174. FaxPrinterNotifyHandles[i] = ModemTimerHandle;
  1175. }
  1176. } else {
  1177. ModemTimerIdx = i;
  1178. FaxPrinterNotifyHandles[i] = ModemTimerHandle;
  1179. }
  1180. Rval = TRUE;
  1181. exit:
  1182. LeaveCriticalSection( &CsJob );
  1183. MemFree( PrinterInfo );
  1184. return Rval;
  1185. }
  1186. BOOL
  1187. HandleJobChange(
  1188. PFAX_PRINTER_INFO FaxPrinterInfo,
  1189. DWORD JobStatus,
  1190. DWORD JobId
  1191. )
  1192. /*++
  1193. Routine Description:
  1194. This function handles a print job change. We only care
  1195. about job deletions. When a user deletes a fax print job
  1196. we must call the device provider's abort function so
  1197. that the fax operation can be terminated.
  1198. Arguments:
  1199. FaxPrinterInfo - Printer info structure for the printer that owns this job
  1200. JobStatus - The new status of the job
  1201. JobId - The print job id
  1202. Return Value:
  1203. TRUE for success.
  1204. FALSE for failure.
  1205. --*/
  1206. {
  1207. PJOB_ENTRY JobEntry;
  1208. EnterCriticalSection( &CsJob );
  1209. //
  1210. // is the job being deleted?
  1211. //
  1212. if (!(JobStatus & JOB_STATUS_DELETING)) {
  1213. LeaveCriticalSection( &CsJob );
  1214. return FALSE;
  1215. }
  1216. //
  1217. // get the fax job
  1218. //
  1219. JobEntry = FindJobByPrintJob( JobId );
  1220. if (JobEntry == NULL || JobEntry->Aborting) {
  1221. //
  1222. // either the job does not exist or it is already aborting
  1223. //
  1224. LeaveCriticalSection( &CsJob );
  1225. return FALSE;
  1226. }
  1227. SetPrintJobStatus(
  1228. FaxPrinterInfo->hPrinter,
  1229. JobId,
  1230. FPS_ABORTING,
  1231. NULL,
  1232. -1
  1233. );
  1234. //
  1235. // call the device provider's abort function
  1236. //
  1237. __try {
  1238. JobEntry->LineInfo->Provider->FaxDevAbortOperation(
  1239. (HANDLE) JobEntry->InstanceData
  1240. );
  1241. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1242. JobEntry->ErrorCode = GetExceptionCode();
  1243. }
  1244. JobEntry->Aborting = TRUE;
  1245. LeaveCriticalSection( &CsJob );
  1246. return TRUE;
  1247. }
  1248. HANDLE
  1249. GetSpoolerProcessHandle(
  1250. VOID
  1251. )
  1252. /*++
  1253. Routine Description:
  1254. This function gets a handles to the spooler's
  1255. process object. It does this by enumerating the
  1256. task list on the system and then looks for a
  1257. process called "spoolss.exe". This task's process
  1258. identifier is used to open a process handle.
  1259. Arguments:
  1260. None.
  1261. Return Value:
  1262. NULL - Could not get the spooler's process handle
  1263. HANDLE - The spooler's process handle
  1264. --*/
  1265. {
  1266. #define MAX_TASKS 256
  1267. DWORD TaskCount;
  1268. PTASK_LIST TaskList = NULL;
  1269. DWORD SpoolerPid = 0;
  1270. DWORD i;
  1271. HANDLE SpoolerProcessHandle = NULL;
  1272. TaskList = (PTASK_LIST) MemAlloc( MAX_TASKS * sizeof(TASK_LIST) );
  1273. if (!TaskList) {
  1274. goto exit;
  1275. }
  1276. TaskCount = GetTaskList( TaskList, MAX_TASKS );
  1277. if (!TaskCount) {
  1278. goto exit;
  1279. }
  1280. for (i=0; i<TaskCount; i++) {
  1281. if (_stricmp( TaskList[i].ProcessName, "spoolss.exe" ) == 0) {
  1282. SpoolerPid = TaskList[i].dwProcessId;
  1283. break;
  1284. }
  1285. }
  1286. if (i == TaskCount) {
  1287. goto exit;
  1288. }
  1289. if (SpoolerProcessHandle) {
  1290. CloseHandle( SpoolerProcessHandle );
  1291. }
  1292. SpoolerProcessHandle = OpenProcess( SYNCHRONIZE, FALSE, SpoolerPid );
  1293. exit:
  1294. MemFree( TaskList );
  1295. return SpoolerProcessHandle;
  1296. }
  1297. DWORD
  1298. WaitForSpoolerToStart(
  1299. VOID
  1300. )
  1301. /*++
  1302. Routine Description:
  1303. This function waits for the spooler service to start.
  1304. It calls the service controller and queries the status
  1305. of the spooler every 2 seconds (polled).
  1306. Arguments:
  1307. None.
  1308. Return Value:
  1309. Error code.
  1310. --*/
  1311. {
  1312. DWORD rVal = 0;
  1313. SC_HANDLE hSvcMgr = NULL;
  1314. SC_HANDLE hService = NULL;
  1315. SERVICE_STATUS Status;
  1316. hSvcMgr = OpenSCManager(
  1317. NULL,
  1318. NULL,
  1319. SC_MANAGER_ALL_ACCESS
  1320. );
  1321. if (!hSvcMgr) {
  1322. rVal = GetLastError();
  1323. DebugPrint(( TEXT("could not open service manager: error code = %u"), rVal ));
  1324. goto exit;
  1325. }
  1326. hService = OpenService(
  1327. hSvcMgr,
  1328. TEXT("Spooler"),
  1329. SERVICE_ALL_ACCESS
  1330. );
  1331. if (!hService) {
  1332. rVal = GetLastError();
  1333. DebugPrint((
  1334. TEXT("could not open the Spooler service: error code = %u"),
  1335. rVal
  1336. ));
  1337. goto exit;
  1338. }
  1339. if (!QueryServiceStatus( hService, &Status )) {
  1340. rVal = GetLastError();
  1341. DebugPrint((
  1342. TEXT("could not query status for the Spooler service: error code = %u"),
  1343. rVal
  1344. ));
  1345. goto exit;
  1346. }
  1347. while (Status.dwCurrentState != SERVICE_RUNNING) {
  1348. Sleep( 1000 * 2 );
  1349. if (!QueryServiceStatus( hService, &Status )) {
  1350. break;
  1351. }
  1352. }
  1353. if (Status.dwCurrentState != SERVICE_RUNNING) {
  1354. rVal = GetLastError();
  1355. DebugPrint((
  1356. TEXT("could not start the Spooler service: error code = %u"),
  1357. rVal
  1358. ));
  1359. goto exit;
  1360. }
  1361. rVal = ERROR_SUCCESS;
  1362. //
  1363. // get the spooler's process handle
  1364. //
  1365. SpoolerProcessHandle = GetSpoolerProcessHandle();
  1366. exit:
  1367. CloseServiceHandle( hService );
  1368. CloseServiceHandle( hSvcMgr );
  1369. return rVal;
  1370. }
  1371. DWORD
  1372. PrintStatusThread(
  1373. LPVOID NotUsed
  1374. )
  1375. /*++
  1376. Routine Description:
  1377. This function runs as a thread to process print
  1378. status changes. Each fax printer sends status changes
  1379. in the form of events to this thread. When it is
  1380. determined that a job is being deleted, the abort
  1381. function for the device provider is called to
  1382. terminate the fax send operation.
  1383. Arguments:
  1384. None.
  1385. Return Value:
  1386. Error code.
  1387. --*/
  1388. {
  1389. DWORD FailCount = 0;
  1390. PPRINTER_NOTIFY_INFO PrinterNotifyInfo;
  1391. DWORD WaitObject;
  1392. DWORD Change;
  1393. HANDLE CleanQueueHandle = NULL;
  1394. while (TRUE) {
  1395. //
  1396. // wat for a job notification change
  1397. //
  1398. if (!HandleCount) {
  1399. if (WaitForSpoolerToStart() != ERROR_SUCCESS) {
  1400. FaxLog(
  1401. FAXLOG_CATEGORY_UNKNOWN,
  1402. FAXLOG_LEVEL_MIN,
  1403. 0,
  1404. MSG_PRINTER_FAILURE
  1405. );
  1406. ReportServiceStatus( SERVICE_STOPPED, 0, 0 );
  1407. ExitProcess(0);
  1408. }
  1409. if (!RefreshPrinterInfo()) {
  1410. FailCount += 1;
  1411. Sleep( 1000 );
  1412. if (FailCount == 20) {
  1413. FaxLog(
  1414. FAXLOG_CATEGORY_UNKNOWN,
  1415. FAXLOG_LEVEL_MIN,
  1416. 0,
  1417. MSG_PRINTER_FAILURE
  1418. );
  1419. ReportServiceStatus( SERVICE_STOPPED, 0, 0 );
  1420. ExitProcess(0);
  1421. }
  1422. }
  1423. continue;
  1424. }
  1425. WaitObject = WaitForMultipleObjects(
  1426. HandleCount,
  1427. FaxPrinterNotifyHandles,
  1428. FALSE,
  1429. INFINITE
  1430. );
  1431. if (WaitObject == WAIT_FAILED || (WaitObject >= HandleCount && WaitObject < MAXIMUM_WAIT_OBJECTS)) {
  1432. //
  1433. // there was some problem in receiving the event
  1434. //
  1435. DebugPrint(( TEXT("WaitForMultipleObjects() failed, ec=%d"), GetLastError() ));
  1436. continue;
  1437. }
  1438. if (WaitObject == SpoolerProcessIdx) {
  1439. //
  1440. // the spooler just ended
  1441. //
  1442. SpoolerProcessHandle = 0;
  1443. SpoolerProcessIdx = 0;
  1444. WaitForSpoolerToStart();
  1445. RefreshPrinterInfo();
  1446. continue;
  1447. }
  1448. if (WaitObject == DirtyTimerIdx) {
  1449. DWORD ThreadId;
  1450. DWORD WaitObject;
  1451. //
  1452. // if the thread is still running, don't create another one
  1453. //
  1454. if (CleanQueueHandle != NULL) {
  1455. WaitObject = WaitForSingleObject( CleanQueueHandle, 0 );
  1456. if (WaitObject == WAIT_TIMEOUT) {
  1457. continue;
  1458. }
  1459. CloseHandle( CleanQueueHandle );
  1460. }
  1461. CleanQueueHandle = CreateThread(
  1462. NULL,
  1463. 1024*100,
  1464. (LPTHREAD_START_ROUTINE) CleanDirtyQueues,
  1465. NULL,
  1466. 0,
  1467. &ThreadId
  1468. );
  1469. if (CleanQueueHandle == NULL) {
  1470. DebugPrint(( TEXT("Cannot create CleanDirtyQueues thread") ));
  1471. }
  1472. continue;
  1473. }
  1474. if (WaitObject == ModemTimerIdx) {
  1475. PLIST_ENTRY Next;
  1476. PLINE_INFO LineInfo;
  1477. EnterCriticalSection( &CsLine );
  1478. Next = TapiLinesListHead.Flink;
  1479. if (Next) {
  1480. while ((ULONG)Next != (ULONG)&TapiLinesListHead) {
  1481. LineInfo = CONTAINING_RECORD( Next, LINE_INFO, ListEntry );
  1482. Next = LineInfo->ListEntry.Flink;
  1483. if (LineInfo->UnimodemDevice && (LineInfo->Flags & FPF_POWERED_OFF) &&
  1484. (LineInfo->Flags & FPF_RECEIVE_OK)) {
  1485. //
  1486. // put a popup on the currently active desktop
  1487. // we only allow 1 popup per device at a time
  1488. // and we only present the popup twice
  1489. //
  1490. if (!LineInfo->ModemInUse &&
  1491. LineInfo->ModemPopupActive &&
  1492. LineInfo->ModemPopUps < MAX_MODEM_POPUPS)
  1493. {
  1494. LineInfo->ModemPopupActive = 0;
  1495. LineInfo->ModemPopUps += 1;
  1496. ServiceMessageBox(
  1497. GetString( IDS_POWERED_OFF_MODEM ),
  1498. MB_OK | MB_ICONEXCLAMATION | MB_SETFOREGROUND,
  1499. TRUE,
  1500. &LineInfo->ModemPopupActive
  1501. );
  1502. }
  1503. //
  1504. // see if we can revive the device
  1505. //
  1506. if (OpenTapiLine( LineInfo )) {
  1507. LPLINEDEVSTATUS LineDevStatus;
  1508. //
  1509. // check to see if the line is in use
  1510. //
  1511. LineDevStatus = MyLineGetLineDevStatus( LineInfo->hLine );
  1512. if (LineDevStatus) {
  1513. if (LineDevStatus->dwNumOpens > 0 && LineDevStatus->dwNumActiveCalls > 0) {
  1514. LineInfo->ModemInUse = TRUE;
  1515. } else {
  1516. LineInfo->ModemInUse = FALSE;
  1517. }
  1518. MemFree( LineDevStatus );
  1519. }
  1520. if (!LineInfo->ModemInUse) {
  1521. DebugPrint(( TEXT("Device %s is now powered on, connected, and ready for use"), LineInfo->DeviceName ));
  1522. LineInfo->Flags &= ~FPF_POWERED_OFF;
  1523. LineInfo->Flags &= ~FPF_RECEIVE_OK;
  1524. LineInfo->Flags |= FPF_RECEIVE;
  1525. LineInfo->State = FPS_AVAILABLE;
  1526. CreateFaxEvent( LineInfo->PermanentLineID, FEI_MODEM_POWERED_ON );
  1527. }
  1528. }
  1529. if (LineInfo->Flags & FPF_POWERED_OFF) {
  1530. DebugPrint(( TEXT("Could not revive device [%s]"), LineInfo->DeviceName ));
  1531. }
  1532. }
  1533. }
  1534. }
  1535. LeaveCriticalSection( &CsLine );
  1536. continue;
  1537. }
  1538. //
  1539. // get the status information from the spooler
  1540. //
  1541. if (!FindNextPrinterChangeNotification( FaxPrinterNotifyHandles[WaitObject], &Change, NULL, &PrinterNotifyInfo )) {
  1542. DebugPrint(( TEXT("FindNextPrinterChangeNotification() failed, ec=%d"), GetLastError() ));
  1543. continue;
  1544. }
  1545. if (Change == PRINTER_CHANGE_ADD_PRINTER || Change == PRINTER_CHANGE_DELETE_PRINTER) {
  1546. //
  1547. // get the current printer info
  1548. //
  1549. RefreshPrinterInfo();
  1550. } else if (PrinterNotifyInfo && PrinterNotifyInfo->aData[0].Field == JOB_NOTIFY_FIELD_STATUS) {
  1551. HandleJobChange(
  1552. &FaxPrinterInfo[WaitObject],
  1553. PrinterNotifyInfo->aData[0].NotifyData.adwData[0],
  1554. PrinterNotifyInfo->aData[0].Id
  1555. );
  1556. }
  1557. //
  1558. // free the spooler allocated memory
  1559. //
  1560. FreePrinterNotifyInfo( PrinterNotifyInfo );
  1561. }
  1562. return 0;
  1563. }
  1564. VOID
  1565. DisallowFaxSharing(
  1566. VOID
  1567. )
  1568. {
  1569. HANDLE hPrinterServer;
  1570. PRINTER_DEFAULTS PrinterDefaults;
  1571. TCHAR String[128];
  1572. LONG Rslt;
  1573. DWORD Size;
  1574. PrinterDefaults.pDatatype = NULL;
  1575. PrinterDefaults.pDevMode = NULL;
  1576. PrinterDefaults.DesiredAccess = SERVER_ACCESS_ADMINISTER;
  1577. if (!OpenPrinter( NULL, &hPrinterServer, &PrinterDefaults )) {
  1578. DebugPrint(( TEXT("OpenPrinter() failed, ec=%d"), GetLastError() ));
  1579. return;
  1580. }
  1581. _tcscpy( String, FAX_DRIVER_NAME );
  1582. Size = StringSize( String );
  1583. Rslt = SetPrinterData(
  1584. hPrinterServer,
  1585. SPLREG_NO_REMOTE_PRINTER_DRIVERS,
  1586. REG_SZ,
  1587. (LPBYTE) String,
  1588. Size
  1589. );
  1590. if ((Rslt != ERROR_SUCCESS) && (Rslt != ERROR_SUCCESS_RESTART_REQUIRED)) {
  1591. DebugPrint(( TEXT("SetPrinterData() failed, ec=%d"), Rslt ));
  1592. }
  1593. ClosePrinter( hPrinterServer );
  1594. return;
  1595. }
  1596. BOOL
  1597. InitializePrinting(
  1598. VOID
  1599. )
  1600. /*++
  1601. Routine Description:
  1602. This function initializes the printing thread. The thread
  1603. is used to handle the case where the user that started a
  1604. fax send wants to delete the print job.
  1605. Arguments:
  1606. None.
  1607. Return Value:
  1608. TRUE for success.
  1609. FALSE for failure.
  1610. --*/
  1611. {
  1612. DWORD ThreadId;
  1613. HANDLE hThread;
  1614. //
  1615. // this shouldn't be necessary, but someone might
  1616. // figure out how to subvert our security
  1617. //
  1618. if (InstallType & FAX_INSTALL_WORKSTATION) {
  1619. DisallowFaxSharing();
  1620. }
  1621. //
  1622. // get the spooler's process handle
  1623. //
  1624. SpoolerProcessHandle = GetSpoolerProcessHandle();
  1625. //
  1626. // get the current printer info
  1627. //
  1628. RefreshPrinterInfo();
  1629. //
  1630. // start the thread that will do the actual
  1631. // status processing
  1632. //
  1633. hThread = CreateThread(
  1634. NULL,
  1635. 1024*100,
  1636. (LPTHREAD_START_ROUTINE) PrintStatusThread,
  1637. NULL,
  1638. 0,
  1639. &ThreadId
  1640. );
  1641. if (!hThread) {
  1642. return GetLastError();
  1643. }
  1644. CloseHandle( hThread );
  1645. return TRUE;
  1646. }
  1647. VOID
  1648. CleanDirtyQueues(
  1649. VOID
  1650. )
  1651. /*++
  1652. Routine Description:
  1653. This function is invoked periodically by PrintStatusThread to clean the fax printer queues of
  1654. print jobs that have failed to be sent and have been in the queue longer than FaxDirtyDays.
  1655. This function also attempts to route inbound faxes that have failed previous routing attempts.
  1656. Arguments:
  1657. None.
  1658. Return Value:
  1659. None.
  1660. --*/
  1661. {
  1662. #if 0
  1663. DWORD i;
  1664. DWORD j;
  1665. PJOB_INFO_2 JobInfo;
  1666. BYTE JobBuffer[4096];
  1667. BOOL Result;
  1668. DWORD cbData;
  1669. DWORD cJobs;
  1670. LARGE_INTEGER CurrentTime;
  1671. LARGE_INTEGER SubmitTime;
  1672. DWORD cBytes;
  1673. DWORD Retries;
  1674. LPTSTR RetryTag;
  1675. LPTSTR RouteTag;
  1676. DWORD WaitObject;
  1677. // wait for the server to come up completely
  1678. WaitObject = WaitForSingleObject( FaxServerEvent, INFINITE );
  1679. DebugPrint(( TEXT("Cleaning print queues") ));
  1680. GetSystemTimeAsFileTime( (FILETIME *) &CurrentTime );
  1681. // enumerate all of the print jobs in all of the fax printers
  1682. for (i = 0; i < FaxPrinters; i++) {
  1683. for (j = 0; TRUE ; j++) {
  1684. Result = EnumJobs(
  1685. FaxPrinterInfo[i].hPrinter,
  1686. j,
  1687. 1,
  1688. 2,
  1689. JobBuffer,
  1690. sizeof(JobBuffer),
  1691. &cbData,
  1692. &cJobs
  1693. );
  1694. JobInfo = (PJOB_INFO_2) JobBuffer;
  1695. if (!Result || cJobs == 0) {
  1696. break;
  1697. }
  1698. // only consider the jobs that are paused
  1699. if (!(JobInfo->Status & JOB_STATUS_PAUSED) || JobInfo->pParameters == NULL) {
  1700. continue;
  1701. }
  1702. // if it is a send retry that has maxed out, delete the job
  1703. RetryTag = ExtractFaxTag(FAXTAG_SEND_RETRY, JobInfo->pParameters, &cBytes);
  1704. if (RetryTag) {
  1705. Retries = _ttoi( RetryTag );
  1706. if (Retries == 0) {
  1707. SystemTimeToFileTime( &JobInfo->Submitted, (FILETIME *) &SubmitTime);
  1708. if (SubmitTime.QuadPart + (FaxDirtyDays * FILETIMETICKS_PER_DAY) < CurrentTime.QuadPart) {
  1709. while (SetPrintJobCompleted( FaxPrinterInfo[i].hPrinter, JobInfo->JobId ))
  1710. ;
  1711. }
  1712. }
  1713. continue;
  1714. }
  1715. // if it is an inbound routing failure, try to route it again
  1716. RouteTag = ExtractFaxTag(FAXTAG_ROUTE_FILE, JobInfo->pParameters, &cBytes);
  1717. if (RouteTag) {
  1718. PROUTE_INFO RouteInfo;
  1719. RouteTag++; // skip over the space
  1720. RouteInfo = LoadRouteInfo( RouteTag );
  1721. if (RouteInfo != NULL) {
  1722. __try {
  1723. FaxRoute(
  1724. &RouteInfo->FaxReceive,
  1725. &RouteInfo->LineInfo,
  1726. &RouteInfo->FaxStatus,
  1727. NULL,
  1728. 0,
  1729. RouteInfo->ElapsedTime
  1730. );
  1731. } __except (EXCEPTION_EXECUTE_HANDLER) {
  1732. // if the file is corrupt and causes an exception, delete it and cancel the print job
  1733. DebugPrint(( TEXT("Exception processing routing information file") ));
  1734. DeleteFile( RouteTag );
  1735. }
  1736. MemFree( RouteInfo );
  1737. if (GetFileAttributes( RouteTag ) == 0xffffffff) {
  1738. if(!SetJob(
  1739. FaxPrinterInfo[i].hPrinter,
  1740. JobInfo->JobId,
  1741. 0,
  1742. NULL,
  1743. JOB_CONTROL_CANCEL
  1744. )) {
  1745. DebugPrint(( TEXT("CleanDirtyQueues - SetJob failed - ec %d"), GetLastError() ));
  1746. }
  1747. } else {
  1748. SetPrintJobStatus(
  1749. FaxPrinterInfo[i].hPrinter,
  1750. JobInfo->JobId,
  1751. FPS_ROUTERETRY,
  1752. NULL,
  1753. -1
  1754. );
  1755. }
  1756. }
  1757. }
  1758. }
  1759. }
  1760. #endif
  1761. }