PSCommandAImpl.mesa
Copyright (C) Xerox Corporation 1983, 1984, 1985, 1986. All rights reserved.
Last edited by Jacks 11-Jun-86 14:03:25
Contains those PSCommand operations which are not mode related; mainly Document and Control Operations.
DIRECTORY
BasicTime USING [Update, GetUniversalID, GMT, SecondsSinceEpoch],
DecomposerControl USING [DocumentInProgress, FreeDecomposeObject, NoticeNewFonts, Start, Stop, Stopped],
ForwardingControl USING [Start, Stop, Stopped],
Heap USING [FreeNode, MakeNode],
MarkerControl USING [EngineSpecific],
MergeControl USING [Start, Stop, Stopped],
MsgOps USING [FilingErrToMsg],
NSDataStream USING [Abort, Aborted, Handle, OperateOnSource, Source, SourceStream],
NSFile USING [Attribute, Attributes, Close, Error, ErrorRecord, GetAttributes, GetAttributesRecord, Handle, lastPosition, noSelections, nullHandle, ReleaseAttributesRecord, Replace, Selections, Session],
NSName USING [Name],
NSPrintCourier USING [ExportRemoteProgram, UnexportRemoteProgram],
NSString USING [AppendCharacter, AppendString, Character, EquivalentStrings, EqualCharacter, nullString, ScanForCharacter, String, StringBoundsFault, StringFromMesaString],
PaperHandling USING [TwoPaperSizes],
PaperTypes USING [PaperMMDimension, PaperSize],
PaperTypesExtras USING [nullPaper],
PrincOps USING [BYTE],
PrintQueue USING [CopyStringIn, CopyQueueObject, LocateHandle, maxFaxPhoneNos, maxPhoneNoLength, nilQueueObjectHandle, ObjectStatus, Previous, QueueObject, QueueObjectHandle, QueueStage, Requeue],
PrintQueueExtras USING [GetQueueObject],
Process USING [Detach],
PSAsyncMsg USING [Expand1AndPutString, ExpandArrayAndPutString, PutMesaString],
PSCommand USING [allDocuments, DocumentAttributes, DocumentAttrRecord, DocumentFilter, DocumentID, DocumentParameters, DocumentProc, DocumentStatus, Error, ErrorRecord, FaxTransmitData, noDocuments, nullDocumentID, SimpleDocStatus],
PSCommandInternal USING [commandHeap, currentCondition, fontsNoticed, markerProcs, RotateFonts90, state, stateSpace, testPatternsNoticed],
PSState USING [SpoolerState],
PSVolume USING [GetDefaultSession],
QueueControl USING [WaitAbortQueueEmpty],
QueueFile USING [CreateError, CreateTempFile, Delete, InsufficientPages, MakePermanent],
Space USING [ForceOut],
SpoolControl USING [ConnectionClosed, Error, ErrorTypes, FilterConnection, Start, Stop, Stopped, Suspend],
Stream USING [Delete],
String USING [AppendDecimal, AppendLongDecimal],
TestPattern USING [CatalogTPs],
Time USING [Append, AppendCurrent, Unpack];
PSCommandAImpl: CEDAR PROGRAM
IMPORTS BasicTime, DecomposerControl, ForwardingControl, Heap, MergeControl, MsgOps, NSDataStream, NSFile, NSPrintCourier, NSString, PrincOps, PrintQueue, PrintQueueExtras, Process, PSAsyncMsg, PSCommand, PSCommandInternal, PSVolume, QueueControl, QueueFile, Space, SpoolControl, Stream, String, TestPattern, Time
EXPORTS PSCommand, PSCommandInternal
SHARES SpoolControl = BEGIN
OPEN PSCommandInternal;
session: NSFile.Session = PSVolume.GetDefaultSession[];
nsNil: NSString.String = NSString.nullString;
Same as PSCommand.DocumentFilter except filters on PrintQueue.ObjectStatus:
QueueObjectFilter: TYPE = RECORD [
id: PSCommand.DocumentID ← PSCommand.nullDocumentID,
name: NSString.String ← nsNil,
sender: NSString.String ← nsNil,
status: PACKED ARRAY PrintQueue.ObjectStatus OF BOOLEANALL[FALSE]];
Error: PUBLIC ERROR [problem: PSCommand.ErrorRecord] = CODE;
*********************************
PUBLIC PROCS:--
*********************************
*********************************
Queue/Document Operations:
*********************************
Enqueue: PUBLIC PROCEDURE [document: NSDataStream.Source, parameters: PSCommand.DocumentParameters]
RETURNS [documentID: PSCommand.DocumentID] = BEGIN
beginSpoolDate: BasicTime.GMT ← BasicTime.Update[];
file: NSFile.Handle;
attris: ARRAY [0..1) OF NSFile.Attribute ← [[position[NSFile.lastPosition]]];
qOH: PrintQueue.QueueObjectHandle;
why: PSCommand.ErrorRecord;
HandleNSFileFailure: PROCEDURE [qOH: PrintQueue.QueueObjectHandle, error: NSFile.ErrorRecord] = BEGIN
IF state.spoolerTrace # none THEN BEGIN
nsFileFailure: NSString.String = Str["--File Transfer Failed: <1>"L];
stringArray: ARRAY [0..1) OF NSString.String;
DisplayInitialSpoolInfo[qOH];
[stringArray[0],] ← MsgOps.FilingErrToMsg[error];
PSAsyncMsg.ExpandArrayAndPutString[nsFileFailure, DESCRIPTOR[stringArray]];
END;
qOH.currentStatus ← spoolFailure;
qOH.fileID ← QueueFile.Delete[qOH.fileID, file];
[] ← PrintQueue.Requeue[qOH: qOH, fromQueue: spooling, toQueue: aborted];
END; --HandleNSFileFailure
BEGIN
SpoolControl.FilterConnection[! SpoolControl.Error => {
why ← ConvertSpoolControlError[type]; GOTO SpoolControlError}];
[file, qOH] ← CreateSpoolFile[parameters !
UNWIND => SpoolControl.ConnectionClosed[]];
EXITS SpoolControlError => {
NSDataStream.OperateOnSource[document, AbortAndDeleteSourceStream];
ERROR PSCommand.Error[why]; };
END;
NSFile.Replace[file, document, , session
! NSFile.Error => {SpoolControl.ConnectionClosed[];
HandleNSFileFailure[qOH, error]; REJECT}];
SpoolControl.ConnectionClosed[];
QueueFile.MakePermanent[file, DESCRIPTOR[attris]
! NSFile.Error => {HandleNSFileFailure[qOH, error]; REJECT}];
Process.Detach[FORK CompleteEnqueue[qOH, file, beginSpoolDate]]; --finish up queuing without keeping the client waiting
RETURN[qOH.uid];
END; --Enqueue
ListDocuments: PUBLIC SAFE PROCEDURE [proc: PSCommand.DocumentProc, filter: PSCommand.DocumentFilter ← PSCommand.allDocuments] =
ListDocuments lists the queue stage(s) corresponding to the statuses specified in the filter. Status types are defined in PSCommand and include: pending, inProgress, completed, completedWithWarnings, unknown, rejected, aborted, canceled and held. The statuses completedWithWarnings, unknown and held are not currently supported.
The queues containing the newest documents are listed first. The procedure ListQueueStage goes through the documents on the queue stage newest first and determines which ones satisfy the rest of the filter and calls the proc passing the attributes of such documents.
BEGIN
continue: BOOLEANTRUE;
qObjFilter: QueueObjectFilter ← [];
scratchQOH: PrintQueue.QueueObjectHandle ← NIL;
scratchDocAttributes: PSCommand.DocumentAttributes ← NIL;
scratchFaxMitData: LONG DESCRIPTOR FOR ARRAY OF PSCommand.FaxTransmitData ← DESCRIPTOR[NIL, 0];
IF filter = PSCommand.noDocuments THEN RETURN;
QObjFilterFromClientFilter[@filter, @qObjFilter];
Allocate space used by ListQueueStage proc...
scratchQOH ← PrintQueueExtras.GetQueueObject[commandHeap];
scratchDocAttributes ← commandHeap.NEW[PSCommand.DocumentAttrRecord.fax495]; --allocate enough space for the largest variant
scratchFaxMitData ← DESCRIPTOR[Heap.MakeNode[
commandHeap, SIZE[PSCommand.FaxTransmitData] * PrintQueue.maxFaxPhoneNos], PrintQueue.maxFaxPhoneNos];
BEGIN --extra begin/end for exits statement at end of proc
The filter 'allDocuments' lists all 15 queue stages, including the temp queue, which is otherwise never listed.
IF filter = PSCommand.allDocuments THEN BEGIN --list all queues
noOfQueues: CARDINAL = 18;
queueStage: ARRAY [0..noOfQueues) OF PrintQueue.QueueStage ← [
spooling, spooledNormal, bannerOnly, tpSpooled, decomposing, decomposed,
tpDecomposed, retransmit, marking, marked, merging, merged,
tpMerged, forwarding, forwarded, aborted, temp, inactive];
FOR i: CARDINAL IN [0..noOfQueues) DO
continue ← ListQueueStage[
queueStage[i], proc, qObjFilter, scratchQOH,
scratchDocAttributes, scratchFaxMitData];
IF NOT continue THEN GOTO Done;
ENDLOOP;
END
ELSE BEGIN --List queue stages corresponding to statuses specified:
If pending documents are to be listed, list in order the spooler working queue, spooler done queue, decomposer from queue, decomposer retry queue, decomposer banner only queue and test pattern spooled queue:
IF filter.status[pending] THEN BEGIN
noOfQueues: CARDINAL = 4;
queueStage: ARRAY [0..noOfQueues) OF PrintQueue.QueueStage ← [
spooling, spooledNormal, bannerOnly, tpSpooled];
FOR i: CARDINAL IN [0..noOfQueues) DO
continue ← ListQueueStage[
queueStage[i], proc, qObjFilter, scratchQOH,
scratchDocAttributes, scratchFaxMitData];
IF NOT continue THEN GOTO Done;
ENDLOOP;
END;
If inProgress documents are to be listed, list in order the decomposer working queue, decomposer done queue, marker from queue, test pattern decomposed queue and marker working queue:
IF filter.status[inProgress] THEN BEGIN
noOfQueues: CARDINAL = 9;
queueStage: ARRAY [0..noOfQueues) OF PrintQueue.QueueStage ← [
decomposing, decomposed, tpDecomposed, retransmit, marking,
merging, merged, tpMerged, forwarding];
FOR i: CARDINAL IN [0..noOfQueues) DO
continue ← ListQueueStage[
queueStage[i], proc, qObjFilter, scratchQOH,
scratchDocAttributes, scratchFaxMitData];
IF NOT continue THEN GOTO Done;
ENDLOOP;
END;
If completed, rejected, aborted or canceled documents are to be listed, list in order the marker done queue, abort queue and inactive queue:
IF filter.status[completed] OR filter.status[rejected] OR filter.status[aborted] OR filter.status[canceled] THEN BEGIN
noOfQueues: CARDINAL = 4;
queueStage: ARRAY [0..noOfQueues) OF PrintQueue.QueueStage ← [
marked, forwarded, aborted, inactive];
FOR i: CARDINAL IN [0..noOfQueues) DO
continue ← ListQueueStage[
queueStage[i], proc, qObjFilter, scratchQOH,
scratchDocAttributes, scratchFaxMitData];
IF NOT continue THEN GOTO Done;
ENDLOOP;
END;
END;
EXITS
Done => NULL;
END;
commandHeap.FREE[@scratchQOH];
commandHeap.FREE[@scratchDocAttributes];
Heap.FreeNode[commandHeap, BASE[scratchFaxMitData]];
END; --ListDocuments
CancelDocument: PUBLIC PROCEDURE [documentID: PSCommand.DocumentID]
RETURNS [status: PSCommand.DocumentStatus] = BEGIN
Cannot currently cancel a document on spooling queue or temp queue.
What happens if, while we try to cancel a doc on an intermediate queue (e.g. spooled), the doc moves onto a working queue (e.g. decomposing)?
qOH: PrintQueue.QueueObjectHandle;
queueStage: PrintQueue.QueueStage;
[qOH, queueStage] ← PrintQueue.LocateHandle[documentID];
IF qOH = PrintQueue.nilQueueObjectHandle THEN ERROR Error[[documentNotFound[]]];
SELECT queueStage FROM
spooledNormal, bannerOnly, decomposed, merged, tpSpooled, tpDecomposed, tpMerged => BEGIN
[] ← PrintQueue.Requeue[qOH: qOH, fromQueue: queueStage, toQueue: temp];
qOH.currentStatus ← canceledInQueue;
[] ← PrintQueue.Requeue[qOH: qOH, fromQueue: temp, toQueue: aborted];
QueueControl.WaitAbortQueueEmpty[];
END;
retransmit => BEGIN
[] ← PrintQueue.Requeue[qOH: qOH, fromQueue: queueStage, toQueue: temp];
qOH.currentStatus ← faxCanceled;
WITH q: qOH SELECT FROM
fax495 => FOR p: CARDINAL IN [0..q.phoneNoCount) DO
q.transmitData[p].queuedForRetry ← FALSE;
ENDLOOP;
ENDCASE;
[] ← PrintQueue.Requeue[qOH: qOH, fromQueue: temp, toQueue: aborted];
QueueControl.WaitAbortQueueEmpty[];
END;
decomposing => BEGIN
state.internalControl.formatterEnabled ← FALSE;
DecomposerControl.Stop[status: canceledInDecomposer];
[] ← DecomposerControl.Stopped[wait];
QueueControl.WaitAbortQueueEmpty[];
state.internalControl.formatterEnabled ← TRUE;
IF state.clientControl.formatterEnabled THEN DecomposerControl.Start[];
END;
marking => BEGIN
state.internalControl.markerEnabled ← FALSE;
WITH q: qOH SELECT FROM
fax495 => markerProcs.stop[status: faxCanceled];
ENDCASE => markerProcs.stop[status: canceledInMarker];
[] ← markerProcs.stopped[wait];
QueueControl.WaitAbortQueueEmpty[];
state.internalControl.markerEnabled ← TRUE;
IF state.clientControl.markerEnabled THEN markerProcs.start[];
END;
merging => BEGIN
state.internalControl.markerEnabled ← FALSE;
MergeControl.Stop[status: canceledInMerger];
[] ← MergeControl.Stopped[wait];
QueueControl.WaitAbortQueueEmpty[];
state.internalControl.markerEnabled ← TRUE;
IF state.clientControl.markerEnabled THEN MergeControl.Start[];
END;
forwarding => BEGIN
state.internalControl.markerEnabled ← FALSE;
ForwardingControl.Stop[status: canceledInForwarder];
[] ← ForwardingControl.Stopped[wait];
QueueControl.WaitAbortQueueEmpty[];
state.internalControl.markerEnabled ← TRUE;
IF state.clientControl.markerEnabled THEN ForwardingControl.Start[];
END;
ENDCASE;
RETURN[DocumentStatusFromQObjStatus[qOH]];
END; --CancelDocument
****************************************
Print Service Control Operations:
****************************************
Start: PUBLIC PROCEDURE = BEGIN
Called to undo Shutdown or Start PS after initialization.
IF currentCondition = stopped THEN BEGIN
currentCondition ← starting;
IF state.mode.current # repair THEN BEGIN
EnableQueuing[];
EnablePrinting[];
IF state.option = raven THEN --don't reference markerProcs if printing option = feps9700
WITH m: markerProcs SELECT FROM
raven => m.wakeupEngine[]; --Marker checks to be sure engine build is compatible.
ENDCASE;
state.mode.returnTo ← state.mode.current ← normal;
END
ELSE state.mode.returnTo ← normal;
NSPrintCourier.ExportRemoteProgram[];
Space.ForceOut[stateSpace];
currentCondition ← started;
END;
END; --StartPrintService
Stop: PUBLIC PROCEDURE = BEGIN
Suspend and checkpoint all activities in anticipation of a power-off. PS will not be completely "stopped" if it is in repair mode.
IF currentCondition = started THEN BEGIN
currentCondition ← stopping;
IF state.mode.current # repair THEN BEGIN
DisableQueuing[];
DisablePrinting[];
IF state.option = raven THEN --don't reference markerProcs if printing option = feps9700
WITH m: markerProcs SELECT FROM
raven => m.dozeoffEngine[]; --Marker checks to be sure engine build is compatible.
ENDCASE;
state.mode.current ← state.mode.returnTo ← shutDown;
END
ELSE state.mode.returnTo ← shutDown;
NSPrintCourier.UnexportRemoteProgram[];
Space.ForceOut[stateSpace];
currentCondition ← stopped;
What else??
END;
END; --StopPrintService
StartPrinting: PUBLIC PROCEDURE [user: NSName.Name] = BEGIN
IF state.clientControl.formatterEnabled THEN RETURN;
IF state.option = bansheeDl THEN
Call a proc which checks to see if any fonts need to be
rotated for banshee (raven fonts are rotated 90 degrees)
PSCommandInternal.RotateFonts90[];
IF NOT fontsNoticed THEN BEGIN
DecomposerControl.NoticeNewFonts[
! DecomposerControl.DocumentInProgress => ERROR
Error[[documentInProgress[]]]];
fontsNoticed ← TRUE;
END;
IF NOT testPatternsNoticed THEN BEGIN
TestPattern.CatalogTPs[];
testPatternsNoticed ← TRUE;
END;
state.clientControl.formatterEnabled ← state.clientControl.markerEnabled ← TRUE;
IF state.internalControl.markerEnabled THEN BEGIN
DecomposerControl.Start[];
IF state.option = feps9700 THEN BEGIN
MergeControl.Start[];
ForwardingControl.Start[];
END ELSE
markerProcs.start[];
END;
state.lastUserToStartPrinting.length ← 0;
IF user.local.length > 0 THEN
state.lastUserToStartPrinting ← NSString.AppendString[
to: state.lastUserToStartPrinting, from: user.local
! NSString.StringBoundsFault => CONTINUE];
Space.ForceOut[stateSpace];
END; --StartPrinting
StopPrinting: PUBLIC PROCEDURE [user: NSName.Name, reason: NSString.String ← NSString.nullString] = BEGIN
abortedCount: LONG CARDINAL ← state.docsAborted.total;
IF NOT state.clientControl.formatterEnabled THEN RETURN;
state.clientControl.formatterEnabled ← state.clientControl.markerEnabled ← FALSE;
IF state.internalControl.markerEnabled THEN StopPrintingInternal[];
state.lastUserToStopPrinting.length ← 0;
state.lastStopPrintingReason.length ← 0;
IF user.local.length > 0 THEN
state.lastUserToStopPrinting ← NSString.AppendString[
to: state.lastUserToStopPrinting, from: user.local
! NSString.StringBoundsFault => CONTINUE];
IF reason.length > 0 THEN
state.lastStopPrintingReason ← NSString.AppendString[
to: state.lastStopPrintingReason, from: reason
! NSString.StringBoundsFault => CONTINUE];
Space.ForceOut[stateSpace];
END; --StopPrinting
StartQueuing: PUBLIC PROCEDURE [user: NSName.Name] = BEGIN
IF state.clientControl.spooler = enabled THEN RETURN;
state.clientControl.spooler ← enabled;
IF state.internalControl.spooler = enabled THEN
SpoolControl.Start[];
state.lastUserToStartQueuing.length ← 0;
IF user.local.length > 0 THEN
state.lastUserToStartQueuing ← NSString.AppendString[
to: state.lastUserToStartQueuing, from: user.local
! NSString.StringBoundsFault => CONTINUE];
Space.ForceOut[stateSpace];
END; --StartQueuing
StopQueuing: PUBLIC PROCEDURE [user: NSName.Name, reason: NSString.String ← NSString.nullString] = BEGIN
IF state.clientControl.spooler # enabled THEN RETURN;
state.clientControl.spooler ← disabled;
IF state.internalControl.spooler = enabled THEN BEGIN
SpoolControl.Stop[aborted];
[] ← SpoolControl.Stopped[wait];
END;
state.lastUserToStopQueuing.length ← 0;
state.lastStopQueuingReason.length ← 0;
IF user.local.length > 0 THEN
state.lastUserToStopQueuing ← NSString.AppendString[
to: state.lastUserToStopQueuing, from: user.local
! NSString.StringBoundsFault => CONTINUE];
IF reason.length > 0 THEN
state.lastStopQueuingReason ← NSString.AppendString[
to: state.lastStopQueuingReason, from: reason
! NSString.StringBoundsFault => CONTINUE];
Space.ForceOut[stateSpace];
END; --StopQueuing
ShutDownEngine: PUBLIC PROCEDURE = BEGIN
WITH s: state SELECT FROM
raven =>
IF s.engineBuild > b1 THEN
WITH m: markerProcs SELECT FROM
raven => m.dozeoffEngine[];
ENDCASE => ERROR --Marker procs engine type disagrees with state record.
ELSE ERROR Error[[incompatiblePrintingOption[]]];
ENDCASE => ERROR Error[[incompatiblePrintingOption[]]];
END; --ShutdownEngine
WakeUpEngine: PUBLIC PROCEDURE = BEGIN
WITH s: state SELECT FROM
raven =>
IF s.engineBuild > b1 THEN
WITH m: markerProcs SELECT FROM
raven => m.wakeupEngine[];
ENDCASE => ERROR --Marker procs engine type disagrees with state record.
ELSE ERROR Error[[incompatiblePrintingOption[]]];
ENDCASE => ERROR Error[[incompatiblePrintingOption[]]];
END; --WakeupEngine
PSCOMMANDINTERNAL PROCEDURES:--
EnablePrinting: PUBLIC PROCEDURE = BEGIN
IF state.internalControl.formatterEnabled THEN RETURN;
state.internalControl.formatterEnabled ← state.internalControl.markerEnabled ← TRUE;
IF state.clientControl.markerEnabled THEN BEGIN
DecomposerControl.Start[];
IF state.option = feps9700 THEN BEGIN
MergeControl.Start[];
ForwardingControl.Start[];
END ELSE
markerProcs.start[];
END;
Space.ForceOut[stateSpace];
END; --EnablePrinting
DisablePrinting: PUBLIC PROCEDURE = BEGIN
IF NOT state.internalControl.formatterEnabled THEN RETURN;
state.internalControl.formatterEnabled ← state.internalControl.markerEnabled ← FALSE;
IF state.clientControl.markerEnabled THEN StopPrintingInternal[];
Space.ForceOut[stateSpace];
END; --DisablePrinting
EnableQueuing: PUBLIC PROCEDURE = BEGIN
IF state.internalControl.spooler = enabled THEN RETURN;
state.internalControl.spooler ← enabled;
IF state.clientControl.spooler = enabled THEN SpoolControl.Start[];
Space.ForceOut[stateSpace];
END; --EnableQueuing
DisableQueuing: PUBLIC PROCEDURE [reason: PSState.SpoolerState ← disabled] = BEGIN
IF state.internalControl.spooler # enabled THEN RETURN;
state.internalControl.spooler ← reason;
IF state.clientControl.spooler = enabled THEN BEGIN
IF reason = disabledForMarking THEN SpoolControl.Suspend[] ELSE SpoolControl.Stop[aborted];
[] ← SpoolControl.Stopped[wait];
END;
Space.ForceOut[stateSpace];
END; --DisableQueuing
PRIVATE PROCEDURES:--
Procedures used by ENQUEUE:--
AbortAndDeleteSourceStream: PROCEDURE [stream: NSDataStream.SourceStream] = BEGIN
NSDataStream.Abort[stream];
Stream.Delete[stream ! NSDataStream.Aborted => CONTINUE];
END; --AbortAndDeleteSourceStream
CompleteEnqueue: PROCEDURE [qOH: PrintQueue.QueueObjectHandle, file: NSFile.Handle,
beginSpoolDate: BasicTime.GMT] = BEGIN
--This procedure does a few final things with the qOH before putting it on the spooled queue. It is forked by Enqueue so that Enqueue's client is not kept hanging any longer than necessary.--
selection: NSFile.Selections ← NSFile.noSelections;
attribute: NSFile.Attributes ← NSFile.GetAttributesRecord[];
IF state.spoolerTrace # none THEN DisplayInitialSpoolInfo[qOH];
Get true file size...
selection.interpreted[dataSize] ← TRUE;
NSFile.GetAttributes[file, selection, attribute, session];
qOH.fileSize ← attribute.dataSize;
NSFile.Close[file, session];
NSFile.ReleaseAttributesRecord[attribute];
qOH.fileQueuedDate ← BasicTime.Update[];
qOH.currentStatus ← spooled;
[] ← PrintQueue.Requeue[qOH: qOH, fromQueue: spooling, toQueue: spooledNormal];
IF state.spoolerTrace = verbose THEN DisplayFinalSpoolInfo[qOH, beginSpoolDate];
If printing option is a B2 raven engine, wake up the engine if necessary...
IF state.option = raven THEN
WITH m: markerProcs SELECT FROM
raven =>
WITH d: m.status[].engine SELECT FROM
raven =>
IF d.raven IN [aboutToDozeOff..fuserUnderTemperature] THEN
m.wakeupEngine[];
ENDCASE => ERROR;
ENDCASE => ERROR;
END; -- of CompleteEnqueue
CopyDocParametersToQueueObject: PROCEDURE [qOH: PrintQueue.QueueObjectHandle,
parms: PSCommand.DocumentParameters] = BEGIN
timeLength: CARDINAL = 18;
timeString: LONG STRING ← [timeLength];
qOH.fileName.length ← 0;
qOH.localFileName.length ← 0;
IF parms.name # NSString.nullString THEN BEGIN
PrintQueue.CopyStringIn[qOH, parms.name, fileName];
PrintQueue.CopyStringIn[qOH, parms.name, localFileName];
END;
Append time to local file name (if there was no file name the date will serve as one)...
Time.AppendCurrent[timeString];
qOH.localFileName ← NSString.AppendString[qOH.localFileName, Str[timeString]
! NSString.StringBoundsFault => CONTINUE];
qOH.fileCreateDate ← parms.createDate;
IF parms.senderName # NSString.nullString THEN
PrintQueue.CopyStringIn[qOH, parms.senderName, sender];
qOH.fileSize ← parms.size;
IF parms.recipientName # NSString.nullString THEN
PrintQueue.CopyStringIn[qOH, parms.recipientName, recipient];
IF parms.message # NSString.nullString THEN
PrintQueue.CopyStringIn[qOH, parms.message, operatorMsg];
qOH.numberCopies ← parms.copyCount;
--This is a kludge where we check for page number zero which is not allowed. (It is documented in Printing Protocol standard that page numbers start at 1.) The decomposer will act strangely if you give it page number zero. Since OS 5.0 Star used to send first PageToPrint=0, we need to have the kludge in for a while for backward compatibility. An AR has been submitted against Viewpoint and is expected to be fixed.
NOTE: This kludge should be taken out in some subsequent release.--
IF parms.firstPageToPrint = 0 OR parms.lastPageToPrint = 0 THEN BEGIN
Invalid page numbers, so use default values
qOH.firstPageToPrint ← 1;
qOH.lastPageToPrint ← LAST[CARDINAL];
END ELSE BEGIN
qOH.firstPageToPrint ← parms.firstPageToPrint;
qOH.lastPageToPrint ← parms.lastPageToPrint;
END;
qOH.paper ← parms.paper;
qOH.staple ← parms.staple;
qOH.twoSided ← parms.twoSided;
qOH.priority ← LOOPHOLE[parms.priority];
qOH.releaseKey ← parms.releaseKey;
WITH s: state SELECT FROM
bansheeDl => BEGIN
dStatus: MarkerControl.EngineSpecific ← markerProcs.status[].engine;
WITH d: dStatus SELECT FROM
bansheeDl => BEGIN
IF parms.paper = PaperTypesExtras.nullPaper THEN qOH.paper ← d.paper; --Default to currently loaded paper size if size not specified
IF qOH.paper # d.paper THEN
PSCommand.Error[[enqueue[mediumUnavailable]]];
END;
ENDCASE => ERROR;
END;
d1 => BEGIN
dStatus: MarkerControl.EngineSpecific ← markerProcs.status[].engine;
WITH d: dStatus SELECT FROM
d1 => BEGIN
IF parms.paper = PaperTypesExtras.nullPaper THEN qOH.paper.knownSize ← d.paperSize; --Default to currently loaded paper size if size not specified
IF qOH.paper.knownSize # d.paperSize THEN
PSCommand.Error[[enqueue[mediumUnavailable]]];
END;
ENDCASE => ERROR;
END;
fax295 => BEGIN
SELECT s.paperWidth FROM
PaperTypes.PaperMMDimension[letter].short => BEGIN --Paper width is for letter/legal paper.
IF parms.paper = PaperTypesExtras.nullPaper THEN qOH.paper.knownSize ← letter; --Default to letter if size not specified
IF qOH.paper.knownSize = a4 THEN qOH.paper.knownSize ← legal; --Allow a4 documents to be printed on legal paper
IF qOH.paper.knownSize # letter AND qOH.paper.knownSize # legal THEN
PSCommand.Error[[enqueue[mediumUnavailable]]];
END;
PaperTypes.PaperMMDimension[a4].short => BEGIN --Paper width is for a4 paper.
IF parms.paper = PaperTypesExtras.nullPaper THEN qOH.paper.knownSize ← a4; --Default to a4 if size not specified
IF qOH.paper.knownSize # a4 THEN PSCommand.Error[[enqueue[mediumUnavailable]]];
END;
ENDCASE => ERROR; --Paper width is other than letter/legal or a4???
END;
fax495 => BEGIN
SELECT s.paperWidth FROM
PaperTypes.PaperMMDimension[letter].short => BEGIN --Paper width is for letter/legal paper.
IF parms.paper = PaperTypesExtras.nullPaper THEN qOH.paper.knownSize ← letter; --Default to letter if size not specified
IF qOH.paper.knownSize = a4 THEN qOH.paper.knownSize ← legal; --Allow a4 documents to be printed on legal paper
IF qOH.paper.knownSize # letter AND qOH.paper.knownSize # legal THEN
PSCommand.Error[[enqueue[mediumUnavailable]]];
END;
PaperTypes.PaperMMDimension[a4].short => BEGIN --Paper width is for a4 paper.
IF parms.paper = PaperTypesExtras.nullPaper THEN qOH.paper.knownSize ← a4; --Default to a4 if size not specified
IF qOH.paper.knownSize # a4 THEN PSCommand.Error[[enqueue[mediumUnavailable]]];
END;
ENDCASE => ERROR; --Paper width is other than letter/legal or a4???
IF parms.message # NSString.nullString THEN GetFaxDataFromString[parms.message, qOH]
ELSE --If no message, do a local print.
WITH q: qOH SELECT FROM
fax495 => q.localPrintStatus ← queued;
ENDCASE => ERROR;
END;
feps9700 => BEGIN
IF parms.paper = PaperTypesExtras.nullPaper THEN qOH.paper.knownSize ←
IF s.paperSupply.size1 # letter AND s.paperSupply.size2 # letter
THEN s.paperSupply.size1 ELSE letter;
IF qOH.paper.knownSize # s.paperSupply.size1 AND
qOH.paper.knownSize # s.paperSupply.size2 THEN
PSCommand.Error[[enqueue[mediumUnavailable]]];
END;
fx3500 => BEGIN
dStatus: MarkerControl.EngineSpecific ← markerProcs.status[].engine;
WITH d: dStatus SELECT FROM
fx3500 => BEGIN
IF parms.paper = PaperTypesExtras.nullPaper THEN qOH.paper.knownSize ←
IF d.paperSupply.size1 # a4 AND d.paperSupply.size2 # a4
THEN d.paperSupply.size1 ELSE a4;
IF qOH.paper.knownSize # d.paperSupply.size1 AND
qOH.paper.knownSize # d.paperSupply.size2 THEN
PSCommand.Error[[enqueue[mediumUnavailable]]];
END;
ENDCASE => ERROR;
END;
raven => BEGIN
IF parms.paper = PaperTypesExtras.nullPaper THEN qOH.paper.knownSize ←
IF s.paperSupply.size1 # letter AND s.paperSupply.size2 # letter
THEN s.paperSupply.size1 ELSE letter;
IF qOH.paper.knownSize # s.paperSupply.size1 AND
qOH.paper.knownSize # s.paperSupply.size2 THEN
PSCommand.Error[[enqueue[mediumUnavailable]]];
END;
ENDCASE => ERROR; --unknown printing option?
END; --CopyDocParametersToQueueObject
ConvertSpoolControlError: PROCEDURE [sType: SpoolControl.ErrorTypes]
RETURNS [error: PSCommand.ErrorRecord] = BEGIN
RETURN [SELECT sType FROM
busy => [enqueue[busySpooling]],
spoolingDisabled => [enqueue[spoolingDisabled]],
tooManyConnections => [enqueue[tooManyClients]],
spoolFull => [enqueue[spoolingQueueFull]],
ENDCASE => ERROR]
END; --ConvertSpoolControlError
CreateSpoolFile: PROCEDURE [docParameters: PSCommand.DocumentParameters]
RETURNS [file: NSFile.Handle ← NSFile.nullHandle,
qOH: PrintQueue.QueueObjectHandle ← PrintQueue.nilQueueObjectHandle] = BEGIN
createFileError: PSCommand.ErrorRecord; BEGIN
fileBytes: LONG CARDINAL;
qOH ← PrintQueue.Requeue[fromQueue: inactive, toQueue: spooling];
qOH.currentStatus ← PrintQueue.ObjectStatus[spooling];
CopyDocParametersToQueueObject[qOH, docParameters
! PSCommand.Error => {
IF state.spoolerTrace # none THEN PSAsyncMsg.PutMesaString[" **PSCommand.Error[[enqueue[mediumUnavailable]]]"L];
qOH.currentStatus ← PrintQueue.ObjectStatus[spoolFailure];
[] ← PrintQueue.Requeue[qOH: qOH, fromQueue: spooling,
toQueue: aborted];
REJECT}];
fileBytes ← IF qOH.fileSize = 0 THEN 20 ELSE qOH.fileSize;
[qOH.fileID, file] ← QueueFile.CreateTempFile[qOH.localFileName, fileBytes !
QueueFile.CreateError => {createFileError ← [enqueue[other]]; GOTO Error};
QueueFile.InsufficientPages =>
{createFileError ← [insufficientSpace[]]; GOTO Error};];
qOH.uid ← BasicTime.GetUniversalID[]; EXITS
Error => BEGIN
qOH.currentStatus ← PrintQueue.ObjectStatus[spoolFailure];
[] ← PrintQueue.Requeue[qOH: qOH,
fromQueue: spooling, toQueue: aborted];
PSCommand.Error[createFileError];
END;
END;
END; --CreateSpoolFile
GetFaxDataFromString: PROCEDURE [
string: NSString.String, qOH: PrintQueue.QueueObjectHandle] = BEGIN
WITH q: qOH SELECT FROM
fax495 => BEGIN
endOfParse: BOOLEANFALSE;
startParseIndex, --index of string char where parsing should begin
stopParseIndex, --index of string char where parsing should end (past last legal char)
actualLength, --actual number of legal phone number chars found for a given phone number
parseIndex, --current string char being looked at during parse
phoneNos, --number of phone numbers found
phoneNoIndex --index into queue object phone number array where next phone number goes
: CARDINAL ← 0;
chset: PrincOps.BYTE ← 0;
char: NSString.Character;
msgLength: CARDINAL ← string.length;
chsetChangeMarker: PrincOps.BYTE = 377B;
delimiter: NSString.Character = [0, 57B]; --slash char '/
blank: NSString.Character = [0, 40B];
comma: NSString.Character = [0, 54B];
letterL: NSString.Character = [0, 114B];
minActualLength: CARDINAL = 2; --min # of actual phone number chars allowed
maxActualLength: CARDINAL = 27; --max # of actual phone number chars allowed
EndOfParse: SIGNAL = CODE;
ParseError: ERROR = CODE;
ActualPhoneNoChar: PROC [c: NSString.Character] RETURNS [BOOLEAN] = BEGIN
SELECT c FROM
[0, 60B]--0--, [0, 61B]--1--, [0, 62B]--2--, [0, 63B]--3--,
[0, 64B]--4--, [0, 65B]--5--, [0, 66B]--6--, [0, 67B]--7--,
[0, 70B]--8--, [0, 71B]--9--, [0, 120B]--P--,
[0, 52B]--*--, [0, 43B]--#-- => RETURN [TRUE];
ENDCASE => RETURN [FALSE];
END; --ActualPhoneNoChar
GetNextChar: PROCEDURE RETURNS [NSString.Character] = BEGIN
code: PrincOps.BYTE;
ValidCharacter: PROC [c: NSString.Character] RETURNS [BOOLEAN] = BEGIN
SELECT c FROM
[0, 60B]--0--, [0, 61B]--1--, [0, 62B]--2--, [0, 63B]--3--,
[0, 64B]--4--, [0, 65B]--5--, [0, 66B]--6--, [0, 67B]--7--,
[0, 70B]--8--, [0, 71B]--9--, [0, 55B]--minus--,
[0, 50B]--leftParen--, [0, 51B]--rightParen--,
[0, 120B]--P--, [0, 52B]--*--, [0, 43B]--#--,
[41B, 76B]--hyphen--, blank, comma, letterL => RETURN [TRUE];
ENDCASE => RETURN [FALSE];
END; --ValidCharacter
IF parseIndex >= stopParseIndex THEN SIGNAL EndOfParse;
code ← string.bytes[parseIndex];
IF code = chsetChangeMarker THEN BEGIN
IF (parseIndex ← parseIndex + 1) >= msgLength THEN ERROR ParseError;
chset ← string.bytes[parseIndex];
IF (parseIndex ← parseIndex + 1) >= msgLength THEN ERROR ParseError;
code ← string.bytes[parseIndex];
END;
parseIndex ← parseIndex + 1;
IF NOT ValidCharacter[[chset, code]] THEN ERROR ParseError;
RETURN[[chset, code]];
END; --GetNextChar
LookForSinglePhoneNo: PROCEDURE = BEGIN
chset ← parseIndex ← 0;
stopParseIndex ← msgLength;
q.localPrintStatus ← null;
q.phoneNoCount ← 1;
q.transmitData ← ALL[];
q.transmitData[0].status ← queued;
q.transmitData[0].phoneNumber ← [
bytes: LOOPHOLE[@q.transmitData[0].phoneNumberBody],
length: 0, maxlength: PrintQueue.maxPhoneNoLength];
actualLength ← 0;
char ← GetNextChar[!
EndOfParse, ParseError => GOTO localPrint];
UNTIL char = comma OR char = letterL --letter L no allowed in phone number
OR q.transmitData[0].phoneNumber.length >= q.transmitData[0].phoneNumber.maxlength DO
q.transmitData[0].phoneNumber ←
NSString.AppendCharacter[q.transmitData[0].phoneNumber, char];
IF ActualPhoneNoChar[char] THEN actualLength ← actualLength + 1;
char ← GetNextChar[! EndOfParse =>
IF actualLength < minActualLength OR actualLength > maxActualLength THEN
GOTO localPrint ELSE GOTO finished;
ParseError => GOTO localPrint];
ENDLOOP;
IF actualLength < minActualLength OR actualLength > maxActualLength THEN
GOTO localPrint;
DO
IF char # blank THEN GOTO localPrint;
char ← GetNextChar[! EndOfParse => GOTO finished;
ParseError => GOTO localPrint];
ENDLOOP;
EXITS
finished => NULL;
localPrint => BEGIN
q.localPrintStatus ← queued;
q.phoneNoCount ← 0;
q.transmitData ← ALL[];
END;
END; --LookForSinglePhoneNo
BEGIN
IF msgLength = 0 THEN {q.localPrintStatus ← queued; GOTO done};
parseIndex ← NSString.ScanForCharacter[delimiter, string];
IF parseIndex = LAST[CARDINAL] THEN --no slash found
GOTO lookForSinglePhoneNo;
IF NOT NSString.EqualCharacter[delimiter, string, parseIndex + 1] THEN --second slash not found
GOTO lookForSinglePhoneNo;
startParseIndex ← parseIndex + 2;
parseIndex ← NSString.ScanForCharacter[delimiter, string, startParseIndex];
IF parseIndex = LAST[CARDINAL] THEN --no slash found
GOTO lookForSinglePhoneNo;
IF NOT NSString.EqualCharacter[delimiter, string, parseIndex + 1] THEN --second slash not found
GOTO lookForSinglePhoneNo;
stopParseIndex ← parseIndex;
parseIndex ← startParseIndex;
DO --Look for leading blanks or commas and letter L for local print.
char ← GetNextChar[! EndOfParse, ParseError => GOTO lookForSinglePhoneNo];
SELECT char FROM
letterL => BEGIN
q.localPrintStatus ← queued;
Look for comma after L:
char ← GetNextChar[! EndOfParse => GOTO done;
ParseError => GOTO lookForSinglePhoneNo];
UNTIL char = comma DO
IF char # blank THEN GOTO lookForSinglePhoneNo;
char ← GetNextChar[! EndOfParse => GOTO done;
ParseError => GOTO lookForSinglePhoneNo];
ENDLOOP;
EXIT;
END;
blank, comma => LOOP;
ENDCASE => EXIT;
ENDLOOP;
DO --Look for phone numbers.
Extra blanks and commas allowed between items:
UNTIL char # blank AND char # comma DO
char ← GetNextChar[! EndOfParse =>
IF q.localPrintStatus = queued OR q.phoneNoCount > 0 THEN GOTO done
ELSE GOTO lookForSinglePhoneNo;
ParseError => GOTO lookForSinglePhoneNo];
ENDLOOP;
phoneNos ← phoneNos + 1;
actualLength ← 0;
Look for a phone number before next comma:
UNTIL char = comma OR char = letterL --letter L is valid only as local print indicator at beginning of string.
OR q.transmitData[phoneNoIndex].phoneNumber.length >= q.transmitData[phoneNoIndex].phoneNumber.maxlength DO
q.transmitData[phoneNoIndex].phoneNumber ←
NSString.AppendCharacter[q.transmitData[phoneNoIndex].phoneNumber, char];
IF ActualPhoneNoChar[char] THEN actualLength ← actualLength + 1;
char ← GetNextChar[! EndOfParse =>
IF actualLength < minActualLength OR actualLength > maxActualLength THEN
GOTO lookForSinglePhoneNo ELSE GOTO done;
ParseError => GOTO lookForSinglePhoneNo];
ENDLOOP;
phoneNoIndex ← phoneNoIndex + 1;
IF actualLength < minActualLength OR actualLength > maxActualLength THEN
GOTO lookForSinglePhoneNo;
IF phoneNos >= PrintQueue.maxFaxPhoneNos THEN GOTO done;
UNTIL char = comma DO --Char should be a comma (or a blank before comma) or else phone number to too long
IF char # blank THEN GOTO lookForSinglePhoneNo; --Phone number was too long or an L was found.
char ← GetNextChar[! EndOfParse => GOTO done;
ParseError => GOTO lookForSinglePhoneNo];
ENDLOOP;
ENDLOOP;
EXITS
done => IF phoneNos > 0 THEN BEGIN
FOR i: CARDINAL IN [0..phoneNos) DO
q.transmitData[i].status ← queued;
ENDLOOP;
q.phoneNoCount ← phoneNos;
END;
lookForSinglePhoneNo => LookForSinglePhoneNo[];
END;
END;
ENDCASE;
END; --GetFaxDataFromString
Debugging procedures
DisplayInitialSpoolInfo: PROCEDURE [qOH: PrintQueue.QueueObjectHandle] = BEGIN
nsPrintRequest: NSString.String = Str["--Print Request by <1>"L];
nsFile: NSString.String = Str["--File: <1>"L];
PSAsyncMsg.Expand1AndPutString[nsPrintRequest, qOH.sender];
PSAsyncMsg.Expand1AndPutString[nsFile, qOH.fileName];
END; -- DisplayInitialSpoolInfo
DisplayFinalSpoolInfo: PROCEDURE [qOH: PrintQueue.QueueObjectHandle,
beginSpoolDate: BasicTime.GMT] = BEGIN
nsComplete: NSString.String = Str["--File transfer took <1> seconds; completed: <2>"];
nsCopiesAndLength: NSString.String = Str["--Copies: <1>; BYTE Length: <2>"L];
stringArray: ARRAY [0..2) OF NSString.String;
spoolTime: LONG CARDINAL ← BasicTime.SecondsSinceEpoch[qOH.fileQueuedDate] - BasicTime.SecondsSinceEpoch[beginSpoolDate];
sTime: LONG STRING ← [10];
sDate: LONG STRING ← [20];
sCopies: LONG STRING ← [10];
sLength: LONG STRING ← [15];
String.AppendLongDecimal[sTime, spoolTime];
stringArray[0] ← Str[sTime];
Time.Append[sDate, Time.Unpack[qOH.fileQueuedDate]];
stringArray[1] ← Str[sDate];
PSAsyncMsg.ExpandArrayAndPutString[nsComplete, DESCRIPTOR[stringArray]];
String.AppendDecimal[sCopies, qOH.numberCopies];
String.AppendLongDecimal[sLength, qOH.fileSize];
stringArray[0] ← Str[sCopies];
stringArray[1] ← Str[sLength];
PSAsyncMsg.ExpandArrayAndPutString[nsCopiesAndLength, DESCRIPTOR[stringArray]];
END; -- DisplayFinalSpoolInfo
*********************************--
Procedures used by LISTDOCUMENTS:--
DocumentStatusFromQObjStatus: PROCEDURE [qOH: PrintQueue.QueueObjectHandle]
RETURNS [PSCommand.DocumentStatus] = BEGIN
RETURN[SELECT qOH.currentStatus FROM
restart => [pending[restart]],
spooling => [pending[spooling]],
spooled => [pending[spooled]],
decomposing => [inProgress[decomposing]],
decomposed => [inProgress[decomposed]],
marking => [inProgress[marking]],
printed => [completed[printed]],
merging => [inProgress[merging]],
merged => [inProgress[merged]],
forwarding => [inProgress[forwarding]],
forwarded => [completed[forwarded]],
canceledInDecomposer => [canceled[canceledInDecomposer]],
canceledInMarker => [canceled[canceledInMarker]],
canceledInMerger => [canceled[canceledInMerger]],
canceledInForwarder => [canceled[canceledInForwarder]],
canceledInQueue => [canceled[canceledInQueue]],
spoolFailure => [rejected[spoolFailure]],
decomposeFailure => [aborted[decomposeFailure]],
markFailure => [aborted[markFailure]],
mergeFailure => [aborted[mergeFailure]],
forwardFailure => [aborted[forwardFailure]],
sysRestartInSpooler => [aborted[sysRestartInSpooler]],
sysRestartInDecomposer => [aborted[sysRestartInDecomposer]],
sysRestartInMarker => [aborted[sysRestartInMarker]],
sysRestartInMerger => [aborted[sysRestartInMerger]],
sysRestartInForwarder => [aborted[sysRestartInForwarder]],
sysRestartInQueue => [aborted[sysRestartInQueue]],
faxInProgress => [inProgress[faxStatus]],
faxCompleted => [completed[faxStatus]],
faxCanceled => [canceled[faxStatus]],
faxAborted => [aborted[faxStatus]],
ENDCASE => [unknown[]]];
END; --DocumentStatusFromQObjStatus
IDFilterOk: PROCEDURE [filterID, qObjID: PSCommand.DocumentID]
RETURNS [BOOLEAN] = BEGIN
An id gets through the id filter if the id filter is nil or the id matches the id filter exacly.
IF filterID = PSCommand.nullDocumentID THEN RETURN[TRUE]
ELSE BEGIN
IF filterID = qObjID THEN RETURN[TRUE]
ELSE RETURN[FALSE];
END;
END; --IDFilterOk
ListQueueStage: PROCEDURE [
queueStage: PrintQueue.QueueStage, proc: PSCommand.DocumentProc,
filter: QueueObjectFilter, scratchQOH: PrintQueue.QueueObjectHandle,
scratchDocAttributes: PSCommand.DocumentAttributes,
scratchFaxMitData: LONG DESCRIPTOR FOR ARRAY OF PSCommand.FaxTransmitData]
RETURNS [continue: BOOLEANTRUE] = BEGIN
ListQueueStage goes through the documents (referenced by their queue object handle) in the specified queue stage and lists those documents specified by the other elements of the filter: id, file name and sender.
qOH, nextQOH: PrintQueue.QueueObjectHandle;
CopyDocumentAttributes: PROCEDURE = BEGIN
Copies the queue object of the desired document and then copies the attributes from the queue object to the attribute record.
PrintQueue.CopyQueueObject[fromQOH: qOH, toQOH: scratchQOH];
SELECT scratchQOH.option FROM
bansheeDl => scratchDocAttributes^ ← [optionDependent: bansheeDl[]];
d1 => scratchDocAttributes^ ← [optionDependent: d1[]];
fax295 => scratchDocAttributes^ ← [optionDependent: fax295[]];
fax495 => scratchDocAttributes^ ← [optionDependent: fax495[]];
feps9700 => scratchDocAttributes^ ← [optionDependent: feps9700[]];
fx3500 => scratchDocAttributes^ ← [optionDependent: fx3500[]];
raven => scratchDocAttributes^ ← [optionDependent: raven[]];
ENDCASE => ERROR;
scratchDocAttributes.id ← scratchQOH.uid;
scratchDocAttributes.name ← scratchQOH.fileName;
scratchDocAttributes.sender ← scratchQOH.sender;
scratchDocAttributes.recipient ← scratchQOH.recipient;
scratchDocAttributes.errorMessage ← scratchQOH.errorMsg;
scratchDocAttributes.status ← DocumentStatusFromQObjStatus[scratchQOH];
scratchDocAttributes.priority ← LOOPHOLE[scratchQOH.priority]; --PrintQueue.Priority = NSPrint.PriorityHint
scratchDocAttributes.sourceSystemElement ← scratchQOH.sourceSystemElement;
scratchDocAttributes.sizeInBytes ← scratchQOH.fileSize;
scratchDocAttributes.pagesDecomposed ← scratchQOH.platesDecomposed;
scratchDocAttributes.numberOfCopies ← scratchQOH.numberCopies;
scratchDocAttributes.dateReceived ← scratchQOH.fileCreateDate;
scratchDocAttributes.secondsInFormatter ← scratchQOH.decomposeTime;
scratchDocAttributes.completionDate ← scratchQOH.completionDate;
WITH q: scratchQOH SELECT FROM
fax495 => --Copy fax specific data.
WITH d: scratchDocAttributes SELECT FROM
fax495 => BEGIN OPEN d.faxStatus;
localPrint ← LOOPHOLE[q.localPrintStatus];
localPrintCompletionDate ← q.localPrintCompletionDate;
phoneNumberCount ← q.phoneNoCount;
FOR i: CARDINAL IN [0..q.phoneNoCount) DO
scratchFaxMitData[i].phoneNumber ← q.transmitData[i].phoneNumber;
scratchFaxMitData[i].transmit ← LOOPHOLE[q.transmitData[i].status];
scratchFaxMitData[i].retryCount ← q.transmitData[i].retryCount;
scratchFaxMitData[i].willRetry ← q.transmitData[i].queuedForRetry;
scratchFaxMitData[i].completionDate ← q.transmitData[i].completionDate;
scratchFaxMitData[i].phoneCallElapsedTime ← q.transmitData[i].elapsedTime;
scratchFaxMitData[i].errorCode ← q.transmitData[i].errorCode;
ENDLOOP;
transmitData ← DESCRIPTOR[BASE[scratchFaxMitData], q.phoneNoCount];
END;
ENDCASE => ERROR; --Printing option types types disagree
ENDCASE;
END; --CopyDocumentAttributes
qOH ← PrintQueue.Previous[fromQueue: queueStage]; --get last (i.e. newest) document from queue stage
Go through all the documents in the queue stage:
UNTIL qOH = PrintQueue.nilQueueObjectHandle DO
nextQOH ← PrintQueue.Previous[qOH: qOH, fromQueue: queueStage]; --get next older doc from queue stage
Next queue object is gotten here, because after the client proc is called we don't know if the original queue object will even be on the queue stage we are listing.
IF filter.status[qOH.currentStatus]
--If the document has an acceptable queue object status-- THEN
IF StringFilterOk[filter.sender, qOH.sender] THEN
IF StringFilterOk[filter.name, qOH.fileName] THEN
IF IDFilterOk[filter.id, qOH.uid] THEN BEGIN
If the other filters are either nil or match
exactly then list the document.
CopyDocumentAttributes[];
continue ← proc[scratchDocAttributes];
IF NOT continue THEN RETURN;
END;
qOH ← nextQOH;
ENDLOOP;
END; --ListQueueStage
QObjFilterFromClientFilter: PROCEDURE [clientFilter: LONG POINTER TO PSCommand.DocumentFilter, qObjFilter: LONG POINTER TO QueueObjectFilter] = BEGIN
qObjFilter.id ← clientFilter.id;
qObjFilter.name ← clientFilter.name;
qObjFilter.sender ← clientFilter.sender;
qObjFilter.status ← ALL[FALSE];
FOR s: PSCommand.SimpleDocStatus IN PSCommand.SimpleDocStatus DO
IF clientFilter.status[s] THEN SELECT s FROM
pending =>
qObjFilter.status[restart] ← qObjFilter.status[spooling] ←
qObjFilter.status[spooled] ← TRUE;
inProgress =>
qObjFilter.status[decomposing] ← qObjFilter.status[decomposed] ←
qObjFilter.status[marking] ← qObjFilter.status[merging] ←
qObjFilter.status[merged] ← qObjFilter.status[forwarding] ←
qObjFilter.status[faxInProgress] ← TRUE;
completed =>
qObjFilter.status[printed] ← qObjFilter.status[forwarded] ←
qObjFilter.status[faxCompleted] ← TRUE;
completedWithWarnings => NULL;
unknown => NULL;
rejected => qObjFilter.status[spoolFailure] ← TRUE;
aborted =>
qObjFilter.status[decomposeFailure] ←
qObjFilter.status[markFailure] ←
qObjFilter.status[mergeFailure] ←
qObjFilter.status[forwardFailure] ←
qObjFilter.status[sysRestartInSpooler] ←
qObjFilter.status[sysRestartInDecomposer] ←
qObjFilter.status[sysRestartInMarker] ←
qObjFilter.status[sysRestartInMerger] ←
qObjFilter.status[sysRestartInForwarder] ←
qObjFilter.status[sysRestartInQueue] ←
qObjFilter.status[faxAborted] ← TRUE;
canceled =>
qObjFilter.status[canceledInQueue] ←
qObjFilter.status[canceledInDecomposer] ←
qObjFilter.status[canceledInMarker] ←
qObjFilter.status[canceledInMerger] ←
qObjFilter.status[canceledInForwarder] ←
qObjFilter.status[faxCanceled] ← TRUE;
held => NULL;
ENDCASE;
ENDLOOP;
END; --QObjFilterFromClientFilter
StringFilterOk: PROCEDURE [filterString, qObjString: NSString.String]
RETURNS [BOOLEAN] = BEGIN
A string gets through the string filter if the string filter is nil or the string matches the string filter exactly.
IF filterString = nsNil THEN RETURN[TRUE]
ELSE RETURN[NSString.EquivalentStrings[filterString, qObjString]];
END; --StringFilterOk
*********************************--
Procedures used by CONTROL PROCEDURES:--
RequeueDecomposedDocs: PROCEDURE [fromQueue: PrintQueue.QueueStage] = BEGIN
qOH: PrintQueue.QueueObjectHandle ← PrintQueue.Requeue[
fromQueue: fromQueue, toQueue: spooledNormal, position: front];
UNTIL qOH = PrintQueue.nilQueueObjectHandle DO
IF qOH.printObjectHandle # NIL THEN
DecomposerControl.FreeDecomposeObject[qOH.uid];
qOH.printObjectHandle ← NIL;
qOH.currentStatus ← restart;
qOH ← PrintQueue.Requeue[
fromQueue: fromQueue, toQueue: spooledNormal, position: front];
ENDLOOP;
END; --RequeueDecomposedDocs
StopPrintingInternal: PROCEDURE = BEGIN --retry all docs in progress
QUESTION: Why do we free decompose handles of decomposed documents?
ANSWER: For feps9700, at least we MUST requeue decomposed documents or else we end up with documents in the queue with the status "Being formatted" when printing is stopped!
IF state.option = feps9700 THEN BEGIN
ForwardingControl.Stop[status: merged];
MergeControl.Stop[status: restart];
END ELSE
markerProcs.stop[status: restart];
DecomposerControl.Stop[status: restart];
RequeueDecomposedDocs[fromQueue: retransmit];
RequeueDecomposedDocs[fromQueue: decomposed];
[] ← DecomposerControl.Stopped[wait];
IF state.option = feps9700 THEN BEGIN
[] ← ForwardingControl.Stopped[wait];
[] ← MergeControl.Stopped[wait];
END ELSE
[] ← markerProcs.stopped[wait];
END; --StopPrintingInternal
Str: PROCEDURE [s: LONG STRING] RETURNS [ns: NSString.String] = INLINE BEGIN
RETURN[NSString.StringFromMesaString[s]]
END;
END. --PSCommandAImpl
LOG when/who/what
****EARLIER LOG ENTRIES DELETED. See archived version from 8.0.
6-Sep-84 12:58:10 - Jacks - Updated to 9.0 PS interfaces; removed code for aps5; added code for banshee, fax295 and feps9700.
20-Sep-84 13:49:31 - Jacks - Moved the waking up of a dozing raven to Enqueue from DecomposerControlImpl proc.
26-Oct-84 15:03:04 - Jacks - Added code for feps9700.
16-Nov-84 17:19:58 - Jacks - Updated to second round 9.0 interfaces; made use of MiscUtilities.
3-Dec-84 15:59:51 - Jacks - Added call to RotateFonts90 to StartPrinting.
15-Jan-85 15:25:13 - Jacks - Now save staple and twoSided options when present in NSPrint call (CopyPrintOptionsToQueueObject).
18-Jan-85 14:52:40 - Jacks - In StopPrintingInternal: now stop the decomposer before requeuing decomposed docs which eliminates a timing window which allowed an occasional document to end up on the decomposed queue when printing was stopped.
13-Feb-85 15:03:01 - Jacks - FOR 10.0: Removed this module's dependence on NSPrint. Now raise PSCommandExtras.ErrorX instead of NSPrint.Error. Implemented new EnqueueX proc, temporarily defined in PSCommandExtras.
28-Feb-85 10:09:23 - Jacks - Now call RotateFonts90 every time in StartPrinting if the engine is bansheeDl to check if any fonts need to be rotated.
12-Mar-85 11:20:02 - Jacks - Put call to GetFaxDataFromString into CopyDocParametersToQueueObject.
18-Jun-85 15:12:15 - Jacks - Added copyright notice; updated to PS Euclid interfaces.
26-Jun-85 9:55:55 - Jacks - Added d1 specific code to select stmts.
3-Jul-85 9:28:17 - Jacks - Got rid of fax canceled/aborted kludge.
19-Jul-85 11:31:56 - Jacks - Converted to XMessage and QueueFile; created CompleteEnqueue.
7-Aug-85 10:57:36 - Jacks - Updated to 10.0 DecomposerControl.FreeDecomposeObject; made use of NSFile.GetAttributesRecord.
15-Aug-85 16:46:48 - Jacks - Put in kludge for firstPageToPrint or lastPageToPrint = 0.
26-Aug-85 10:37:08 - Jacks - Made QueueObjectFilter status a PACKED ARRAY.
10-Sep-85 15:04:12 - Jacks - Got queueObject, documentAttrRecord and faxMitData out of local frame in ListQueueStage; ListDocuments temporarily exported by PSCommandExtras; default d1 and banshee paper size to what is currently loaded.
24-Sep-85 14:04:34 - Jacks - Put PSCommandExtras stuff into PSCommand.
15-Oct-85 9:41:06 - Jacks - Copy new fax errorCode in CopyDocumentAttributes; improved paper size defaulting in CopyDocParametersToQueueObject.
6-Nov-85 10:17:53 - Jacks - Catch DecomposerControl.DocumentInProgress in StartPrinting.
22-Apr-86 14:07:14 - Jacks - RequeueDecomposedDocs always requeues to front of spooledNormal queue.
1-May-86 17:11:26 - Jacks - Fixed space leak in ListDocuments by adding GOTO stmts.
11-Jun-86 14:03:22 - Jacks - Again fixed space leak in ListDocuments.