DIRECTORY BasicTime USING [Now], FS USING [Close, Copy, Create, Delete, Error, GetName, maxFNameLength, nullOpenFile, Open, OpenFile], IO USING [STREAM], NSString USING [AppendString, String, StringFromMesaString, StringRep, TruncateString], PrintQueue, PrintingTypes USING [Option], PrincOps USING [bytesPerPage, PageCount, wordsPerPage], PrincOpsUtils USING [PagesForWords], Process USING [Detach], PSAsyncMsg USING [ExpandArrayAndPutString], QueueFile, Rope USING [FromRefText, ROPE, ToRefText], System USING [nullID, UniversalID], XMessage USING [StringArray] ; PrintQueueImpl: MONITOR IMPORTS BasicTime, FS, NSString, PrincOpsUtils, Process, PSAsyncMsg, Rope EXPORTS PrintQueue, QueueFile = BEGIN Error: PUBLIC ERROR [errortype: PrintQueue.Errortype] = CODE; InsufficientPages: PUBLIC ERROR = CODE; -- for QueueFile CreateError: PUBLIC ERROR = CODE; -- for QueueFile LocalError: ERROR = CODE; ROPE: TYPE ~ Rope.ROPE; ObjectStatus: TYPE = MACHINE DEPENDENT{pending(0), current(1), complete(2), scavanged(3), unlinked(4), null(maxObjectStatus)}; QueueElement: TYPE = RECORD [ qObject: PrintQueue.QueueObjectHandle _, previous, next: CARDINAL _, stage: PrintQueue.QueueStage _, status: ObjectStatus _, testPattern: BOOLEAN _ FALSE]; NotifyProcs: TYPE = ARRAY PrintQueue.QueueStage OF PrintQueue.NewObjectQueuedProc; Queue: TYPE = ARRAY [0..builtInFixedQueueSize) OF QueueElement; QueueObjectPointer: TYPE = REF QueueObjectArray; QueueObjectArray: TYPE = ARRAY [0..builtInFixedQueueSize) OF PrintQueue.QueueObject; DataRecord: TYPE = RECORD [queue: Queue, qStats: PrintQueue.StatsRecord]; builtInFixedQueueSize: CARDINAL = 40; maxObjectStatus: CARDINAL = 7; maxStringBytes: CARDINAL = PrintQueue.maxStringBytes; nullQueueIndex: CARDINAL = LAST[CARDINAL]; blank: CHAR = ' ; dataSpacePages: PrincOps.PageCount = PrincOpsUtils.PagesForWords[ SIZE[DataRecord] + SIZE[QueueObjectArray] + 1]; printingOption: PrintingTypes.Option _ unknown; initialized: BOOLEAN _ FALSE; -- for safety qFiletrace: QueueFile.TraceLevel _ none; queueObjects: QueueObjectPointer; -- can be declared in Initialize's local frame notifyProc: NotifyProcs _ ALL[NIL]; dataRecord: REF DataRecord _ NIL; spoolDirectory: ROPE _ NIL; -- Is opened/created in the Initialize. Requeue: PUBLIC ENTRY PROCEDURE [ qOH: PrintQueue.QueueObjectHandle _ PrintQueue.nilQueueObjectHandle, fromQueue: PrintQueue.QueueStage, toQueue: PrintQueue.QueueStage, position: PrintQueue.RelativePosition _ back] RETURNS [returnQOH: PrintQueue.QueueObjectHandle] = BEGIN ENABLE UNWIND => NULL; qIndex: CARDINAL _ IF qOH # PrintQueue.nilQueueObjectHandle THEN FindIndex[qOH] ELSE FindFirst[fromQueue]; SELECT TRUE FROM qIndex = nullQueueIndex => RETURN [PrintQueue.nilQueueObjectHandle]; fromQueue = inactive => MakeNull[qIndex]; fromQueue = tpInactive => MakeTPNull[qIndex]; toQueue = inactive => BEGIN IF dataRecord.queue[qIndex].testPattern THEN toQueue _ tpInactive; DeleteFile[dataRecord.queue[qIndex].qObject]; --This used to be done only if qObject wasn't a test pattern; now done for all because test pattern interleaved files need to be deleted for feps9700 and DeleteFile will not succeed in deleting a test pattern interpress file. END; ENDCASE => NULL; returnQOH _ SELECT TRUE FROM qOH # PrintQueue.nilQueueObjectHandle AND dataRecord.queue[qIndex].next # nullQueueIndex => dataRecord.queue[dataRecord.queue[qIndex].next].qObject, --return next qOH # PrintQueue.nilQueueObjectHandle => PrintQueue.nilQueueObjectHandle, ENDCASE => dataRecord.queue[qIndex].qObject; -- return first one IF fromQueue # toQueue THEN BEGIN Unlink[qIndex]; IF position = back THEN AddLast[qIndex, toQueue] ELSE AddFirst[qIndex, toQueue]; END; InternalBackup[]; --Backup the print queue to the backing file. TellClient[toQueue]; END; -- Requeue Next: PUBLIC ENTRY PROCEDURE [ qOH: PrintQueue.QueueObjectHandle _ PrintQueue.nilQueueObjectHandle, fromQueue: PrintQueue.QueueStage] RETURNS [PrintQueue.QueueObjectHandle] = BEGIN ENABLE UNWIND => NULL; qIndex: CARDINAL _ IF qOH # PrintQueue.nilQueueObjectHandle THEN FindIndex[qOH] ELSE FindFirst[fromQueue]; RETURN[SELECT TRUE FROM qIndex = nullQueueIndex AND qOH = PrintQueue.nilQueueObjectHandle --queue must be empty => PrintQueue.nilQueueObjectHandle, qIndex # nullQueueIndex AND qOH = PrintQueue.nilQueueObjectHandle --return first entry => dataRecord.queue[qIndex].qObject, qIndex # nullQueueIndex AND dataRecord.queue[qIndex].next # nullQueueIndex => dataRecord.queue[dataRecord.queue[qIndex].next].qObject, ENDCASE => PrintQueue.nilQueueObjectHandle]; --no more in queue END; -- Next Previous: PUBLIC ENTRY PROCEDURE [ qOH: PrintQueue.QueueObjectHandle _ PrintQueue.nilQueueObjectHandle, fromQueue: PrintQueue.QueueStage] RETURNS [PrintQueue.QueueObjectHandle] = BEGIN ENABLE UNWIND => NULL; qIndex: CARDINAL _ IF qOH # PrintQueue.nilQueueObjectHandle THEN FindIndex[qOH] ELSE FindLast[fromQueue]; RETURN[SELECT TRUE FROM qIndex = nullQueueIndex AND qOH = PrintQueue.nilQueueObjectHandle --queue must be empty => PrintQueue.nilQueueObjectHandle, qIndex # nullQueueIndex AND qOH = PrintQueue.nilQueueObjectHandle --return last entry => dataRecord.queue[qIndex].qObject, qIndex # nullQueueIndex AND dataRecord.queue[qIndex].previous # nullQueueIndex => dataRecord.queue[dataRecord.queue[qIndex].previous].qObject, ENDCASE => PrintQueue.nilQueueObjectHandle]; --no more in queue END; -- Previous Empty: PUBLIC ENTRY PROCEDURE [queue: PrintQueue.QueueStage] RETURNS [BOOLEAN] = BEGIN ENABLE UNWIND => NULL; RETURN[FindFirst[queue] = nullQueueIndex]; END; -- Empty ReserveForTestPattern: PUBLIC ENTRY PROCEDURE [ qOH: PrintQueue.QueueObjectHandle _ PrintQueue.nilQueueObjectHandle, fromQueue: PrintQueue.QueueStage _ inactive, toQueue: PrintQueue.QueueStage _ tpInactive] RETURNS [PrintQueue.QueueObjectHandle] = BEGIN ENABLE UNWIND => NULL; qIndex: CARDINAL _ IF qOH # PrintQueue.nilQueueObjectHandle THEN FindIndex[qOH] ELSE FindFirst[fromQueue]; SELECT TRUE FROM qIndex = nullQueueIndex => RETURN[PrintQueue.nilQueueObjectHandle]; fromQueue = inactive => MakeNull[qIndex]; ENDCASE => NULL; dataRecord.queue[qIndex].testPattern _ TRUE; Unlink[qIndex]; AddLast[qIndex, toQueue]; InternalBackup[]; TellClient[toQueue]; RETURN[dataRecord.queue[qIndex].qObject]; END; -- ReserveForTestPattern ReleaseAsTestPattern: PUBLIC ENTRY PROCEDURE [qOH: PrintQueue.QueueObjectHandle, fromQueue: PrintQueue.QueueStage _ tpInactive, toQueue: PrintQueue.QueueStage _ inactive] = BEGIN ENABLE UNWIND => NULL; qIndex: CARDINAL _ IF qOH # PrintQueue.nilQueueObjectHandle THEN FindIndex[qOH] ELSE FindFirst[fromQueue]; dataRecord.queue[qIndex].testPattern _ FALSE; DeleteFile[dataRecord.queue[qIndex].qObject]; MakeNull[qIndex]; Unlink[qIndex]; AddLast[qIndex, toQueue]; InternalBackup[]; TellClient[toQueue]; END; -- ReleaseAsTestPattern QueueWatcher: PUBLIC ENTRY PROCEDURE [ proc: PrintQueue.NewObjectQueuedProc, queueStage: PrintQueue.QueueStage] = BEGIN ENABLE UNWIND => NULL; IF proc # NIL AND notifyProc[queueStage] # NIL THEN Error[multipleWatchers]; notifyProc[queueStage] _ proc; IF FindFirst[queueStage] # nullQueueIndex THEN TellClient[queueStage]; END; -- QueueWatcher LocateHandle: PUBLIC ENTRY PROCEDURE [fileSent: System.UniversalID] RETURNS [qOH: PrintQueue.QueueObjectHandle _ PrintQueue.nilQueueObjectHandle, queueStage: PrintQueue.QueueStage _ inactive] = BEGIN ENABLE UNWIND => NULL; FOR qIndex: CARDINAL IN [0..builtInFixedQueueSize) DO IF dataRecord.queue[qIndex].qObject.uid = fileSent THEN RETURN[dataRecord.queue[qIndex].qObject, dataRecord.queue[qIndex].stage]; ENDLOOP; END; -- LocateHandle WhereIs: PUBLIC ENTRY PROCEDURE [qOH: PrintQueue.QueueObjectHandle] RETURNS [valid: BOOLEAN, queueStage: PrintQueue.QueueStage] = BEGIN ENABLE UNWIND => NULL; FOR qIndex: CARDINAL IN [0..builtInFixedQueueSize) DO IF dataRecord.queue[qIndex].qObject = qOH THEN RETURN[TRUE, dataRecord.queue[qIndex].stage]; ENDLOOP; RETURN[FALSE, temp --qOH not actually found--]; END; -- WhereIs CopyStringIn: PUBLIC ENTRY PROCEDURE [qOH: PrintQueue.QueueObjectHandle, fromString: NSString.String, toField: PrintQueue.ObjectStringField] = BEGIN -- Copies fromString to qOH.toField ENABLE UNWIND => NULL; truncatedString: NSString.String; toString: NSString.String; IF qOH = PrintQueue.nilQueueObjectHandle THEN Error[nullQueueObject]; toString _ SELECT toField FROM fileName => qOH.fileName, localFileName => qOH.localFileName, sender => qOH.sender, recipient => qOH.recipient, operatorMsg => qOH.operatorMsg, ENDCASE --errorMsg-- => qOH.errorMsg; truncatedString _ NSString.TruncateString[fromString, IF fromString.length < toString.maxLength THEN fromString.length ELSE toString.maxLength]; toString.length _ 0; toString _ NSString.AppendString[toString, truncatedString]; END; -- CopyStringIn GetQueueObject: PUBLIC ENTRY PROCEDURE [] RETURNS [qOH: PrintQueue.QueueObjectHandle] = BEGIN ENABLE UNWIND => NULL; qOH _ NEW[PrintQueue.QueueObject.fax495]; END; -- of GetQueueObject CopyQueueObject: PUBLIC ENTRY PROCEDURE [ fromQOH: PrintQueue.QueueObjectHandle, toQOH: PrintQueue.QueueObjectHandle] = TRUSTED BEGIN ENABLE UNWIND => NULL; Copy: PROC [p: PACKED ARRAY PrintQueue.StringBody OF CHAR] RETURNS [s: NSString.String] = TRUSTED BEGIN s _ NEW[NSString.StringRep[LAST[PrintQueue.StringBody]+1]]; FOR i: PrintQueue.StringBody IN PrintQueue.StringBody DO s[i] _ p[i]; ENDLOOP; END; CopyPhone: PROC [p: PACKED ARRAY [0..PrintQueue.maxPhoneNoLength) OF CHAR] RETURNS [s: NSString.String] = TRUSTED BEGIN s _ NEW[NSString.StringRep[PrintQueue.maxPhoneNoLength]]; FOR i: [0..PrintQueue.maxPhoneNoLength) IN [0..PrintQueue.maxPhoneNoLength) DO s[i] _ p[i]; ENDLOOP; END; Copy4: PROC [p: PACKED ARRAY [0..4) OF CHAR] RETURNS [s: NSString.String] = TRUSTED BEGIN s _ NEW[NSString.StringRep[4]]; FOR i: [0..4) IN [0..4) DO s[i] _ p[i]; ENDLOOP; END; toQOH^ _ fromQOH^; toQOH.fileName _ Copy[toQOH.fileNameBody]; toQOH.localFileName _ Copy[toQOH.localFileNameBody]; toQOH.sender _ Copy[toQOH.senderBody]; toQOH.recipient _ Copy[toQOH.recipientBody]; toQOH.operatorMsg _ Copy[toQOH.operatorMsgBody]; toQOH.errorMsg _ Copy[toQOH.errorMsgBody]; WITH q: toQOH SELECT FROM fax495 => FOR i: CARDINAL IN [0..PrintQueue.maxFaxPhoneNos) DO q.transmitData[i].phoneNumber _ CopyPhone[q.transmitData[i].phoneNumberBody]; q.transmitData[i].errorCode _ Copy4[q.transmitData[i].errorCodeBody]; ENDLOOP; ENDCASE; END; --CopyQueueObject Stats: PUBLIC ENTRY PROCEDURE RETURNS [stats: PrintQueue.StatsRecord] = BEGIN ENABLE UNWIND => NULL; RETURN[dataRecord.qStats]; END; -- Stats ResetStats: PUBLIC ENTRY PROCEDURE = BEGIN dataRecord.qStats _ [statsFrom: BasicTime.Now[], inconsistantAtInit: 0, activity: ALL[0]]; END; -- ResetStats Backup: PUBLIC ENTRY PROCEDURE = BEGIN InternalBackup[]; END; --Backup CreateTempFile: PUBLIC ENTRY PROCEDURE [fName: NSString.String, fBytes: LONG CARDINAL] RETURNS [fileID: FS.OpenFile, fileH: IO.STREAM] = BEGIN ENABLE UNWIND => NULL; trucatedString: NSString.String; CreateFile: PROC = BEGIN fileID _ FS.Create[name: Rope.FromRefText[trucatedString], pages: (fBytes/PrincOps.bytesPerPage)+1]; END; -- CreateFile trucatedString _ NSString.TruncateString[fName, FS.maxFNameLength]; fileID _ FS.nullOpenFile; CreateFile[ ! FS.Error => BEGIN IF qFiletrace # none THEN BEGIN nsCreateFileError: NSString.String = " **CreateFile: <1> !<2>"; stringArray: REF XMessage.StringArray _ NEW[XMessage.StringArray[2]]; stringArray.data[0] _ trucatedString; stringArray.data[1] _ Rope.ToRefText[error.explanation]; PSAsyncMsg.ExpandArrayAndPutString[nsCreateFileError, stringArray]; END; IF error.code = $volumeFull THEN ERROR InsufficientPages ELSE ERROR CreateError; END; ]; END; -- CreateTempFile Delete: PUBLIC ENTRY PROCEDURE [fileID: FS.OpenFile, file: IO.STREAM _ NIL] RETURNS [FS.OpenFile] = BEGIN ENABLE UNWIND => NULL; IF fileID # FS.nullOpenFile THEN FS.Close[fileID ! FS.Error => CONTINUE]; --cause FileDelete Opens it again. FileDelete[fileID ! LocalError => CONTINUE]; RETURN [FS.nullOpenFile]; END; -- Delete MakePermanent: PUBLIC PROCEDURE [file: FS.OpenFile, attrs: NSString.String] = BEGIN [] _ FS.Copy[from: FS.GetName[file].fullFName, to: Rope.FromRefText[attrs], wDir: spoolDirectory] END; -- MakePermanent. SetTrace: PUBLIC PROCEDURE [trace: QueueFile.TraceLevel] = {qFiletrace _ trace}; InternalBackup: INTERNAL PROCEDURE [] = BEGIN END; FindIndex: INTERNAL PROCEDURE [qOH: PrintQueue.QueueObjectHandle] RETURNS [qIndex: CARDINAL] = BEGIN FOR qIndex IN [0..builtInFixedQueueSize) DO IF dataRecord.queue[qIndex].qObject = qOH THEN RETURN[qIndex]; ENDLOOP; ERROR Error[invalidQueueObject]; END; -- FindIndex MakeNull: INTERNAL PROCEDURE [qIndex: CARDINAL] = BEGIN Copy: PROC [p: PACKED ARRAY PrintQueue.StringBody OF CHAR] RETURNS [s: NSString.String] = BEGIN s _ NEW[NSString.StringRep[LAST[PrintQueue.StringBody]+1]]; FOR i: PrintQueue.StringBody IN PrintQueue.StringBody DO s[i] _ p[i]; ENDLOOP; END; qOH: PrintQueue.QueueObjectHandle _ dataRecord.queue[qIndex].qObject; IF dataRecord.queue[qIndex].status # null THEN BEGIN qOH^ _ [ fileName: NEW[NSString.StringRep[maxStringBytes]], localFileName: NEW[NSString.StringRep[maxStringBytes]], sender: NEW[NSString.StringRep[maxStringBytes]], recipient: NEW[NSString.StringRep[maxStringBytes]], operatorMsg: NEW[NSString.StringRep[maxStringBytes]], errorMsg: NEW[NSString.StringRep[maxStringBytes]], optionVariant: unknown[] --Compiler won't accept select stmt (below) here. **AJ 12/20/83 ]; dataRecord.queue[qIndex].status _ null; END; IF qOH.option # printingOption THEN BEGIN --Change printing option if necessary. SELECT printingOption FROM bansheeDl => qOH.optionVariant _ bansheeDl[]; d1 => qOH.optionVariant _ d1[]; fax295 => qOH.optionVariant _ fax295[]; fax495 => qOH.optionVariant _ fax495[]; feps9700 => qOH.optionVariant _ feps9700[]; fx3500 => qOH.optionVariant _ fx3500[]; raven => qOH.optionVariant _ raven[]; ENDCASE => ERROR; WITH q: qOH SELECT FROM fax495 => FOR i: CARDINAL IN [0..PrintQueue.maxFaxPhoneNos) DO q.transmitData[i].phoneNumber _ NEW[NSString.StringRep[PrintQueue.maxPhoneNoLength]]; q.transmitData[i].errorCode _ NEW[NSString.StringRep[4]]; ENDLOOP; ENDCASE; END; END; -- MakeNull MakeTPNull: INTERNAL PROCEDURE [qIndex: CARDINAL] = BEGIN -- assumes STRINGs are still pointing at correct bodies qOH: PrintQueue.QueueObjectHandle _ dataRecord.queue[qIndex].qObject; IF dataRecord.queue[qIndex].status # null THEN BEGIN qOH.fileID _ FS.nullOpenFile; qOH.uid _ System.nullID; qOH.numberCopies _ qOH.platesDecomposed _ 0; qOH.firstPageToPrint _ 1; qOH.lastPageToPrint _ LAST[CARDINAL]; qOH.twoSided _ qOH.staple _ FALSE; qOH.printObjectHandle _ PrintQueue.nilPrintObjectHandle; qOH.currentStatus _ qOH.priorStatus _ null; qOH.bannerOnly _ FALSE; qOH.sender.length _ qOH.recipient.length _ qOH.operatorMsg.length _ qOH.errorMsg.length _ 0; dataRecord.queue[qIndex].status _ null; END; SELECT printingOption FROM --Even if queue object was already null, must initialize it to current printing option. bansheeDl => qOH.optionVariant _ bansheeDl[]; d1 => qOH.optionVariant _ d1[]; fax295 => qOH.optionVariant _ fax295[]; fax495 => qOH.optionVariant _ fax495[]; feps9700 => qOH.optionVariant _ feps9700[]; fx3500 => qOH.optionVariant _ fx3500[]; raven => qOH.optionVariant _ raven[]; ENDCASE => ERROR; WITH q: qOH SELECT FROM fax495 => FOR i: CARDINAL IN [0..PrintQueue.maxFaxPhoneNos) DO q.transmitData[i].phoneNumber _ NEW[NSString.StringRep[PrintQueue.maxPhoneNoLength]]; q.transmitData[i].errorCode _ NEW[NSString.StringRep[4]]; ENDLOOP; ENDCASE; END; -- MakeTPNull DeleteFile: INTERNAL PROCEDURE [qOH: PrintQueue.QueueObjectHandle] = BEGIN IF qOH.deleteInactiveFile AND qOH.fileID # FS.nullOpenFile THEN FileDelete[qOH.fileID ! LocalError => CONTINUE]; qOH.localFileName.length _ 0; qOH.fileID _ FS.nullOpenFile; WITH q: qOH SELECT FROM feps9700 => BEGIN --delete interleaved IP master, if any IF q.ivFileID # FS.nullOpenFile THEN FileDelete[q.ivFileID ! LocalError => CONTINUE]; q.ivFileID _ FS.nullOpenFile; END; ENDCASE; END; -- DeleteFile FileDelete: INTERNAL PROCEDURE [fileID: FS.OpenFile] = BEGIN file: FS.OpenFile; fileError: BOOLEAN _ FALSE; name: ROPE _ FS.GetName[fileID].fullFName; FS.Close[fileID]; FS.Delete[name: name] END; -- FileDelete Unlink: INTERNAL PROCEDURE [qIndex: CARDINAL] = BEGIN OPEN dataRecord; IF queue[qIndex].next # nullQueueIndex THEN queue[queue[qIndex].next].previous _ queue[qIndex].previous; IF queue[qIndex].previous # nullQueueIndex THEN queue[queue[qIndex].previous].next _ queue[qIndex].next; queue[qIndex].previous _ queue[qIndex].next _ nullQueueIndex; queue[qIndex].status _ unlinked; END; -- Unlink AddLast: INTERNAL PROCEDURE [qIndex: CARDINAL, qStage: PrintQueue.QueueStage, objStatus: ObjectStatus _ pending] = BEGIN OPEN dataRecord; -- assumes queue[qIndex] has been Unlinked. IF queue[qIndex].status # unlinked THEN ERROR; -- removable for production queue[qIndex].previous _ FindLast[qStage]; IF queue[qIndex].previous # nullQueueIndex THEN queue[queue[qIndex].previous].next _ qIndex; queue[qIndex].stage _ qStage; queue[qIndex].status _ objStatus; qStats.activity[qStage] _ qStats.activity[qStage] + 1; END; -- AddLast AddFirst: INTERNAL PROCEDURE [qIndex: CARDINAL, qStage: PrintQueue.QueueStage, objStatus: ObjectStatus _ pending] = BEGIN OPEN dataRecord; -- assumes queue[qIndex] has been Unlinked. IF queue[qIndex].status # unlinked THEN ERROR; -- removable for production queue[qIndex].next _ FindFirst[qStage]; IF queue[qIndex].next # nullQueueIndex THEN queue[queue[qIndex].next].previous _ qIndex; queue[qIndex].stage _ qStage; queue[qIndex].status _ objStatus; qStats.activity[qStage] _ qStats.activity[qStage] + 1; END; -- AddFirst FindLast: INTERNAL PROCEDURE [qStage: PrintQueue.QueueStage] RETURNS [qIndex: CARDINAL] = BEGIN OPEN dataRecord; -- returns qIndex of last (latest) entry in queue or nullQueueIndex FOR qIndex IN [0..builtInFixedQueueSize) DO IF queue[qIndex].stage = qStage THEN BEGIN UNTIL queue[qIndex].next = nullQueueIndex DO qIndex _ queue[qIndex].next; ENDLOOP; RETURN[qIndex]; END; ENDLOOP; RETURN[nullQueueIndex]; END; -- FindLast FindFirst: INTERNAL PROCEDURE [qStage: PrintQueue.QueueStage] RETURNS [qIndex: CARDINAL] = BEGIN OPEN dataRecord; -- returns qIndex of first (earliest) entry in queue or nullQueueIndex FOR qIndex IN [0..builtInFixedQueueSize) DO IF queue[qIndex].stage = qStage THEN BEGIN UNTIL queue[qIndex].previous = nullQueueIndex DO qIndex _ queue[qIndex].previous; ENDLOOP; RETURN[qIndex]; END; ENDLOOP; RETURN[nullQueueIndex]; END; -- FindFirst TellClient: INTERNAL PROCEDURE [q: PrintQueue.QueueStage] = TRUSTED BEGIN IF notifyProc[q] # NIL THEN Process.Detach[FORK notifyProc[q]]; END; Initialize: PUBLIC PROCEDURE [directory: REF TEXT, queueEntries: CARDINAL, currentOption: PrintingTypes.Option] RETURNS [queueSize: CARDINAL] = BEGIN nsQueueBackingStore: ROPE = "PrintQueue14.BackingStore"; oldnsQueueBackingStore: ROPE = "PrintQueue10.BackingStore"; file: FS.OpenFile _ FS.nullOpenFile; newBackingFile: BOOLEAN _ FALSE; CreateBackingFile: PROC[] = BEGIN file _ FS.Create[name: nsQueueBackingStore, wDir: Rope.FromRefText[directory], pages: dataSpacePages]; END; -- CreateBackingFile InitializeSpace: PROC = BEGIN OPEN dataRecord; FOR i: CARDINAL IN [0..builtInFixedQueueSize) DO -- Allocate the QueueObjects ENDLOOP; FOR i: CARDINAL IN [1..builtInFixedQueueSize) DO -- backward and forward indexes queue[i].previous _ i - 1; queue[i - 1].next _ i; ENDLOOP; qStats _ [statsFrom: BasicTime.Now[], inconsistantAtInit: 0, activity: ALL[0]]; END; -- InitializeSpace FixSpace: PROC = BEGIN ERROR; END; -- FixSpace CheckData: PROC = BEGIN OPEN dataRecord; END; -- CheckData printingOption _ currentOption; --printingOption is a global var IF initialized THEN ERROR; initialized _ TRUE; FS.Delete[name: oldnsQueueBackingStore, wDir: Rope.FromRefText[directory] ! FS.Error => CONTINUE]; -- delete old one BEGIN --Open new print queue backing file. file _ FS.Open[name: nsQueueBackingStore, wDir: Rope.FromRefText[directory] ! FS.Error => GOTO FileNotFound]; EXITS FileNotFound => {CreateBackingFile[]; newBackingFile _ TRUE; }; END; BEGIN -- Create space for queue data and map it to backing file. END; -- Create space IF newBackingFile THEN InitializeSpace[] ELSE CheckData[]; RETURN [builtInFixedQueueSize]; END; -- Initialize Str: PROCEDURE [s: REF TEXT] RETURNS [ns: NSString.String] = INLINE { RETURN[NSString.StringFromMesaString[s]]}; END. LOG ****EARLIER LOG ENTRIES DELETED. See archived version from 8.0. 17-Sep-84 16:16:12 - Jacks - Updated to new PrintQueue interface for 9.0; added provisions for bansheeDl, fax295 and feps9700/got rid of aps5. 9-Nov-84 11:39:53 - Jacks - DeleteFile now deletes interleaved ip master as well as spool file; added feps9700 stuff to CheckData. 21-Nov-84 14:16:47 - Jacks - When toQueue=inactive, Requeue now calls DeleteFile even if qObject is for test pattern. 17-Jun-85 15:44:28 - Jacks - Added copyright notice; updated to new PS Euclid interfaces. 28-Jun-85 10:37:28 - Jacks - Added d1 variants and went to new backing store; fixed sender/recipient bug in CheckData. 1-Jul-85 16:32:45 - Jacks - New backing store. 23-Jul-85 14:00:43 - Jacks - Updated to Euclid Service interfaces; got rid of QueueData in the DataRecord; deleted GetPages, SetMaxPages and GetDirectory. 13-Aug-85 9:54:54 - Jacks - Initialize firstPageToPrint to 1 instead of 0 in MakeTPNull. 26-Aug-85 10:22:49 - Jacks - Made use of NSFile.GetAttributesRecord in CreateTempFile to reduce local frame size. 9-Sep-85 15:28:12 - Jacks - Added GetQueueObject. 14-Oct-85 17:22:10 - Jacks - Added code for fax495 errorCode. )ŠPrintQueueImpl.mesa Copyright (C) Xerox Corporation 1981, 1982, 1983, 1984, 1985, 1986. All rights reserved. Last edited by Jacks: 14-Oct-85 17:22:25 Tim Diebert: December 29, 1986 10:00:25 am PST <> PSAssignedTypes USING [tBackup, tSpooled], PSVolume USING [GetDefaultSession, GetDirectory], ERRORS TYPES previous points to the front of the queue where the earlier entries are, next points toward the end of the queue where new entries are added. Constants backingStoreFileType: NSFile.Type = PSAssignedTypes.tBackup; tSpool: NSFile.Type = PSAssignedTypes.tSpooled; Globals queueSpace: Space.Interval _ Space.nullInterval; -- to DataRecord in VM session: NSFile.Session = PSVolume.GetDefaultSession[]; ==== ==== ==== ==== ==== ==== PrintQueue PROCEDURES ==== ==== ==== ==== ==== ==== If fromQueue Empty then return nilQueueObjectHandle else next QueueObjectHandle (i.e., from front of fromQueue) position specifies the relative positon of the toQueue; Requeues to inactive queue means that the QueueObject's fid can be deleted. queue must be empty Space.ForceOut[queueSpace]; If qOH=nilQueueObjectHandle then return the QueueObjectHandleat the front of the fromQueue (i.e. the oldest entry on the queue) Else if there's a newer QueueObject on the queue than the specified QueueObject then return it's QueueObjectHandle Else return nilQueueObjectHandle; Queue entries are not removed from the queue and are not displaced in any way. return next If qOH=nilQueueObjectHandle then return the QueueObjectHandle at the back of the fromQueue (i.e. the newest entry on the queue) Else if there's an older QueueObject on the queue than the specified QueueObject then return it's QueueObjectHandle Else return nilQueueObjectHandle; Queue entries are not removed from the queue and are not displaced in any way. return previous Space.ForceOut[queueSpace]; Space.ForceOut[queueSpace]; NOTE: The queue object must always be allocated with the largest variant type, so the client can set the queue object to any variant he wants to. Reset toQOH string pointers correctly: Copies print queue to backing file. (Used in FaxMarkerControlImpl to save information about local print/phone number completions, since Requeue isn't called until the entire job finishes marking.) Space.ForceOut[queueSpace]; ==== ==== ==== ==== ==== ==== QueueFile PROCEDURES ==== ==== ==== ==== ==== ==== selection: NSFile.Selections _ NSFile.noSelections; attribute: NSFile.Attributes _ NSFile.GetAttributesRecord[]; ===================================== ===================================== attrList: ARRAY [0..3) OF NSFile.Attribute _ [ [type[tSpool]], [name[trucatedString]], [dataSize[fBytes]]]; ===================================== selection.interpreted[fileID] _ TRUE; NSFile.GetAttributes[fileH, selection, attribute, session ! NSFile.Error => BEGIN IF qFiletrace # none THEN BEGIN nsCreateFileError: NSString.String = Str[" **CreateFile: <1>; <2>"L]; stringArray: ARRAY [0..2) OF NSString.String; stringArray[0] _ trucatedString; [stringArray[1],] _ MsgOps.FilingErrToMsg[error]; PSAsyncMsg.ExpandArrayAndPutString[nsCreateFileError, DESCRIPTOR[stringArray]]; END; GOTO Error; END; ]; fileID _ attribute.fileID; NSFile.ReleaseAttributesRecord[attribute]; EXITS Error => BEGIN IF fileH # NSFile.nullHandle THEN NSFile.Close[fileH, session ! NSFile.Error => CONTINUE]; ERROR CreateError; END; NSFile.Move[file, spoolDirectory, attrs, session]; ==== ==== ==== ==== ==== ==== INTERNAL PROCEDURES ==== ==== ==== ==== ==== ==== Space.ForceOut[]; attrList: ARRAY [0..1) OF NSFile.Attribute _ [[fileID[fileID]]]; file _ NSFile.Open[ attributes: DESCRIPTOR[attrList], directory: spoolDirectory, session: session ! NSFile.Error => BEGIN IF qFiletrace # none THEN BEGIN nsFileDeleteError: NSString.String = Str[" **FileDelete: Open !<1>"L]; stringArray: ARRAY [0..1) OF NSString.String; [stringArray[0],] _ MsgOps.FilingErrToMsg[error]; PSAsyncMsg.ExpandArrayAndPutString[nsFileDeleteError, DESCRIPTOR[stringArray]]; END; GOTO Error; END]; NSFile.Delete[file, session ! NSFile.Error => BEGIN IF qFiletrace # none THEN BEGIN nsFileDeleteError: NSString.String = Str[" **FileDelete: Delete !<1>"L]; stringArray: ARRAY [0..1) OF NSString.String; [stringArray[0],] _ MsgOps.FilingErrToMsg[error]; PSAsyncMsg.ExpandArrayAndPutString[nsFileDeleteError, DESCRIPTOR[stringArray]]; END; GOTO Error; END]; EXITS Error => LocalError; queue[qIndex].qObject.timeStamp[qStage] _ BasicTime.Now[]; queue[qIndex].qObject.timeStamp[qStage] _ BasicTime.Now[]; ==== ==== ==== ==== INITIALIZATION ==== ==== ==== ==== ==================================================== ==================================================== attrList: ARRAY [0..3) OF NSFile.Attribute _ [ [type[backingStoreFileType]], [dataSize[dataSpaceBytes]], [name[nsQueueBackingStore]]]; ==================================================== ==================================================== queue[i] _ [qObject: @queueObjects[i], previous: nullQueueIndex, next: nullQueueIndex, stage: inactive, status: null]; queue[i].qObject­ _ [ fileName: [ bytes: LOOPHOLE[@queue[i].qObject.fileNameBody], length: 0, maxlength: maxStringBytes], localFileName: [ bytes: LOOPHOLE[@queue[i].qObject.localFileNameBody], length: 0, maxlength: maxStringBytes], sender: [ bytes: LOOPHOLE[@queue[i].qObject.senderBody], length: 0, maxlength: maxStringBytes], recipient: [ bytes: LOOPHOLE[@queue[i].qObject.recipientBody], length: 0, maxlength: maxStringBytes], operatorMsg: [ bytes: LOOPHOLE[@queue[i].qObject.operatorMsgBody], length: 0, maxlength: maxStringBytes], errorMsg: [ bytes: LOOPHOLE[@queue[i].qObject.errorMsgBody], length: 0, maxlength: maxStringBytes], optionVariant: unknown[] --Compiler won't accept select stmt (below) here. **AJ 12/20/83 ]; SELECT currentOption FROM bansheeDl => queue[i].qObject.optionVariant _ bansheeDl[]; d1 => queue[i].qObject.optionVariant _ d1[]; fax295 => queue[i].qObject.optionVariant _ fax295[]; fax495 => queue[i].qObject.optionVariant _ fax495[]; feps9700 => queue[i].qObject.optionVariant _ feps9700[]; fx3500 => queue[i].qObject.optionVariant _ fx3500[]; raven => queue[i].qObject.optionVariant _ raven[]; ENDCASE => ERROR; WITH q: queue[i].qObject SELECT FROM fax495 => FOR j: CARDINAL IN [0..PrintQueue.maxFaxPhoneNos) DO q.transmitData[j].phoneNumber _ [ bytes: LOOPHOLE[@q.transmitData[j].phoneNumberBody], length: 0, maxlength: PrintQueue.maxPhoneNoLength]; q.transmitData[j].errorCode _ [ bytes: LOOPHOLE[@q.transmitData[j].errorCodeBody], length: 0, maxlength: 4]; ENDLOOP; ENDCASE; Space.ForceOut[queueSpace]; ==================================================== ==================================================== FOR i: CARDINAL IN [0..builtInFixedQueueSize) DO -- check the queueObjects' files queue[i].qObject _ @queueObjects[i]; ensure that strings are pointing at correct location queue[i].qObject.fileName.bytes _ LOOPHOLE[@queue[i].qObject.fileNameBody]; queue[i].qObject.localFileName.bytes _ LOOPHOLE[@queue[i].qObject.localFileNameBody]; queue[i].qObject.sender.bytes _ LOOPHOLE[@queue[i].qObject.senderBody]; queue[i].qObject.recipient.bytes _ LOOPHOLE[@queue[i].qObject.recipientBody]; queue[i].qObject.operatorMsg.bytes _ LOOPHOLE[@queue[i].qObject.operatorMsgBody]; queue[i].qObject.errorMsg.bytes _ LOOPHOLE[@queue[i].qObject.errorMsgBody]; WITH q: queue[i].qObject SELECT FROM fax495 => FOR j: CARDINAL IN [0..PrintQueue.maxFaxPhoneNos) DO q.transmitData[j].phoneNumber.bytes _ LOOPHOLE[@q.transmitData[j].phoneNumberBody]; q.transmitData[j].errorCode.bytes _ LOOPHOLE[@q.transmitData[j].errorCodeBody]; ENDLOOP; feps9700 => Check for interleaved interpress master file: IF q.ivFileID # NSFile.nullID THEN BEGIN fH: NSFile.Handle _ NSFile.OpenByReference[ reference: NSFile.MakeReference[q.ivFileID], session: session ! NSFile.Error => GOTO MergedFileNotFound]; NSFile.Close[file: fH, session: session]; EXITS MergedFileNotFound => Only docs on merged and forwarding queues should have permanent interleaved files. If permanent files are not found for those docs, something is wrong. IF queue[i].stage = merged OR queue[i].stage = forwarding THEN BEGIN q.ivFileID _ NSFile.nullID; -- ?????? qStats.inconsistantAtInit _ qStats.inconsistantAtInit + 1; [] _ Requeue[queue[i].qObject, queue[i].stage, inactive]; END ELSE q.ivFileID _ NSFile.nullID; END; ENDCASE; queue[i].qObject.printObjectHandle _ NIL; --Bands List and Font Load were temp files Check for spooled file: IF queue[i].qObject.fileID # NSFile.nullID THEN BEGIN fH: NSFile.Handle _ NSFile.OpenByReference[ reference: NSFile.MakeReference[queue[i].qObject.fileID], session: session ! NSFile.Error => GOTO FileNotFound]; NSFile.Close[file: fH, session: session]; EXITS FileNotFound => BEGIN queue[i].testPattern _ FALSE; queue[i].qObject.fileID _ NSFile.nullID; -- ?????? qStats.inconsistantAtInit _ qStats.inconsistantAtInit + 1; [] _ Requeue[queue[i].qObject, queue[i].stage, inactive]; END; END ELSE -- queue[i].qObject.fileID = NSFile.nullID IF (queue[i].qObject.localFileName.length # 0 OR queue[i].stage # inactive) AND (queue[i].stage # merged --spooled file was deleted for AND queue[i].stage # forwarding --feps9700 merged files AND queue[i].stage # forwarded) THEN BEGIN queue[i].testPattern _ FALSE; qStats.inconsistantAtInit _ qStats.inconsistantAtInit + 1; [] _ Requeue[queue[i].qObject, queue[i].stage, inactive]; END; ENDLOOP; Space.ForceOut[queueSpace]; ==================================================== dataRecord _ NEW[DataRecord]; queueSpace _ NSSegment.Map[ origin: origin, access: NSFile.fullAccess, swapUnits: [uniform[3]], session: session]; 3 page swap units because QueueObject is between 2 and 3 pages big dataRecord _ queueSpace.pointer; queueObjects _ LOOPHOLE[dataRecord + SIZE[DataRecord], LONG POINTER]; spoolDirectory _ PSVolume.GetDirectory[tSpool]; Κ˜codešœ™KšœX™XKšœ(™(K™.—K˜™C™UK™N—™K™fK™/Kšœ7Οkœœ ™Ršœ$œœ™`K™M—šœV™\Kšœ/™7———K˜š ˜ Kšœ œ˜Kšœœ]˜eKšœœœ˜Kšœ œI˜WK˜ Kšœœ ˜Kšœ œ)˜7Kšœœ˜$Kšœœ ˜Kšœœ™*Kšœ œ˜+Kšœ œ#™1K˜ Kšœœœ ˜*Kšœœ˜#Kšœ œ˜Kšœ˜—K˜šΠlnœ˜Kšœ œ5˜JKšœ˜Kš˜—˜Kšœ™—˜KšΟnœœœ%œ˜=Kš ŸœœœœΟc˜9Kš Ÿ œœœœ ˜3KšŸ œœœ˜—˜Kšœ™K˜Kšœœœ˜K˜K˜Kšœœœ œX˜~šœœœ˜K˜(šœœ˜Kšœ™—K˜K˜Kšœ œœ˜—Kšœ œœœ ˜RKšœœœœ˜?Kšœœœ˜0Kšœœœœ˜TKšœ œœ0˜I—˜Kšœ ™ —˜Kšœœ˜%Kšœœ˜Kšœœ˜5Kšœœœœ˜*Kšœœ˜šœA˜AKšœœ˜/—K™<™/K˜—Kšœ™—˜K˜/Kšœ œœ  ˜,K˜(Kšœ# .˜QKšœœœ˜#Kšœ2 ™HKšœ œœ˜!Kšœœœ '˜D™7K˜—Kšœ™Kšœ™Kšœ™—˜š Ÿœœœ œ·œ,˜Kšœœœ˜Kšœ§™§KšœK™Kšœœœ&˜;Kšœœ˜.—šœœ˜Kšœœ#˜DK˜)K˜-šœ˜Kšœ&œ˜BKšœ. α˜Kšœ˜—Kšœœ˜—šœ œœ˜Kšœ%œm  ˜£˜IKšœ™—Kšœ' ˜A—šœœ˜!K˜Kšœœœ˜PKšœ˜—K™Kšœ -˜?K˜Kšœ  ˜——˜š Ÿœœœ œjœ!˜΄Kšœœœ˜Kšœ™Kšœr™rKšœ!™!KšœN™Nšœœœ&˜;Kšœœ˜.—šœœœ˜šœœ( ˜XK˜#—šœœ( ˜WK˜$—šœœ/˜JKšœ ™ K˜;—Kšœ' ˜@—Kšœ ˜ ——˜š Ÿœœœ œjœ!˜ΈKšœœœ˜Kšœ™Kšœs™sKšœ!™!KšœN™Nšœœœ&˜;Kšœœ˜-—šœœœ˜šœœ( ˜XK˜#—šœœ( ˜VK˜$—šœœ3˜NKšœ™K˜?—Kšœ' ˜@—Kšœ  ˜——˜š Ÿœœœ œ œœ˜PKš œœœœœ%œ ˜V——˜š Ÿœœœ œ‘œ!˜ύKšœœœ˜šœœœ&˜;Kšœœ˜.—šœœ˜Kšœœ"˜CK˜)Kšœœ˜—Kšœ'œ˜,K˜K˜K˜K™K˜Kšœ#˜)Kšœ ˜K˜—š Ÿœœœ œ€˜²Kšœœœ˜šœœœ&˜;Kšœœ˜.—Kšœ'œ˜-K˜-K˜K˜K˜K˜K™K˜Kšœ ˜K˜—š Ÿ œœœ œM˜wKšœœœ˜Kš œœœœœ˜LK˜Kšœ(œ˜FKšœ ˜K˜—š Ÿ œœœ œœv˜ΗKšœœœ˜šœ œœ˜5šœ1˜7KšœC˜I—Kšœ˜—Kšœ ˜——˜š Ÿœœœ œ$œ œ&˜‡Kšœœœ˜šœ œœ˜5šœ(˜.Kšœœ"˜-—Kšœ˜—Kšœœ œ˜/Kšœ  ˜——˜š Ÿ œœœ œjœ $˜ΊKšœœœ˜K˜!Kšœ˜Kšœ'œ˜Ešœ œ ˜K˜K˜#K˜K˜K˜Kšœ  œ˜%—˜5šœ'˜)Kšœœ˜0——K˜K˜KšœM˜MKšœE˜EKšœ˜—Kšœ˜—Kšœ ˜——˜š Ÿœœœ œœ"˜GKš œœœœœœ ˜FK˜—š Ÿ œœœ œ˜*KšœRœ˜ZKšœ  ˜K˜—š Ÿœœœ œ˜&KšœΔ™ΔK˜K™Kšœ ˜ K˜K˜—Kšœ™Kšœ™Kšœ™—˜š Ÿœœœ œ"œœ˜VKšœ œœœ˜1Kšœœœœ˜K˜ K™3K™Kšœœ2˜UKšœœ˜9Kšœ˜—Kšœ˜—Kšœ˜—Kšœ  ˜——˜š Ÿ œœ œ œœ 7˜rK˜Ešœ(œ˜4Kšœ œ˜K˜K˜,K˜Kšœœœ˜%Kšœœ˜"K˜8K˜+Kšœœ˜K˜\K˜'Kšœ˜—šœœ W˜rK˜-K˜K˜'K˜'K˜+K˜'K˜%Kšœœ˜—šœœ˜šœ œœœ ˜>Kšœ œ2˜UKšœœ˜9Kšœ˜—Kšœ˜—Kšœ  ˜——˜šŸ œœ œ&˜JKš œœœœ'œ˜pK˜Kšœ œ˜šœœ˜šœ œ &˜8Kšœœœ'œ˜UKšœ œ˜Kšœ˜—Kšœ˜—Kšœ  ˜K˜—š Ÿ œœ œ œ ˜K™—™ Kšœœ,™;K™—Kšœ ?™XK™—šœ™K™:K™,K™4K™4K™8K™4K™2Kšœœ™—šœœ™$šœ œœœ ™>™!Kšœœ%™4K™3—™Kšœœ#™2K™—Kšœ™—Kšœ™—Kšœ˜—š œœœœ ˜QKšœ2œ˜:—KšœGœ˜OK™Kšœ ˜—K™Kšœ4™4Kš Ÿœœœœœ  ˜/Kšœ4™4K˜šŸ œœœœ ˜(š œœœœ  ™RK™$Kšœ4™4Kšœ"œ!™KKšœ'œ&™UKšœ œ™GKšœ#œ"™MKšœ%œ$™QKšœ"œ!™Kšœœ™$šœ œœœ ™>Kšœ% œ%™SKšœ# œ#™OKšœ™—™ Kšœ-™-šœœ™(™+K™?Kšœœ™)—K™)š™™Kšœ5™5Kšœ0™0Kšœ1™1šœœœ™DKšœ  ™&K™:K™9Kš™—Kšœ™ ——Kšœ™——Kšœ™K™—Kšœ%œ *™TK™Kšœ™šœ)œ™5™+K™LKšœœ™#—K™)š™šœ™Kšœœ™Kšœ*  ™3K™:K™9Kšœ™——Kš™—šœ *™0šœ+™-Kšœ™Kšœ ™>Kšœ ™7Kšœœ™*Kšœœ™K™:K™9Kšœ™——Kšœ™—K™Kšœ  ˜—K™Kšœ4™4K˜Kšœ   ˜@K˜Kšœ œœ˜Kšœœ˜K˜K–R[name: ROPE, wantedCreatedTime: GMT _ OPAQUE#17777777777B, wDir: ROPE _ NIL]šœJœ œ ˜tšœ $˜*–†[name: ROPE, lock: FS.Lock _ read, wantedCreatedTime: GMT _ OPAQUE#17777777777B, remoteCheck: BOOL _ TRUE, wDir: ROPE _ NIL]šœœB˜KKšœœ œ˜!—Kšœ8œ˜EKšœ˜—šœ :˜AKšœ œ ™™™VKšœB™B——K™ Kš œœœœœ™EKšœ ˜—Kšœœœ ˜:K™/Kšœ˜Kšœ  ˜K˜—š Ÿœ œœœœœ˜EKšœ$˜*——˜Kšœ˜—K˜K˜Kš˜Kš œœœœœ!˜@˜K˜‚—K˜uKšœDœ˜Y˜vK˜.—K˜šK˜Y˜qK˜1—K˜>—…—Tΰo