windows-nt/Source/XPSP1/NT/admin/netui/macprint/spooler/pspquery.c
2020-09-26 16:20:57 +08:00

1248 lines
26 KiB
C

/*
** 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 <stdio.h>
#include <string.h>
#include <search.h>
#include <windows.h>
#include <macps.h>
#include <psqfont.h>
#include <debug.h>
#include <pskey.h>
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 "<level>"
// where <level> 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;
}