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.

1569 lines
32 KiB

  1. ////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // MacPrint - Windows NT Print Server for Macintosh Clients
  4. // Copyright (c) Microsoft Corp., 1991, 1992, 1993
  5. //
  6. // psp.c - Macintosh Print Service Postscript Parsing Routines
  7. //
  8. // Author: Frank D. Byrum
  9. // adapted from MacPrint from LAN Manager Services for Macintosh
  10. //
  11. // DESCRIPTION:
  12. // This module provides the routines to parse the Adobe DSC 2.0
  13. // comments in a PostScript stream.
  14. //
  15. ////////////////////////////////////////////////////////////////////////////////
  16. #include <stdio.h>
  17. #include <string.h>
  18. #include <stdlib.h>
  19. #include <windows.h>
  20. #include <macpsmsg.h>
  21. #include <macps.h>
  22. #include <pskey.h>
  23. #include <debug.h>
  24. // function prototypes
  25. DWORD HandleTitle(PJR pjr);
  26. DWORD HandleBeginExitServer(PJR pjr);
  27. DWORD HandleCreationDate(PJR pjr);
  28. DWORD HandleCreator(PJR pjr);
  29. DWORD HandleEndExitServer(PJR pjr);
  30. DWORD HandleEOF(PJR pjr);
  31. DWORD HandleFor(PJR pjr);
  32. DWORD HandleLogin(PJR pjr);
  33. DWORD HandleBeginProcSet(PJR pjr);
  34. DWORD HandleEndProcSet(PJR pjr);
  35. DWORD HandleIncludeProcSet(PJR pjr);
  36. DWORD HandleComment(PJR, PBYTE);
  37. DWORD HandleBeginBinary(PJR pjr);
  38. DWORD HandleEndBinary(PJR pjr);
  39. DWORD HandlePages(PJR pjr);
  40. void HandleJobComment (PJR, PBYTE);
  41. PFR ReAllocateFontList (PFR pfrOld, DWORD cOldFonts, DWORD cNewFonts);
  42. #if DBG_SPOOL_LOCALLY
  43. HANDLE DbgSpoolFile = INVALID_HANDLE_VALUE;
  44. #endif
  45. char * deffonts[DEFAULTFONTS] =
  46. {
  47. FONT00, FONT01, FONT02, FONT03, FONT04, FONT05, FONT06, FONT07,
  48. FONT08, FONT09, FONT10, FONT11, FONT12, FONT13, FONT14, FONT15,
  49. FONT16, FONT17, FONT18, FONT19, FONT20, FONT21, FONT22, FONT23,
  50. FONT24, FONT25, FONT26, FONT27, FONT28, FONT29, FONT30, FONT31,
  51. FONT32, FONT33, FONT34
  52. };
  53. ////////////////////////////////////////////////////////////////////////////////
  54. //
  55. // SetDefaultPPDInfo() - Initialize to LaserWriter Plus configuration
  56. //
  57. // DESCRIPTION:
  58. // This routine is used to set the default parameters of our
  59. // printer to LaserWriter Plus characteristics. This is used
  60. // in the event there is no PPD file associated with the given
  61. // NT Printer Object (as in the case of non Postscript printers)
  62. //
  63. // returns true if queue structure initialized OK.
  64. //
  65. ////////////////////////////////////////////////////////////////////////////////
  66. BOOLEAN
  67. SetDefaultPPDInfo(
  68. PQR pqr
  69. )
  70. {
  71. DWORD i;
  72. //
  73. // initialize Postscript keywords
  74. //
  75. strcpy(pqr->LanguageVersion, ENGLISH);
  76. strcpy(pqr->Product, DEFAULTPRODUCTRESPONSE);
  77. strcpy(pqr->Version, DEFAULTPSVERSION);
  78. strcpy(pqr->Revision, DEFAULTPSREVISION);
  79. strcpy(pqr->DeviceNickName, UNKNOWNPRINTER);
  80. strcpy(pqr->pszColorDevice, COLORDEVICEDEFAULT);
  81. strcpy(pqr->pszResolution, RESOLUTIONDEFAULT);
  82. strcpy(pqr->pszLanguageLevel, DEFAULTLANGUAGELEVEL);
  83. pqr->FreeVM = VMDEFAULT;
  84. pqr->SupportsBinary = FALSE;
  85. pqr->fonts = NULL;
  86. return (TRUE);
  87. }
  88. ////////////////////////////////////////////////////////////////////////////////
  89. //
  90. // SetDefaultFonts() - Initialize to LaserWriter Plus configuration
  91. //
  92. // DESCRIPTION:
  93. // This routine is used to set the default parameters of our
  94. // printer to LaserWriter Plus characteristics. This is used
  95. // in the event there is no PPD file associated with the given
  96. // NT Printer Object (as in the case of non Postscript printers)
  97. //
  98. // returns true if queue structure initialized OK.
  99. //
  100. ////////////////////////////////////////////////////////////////////////////////
  101. BOOLEAN
  102. SetDefaultFonts(
  103. PQR pqr
  104. )
  105. {
  106. DWORD i;
  107. if (pqr->fonts != NULL)
  108. {
  109. DBGPRINT(("ERROR: pqr->fonts is nonnull!\n"));
  110. }
  111. pqr->fonts = (PFR)LocalAlloc(LPTR, DEFAULTFONTS * sizeof (FONT_RECORD));
  112. if (pqr->fonts == NULL)
  113. {
  114. DBGPRINT(("ERROR: unable to allocate font data\n"));
  115. ReportEvent(
  116. hEventLog,
  117. EVENTLOG_ERROR_TYPE,
  118. EVENT_CATEGORY_INTERNAL,
  119. EVENT_SERVICE_OUT_OF_MEMORY,
  120. NULL, 0, 0, NULL, NULL);
  121. return (FALSE);
  122. }
  123. //
  124. // copy font names
  125. //
  126. for (i = 0; i < DEFAULTFONTS; i++)
  127. {
  128. strcpy(pqr->fonts[i].name, deffonts[i]);
  129. }
  130. pqr->MaxFontIndex = DEFAULTFONTS-1;
  131. return (TRUE);
  132. }
  133. ////////////////////////////////////////////////////////////////////////////////
  134. //
  135. // GetPPDInfo() - Initialize to LaserWriter Plus configuration
  136. //
  137. // DESCRIPTION:
  138. // This routine is used to set the parameters of our
  139. // printer to the characteristics specified in the PPD
  140. // file for the printer.
  141. //
  142. // returns true if queue structure initialized OK.
  143. //
  144. ////////////////////////////////////////////////////////////////////////////////
  145. BOOLEAN
  146. GetPPDInfo(
  147. PQR pqr
  148. )
  149. {
  150. FILE * ppdfile = NULL;
  151. char * result = NULL;
  152. char * token = NULL;
  153. char line[PSLEN];
  154. PFR fontPtr=NULL;
  155. USHORT MaxFonts = 100;
  156. USHORT fontindex = 0;
  157. LPDRIVER_INFO_2 pdiThis = NULL;
  158. DWORD cbpdiThis = sizeof(DRIVER_INFO_2) + 256;
  159. LPSTR pszPPDFile = NULL;
  160. BOOLEAN ReturnStatus = TRUE;
  161. HANDLE hPrinter = INVALID_HANDLE_VALUE;
  162. int toklen;
  163. do
  164. {
  165. // get the path of the ppdfile
  166. if (!OpenPrinter(pqr->pPrinterName, &hPrinter, NULL))
  167. {
  168. hPrinter = INVALID_HANDLE_VALUE;
  169. DBGPRINT(("ERROR: unable to get printer handle, error=%d\n", GetLastError()));
  170. ReturnStatus = FALSE;
  171. break;
  172. }
  173. pdiThis = (LPDRIVER_INFO_2) LocalAlloc(LPTR, cbpdiThis);
  174. if (pdiThis == NULL)
  175. {
  176. DBGPRINT(("ERROR: unable to allocate new driverinfo buffer\n"));
  177. ReturnStatus = FALSE;
  178. break;
  179. }
  180. if (!GetPrinterDriver(hPrinter,
  181. NULL,
  182. 2,
  183. (LPBYTE) pdiThis,
  184. cbpdiThis,
  185. &cbpdiThis))
  186. {
  187. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
  188. {
  189. DBGPRINT(("ERROR: unable to get printer driver info\n"));
  190. ReturnStatus = FALSE;
  191. break;
  192. }
  193. LocalFree(pdiThis);
  194. pdiThis = (LPDRIVER_INFO_2) LocalAlloc(LPTR, cbpdiThis);
  195. if (pdiThis == NULL)
  196. {
  197. DBGPRINT(("ERROR: unable to allocte new driverinfo buffer\n"));
  198. ReturnStatus = FALSE;
  199. break;
  200. }
  201. if (!GetPrinterDriver(hPrinter,
  202. NULL,
  203. 2,
  204. (LPBYTE) pdiThis,
  205. cbpdiThis,
  206. &cbpdiThis))
  207. {
  208. DBGPRINT(("ERROR: unable to get printer driver info\n"));
  209. ReturnStatus = FALSE;
  210. break;
  211. }
  212. }
  213. #ifdef DBCS
  214. pszPPDFile = (LPSTR)LocalAlloc(LPTR, (wcslen(pdiThis->pDataFile)+1) * sizeof(WCHAR));
  215. #else
  216. pszPPDFile = (LPSTR)LocalAlloc(LPTR, wcslen(pdiThis->pDataFile)+1);
  217. #endif
  218. DBGPRINT(("pDataFile name length = %d\n", wcslen(pdiThis->pDataFile)));
  219. if (pszPPDFile == NULL)
  220. {
  221. DBGPRINT(("out of memory for pszPPDFile\n"));
  222. ReturnStatus = FALSE;
  223. break;
  224. }
  225. CharToOem(pdiThis->pDataFile, pszPPDFile);
  226. DBGPRINT(("pDataFile = %ws, pszPPDFile = %s\n", pdiThis->pDataFile, pszPPDFile));
  227. if ((ppdfile = fopen(pszPPDFile, "rt")) == NULL)
  228. {
  229. DBGPRINT(("File open error %s", pszPPDFile));
  230. ReturnStatus = FALSE;
  231. break;
  232. }
  233. /*
  234. * Allocate a buffer for fonts. We don't know yet what size we need.
  235. * We make a guess and increase the size as we go. The incremental
  236. * size is 10 fonts. We start off with 100. We shrink the segment size
  237. * to the final size.
  238. */
  239. fontPtr = (PFR) LocalAlloc (LPTR, sizeof(FONT_RECORD)*MaxFonts);
  240. if (fontPtr == NULL)
  241. {
  242. DBGPRINT(("ERROR: cannot allocate font list buffer, error=%d\n", GetLastError()));
  243. ReturnStatus = FALSE;
  244. break;
  245. }
  246. pqr->SupportsBinary = FALSE; // Default
  247. while (result = fgets(line, PSLEN, ppdfile))
  248. {
  249. if (line[0] != ASTERISK || (token= strtok(line, " \011")) == NULL)
  250. continue;
  251. // PPD Font Entry?
  252. if (!_stricmp(line, ppdFONT))
  253. {
  254. /* This should be the fontname */
  255. if ((token= strtok(NULL, " \011:")) != NULL)
  256. {
  257. if (strlen(token) <= FONTNAMELEN)
  258. {
  259. strcpy(fontPtr[fontindex].name, token);
  260. DBGPRINT(("Font: %s\n", token));
  261. fontindex++;
  262. if (fontindex >= MaxFonts)
  263. {
  264. fontPtr = ReAllocateFontList (fontPtr, MaxFonts, MaxFonts + 10);
  265. if (fontPtr == NULL)
  266. {
  267. DBGPRINT(("ERROR: unable to grow font buffer, error=%d\n", GetLastError()));
  268. ReturnStatus = FALSE;
  269. break;
  270. }
  271. MaxFonts += 10;
  272. }
  273. }
  274. else DBGPRINT(("Fontname > PPDLEN ???\n"));
  275. }
  276. }
  277. else if (!_stricmp(token, ppdPSVERSION))
  278. {
  279. // PPD Postscript Version Entry?
  280. /* Get the PostScript version */
  281. token= strtok(NULL, "\011()\""); /* This should be the version */
  282. if (token != NULL)
  283. {
  284. toklen = strlen(token);
  285. /* Get the PostScript revision */
  286. if ((toklen <= PPDLEN) && (toklen > 0))
  287. {
  288. strcpy(pqr->Version, token);
  289. DBGPRINT(("Version: %s\n", pqr->Version));
  290. }
  291. else
  292. {
  293. strcpy(pqr->Version, "1.0"); // Default
  294. DBGPRINT(("Version > PPDLEN ???\n"));
  295. }
  296. token= strtok(NULL, "()\""); /* This should be the revision */
  297. if (token != NULL)
  298. {
  299. while ((*token != '\0') && (*token == ' '))
  300. token ++;
  301. toklen = strlen(token);
  302. if ((toklen <= PPDLEN) && (toklen > 0))
  303. {
  304. strcpy(pqr->Revision, token);
  305. DBGPRINT(("Revision: %s\n", pqr->Revision));
  306. }
  307. else
  308. {
  309. strcpy(pqr->Revision, "1.0"); // Some bogus token
  310. DBGPRINT(("Revision > PPDLEN ???\n"));
  311. }
  312. }
  313. else
  314. {
  315. strcpy(pqr->Version, "1.0"); // Defaults
  316. strcpy(pqr->Revision, "1.0");
  317. }
  318. }
  319. }
  320. else if (!_stricmp(token, ppdNICKNAME))
  321. {
  322. // PPD NickName?
  323. /* Get the NICKNAME */
  324. token= strtok(NULL, "\011()\""); /* This should be the nickname */
  325. if ((token != NULL) && (strlen(token) <= PPDLEN))
  326. {
  327. strcpy(pqr->DeviceNickName, token);
  328. DBGPRINT(("DeviceNickName: %s\n", pqr->DeviceNickName));
  329. }
  330. else DBGPRINT(("DeviceNickName > PPDLEN ???\n"));
  331. }
  332. else if (!_stricmp(token, ppdLANGUAGEVERSION))
  333. {
  334. // PPD Postscript Language Version?
  335. /* Get the LANGUAGEVERSION */
  336. token= strtok(NULL, " \011:"); /* This should be the language */
  337. if ((token != NULL) && (strlen(token) <= PPDLEN))
  338. {
  339. strcpy(pqr->LanguageVersion, token);
  340. DBGPRINT(("LanguageVersion: %s\n", pqr->LanguageVersion));
  341. }
  342. else DBGPRINT(("LanguageVersion > PPDLEN ???\n"));
  343. }
  344. else if (!_stricmp(token, ppdPRODUCT))
  345. {
  346. // PPD Product ?
  347. /* Get the PRODUCT */
  348. token = strtok(NULL, "\011()\""); /* This should be the product */
  349. if ((token != NULL) && (strlen(token) <= PPDLEN))
  350. {
  351. strcpy(pqr->Product, token);
  352. DBGPRINT(("Product: %s\n", pqr->Product));
  353. }
  354. else DBGPRINT(("Product > PPDLEN ???\n"));
  355. }
  356. else if (!_stricmp(token, ppdFREEVM))
  357. {
  358. token= strtok(NULL, "\011()\""); /* This should be the product */
  359. if (token != NULL)
  360. sscanf(token, "%ld", &pqr->FreeVM);
  361. DBGPRINT(("Free VM: %ld\n", pqr->FreeVM));
  362. }
  363. else if (!_stricmp(token, ppdCOLORDEVICE))
  364. {
  365. // this should be a string indicating color support or not
  366. // in the form of <True> or <False> (brackets not included)
  367. token = strtok(NULL, " \011:\x0d\x0a");
  368. if ((token != NULL) && (strlen(token) < COLORDEVICEBUFFLEN))
  369. {
  370. strcpy (pqr->pszColorDevice, token);
  371. }
  372. else
  373. {
  374. strcpy (pqr->pszColorDevice, COLORDEVICEDEFAULT);
  375. }
  376. DBGPRINT(("Color device: %s\n", pqr->pszColorDevice));
  377. }
  378. else if (!_stricmp(token, ppdDEFAULTRESOLUTION))
  379. {
  380. // this should be a string indicating the default
  381. // resolution of the printer in the form <xxxxdpi>
  382. // where xxxx is a number
  383. token = strtok(NULL, " \011:\x0d\x0a");
  384. if ((token != NULL) && (strlen(token) < RESOLUTIONBUFFLEN))
  385. {
  386. strcpy (pqr->pszResolution, token);
  387. }
  388. else
  389. {
  390. strcpy (pqr->pszResolution, RESOLUTIONDEFAULT);
  391. }
  392. DBGPRINT(("Resolution: %s\n", pqr->pszResolution));
  393. }
  394. else if (!_stricmp(token, ppdLANGUAGELEVEL))
  395. {
  396. // this should be the PostScript level ("1" or "2")
  397. // implemented in this printer
  398. token = strtok(NULL, " \011\"");
  399. if ((token != NULL) && (PPDLEN >= strlen(token)))
  400. {
  401. strcpy (pqr->pszLanguageLevel, token);
  402. }
  403. else
  404. {
  405. strcpy (pqr->pszLanguageLevel, DEFAULTLANGUAGELEVEL);
  406. }
  407. DBGPRINT(("Language Level: %s\n", pqr->pszLanguageLevel));
  408. }
  409. else if (!_stricmp(line, ppdPROTOCOL))
  410. {
  411. /* Get the string following and see if it is BCP or TBCP ? */
  412. if ((token= strtok(NULL, " \011:")) != NULL)
  413. {
  414. if (strstr(token, PROTOCOL_BCP) != NULL)
  415. {
  416. pqr->SupportsBinary = TRUE;
  417. }
  418. }
  419. }
  420. }
  421. if (!ReturnStatus)
  422. {
  423. pqr->fonts = NULL;
  424. pqr->MaxFontIndex = 0;
  425. }
  426. else
  427. {
  428. pqr->fonts = fontPtr;
  429. pqr->MaxFontIndex = fontindex-1;
  430. }
  431. } while (FALSE);
  432. if (pszPPDFile != NULL)
  433. {
  434. LocalFree(pszPPDFile);
  435. }
  436. if (ppdfile != NULL)
  437. {
  438. fclose(ppdfile);
  439. }
  440. if (hPrinter != INVALID_HANDLE_VALUE)
  441. {
  442. ClosePrinter(hPrinter);
  443. }
  444. if (pdiThis != NULL)
  445. {
  446. LocalFree(pdiThis);
  447. }
  448. if (!ReturnStatus)
  449. {
  450. if (fontPtr != NULL)
  451. {
  452. LocalFree(fontPtr);
  453. }
  454. }
  455. return (ReturnStatus);
  456. }
  457. PFR
  458. ReAllocateFontList(
  459. PFR pfrOld,
  460. DWORD cOldFonts,
  461. DWORD cNewFonts
  462. )
  463. {
  464. PFR pfrNew = NULL;
  465. DBGPRINT(("enter ReAllocateFontList()\n"));
  466. do
  467. {
  468. // allocate new font record
  469. pfrNew = LocalAlloc(LPTR, cNewFonts * sizeof(FONT_RECORD));
  470. if (pfrNew == NULL)
  471. {
  472. DBGPRINT(("LocalAlloc fails with %d\n", GetLastError()));
  473. break;
  474. }
  475. //
  476. // copy old font record
  477. //
  478. CopyMemory(pfrNew, pfrOld, cOldFonts * sizeof(FONT_RECORD));
  479. } while (FALSE);
  480. LocalFree(pfrOld);
  481. return pfrNew;
  482. }
  483. /*
  484. **
  485. ** WriteToSpool()
  486. **
  487. ** Purpose: Determines if job stream is currently being written to
  488. ** the spooler, then writes it to the file if it is being written.
  489. **
  490. ** Returns: fwrite return codes.
  491. **
  492. */
  493. DWORD
  494. WriteToSpool(
  495. PJR pjr,
  496. PBYTE pchbuf,
  497. int cchlen
  498. )
  499. {
  500. BOOL SpoolIt=FALSE;
  501. DWORD cbWritten;
  502. DWORD dwError = NO_ERROR;
  503. if ((cchlen !=0) && (pchbuf != NULL) &&
  504. ((pjr->psJobState==psExitServerJob) || (pjr->psJobState==psStandardJob)))
  505. {
  506. /* determine the data stream mode to know whether to write */
  507. switch (pjr->JSState)
  508. {
  509. case JSStripEOL:
  510. case JSStripKW:
  511. case JSStripTok:
  512. DBGPRINT(("POP - strip\n"));
  513. PopJSState(pjr);
  514. break;
  515. case JSWriteEOL:
  516. case JSWriteKW:
  517. case JSWriteTok:
  518. DBGPRINT(("POP - write\n"));
  519. PopJSState(pjr);
  520. case JSWrite:
  521. SpoolIt=TRUE;
  522. break;
  523. }
  524. // Do we write this Data to the Output Stream ?
  525. if (SpoolIt)
  526. {
  527. // retry on disk full conditions.
  528. LONG RetryCount = 0;
  529. do
  530. {
  531. dwError = NO_ERROR;
  532. do
  533. {
  534. if (pjr->FirstWrite)
  535. {
  536. // don't need that filter string anymore
  537. #if 0
  538. //
  539. // place comment in job to signal AppleTalk monitor not to filter control characters
  540. //
  541. if (!WritePrinter(pjr->hPrinter, FILTERCONTROL, SIZE_FC, &cbWritten))
  542. {
  543. dwError = GetLastError();
  544. DBGPRINT(("WritePrinter() failed with %d\n", dwError));
  545. RetryCount++;
  546. break;
  547. }
  548. #endif
  549. pjr->FirstWrite = FALSE;
  550. }
  551. #if DBG_SPOOL_LOCALLY
  552. if (DbgSpoolFile != INVALID_HANDLE_VALUE)
  553. {
  554. WriteFile( DbgSpoolFile, pchbuf, cchlen, &cbWritten, NULL );
  555. }
  556. #endif
  557. if (!WritePrinter(pjr->hPrinter, pchbuf, cchlen, &cbWritten))
  558. {
  559. dwError = GetLastError();
  560. DBGPRINT(("ERROR: cannot write to printer, error = %x\n", dwError));
  561. RetryCount++;
  562. break;
  563. }
  564. } while (FALSE);
  565. if (dwError == NO_ERROR)
  566. break;
  567. if ((dwError == ERROR_HANDLE_DISK_FULL) || (dwError == ERROR_DISK_FULL))
  568. {
  569. Sleep(180*1000); // 3 minutes. Its okay to block since we cannot
  570. // service any other jobs either since the disk
  571. // has no space anyway
  572. }
  573. } while (RetryCount <= 10);
  574. }
  575. }
  576. return dwError;
  577. }
  578. /*
  579. ** MoveToPending()
  580. **
  581. ** Purpose: Moves the buffer pointed at into the pending buffer.
  582. **
  583. ** Returns: DosWrite error codes.
  584. **
  585. */
  586. DWORD
  587. MoveToPending(
  588. PJR pjr,
  589. PBYTE pchbuf,
  590. int cchlen
  591. )
  592. {
  593. DBGPRINT(("Enter MoveToPending\n"));
  594. if ((cchlen > PSLEN) || (*pchbuf != '%'))
  595. {
  596. /*
  597. * input line is not a comment and is conforming PostScript line,
  598. * so give it to WriteToSpool
  599. */
  600. DBGPRINT(("not a DSC comment, so sending to spooler\n"));
  601. return (WriteToSpool (pjr, pchbuf, cchlen));
  602. }
  603. pjr->PendingLen= cchlen;
  604. memcpy(&pjr->bufPool[pjr->bufIndx].PendingBuffer[PENDLEN-cchlen], pchbuf, cchlen);
  605. return (NO_ERROR);
  606. }
  607. /*
  608. ** TellClient ()
  609. **
  610. ** Purpose: Sends a message back to the client
  611. **
  612. ** Returns: Any of the PAPWrite return codes.
  613. **
  614. */
  615. DWORD
  616. TellClient(
  617. PJR pjr,
  618. BOOL fEof,
  619. PBYTE BuffPtr,
  620. int cchlen
  621. )
  622. {
  623. DWORD rc = NO_ERROR;
  624. fd_set writefds;
  625. struct timeval timeout;
  626. int sendflag;
  627. int wsErr;
  628. DBGPRINT(("enter TellClient()\n"));
  629. do
  630. {
  631. FD_ZERO(&writefds);
  632. FD_SET(pjr->sJob, &writefds);
  633. //
  634. // wait up to 30 seconds to be able to write
  635. //
  636. if (fEof)
  637. {
  638. sendflag = 0;
  639. }
  640. else
  641. {
  642. sendflag = MSG_PARTIAL;
  643. }
  644. timeout.tv_sec = 30;
  645. timeout.tv_usec = 0;
  646. DBGPRINT(("waiting for writeability\n"));
  647. wsErr = select(0, NULL, &writefds, NULL, &timeout);
  648. if (wsErr == 0)
  649. {
  650. DBGPRINT(("response to client times out\n"));
  651. rc = ERROR_SEM_TIMEOUT;
  652. break;
  653. }
  654. if (wsErr != 1)
  655. {
  656. rc = GetLastError();
  657. DBGPRINT(("select(writefds) fails with %d\n"));
  658. break;
  659. }
  660. if (send(pjr->sJob, BuffPtr, cchlen, sendflag) == SOCKET_ERROR)
  661. {
  662. rc = GetLastError();
  663. DBGPRINT(("send() fails with %d\n", rc));
  664. break;
  665. }
  666. } while (FALSE);
  667. return rc;
  668. }
  669. /*
  670. **
  671. ** HandleBeginBinary()
  672. **
  673. ** Purpose: Handles BeginBinary Comment Events.
  674. **
  675. */
  676. DWORD
  677. HandleBeginBinary(
  678. PJR pjr
  679. )
  680. {
  681. DBGPRINT(("Enter HandleBeginBinary\n"));
  682. /* Process the BeginBinary Comment */
  683. pjr->InBinaryOp = TRUE;
  684. return NO_ERROR;
  685. }
  686. /*
  687. **
  688. ** HandleEndBinary()
  689. **
  690. ** Purpose: Handles BeginBinary Comment Events.
  691. **
  692. */
  693. DWORD
  694. HandleEndBinary(
  695. PJR pjr
  696. )
  697. {
  698. DBGPRINT(("Enter HandleEndBinary\n"));
  699. // Process the EndBinary Comment
  700. pjr->InBinaryOp = FALSE;
  701. return NO_ERROR;
  702. }
  703. /*
  704. **
  705. ** HandleBeginExitServer()
  706. **
  707. ** Purpose: Handles BeginExitServer Comment Events.
  708. **
  709. */
  710. DWORD
  711. HandleBeginExitServer(
  712. PJR pjr
  713. )
  714. {
  715. DBGPRINT(("Enter HandleBeginExitServer\n"));
  716. switch (pjr->psJobState)
  717. {
  718. case psQueryJob:
  719. case psExitServerJob:
  720. PushJSState(pjr, JSStrip);
  721. break;
  722. case psStandardJob:
  723. PushJSState(pjr, JSStripEOL);
  724. break;
  725. }
  726. return NO_ERROR;
  727. }
  728. /*
  729. **
  730. ** HandleCreationDate()
  731. **
  732. ** Purpose: Handles CreationDate Comment Events.
  733. **
  734. ** Returns: Number of lines that should be skipped before scanning
  735. ** for another event starts again.
  736. **
  737. */
  738. DWORD
  739. HandleCreationDate(
  740. PJR pjr
  741. )
  742. {
  743. return NO_ERROR;
  744. }
  745. /*
  746. **
  747. ** HandleCreator() -
  748. **
  749. ** Purpose: Handles Creator Comment Events.
  750. **
  751. */
  752. DWORD
  753. HandleCreator(
  754. PJR pjr
  755. )
  756. {
  757. return NO_ERROR;
  758. }
  759. /*
  760. **
  761. ** HandleEndExitServer()-
  762. **
  763. ** Purpose: Handles EndExitServer Comment Events.
  764. **
  765. */
  766. DWORD
  767. HandleEndExitServer(
  768. PJR pjr
  769. )
  770. {
  771. DBGPRINT(("Enter HandleEndExitServer\n"));
  772. if (pjr->psJobState == psStandardJob)
  773. PushJSState (pjr, JSStripEOL);
  774. return NO_ERROR;
  775. }
  776. /*
  777. ** HandleEOF()
  778. **
  779. ** Purpose: Handles EOF Comment Events.
  780. **
  781. */
  782. DWORD
  783. HandleEOF(
  784. PJR pjr
  785. )
  786. {
  787. DBGPRINT(("Enter HandleEOF\n"));
  788. if (pjr->psJobState == psQueryJob || pjr->psJobState == psExitServerJob)
  789. {
  790. pjr->psJobState = psStandardJob;
  791. }
  792. // pjr->JSState = JSStripKW;
  793. return NO_ERROR;
  794. }
  795. /*
  796. **
  797. ** HandleFor()
  798. **
  799. ** Purpose: Handles For Comment Events.
  800. **
  801. */
  802. DWORD
  803. HandleFor(
  804. PJR pjr
  805. )
  806. {
  807. LPSTR token;
  808. BYTE pbBuffer[GENERIC_BUFFER_SIZE];
  809. PJOB_INFO_1 pji1Job;
  810. DWORD cbNeeded;
  811. DWORD Status = NO_ERROR;
  812. DBGPRINT(("Enter HandleFor\n"));
  813. //
  814. // only look for name in main part of print job
  815. //
  816. if (pjr->psJobState != psStandardJob)
  817. {
  818. DBGPRINT(("not in standard job, skipping username\n"));
  819. return NO_ERROR;
  820. }
  821. //
  822. // make sure we haven't already set the title
  823. //
  824. if (pjr->dwFlags & JOB_FLAG_OWNERSET)
  825. {
  826. DBGPRINT(("owner already set, skipping username\n"));
  827. return NO_ERROR;
  828. }
  829. //
  830. // mark the job as having an owner
  831. //
  832. pjr->dwFlags |= JOB_FLAG_OWNERSET;
  833. //
  834. // look for the client name in the comment and
  835. // default if not found
  836. //
  837. if (((token = strtok(NULL, NULL_STR)) == NULL) ||
  838. (strchr(token, '*') != NULL))
  839. {
  840. token = CLIENTNAME;
  841. }
  842. //
  843. // get the current job info
  844. //
  845. pji1Job = (PJOB_INFO_1)pbBuffer;
  846. if (!GetJob(pjr->hPrinter,
  847. pjr->dwJobId,
  848. 1,
  849. pbBuffer,
  850. GENERIC_BUFFER_SIZE,
  851. &cbNeeded))
  852. {
  853. //
  854. // need more buffer? If so, try again with a larger one
  855. //
  856. if (cbNeeded > GENERIC_BUFFER_SIZE)
  857. {
  858. DBGPRINT(("GetJob needs larger buffer. Retrying\n"));
  859. pji1Job = (PJOB_INFO_1)LocalAlloc(LPTR, cbNeeded);
  860. if (pji1Job == NULL)
  861. {
  862. Status = GetLastError();
  863. DBGPRINT(("ERROR: out of memory in HandleFor\n"));
  864. return Status;
  865. }
  866. if (!GetJob(pjr->hPrinter,
  867. pjr->dwJobId,
  868. 1,
  869. (LPBYTE)pji1Job,
  870. cbNeeded,
  871. &cbNeeded))
  872. {
  873. Status = GetLastError();
  874. DBGPRINT(("ERROR: second GetJob fails in HandleFor with %d\n",
  875. Status));
  876. return Status;
  877. }
  878. }
  879. else
  880. {
  881. Status = GetLastError();
  882. DBGPRINT(("GetJob fails with %d\n", Status));
  883. return Status ;
  884. }
  885. }
  886. //
  887. // change the username
  888. //
  889. OemToCharBuffW(token, pjr->pszUser, (TOKLEN > strlen(token))?(strlen(token)+1):(TOKLEN+1));
  890. pji1Job->pUserName = pjr->pszUser;
  891. DBGPRINT(("Setting user name to %ws\n", pjr->pszUser));
  892. //
  893. // set new job information (do not change job position)
  894. //
  895. pji1Job->Position = 0;
  896. if (!SetJob(pjr->hPrinter,
  897. pjr->dwJobId,
  898. 1,
  899. (LPBYTE)pji1Job,
  900. 0))
  901. {
  902. Status = GetLastError();
  903. DBGPRINT(("WARNING: tried to change user name and failed setjob with %d\n", Status));
  904. }
  905. return Status;
  906. }
  907. /*
  908. **
  909. ** HandleLogin()
  910. **
  911. ** Purpose: Handles Login Comment Events.
  912. **
  913. ** Returns: PAPWrite errors.
  914. **
  915. */
  916. DWORD
  917. HandleLogin(
  918. PJR pjr
  919. )
  920. {
  921. DBGPRINT(("Enter HandleLogin\n"));
  922. PushJSState(pjr,JSStripEOL);
  923. return (TellClient(pjr, TRUE, LOGINRESPONSE, sizeof(LOGINRESPONSE)-1));
  924. }
  925. /*
  926. **
  927. ** HandleTitle()
  928. **
  929. ** Purpose: Handles Title Comment Events.
  930. **
  931. */
  932. DWORD
  933. HandleTitle(
  934. PJR pjr
  935. )
  936. {
  937. LPSTR token;
  938. LPWSTR pszTitle;
  939. BYTE pbBuffer[GENERIC_BUFFER_SIZE];
  940. PJOB_INFO_1 pji1Job;
  941. PJOB_INFO_1 pji1JobAlloc=NULL;
  942. DWORD cbNeeded;
  943. DWORD Status = NO_ERROR;
  944. DBGPRINT(("Enter HandleTitle\n"));
  945. //
  946. // only get title if we are in main part of job
  947. //
  948. if (pjr->psJobState != psStandardJob)
  949. {
  950. DBGPRINT(("skipping this title, not main job\n"));
  951. return NO_ERROR ;
  952. }
  953. //
  954. // make sure title not already set
  955. //
  956. if (JOB_FLAG_TITLESET & pjr->dwFlags)
  957. {
  958. DBGPRINT(("title already set. Skipping this title\n"));
  959. return NO_ERROR;
  960. }
  961. //
  962. // marke the title as set
  963. //
  964. pjr->dwFlags |= JOB_FLAG_TITLESET;
  965. //
  966. // get the current job data
  967. //
  968. pji1Job = (PJOB_INFO_1)pbBuffer;
  969. if (!GetJob(pjr->hPrinter,
  970. pjr->dwJobId,
  971. 1,
  972. pbBuffer,
  973. GENERIC_BUFFER_SIZE,
  974. &cbNeeded))
  975. {
  976. //
  977. // need more buffer? If so, try again with a larger one
  978. //
  979. if (cbNeeded > GENERIC_BUFFER_SIZE)
  980. {
  981. DBGPRINT(("GetJob needs larger buffer. Retrying\n"));
  982. pji1JobAlloc = (PJOB_INFO_1)LocalAlloc(LPTR, cbNeeded);
  983. if (pji1JobAlloc == NULL)
  984. {
  985. Status = GetLastError();
  986. DBGPRINT(("ERROR: out of memory\n"));
  987. return Status;
  988. }
  989. pji1Job = pji1JobAlloc;
  990. if (!GetJob(pjr->hPrinter,
  991. pjr->dwJobId,
  992. 1,
  993. (LPBYTE)pji1Job,
  994. cbNeeded,
  995. &cbNeeded))
  996. {
  997. Status = GetLastError();
  998. DBGPRINT(("ERROR: second GetJob fails with %d\n", Status));
  999. LocalFree(pji1JobAlloc);
  1000. return Status;
  1001. }
  1002. }
  1003. else
  1004. {
  1005. Status = GetLastError();
  1006. DBGPRINT(("GetJob fails with %d\n", Status));
  1007. return Status;
  1008. }
  1009. }
  1010. //
  1011. // get the title
  1012. //
  1013. if ((token = strtok(NULL, NULL_STR)) == NULL)
  1014. {
  1015. // Clear flag. No title.
  1016. pjr->dwFlags &= ~JOB_FLAG_TITLESET;
  1017. return NO_ERROR ;
  1018. }
  1019. pszTitle = (LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR) * (strlen(token)+1));
  1020. if (pszTitle == NULL)
  1021. {
  1022. Status = GetLastError();
  1023. DBGPRINT(("out of memory for pszTitle\n"));
  1024. return Status;
  1025. }
  1026. OemToCharBuffW(token, pszTitle, strlen(token)+1);
  1027. //
  1028. // change the title
  1029. //
  1030. pji1Job->Position = 0;
  1031. pji1Job->pDocument = pszTitle;
  1032. DBGPRINT(("changing title to %ws\n", pszTitle));
  1033. if (!SetJob(pjr->hPrinter,
  1034. pjr->dwJobId,
  1035. 1,
  1036. (LPBYTE)pji1Job,
  1037. 0))
  1038. {
  1039. Status = GetLastError();
  1040. DBGPRINT(("WARNING: tried to change title and failed setjob with %d\n", Status));
  1041. }
  1042. if (pji1JobAlloc)
  1043. {
  1044. LocalFree(pji1JobAlloc);
  1045. }
  1046. LocalFree(pszTitle);
  1047. return Status;
  1048. }
  1049. /*
  1050. **
  1051. ** HandleBeginProcSet()
  1052. **
  1053. ** Purpose: Handles Begining of a ProcSet Upload
  1054. **
  1055. */
  1056. DWORD
  1057. HandleBeginProcSet(
  1058. PJR pjr
  1059. )
  1060. {
  1061. DBGPRINT(("Enter HandleBeginProcSet\n"));
  1062. return NO_ERROR;
  1063. }
  1064. /*
  1065. ** HandleEndProcSet()
  1066. **
  1067. ** Purpose: Handles End of a procset inclusion.
  1068. **
  1069. */
  1070. DWORD
  1071. HandleEndProcSet(
  1072. PJR pjr
  1073. )
  1074. {
  1075. DBGPRINT(("Enter HandleEndProcSet\n"));
  1076. return NO_ERROR;
  1077. }
  1078. /*
  1079. ** HandleIncludeProcSet()
  1080. **
  1081. ** Purpose: Handles end of a procset inclusion.
  1082. **
  1083. ** Entry:
  1084. ** Pointer to Job Structure
  1085. **
  1086. ** Exit:
  1087. **
  1088. ** 0 if no error, otherwise error code.
  1089. */
  1090. DWORD
  1091. HandleIncludeProcSet(
  1092. PJR pjr
  1093. )
  1094. {
  1095. DBGPRINT(("Enter HandleIncludeProcSet\n"));
  1096. return NO_ERROR;
  1097. }
  1098. ///////////////////////////////////////////////////////////////////////////////
  1099. //
  1100. // HandlePages()
  1101. //
  1102. // This comment includes the total number of pages in the job and is
  1103. // used to set the jobinfo structure for the job with the total number
  1104. // of pages
  1105. //
  1106. ///////////////////////////////////////////////////////////////////////////////
  1107. DWORD
  1108. HandlePages(
  1109. PJR pjr
  1110. )
  1111. {
  1112. LPSTR token;
  1113. DWORD cPages = 0;
  1114. BYTE pbBuffer[GENERIC_BUFFER_SIZE];
  1115. PJOB_INFO_1 pji1Job;
  1116. DWORD cbNeeded;
  1117. DWORD Status = NO_ERROR;
  1118. DBGPRINT(("Enter HandlePages\n"));
  1119. //
  1120. // only get pages if we are in main part of job
  1121. //
  1122. if (pjr->psJobState != psStandardJob)
  1123. {
  1124. DBGPRINT(("skipping this comment, not main job\n"));
  1125. return NO_ERROR ;
  1126. }
  1127. //
  1128. // get the current job data
  1129. //
  1130. pji1Job = (PJOB_INFO_1)pbBuffer;
  1131. if (!GetJob(pjr->hPrinter,
  1132. pjr->dwJobId,
  1133. 1,
  1134. pbBuffer,
  1135. GENERIC_BUFFER_SIZE,
  1136. &cbNeeded))
  1137. {
  1138. //
  1139. // GetJob failed, and buffer passed in is larger than the largest
  1140. // possible buffer for a job_info_1, so abort this ADSC comment
  1141. //
  1142. Status = GetLastError();
  1143. DBGPRINT(("GetJob() fails with %d\n", Status));
  1144. return Status;
  1145. }
  1146. //
  1147. // get the number of pages. The comment is of the form %%Pages xx nn
  1148. // where xx is the number of pages to display
  1149. //
  1150. token = strtok(NULL, " ");
  1151. if (token == NULL)
  1152. return(NO_ERROR);
  1153. cPages = atoi(token);
  1154. //
  1155. // change the number of pages
  1156. //
  1157. pji1Job->Position = 0;
  1158. pji1Job->TotalPages = cPages;
  1159. DBGPRINT(("changing page count to %d\n", cPages));
  1160. if (!SetJob(pjr->hPrinter,
  1161. pjr->dwJobId,
  1162. 1,
  1163. (LPBYTE)pji1Job,
  1164. 0))
  1165. {
  1166. Status = GetLastError();
  1167. DBGPRINT(("SetJob fails with %d\n",Status));
  1168. }
  1169. return Status;
  1170. }
  1171. struct commtable
  1172. {
  1173. PSZ commentstr;
  1174. DWORD (near *pfnHandle)(PJR);
  1175. } commtable [] =
  1176. {
  1177. { FORCOMMENT, HandleFor },
  1178. { TITLECOMMENT, HandleTitle },
  1179. { BEXITSERVER, HandleBeginExitServer },
  1180. { EEXITSERVER, HandleEndExitServer },
  1181. { BPROCSET, HandleBeginProcSet },
  1182. { EPROCSET, HandleEndProcSet },
  1183. { INCLUDEPROCSET, HandleIncludeProcSet },
  1184. { CREATIONDATE, HandleCreationDate },
  1185. { CREATOR, HandleCreator },
  1186. { EOFCOMMENT, HandleEOF },
  1187. { LOGIN, HandleLogin },
  1188. { LOGINCONT, HandleLogin },
  1189. { BEGINBINARY, HandleBeginBinary },
  1190. { ENDBINARY, HandleEndBinary },
  1191. { PAGESCOMMENT, HandlePages },
  1192. { NULL, NULL }
  1193. };
  1194. /*
  1195. ** HandleComment()
  1196. **
  1197. ** Purpose: Handles Comment Events.
  1198. **
  1199. */
  1200. DWORD
  1201. HandleComment(
  1202. PJR pjr,
  1203. PBYTE ps
  1204. )
  1205. {
  1206. PSZ token;
  1207. struct commtable *pct;
  1208. DWORD status = NO_ERROR;
  1209. DBGPRINT(("Enter HandleComment\n"));
  1210. if ((token = strtok(ps," :")) != NULL)
  1211. {
  1212. DBGPRINT(("Comment: %s\n", token));
  1213. for (pct = commtable; pct->pfnHandle; pct++)
  1214. {
  1215. if (!_stricmp(token, pct->commentstr))
  1216. {
  1217. status = pct->pfnHandle(pjr);
  1218. break;
  1219. }
  1220. }
  1221. }
  1222. // No action on this keyword !!!
  1223. return status;
  1224. }
  1225. /*
  1226. ** HandleJobComment()
  1227. **
  1228. ** Purpose: This parses PostScript Job Comments
  1229. */
  1230. void
  1231. HandleJobComment(
  1232. PJR pjr,
  1233. PBYTE ps
  1234. )
  1235. {
  1236. char *token;
  1237. DBGPRINT(("Enter HandleJobComment\n"));
  1238. token= strtok(ps, " ");
  1239. //
  1240. // it's a job statement
  1241. //
  1242. if ((token = strtok(NULL, " ")) != NULL)
  1243. {
  1244. /* standard job identification */
  1245. if (!strcmp(token, QUERYJOBID))
  1246. {
  1247. pjr->psJobState = psQueryJob;
  1248. pjr->JSState = JSStrip;
  1249. DBGPRINT(("This is a standard job\n"));
  1250. return;
  1251. }
  1252. if (!strcmp(token, EXITJOBID))
  1253. {
  1254. pjr->psJobState = psExitServerJob;
  1255. pjr->JSState = JSStrip;
  1256. DBGPRINT(("This is an exitjob\n"));
  1257. return;
  1258. }
  1259. }
  1260. //
  1261. // Job identification not recognized, but some PostScript hackers
  1262. // put the program name in this comment, so we treat this as a standard
  1263. // job
  1264. //
  1265. DBGPRINT(("This is an unknown jobtype - processing as standard job\n"));
  1266. pjr->psJobState = psStandardJob;
  1267. pjr->JSState = JSWrite;
  1268. }
  1269. /* LineLength -
  1270. * Returns the number of bytes, including CR/LF to the next
  1271. * CR/LF in the buffer. If no CR/LF found, returns -1
  1272. */
  1273. int
  1274. LineLength(PBYTE pBuf, int cbBuf)
  1275. {
  1276. int intLength = 0;
  1277. while (intLength < cbBuf)
  1278. {
  1279. //
  1280. // we are looking for a CR
  1281. //
  1282. if ((pBuf[intLength] != '\x0d') && (pBuf[intLength] != '\x0a'))
  1283. {
  1284. intLength++;
  1285. continue;
  1286. }
  1287. //
  1288. // we've found a CR. If it's followed by a LF, return that
  1289. // length too, otherwise, just return what we've found
  1290. //
  1291. if ((intLength + 1) < cbBuf)
  1292. {
  1293. if (pBuf[intLength + 1] == '\x0a')
  1294. {
  1295. return intLength + 2;
  1296. }
  1297. }
  1298. return intLength + 1;
  1299. }
  1300. return (-1);
  1301. }
  1302. /*
  1303. **
  1304. ** PSParse()
  1305. **
  1306. ** Purpose: This does the actual parsing of the PostScript Data Stream.
  1307. ** This routine is always called pointing to the data stream at
  1308. ** the beginning of a the Data Stream, or the beginning of a line.
  1309. **
  1310. ** Returns: PAPWrite error codes.
  1311. **
  1312. */
  1313. DWORD
  1314. PSParse(
  1315. PJR pjr,
  1316. PBYTE pchbuf,
  1317. int cchlen
  1318. )
  1319. {
  1320. int cbskip;
  1321. char ps[PENDLEN];
  1322. DWORD err = NO_ERROR;
  1323. DBGPRINT(("ENTER: PSParse()\n"));
  1324. while (cchlen > 0)
  1325. {
  1326. if ((cbskip = LineLength(pchbuf, cchlen)) == -1)
  1327. return (MoveToPending(pjr, pchbuf, cchlen));
  1328. /* Determine what the event is */
  1329. if ((cbskip < PSLEN) && (pchbuf[0] == '%'))
  1330. {
  1331. /* copy a comment into the ps string */
  1332. memcpy(ps, pchbuf, cbskip);
  1333. ps[cbskip-1] = 0; // OverWrite the CR/LF
  1334. if (ps[1] == '%')
  1335. {
  1336. /* Its a Query Comment */
  1337. if (ps[2] == '?'&& !pjr->InBinaryOp)
  1338. {
  1339. if (ps[3] == 'B')
  1340. {
  1341. /* Process the Begin Query Comment */
  1342. if ((err = HandleBQComment(pjr, ps)) != NO_ERROR)
  1343. {
  1344. DBGPRINT(("PSParse: HandleBQComment %ld\n", err));
  1345. return(err);
  1346. }
  1347. }
  1348. else if (ps[3] == 'E')
  1349. {
  1350. if (pjr->InProgress == QUERYDEFAULT)
  1351. {
  1352. if ((err = FinishDefaultQuery(pjr, ps)) != NO_ERROR)
  1353. {
  1354. DBGPRINT(("PSParse: FinishDefaultQuery %ld\n", err));
  1355. return(err);
  1356. }
  1357. }
  1358. }
  1359. }
  1360. else
  1361. {
  1362. /* Process the Comment */
  1363. if ((err = HandleComment(pjr, ps)) != NO_ERROR)
  1364. {
  1365. DBGPRINT(("PSParse: HandleComment %ld\n", err));
  1366. return(err);
  1367. }
  1368. }
  1369. }
  1370. else if (ps[1] == '!'&& !pjr->InBinaryOp)
  1371. {
  1372. /* Process Job ID Comment */
  1373. HandleJobComment(pjr, ps);
  1374. }
  1375. }
  1376. /* Write the lines to the spoolfile? */
  1377. if ((err = WriteToSpool (pjr, pchbuf, cbskip)) != NO_ERROR)
  1378. return (err);
  1379. pchbuf += cbskip;
  1380. cchlen -= cbskip;
  1381. }
  1382. return NO_ERROR;
  1383. }