|
|
////////////////////////////////////////////////////////////////////////////////
//
// MacPrint - Windows NT Print Server for Macintosh Clients
// Copyright (c) Microsoft Corp., 1991, 1992, 1993
//
// psp.c - Macintosh Print Service Postscript Parsing Routines
//
// Author: Frank D. Byrum
// adapted from MacPrint from LAN Manager Services for Macintosh
//
// DESCRIPTION:
// This module provides the routines to parse the Adobe DSC 2.0
// comments in a PostScript stream.
//
////////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <windows.h>
#include <macpsmsg.h>
#include <macps.h>
#include <pskey.h>
#include <debug.h>
// function prototypes
DWORD HandleTitle(PJR pjr); DWORD HandleBeginExitServer(PJR pjr); DWORD HandleCreationDate(PJR pjr); DWORD HandleCreator(PJR pjr); DWORD HandleEndExitServer(PJR pjr); DWORD HandleEOF(PJR pjr); DWORD HandleFor(PJR pjr); DWORD HandleLogin(PJR pjr); DWORD HandleBeginProcSet(PJR pjr); DWORD HandleEndProcSet(PJR pjr); DWORD HandleIncludeProcSet(PJR pjr); DWORD HandleComment(PJR, PBYTE); DWORD HandleBeginBinary(PJR pjr); DWORD HandleEndBinary(PJR pjr); DWORD HandlePages(PJR pjr); void HandleJobComment (PJR, PBYTE); PFR ReAllocateFontList (PFR pfrOld, DWORD cOldFonts, DWORD cNewFonts);
#if DBG_SPOOL_LOCALLY
HANDLE DbgSpoolFile = INVALID_HANDLE_VALUE; #endif
char * deffonts[DEFAULTFONTS] = { FONT00, FONT01, FONT02, FONT03, FONT04, FONT05, FONT06, FONT07, FONT08, FONT09, FONT10, FONT11, FONT12, FONT13, FONT14, FONT15, FONT16, FONT17, FONT18, FONT19, FONT20, FONT21, FONT22, FONT23, FONT24, FONT25, FONT26, FONT27, FONT28, FONT29, FONT30, FONT31, FONT32, FONT33, FONT34 };
////////////////////////////////////////////////////////////////////////////////
//
// SetDefaultPPDInfo() - Initialize to LaserWriter Plus configuration
//
// DESCRIPTION:
// This routine is used to set the default parameters of our
// printer to LaserWriter Plus characteristics. This is used
// in the event there is no PPD file associated with the given
// NT Printer Object (as in the case of non Postscript printers)
//
// returns true if queue structure initialized OK.
//
////////////////////////////////////////////////////////////////////////////////
BOOLEAN SetDefaultPPDInfo( PQR pqr ) { DWORD i;
//
// initialize Postscript keywords
//
strcpy(pqr->LanguageVersion, ENGLISH); strcpy(pqr->Product, DEFAULTPRODUCTRESPONSE); strcpy(pqr->Version, DEFAULTPSVERSION); strcpy(pqr->Revision, DEFAULTPSREVISION); strcpy(pqr->DeviceNickName, UNKNOWNPRINTER); strcpy(pqr->pszColorDevice, COLORDEVICEDEFAULT); strcpy(pqr->pszResolution, RESOLUTIONDEFAULT); strcpy(pqr->pszLanguageLevel, DEFAULTLANGUAGELEVEL); pqr->FreeVM = VMDEFAULT; pqr->SupportsBinary = FALSE;
pqr->fonts = NULL;
return (TRUE); }
////////////////////////////////////////////////////////////////////////////////
//
// SetDefaultFonts() - Initialize to LaserWriter Plus configuration
//
// DESCRIPTION:
// This routine is used to set the default parameters of our
// printer to LaserWriter Plus characteristics. This is used
// in the event there is no PPD file associated with the given
// NT Printer Object (as in the case of non Postscript printers)
//
// returns true if queue structure initialized OK.
//
////////////////////////////////////////////////////////////////////////////////
BOOLEAN SetDefaultFonts( PQR pqr ) { DWORD i;
if (pqr->fonts != NULL) { DBGPRINT(("ERROR: pqr->fonts is nonnull!\n")); }
pqr->fonts = (PFR)LocalAlloc(LPTR, DEFAULTFONTS * sizeof (FONT_RECORD)); if (pqr->fonts == NULL) { DBGPRINT(("ERROR: unable to allocate font data\n")); ReportEvent( hEventLog, EVENTLOG_ERROR_TYPE, EVENT_CATEGORY_INTERNAL, EVENT_SERVICE_OUT_OF_MEMORY, NULL, 0, 0, NULL, NULL); return (FALSE); }
//
// copy font names
//
for (i = 0; i < DEFAULTFONTS; i++) { strcpy(pqr->fonts[i].name, deffonts[i]); } pqr->MaxFontIndex = DEFAULTFONTS-1;
return (TRUE); }
////////////////////////////////////////////////////////////////////////////////
//
// GetPPDInfo() - Initialize to LaserWriter Plus configuration
//
// DESCRIPTION:
// This routine is used to set the parameters of our
// printer to the characteristics specified in the PPD
// file for the printer.
//
// returns true if queue structure initialized OK.
//
////////////////////////////////////////////////////////////////////////////////
BOOLEAN GetPPDInfo( PQR pqr ) { FILE * ppdfile = NULL; char * result = NULL; char * token = NULL; char line[PSLEN]; PFR fontPtr=NULL; USHORT MaxFonts = 100; USHORT fontindex = 0; LPDRIVER_INFO_2 pdiThis = NULL; DWORD cbpdiThis = sizeof(DRIVER_INFO_2) + 256; LPSTR pszPPDFile = NULL; BOOLEAN ReturnStatus = TRUE; HANDLE hPrinter = INVALID_HANDLE_VALUE; int toklen;
do { // get the path of the ppdfile
if (!OpenPrinter(pqr->pPrinterName, &hPrinter, NULL)) { hPrinter = INVALID_HANDLE_VALUE; DBGPRINT(("ERROR: unable to get printer handle, error=%d\n", GetLastError())); ReturnStatus = FALSE; break; }
pdiThis = (LPDRIVER_INFO_2) LocalAlloc(LPTR, cbpdiThis); if (pdiThis == NULL) { DBGPRINT(("ERROR: unable to allocate new driverinfo buffer\n")); ReturnStatus = FALSE; break; } if (!GetPrinterDriver(hPrinter, NULL, 2, (LPBYTE) pdiThis, cbpdiThis, &cbpdiThis)) { if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { DBGPRINT(("ERROR: unable to get printer driver info\n")); ReturnStatus = FALSE; break; }
LocalFree(pdiThis); pdiThis = (LPDRIVER_INFO_2) LocalAlloc(LPTR, cbpdiThis); if (pdiThis == NULL) { DBGPRINT(("ERROR: unable to allocte new driverinfo buffer\n")); ReturnStatus = FALSE; break; }
if (!GetPrinterDriver(hPrinter, NULL, 2, (LPBYTE) pdiThis, cbpdiThis, &cbpdiThis)) { DBGPRINT(("ERROR: unable to get printer driver info\n")); ReturnStatus = FALSE; break; } } #ifdef DBCS
pszPPDFile = (LPSTR)LocalAlloc(LPTR, (wcslen(pdiThis->pDataFile)+1) * sizeof(WCHAR)); #else
pszPPDFile = (LPSTR)LocalAlloc(LPTR, wcslen(pdiThis->pDataFile)+1); #endif
DBGPRINT(("pDataFile name length = %d\n", wcslen(pdiThis->pDataFile))); if (pszPPDFile == NULL) { DBGPRINT(("out of memory for pszPPDFile\n")); ReturnStatus = FALSE; break; } CharToOem(pdiThis->pDataFile, pszPPDFile); DBGPRINT(("pDataFile = %ws, pszPPDFile = %s\n", pdiThis->pDataFile, pszPPDFile));
if ((ppdfile = fopen(pszPPDFile, "rt")) == NULL) { DBGPRINT(("File open error %s", pszPPDFile)); ReturnStatus = FALSE; break; }
/*
* Allocate a buffer for fonts. We don't know yet what size we need. * We make a guess and increase the size as we go. The incremental * size is 10 fonts. We start off with 100. We shrink the segment size * to the final size. */ fontPtr = (PFR) LocalAlloc (LPTR, sizeof(FONT_RECORD)*MaxFonts); if (fontPtr == NULL) { DBGPRINT(("ERROR: cannot allocate font list buffer, error=%d\n", GetLastError())); ReturnStatus = FALSE; break; }
pqr->SupportsBinary = FALSE; // Default
while (result = fgets(line, PSLEN, ppdfile)) { if (line[0] != ASTERISK || (token= strtok(line, " \011")) == NULL) continue;
// PPD Font Entry?
if (!_stricmp(line, ppdFONT)) { /* This should be the fontname */ if ((token= strtok(NULL, " \011:")) != NULL) { if (strlen(token) <= FONTNAMELEN) { strcpy(fontPtr[fontindex].name, token); DBGPRINT(("Font: %s\n", token)); fontindex++; if (fontindex >= MaxFonts) { fontPtr = ReAllocateFontList (fontPtr, MaxFonts, MaxFonts + 10); if (fontPtr == NULL) { DBGPRINT(("ERROR: unable to grow font buffer, error=%d\n", GetLastError())); ReturnStatus = FALSE; break; } MaxFonts += 10; } } else DBGPRINT(("Fontname > PPDLEN ???\n")); } } else if (!_stricmp(token, ppdPSVERSION)) { // PPD Postscript Version Entry?
/* Get the PostScript version */ token= strtok(NULL, "\011()\""); /* This should be the version */ if (token != NULL) { toklen = strlen(token); /* Get the PostScript revision */ if ((toklen <= PPDLEN) && (toklen > 0)) { strcpy(pqr->Version, token); DBGPRINT(("Version: %s\n", pqr->Version)); } else { strcpy(pqr->Version, "1.0"); // Default
DBGPRINT(("Version > PPDLEN ???\n")); } token= strtok(NULL, "()\""); /* This should be the revision */ if (token != NULL) { while ((*token != '\0') && (*token == ' ')) token ++; toklen = strlen(token); if ((toklen <= PPDLEN) && (toklen > 0)) { strcpy(pqr->Revision, token); DBGPRINT(("Revision: %s\n", pqr->Revision)); } else { strcpy(pqr->Revision, "1.0"); // Some bogus token
DBGPRINT(("Revision > PPDLEN ???\n")); } } else { strcpy(pqr->Version, "1.0"); // Defaults
strcpy(pqr->Revision, "1.0"); } } } else if (!_stricmp(token, ppdNICKNAME)) { // PPD NickName?
/* Get the NICKNAME */ token= strtok(NULL, "\011()\""); /* This should be the nickname */ if ((token != NULL) && (strlen(token) <= PPDLEN)) { strcpy(pqr->DeviceNickName, token); DBGPRINT(("DeviceNickName: %s\n", pqr->DeviceNickName)); } else DBGPRINT(("DeviceNickName > PPDLEN ???\n")); } else if (!_stricmp(token, ppdLANGUAGEVERSION)) { // PPD Postscript Language Version?
/* Get the LANGUAGEVERSION */ token= strtok(NULL, " \011:"); /* This should be the language */ if ((token != NULL) && (strlen(token) <= PPDLEN)) { strcpy(pqr->LanguageVersion, token); DBGPRINT(("LanguageVersion: %s\n", pqr->LanguageVersion)); } else DBGPRINT(("LanguageVersion > PPDLEN ???\n")); } else if (!_stricmp(token, ppdPRODUCT)) { // PPD Product ?
/* Get the PRODUCT */ token = strtok(NULL, "\011()\""); /* This should be the product */ if ((token != NULL) && (strlen(token) <= PPDLEN)) { strcpy(pqr->Product, token); DBGPRINT(("Product: %s\n", pqr->Product)); } else DBGPRINT(("Product > PPDLEN ???\n")); } else if (!_stricmp(token, ppdFREEVM)) { token= strtok(NULL, "\011()\""); /* This should be the product */ if (token != NULL) sscanf(token, "%ld", &pqr->FreeVM); DBGPRINT(("Free VM: %ld\n", pqr->FreeVM)); } else if (!_stricmp(token, ppdCOLORDEVICE)) { // this should be a string indicating color support or not
// in the form of <True> or <False> (brackets not included)
token = strtok(NULL, " \011:\x0d\x0a"); if ((token != NULL) && (strlen(token) < COLORDEVICEBUFFLEN)) { strcpy (pqr->pszColorDevice, token); } else { strcpy (pqr->pszColorDevice, COLORDEVICEDEFAULT); } DBGPRINT(("Color device: %s\n", pqr->pszColorDevice)); } else if (!_stricmp(token, ppdDEFAULTRESOLUTION)) { // this should be a string indicating the default
// resolution of the printer in the form <xxxxdpi>
// where xxxx is a number
token = strtok(NULL, " \011:\x0d\x0a"); if ((token != NULL) && (strlen(token) < RESOLUTIONBUFFLEN)) { strcpy (pqr->pszResolution, token); } else { strcpy (pqr->pszResolution, RESOLUTIONDEFAULT); } DBGPRINT(("Resolution: %s\n", pqr->pszResolution)); } else if (!_stricmp(token, ppdLANGUAGELEVEL)) { // this should be the PostScript level ("1" or "2")
// implemented in this printer
token = strtok(NULL, " \011\""); if ((token != NULL) && (PPDLEN >= strlen(token))) { strcpy (pqr->pszLanguageLevel, token); } else { strcpy (pqr->pszLanguageLevel, DEFAULTLANGUAGELEVEL); } DBGPRINT(("Language Level: %s\n", pqr->pszLanguageLevel)); } else if (!_stricmp(line, ppdPROTOCOL)) { /* Get the string following and see if it is BCP or TBCP ? */ if ((token= strtok(NULL, " \011:")) != NULL) { if (strstr(token, PROTOCOL_BCP) != NULL) { pqr->SupportsBinary = TRUE; } } } }
if (!ReturnStatus) { pqr->fonts = NULL; pqr->MaxFontIndex = 0; } else { pqr->fonts = fontPtr; pqr->MaxFontIndex = fontindex-1; } } while (FALSE);
if (pszPPDFile != NULL) { LocalFree(pszPPDFile); }
if (ppdfile != NULL) { fclose(ppdfile); }
if (hPrinter != INVALID_HANDLE_VALUE) { ClosePrinter(hPrinter); }
if (pdiThis != NULL) { LocalFree(pdiThis); }
if (!ReturnStatus) { if (fontPtr != NULL) { LocalFree(fontPtr); } }
return (ReturnStatus); }
PFR ReAllocateFontList( PFR pfrOld, DWORD cOldFonts, DWORD cNewFonts ) { PFR pfrNew = NULL;
DBGPRINT(("enter ReAllocateFontList()\n"));
do { // allocate new font record
pfrNew = LocalAlloc(LPTR, cNewFonts * sizeof(FONT_RECORD)); if (pfrNew == NULL) { DBGPRINT(("LocalAlloc fails with %d\n", GetLastError())); break; }
//
// copy old font record
//
CopyMemory(pfrNew, pfrOld, cOldFonts * sizeof(FONT_RECORD)); } while (FALSE);
LocalFree(pfrOld);
return pfrNew; }
/*
** ** WriteToSpool() ** ** Purpose: Determines if job stream is currently being written to ** the spooler, then writes it to the file if it is being written. ** ** Returns: fwrite return codes. ** */ DWORD WriteToSpool( PJR pjr, PBYTE pchbuf, int cchlen ) { BOOL SpoolIt=FALSE; DWORD cbWritten; DWORD dwError = NO_ERROR;
if ((cchlen !=0) && (pchbuf != NULL) && ((pjr->psJobState==psExitServerJob) || (pjr->psJobState==psStandardJob))) { /* determine the data stream mode to know whether to write */ switch (pjr->JSState) { case JSStripEOL: case JSStripKW: case JSStripTok: DBGPRINT(("POP - strip\n")); PopJSState(pjr); break;
case JSWriteEOL: case JSWriteKW: case JSWriteTok: DBGPRINT(("POP - write\n")); PopJSState(pjr); case JSWrite: SpoolIt=TRUE; break; }
// Do we write this Data to the Output Stream ?
if (SpoolIt) { // retry on disk full conditions.
LONG RetryCount = 0;
do { dwError = NO_ERROR; do { if (pjr->FirstWrite) { // don't need that filter string anymore
#if 0
//
// place comment in job to signal AppleTalk monitor not to filter control characters
//
if (!WritePrinter(pjr->hPrinter, FILTERCONTROL, SIZE_FC, &cbWritten)) { dwError = GetLastError(); DBGPRINT(("WritePrinter() failed with %d\n", dwError)); RetryCount++; break; } #endif
pjr->FirstWrite = FALSE; }
#if DBG_SPOOL_LOCALLY
if (DbgSpoolFile != INVALID_HANDLE_VALUE) { WriteFile( DbgSpoolFile, pchbuf, cchlen, &cbWritten, NULL ); } #endif
if (!WritePrinter(pjr->hPrinter, pchbuf, cchlen, &cbWritten)) { dwError = GetLastError(); DBGPRINT(("ERROR: cannot write to printer, error = %x\n", dwError)); RetryCount++; break; } } while (FALSE);
if (dwError == NO_ERROR) break;
if ((dwError == ERROR_HANDLE_DISK_FULL) || (dwError == ERROR_DISK_FULL)) { Sleep(180*1000); // 3 minutes. Its okay to block since we cannot
// service any other jobs either since the disk
// has no space anyway
} } while (RetryCount <= 10); } } return dwError; }
/*
** MoveToPending() ** ** Purpose: Moves the buffer pointed at into the pending buffer. ** ** Returns: DosWrite error codes. ** */ DWORD MoveToPending( PJR pjr, PBYTE pchbuf, int cchlen ) { DBGPRINT(("Enter MoveToPending\n")); if ((cchlen > PSLEN) || (*pchbuf != '%')) { /*
* input line is not a comment and is conforming PostScript line, * so give it to WriteToSpool */ DBGPRINT(("not a DSC comment, so sending to spooler\n")); return (WriteToSpool (pjr, pchbuf, cchlen)); }
pjr->PendingLen= cchlen; memcpy(&pjr->bufPool[pjr->bufIndx].PendingBuffer[PENDLEN-cchlen], pchbuf, cchlen); return (NO_ERROR); }
/*
** TellClient () ** ** Purpose: Sends a message back to the client ** ** Returns: Any of the PAPWrite return codes. ** */ DWORD TellClient( PJR pjr, BOOL fEof, PBYTE BuffPtr, int cchlen ) { DWORD rc = NO_ERROR; fd_set writefds; struct timeval timeout; int sendflag; int wsErr;
DBGPRINT(("enter TellClient()\n"));
do { FD_ZERO(&writefds); FD_SET(pjr->sJob, &writefds);
//
// wait up to 30 seconds to be able to write
//
if (fEof) { sendflag = 0; } else { sendflag = MSG_PARTIAL; }
timeout.tv_sec = 30; timeout.tv_usec = 0;
DBGPRINT(("waiting for writeability\n"));
wsErr = select(0, NULL, &writefds, NULL, &timeout);
if (wsErr == 0) { DBGPRINT(("response to client times out\n")); rc = ERROR_SEM_TIMEOUT; break; }
if (wsErr != 1) { rc = GetLastError(); DBGPRINT(("select(writefds) fails with %d\n")); break; }
if (send(pjr->sJob, BuffPtr, cchlen, sendflag) == SOCKET_ERROR) { rc = GetLastError(); DBGPRINT(("send() fails with %d\n", rc)); break; } } while (FALSE);
return rc; }
/*
** ** HandleBeginBinary() ** ** Purpose: Handles BeginBinary Comment Events. ** */ DWORD HandleBeginBinary( PJR pjr ) { DBGPRINT(("Enter HandleBeginBinary\n"));
/* Process the BeginBinary Comment */ pjr->InBinaryOp = TRUE; return NO_ERROR; }
/*
** ** HandleEndBinary() ** ** Purpose: Handles BeginBinary Comment Events. ** */ DWORD HandleEndBinary( PJR pjr ) { DBGPRINT(("Enter HandleEndBinary\n"));
// Process the EndBinary Comment
pjr->InBinaryOp = FALSE; return NO_ERROR; }
/*
** ** HandleBeginExitServer() ** ** Purpose: Handles BeginExitServer Comment Events. ** */ DWORD HandleBeginExitServer( PJR pjr ) { DBGPRINT(("Enter HandleBeginExitServer\n")); switch (pjr->psJobState) { case psQueryJob: case psExitServerJob: PushJSState(pjr, JSStrip); break;
case psStandardJob: PushJSState(pjr, JSStripEOL); break; } return NO_ERROR; }
/*
** ** HandleCreationDate() ** ** Purpose: Handles CreationDate Comment Events. ** ** Returns: Number of lines that should be skipped before scanning ** for another event starts again. ** */ DWORD HandleCreationDate( PJR pjr ) { return NO_ERROR; }
/*
** ** HandleCreator() - ** ** Purpose: Handles Creator Comment Events. ** */ DWORD HandleCreator( PJR pjr ) { return NO_ERROR; }
/*
** ** HandleEndExitServer()- ** ** Purpose: Handles EndExitServer Comment Events. ** */ DWORD HandleEndExitServer( PJR pjr ) { DBGPRINT(("Enter HandleEndExitServer\n"));
if (pjr->psJobState == psStandardJob) PushJSState (pjr, JSStripEOL);
return NO_ERROR; }
/*
** HandleEOF() ** ** Purpose: Handles EOF Comment Events. ** */ DWORD HandleEOF( PJR pjr ) {
DBGPRINT(("Enter HandleEOF\n"));
if (pjr->psJobState == psQueryJob || pjr->psJobState == psExitServerJob) { pjr->psJobState = psStandardJob; } // pjr->JSState = JSStripKW;
return NO_ERROR; }
/*
** ** HandleFor() ** ** Purpose: Handles For Comment Events. ** */ DWORD HandleFor( PJR pjr ) {
LPSTR token; BYTE pbBuffer[GENERIC_BUFFER_SIZE]; PJOB_INFO_1 pji1Job; DWORD cbNeeded; DWORD Status = NO_ERROR;
DBGPRINT(("Enter HandleFor\n"));
//
// only look for name in main part of print job
//
if (pjr->psJobState != psStandardJob) { DBGPRINT(("not in standard job, skipping username\n")); return NO_ERROR; }
//
// make sure we haven't already set the title
//
if (pjr->dwFlags & JOB_FLAG_OWNERSET) { DBGPRINT(("owner already set, skipping username\n")); return NO_ERROR; }
//
// mark the job as having an owner
//
pjr->dwFlags |= JOB_FLAG_OWNERSET;
//
// look for the client name in the comment and
// default if not found
//
if (((token = strtok(NULL, NULL_STR)) == NULL) || (strchr(token, '*') != NULL)) { token = CLIENTNAME; }
//
// get the current job info
//
pji1Job = (PJOB_INFO_1)pbBuffer; if (!GetJob(pjr->hPrinter, pjr->dwJobId, 1, pbBuffer, GENERIC_BUFFER_SIZE, &cbNeeded)) { //
// need more buffer? If so, try again with a larger one
//
if (cbNeeded > GENERIC_BUFFER_SIZE) { DBGPRINT(("GetJob needs larger buffer. Retrying\n")); pji1Job = (PJOB_INFO_1)LocalAlloc(LPTR, cbNeeded); if (pji1Job == NULL) { Status = GetLastError(); DBGPRINT(("ERROR: out of memory in HandleFor\n")); return Status; }
if (!GetJob(pjr->hPrinter, pjr->dwJobId, 1, (LPBYTE)pji1Job, cbNeeded, &cbNeeded)) { Status = GetLastError(); DBGPRINT(("ERROR: second GetJob fails in HandleFor with %d\n", Status)); return Status; } } else { Status = GetLastError(); DBGPRINT(("GetJob fails with %d\n", Status)); return Status ; } }
//
// change the username
//
OemToCharBuffW(token, pjr->pszUser, (TOKLEN > strlen(token))?(strlen(token)+1):(TOKLEN+1)); pji1Job->pUserName = pjr->pszUser; DBGPRINT(("Setting user name to %ws\n", pjr->pszUser));
//
// set new job information (do not change job position)
//
pji1Job->Position = 0;
if (!SetJob(pjr->hPrinter, pjr->dwJobId, 1, (LPBYTE)pji1Job, 0)) { Status = GetLastError(); DBGPRINT(("WARNING: tried to change user name and failed setjob with %d\n", Status)); }
return Status; }
/*
** ** HandleLogin() ** ** Purpose: Handles Login Comment Events. ** ** Returns: PAPWrite errors. ** */ DWORD HandleLogin( PJR pjr ) { DBGPRINT(("Enter HandleLogin\n")); PushJSState(pjr,JSStripEOL); return (TellClient(pjr, TRUE, LOGINRESPONSE, sizeof(LOGINRESPONSE)-1)); }
/*
** ** HandleTitle() ** ** Purpose: Handles Title Comment Events. ** */ DWORD HandleTitle( PJR pjr ) { LPSTR token; LPWSTR pszTitle; BYTE pbBuffer[GENERIC_BUFFER_SIZE]; PJOB_INFO_1 pji1Job; PJOB_INFO_1 pji1JobAlloc=NULL; DWORD cbNeeded; DWORD Status = NO_ERROR;
DBGPRINT(("Enter HandleTitle\n"));
//
// only get title if we are in main part of job
//
if (pjr->psJobState != psStandardJob) { DBGPRINT(("skipping this title, not main job\n")); return NO_ERROR ; }
//
// make sure title not already set
//
if (JOB_FLAG_TITLESET & pjr->dwFlags) { DBGPRINT(("title already set. Skipping this title\n")); return NO_ERROR; }
//
// marke the title as set
//
pjr->dwFlags |= JOB_FLAG_TITLESET;
//
// get the current job data
//
pji1Job = (PJOB_INFO_1)pbBuffer; if (!GetJob(pjr->hPrinter, pjr->dwJobId, 1, pbBuffer, GENERIC_BUFFER_SIZE, &cbNeeded)) { //
// need more buffer? If so, try again with a larger one
//
if (cbNeeded > GENERIC_BUFFER_SIZE) { DBGPRINT(("GetJob needs larger buffer. Retrying\n")); pji1JobAlloc = (PJOB_INFO_1)LocalAlloc(LPTR, cbNeeded); if (pji1JobAlloc == NULL) { Status = GetLastError(); DBGPRINT(("ERROR: out of memory\n")); return Status; }
pji1Job = pji1JobAlloc;
if (!GetJob(pjr->hPrinter, pjr->dwJobId, 1, (LPBYTE)pji1Job, cbNeeded, &cbNeeded)) { Status = GetLastError(); DBGPRINT(("ERROR: second GetJob fails with %d\n", Status)); LocalFree(pji1JobAlloc); return Status; } } else { Status = GetLastError(); DBGPRINT(("GetJob fails with %d\n", Status)); return Status; } }
//
// get the title
//
if ((token = strtok(NULL, NULL_STR)) == NULL) { // Clear flag. No title.
pjr->dwFlags &= ~JOB_FLAG_TITLESET; return NO_ERROR ; }
pszTitle = (LPWSTR)LocalAlloc(LPTR, sizeof(WCHAR) * (strlen(token)+1)); if (pszTitle == NULL) { Status = GetLastError(); DBGPRINT(("out of memory for pszTitle\n")); return Status; }
OemToCharBuffW(token, pszTitle, strlen(token)+1);
//
// change the title
//
pji1Job->Position = 0; pji1Job->pDocument = pszTitle; DBGPRINT(("changing title to %ws\n", pszTitle));
if (!SetJob(pjr->hPrinter, pjr->dwJobId, 1, (LPBYTE)pji1Job, 0)) {
Status = GetLastError(); DBGPRINT(("WARNING: tried to change title and failed setjob with %d\n", Status)); }
if (pji1JobAlloc) { LocalFree(pji1JobAlloc); }
LocalFree(pszTitle); return Status; }
/*
** ** HandleBeginProcSet() ** ** Purpose: Handles Begining of a ProcSet Upload ** */ DWORD HandleBeginProcSet( PJR pjr ) { DBGPRINT(("Enter HandleBeginProcSet\n")); return NO_ERROR; }
/*
** HandleEndProcSet() ** ** Purpose: Handles End of a procset inclusion. ** */ DWORD HandleEndProcSet( PJR pjr ) { DBGPRINT(("Enter HandleEndProcSet\n")); return NO_ERROR; }
/*
** HandleIncludeProcSet() ** ** Purpose: Handles end of a procset inclusion. ** ** Entry: ** Pointer to Job Structure ** ** Exit: ** ** 0 if no error, otherwise error code. */ DWORD HandleIncludeProcSet( PJR pjr ) { DBGPRINT(("Enter HandleIncludeProcSet\n"));
return NO_ERROR; }
///////////////////////////////////////////////////////////////////////////////
//
// HandlePages()
//
// This comment includes the total number of pages in the job and is
// used to set the jobinfo structure for the job with the total number
// of pages
//
///////////////////////////////////////////////////////////////////////////////
DWORD HandlePages( PJR pjr ) { LPSTR token; DWORD cPages = 0; BYTE pbBuffer[GENERIC_BUFFER_SIZE]; PJOB_INFO_1 pji1Job; DWORD cbNeeded; DWORD Status = NO_ERROR;
DBGPRINT(("Enter HandlePages\n"));
//
// only get pages if we are in main part of job
//
if (pjr->psJobState != psStandardJob) { DBGPRINT(("skipping this comment, not main job\n")); return NO_ERROR ; }
//
// get the current job data
//
pji1Job = (PJOB_INFO_1)pbBuffer; if (!GetJob(pjr->hPrinter, pjr->dwJobId, 1, pbBuffer, GENERIC_BUFFER_SIZE, &cbNeeded)) { //
// GetJob failed, and buffer passed in is larger than the largest
// possible buffer for a job_info_1, so abort this ADSC comment
//
Status = GetLastError(); DBGPRINT(("GetJob() fails with %d\n", Status)); return Status; }
//
// get the number of pages. The comment is of the form %%Pages xx nn
// where xx is the number of pages to display
//
token = strtok(NULL, " "); if (token == NULL) return(NO_ERROR); cPages = atoi(token);
//
// change the number of pages
//
pji1Job->Position = 0; pji1Job->TotalPages = cPages; DBGPRINT(("changing page count to %d\n", cPages));
if (!SetJob(pjr->hPrinter, pjr->dwJobId, 1, (LPBYTE)pji1Job, 0)) { Status = GetLastError(); DBGPRINT(("SetJob fails with %d\n",Status)); }
return Status; }
struct commtable { PSZ commentstr; DWORD (near *pfnHandle)(PJR); } commtable [] = { { FORCOMMENT, HandleFor }, { TITLECOMMENT, HandleTitle }, { BEXITSERVER, HandleBeginExitServer }, { EEXITSERVER, HandleEndExitServer }, { BPROCSET, HandleBeginProcSet }, { EPROCSET, HandleEndProcSet }, { INCLUDEPROCSET, HandleIncludeProcSet }, { CREATIONDATE, HandleCreationDate }, { CREATOR, HandleCreator }, { EOFCOMMENT, HandleEOF }, { LOGIN, HandleLogin }, { LOGINCONT, HandleLogin }, { BEGINBINARY, HandleBeginBinary }, { ENDBINARY, HandleEndBinary }, { PAGESCOMMENT, HandlePages }, { NULL, NULL } };
/*
** HandleComment() ** ** Purpose: Handles Comment Events. ** */ DWORD HandleComment( PJR pjr, PBYTE ps ) { PSZ token; struct commtable *pct; DWORD status = NO_ERROR;
DBGPRINT(("Enter HandleComment\n"));
if ((token = strtok(ps," :")) != NULL) { DBGPRINT(("Comment: %s\n", token)); for (pct = commtable; pct->pfnHandle; pct++) { if (!_stricmp(token, pct->commentstr)) { status = pct->pfnHandle(pjr); break; } } }
// No action on this keyword !!!
return status; }
/*
** HandleJobComment() ** ** Purpose: This parses PostScript Job Comments */ void HandleJobComment( PJR pjr, PBYTE ps ) { char *token;
DBGPRINT(("Enter HandleJobComment\n"));
token= strtok(ps, " ");
//
// it's a job statement
//
if ((token = strtok(NULL, " ")) != NULL) { /* standard job identification */ if (!strcmp(token, QUERYJOBID)) { pjr->psJobState = psQueryJob; pjr->JSState = JSStrip; DBGPRINT(("This is a standard job\n")); return; }
if (!strcmp(token, EXITJOBID)) { pjr->psJobState = psExitServerJob; pjr->JSState = JSStrip; DBGPRINT(("This is an exitjob\n")); return; } }
//
// Job identification not recognized, but some PostScript hackers
// put the program name in this comment, so we treat this as a standard
// job
//
DBGPRINT(("This is an unknown jobtype - processing as standard job\n")); pjr->psJobState = psStandardJob; pjr->JSState = JSWrite; }
/* LineLength -
* Returns the number of bytes, including CR/LF to the next * CR/LF in the buffer. If no CR/LF found, returns -1 */ int LineLength(PBYTE pBuf, int cbBuf) {
int intLength = 0;
while (intLength < cbBuf) { //
// we are looking for a CR
//
if ((pBuf[intLength] != '\x0d') && (pBuf[intLength] != '\x0a')) { intLength++; continue; }
//
// we've found a CR. If it's followed by a LF, return that
// length too, otherwise, just return what we've found
//
if ((intLength + 1) < cbBuf) { if (pBuf[intLength + 1] == '\x0a') { return intLength + 2; } }
return intLength + 1; }
return (-1); }
/*
** ** PSParse() ** ** Purpose: This does the actual parsing of the PostScript Data Stream. ** This routine is always called pointing to the data stream at ** the beginning of a the Data Stream, or the beginning of a line. ** ** Returns: PAPWrite error codes. ** */ DWORD PSParse( PJR pjr, PBYTE pchbuf, int cchlen ) { int cbskip; char ps[PENDLEN]; DWORD err = NO_ERROR;
DBGPRINT(("ENTER: PSParse()\n"));
while (cchlen > 0) { if ((cbskip = LineLength(pchbuf, cchlen)) == -1) return (MoveToPending(pjr, pchbuf, cchlen));
/* Determine what the event is */ if ((cbskip < PSLEN) && (pchbuf[0] == '%')) { /* copy a comment into the ps string */ memcpy(ps, pchbuf, cbskip); ps[cbskip-1] = 0; // OverWrite the CR/LF
if (ps[1] == '%') { /* Its a Query Comment */ if (ps[2] == '?'&& !pjr->InBinaryOp) { if (ps[3] == 'B') { /* Process the Begin Query Comment */ if ((err = HandleBQComment(pjr, ps)) != NO_ERROR) { DBGPRINT(("PSParse: HandleBQComment %ld\n", err)); return(err); } } else if (ps[3] == 'E') { if (pjr->InProgress == QUERYDEFAULT) { if ((err = FinishDefaultQuery(pjr, ps)) != NO_ERROR) { DBGPRINT(("PSParse: FinishDefaultQuery %ld\n", err)); return(err); } } } } else { /* Process the Comment */ if ((err = HandleComment(pjr, ps)) != NO_ERROR) { DBGPRINT(("PSParse: HandleComment %ld\n", err)); return(err); } } } else if (ps[1] == '!'&& !pjr->InBinaryOp) { /* Process Job ID Comment */ HandleJobComment(pjr, ps); } }
/* Write the lines to the spoolfile? */ if ((err = WriteToSpool (pjr, pchbuf, cbskip)) != NO_ERROR) return (err);
pchbuf += cbskip; cchlen -= cbskip; } return NO_ERROR; }
|