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.

1284 lines
31 KiB

  1. /*****************************************************************************\
  2. * MODULE: ppprn.c
  3. *
  4. * This module contains the routines which control the printer during the
  5. * course of a single job.
  6. *
  7. *
  8. * Copyright (C) 1996-1997 Microsoft Corporation
  9. * Copyright (C) 1996-1997 Hewlett Packard
  10. *
  11. * History:
  12. * 09-Jun-1993 JonMarb Created
  13. * 07-Oct-1996 HWP-Guys Initiated port from win95 to winNT
  14. *
  15. \*****************************************************************************/
  16. #include "precomp.h"
  17. #include "priv.h"
  18. /*****************************************************************************\
  19. * _ppprn_free_hprinter (Local Routine)
  20. *
  21. * Free up the hPrinter handle.
  22. *
  23. \*****************************************************************************/
  24. _inline VOID _ppprn_free_hprinter(
  25. HANDLE hPrinter)
  26. {
  27. LPINET_HPRINTER pPrt;
  28. if (pPrt = (LPINET_HPRINTER)hPrinter) {
  29. #ifdef WINNT32
  30. DeleteHandleFromList (pPrt);
  31. #endif
  32. if (pPrt->lpszName)
  33. memFreeStr(pPrt->lpszName);
  34. #ifdef WINNT32
  35. if (pPrt->hUser)
  36. delete ( pPrt->hUser );
  37. #endif
  38. memFree(pPrt, sizeof(INET_HPRINTER));
  39. }
  40. }
  41. /*****************************************************************************\
  42. * _ppprn_inc_user_refcount (Local Routine)
  43. *
  44. * Increment the reference count for the Port on the current printer
  45. *
  46. \*****************************************************************************/
  47. #ifdef WINNT32
  48. _inline DWORD __ppprn_inc_user_refcout(
  49. HANDLE hPrinter ) {
  50. LPINET_HPRINTER pPrt;
  51. DWORD dwRet = MAXDWORD;
  52. if (pPrt = (LPINET_HPRINTER)hPrinter) {
  53. dwRet = (PCINETMONPORT (pPrt->hPort))->IncUserRefCount(pPrt->hUser );
  54. } else
  55. SetLastError( ERROR_INVALID_PARAMETER );
  56. return dwRet;
  57. }
  58. #endif
  59. /*****************************************************************************\
  60. * _ppprn_make_hprinter (Local Routine)
  61. *
  62. * Returns a printer handle.
  63. *
  64. \*****************************************************************************/
  65. HANDLE _ppprn_make_hprinter(
  66. HANDLE hPort,
  67. LPCTSTR lpszPrnName)
  68. {
  69. LPINET_HPRINTER pPrt;
  70. if (pPrt = (LPINET_HPRINTER)memAlloc(sizeof(INET_HPRINTER))) {
  71. pPrt->dwSignature = IPO_SIGNATURE;
  72. pPrt->lpszName = memAllocStr(lpszPrnName);
  73. pPrt->hPort = hPort;
  74. pPrt->dwStatus = 0;
  75. pPrt->pjmJob = NULL;
  76. #ifdef WINNT32
  77. pPrt->hUser = new CLogonUserData;
  78. #endif
  79. if (
  80. pPrt->lpszName
  81. #ifdef WINNT32
  82. && pPrt->hUser
  83. && pPrt->hUser->bValid ()
  84. && AddHandleToList (pPrt)
  85. #endif
  86. ) {
  87. return (HANDLE)pPrt;
  88. } else {
  89. if (pPrt->lpszName)
  90. memFreeStr (pPrt->lpszName);
  91. #ifdef WINNT32
  92. if (pPrt->hUser) {
  93. delete ( pPrt->hUser );
  94. }
  95. #endif
  96. memFree (pPrt, sizeof(INET_HPRINTER));
  97. }
  98. }
  99. return NULL;
  100. }
  101. #ifdef WINNT32
  102. /*****************************************************************************\
  103. * _ppprn_free_xcv_hprinter (Local Routine)
  104. *
  105. * Free a xcv printer handle.
  106. *
  107. \*****************************************************************************/
  108. _inline VOID _ppprn_free_xcv_hprinter(
  109. HANDLE hPrinter)
  110. {
  111. LPINET_XCV_HPRINTER pPrt;
  112. if (pPrt = (LPINET_XCV_HPRINTER)hPrinter) {
  113. memFreeStr (pPrt->lpszName);
  114. memFree(pPrt, sizeof(INET_XCV_HPRINTER));
  115. }
  116. }
  117. /*****************************************************************************\
  118. * _ppprn_make_xcv_hprinter (Local Routine)
  119. *
  120. * Returns a xcv printer handle.
  121. *
  122. \*****************************************************************************/
  123. HANDLE _ppprn_make_xcv_hprinter(
  124. PCINETMONPORT pIniPort)
  125. {
  126. LPINET_XCV_HPRINTER pPrt;
  127. if (pPrt = (LPINET_XCV_HPRINTER)memAlloc(sizeof(INET_XCV_HPRINTER))) {
  128. pPrt->dwSignature = IPO_XCV_SIGNATURE;
  129. pPrt->lpszName = memAllocStr(pIniPort->GetPortName());
  130. }
  131. return pPrt;
  132. }
  133. #endif
  134. /*****************************************************************************\
  135. * ppprn_IppSetRsp (Local Callback Routine)
  136. *
  137. * Retrieves a SetPrinter response from the IPP server
  138. *
  139. \*****************************************************************************/
  140. BOOL CALLBACK ppprn_IppSetRsp(
  141. CAnyConnection *pConnection,
  142. HINTERNET hReq,
  143. PCINETMONPORT pIniPort,
  144. LPARAM lParam)
  145. {
  146. HANDLE hIpp;
  147. DWORD dwRet;
  148. DWORD cbRd;
  149. LPBYTE lpDta;
  150. DWORD cbDta;
  151. LPIPPRET_PRN lpRsp;
  152. DWORD cbRsp;
  153. BYTE bBuf[MAX_IPP_BUFFER];
  154. BOOL bRet = FALSE;
  155. if (hIpp = WebIppRcvOpen((WORD)(LPARAM)lParam)) {
  156. while (TRUE) {
  157. cbRd = 0;
  158. if (pIniPort->ReadFile (pConnection, hReq, (LPVOID)bBuf, sizeof(bBuf), &cbRd) && cbRd) {
  159. dwRet = WebIppRcvData(hIpp, bBuf, cbRd, (LPBYTE*)&lpRsp, &cbRsp, &lpDta, &cbDta);
  160. switch (dwRet) {
  161. case WEBIPP_OK:
  162. if ((bRet = lpRsp->bRet) == FALSE)
  163. SetLastError(lpRsp->dwLastError);
  164. WebIppFreeMem(lpRsp);
  165. goto EndSetRsp;
  166. case WEBIPP_MOREDATA:
  167. // Need to do another read to fullfill our header-response.
  168. //
  169. break;
  170. default:
  171. DBG_MSG(DBG_LEV_ERROR, (TEXT("ppprn_IppSetRsp - Err : Receive Data Error (dwRet=%d, LE=%d)"),
  172. dwRet, WebIppGetError(hIpp)));
  173. SetLastError(ERROR_INVALID_DATA);
  174. goto EndSetRsp;
  175. }
  176. } else {
  177. goto EndSetRsp;
  178. }
  179. }
  180. EndSetRsp:
  181. WebIppRcvClose(hIpp);
  182. } else {
  183. SetLastError(ERROR_OUTOFMEMORY);
  184. }
  185. return bRet;
  186. }
  187. /*****************************************************************************\
  188. * ppprn_Set (Local Routine)
  189. *
  190. * Sets a printer command.
  191. *
  192. \*****************************************************************************/
  193. BOOL ppprn_Set(
  194. PCINETMONPORT pIniPort,
  195. DWORD dwCmd)
  196. {
  197. PIPPREQ_SETPRN psp;
  198. REQINFO ri;
  199. DWORD dwRet;
  200. LPBYTE lpIpp;
  201. DWORD cbIpp;
  202. WORD wReq;
  203. LPTSTR lpszUsrName;
  204. BOOL bRet = FALSE;
  205. // Create our ipp-reqest-structure.
  206. //
  207. if (lpszUsrName = GetUserName()) {
  208. psp = WebIppCreateSetPrnReq(dwCmd,
  209. lpszUsrName,
  210. pIniPort->GetPortName());
  211. memFreeStr(lpszUsrName);
  212. if (psp) {
  213. switch (dwCmd) {
  214. case PRINTER_CONTROL_PAUSE:
  215. wReq = IPP_REQ_PAUSEPRN;
  216. break;
  217. case PRINTER_CONTROL_RESUME:
  218. wReq = IPP_REQ_RESUMEPRN;
  219. break;
  220. case PRINTER_CONTROL_PURGE:
  221. wReq = IPP_REQ_CANCELPRN;
  222. break;
  223. default:
  224. wReq = 0;
  225. break;
  226. }
  227. // Convert the reqest to IPP, and perform the
  228. // post.
  229. //
  230. ZeroMemory(&ri, sizeof(REQINFO));
  231. ri.cpReq = CP_UTF8;
  232. ri.idReq = wReq;
  233. ri.fReq[0] = IPP_REQALL;
  234. ri.fReq[1] = IPP_REQALL;
  235. dwRet = WebIppSndData(wReq,
  236. &ri,
  237. (LPBYTE)psp,
  238. psp->cbSize,
  239. &lpIpp,
  240. &cbIpp);
  241. // The request-structure has been converted to IPP format,
  242. // so it is ready to go to the server.
  243. //
  244. if (dwRet == WEBIPP_OK) {
  245. bRet = pIniPort->SendReq(lpIpp,
  246. cbIpp,
  247. ppprn_IppSetRsp,
  248. (LPARAM)(wReq | IPP_RESPONSE),
  249. TRUE);
  250. WebIppFreeMem(lpIpp);
  251. } else {
  252. SetLastError(ERROR_OUTOFMEMORY);
  253. }
  254. WebIppFreeMem(psp);
  255. } else {
  256. SetLastError(ERROR_OUTOFMEMORY);
  257. }
  258. }
  259. return bRet;
  260. }
  261. #ifdef WINNT32
  262. void
  263. _ppprn_working_thread (
  264. PENDDOCTHREADCONTEXT pThreadData)
  265. {
  266. BOOL bRet = FALSE;
  267. PJOBMAP pjm = pThreadData->pjmJob;
  268. PCINETMONPORT pIniPort = pThreadData->pIniPort;
  269. static DWORD cdwWaitTime = 15000;
  270. DBGMSGT (DBG_LEV_CALLTREE, ("Enter _ppprn_working_thread (%p)\n", pThreadData));
  271. pThreadData->pSidToken->SetCurrentSid ();
  272. delete pThreadData->pSidToken;
  273. pThreadData->pSidToken = NULL;
  274. semEnterCrit();
  275. pjmUpdateLocalJobStatus (pjm, JOB_STATUS_PRINTING);
  276. //
  277. // The document is cancelled
  278. //
  279. if (pjmChkState(pThreadData->pjmJob, PJM_CANCEL)) {
  280. bRet = TRUE;
  281. }
  282. else {
  283. // Refresh the notification handle
  284. //
  285. RefreshNotificationPort (pIniPort);
  286. bRet = pIniPort->EndDocPort(pjm);
  287. #if 0
  288. bRet = FALSE;
  289. //
  290. // This is for testing
  291. //
  292. semLeaveCrit();
  293. Sleep (3000);
  294. semEnterCrit();
  295. #endif
  296. }
  297. //
  298. // Check this flags again, since we left CriticalSection during file transfer
  299. //
  300. if (pjmChkState(pThreadData->pjmJob, PJM_CANCEL)) {
  301. bRet = TRUE;
  302. }
  303. if (bRet) {
  304. //
  305. // Clear our spooling-state. This will free up any spool-job-resources.
  306. //
  307. pjmClrState(pjm, PJM_SPOOLING);
  308. //
  309. // Invalidate both job and printer caches
  310. //
  311. pIniPort->InvalidateGetPrinterCache ();
  312. pIniPort->InvalidateEnumJobsCache ();
  313. }
  314. else {
  315. pjmUpdateLocalJobStatus (pjm, JOB_STATUS_ERROR);
  316. }
  317. // Refresh the notification handle
  318. //
  319. RefreshNotificationPort (pIniPort);
  320. //
  321. // Clean the async thread flag
  322. //
  323. pjmClrState(pjm, PJM_ASYNCON);
  324. pIniPort->DecRef();
  325. semLeaveCrit();
  326. delete pThreadData;
  327. DBGMSGT (DBG_LEV_CALLTREE, ("Leave _ppprn_working_thread (ret = %d)\n", bRet));
  328. }
  329. BOOL
  330. _ppprn_end_docprinter_async (
  331. PCINETMONPORT pIniPort,
  332. PJOBMAP pjmJob)
  333. {
  334. BOOL bRet = FALSE;
  335. PENDDOCTHREADCONTEXT pThreadData = new ENDDOCTHREADCONTEXT;
  336. if (pThreadData) {
  337. pThreadData->pIniPort = pIniPort;
  338. pThreadData->pjmJob = pjmJob;
  339. pThreadData->pSidToken = new CSid;
  340. if (pThreadData->pSidToken && pThreadData->pSidToken->bValid ()) {
  341. HANDLE hThread;
  342. pjmSetState(pjmJob, PJM_ASYNCON);
  343. //
  344. // Increase the ref count of the port to make sure it is not deleted
  345. //
  346. pIniPort->IncRef();
  347. if (pIniPort->CreateTerminateEvent() &&
  348. (hThread = CreateThread (NULL,
  349. COMMITTED_STACK_SIZE,
  350. (LPTHREAD_START_ROUTINE)_ppprn_working_thread,
  351. (PVOID) pThreadData, 0, NULL))) {
  352. CloseHandle (hThread);
  353. bRet = TRUE;
  354. }
  355. else {
  356. //
  357. // Fail to create the thread
  358. //
  359. pIniPort->DecRef ();
  360. pjmClrState(pjmJob, PJM_ASYNCON);
  361. }
  362. }
  363. if (!bRet) {
  364. if (pThreadData->pSidToken) {
  365. delete (pThreadData->pSidToken);
  366. pThreadData->pSidToken = NULL;
  367. }
  368. delete (pThreadData);
  369. }
  370. }
  371. return bRet;
  372. }
  373. #endif
  374. /*****************************************************************************\
  375. * PP_OpenJobInfo
  376. *
  377. * Opens a job-information. This is called at StartDoc timeframe when we
  378. * need to start a spool-job.
  379. *
  380. \*****************************************************************************/
  381. PJOBMAP PP_OpenJobInfo(
  382. HANDLE hPrinter,
  383. PCINETMONPORT pIniPort,
  384. LPTSTR pDocName)
  385. {
  386. PJOBMAP* pjmList;
  387. LPINET_HPRINTER lpPrt = (LPINET_HPRINTER)hPrinter;
  388. LPTSTR pUserName = GetUserName();
  389. pjmList = pIniPort->GetPJMList();
  390. if (lpPrt->pjmJob = pjmAdd(pjmList, pIniPort, pUserName, pDocName)) {
  391. // Set the state to spooling for our job-entry. This wil
  392. // create the spool-file object.
  393. //
  394. pjmSetState(lpPrt->pjmJob, PJM_SPOOLING);
  395. }
  396. memFreeStr (pUserName);
  397. return lpPrt->pjmJob;
  398. }
  399. /*****************************************************************************\
  400. * PP_CloseJobInfo
  401. *
  402. * Close our spool-job and clear out the information regarding a printjob from
  403. * the printer.
  404. *
  405. \*****************************************************************************/
  406. VOID PP_CloseJobInfo(
  407. HANDLE hPrinter)
  408. {
  409. PJOBMAP* pjmList;
  410. LPINET_HPRINTER lpPrt = (LPINET_HPRINTER)hPrinter;
  411. // Clear our spooling-state. This will free up any spool-job-resources.
  412. //
  413. pjmClrState(lpPrt->pjmJob, PJM_SPOOLING);
  414. // If we had cancelled our print-job, then we can remove the
  415. // entry.
  416. //
  417. if (pjmChkState(lpPrt->pjmJob, PJM_CANCEL)) {
  418. pjmList = ((PCINETMONPORT)(lpPrt->hPort))->GetPJMList();
  419. pjmDel(pjmList, lpPrt->pjmJob);
  420. }
  421. // Clear out or spool-status.
  422. //
  423. lpPrt->pjmJob = NULL;
  424. }
  425. VOID PP_CloseJobInfo2(
  426. HANDLE hPrinter)
  427. {
  428. PJOBMAP* pjmList;
  429. LPINET_HPRINTER lpPrt = (LPINET_HPRINTER)hPrinter;
  430. // Clear out or spool-status.
  431. //
  432. lpPrt->pjmJob = NULL;
  433. }
  434. /*****************************************************************************\
  435. * PPAbortPrinter
  436. *
  437. * Deletes a printer's spool file if the printer is configured for spooling.
  438. * Returns TRUE if successful, FALSE if an error occurs.
  439. *
  440. \*****************************************************************************/
  441. BOOL PPAbortPrinter(
  442. HANDLE hPrinter)
  443. {
  444. PCINETMONPORT pIniPort;
  445. BOOL bRet = FALSE;
  446. DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: PPAbortPrinter(%08lX)"), hPrinter));
  447. semEnterCrit();
  448. if (pIniPort = utlValidatePrinterHandle(hPrinter)) {
  449. if ( PP_ChkStatus(hPrinter, PP_STARTDOC) &&
  450. !PP_ChkStatus(hPrinter, PP_ENDDOC)) {
  451. if (bRet = pIniPort->AbortPort(PP_GetJobInfo(hPrinter))) {
  452. // If this call was successful, the job-info
  453. // will have been freed. Therefore, it is OK
  454. // to set the printer-jobreq to NULL.
  455. //
  456. PP_SetStatus(hPrinter, PP_CANCELLED);
  457. PP_ClrStatus(hPrinter, PP_STARTDOC);
  458. PP_CloseJobInfo(hPrinter);
  459. }
  460. } else {
  461. if (PP_ChkStatus(hPrinter, PP_CANCELLED))
  462. SetLastError(ERROR_PRINT_CANCELLED);
  463. else
  464. SetLastError(ERROR_SPL_NO_STARTDOC);
  465. bRet = TRUE;
  466. }
  467. }
  468. semLeaveCrit();
  469. return bRet;
  470. }
  471. /*****************************************************************************\
  472. * PPClosePrinter
  473. *
  474. * Closes a printer that was previously opened with PPOpenPrinter. Returns
  475. * TRUE if successful, FALSE if an error occurs.
  476. *
  477. \*****************************************************************************/
  478. BOOL PPClosePrinter(
  479. HANDLE hPrinter)
  480. {
  481. PCINETMONPORT pIniPort;
  482. BOOL bRet = FALSE;
  483. BOOL bDeletePending = FALSE;
  484. DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: PPClosePrinter: Printer(%08lX)"), hPrinter));
  485. semEnterCrit();
  486. if (pIniPort = utlValidatePrinterHandleForClose(hPrinter, &bDeletePending) ) {
  487. if (bDeletePending) {
  488. bRet = gpInetMon->InetmonReleasePort(pIniPort);
  489. _ppprn_free_hprinter(hPrinter);
  490. }
  491. else {
  492. if ( PP_ChkStatus(hPrinter, PP_STARTDOC) &&
  493. !PP_ChkStatus(hPrinter, PP_ENDDOC)) {
  494. PP_SetStatus(hPrinter, PP_ENDDOC);
  495. pIniPort->EndDocPort(PP_GetJobInfo(hPrinter));
  496. PP_ClrStatus(hPrinter, (PP_STARTDOC | PP_ENDDOC));
  497. PP_CloseJobInfo(hPrinter);
  498. }
  499. // Our write-port does leave the crit-sect. If this
  500. // routine is called while we're still in an end-doc, then
  501. // we will set a zombie-flag and let the End-Doc clean up
  502. // the handle for us.
  503. //
  504. if (PP_ChkStatus(hPrinter, PP_ENDDOC)) {
  505. bRet = TRUE;
  506. PP_SetStatus(hPrinter, PP_ZOMBIE);
  507. } else {
  508. bRet = gpInetMon->InetmonClosePort(pIniPort, hPrinter );
  509. _ppprn_free_hprinter(hPrinter);
  510. }
  511. }
  512. }
  513. #ifdef WINNT32
  514. else if (utlValidateXcvPrinterHandle(hPrinter) ) {
  515. //
  516. // We don't need to dec-ref on the http port for XCV handle
  517. //
  518. //
  519. // Free memory
  520. //
  521. _ppprn_free_xcv_hprinter(hPrinter);
  522. }
  523. #endif
  524. semLeaveCrit();
  525. return bRet;
  526. }
  527. /*****************************************************************************\
  528. * PPEndDocPrinter
  529. *
  530. * Ends a print job on the specified printer. Returns TRUE if successful,
  531. * FALSE otherwise.
  532. *
  533. \*****************************************************************************/
  534. BOOL PPEndDocPrinter(
  535. HANDLE hPrinter)
  536. {
  537. PCINETMONPORT pIniPort;
  538. PJOBMAP pjmJob;
  539. DWORD dwLE;
  540. BOOL bRet = FALSE;
  541. DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: PPEndDocPrinter: Printer(%08lX)"), hPrinter));
  542. semEnterCrit();
  543. if (pIniPort = utlValidatePrinterHandle(hPrinter)) {
  544. // Verify that we are in a StartDoc.
  545. //
  546. if ( PP_ChkStatus(hPrinter, PP_STARTDOC) &&
  547. !PP_ChkStatus(hPrinter, PP_ENDDOC)) {
  548. PP_SetStatus(hPrinter, PP_ENDDOC);
  549. // Get the job we're dealing with.
  550. //
  551. pjmJob = PP_GetJobInfo(hPrinter);
  552. // End the job. This closes our spooling
  553. // and submits it to the server. If our job was
  554. // cancelled at anytime prior to EndDoc(), then we should
  555. // only remove the local-spool-job and not hit the server.
  556. //
  557. if (pjmChkState(pjmJob, PJM_CANCEL)) {
  558. bRet = TRUE;
  559. } else {
  560. #ifdef WINNT32
  561. if ((bRet = _ppprn_end_docprinter_async(pIniPort, pjmJob)) == FALSE)
  562. dwLE = ERROR_CAN_NOT_COMPLETE;
  563. #else
  564. if ((bRet = pIniPort->EndDocPort(pjmJob)) == FALSE)
  565. dwLE = ERROR_CAN_NOT_COMPLETE;
  566. #endif
  567. }
  568. // Clear our flags so others can use the
  569. // printer.
  570. //
  571. PP_ClrStatus(hPrinter, (PP_STARTDOC | PP_ENDDOC));
  572. #ifdef WINNT32
  573. PP_CloseJobInfo2(hPrinter);
  574. #else
  575. PP_CloseJobInfo(hPrinter);
  576. // Invalidate both job and printer caches
  577. //
  578. pIniPort->InvalidateGetPrinterCache ();
  579. pIniPort->InvalidateEnumJobsCache ();
  580. #endif
  581. // Since the end-doc-port leaves the crit-sect, there's
  582. // the possibility that the printer-handle has been
  583. // closed. If so, check for zombie-status and delete
  584. // the printer-handle accordingly.
  585. //
  586. if (PP_ChkStatus(hPrinter, PP_ZOMBIE)) {
  587. gpInetMon->InetmonClosePort(pIniPort, hPrinter);
  588. _ppprn_free_hprinter(hPrinter);
  589. }
  590. } else {
  591. if (PP_ChkStatus(hPrinter, PP_CANCELLED))
  592. dwLE = ERROR_PRINT_CANCELLED;
  593. else
  594. dwLE = ERROR_SPL_NO_STARTDOC;
  595. }
  596. } else {
  597. dwLE = ERROR_INVALID_HANDLE;
  598. }
  599. semLeaveCrit();
  600. if (bRet == FALSE)
  601. SetLastError(dwLE);
  602. return bRet;
  603. }
  604. /*****************************************************************************\
  605. * PPEndPagePrinter
  606. *
  607. * Informs the printer that the data sent with WritePrinter since the last
  608. * BeginPage functions, constitutes a page. Returns TRUE if successful.
  609. * Otherwise, it returns FALSE.
  610. *
  611. \*****************************************************************************/
  612. BOOL PPEndPagePrinter(
  613. HANDLE hPrinter)
  614. {
  615. BOOL bRet = FALSE;
  616. DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: PPEndPagePrinter: hPrinter(%08lX)"), hPrinter));
  617. semEnterCrit();
  618. if (utlValidatePrinterHandle(hPrinter) != NULL) {
  619. if (PP_ChkStatus(hPrinter, PP_CANCELLED))
  620. SetLastError(ERROR_PRINT_CANCELLED);
  621. else
  622. bRet = TRUE;
  623. }
  624. semLeaveCrit();
  625. return bRet;
  626. }
  627. /*****************************************************************************\
  628. * PPOpenPrinter
  629. *
  630. * Obtains a handle for the specified printer (queue).
  631. *
  632. * NOTE: We're going to delay the validation of the printer-port-name until
  633. * later (StartDoc), as to handle cases where the server is down. If
  634. * this is not done, we appear to hang at the UI as we attempt to
  635. * send a request to the server.
  636. *
  637. * Return Value:
  638. *
  639. * We have to return the correct router code to the spooler
  640. *
  641. * ROUTER_* status code:
  642. *
  643. * ROUTER_SUCCESS, phPrinter holds return handle, name cached
  644. * ROUTER_UNKNOWN, printer not recognized, error updated
  645. * ROUTER_STOP_ROUTING, printer recognized, but failure, error updated
  646. *
  647. *
  648. \*****************************************************************************/
  649. #ifdef WINNT32
  650. BOOL PPOpenPrinter(
  651. LPTSTR lpszPrnName,
  652. LPHANDLE phPrinter,
  653. LPPRINTER_DEFAULTS pDefaults)
  654. {
  655. PCINETMONPORT pIniPort;
  656. BOOL bRet = FALSE;
  657. DWORD dwRet = ROUTER_UNKNOWN;
  658. DWORD dwLE;
  659. BOOL bXcv = FALSE;
  660. DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: PPOpenPrinter: Name(%s)"), lpszPrnName));
  661. semEnterCrit();
  662. // Open the port for the printer, and create the true
  663. // printer handle.
  664. //
  665. if (pIniPort = gpInetMon->InetmonOpenPort(lpszPrnName, &bXcv)) {
  666. if (!bXcv) {
  667. // Not an XcvOpen call
  668. if (*phPrinter = _ppprn_make_hprinter(pIniPort, lpszPrnName)) {
  669. if (__ppprn_inc_user_refcout( *phPrinter ) != MAXDWORD ) {
  670. dwRet = ROUTER_SUCCESS;
  671. } else {
  672. _ppprn_free_hprinter( *phPrinter );
  673. // This will also free the hUser
  674. *phPrinter = NULL;
  675. // Make sure we don't return anything and the router stops.
  676. dwRet = ROUTER_STOP_ROUTING;
  677. }
  678. } else {
  679. SetLastError(ERROR_OUTOFMEMORY);
  680. gpInetMon->InetmonClosePort(pIniPort, NULL );
  681. dwRet = ROUTER_STOP_ROUTING;
  682. }
  683. }
  684. else {
  685. // XcvOpen call
  686. if (*phPrinter = _ppprn_make_xcv_hprinter(pIniPort)) {
  687. dwRet = ROUTER_SUCCESS;
  688. }
  689. else {
  690. SetLastError(ERROR_OUTOFMEMORY);
  691. //
  692. // We don't need to dec-ref port since we never add-ref in XCV Open
  693. //
  694. dwRet = ROUTER_STOP_ROUTING;
  695. }
  696. }
  697. }
  698. semLeaveCrit();
  699. DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: PPOpenPrinter : Return Value(%d), LastError(%d)"), dwRet, GetLastError()));
  700. return dwRet;
  701. }
  702. #else
  703. // Win9X Code
  704. BOOL PPOpenPrinter(
  705. LPTSTR lpszPrnName,
  706. LPHANDLE phPrinter,
  707. LPPRINTER_DEFAULTS pDefaults)
  708. {
  709. PCINETMONPORT pIniPort;
  710. BOOL bRet = FALSE;
  711. DWORD dwRet = ROUTER_UNKNOWN;
  712. DWORD dwLE;
  713. BOOL bXcv = FALSE;
  714. DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: PPOpenPrinter: Name(%s)"), lpszPrnName));
  715. semEnterCrit();
  716. // Open the port for the printer, and create the true
  717. // printer handle.
  718. //
  719. if ((pIniPort = gpInetMon->InetmonOpenPort(lpszPrnName, &bXcv)) && !bXcv) {
  720. if (*phPrinter = _ppprn_make_hprinter(pIniPort, lpszPrnName)) {
  721. dwRet = ROUTER_SUCCESS;
  722. } else {
  723. SetLastError(ERROR_OUTOFMEMORY);
  724. gpInetMon->InetmonClosePort(pIniPort, NULL );
  725. }
  726. }
  727. semLeaveCrit();
  728. DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: PPOpenPrinter : Return Value(%d), LastError(%d)"), dwRet, GetLastError()));
  729. return dwRet;
  730. }
  731. #endif
  732. /*****************************************************************************\
  733. * PPStartDocPrinter
  734. *
  735. * Ends a print job on the specified printer. Returns a print job ID if
  736. * successful. Otherwise, it returns zero.
  737. *
  738. \*****************************************************************************/
  739. DWORD PPStartDocPrinter(
  740. HANDLE hPrinter,
  741. DWORD dwLevel,
  742. LPBYTE pDocInfo)
  743. {
  744. PCINETMONPORT pIniPort = NULL;
  745. PJOBMAP pjmJob;
  746. DWORD idJob = 0;
  747. DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: PPStartDocPrinter: Printer(%08lX) dwLevel(%d)"), hPrinter, dwLevel));
  748. semEnterCrit();
  749. if (pIniPort = utlValidatePrinterHandle(hPrinter)) {
  750. // Look at the support levels, then do the StartDocPrinter on
  751. // the port.
  752. //
  753. switch (dwLevel) {
  754. case PRINT_LEVEL_1:
  755. // Serialize access to the port. Don't allow startdoc on
  756. // the printer if one is already in progress.
  757. //
  758. if (PP_ChkStatus(hPrinter, PP_STARTDOC)) {
  759. SetLastError(ERROR_BUSY);
  760. } else {
  761. if (pjmJob = PP_OpenJobInfo(hPrinter, pIniPort, ((PDOC_INFO_1) pDocInfo)->pDocName)) {
  762. // Get the JobId for the start-doc, then set the info
  763. // into the printer-handle.
  764. //
  765. if (pIniPort->StartDocPort(dwLevel, pDocInfo, pjmJob)) {
  766. idJob = pjmJobId(pjmJob, PJM_LOCALID);
  767. PP_ClrStatus(hPrinter, PP_CANCELLED);
  768. PP_SetStatus(hPrinter, (PP_STARTDOC | PP_FIRSTWRITE));
  769. } else {
  770. PP_CloseJobInfo(hPrinter);
  771. }
  772. } else {
  773. SetLastError(ERROR_OUTOFMEMORY);
  774. }
  775. }
  776. break;
  777. default:
  778. DBG_MSG(DBG_LEV_WARN, (TEXT("Warn: PPStartDocPrinter: Invalid Level (%d)"), dwLevel));
  779. SetLastError(ERROR_INVALID_LEVEL);
  780. break;
  781. }
  782. }
  783. semLeaveCrit();
  784. return idJob;
  785. }
  786. /*****************************************************************************\
  787. * PPStartPagePrinter
  788. *
  789. * Informs the spool subsystem that a page is about to be started on this
  790. * printer. Returns TRUE if successful. Otherwise, FALSE if an error occurs.
  791. *
  792. \*****************************************************************************/
  793. BOOL PPStartPagePrinter(
  794. HANDLE hPrinter)
  795. {
  796. BOOL bRet = FALSE;
  797. DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: PPStartPagePrinter: hPrinter(%08lX)"), hPrinter));
  798. semEnterCrit();
  799. if (utlValidatePrinterHandle(hPrinter) != NULL) {
  800. if (PP_ChkStatus(hPrinter, PP_CANCELLED))
  801. SetLastError(ERROR_PRINT_CANCELLED);
  802. else
  803. bRet = TRUE;
  804. }
  805. semLeaveCrit();
  806. return bRet;
  807. }
  808. /*****************************************************************************\
  809. * PPWritePrinter
  810. *
  811. * Sends the data pointed to by pBuf to the specified printer. Returns TRUE
  812. * if successful. Otherwise, it returns FALSE.
  813. *
  814. \*****************************************************************************/
  815. BOOL PPWritePrinter(
  816. HANDLE hPrinter,
  817. LPVOID lpvBuf,
  818. DWORD cbBuf,
  819. LPDWORD pcbWr)
  820. {
  821. PCINETMONPORT pIniPort;
  822. PJOBMAP pjmJob;
  823. BOOL bRet = FALSE;
  824. DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: PPWritePrinter: Printer(%08lX)"), hPrinter));
  825. semEnterCrit();
  826. *pcbWr = 0;
  827. if (pIniPort = utlValidatePrinterHandle(hPrinter)) {
  828. // If we're in a start-doc, and end-doc hasn't been
  829. // called, then we can still write to the port.
  830. //
  831. if ( PP_ChkStatus(hPrinter, PP_STARTDOC) &&
  832. !PP_ChkStatus(hPrinter, PP_ENDDOC)) {
  833. pjmJob = PP_GetJobInfo(hPrinter);
  834. // If we received a SetJob(CANCEL), during the print-spooling
  835. // process, then we need to mark our job as done.
  836. //
  837. if (!pjmChkState(pjmJob, PJM_CANCEL)) {
  838. bRet = pIniPort->WritePort(pjmJob, (LPBYTE) lpvBuf, cbBuf, pcbWr);
  839. #ifdef WINNT32
  840. pjmAddJobSize (pjmJob, *pcbWr);
  841. // We do not need to update the cache since the job info is stored locally
  842. //
  843. RefreshNotificationPort (pIniPort);
  844. #endif
  845. } else {
  846. bRet = TRUE;
  847. if (pIniPort->AbortPort(pjmJob)) {
  848. // If this call was successful, the job-info
  849. // will have been freed. Therefore, it is OK
  850. // to set the printer-jobreq to NULL.
  851. //
  852. PP_SetStatus(hPrinter, PP_CANCELLED);
  853. PP_ClrStatus(hPrinter, PP_STARTDOC);
  854. PP_CloseJobInfo(hPrinter);
  855. }
  856. }
  857. } else {
  858. if (PP_ChkStatus(hPrinter, PP_CANCELLED))
  859. SetLastError(ERROR_PRINT_CANCELLED);
  860. else
  861. SetLastError(ERROR_SPL_NO_STARTDOC);
  862. }
  863. }
  864. semLeaveCrit();
  865. return bRet;
  866. }
  867. /*****************************************************************************\
  868. * PPSetPrinter
  869. *
  870. * Set printer command.
  871. *
  872. \*****************************************************************************/
  873. BOOL PPSetPrinter(
  874. HANDLE hPrinter,
  875. DWORD dwLevel,
  876. LPBYTE pbPrinter,
  877. DWORD dwCmd)
  878. {
  879. PCINETMONPORT pIniPort;
  880. BOOL bRet = FALSE;
  881. DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: PPSetPrinter: Printer(%08lX)"), hPrinter));
  882. semEnterCrit();
  883. if (pIniPort = utlValidatePrinterHandle(hPrinter)) {
  884. #ifdef WINNT32
  885. // Set printer parameters.
  886. //
  887. switch (dwLevel) {
  888. case PRINT_LEVEL_0:
  889. // Do not set parameters. (0) represents "no-command".
  890. //
  891. switch (dwCmd) {
  892. case PRINTER_CONTROL_PAUSE:
  893. case PRINTER_CONTROL_RESUME:
  894. case PRINTER_CONTROL_PURGE:
  895. bRet = ppprn_Set(pIniPort, dwCmd);
  896. if (bRet) {
  897. pIniPort->InvalidateGetPrinterCache ();
  898. if (dwCmd == PRINTER_CONTROL_PURGE) {
  899. //
  900. // Clean job cache if the command is to cancel all documents
  901. //
  902. pIniPort->InvalidateEnumJobsCache ();
  903. }
  904. RefreshNotification((LPINET_HPRINTER)hPrinter);
  905. }
  906. break;
  907. case 0:
  908. bRet = TRUE;
  909. break;
  910. }
  911. break;
  912. default:
  913. DBG_MSG(DBG_LEV_WARN, (TEXT("Warn: PPSetPrinter: Invalid Level (%d)"), dwLevel));
  914. SetLastError(ERROR_INVALID_LEVEL);
  915. break;
  916. }
  917. #else
  918. if (dwCmd) {
  919. // Do not set parameters. (0) represents "no-command".
  920. //
  921. switch (dwCmd) {
  922. case PRINTER_CONTROL_PAUSE:
  923. case PRINTER_CONTROL_RESUME:
  924. case PRINTER_CONTROL_PURGE:
  925. bRet = ppprn_Set(pIniPort, dwCmd);
  926. break;
  927. }
  928. } else {
  929. switch (dwLevel) {
  930. case PRINT_LEVEL_1:
  931. case PRINT_LEVEL_2:
  932. case PRINT_LEVEL_0:
  933. default:
  934. DBG_MSG(DBG_LEV_WARN, (TEXT("Warn: PPSetPrinter: Invalid Level (%d)"), dwLevel));
  935. SetLastError(ERROR_INVALID_LEVEL);
  936. break;
  937. }
  938. }
  939. #endif
  940. }
  941. semLeaveCrit();
  942. return bRet;
  943. }