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.

1247 lines
27 KiB

  1. /*
  2. ** Copyright(c) Microsoft Corp., 1991
  3. *
  4. /*
  5. ** File Name:
  6. **
  7. ** PSPQUERY.C - PostScript Parser Handlers for Query Comments
  8. **
  9. ** General Description:
  10. **
  11. ** These are the routines that parse and interprete the PostScript data
  12. ** stream. This interpreter looks for PostScript Document Structuring
  13. ** Comments, which are the spooler commands that are imbedded in the
  14. ** PostScript job stream. This particular file has the code that handles
  15. ** the postscript query commands
  16. */
  17. #include <stdio.h>
  18. #include <string.h>
  19. #include <search.h>
  20. #include <windows.h>
  21. #include <macps.h>
  22. #include <psqfont.h>
  23. #include <debug.h>
  24. #include <pskey.h>
  25. DWORD HandleFeatureLanguage(PJR pjr);
  26. DWORD HandleFeatureVersion(PJR pjr);
  27. DWORD HandleFeatureBinary(PJR pjr);
  28. DWORD HandleFeatureProduct(PJR pjr);
  29. DWORD HandleFeatureResolution(PJR pjr);
  30. DWORD HandleFeatureColor(PJR pjr);
  31. DWORD HandleFeatureVM(PJR pjr);
  32. DWORD HandleFeatureSpooler(PJR pjr);
  33. DWORD HandleBeginFeatureQuery(PJR pjr, PSZ pszQuery);
  34. DWORD HandleEndFeatureQuery(PJR pjr, PSZ pszDefaultResponse);
  35. BOOL IsFontAvailable(PQR pqr, LPSTR pszFontName);
  36. int __cdecl compare(const void * arg1, const void * arg2);
  37. LONG GetFontListResponse(PQR pqr, LPSTR pFontBuffer, DWORD cbFontBuffer, LPDWORD pcbNeeded);
  38. /*
  39. ** HandleEndFontListQuery()
  40. **
  41. ** Purpose: Handles the EndFontListQuery Comment
  42. **
  43. ** Returns: Error Codes from PAPWrite Call
  44. **
  45. */
  46. #define DEFAULT_FONTBUF_SIZE 2048
  47. DWORD
  48. HandleEndFontListQuery(
  49. PJR pjr
  50. )
  51. {
  52. PQR pqr = pjr->job_pQr;
  53. LPSTR pFontBuffer = NULL;
  54. LPSTR pFontWalker = NULL;
  55. DWORD cbFontBuffer = 0;
  56. DWORD dwStatus = NO_ERROR;
  57. DWORD cbNeeded;
  58. DBGPRINT(("Enter HandleEndFontListQuery\n"));
  59. do
  60. {
  61. //
  62. // allocate a typical font buffer
  63. //
  64. if ((pFontBuffer = (LPSTR)LocalAlloc(LPTR, DEFAULT_FONTBUF_SIZE)) == NULL)
  65. {
  66. dwStatus = GetLastError();
  67. DBGPRINT(("ERROR: unable to allocate font buffer\n"));
  68. break;
  69. }
  70. cbFontBuffer = DEFAULT_FONTBUF_SIZE;
  71. //
  72. // get the fontlist response
  73. //
  74. if ((dwStatus = GetFontListResponse(pqr, pFontBuffer, cbFontBuffer, &cbNeeded)) != ERROR_SUCCESS)
  75. {
  76. //
  77. // if buffer too small, reallocate and try again
  78. //
  79. if (dwStatus == ERROR_MORE_DATA)
  80. {
  81. LocalFree(pFontBuffer);
  82. if ((pFontBuffer = (LPSTR)LocalAlloc(LPTR, cbNeeded)) == NULL)
  83. {
  84. dwStatus = GetLastError();
  85. DBGPRINT(("ERROR: unable to reallocate font buffer\n"));
  86. break;
  87. }
  88. cbFontBuffer = cbNeeded;
  89. if ((dwStatus = GetFontListResponse(pqr, pFontBuffer, cbFontBuffer, &cbNeeded)) != ERROR_SUCCESS)
  90. {
  91. DBGPRINT(("ERROR: unable to get font list response\n"));
  92. break;
  93. }
  94. }
  95. }
  96. //
  97. // send response to client (in single font name per write)
  98. // NOTE: While the Apple LaserWriter driver gets fonts from
  99. // the printer in 512 byte packets that are packed with multiple
  100. // font names, the PageMaker driver expects fonts to come in
  101. // a single font per write scheme. So we lose the work that builds
  102. // a font response like the Mac LaserWriter driver by sending
  103. // the fonts as PageMaker expects them (which works for both
  104. // drivers)
  105. //
  106. DBGPRINT(("writing fontlist:\n%s", pFontBuffer));
  107. pFontWalker = pFontBuffer;
  108. cbFontBuffer = 0;
  109. while (*pFontWalker != '*')
  110. {
  111. cbFontBuffer = strlen(pFontWalker);
  112. if ((dwStatus = TellClient(pjr, FALSE, pFontWalker, cbFontBuffer)) != NO_ERROR)
  113. {
  114. //
  115. // error sending data to client
  116. //
  117. DBGPRINT(("ERROR: unable to send font to client\n"));
  118. break;
  119. }
  120. pFontWalker += (cbFontBuffer + 1);
  121. }
  122. //
  123. // do not fail if a send of a font fails. If we can get the
  124. // termination font out, the Mac will just download any fonts
  125. // it needs and the job will print - albeit slowly.
  126. //
  127. if ((dwStatus = TellClient(pjr, pjr->EOFRecvd, pFontWalker, strlen(pFontWalker))) != NO_ERROR)
  128. {
  129. DBGPRINT(("ERROR: unable to send terminating font to client\n"));
  130. break;
  131. }
  132. } while (FALSE);
  133. if (pFontBuffer != NULL)
  134. {
  135. LocalFree (pFontBuffer);
  136. }
  137. return dwStatus;
  138. }
  139. //////////////////////////////////////////////////////////////////////////////
  140. //
  141. // GetFontListResponse - formats a fontlist buffer to send to a Mac
  142. //
  143. // Based on the queue type (Postscript or non), a fontlist is generated
  144. // and placed in the supplied buffer. The font list is an ordered list
  145. // of fonts separated by '\n\0' with a terminating font of '*\n\0'.
  146. //
  147. // if the buffer is too small, this routine returns ERROR_MORE_DATA.
  148. // if for some other reason the list cannot be generated, the return
  149. // value is ERROR_INVALID_PARAMETER.
  150. // if the function successfully returns a font list, the return value
  151. // is ERROR_SUCCESS.
  152. //
  153. //////////////////////////////////////////////////////////////////////////////
  154. LONG
  155. GetFontListResponse(
  156. PQR pqr,
  157. LPSTR pFontBuffer,
  158. DWORD cbFontBuffer,
  159. LPDWORD pcbNeeded
  160. )
  161. {
  162. LONG lReturn = ERROR_SUCCESS;
  163. HANDLE hFontQuery = INVALID_HANDLE_VALUE;
  164. DWORD cFonts;
  165. DWORD dwIndex;
  166. BOOL boolPSQueue;
  167. LPSTR *apszFontNames = NULL;
  168. LPSTR pTempBuffer = NULL;
  169. DWORD cbTempBuffer = cbFontBuffer;
  170. DWORD cbFontFileName;
  171. LPSTR pFont;
  172. DWORD cbFont;
  173. DWORD rc;
  174. DBGPRINT(("enter GetFontListResponse(cbBuffer:%d, cbNeeded:%d\n", cbFontBuffer, *pcbNeeded));
  175. do
  176. {
  177. //
  178. // what kind of queue are we
  179. //
  180. if (wcscmp(pqr->pDataType, MACPS_DATATYPE_RAW))
  181. {
  182. //
  183. // we are PSTODIB
  184. //
  185. boolPSQueue = FALSE;
  186. }
  187. else
  188. {
  189. //
  190. // we are Postscript
  191. //
  192. boolPSQueue = TRUE;
  193. }
  194. //
  195. // allocate an array of fontname pointers.
  196. //
  197. if (boolPSQueue)
  198. {
  199. cFonts = pqr->MaxFontIndex + 1;
  200. DBGPRINT(("cFonts=%d\n", cFonts));
  201. apszFontNames = (LPSTR*)LocalAlloc(LPTR, cFonts * sizeof(LPSTR));
  202. }
  203. else
  204. {
  205. //
  206. // for PSTODIB we will need a temp buffer for the fonts as well
  207. //
  208. if ((pTempBuffer = (LPSTR)LocalAlloc(LPTR, cbFontBuffer)) == NULL)
  209. {
  210. lReturn = ERROR_INVALID_PARAMETER;
  211. DBGPRINT(("ERROR: unable to allocate temp font buffer\n"));
  212. break;
  213. }
  214. if ((rc = PsBeginFontQuery(&hFontQuery)) != PS_QFONT_SUCCESS)
  215. {
  216. DBGPRINT(("ERROR: PsBeginFontQuery returns %d\n", rc));
  217. lReturn = ERROR_INVALID_PARAMETER;
  218. break;
  219. }
  220. if ((rc = PsGetNumFontsAvailable(hFontQuery,
  221. &cFonts)) != PS_QFONT_SUCCESS)
  222. {
  223. DBGPRINT(("ERROR: PsGetNumFontsAvailable returns %d\n", rc));
  224. lReturn = ERROR_INVALID_PARAMETER;
  225. break;
  226. }
  227. apszFontNames = (LPSTR*)LocalAlloc(LPTR, cFonts * sizeof(LPSTR));
  228. }
  229. if (apszFontNames == NULL)
  230. {
  231. DBGPRINT(("ERROR: cannot allocate font list array\n"));
  232. lReturn = ERROR_INVALID_PARAMETER;
  233. break;
  234. }
  235. //
  236. // fill the array of fontname pointers
  237. //
  238. *pcbNeeded = 3;
  239. pFont = pTempBuffer;
  240. for (dwIndex = 0; dwIndex < cFonts; dwIndex++)
  241. {
  242. if (boolPSQueue)
  243. {
  244. apszFontNames[dwIndex] = pqr->fonts[dwIndex].name;
  245. *pcbNeeded += (strlen(pqr->fonts[dwIndex].name)+2);
  246. DBGPRINT(("adding font:%s, cbNeeded:%d, index:%d\n", pqr->fonts[dwIndex].name, *pcbNeeded, dwIndex));
  247. }
  248. else
  249. {
  250. //
  251. // pstodib - add the font to the temp buffer
  252. // and set the pointer
  253. //
  254. cbFont = cbTempBuffer = cbFontBuffer;
  255. if ((rc = PsGetFontInfo(hFontQuery,
  256. dwIndex,
  257. pFont,
  258. &cbFont,
  259. NULL,
  260. &cbFontFileName)) != PS_QFONT_SUCCESS)
  261. {
  262. //
  263. // if we are out of memory, continue enumeration
  264. // to get size needed, but set return to ERROR_MORE_DATA
  265. //
  266. if (rc == PS_QFONT_ERROR_FONTNAMEBUFF_TOSMALL)
  267. {
  268. DBGPRINT(("user buffer too small for font query\n"));
  269. lReturn = ERROR_MORE_DATA;
  270. pFont = pTempBuffer;
  271. cbFont = cbTempBuffer = cbFontBuffer;
  272. if ((rc = PsGetFontInfo(hFontQuery,
  273. dwIndex,
  274. pFont,
  275. &cbFont,
  276. NULL,
  277. &cbFontFileName)) != PS_QFONT_SUCCESS)
  278. {
  279. //
  280. // we be hosed. Fail.
  281. //
  282. lReturn = ERROR_INVALID_PARAMETER;
  283. DBGPRINT(("ERROR: cannot continue PSTODIB font enumeration\n"));
  284. break;
  285. }
  286. else
  287. {
  288. *pcbNeeded += cbFont + 2;
  289. }
  290. }
  291. }
  292. else
  293. {
  294. *pcbNeeded += cbFont + 2;
  295. }
  296. apszFontNames[dwIndex] = pFont;
  297. cbTempBuffer -= cbFont;
  298. pFont += cbFont;
  299. cbFont = cbTempBuffer;
  300. }
  301. }
  302. if (*pcbNeeded > cbFontBuffer)
  303. {
  304. lReturn = ERROR_MORE_DATA;
  305. break;
  306. }
  307. //
  308. // build the fontlistresponse
  309. //
  310. cbFontBuffer = 0;
  311. for (dwIndex = 0; dwIndex < cFonts; dwIndex++)
  312. {
  313. cbFont = sprintf(pFontBuffer, "%s\n", apszFontNames[dwIndex]) + 1;
  314. pFontBuffer += cbFont;
  315. cbFontBuffer += cbFont;
  316. }
  317. memcpy (pFontBuffer, "*\n", 3);
  318. } while (FALSE);
  319. if (apszFontNames != NULL)
  320. {
  321. LocalFree(apszFontNames);
  322. }
  323. if (pTempBuffer != NULL)
  324. {
  325. LocalFree(pTempBuffer);
  326. }
  327. if (hFontQuery != INVALID_HANDLE_VALUE)
  328. {
  329. PsEndFontQuery(hFontQuery);
  330. }
  331. return (lReturn);
  332. }
  333. int __cdecl
  334. compare(const void* arg1, const void* arg2)
  335. {
  336. return _stricmp(* (char **)arg1, * (char **)arg2);
  337. }
  338. //
  339. // For Postscript printers, the font enumeration technique is complex.
  340. // EnumFontFamilies expects the programmer to specify a callback function
  341. // that will be called either once for every font family, or once for
  342. // every font face in a family. To get all fonts available, I use
  343. // EnumFontFamilies twice. The first enumeration, I call EnumFontFamilies
  344. // with a null value for the family name. This causes the callback
  345. // function to be called once for each family name installed. This
  346. // callback function then does an enumeration on that family name to
  347. // get the specific face names in the family. This second layer of
  348. // enumeration specifies yet another callback function that returns
  349. // the font name to the Macintosh client.
  350. //
  351. void
  352. EnumeratePostScriptFonts(
  353. PJR pjr
  354. )
  355. {
  356. PQR pqr = pjr->job_pQr;
  357. DBGPRINT(("ENTER EnumeratePostScriptFonts\n"));
  358. if (pjr->hicFontFamily != NULL)
  359. {
  360. //
  361. // enumerate the font families
  362. //
  363. EnumFontFamilies(pjr->hicFontFamily,
  364. NULL,
  365. (FONTENUMPROC)FamilyEnumCallback,
  366. (LPARAM)pjr);
  367. }
  368. }
  369. int CALLBACK
  370. FamilyEnumCallback(
  371. LPENUMLOGFONT lpelf,
  372. LPNEWTEXTMETRIC pntm,
  373. int iFontType,
  374. LPARAM lParam
  375. )
  376. {
  377. PQR pqr = ((PJR)lParam)->job_pQr;
  378. PJR pjr = (PJR)lParam;
  379. DBGPRINT(("Enter FamilyEnumCallback for family %ws\n", lpelf->elfFullName));
  380. //
  381. // enumerate the fonts in this family
  382. //
  383. if (iFontType & DEVICE_FONTTYPE)
  384. {
  385. DBGPRINT(("enumerating face names\n"));
  386. EnumFontFamilies(pjr->hicFontFace,
  387. lpelf->elfFullName,
  388. (FONTENUMPROC)FontEnumCallback,
  389. lParam);
  390. }
  391. else
  392. {
  393. DBGPRINT(("this family is not a DEVICE_FONTTYPE\n"));
  394. }
  395. return 1;
  396. }
  397. int CALLBACK
  398. FontEnumCallback(
  399. LPENUMLOGFONT lpelf,
  400. LPNEWTEXTMETRIC pntm,
  401. int iFontType,
  402. LPARAM lParam
  403. )
  404. {
  405. DWORD PAPStatus;
  406. PJR pjr = (PJR)lParam;
  407. BYTE pszFontName[255];
  408. DBGPRINT(("Enter FontEnumCallback\n"));
  409. //
  410. // return this font name to the client
  411. //
  412. if (iFontType & DEVICE_FONTTYPE)
  413. {
  414. CharToOem(lpelf->elfFullName, pszFontName);
  415. if (PAPStatus = TellClient(pjr,
  416. FALSE,
  417. pszFontName,
  418. strlen(pszFontName)))
  419. {
  420. DBGPRINT(("ERROR: TellClient returns %d\n", PAPStatus));
  421. }
  422. }
  423. else
  424. {
  425. DBGPRINT(("%ws is not a DEVICE_FONTTYPE\n", lpelf->elfFullName));
  426. }
  427. return 1;
  428. }
  429. /*
  430. ** HandleEndQuery()
  431. **
  432. ** Purpose: PageMaker will send a query that goes like this:
  433. **
  434. ** %%BeginQuery
  435. ** ...
  436. ** %%EndQuery (spooler)
  437. **
  438. ** In order to allow pagemaker to print TIFF formated images
  439. ** properly, we should respond to this query with "printer".
  440. **
  441. ** Returns: Error Codes from PAPWrite Call
  442. **
  443. */
  444. DWORD
  445. HandleEndQuery(
  446. PJR pjr,
  447. PBYTE ps
  448. )
  449. {
  450. char *token;
  451. CHAR pszResponse[PSLEN+1];
  452. DBGPRINT(("Enter HandleEndQuery\n"));
  453. token = strtok(NULL,"\n");
  454. if (token == NULL)
  455. {
  456. return NO_ERROR;
  457. }
  458. /* strip off any leading blanks in the default */
  459. token += strspn(token, " ");
  460. //
  461. // respond with the default
  462. //
  463. sprintf(pszResponse, "%s\x0a", token);
  464. return (TellClient(pjr, pjr->EOFRecvd, pszResponse, strlen(pszResponse)));
  465. }
  466. /***************************************************************************
  467. ** FinishDefaultQuery()
  468. **
  469. ** Purpose: Scans for the PostScript command specified in psKeyWord. It
  470. ** then will respond with the default response specified on that
  471. ** line. It will set the InProgress field in the JOB_RECORD to
  472. ** an InProgress value if the default is not found in this buffer.
  473. **
  474. ** Returns: Error Codes from PAPWrite Call
  475. **
  476. ***************************************************************************/
  477. DWORD
  478. FinishDefaultQuery(
  479. PJR pjr,
  480. PBYTE ps
  481. )
  482. {
  483. char * token;
  484. char buf[PSLEN+1];
  485. DBGPRINT(("FinishDefaultQuery: %s\n", ps));
  486. if (NULL == (token = strtok (ps," :")))
  487. {
  488. return (NO_ERROR);
  489. }
  490. pjr->InProgress= NOTHING;
  491. /* First We Should Handle the cases that do not use the default response */
  492. if (!_stricmp(token, EFEATUREQUERY))
  493. return (HandleEndFeatureQuery(pjr, strtok (NULL," \n")));
  494. if (!_stricmp(token, EFONTLISTQ))
  495. return( HandleEndFontListQuery (pjr));
  496. if (!_stricmp(token, EQUERY))
  497. return( HandleEndQuery (pjr, ps));
  498. if (!_stricmp(token, EPRINTERQUERY))
  499. return( HandleEndPrinterQuery(pjr));
  500. if (!_stricmp(token, EVMSTATUS))
  501. {
  502. sprintf(buf, "%ld", pjr->job_pQr->FreeVM);
  503. return (TellClient(pjr, pjr->EOFRecvd, buf , strlen(buf)));
  504. }
  505. if ((token = strtok(NULL,"\n")) == NULL)
  506. {
  507. return (NO_ERROR);
  508. }
  509. /* strip off any leading blanks in the default. Append a LF */
  510. token += strspn(token, " ");
  511. sprintf(buf, "%s\x0a", token);
  512. return (TellClient(pjr, pjr->EOFRecvd, buf, strlen(buf)));
  513. }
  514. DWORD
  515. HandleEndFeatureQuery(
  516. PJR pjr,
  517. PSZ pszDefaultResponse)
  518. {
  519. DWORD rc = NO_ERROR;
  520. CHAR pszResponse[PSLEN];
  521. DBGPRINT(("enter HandleEndFeatureQuery\n"));
  522. do
  523. {
  524. //
  525. // return the default response if there is one
  526. //
  527. if (NULL != pszDefaultResponse)
  528. {
  529. sprintf(pszResponse, "%s\x0a", pszDefaultResponse);
  530. DBGPRINT(("responding with default response from query: %s\n", pszResponse));
  531. rc = TellClient(pjr, pjr->EOFRecvd, pszResponse, strlen(pszResponse));
  532. break;
  533. }
  534. DBGPRINT(("responding with Unknown\n"));
  535. rc = TellClient(pjr, pjr->EOFRecvd, DEFAULTRESPONSE, strlen(DEFAULTRESPONSE));
  536. } while (FALSE);
  537. return rc;
  538. }
  539. /*
  540. ** Routine:
  541. ** ParseDict
  542. **
  543. ** Purpse:
  544. **
  545. ** This routine will take a given QueryProcSet, BeginProcSet, or
  546. ** IncludeProcSet comment and determine what dictionary is being
  547. ** referenced.
  548. **
  549. ** Entry:
  550. **
  551. ** Address of a record to fill in with the Dictionary information.
  552. **
  553. ** Exit:
  554. **
  555. ** Filed in structure
  556. **
  557. */
  558. void
  559. FindDictVer(
  560. PDR pdr
  561. )
  562. {
  563. char *token;
  564. pdr->name[0] = 0;
  565. pdr->version[0] = 0;
  566. pdr->revision[0] = 0;
  567. DBGPRINT(("Enter FindDictVer\n"));
  568. /* lets look for a line like this: "(appledict md)" 67 0 */
  569. token = strtok(NULL,"() \""); /* this should be appledict */
  570. if (token !=NULL)
  571. {
  572. /*/
  573. ** If the token is "Appledict", then we need to parse again to get
  574. ** the real dict name.
  575. */
  576. if (!_stricmp(token, APPLEDICTNAME))
  577. token = strtok(NULL,"() \""); /* this sholud be md, or some other dict name */
  578. if (token != NULL)
  579. {
  580. strcpy(pdr->name, token);
  581. token = strtok(NULL," \"");
  582. if (token != NULL)
  583. {
  584. strcpy(pdr->version,token);
  585. token = strtok(NULL," \"");
  586. if (token != NULL)
  587. strcpy(pdr->revision,token);
  588. }
  589. }
  590. }
  591. DBGPRINT(("FindDictVer: %s:%s:%s\n", pdr->name,
  592. pdr->version, pdr->revision));
  593. } // End of FindDictVer
  594. struct commtable
  595. {
  596. PSZ commentstr;
  597. DWORD (*pfnHandle)(PJR, PSZ);
  598. PSZ parmstr;
  599. } qrytable [] =
  600. {
  601. { BPROCSETQUERY, HandleBeginProcSetQuery, NULL },
  602. { BFONTQUERY, HandleBeginFontQuery, NULL },
  603. { NULL, NULL, NULL }
  604. };
  605. /*
  606. **
  607. ** HandleBQCommentEvent()
  608. **
  609. ** Purpose: Handles Begin Query Comment Events.
  610. **
  611. ** Returns: Error Codes
  612. */
  613. DWORD
  614. HandleBQComment(
  615. PJR pjr,
  616. PBYTE ps
  617. )
  618. {
  619. PSZ token;
  620. PSZ qrytoken;
  621. PSZ endquery = EQCOMMENT;
  622. DWORD status = NO_ERROR;
  623. struct commtable *pct;
  624. DBGPRINT(("Enter HandleBQComment\n"));
  625. //
  626. // Parse the keyword
  627. //
  628. if ((token= strtok(ps," :")) != NULL)
  629. {
  630. DBGPRINT(("query: %s\n", token));
  631. // found the keyword, call the correct handler
  632. for (pct = qrytable; pct->pfnHandle != NULL; pct++)
  633. {
  634. if (!strcmp(token, pct->commentstr))
  635. {
  636. status = pct->pfnHandle(pjr,
  637. pct->parmstr == NULL ? ps : pct->parmstr);
  638. if (status == (DWORD)-1) // Special error code, handle it the default way
  639. {
  640. status = NO_ERROR;
  641. break;
  642. }
  643. return (status);
  644. }
  645. }
  646. // special case the BeginFeatureQuery comment as the item
  647. // being queried comes as the next token
  648. if (!strcmp(token, BFEATUREQUERY))
  649. {
  650. status = HandleBeginFeatureQuery(pjr, strtok(NULL," \n\x09"));
  651. return (status);
  652. }
  653. // special case the BeginQuery comment for the same reasons
  654. // as BeginFeatureQuery
  655. if (!strcmp(token, BQUERY))
  656. {
  657. qrytoken = strtok(NULL, " \n\x09");
  658. if (NULL != qrytoken)
  659. {
  660. status = HandleBeginFeatureQuery(pjr, qrytoken);
  661. return (status);
  662. }
  663. }
  664. // keyword not recognized, parse as unknown comment. Token is
  665. // of form %%?BeginXXXXQuery. Change this to the form %%?EndXXXXQuery
  666. // and pass it to HandleBeginXQuery.
  667. token += sizeof(BQCOMMENT) - sizeof(EQCOMMENT);
  668. strncpy(token, EQCOMMENT, sizeof(EQCOMMENT)-1);
  669. HandleBeginXQuery(pjr, token);
  670. }
  671. return (status);
  672. }
  673. struct featurecommtable
  674. {
  675. PSZ commentstr;
  676. DWORD (*pfnHandle)(PJR);
  677. } featureqrytable [] =
  678. {
  679. { FQLANGUAGELEVEL, HandleFeatureLanguage },
  680. { FQPSVERSION, HandleFeatureVersion },
  681. { FQBINARYOK, HandleFeatureBinary },
  682. { FQPRODUCT, HandleFeatureProduct },
  683. { FQPRODUCT1, HandleFeatureProduct },
  684. { FQRESOLUTION, HandleFeatureResolution },
  685. { FQCOLORDEVICE, HandleFeatureColor },
  686. { FQFREEVM, HandleFeatureVM },
  687. { FQTOTALVM, HandleFeatureVM },
  688. { FQSPOOLER, HandleFeatureSpooler },
  689. { NULL, NULL }
  690. };
  691. DWORD
  692. HandleBeginFeatureQuery(
  693. PJR pjr,
  694. PSZ pszQuery
  695. )
  696. {
  697. DWORD i, rc = NO_ERROR;
  698. struct featurecommtable *pct;
  699. DBGPRINT(("enter HandleBeginFeatureQuery:%s\n", pszQuery));
  700. do
  701. {
  702. //
  703. // if we have no query keyword, break;
  704. //
  705. if (NULL == pszQuery)
  706. {
  707. DBGPRINT(("NULL feature\n"));
  708. break;
  709. }
  710. // Strip out any trailing CR/LF before comparing
  711. for (i = strlen(pszQuery) - 1; ; i--)
  712. {
  713. if ((pszQuery[i] != CR) && (pszQuery[i] != LINEFEED))
  714. break;
  715. pszQuery[i] = 0;
  716. }
  717. //
  718. // walk the list of known feature queries and call the appropriate
  719. // feature query handler
  720. //
  721. for (pct = featureqrytable; pct->pfnHandle != NULL; pct++)
  722. {
  723. if (!strcmp(pszQuery, pct->commentstr))
  724. {
  725. rc = pct->pfnHandle(pjr);
  726. break;
  727. }
  728. }
  729. if (NULL == pct->pfnHandle)
  730. {
  731. DBGPRINT(("WARNING: feature query not found\n"));
  732. pjr->InProgress = QUERYDEFAULT;
  733. }
  734. } while (FALSE);
  735. return rc;
  736. }
  737. DWORD
  738. HandleFeatureLanguage(
  739. PJR pjr
  740. )
  741. {
  742. CHAR pszResponse[PSLEN];
  743. //
  744. // this routine should respond with the PostScript language level
  745. // supported by the printer. The response is in the form "<level>"
  746. // where <level> is PostScript language level - either a 1 or a 2 at
  747. // the time of this writing.
  748. //
  749. DBGPRINT(("enter HandleFeatureLanguage\n"));
  750. sprintf(pszResponse, "\"%s\"\x0a", pjr->job_pQr->pszLanguageLevel);
  751. DBGPRINT(("responding with:%s\n", pszResponse));
  752. return (TellClient(pjr, pjr->EOFRecvd, pszResponse, strlen(pszResponse)));
  753. }
  754. DWORD
  755. HandleFeatureVersion(
  756. PJR pjr
  757. )
  758. {
  759. CHAR pszResponse[PSLEN];
  760. DBGPRINT(("enter HandleFeatureVersion\n"));
  761. sprintf(pszResponse, "\"(%s) %s\"\x0a", pjr->job_pQr->Version, pjr->job_pQr->Revision);
  762. DBGPRINT(("responding with:%s\n", pszResponse));
  763. return (TellClient(pjr, pjr->EOFRecvd, pszResponse, strlen(pszResponse)));
  764. }
  765. DWORD
  766. HandleFeatureBinary(
  767. PJR pjr
  768. )
  769. {
  770. DBGPRINT(("enter HandleFeatureBinary\n"));
  771. return (TellClient(pjr,
  772. pjr->EOFRecvd,
  773. pjr->job_pQr->SupportsBinary ? "True\x0a" : "False\x0a",
  774. pjr->job_pQr->SupportsBinary ? 5: 6));
  775. }
  776. DWORD
  777. HandleFeatureProduct(
  778. PJR pjr
  779. )
  780. {
  781. CHAR pszResponse[PSLEN];
  782. DBGPRINT(("enter HandleFeatureProduct\n"));
  783. sprintf(pszResponse, "\"(%s)\"\x0a", pjr->job_pQr->Product);
  784. DBGPRINT(("responding with:%s\n", pszResponse));
  785. return (TellClient(pjr, pjr->EOFRecvd, pszResponse, strlen(pszResponse)));
  786. }
  787. DWORD
  788. HandleFeatureResolution(
  789. PJR pjr
  790. )
  791. {
  792. CHAR pszResponse[PSLEN];
  793. DBGPRINT(("enter HandleFeatureResolution\n"));
  794. sprintf(pszResponse, "%s\x0a", pjr->job_pQr->pszResolution);
  795. DBGPRINT(("responding with:%s\n", pszResponse));
  796. return (TellClient(pjr, pjr->EOFRecvd, pszResponse, strlen(pszResponse)));
  797. }
  798. DWORD
  799. HandleFeatureColor (PJR pjr)
  800. {
  801. CHAR pszResponse[PSLEN];
  802. DBGPRINT(("enter HandleFeatureColor\n"));
  803. sprintf(pszResponse, "%s\x0a", pjr->job_pQr->pszColorDevice);
  804. DBGPRINT(("responding with:%s\n", pszResponse));
  805. return (TellClient(pjr, pjr->EOFRecvd, pszResponse, strlen(pszResponse)));
  806. }
  807. DWORD
  808. HandleFeatureVM(
  809. PJR pjr
  810. )
  811. {
  812. CHAR pszResponse[PSLEN];
  813. DBGPRINT(("enter HandleFeatureVM\n"));
  814. sprintf(pszResponse, "\"%d\"\x0a", pjr->job_pQr->FreeVM);
  815. DBGPRINT(("responding with:%s\n", pszResponse));
  816. return (TellClient(pjr, pjr->EOFRecvd, pszResponse, strlen(pszResponse)));
  817. }
  818. DWORD
  819. HandleFeatureSpooler(
  820. PJR pjr
  821. )
  822. {
  823. DBGPRINT(("enter HandleFeatureSpooler\n"));
  824. return (TellClient(pjr, pjr->EOFRecvd, "1 \x0a", 3));
  825. }
  826. /*
  827. ** HandleBeginProcSetQuery()
  828. **
  829. ** Purpose: Handles BeginProcSetQuery Comment Events.
  830. **
  831. ** Returns: Number of lines that should be skipped before scanning
  832. ** for another event starts again.
  833. */
  834. DWORD
  835. HandleBeginProcSetQuery(
  836. PJR pjr,
  837. PSZ dummy
  838. )
  839. {
  840. DICT_RECORD QDict;
  841. PQR pqr = pjr->job_pQr;
  842. DWORD rc;
  843. DBGPRINT(("Enter HandleBeginProcSetQuery\n"));
  844. //
  845. // the dictionary the job is looking for determines what
  846. // client version the job originated from.
  847. //
  848. FindDictVer(&QDict);
  849. //
  850. // if we are a 5.2 client, then reset this to be a PSTODIB job
  851. //
  852. if ((_stricmp(QDict.name, MDNAME) == 0) &&
  853. (_stricmp(QDict.version, CHOOSER_52) == 0))
  854. {
  855. DBGPRINT(("a 5.2 client - we do not support him\n"));
  856. rc = ERROR_NOT_SUPPORTED;
  857. }
  858. else
  859. {
  860. // we don't cache any other dictionaries, so tell client we
  861. // don't have it
  862. rc = TellClient(pjr,
  863. pjr->EOFRecvd,
  864. PROCSETMISSINGRESPONSE,
  865. strlen(PROCSETMISSINGRESPONSE));
  866. }
  867. return rc;
  868. }
  869. /*
  870. **
  871. ** HandleBeginFontQuery()
  872. **
  873. ** Purpose: Handles BeginFontQuery Comment Events.
  874. **
  875. ** Returns: PAPWrite Error Codes
  876. **
  877. */
  878. DWORD
  879. HandleBeginFontQuery(
  880. PJR pjr,
  881. PSZ ps
  882. )
  883. {
  884. PQR pqr = pjr->job_pQr;
  885. CHAR response[PSLEN + 3];
  886. LPSTR pszResponseFont = response;
  887. DWORD cbResponseUsed = 0;
  888. LPSTR requestedFont = NULL;
  889. DWORD len= 0;
  890. DWORD rc = NO_ERROR;
  891. DBGPRINT(("Enter HandleBeginFontQuery\n"));
  892. do
  893. {
  894. // parse out the fontname list
  895. requestedFont= strtok(NULL,"\n");
  896. if (NULL == requestedFont)
  897. {
  898. rc = (DWORD)-1; // Special error code to indicate we want default handling
  899. break;
  900. }
  901. len = strlen(requestedFont);
  902. DBGPRINT(("requesting font list:%s. Length: %d\n", requestedFont, len));
  903. // Mac will request status on a list of fonts separated by spaces.
  904. // for each font we respond with /fontname:yes or /fontname:no and
  905. // bundle this response into one write
  906. requestedFont = strtok(requestedFont, " ");
  907. while (requestedFont != NULL)
  908. {
  909. DBGPRINT(("looking for font:%s\n", requestedFont));
  910. // enough space for response?
  911. if (PSLEN < (cbResponseUsed + strlen(requestedFont) + sizeof(":yes ")))
  912. {
  913. DBGPRINT(("out of space for response\n"));
  914. break;
  915. }
  916. if (IsFontAvailable(pqr, requestedFont))
  917. {
  918. sprintf(pszResponseFont, "/%s:Yes\x0a", requestedFont);
  919. }
  920. else
  921. {
  922. sprintf(pszResponseFont, "/%s:No\x0a", requestedFont);
  923. }
  924. cbResponseUsed += strlen(pszResponseFont);
  925. pszResponseFont += strlen(pszResponseFont);
  926. requestedFont = strtok(NULL, " ");
  927. }
  928. } while (FALSE);
  929. strcpy (pszResponseFont, "*\x0a");
  930. if (NO_ERROR == rc)
  931. {
  932. DBGPRINT(("responding with:%s", response));
  933. rc = TellClient(pjr, pjr->EOFRecvd, response, strlen(response));
  934. }
  935. return rc;
  936. }
  937. BOOL
  938. IsFontAvailable(
  939. PQR pqr,
  940. LPSTR pszFontName
  941. )
  942. {
  943. BOOL rc = FALSE;
  944. DWORD i;
  945. PFR fontPtr;
  946. HANDLE hFontQuery = INVALID_HANDLE_VALUE;
  947. DWORD cFonts;
  948. DWORD dummy;
  949. CHAR pszFont[PPDLEN + 1];
  950. DWORD cbFont = 0;
  951. DWORD err;
  952. DBGPRINT(("enter IsFontAvailable\n"));
  953. do
  954. {
  955. //
  956. // fonts for Postscript queues different than for PSTODIB queues
  957. //
  958. if (!wcscmp(pqr->pDataType, MACPS_DATATYPE_RAW))
  959. {
  960. //
  961. // do a PostScript queue font search
  962. //
  963. DBGPRINT(("starting font search on PostScript queue\n"));
  964. for (i = 0, fontPtr = pqr->fonts; i <= pqr->MaxFontIndex; i++, fontPtr++)
  965. {
  966. if (!_stricmp(pszFontName, fontPtr->name))
  967. {
  968. DBGPRINT(("found the font\n"));
  969. rc = TRUE;
  970. break;
  971. }
  972. }
  973. }
  974. else
  975. {
  976. //
  977. // do a PSTODIB font search
  978. //
  979. DBGPRINT(("starting font search on PSTODIB queue\n"));
  980. if (PS_QFONT_SUCCESS != (PsBeginFontQuery(&hFontQuery)))
  981. {
  982. DBGPRINT(("PsBeginFontQuery fails\n"));
  983. hFontQuery = INVALID_HANDLE_VALUE;
  984. break;
  985. }
  986. if (PS_QFONT_SUCCESS != (PsGetNumFontsAvailable(hFontQuery, &cFonts)))
  987. {
  988. DBGPRINT(("psGetNumFontsAvailable fails\n"));
  989. break;
  990. }
  991. for (i = 0; i < cFonts; i++)
  992. {
  993. cbFont = PPDLEN + 1;
  994. dummy = 0;
  995. err = PsGetFontInfo(hFontQuery, i, pszFont, &cbFont, NULL, &dummy);
  996. if (PS_QFONT_SUCCESS != err)
  997. {
  998. DBGPRINT(("PsGetFontInfo fails with %d\n", err));
  999. break;
  1000. }
  1001. if (0 == _stricmp(pszFontName, pszFont))
  1002. {
  1003. DBGPRINT(("found the font\n"));
  1004. rc = TRUE;
  1005. break;
  1006. }
  1007. }
  1008. }
  1009. } while (FALSE);
  1010. if (INVALID_HANDLE_VALUE != hFontQuery)
  1011. {
  1012. PsEndFontQuery(hFontQuery);
  1013. }
  1014. return rc;
  1015. }
  1016. /*
  1017. **
  1018. ** HandleEndPrinterQuery()
  1019. **
  1020. ** Purpose: Handles EndPrinterQuery Comment Events.
  1021. **
  1022. */
  1023. DWORD
  1024. HandleEndPrinterQuery(
  1025. PJR pjr
  1026. )
  1027. {
  1028. char reply[PSLEN+1];
  1029. PQR QPtr = pjr->job_pQr;
  1030. DBGPRINT(("Enter HandleEndPrinterQuery\n"));
  1031. /* respond with revision number, version and product */
  1032. sprintf(reply, "%s\n(%s)\n(%s)\n", QPtr->Revision, QPtr->Version, QPtr->Product);
  1033. /* respond to the client */
  1034. return (TellClient(pjr, pjr->EOFRecvd, reply, strlen(reply)));
  1035. }
  1036. /*
  1037. ** HandleBeginXQuery()
  1038. **
  1039. ** Purpose: Handles BeginQuery Comment Events.
  1040. */
  1041. void
  1042. HandleBeginXQuery(
  1043. PJR pjr,
  1044. PSZ string
  1045. )
  1046. {
  1047. DBGPRINT(("BeginQuery: %s\n", string));
  1048. strcpy(pjr->JSKeyWord, string);
  1049. pjr->InProgress=QUERYDEFAULT;
  1050. }