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.

1998 lines
55 KiB

  1. /*****************************************************************************\
  2. * MODULE: ppjobs.c
  3. *
  4. * This module contains the print-job manipulating routines.
  5. *
  6. *
  7. * Copyright (C) 1996-1997 Microsoft Corporation
  8. * Copyright (C) 1996-1997 Hewlett Packard
  9. *
  10. * History:
  11. * 07-Oct-1996 HWP-Guys Initiated port from win95 to winNT
  12. *
  13. \*****************************************************************************/
  14. #include "precomp.h"
  15. #include "priv.h"
  16. BOOL
  17. _ppprn_end_docprinter_async (
  18. PCINETMONPORT pIniPort,
  19. PJOBMAP pjmJob);
  20. typedef struct _ADDJOB_INFO_2W {
  21. LPWSTR pData;
  22. DWORD JobId;
  23. } ADDJOB_INFO_2W, *PADDJOB_INFO_2W, *LPADDJOB_INFO_2W;
  24. DWORD
  25. ppjob_GetOneSize (
  26. DWORD dwLevel)
  27. {
  28. DWORD cbIdx;
  29. switch (dwLevel) {
  30. case PRINT_LEVEL_1:
  31. cbIdx = sizeof(JOB_INFO_1);
  32. break;
  33. case PRINT_LEVEL_2:
  34. cbIdx = sizeof(JOB_INFO_2);
  35. break;
  36. case PRINT_LEVEL_3:
  37. cbIdx = sizeof(JOB_INFO_3);
  38. break;
  39. }
  40. return cbIdx;
  41. }
  42. /*****************************************************************************\
  43. * ppjob_IppPrtRsp (Local Routine)
  44. *
  45. * Retrieves a get response from the IPP server. Our (pjmJob) in the
  46. * parameter list references a job-entry.
  47. *
  48. \*****************************************************************************/
  49. BOOL CALLBACK ppjob_IppPrtRsp(
  50. CAnyConnection *pConnection,
  51. HINTERNET hJobReq,
  52. PCINETMONPORT pIniPort,
  53. PJOBMAP pjmJob)
  54. {
  55. HANDLE hIpp;
  56. DWORD dwRet;
  57. DWORD cbRd;
  58. LPBYTE lpDta;
  59. DWORD cbDta;
  60. LPIPPRET_JOB lpRsp;
  61. DWORD cbRsp;
  62. BYTE bBuf[MAX_IPP_BUFFER];
  63. BOOL bRet = FALSE;
  64. if (hIpp = WebIppRcvOpen(IPP_RET_PRINTJOB)) {
  65. while (TRUE) {
  66. cbRd = 0;
  67. if (pIniPort->ReadFile ( pConnection, hJobReq, (LPVOID)bBuf, sizeof(bBuf), &cbRd) && cbRd) {
  68. dwRet = WebIppRcvData(hIpp, bBuf, cbRd, (LPBYTE*)&lpRsp, &cbRsp, &lpDta, &cbDta);
  69. switch (dwRet) {
  70. case WEBIPP_OK:
  71. if (bRet = lpRsp->bRet) {
  72. // Set the remote-job-id to the job-entry. This
  73. // entry was added at the time the spool-job-file
  74. // was created.
  75. //
  76. semEnterCrit();
  77. pjmSetJobRemote(pjmJob, lpRsp->ji.ji2.JobId, lpRsp->ji.ipp.pJobUri);
  78. semLeaveCrit();
  79. } else {
  80. // If the job failed to open on the server, then
  81. // we will set the last-error from the server
  82. // response.
  83. //
  84. SetLastError(lpRsp->dwLastError);
  85. }
  86. WebIppFreeMem(lpRsp);
  87. goto EndPrtRsp;
  88. case WEBIPP_MOREDATA:
  89. // Need to do another read to fullfill our header-response.
  90. //
  91. break;
  92. default:
  93. DBG_MSG(DBG_LEV_ERROR, (TEXT("ppjob_IppPrtRsp : Receive Data Error")));
  94. SetLastError(ERROR_INVALID_DATA);
  95. goto EndPrtRsp;
  96. }
  97. } else {
  98. goto EndPrtRsp;
  99. }
  100. }
  101. EndPrtRsp:
  102. WebIppRcvClose(hIpp);
  103. } else {
  104. SetLastError(ERROR_OUTOFMEMORY);
  105. }
  106. return bRet;
  107. }
  108. /*****************************************************************************\
  109. * ppjob_GetJobSize (Local Routine)
  110. *
  111. * Returns the size necessary to hold the jobinfo.
  112. *
  113. \*****************************************************************************/
  114. DWORD ppjob_GetJobSize(
  115. LPJOB_INFO_2 pji2,
  116. DWORD dwLevel)
  117. {
  118. DWORD cbSize;
  119. switch (dwLevel) {
  120. case PRINT_LEVEL_1:
  121. cbSize = sizeof(JOB_INFO_1) +
  122. utlStrSize(pji2->pPrinterName) +
  123. utlStrSize(pji2->pMachineName) +
  124. utlStrSize(pji2->pUserName) +
  125. utlStrSize(pji2->pDocument) +
  126. utlStrSize(pji2->pDatatype) +
  127. utlStrSize(pji2->pStatus);
  128. break;
  129. case PRINT_LEVEL_2:
  130. cbSize = sizeof(JOB_INFO_2) +
  131. utlStrSize(pji2->pPrinterName) +
  132. utlStrSize(pji2->pMachineName) +
  133. utlStrSize(pji2->pUserName) +
  134. utlStrSize(pji2->pDocument) +
  135. utlStrSize(pji2->pNotifyName) +
  136. utlStrSize(pji2->pDatatype) +
  137. utlStrSize(pji2->pPrintProcessor) +
  138. utlStrSize(pji2->pParameters) +
  139. utlStrSize(pji2->pDriverName) +
  140. utlStrSize(pji2->pStatus);
  141. if (pji2->pDevMode)
  142. cbSize += (pji2->pDevMode->dmSize + pji2->pDevMode->dmDriverExtra);
  143. cbSize = (cbSize + sizeof(DWORD)-1) & ~(sizeof(DWORD)-1);
  144. break;
  145. case PRINT_LEVEL_3:
  146. cbSize = sizeof(JOB_INFO_3);
  147. break;
  148. default:
  149. cbSize = 0;
  150. break;
  151. }
  152. return cbSize;
  153. }
  154. /*****************************************************************************\
  155. * ppjob_CopyJob (Local Routine)
  156. *
  157. * Copies a job-info structure to another.
  158. *
  159. \*****************************************************************************/
  160. LPBYTE ppjob_CopyJob(
  161. LPBYTE pbJobDst,
  162. DWORD dwLevel,
  163. LPJOB_INFO_2 pji2Src,
  164. LPBYTE pbEnd)
  165. {
  166. LPJOB_INFO_1 pji1Dst;
  167. LPJOB_INFO_2 pji2Dst;
  168. LPJOB_INFO_3 pji3Dst;
  169. LPJOBMAP pjm;
  170. LPDWORD pOffsets;
  171. DWORD cbDM;
  172. LPTSTR* lpszSrc;
  173. LPTSTR aszSrc[(sizeof(JOB_INFO_2) / sizeof(LPTSTR))];
  174. static DWORD s_JI1Offsets[] = {
  175. offsetof(LPJOB_INFO_1, pPrinterName),
  176. offsetof(LPJOB_INFO_1, pMachineName),
  177. offsetof(LPJOB_INFO_1, pUserName),
  178. offsetof(LPJOB_INFO_1, pDocument),
  179. offsetof(LPJOB_INFO_1, pDatatype),
  180. offsetof(LPJOB_INFO_1, pStatus),
  181. 0xFFFFFFFF
  182. };
  183. static DWORD s_JI2Offsets[] = {
  184. offsetof(LPJOB_INFO_2, pPrinterName),
  185. offsetof(LPJOB_INFO_2, pMachineName),
  186. offsetof(LPJOB_INFO_2, pUserName),
  187. offsetof(LPJOB_INFO_2, pDocument),
  188. offsetof(LPJOB_INFO_2, pNotifyName),
  189. offsetof(LPJOB_INFO_2, pDatatype),
  190. offsetof(LPJOB_INFO_2, pPrintProcessor),
  191. offsetof(LPJOB_INFO_2, pParameters),
  192. offsetof(LPJOB_INFO_2, pDriverName),
  193. offsetof(LPJOB_INFO_2, pDevMode),
  194. offsetof(LPJOB_INFO_2, pStatus),
  195. offsetof(LPJOB_INFO_2, pSecurityDescriptor),
  196. 0xFFFFFFFF
  197. };
  198. static DWORD s_JI3Offsets[]={0xFFFFFFFF};
  199. // Set the start of the string-buffer.
  200. //
  201. ZeroMemory(aszSrc, sizeof(aszSrc));
  202. lpszSrc = aszSrc;
  203. // Process the appropriate structure.
  204. //
  205. switch (dwLevel) {
  206. case PRINT_LEVEL_1:
  207. pji1Dst = (LPJOB_INFO_1)pbJobDst;
  208. pOffsets = s_JI1Offsets;
  209. // Copy fixed values.
  210. //
  211. pji1Dst->JobId = pji2Src->JobId;
  212. pji1Dst->Status = pji2Src->Status;
  213. pji1Dst->Priority = pji2Src->Priority;
  214. pji1Dst->Position = pji2Src->Position;
  215. pji1Dst->TotalPages = pji2Src->TotalPages;
  216. pji1Dst->PagesPrinted = pji2Src->PagesPrinted;
  217. pji1Dst->Submitted = pji2Src->Submitted;
  218. // Copy strings.
  219. //
  220. *lpszSrc++ = pji2Src->pPrinterName;
  221. *lpszSrc++ = pji2Src->pMachineName;
  222. *lpszSrc++ = pji2Src->pUserName;
  223. *lpszSrc++ = pji2Src->pDocument;
  224. *lpszSrc++ = pji2Src->pDatatype;
  225. *lpszSrc++ = pji2Src->pStatus;
  226. break;
  227. case PRINT_LEVEL_2:
  228. pji2Dst = (LPJOB_INFO_2)pbJobDst;
  229. pOffsets = s_JI2Offsets;
  230. // Copy fixed values.
  231. //
  232. pji2Dst->JobId = pji2Src->JobId;
  233. pji2Dst->Status = pji2Src->Status;
  234. pji2Dst->Priority = pji2Src->Priority;
  235. pji2Dst->Position = pji2Src->Position;
  236. pji2Dst->StartTime = pji2Src->StartTime;
  237. pji2Dst->UntilTime = pji2Src->UntilTime;
  238. pji2Dst->TotalPages = pji2Src->TotalPages;
  239. pji2Dst->Size = pji2Src->Size;
  240. pji2Dst->Submitted = pji2Src->Submitted;
  241. pji2Dst->Time = pji2Src->Time;
  242. pji2Dst->PagesPrinted = pji2Src->PagesPrinted;
  243. pji2Dst->pSecurityDescriptor = NULL;
  244. pji2Dst->pDevMode = NULL;
  245. // Copy strings.
  246. //
  247. *lpszSrc++ = pji2Src->pPrinterName;
  248. *lpszSrc++ = pji2Src->pMachineName;
  249. *lpszSrc++ = pji2Src->pUserName;
  250. *lpszSrc++ = pji2Src->pDocument;
  251. *lpszSrc++ = pji2Src->pNotifyName;
  252. *lpszSrc++ = pji2Src->pDatatype;
  253. *lpszSrc++ = pji2Src->pPrintProcessor;
  254. *lpszSrc++ = pji2Src->pParameters;
  255. *lpszSrc++ = pji2Src->pDriverName;
  256. *lpszSrc++ = NULL;
  257. *lpszSrc++ = pji2Src->pStatus;
  258. *lpszSrc++ = NULL;
  259. if (pji2Src->pDevMode) {
  260. cbDM = pji2Src->pDevMode->dmSize + pji2Src->pDevMode->dmDriverExtra;
  261. pbEnd -= cbDM;
  262. pbEnd = (LPBYTE)((UINT_PTR)pbEnd & ~((UINT_PTR)sizeof(UINT_PTR) - 1));
  263. pji2Dst->pDevMode = (LPDEVMODE)pbEnd;
  264. CopyMemory(pji2Dst->pDevMode, pji2Src->pDevMode, cbDM);
  265. }
  266. break;
  267. case PRINT_LEVEL_3:
  268. pji3Dst = (LPJOB_INFO_3)pbJobDst;
  269. pOffsets = s_JI3Offsets;
  270. pji3Dst->JobId = pji2Src->JobId;
  271. break;
  272. }
  273. return utlPackStrings(aszSrc, (LPBYTE)pbJobDst, pOffsets, pbEnd);
  274. }
  275. BOOL ppjob_CalcAndCopyJob(
  276. LPBYTE pbJob,
  277. DWORD cbJob,
  278. PDWORD pcbNeed,
  279. PJOB_INFO_2 pji2,
  280. DWORD dwLevel)
  281. {
  282. BOOL bRet = FALSE;
  283. LPBYTE pbEnd;
  284. // Fill in what we need.
  285. //
  286. *pcbNeed = ppjob_GetJobSize(pji2, dwLevel);
  287. // If our buffer is big-enough, then
  288. // proceed to fill in the info.
  289. //
  290. if (cbJob >= *pcbNeed) {
  291. pbEnd = pbJob + cbJob;
  292. ppjob_CopyJob(pbJob, dwLevel, pji2, pbEnd);
  293. bRet = TRUE;
  294. } else {
  295. SetLastError (ERROR_INSUFFICIENT_BUFFER);
  296. }
  297. return bRet;
  298. }
  299. /*****************************************************************************\
  300. * ppjob_IppEnuRsp (Local Callback Routine)
  301. *
  302. * Retrieves a get response from the IPP server. Our (lParam) in the
  303. * parameter list references a LPPPJOB_ENUM pointer which we are to fill
  304. * in from the enumeration.
  305. *
  306. \*****************************************************************************/
  307. BOOL CALLBACK ppjob_IppEnuRsp(
  308. CAnyConnection *pConnection,
  309. HINTERNET hReq,
  310. PCINETMONPORT pIniPort,
  311. LPARAM lParam)
  312. {
  313. HANDLE hIpp;
  314. DWORD dwRet;
  315. DWORD cbRd;
  316. LPBYTE pbEnd;
  317. DWORD idx;
  318. DWORD idx2;
  319. LPBYTE lpDta;
  320. DWORD cbDta;
  321. LPIPPRET_ENUJOB lpRsp;
  322. DWORD cbRsp;
  323. LPPPJOB_ENUM pje;
  324. LPIPPJI2 pji2;
  325. LPJOBMAP pjm;
  326. PDWORD pidJob;
  327. DWORD cbSize;
  328. PJOBMAP* pjmList;
  329. BYTE bBuf[MAX_IPP_BUFFER];
  330. BOOL bRet = FALSE;
  331. time_t dwPrinterT0;
  332. if (hIpp = WebIppRcvOpen(IPP_RET_ENUJOB)) {
  333. while (TRUE) {
  334. cbRd = 0;
  335. if (pIniPort->ReadFile ( pConnection, hReq, (LPVOID)bBuf, sizeof(bBuf), &cbRd) && cbRd) {
  336. dwRet = WebIppRcvData(hIpp, bBuf, cbRd, (LPBYTE*)&lpRsp, &cbRsp, &lpDta, &cbDta);
  337. switch (dwRet) {
  338. case WEBIPP_OK:
  339. if (bRet = lpRsp->bRet) {
  340. if (lpRsp->cItems && lpRsp->cbItems) {
  341. semEnterCrit();
  342. pjmList = pIniPort->GetPJMList();
  343. pjmCleanRemoteFlag(pjmList);
  344. pji2 = lpRsp->pItems;
  345. // We go over the IPP response and put them into PJM list
  346. // At the mean time, we convert the remote job ID to
  347. // local job id and store them into the IPP response
  348. // data structure.
  349. //
  350. for (idx = 0; idx < lpRsp->cItems; idx++) {
  351. // Fixup the job-id to the local id we
  352. // can deal with.
  353. //
  354. pidJob = & (pji2[idx].ji2.JobId);
  355. if (pjm = pjmFind(pjmList, PJM_REMOTEID, *pidJob)) {
  356. *pidJob = pjmJobId(pjm, PJM_LOCALID);
  357. } else {
  358. if (pjm = pjmAdd(pjmList, pIniPort, NULL, NULL))
  359. pjmSetJobRemote(pjm, *pidJob, pji2[idx].ipp.pJobUri);
  360. *pidJob = pjmJobId(pjm, PJM_LOCALID);
  361. }
  362. }
  363. // Call our routine to clean our client-list
  364. // of jobs. This will remove any entries
  365. // that no longer exist on the server.
  366. //
  367. cbSize = sizeof(PPJOB_ENUM) + lpRsp->cbItems;
  368. // Allocate storage for enumeration.
  369. //
  370. if (pje = (LPPPJOB_ENUM)memAlloc(cbSize)) {
  371. dwPrinterT0 = pIniPort->GetPowerUpTime();
  372. // This now containts the powerup time for the printer in
  373. // our time
  374. pje->cItems = lpRsp->cItems;
  375. pje->cbSize = lpRsp->cbItems;
  376. pji2 = lpRsp->pItems;
  377. pbEnd = ((LPBYTE)pje->ji2) + pje->cbSize;
  378. for (idx = 0; idx < lpRsp->cItems; idx++) {
  379. pbEnd = ppjob_CopyJob((LPBYTE)&pje->ji2[idx],
  380. 2,
  381. &pji2[idx].ji2,
  382. pbEnd);
  383. WebIppConvertSystemTime(&pje->ji2[idx].ji2.Submitted, dwPrinterT0);
  384. }
  385. pjmRemoveOldEntries(pjmList);
  386. semLeaveCrit();
  387. *((LPPPJOB_ENUM *)lParam) = pje;
  388. } else {
  389. SetLastError(ERROR_OUTOFMEMORY);
  390. }
  391. }
  392. else {
  393. //
  394. // This is the case where the job count is 0 on the server
  395. // We still need to allocate the structure so that the client
  396. // enum-job function can merge the localjobs.
  397. //
  398. cbSize = sizeof(PPJOB_ENUM);
  399. // Allocate storage for enumeration.
  400. //
  401. if (pje = (LPPPJOB_ENUM)memAlloc(cbSize)) {
  402. pje->cItems = 0;
  403. pje->cbSize = 0;
  404. *((LPPPJOB_ENUM *)lParam) = pje;
  405. } else {
  406. SetLastError(ERROR_OUTOFMEMORY);
  407. }
  408. }
  409. } else {
  410. SetLastError(lpRsp->dwLastError);
  411. }
  412. WebIppFreeMem(lpRsp);
  413. goto EndEnuRsp;
  414. case WEBIPP_MOREDATA:
  415. // Need to do another read to fullfill our header-response.
  416. //
  417. break;
  418. default:
  419. DBG_MSG(DBG_LEV_ERROR, (TEXT("ppjob_IppEnuRsp : Receive Data Error")));
  420. SetLastError(ERROR_INVALID_DATA);
  421. goto EndEnuRsp;
  422. }
  423. } else {
  424. goto EndEnuRsp;
  425. }
  426. }
  427. EndEnuRsp:
  428. WebIppRcvClose(hIpp);
  429. } else {
  430. SetLastError(ERROR_OUTOFMEMORY);
  431. }
  432. return bRet;
  433. }
  434. /*****************************************************************************\
  435. * ppjob_IppSetRsp (Local Callback Routine)
  436. *
  437. * Retrieves a SetJob response from the IPP server
  438. *
  439. \*****************************************************************************/
  440. BOOL CALLBACK ppjob_IppSetRsp(
  441. CAnyConnection *pConnection,
  442. HINTERNET hReq,
  443. PCINETMONPORT pIniPort,
  444. LPARAM lParam)
  445. {
  446. HANDLE hIpp;
  447. DWORD dwRet;
  448. DWORD cbRd;
  449. LPBYTE lpDta;
  450. DWORD cbDta;
  451. LPIPPRET_JOB lpRsp;
  452. DWORD cbRsp;
  453. BYTE bBuf[MAX_IPP_BUFFER];
  454. BOOL bRet = FALSE;
  455. if (hIpp = WebIppRcvOpen((WORD)(LPARAM)lParam)) {
  456. while (TRUE) {
  457. cbRd = 0;
  458. if (pIniPort->ReadFile (pConnection, hReq, (LPVOID)bBuf, sizeof(bBuf), &cbRd) && cbRd) {
  459. dwRet = WebIppRcvData(hIpp, bBuf, cbRd, (LPBYTE*)&lpRsp, &cbRsp, &lpDta, &cbDta);
  460. switch (dwRet) {
  461. case WEBIPP_OK:
  462. if ((bRet = lpRsp->bRet) == FALSE)
  463. SetLastError(lpRsp->dwLastError);
  464. WebIppFreeMem(lpRsp);
  465. goto EndSetRsp;
  466. case WEBIPP_MOREDATA:
  467. // Need to do another read to fullfill our header-response.
  468. //
  469. break;
  470. default:
  471. DBG_MSG(DBG_LEV_ERROR, (TEXT("ppjob_IppSetRsp : Receive Data Error")));
  472. SetLastError(ERROR_INVALID_DATA);
  473. goto EndSetRsp;
  474. }
  475. } else {
  476. goto EndSetRsp;
  477. }
  478. }
  479. EndSetRsp:
  480. WebIppRcvClose(hIpp);
  481. } else {
  482. SetLastError(ERROR_OUTOFMEMORY);
  483. }
  484. return bRet;
  485. }
  486. /*****************************************************************************\
  487. * ppjob_IppGetRsp (Local Callback Routine)
  488. *
  489. * Retrieves a get response from the IPP server. Our (lParam) in the
  490. * parameter list references a JOB_INFO_2 pointer which we are to fill
  491. * in from the call.
  492. *
  493. \*****************************************************************************/
  494. BOOL CALLBACK ppjob_IppGetRsp(
  495. CAnyConnection *pConnection,
  496. HINTERNET hReq,
  497. PCINETMONPORT pIniPort,
  498. LPARAM lParam)
  499. {
  500. HANDLE hIpp;
  501. DWORD dwRet;
  502. DWORD cbRd;
  503. LPBYTE pbEnd;
  504. DWORD idx;
  505. LPBYTE lpDta;
  506. DWORD cbDta;
  507. LPIPPRET_JOB lpRsp;
  508. DWORD cbRsp;
  509. LPJOB_INFO_2 pji2;
  510. LPJOBMAP pjm;
  511. DWORD cbSize;
  512. BYTE bBuf[MAX_IPP_BUFFER];
  513. PJOBMAP* pjmList;
  514. BOOL bRet = FALSE;
  515. if (hIpp = WebIppRcvOpen(IPP_RET_GETJOB)) {
  516. while (TRUE) {
  517. cbRd = 0;
  518. if (pIniPort->ReadFile ( pConnection, hReq, (LPVOID)bBuf, sizeof(bBuf), &cbRd) && cbRd) {
  519. dwRet = WebIppRcvData(hIpp, bBuf, cbRd, (LPBYTE*)&lpRsp, &cbRsp, &lpDta, &cbDta);
  520. switch (dwRet) {
  521. case WEBIPP_OK:
  522. if (bRet = lpRsp->bRet) {
  523. cbSize = ppjob_GetJobSize(&lpRsp->ji.ji2, 2);
  524. // Allocate storage for enumeration.
  525. //
  526. if (pji2 = (LPJOB_INFO_2)memAlloc(cbSize)) {
  527. pbEnd = ((LPBYTE)pji2) + cbSize;
  528. ppjob_CopyJob((LPBYTE)pji2, 2, &lpRsp->ji.ji2, pbEnd);
  529. semEnterCrit();
  530. pjmList = pIniPort->GetPJMList();
  531. // Fixup the job-id to the local id we
  532. // can deal with.
  533. //
  534. if (pjm = pjmFind(pjmList, PJM_REMOTEID, pji2->JobId)) {
  535. pji2->JobId = pjmJobId(pjm, PJM_LOCALID);
  536. } else {
  537. if (pjm = pjmAdd(pjmList, pIniPort, NULL, NULL))
  538. pjmSetJobRemote(pjm, pji2->JobId, lpRsp->ji.ipp.pJobUri);
  539. pji2->JobId = pjmJobId(pjm, PJM_LOCALID);
  540. }
  541. semLeaveCrit();
  542. *((LPJOB_INFO_2 *)lParam) = pji2;
  543. } else {
  544. SetLastError(ERROR_OUTOFMEMORY);
  545. }
  546. } else {
  547. SetLastError(lpRsp->dwLastError);
  548. }
  549. WebIppFreeMem(lpRsp);
  550. goto EndGetRsp;
  551. case WEBIPP_MOREDATA:
  552. // Need to do another read to fullfill our header-response.
  553. //
  554. break;
  555. default:
  556. DBG_MSG(DBG_LEV_ERROR, (TEXT("ppjob_IppGetRsp - Err : Receive Data Error (dwRet=%d, LE=%d)"),
  557. dwRet, WebIppGetError(hIpp)));
  558. SetLastError(ERROR_INVALID_DATA);
  559. goto EndGetRsp;
  560. }
  561. } else {
  562. goto EndGetRsp;
  563. }
  564. }
  565. EndGetRsp:
  566. WebIppRcvClose(hIpp);
  567. } else {
  568. SetLastError(ERROR_OUTOFMEMORY);
  569. }
  570. return bRet;
  571. }
  572. /*****************************************************************************\
  573. * ppjob_Set (Local Routine)
  574. *
  575. * Sets a job command in the queue.
  576. *
  577. \*****************************************************************************/
  578. BOOL ppjob_Set(
  579. PCINETMONPORT pIniPort,
  580. DWORD idJob,
  581. DWORD dwCmd)
  582. {
  583. PIPPREQ_SETJOB psj;
  584. PJOBMAP pjm;
  585. WORD wReq;
  586. REQINFO ri;
  587. DWORD dwRet;
  588. LPBYTE lpIpp;
  589. DWORD cbIpp;
  590. PJOBMAP* pjmList;
  591. BOOL bRet = FALSE;
  592. // Make sure we have a JobMap entry which we can
  593. // obtain the remote information.
  594. //
  595. pjmList = pIniPort->GetPJMList();
  596. if (pjm = pjmFind(pjmList, PJM_LOCALID, idJob)) {
  597. // If we're still spooling, then we haven't yet
  598. // hit the server. Otherwise, we've performed the EndDoc()
  599. // and the job is being processed remotely.
  600. //
  601. if (pjmChkState(pjm, PJM_SPOOLING)) {
  602. switch (dwCmd) {
  603. case JOB_CONTROL_CANCEL:
  604. case JOB_CONTROL_DELETE:
  605. pjmSetState(pjm, PJM_CANCEL);
  606. //
  607. // If the async thread is on, we let that thread to clean the job queue
  608. //
  609. if (!pjmChkState(pjm, PJM_ASYNCON))
  610. {
  611. //
  612. // Otherwise, we delete the job here.
  613. //
  614. pjmClrState (pjm, PJM_SPOOLING);
  615. }
  616. break;
  617. case JOB_CONTROL_PAUSE:
  618. pjmSetState(pjm, PJM_PAUSE);
  619. break;
  620. case JOB_CONTROL_RESUME:
  621. pjmClrState(pjm, PJM_PAUSE);
  622. break;
  623. case JOB_CONTROL_RESTART:
  624. pjmUpdateLocalJobStatus (pjm, JOB_STATUS_RESTART);
  625. if (!pjmChkState(pjm, PJM_ASYNCON))
  626. {
  627. _ppprn_end_docprinter_async (pIniPort, pjm);
  628. }
  629. break;
  630. }
  631. bRet = TRUE;
  632. } else {
  633. // Look through list to get local/remote job mappings.
  634. //
  635. psj = WebIppCreateSetJobReq(pjmJobId(pjm, PJM_REMOTEID),
  636. dwCmd,
  637. pIniPort->GetPortName());
  638. if (psj) {
  639. switch (dwCmd) {
  640. case JOB_CONTROL_CANCEL:
  641. case JOB_CONTROL_DELETE:
  642. wReq = IPP_REQ_CANCELJOB;
  643. break;
  644. case JOB_CONTROL_PAUSE:
  645. wReq = IPP_REQ_PAUSEJOB;
  646. break;
  647. case JOB_CONTROL_RESUME:
  648. wReq = IPP_REQ_RESUMEJOB;
  649. break;
  650. case JOB_CONTROL_RESTART:
  651. wReq = IPP_REQ_RESTARTJOB;
  652. break;
  653. default:
  654. wReq = 0;
  655. break;
  656. }
  657. // Convert the reqest to IPP, and perform the
  658. // post.
  659. //
  660. ZeroMemory(&ri, sizeof(REQINFO));
  661. ri.cpReq = CP_UTF8;
  662. ri.idReq = wReq;
  663. ri.fReq[0] = IPP_REQALL;
  664. ri.fReq[1] = IPP_REQALL;
  665. dwRet = WebIppSndData(wReq,
  666. &ri,
  667. (LPBYTE)psj,
  668. psj->cbSize,
  669. &lpIpp,
  670. &cbIpp);
  671. // The request-structure has been converted to IPP format,
  672. // so it is ready to go to the server.
  673. //
  674. if (dwRet == WEBIPP_OK) {
  675. bRet = pIniPort->SendReq(lpIpp,
  676. cbIpp,
  677. ppjob_IppSetRsp,
  678. (LPARAM)(wReq | IPP_RESPONSE),
  679. TRUE);
  680. WebIppFreeMem(lpIpp);
  681. } else {
  682. SetLastError(ERROR_OUTOFMEMORY);
  683. }
  684. // Once we've verified the request for cancel, then
  685. // we should remove the job from our list.
  686. //
  687. // NOTE: Should this be deleted always? Or should
  688. // we make this dependent on the success of
  689. // the server-call?
  690. //
  691. // 06-Jan-1998 <chriswil> Will Revisit.
  692. //
  693. if (dwCmd == JOB_CONTROL_CANCEL)
  694. pjmDel(pjmList, pjm);
  695. WebIppFreeMem(psj);
  696. } else {
  697. SetLastError(ERROR_OUTOFMEMORY);
  698. }
  699. }
  700. } else {
  701. SetLastError(ERROR_INVALID_PARAMETER);
  702. }
  703. return bRet;
  704. }
  705. /*****************************************************************************\
  706. * ppjob_Enum (Local Routine)
  707. *
  708. * Enumerates jobs. IPP has the ENUJOB request which can be used for both
  709. * specific jobs, or enumerated-jobs. We will distinguish whether we're
  710. * enumerating by a (IPP_GETJOB_ALL) job-id.
  711. *
  712. \*****************************************************************************/
  713. BOOL ppjob_Enum(
  714. PCINETMONPORT pIniPort,
  715. DWORD nJobStart,
  716. DWORD cJobs,
  717. DWORD dwLevel,
  718. LPBYTE pbJob,
  719. DWORD cbJob,
  720. LPDWORD pcbNeed,
  721. LPDWORD pcItems)
  722. {
  723. PIPPREQ_ENUJOB pgj;
  724. REQINFO ri;
  725. DWORD dwRet;
  726. LPBYTE lpIpp;
  727. DWORD cbIpp;
  728. DWORD idx;
  729. DWORD cbSize;
  730. DWORD cbIdx;
  731. DWORD dwLastError = ERROR_INVALID_DATA;
  732. LPBYTE pbEnd;
  733. LPPPJOB_ENUM pje = NULL;
  734. BOOL bRet = FALSE;
  735. DWORD curIdx = 0;
  736. DWORD dwLocalJobCount = 0;
  737. DWORD cbLocalJobSize = 0;
  738. PJOBMAP* pjmList;
  739. PJOBMAP pjmTmpList;
  740. JOB_INFO_2 JobInfo2;
  741. BOOL bFound;
  742. // Specifying (IPP_GETJOB_ALL) will enumerate all jobs.
  743. //
  744. pjmList = pIniPort->GetPJMList ();
  745. pbEnd = pbJob + cbJob;
  746. cbIdx = ppjob_GetOneSize (dwLevel);
  747. if (pIniPort->BeginReadEnumJobsCache (&pje)) {
  748. bRet = TRUE;
  749. dwLastError = GetLastError();
  750. // Upon return, our (pje) pointer contains an
  751. // enumeration structure of JOB_INFO_2 items.
  752. //
  753. // Based upon the level passed in, we need to either
  754. // return these items or a converted JOB_INFO_1.
  755. //
  756. if (pje) {
  757. // Calculate the size we'll need to store the
  758. // enumerated items.
  759. //
  760. for (idx = 0, cbSize = 0; idx < pje->cItems; idx++)
  761. cbSize += ppjob_GetJobSize(&pje->ji2[idx].ji2, dwLevel);
  762. dwLocalJobCount = pjmGetLocalJobCount(pjmList, &cbLocalJobSize);
  763. if (dwLocalJobCount > 0) {
  764. cbSize += cbLocalJobSize;
  765. }
  766. // Fill in the return-value indicating
  767. // the buffer necessary to hold the items.
  768. //
  769. *pcbNeed = cbSize;
  770. // If the user buffer is of sufficient size,
  771. // then copy/convert the items.
  772. //
  773. if (cbJob >= cbSize) {
  774. *pcItems = pje->cItems + dwLocalJobCount;
  775. for (idx = 0; idx < pje->cItems && cJobs; idx++) {
  776. if ((idx >= nJobStart)) {
  777. pbEnd = ppjob_CopyJob(pbJob,
  778. dwLevel,
  779. &pje->ji2[idx].ji2,
  780. pbEnd);
  781. pbJob += cbIdx;
  782. cJobs--;
  783. }
  784. }
  785. curIdx = idx;
  786. } else {
  787. bRet = FALSE;
  788. dwLastError = ERROR_INSUFFICIENT_BUFFER;
  789. }
  790. }
  791. }
  792. else {
  793. dwLocalJobCount = pjmGetLocalJobCount(pjmList, &cbLocalJobSize);
  794. if (dwLocalJobCount > 0) {
  795. cbSize = cbLocalJobSize;
  796. // Fill in the return-value indicating
  797. // the buffer necessary to hold the items.
  798. //
  799. *pcbNeed = cbSize;
  800. // If the user buffer is of sufficient size,
  801. // then copy/convert the items.
  802. //
  803. if (cbJob >= cbSize) {
  804. *pcItems = dwLocalJobCount;
  805. bRet = TRUE;
  806. } else {
  807. bRet = FALSE;
  808. dwLastError = ERROR_INSUFFICIENT_BUFFER;
  809. }
  810. }
  811. else {
  812. dwLastError = GetLastError();
  813. }
  814. }
  815. if (bRet) {
  816. pjmTmpList = *pjmList;
  817. for (idx = curIdx; idx < curIdx + dwLocalJobCount && cJobs; idx++) {
  818. pjmTmpList = pjmNextLocalJob (&pjmTmpList, &JobInfo2, &bFound);
  819. if ((idx >= nJobStart)) {
  820. if (bFound) {
  821. DBG_ASSERT( ((pbJob < pbEnd)?TRUE:FALSE),
  822. (TEXT("ppjob_Enum: idx = %d, cbIdx = %d, cJobs = %d dwLocalJobCount = %d dwLocalSize=%d, pjd=%p\n"),
  823. idx, cbIdx, cJobs, dwLocalJobCount, dwLocalJobCount, pje));
  824. pbEnd = ppjob_CopyJob(pbJob,
  825. dwLevel,
  826. &JobInfo2,
  827. pbEnd);
  828. pbJob += cbIdx;
  829. cJobs--;
  830. }
  831. else {
  832. bRet = FALSE;
  833. dwLastError = ERROR_INVALID_PARAMETER;
  834. break;
  835. }
  836. }
  837. }
  838. }
  839. // This function has to be called to release the critical section
  840. //
  841. pIniPort->EndReadEnumJobsCache ();
  842. if (!bRet) {
  843. SetLastError(dwLastError);
  844. }
  845. return bRet;
  846. }
  847. /*****************************************************************************\
  848. * ppjob_EnumForCache (Local Routine)
  849. *
  850. * Enumerates jobs. IPP has the ENUJOB request which can be used for both
  851. * specific jobs, or enumerated-jobs. We will distinguish whether we're
  852. * enumerating by a (IPP_GETJOB_ALL) job-id.
  853. *
  854. * Upon return, ppbJob stores a pointer to the cache
  855. *
  856. \*****************************************************************************/
  857. BOOL ppjob_EnumForCache(
  858. PCINETMONPORT pIniPort,
  859. LPPPJOB_ENUM *ppje)
  860. {
  861. PIPPREQ_ENUJOB pgj;
  862. REQINFO ri;
  863. DWORD dwRet;
  864. LPBYTE lpIpp;
  865. DWORD cbIpp;
  866. DWORD idx;
  867. DWORD cbSize;
  868. DWORD cbIdx;
  869. DWORD dwLastError = ERROR_INVALID_DATA;
  870. LPBYTE pbEnd;
  871. LPPPJOB_ENUM pje = NULL;
  872. BOOL bRet = FALSE;
  873. // Specifying (IPP_GETJOB_ALL) will enumerate all jobs.
  874. //
  875. pgj = WebIppCreateEnuJobReq(IPP_GETJOB_ALL, pIniPort->GetPortName());
  876. if (pgj) {
  877. // Convert the reqest to IPP, and perform the
  878. // post.
  879. //
  880. ZeroMemory(&ri, sizeof(REQINFO));
  881. ri.cpReq = CP_UTF8;
  882. ri.idReq = IPP_REQ_ENUJOB;
  883. ri.fReq[0] = IPP_REQALL;
  884. ri.fReq[1] = IPP_REQALL;
  885. dwRet = WebIppSndData(IPP_REQ_ENUJOB,
  886. &ri,
  887. (LPBYTE)pgj,
  888. pgj->cbSize,
  889. &lpIpp,
  890. &cbIpp);
  891. // The request-structure has been converted to IPP format,
  892. // so it is ready to go to the server.
  893. //
  894. if (dwRet == WEBIPP_OK) {
  895. // This routine returns with a LastError set to that
  896. // which the response-routine sets.
  897. //
  898. if (pIniPort->SendReq(lpIpp,
  899. cbIpp,
  900. ppjob_IppEnuRsp,
  901. (LPARAM)&pje,
  902. TRUE)) {
  903. dwLastError = GetLastError();
  904. bRet = TRUE;
  905. *ppje = pje;
  906. } else {
  907. dwLastError = GetLastError();
  908. }
  909. WebIppFreeMem(lpIpp);
  910. } else {
  911. dwLastError = ERROR_OUTOFMEMORY;
  912. }
  913. WebIppFreeMem(pgj);
  914. } else {
  915. dwLastError = ERROR_OUTOFMEMORY;
  916. }
  917. if (!bRet) {
  918. SetLastError(dwLastError);
  919. }
  920. return bRet;
  921. }
  922. /*****************************************************************************\
  923. * ppjob_Get (Local Routine)
  924. *
  925. * Returns information regarding a job.
  926. *
  927. \*****************************************************************************/
  928. BOOL ppjob_Get(
  929. PCINETMONPORT pIniPort,
  930. DWORD idJob,
  931. DWORD dwLevel,
  932. LPBYTE pbJob,
  933. DWORD cbJob,
  934. LPDWORD pcbNeed)
  935. {
  936. PJOBMAP pjm;
  937. PIPPREQ_GETJOB pgj;
  938. REQINFO ri;
  939. LPBYTE lpIpp;
  940. DWORD cbIpp;
  941. DWORD dwRet;
  942. LPBYTE pbEnd;
  943. PJOBMAP* pjmList;
  944. LPJOB_INFO_2 pji2 = NULL;
  945. BOOL bRet = FALSE;
  946. DWORD dwLastError = ERROR_INVALID_DATA;
  947. // Look in our JobMap list for the local-job-id. If we see
  948. // one, the we can get the job-information.
  949. //
  950. pjmList = pIniPort->GetPJMList();
  951. if (pjm = pjmFind(pjmList, PJM_LOCALID, idJob)) {
  952. if (pjm->bRemoteJob) {
  953. // Build a request-structure that we will pass into
  954. // the IPP layer for processing.
  955. //
  956. pgj = WebIppCreateGetJobReq(pjmJobId(pjm, PJM_REMOTEID), pIniPort->GetPortName());
  957. if (pgj) {
  958. // Convert the reqest to IPP that is suitible for
  959. // our post.
  960. //
  961. ZeroMemory(&ri, sizeof(REQINFO));
  962. ri.cpReq = CP_UTF8;
  963. ri.idReq = IPP_REQ_GETJOB;
  964. ri.fReq[0] = IPP_REQALL;
  965. ri.fReq[1] = IPP_REQALL;
  966. dwRet = WebIppSndData(IPP_REQ_GETJOB,
  967. &ri,
  968. (LPBYTE)pgj,
  969. pgj->cbSize,
  970. &lpIpp,
  971. &cbIpp);
  972. // The request-structure has been converted to IPP format,
  973. // so it is ready to go to the server. We set a callback
  974. // to the function that will receive our data.
  975. //
  976. if (dwRet == WEBIPP_OK) {
  977. pIniPort->SendReq(lpIpp,
  978. cbIpp,
  979. ppjob_IppGetRsp,
  980. (LPARAM)&pji2,
  981. TRUE);
  982. // Upon return, our (pji2) contains the JOB_INFO_2
  983. // structure.
  984. //
  985. if (pji2) {
  986. bRet = ppjob_CalcAndCopyJob(pbJob, cbJob, pcbNeed, pji2, dwLevel);
  987. if (!bRet) {
  988. dwLastError = GetLastError ();
  989. }
  990. memFree(pji2, memGetSize(pji2));
  991. }
  992. WebIppFreeMem(lpIpp);
  993. } else {
  994. dwLastError = ERROR_OUTOFMEMORY;
  995. }
  996. WebIppFreeMem(pgj);
  997. } else {
  998. dwLastError = ERROR_OUTOFMEMORY;
  999. }
  1000. }
  1001. else {
  1002. //
  1003. // This is a local job
  1004. //
  1005. if (pjm = pjmFind(pjmList, PJM_LOCALID, idJob)) {
  1006. JOB_INFO_2 JobInfo2;
  1007. BOOL bFound;
  1008. pjmNextLocalJob(&pjm, &JobInfo2, &bFound);
  1009. if (bFound) {
  1010. bRet = ppjob_CalcAndCopyJob(pbJob, cbJob, pcbNeed, &JobInfo2, dwLevel);
  1011. if (!bRet) {
  1012. dwLastError = GetLastError ();
  1013. }
  1014. }
  1015. else
  1016. dwLastError = ERROR_INVALID_PARAMETER;
  1017. } else {
  1018. dwLastError = ERROR_INVALID_PARAMETER;
  1019. }
  1020. }
  1021. } else {
  1022. dwLastError = ERROR_INVALID_PARAMETER;
  1023. }
  1024. // Set the lasterror if failure.
  1025. //
  1026. if (!bRet) {
  1027. SetLastError(dwLastError);
  1028. }
  1029. return bRet;
  1030. }
  1031. /*****************************************************************************\
  1032. * ppjob_Add (Local Routine)
  1033. *
  1034. * Returns information for an addjob call.
  1035. *
  1036. \*****************************************************************************/
  1037. BOOL ppjob_Add(
  1038. HANDLE hPrinter,
  1039. PCINETMONPORT pIniPort,
  1040. DWORD dwLevel,
  1041. LPCTSTR lpszName,
  1042. LPBYTE pbData,
  1043. DWORD cbBuf,
  1044. LPDWORD pcbNeeded)
  1045. {
  1046. PJOBMAP pjm;
  1047. LPCTSTR lpszSplFile;
  1048. LPTSTR* lpszSrc;
  1049. LPBYTE pbEnd;
  1050. PJOBMAP* pjmList;
  1051. LPTSTR aszSrc[(sizeof(ADDJOB_INFO_1) / sizeof(LPTSTR))];
  1052. BOOL bRet = FALSE;
  1053. static DWORD s_AJI1Offsets[] = {
  1054. offsetof(LPADDJOB_INFO_1, Path),
  1055. 0xFFFFFFFF
  1056. };
  1057. // Create a spool-file and job that we will use
  1058. // for this AddJob() call.
  1059. //
  1060. pjmList = pIniPort->GetPJMList();
  1061. if (pjm = pjmAdd(pjmList, pIniPort, lpszName, NULL)) {
  1062. // Set the job into spooling-state. This internally
  1063. // creates the spool-file. By specifying PJM_NOOPEN,
  1064. // we indicate that no open-handles are to be maintained
  1065. // on the spool-file.
  1066. //
  1067. if (pjmSetState(pjm, PJM_SPOOLING | PJM_NOOPEN)) {
  1068. // Get the spool-file.
  1069. //
  1070. lpszSplFile = pjmSplFile(pjm);
  1071. // If a return-size is provided, then set it.
  1072. //
  1073. if (pcbNeeded)
  1074. *pcbNeeded = sizeof(ADDJOB_INFO_1) + utlStrSize(lpszSplFile);
  1075. // If the buffer is capable of holding the
  1076. // return-structure, then proceed.
  1077. //
  1078. if (pbData && (cbBuf >= *pcbNeeded)) {
  1079. // Clean out the string-array and setup
  1080. // for building the structure.
  1081. //
  1082. ZeroMemory(aszSrc, sizeof(aszSrc));
  1083. lpszSrc = aszSrc;
  1084. // Initialize fixed values.
  1085. //
  1086. ((LPADDJOB_INFO_1)pbData)->JobId = pjmJobId(pjm, PJM_LOCALID);
  1087. // Pack the file-name into the return-structure.
  1088. //
  1089. pbEnd = pbData + cbBuf;
  1090. *lpszSrc++ = (LPTSTR)lpszSplFile;
  1091. utlPackStrings(aszSrc, pbData, s_AJI1Offsets, pbEnd);
  1092. // Mark this printer to indicate it's in a
  1093. // addjob.
  1094. //
  1095. // NOTE: do we really need to consume the printer
  1096. // for an AddJob(). LocalSpl does this and
  1097. // sets the job into the printer. I don't
  1098. // see why this is necessary.
  1099. //
  1100. PP_SetStatus(hPrinter, PP_ADDJOB);
  1101. bRet = TRUE;
  1102. } else {
  1103. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  1104. }
  1105. } else {
  1106. SetLastError(ERROR_FILE_NOT_FOUND);
  1107. }
  1108. } else {
  1109. SetLastError(ERROR_INVALID_HANDLE);
  1110. }
  1111. return bRet;
  1112. }
  1113. /*****************************************************************************\
  1114. * ppjob_Schedule (Local Routine)
  1115. *
  1116. * Prints the scheduled job.
  1117. *
  1118. \*****************************************************************************/
  1119. BOOL ppjob_Schedule(
  1120. HANDLE hPrinter,
  1121. PCINETMONPORT pIniPort,
  1122. PJOBMAP pjm)
  1123. {
  1124. HANDLE hOut;
  1125. BOOL bRemote;
  1126. LPCTSTR lpszUser;
  1127. PIPPREQ_PRTJOB ppj;
  1128. REQINFO ri;
  1129. LPBYTE pbOut;
  1130. LPBYTE pbIpp;
  1131. LPBYTE pbSpl;
  1132. DWORD cbOut;
  1133. DWORD cbIpp;
  1134. DWORD cbSpl;
  1135. DWORD dwRet;
  1136. DWORD cbWr;
  1137. PJOBMAP* pjmList;
  1138. DWORD dwLE = ERROR_INVALID_HANDLE;
  1139. CFileStream *pStream = NULL;
  1140. CFileStream *pSplStream = NULL;
  1141. BOOL bRet = FALSE;
  1142. // Lock the file so we can obtain the spool-data.
  1143. //
  1144. pjmList = pIniPort->GetPJMList();
  1145. if (pSplStream = pjmSplLock(pjm)) {
  1146. // Check to determine if this is a remote-call.
  1147. //
  1148. bRemote = TRUE;
  1149. // Get the user-name if one was specified in AddJob().
  1150. //
  1151. lpszUser = pjmSplUser(pjm);
  1152. // Create the print-job-request that we'll be using.
  1153. //
  1154. ppj = WebIppCreatePrtJobReq(FALSE,
  1155. (lpszUser ? lpszUser : TEXT("Unknown")),
  1156. (bRemote ? g_szDocRemote: g_szDocLocal),
  1157. pIniPort->GetPortName());
  1158. if (ppj) {
  1159. ZeroMemory(&ri, sizeof(REQINFO));
  1160. ri.cpReq = CP_UTF8;
  1161. ri.idReq = IPP_REQ_PRINTJOB;
  1162. ri.fReq[0] = IPP_REQALL;
  1163. ri.fReq[1] = IPP_REQALL;
  1164. dwRet = WebIppSndData(IPP_REQ_PRINTJOB,
  1165. &ri,
  1166. (LPBYTE)ppj,
  1167. ppj->cbSize,
  1168. &pbIpp,
  1169. &cbIpp);
  1170. // Make sure we were able to get the ipp-header.
  1171. //
  1172. if (dwRet == WEBIPP_OK) {
  1173. // Create the outputfile that will be used to
  1174. // contain both the ipp-header as well as the
  1175. // spool-data.
  1176. //
  1177. if (hOut = SplCreate(pjmJobId(pjm, PJM_LOCALID), SPLFILE_SPL)) {
  1178. // Output the header and data.
  1179. //
  1180. if (SplWrite(hOut, pbIpp, cbIpp, &cbWr) &&
  1181. SplWrite(hOut, pSplStream) &&
  1182. // Output the request.
  1183. //
  1184. (pStream = SplLock(hOut))) {
  1185. bRet = pIniPort->SendReq(pStream,
  1186. (IPPRSPPROC)ppjob_IppPrtRsp,
  1187. (LPARAM)pjm,
  1188. TRUE);
  1189. if (bRet == FALSE)
  1190. dwLE = GetLastError();
  1191. SplUnlock(hOut);
  1192. } else {
  1193. dwLE = GetLastError();
  1194. }
  1195. // Free up the spool-output-file.
  1196. //
  1197. SplFree(hOut);
  1198. } else {
  1199. dwLE = GetLastError();
  1200. }
  1201. WebIppFreeMem(pbIpp);
  1202. } else {
  1203. dwLE = ERROR_OUTOFMEMORY;
  1204. }
  1205. WebIppFreeMem(ppj);
  1206. } else {
  1207. dwLE = ERROR_OUTOFMEMORY;
  1208. }
  1209. pjmSplUnlock(pjm);
  1210. } else {
  1211. dwLE = GetLastError();
  1212. }
  1213. // Clear out our spooling-status. This will close
  1214. // and delete the spool-file as the job is now in the
  1215. // hands of spooler.
  1216. //
  1217. pjmClrState(pjm, PJM_SPOOLING);
  1218. // If a cancel was set on this job, then delete it's entry from
  1219. // our list.
  1220. //
  1221. if (pjmChkState(pjm, PJM_CANCEL) && pjmList != NULL)
  1222. pjmDel(pjmList, pjm);
  1223. // Set lasterror if problem occured.
  1224. //
  1225. if (bRet == FALSE)
  1226. SetLastError(dwLE);
  1227. return bRet;
  1228. }
  1229. /*****************************************************************************\
  1230. * PPEnumJobs
  1231. *
  1232. * Retrives the information about a specified set of print jobs for a
  1233. * specified printer. Returns TRUE if successful. Otherwise, it returns
  1234. * FALSE.
  1235. *
  1236. \*****************************************************************************/
  1237. BOOL PPEnumJobs(
  1238. HANDLE hPrinter,
  1239. DWORD nJobStart,
  1240. DWORD cJobs,
  1241. DWORD dwLevel,
  1242. LPBYTE pbJob,
  1243. DWORD cbJob,
  1244. LPDWORD pcbNeeded,
  1245. LPDWORD pcItems)
  1246. {
  1247. PCINETMONPORT pIniPort;
  1248. BOOL bRet = FALSE;
  1249. DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: PPEnumJobs: Printer(%08lX) dwLevel(%d)"), hPrinter, dwLevel));
  1250. semEnterCrit();
  1251. *pcbNeeded = 0;
  1252. *pcItems = 0;
  1253. // Make sure we have a valid printer handle.
  1254. //
  1255. if (pIniPort = utlValidatePrinterHandle(hPrinter)) {
  1256. // Attempt to get a list of jobs from the ipp print spooler.
  1257. // Format the job information to the requested information level.
  1258. //
  1259. switch (dwLevel) {
  1260. case PRINT_LEVEL_1:
  1261. case PRINT_LEVEL_2:
  1262. bRet = ppjob_Enum(pIniPort,
  1263. nJobStart,
  1264. cJobs,
  1265. dwLevel,
  1266. pbJob,
  1267. cbJob,
  1268. pcbNeeded,
  1269. pcItems);
  1270. break;
  1271. default:
  1272. DBG_MSG(DBG_LEV_WARN, (TEXT("Warn: PPEnumJobs: Invalid Level (%d)"), dwLevel));
  1273. SetLastError(ERROR_INVALID_LEVEL);
  1274. break;
  1275. }
  1276. }
  1277. semLeaveCrit();
  1278. return bRet;
  1279. }
  1280. /*****************************************************************************\
  1281. * PPGetJob
  1282. *
  1283. * Retrieves information about a print job on a specified printer. Returns
  1284. * TRUE if successful. Otherwise, it returns FASLSE.
  1285. *
  1286. \*****************************************************************************/
  1287. BOOL PPGetJob(
  1288. HANDLE hPrinter,
  1289. DWORD idJob,
  1290. DWORD dwLevel,
  1291. LPBYTE pbJob,
  1292. DWORD cbJob,
  1293. LPDWORD pcbNeed)
  1294. {
  1295. PCINETMONPORT pIniPort;
  1296. BOOL bRet = FALSE;
  1297. DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: PPGetJob: Printer(%08lX) dwLevel(%d)"), hPrinter, dwLevel));
  1298. semEnterCrit();
  1299. *pcbNeed = 0;
  1300. // Make sure we're looking at a valid printer handle.
  1301. //
  1302. if (pIniPort = utlValidatePrinterHandle(hPrinter)) {
  1303. // Switch on print-level.
  1304. //
  1305. switch (dwLevel) {
  1306. case PRINT_LEVEL_1:
  1307. case PRINT_LEVEL_2:
  1308. bRet = ppjob_Get(pIniPort, idJob, dwLevel, pbJob, cbJob, pcbNeed);
  1309. break;
  1310. default:
  1311. DBG_MSG(DBG_LEV_WARN, (TEXT("Warn: PPGetJob: Invalid Level (%d)"), dwLevel));
  1312. SetLastError(ERROR_INVALID_LEVEL);
  1313. break;
  1314. }
  1315. }
  1316. semLeaveCrit();
  1317. return bRet;
  1318. }
  1319. /*****************************************************************************\
  1320. * PPSetJob
  1321. *
  1322. * Sets information for and issues commands to a print job. Returns TRUE
  1323. * if successful. Otherwise, it returns FALSE.
  1324. *
  1325. \*****************************************************************************/
  1326. BOOL PPSetJob(
  1327. HANDLE hPrinter,
  1328. DWORD dwJobId,
  1329. DWORD dwLevel,
  1330. LPBYTE pbJob,
  1331. DWORD dwCmd)
  1332. {
  1333. PCINETMONPORT pIniPort;
  1334. BOOL bResult = FALSE;
  1335. DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: PPSetJob: Printer(%08lX) dwLevel(%d)"), hPrinter, dwLevel));
  1336. semEnterCrit();
  1337. // Make sure we've got a valid printer handle.
  1338. //
  1339. if (pIniPort = utlValidatePrinterHandle(hPrinter)) {
  1340. // Set job parameters.
  1341. //
  1342. switch (dwLevel) {
  1343. case PRINT_LEVEL_0:
  1344. // Do not set parameters. (0) represents "no-command".
  1345. //
  1346. switch (dwCmd) {
  1347. case JOB_CONTROL_CANCEL:
  1348. case JOB_CONTROL_DELETE:
  1349. case JOB_CONTROL_PAUSE:
  1350. case JOB_CONTROL_RESUME:
  1351. case JOB_CONTROL_RESTART:
  1352. bResult = ppjob_Set(pIniPort, dwJobId, dwCmd);
  1353. if (bResult) {
  1354. // Invalidate has to occur before notfication refresh, otherwise, you
  1355. // get an outdated result
  1356. //
  1357. pIniPort->InvalidateEnumJobsCache ();
  1358. pIniPort->InvalidateGetPrinterCache ();
  1359. RefreshNotification((LPINET_HPRINTER)hPrinter);
  1360. }
  1361. break;
  1362. case 0:
  1363. bResult = TRUE;
  1364. break;
  1365. }
  1366. break;
  1367. default:
  1368. DBG_MSG(DBG_LEV_WARN, (TEXT("Warn: PPSetJob: Invalid Level (%d)"), dwLevel));
  1369. SetLastError(ERROR_INVALID_LEVEL);
  1370. break;
  1371. }
  1372. }
  1373. semLeaveCrit();
  1374. return bResult;
  1375. }
  1376. /*****************************************************************************\
  1377. * PPAddJob
  1378. *
  1379. * Sets up for a local-spooled job. Since we are truly a remote-printer, we
  1380. * need to fail this call and signify the correct error-code.
  1381. *
  1382. \*****************************************************************************/
  1383. BOOL PPAddJob(
  1384. HANDLE hPrinter,
  1385. DWORD dwLevel,
  1386. LPBYTE pbData,
  1387. DWORD cbBuf,
  1388. LPDWORD pcbNeeded)
  1389. {
  1390. PCINETMONPORT pIniPort;
  1391. LPTSTR lpszName;
  1392. BOOL bRet = FALSE;
  1393. DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: PPAddJob: Printer(%08lX) dwLevel(%d)"), hPrinter, dwLevel));
  1394. // Zero out the return-parameters.
  1395. //
  1396. *pcbNeeded = 0;
  1397. semEnterCrit();
  1398. if (pIniPort = utlValidatePrinterHandle(hPrinter)) {
  1399. if (pbData && pcbNeeded) {
  1400. switch (dwLevel) {
  1401. case PRINT_LEVEL_2:
  1402. lpszName = (LPTSTR)(pbData + (ULONG_PTR)((LPADDJOB_INFO_2W)pbData)->pData);
  1403. // Make sure this string-address does not extend past the
  1404. // end of available buffer specified.
  1405. //
  1406. if (lpszName > (LPTSTR)(pbData + cbBuf)) {
  1407. SetLastError(ERROR_INVALID_LEVEL);
  1408. goto EndAdd;
  1409. }
  1410. // Ensure NULL termination.
  1411. //
  1412. *(PTCHAR)(((ULONG_PTR)(pbData + cbBuf - sizeof(TCHAR))&~1)) = 0;
  1413. break;
  1414. case PRINT_LEVEL_1:
  1415. lpszName = NULL;
  1416. break;
  1417. default:
  1418. SetLastError(ERROR_INVALID_LEVEL);
  1419. goto EndAdd;
  1420. }
  1421. // Do the add.
  1422. //
  1423. bRet = ppjob_Add(hPrinter,
  1424. pIniPort,
  1425. dwLevel,
  1426. lpszName,
  1427. pbData,
  1428. cbBuf,
  1429. pcbNeeded);
  1430. } else {
  1431. SetLastError(ERROR_INVALID_PARAMETER);
  1432. }
  1433. }
  1434. EndAdd:
  1435. semLeaveCrit();
  1436. return bRet;
  1437. }
  1438. /*****************************************************************************\
  1439. * PPScheduleJob
  1440. *
  1441. * This schedules the job. Since we don't support the PPAddJob(), this call
  1442. * must fail.
  1443. *
  1444. \*****************************************************************************/
  1445. BOOL PPScheduleJob(
  1446. HANDLE hPrinter,
  1447. DWORD idJob)
  1448. {
  1449. PCINETMONPORT pIniPort;
  1450. PJOBMAP pjm;
  1451. PJOBMAP* pjmList;
  1452. BOOL bRet = FALSE;
  1453. DBG_MSG(DBG_LEV_CALLTREE, (TEXT("Call: PPScheduleJob: Printer(%08lX) idJob(%d)"), hPrinter, idJob));
  1454. semEnterCrit();
  1455. if (pIniPort = utlValidatePrinterHandle(hPrinter)) {
  1456. pjmList = pIniPort->GetPJMList();
  1457. if (pjm = pjmFind(pjmList, PJM_LOCALID, idJob)) {
  1458. if (pjmChkState(pjm, PJM_SPOOLING)) {
  1459. bRet = ppjob_Schedule(hPrinter, pIniPort, pjm);
  1460. } else {
  1461. SetLastError(ERROR_SPL_NO_ADDJOB);
  1462. }
  1463. } else {
  1464. SetLastError(ERROR_INVALID_PARAMETER);
  1465. }
  1466. PP_ClrStatus(hPrinter, PP_ADDJOB);
  1467. }
  1468. semLeaveCrit();
  1469. return bRet;
  1470. }