Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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