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.

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