/* ** Copyright(c) Microsoft Corp., 1991 * /* ** File Name: ** ** PSPQUERY.C - PostScript Parser Handlers for Query Comments ** ** General Description: ** ** These are the routines that parse and interprete the PostScript data ** stream. This interpreter looks for PostScript Document Structuring ** Comments, which are the spooler commands that are imbedded in the ** PostScript job stream. This particular file has the code that handles ** the postscript query commands */ #include #include #include #include #include #include #include #include DWORD HandleFeatureLanguage(PJR pjr); DWORD HandleFeatureVersion(PJR pjr); DWORD HandleFeatureBinary(PJR pjr); DWORD HandleFeatureProduct(PJR pjr); DWORD HandleFeatureResolution(PJR pjr); DWORD HandleFeatureColor(PJR pjr); DWORD HandleFeatureVM(PJR pjr); DWORD HandleFeatureSpooler(PJR pjr); DWORD HandleBeginFeatureQuery(PJR pjr, PSZ pszQuery); DWORD HandleEndFeatureQuery(PJR pjr, PSZ pszDefaultResponse); BOOL IsFontAvailable(PQR pqr, LPSTR pszFontName); int __cdecl compare(const void * arg1, const void * arg2); LONG GetFontListResponse(PQR pqr, LPSTR pFontBuffer, DWORD cbFontBuffer, LPDWORD pcbNeeded); /* ** HandleEndFontListQuery() ** ** Purpose: Handles the EndFontListQuery Comment ** ** Returns: Error Codes from PAPWrite Call ** */ #define DEFAULT_FONTBUF_SIZE 2048 DWORD HandleEndFontListQuery( PJR pjr ) { PQR pqr = pjr->job_pQr; LPSTR pFontBuffer = NULL; LPSTR pFontWalker = NULL; DWORD cbFontBuffer = 0; DWORD dwStatus = NO_ERROR; DWORD cbNeeded; DBGPRINT(("Enter HandleEndFontListQuery\n")); do { // // allocate a typical font buffer // if ((pFontBuffer = (LPSTR)LocalAlloc(LPTR, DEFAULT_FONTBUF_SIZE)) == NULL) { dwStatus = GetLastError(); DBGPRINT(("ERROR: unable to allocate font buffer\n")); break; } cbFontBuffer = DEFAULT_FONTBUF_SIZE; // // get the fontlist response // if ((dwStatus = GetFontListResponse(pqr, pFontBuffer, cbFontBuffer, &cbNeeded)) != ERROR_SUCCESS) { // // if buffer too small, reallocate and try again // if (dwStatus == ERROR_MORE_DATA) { LocalFree(pFontBuffer); if ((pFontBuffer = (LPSTR)LocalAlloc(LPTR, cbNeeded)) == NULL) { dwStatus = GetLastError(); DBGPRINT(("ERROR: unable to reallocate font buffer\n")); break; } cbFontBuffer = cbNeeded; if ((dwStatus = GetFontListResponse(pqr, pFontBuffer, cbFontBuffer, &cbNeeded)) != ERROR_SUCCESS) { DBGPRINT(("ERROR: unable to get font list response\n")); break; } } } // // send response to client (in single font name per write) // NOTE: While the Apple LaserWriter driver gets fonts from // the printer in 512 byte packets that are packed with multiple // font names, the PageMaker driver expects fonts to come in // a single font per write scheme. So we lose the work that builds // a font response like the Mac LaserWriter driver by sending // the fonts as PageMaker expects them (which works for both // drivers) // DBGPRINT(("writing fontlist:\n%s", pFontBuffer)); pFontWalker = pFontBuffer; cbFontBuffer = 0; while (*pFontWalker != '*') { cbFontBuffer = strlen(pFontWalker); if ((dwStatus = TellClient(pjr, FALSE, pFontWalker, cbFontBuffer)) != NO_ERROR) { // // error sending data to client // DBGPRINT(("ERROR: unable to send font to client\n")); break; } pFontWalker += (cbFontBuffer + 1); } // // do not fail if a send of a font fails. If we can get the // termination font out, the Mac will just download any fonts // it needs and the job will print - albeit slowly. // if ((dwStatus = TellClient(pjr, pjr->EOFRecvd, pFontWalker, strlen(pFontWalker))) != NO_ERROR) { DBGPRINT(("ERROR: unable to send terminating font to client\n")); break; } } while (FALSE); if (pFontBuffer != NULL) { LocalFree (pFontBuffer); } return dwStatus; } ////////////////////////////////////////////////////////////////////////////// // // GetFontListResponse - formats a fontlist buffer to send to a Mac // // Based on the queue type (Postscript or non), a fontlist is generated // and placed in the supplied buffer. The font list is an ordered list // of fonts separated by '\n\0' with a terminating font of '*\n\0'. // // if the buffer is too small, this routine returns ERROR_MORE_DATA. // if for some other reason the list cannot be generated, the return // value is ERROR_INVALID_PARAMETER. // if the function successfully returns a font list, the return value // is ERROR_SUCCESS. // ////////////////////////////////////////////////////////////////////////////// LONG GetFontListResponse( PQR pqr, LPSTR pFontBuffer, DWORD cbFontBuffer, LPDWORD pcbNeeded ) { LONG lReturn = ERROR_SUCCESS; HANDLE hFontQuery = INVALID_HANDLE_VALUE; DWORD cFonts; DWORD dwIndex; BOOL boolPSQueue; LPSTR *apszFontNames = NULL; LPSTR pTempBuffer = NULL; DWORD cbTempBuffer = cbFontBuffer; DWORD cbFontFileName; LPSTR pFont; DWORD cbFont; DWORD rc; DBGPRINT(("enter GetFontListResponse(cbBuffer:%d, cbNeeded:%d\n", cbFontBuffer, *pcbNeeded)); do { // // what kind of queue are we // if (wcscmp(pqr->pDataType, MACPS_DATATYPE_RAW)) { // // we are PSTODIB // boolPSQueue = FALSE; } else { // // we are Postscript // boolPSQueue = TRUE; } // // allocate an array of fontname pointers. // if (boolPSQueue) { cFonts = pqr->MaxFontIndex + 1; DBGPRINT(("cFonts=%d\n", cFonts)); apszFontNames = (LPSTR*)LocalAlloc(LPTR, cFonts * sizeof(LPSTR)); } else { // // for PSTODIB we will need a temp buffer for the fonts as well // if ((pTempBuffer = (LPSTR)LocalAlloc(LPTR, cbFontBuffer)) == NULL) { lReturn = ERROR_INVALID_PARAMETER; DBGPRINT(("ERROR: unable to allocate temp font buffer\n")); break; } if ((rc = PsBeginFontQuery(&hFontQuery)) != PS_QFONT_SUCCESS) { DBGPRINT(("ERROR: PsBeginFontQuery returns %d\n", rc)); lReturn = ERROR_INVALID_PARAMETER; break; } if ((rc = PsGetNumFontsAvailable(hFontQuery, &cFonts)) != PS_QFONT_SUCCESS) { DBGPRINT(("ERROR: PsGetNumFontsAvailable returns %d\n", rc)); lReturn = ERROR_INVALID_PARAMETER; break; } apszFontNames = (LPSTR*)LocalAlloc(LPTR, cFonts * sizeof(LPSTR)); } if (apszFontNames == NULL) { DBGPRINT(("ERROR: cannot allocate font list array\n")); lReturn = ERROR_INVALID_PARAMETER; break; } // // fill the array of fontname pointers // *pcbNeeded = 3; pFont = pTempBuffer; for (dwIndex = 0; dwIndex < cFonts; dwIndex++) { if (boolPSQueue) { apszFontNames[dwIndex] = pqr->fonts[dwIndex].name; *pcbNeeded += (strlen(pqr->fonts[dwIndex].name)+2); DBGPRINT(("adding font:%s, cbNeeded:%d, index:%d\n", pqr->fonts[dwIndex].name, *pcbNeeded, dwIndex)); } else { // // pstodib - add the font to the temp buffer // and set the pointer // cbFont = cbTempBuffer = cbFontBuffer; if ((rc = PsGetFontInfo(hFontQuery, dwIndex, pFont, &cbFont, NULL, &cbFontFileName)) != PS_QFONT_SUCCESS) { // // if we are out of memory, continue enumeration // to get size needed, but set return to ERROR_MORE_DATA // if (rc == PS_QFONT_ERROR_FONTNAMEBUFF_TOSMALL) { DBGPRINT(("user buffer too small for font query\n")); lReturn = ERROR_MORE_DATA; pFont = pTempBuffer; cbFont = cbTempBuffer = cbFontBuffer; if ((rc = PsGetFontInfo(hFontQuery, dwIndex, pFont, &cbFont, NULL, &cbFontFileName)) != PS_QFONT_SUCCESS) { // // we be hosed. Fail. // lReturn = ERROR_INVALID_PARAMETER; DBGPRINT(("ERROR: cannot continue PSTODIB font enumeration\n")); break; } else { *pcbNeeded += cbFont + 2; } } } else { *pcbNeeded += cbFont + 2; } apszFontNames[dwIndex] = pFont; cbTempBuffer -= cbFont; pFont += cbFont; cbFont = cbTempBuffer; } } if (*pcbNeeded > cbFontBuffer) { lReturn = ERROR_MORE_DATA; break; } // // build the fontlistresponse // cbFontBuffer = 0; for (dwIndex = 0; dwIndex < cFonts; dwIndex++) { cbFont = sprintf(pFontBuffer, "%s\n", apszFontNames[dwIndex]) + 1; pFontBuffer += cbFont; cbFontBuffer += cbFont; } memcpy (pFontBuffer, "*\n", 3); } while (FALSE); if (apszFontNames != NULL) { LocalFree(apszFontNames); } if (pTempBuffer != NULL) { LocalFree(pTempBuffer); } if (hFontQuery != INVALID_HANDLE_VALUE) { PsEndFontQuery(hFontQuery); } return (lReturn); } int __cdecl compare(const void* arg1, const void* arg2) { return _stricmp(* (char **)arg1, * (char **)arg2); } // // For Postscript printers, the font enumeration technique is complex. // EnumFontFamilies expects the programmer to specify a callback function // that will be called either once for every font family, or once for // every font face in a family. To get all fonts available, I use // EnumFontFamilies twice. The first enumeration, I call EnumFontFamilies // with a null value for the family name. This causes the callback // function to be called once for each family name installed. This // callback function then does an enumeration on that family name to // get the specific face names in the family. This second layer of // enumeration specifies yet another callback function that returns // the font name to the Macintosh client. // void EnumeratePostScriptFonts( PJR pjr ) { PQR pqr = pjr->job_pQr; DBGPRINT(("ENTER EnumeratePostScriptFonts\n")); if (pjr->hicFontFamily != NULL) { // // enumerate the font families // EnumFontFamilies(pjr->hicFontFamily, NULL, (FONTENUMPROC)FamilyEnumCallback, (LPARAM)pjr); } } int CALLBACK FamilyEnumCallback( LPENUMLOGFONT lpelf, LPNEWTEXTMETRIC pntm, int iFontType, LPARAM lParam ) { PQR pqr = ((PJR)lParam)->job_pQr; PJR pjr = (PJR)lParam; DBGPRINT(("Enter FamilyEnumCallback for family %ws\n", lpelf->elfFullName)); // // enumerate the fonts in this family // if (iFontType & DEVICE_FONTTYPE) { DBGPRINT(("enumerating face names\n")); EnumFontFamilies(pjr->hicFontFace, lpelf->elfFullName, (FONTENUMPROC)FontEnumCallback, lParam); } else { DBGPRINT(("this family is not a DEVICE_FONTTYPE\n")); } return 1; } int CALLBACK FontEnumCallback( LPENUMLOGFONT lpelf, LPNEWTEXTMETRIC pntm, int iFontType, LPARAM lParam ) { DWORD PAPStatus; PJR pjr = (PJR)lParam; BYTE pszFontName[255]; DBGPRINT(("Enter FontEnumCallback\n")); // // return this font name to the client // if (iFontType & DEVICE_FONTTYPE) { CharToOem(lpelf->elfFullName, pszFontName); if (PAPStatus = TellClient(pjr, FALSE, pszFontName, strlen(pszFontName))) { DBGPRINT(("ERROR: TellClient returns %d\n", PAPStatus)); } } else { DBGPRINT(("%ws is not a DEVICE_FONTTYPE\n", lpelf->elfFullName)); } return 1; } /* ** HandleEndQuery() ** ** Purpose: PageMaker will send a query that goes like this: ** ** %%BeginQuery ** ... ** %%EndQuery (spooler) ** ** In order to allow pagemaker to print TIFF formated images ** properly, we should respond to this query with "printer". ** ** Returns: Error Codes from PAPWrite Call ** */ DWORD HandleEndQuery( PJR pjr, PBYTE ps ) { char *token; CHAR pszResponse[PSLEN+1]; DBGPRINT(("Enter HandleEndQuery\n")); token = strtok(NULL,"\n"); if (token == NULL) { return NO_ERROR; } /* strip off any leading blanks in the default */ token += strspn(token, " "); // // respond with the default // sprintf(pszResponse, "%s\x0a", token); return (TellClient(pjr, pjr->EOFRecvd, pszResponse, strlen(pszResponse))); } /*************************************************************************** ** FinishDefaultQuery() ** ** Purpose: Scans for the PostScript command specified in psKeyWord. It ** then will respond with the default response specified on that ** line. It will set the InProgress field in the JOB_RECORD to ** an InProgress value if the default is not found in this buffer. ** ** Returns: Error Codes from PAPWrite Call ** ***************************************************************************/ DWORD FinishDefaultQuery( PJR pjr, PBYTE ps ) { char * token; char buf[PSLEN+1]; DBGPRINT(("FinishDefaultQuery: %s\n", ps)); if (NULL == (token = strtok (ps," :"))) { return (NO_ERROR); } pjr->InProgress= NOTHING; /* First We Should Handle the cases that do not use the default response */ if (!_stricmp(token, EFEATUREQUERY)) return (HandleEndFeatureQuery(pjr, strtok (NULL," \n"))); if (!_stricmp(token, EFONTLISTQ)) return( HandleEndFontListQuery (pjr)); if (!_stricmp(token, EQUERY)) return( HandleEndQuery (pjr, ps)); if (!_stricmp(token, EPRINTERQUERY)) return( HandleEndPrinterQuery(pjr)); if (!_stricmp(token, EVMSTATUS)) { sprintf(buf, "%ld", pjr->job_pQr->FreeVM); return (TellClient(pjr, pjr->EOFRecvd, buf , strlen(buf))); } if ((token = strtok(NULL,"\n")) == NULL) { return (NO_ERROR); } /* strip off any leading blanks in the default. Append a LF */ token += strspn(token, " "); sprintf(buf, "%s\x0a", token); return (TellClient(pjr, pjr->EOFRecvd, buf, strlen(buf))); } DWORD HandleEndFeatureQuery( PJR pjr, PSZ pszDefaultResponse) { DWORD rc = NO_ERROR; CHAR pszResponse[PSLEN]; DBGPRINT(("enter HandleEndFeatureQuery\n")); do { // // return the default response if there is one // if (NULL != pszDefaultResponse) { sprintf(pszResponse, "%s\x0a", pszDefaultResponse); DBGPRINT(("responding with default response from query: %s\n", pszResponse)); rc = TellClient(pjr, pjr->EOFRecvd, pszResponse, strlen(pszResponse)); break; } DBGPRINT(("responding with Unknown\n")); rc = TellClient(pjr, pjr->EOFRecvd, DEFAULTRESPONSE, strlen(DEFAULTRESPONSE)); } while (FALSE); return rc; } /* ** Routine: ** ParseDict ** ** Purpse: ** ** This routine will take a given QueryProcSet, BeginProcSet, or ** IncludeProcSet comment and determine what dictionary is being ** referenced. ** ** Entry: ** ** Address of a record to fill in with the Dictionary information. ** ** Exit: ** ** Filed in structure ** */ void FindDictVer( PDR pdr ) { char *token; pdr->name[0] = 0; pdr->version[0] = 0; pdr->revision[0] = 0; DBGPRINT(("Enter FindDictVer\n")); /* lets look for a line like this: "(appledict md)" 67 0 */ token = strtok(NULL,"() \""); /* this should be appledict */ if (token !=NULL) { /*/ ** If the token is "Appledict", then we need to parse again to get ** the real dict name. */ if (!_stricmp(token, APPLEDICTNAME)) token = strtok(NULL,"() \""); /* this sholud be md, or some other dict name */ if (token != NULL) { strcpy(pdr->name, token); token = strtok(NULL," \""); if (token != NULL) { strcpy(pdr->version,token); token = strtok(NULL," \""); if (token != NULL) strcpy(pdr->revision,token); } } } DBGPRINT(("FindDictVer: %s:%s:%s\n", pdr->name, pdr->version, pdr->revision)); } // End of FindDictVer struct commtable { PSZ commentstr; DWORD (*pfnHandle)(PJR, PSZ); PSZ parmstr; } qrytable [] = { { BPROCSETQUERY, HandleBeginProcSetQuery, NULL }, { BFONTQUERY, HandleBeginFontQuery, NULL }, { NULL, NULL, NULL } }; /* ** ** HandleBQCommentEvent() ** ** Purpose: Handles Begin Query Comment Events. ** ** Returns: Error Codes */ DWORD HandleBQComment( PJR pjr, PBYTE ps ) { PSZ token; PSZ qrytoken; PSZ endquery = EQCOMMENT; DWORD status = NO_ERROR; struct commtable *pct; DBGPRINT(("Enter HandleBQComment\n")); // // Parse the keyword // if ((token= strtok(ps," :")) != NULL) { DBGPRINT(("query: %s\n", token)); // found the keyword, call the correct handler for (pct = qrytable; pct->pfnHandle != NULL; pct++) { if (!strcmp(token, pct->commentstr)) { status = pct->pfnHandle(pjr, pct->parmstr == NULL ? ps : pct->parmstr); if (status == (DWORD)-1) // Special error code, handle it the default way { status = NO_ERROR; break; } return (status); } } // special case the BeginFeatureQuery comment as the item // being queried comes as the next token if (!strcmp(token, BFEATUREQUERY)) { status = HandleBeginFeatureQuery(pjr, strtok(NULL," \n\x09")); return (status); } // special case the BeginQuery comment for the same reasons // as BeginFeatureQuery if (!strcmp(token, BQUERY)) { qrytoken = strtok(NULL, " \n\x09"); if (NULL != qrytoken) { status = HandleBeginFeatureQuery(pjr, qrytoken); return (status); } } // keyword not recognized, parse as unknown comment. Token is // of form %%?BeginXXXXQuery. Change this to the form %%?EndXXXXQuery // and pass it to HandleBeginXQuery. token += sizeof(BQCOMMENT) - sizeof(EQCOMMENT); strncpy(token, EQCOMMENT, sizeof(EQCOMMENT)-1); HandleBeginXQuery(pjr, token); } return (status); } struct featurecommtable { PSZ commentstr; DWORD (*pfnHandle)(PJR); } featureqrytable [] = { { FQLANGUAGELEVEL, HandleFeatureLanguage }, { FQPSVERSION, HandleFeatureVersion }, { FQBINARYOK, HandleFeatureBinary }, { FQPRODUCT, HandleFeatureProduct }, { FQPRODUCT1, HandleFeatureProduct }, { FQRESOLUTION, HandleFeatureResolution }, { FQCOLORDEVICE, HandleFeatureColor }, { FQFREEVM, HandleFeatureVM }, { FQTOTALVM, HandleFeatureVM }, { FQSPOOLER, HandleFeatureSpooler }, { NULL, NULL } }; DWORD HandleBeginFeatureQuery( PJR pjr, PSZ pszQuery ) { DWORD i, rc = NO_ERROR; struct featurecommtable *pct; DBGPRINT(("enter HandleBeginFeatureQuery:%s\n", pszQuery)); do { // // if we have no query keyword, break; // if (NULL == pszQuery) { DBGPRINT(("NULL feature\n")); break; } // Strip out any trailing CR/LF before comparing for (i = strlen(pszQuery) - 1; ; i--) { if ((pszQuery[i] != CR) && (pszQuery[i] != LINEFEED)) break; pszQuery[i] = 0; } // // walk the list of known feature queries and call the appropriate // feature query handler // for (pct = featureqrytable; pct->pfnHandle != NULL; pct++) { if (!strcmp(pszQuery, pct->commentstr)) { rc = pct->pfnHandle(pjr); break; } } if (NULL == pct->pfnHandle) { DBGPRINT(("WARNING: feature query not found\n")); pjr->InProgress = QUERYDEFAULT; } } while (FALSE); return rc; } DWORD HandleFeatureLanguage( PJR pjr ) { CHAR pszResponse[PSLEN]; // // this routine should respond with the PostScript language level // supported by the printer. The response is in the form "" // where is PostScript language level - either a 1 or a 2 at // the time of this writing. // DBGPRINT(("enter HandleFeatureLanguage\n")); sprintf(pszResponse, "\"%s\"\x0a", pjr->job_pQr->pszLanguageLevel); DBGPRINT(("responding with:%s\n", pszResponse)); return (TellClient(pjr, pjr->EOFRecvd, pszResponse, strlen(pszResponse))); } DWORD HandleFeatureVersion( PJR pjr ) { CHAR pszResponse[PSLEN]; DBGPRINT(("enter HandleFeatureVersion\n")); sprintf(pszResponse, "\"(%s) %s\"\x0a", pjr->job_pQr->Version, pjr->job_pQr->Revision); DBGPRINT(("responding with:%s\n", pszResponse)); return (TellClient(pjr, pjr->EOFRecvd, pszResponse, strlen(pszResponse))); } DWORD HandleFeatureBinary( PJR pjr ) { DBGPRINT(("enter HandleFeatureBinary\n")); return (TellClient(pjr, pjr->EOFRecvd, pjr->job_pQr->SupportsBinary ? "True\x0a" : "False\x0a", pjr->job_pQr->SupportsBinary ? 5: 6)); } DWORD HandleFeatureProduct( PJR pjr ) { CHAR pszResponse[PSLEN]; DBGPRINT(("enter HandleFeatureProduct\n")); sprintf(pszResponse, "\"(%s)\"\x0a", pjr->job_pQr->Product); DBGPRINT(("responding with:%s\n", pszResponse)); return (TellClient(pjr, pjr->EOFRecvd, pszResponse, strlen(pszResponse))); } DWORD HandleFeatureResolution( PJR pjr ) { CHAR pszResponse[PSLEN]; DBGPRINT(("enter HandleFeatureResolution\n")); sprintf(pszResponse, "%s\x0a", pjr->job_pQr->pszResolution); DBGPRINT(("responding with:%s\n", pszResponse)); return (TellClient(pjr, pjr->EOFRecvd, pszResponse, strlen(pszResponse))); } DWORD HandleFeatureColor (PJR pjr) { CHAR pszResponse[PSLEN]; DBGPRINT(("enter HandleFeatureColor\n")); sprintf(pszResponse, "%s\x0a", pjr->job_pQr->pszColorDevice); DBGPRINT(("responding with:%s\n", pszResponse)); return (TellClient(pjr, pjr->EOFRecvd, pszResponse, strlen(pszResponse))); } DWORD HandleFeatureVM( PJR pjr ) { CHAR pszResponse[PSLEN]; DBGPRINT(("enter HandleFeatureVM\n")); sprintf(pszResponse, "\"%d\"\x0a", pjr->job_pQr->FreeVM); DBGPRINT(("responding with:%s\n", pszResponse)); return (TellClient(pjr, pjr->EOFRecvd, pszResponse, strlen(pszResponse))); } DWORD HandleFeatureSpooler( PJR pjr ) { DBGPRINT(("enter HandleFeatureSpooler\n")); return (TellClient(pjr, pjr->EOFRecvd, "1 \x0a", 3)); } /* ** HandleBeginProcSetQuery() ** ** Purpose: Handles BeginProcSetQuery Comment Events. ** ** Returns: Number of lines that should be skipped before scanning ** for another event starts again. */ DWORD HandleBeginProcSetQuery( PJR pjr, PSZ dummy ) { DICT_RECORD QDict; PQR pqr = pjr->job_pQr; DWORD rc; DBGPRINT(("Enter HandleBeginProcSetQuery\n")); // // the dictionary the job is looking for determines what // client version the job originated from. // FindDictVer(&QDict); // // if we are a 5.2 client, then reset this to be a PSTODIB job // if ((_stricmp(QDict.name, MDNAME) == 0) && (_stricmp(QDict.version, CHOOSER_52) == 0)) { DBGPRINT(("a 5.2 client - we do not support him\n")); rc = ERROR_NOT_SUPPORTED; } else { // we don't cache any other dictionaries, so tell client we // don't have it rc = TellClient(pjr, pjr->EOFRecvd, PROCSETMISSINGRESPONSE, strlen(PROCSETMISSINGRESPONSE)); } return rc; } /* ** ** HandleBeginFontQuery() ** ** Purpose: Handles BeginFontQuery Comment Events. ** ** Returns: PAPWrite Error Codes ** */ DWORD HandleBeginFontQuery( PJR pjr, PSZ ps ) { PQR pqr = pjr->job_pQr; CHAR response[PSLEN + 3]; LPSTR pszResponseFont = response; DWORD cbResponseUsed = 0; LPSTR requestedFont = NULL; DWORD len= 0; DWORD rc = NO_ERROR; DBGPRINT(("Enter HandleBeginFontQuery\n")); do { // parse out the fontname list requestedFont= strtok(NULL,"\n"); if (NULL == requestedFont) { rc = (DWORD)-1; // Special error code to indicate we want default handling break; } len = strlen(requestedFont); DBGPRINT(("requesting font list:%s. Length: %d\n", requestedFont, len)); // Mac will request status on a list of fonts separated by spaces. // for each font we respond with /fontname:yes or /fontname:no and // bundle this response into one write requestedFont = strtok(requestedFont, " "); while (requestedFont != NULL) { DBGPRINT(("looking for font:%s\n", requestedFont)); // enough space for response? if (PSLEN < (cbResponseUsed + strlen(requestedFont) + sizeof(":yes "))) { DBGPRINT(("out of space for response\n")); break; } if (IsFontAvailable(pqr, requestedFont)) { sprintf(pszResponseFont, "/%s:Yes\x0a", requestedFont); } else { sprintf(pszResponseFont, "/%s:No\x0a", requestedFont); } cbResponseUsed += strlen(pszResponseFont); pszResponseFont += strlen(pszResponseFont); requestedFont = strtok(NULL, " "); } } while (FALSE); strcpy (pszResponseFont, "*\x0a"); if (NO_ERROR == rc) { DBGPRINT(("responding with:%s", response)); rc = TellClient(pjr, pjr->EOFRecvd, response, strlen(response)); } return rc; } BOOL IsFontAvailable( PQR pqr, LPSTR pszFontName ) { BOOL rc = FALSE; DWORD i; PFR fontPtr; HANDLE hFontQuery = INVALID_HANDLE_VALUE; DWORD cFonts; DWORD dummy; CHAR pszFont[PPDLEN + 1]; DWORD cbFont = 0; DWORD err; DBGPRINT(("enter IsFontAvailable\n")); do { // // fonts for Postscript queues different than for PSTODIB queues // if (!wcscmp(pqr->pDataType, MACPS_DATATYPE_RAW)) { // // do a PostScript queue font search // DBGPRINT(("starting font search on PostScript queue\n")); for (i = 0, fontPtr = pqr->fonts; i <= pqr->MaxFontIndex; i++, fontPtr++) { if (!_stricmp(pszFontName, fontPtr->name)) { DBGPRINT(("found the font\n")); rc = TRUE; break; } } } else { // // do a PSTODIB font search // DBGPRINT(("starting font search on PSTODIB queue\n")); if (PS_QFONT_SUCCESS != (PsBeginFontQuery(&hFontQuery))) { DBGPRINT(("PsBeginFontQuery fails\n")); hFontQuery = INVALID_HANDLE_VALUE; break; } if (PS_QFONT_SUCCESS != (PsGetNumFontsAvailable(hFontQuery, &cFonts))) { DBGPRINT(("psGetNumFontsAvailable fails\n")); break; } for (i = 0; i < cFonts; i++) { cbFont = PPDLEN + 1; dummy = 0; err = PsGetFontInfo(hFontQuery, i, pszFont, &cbFont, NULL, &dummy); if (PS_QFONT_SUCCESS != err) { DBGPRINT(("PsGetFontInfo fails with %d\n", err)); break; } if (0 == _stricmp(pszFontName, pszFont)) { DBGPRINT(("found the font\n")); rc = TRUE; break; } } } } while (FALSE); if (INVALID_HANDLE_VALUE != hFontQuery) { PsEndFontQuery(hFontQuery); } return rc; } /* ** ** HandleEndPrinterQuery() ** ** Purpose: Handles EndPrinterQuery Comment Events. ** */ DWORD HandleEndPrinterQuery( PJR pjr ) { char reply[PSLEN+1]; PQR QPtr = pjr->job_pQr; DBGPRINT(("Enter HandleEndPrinterQuery\n")); /* respond with revision number, version and product */ sprintf(reply, "%s\n(%s)\n(%s)\n", QPtr->Revision, QPtr->Version, QPtr->Product); /* respond to the client */ return (TellClient(pjr, pjr->EOFRecvd, reply, strlen(reply))); } /* ** HandleBeginXQuery() ** ** Purpose: Handles BeginQuery Comment Events. */ void HandleBeginXQuery( PJR pjr, PSZ string ) { DBGPRINT(("BeginQuery: %s\n", string)); strcpy(pjr->JSKeyWord, string); pjr->InProgress=QUERYDEFAULT; }