<> DIRECTORY ControlMessages USING [Key], ForwardingControl USING [CancelProc, TraceLevel, WaitChoice], MiscUtilities USING [KeyForCommunicationStatus], NSFile USING [Attribute, Close, Error, Handle, Open, nullHandle, nullTime, Session, Time], NSString USING [String, StringFromMesaString], PaperTypes USING [Paper], PrintingTypes USING [Option], PrintQueue USING [Empty, nilQueueObjectHandle, Priority, ObjectStatus, QueueObjectHandle, QueueStage, QueueWatcher, Requeue], Process USING [Detach, Pause, Priority, SecondsToTicks, SetPriority, SetTimeout], PSAssignedTypes USING [tSpooled], PSAsyncMsg USING [ExpandArrayAndPutString, Insert, Proc, PutMesaString], PSKMessages USING [GetHandle], PSVolume USING [GetDefaultSession, GetDirectory], String USING [AppendDecimal, AppendLongDecimal, Overflow, StringBoundsFault], System USING [gmtEpoch, GetGreenwichMeanTime, NetworkAddress, nullNetworkAddress, nullID, Overflow, SecondsSinceEpoch, UniversalID], TargetPS USING [Error, ForwardDocument], TargetPSStatus USING [Communication], XMessage USING [Handle, MsgKey]; ForwardingControlImpl: CEDAR MONITOR IMPORTS MiscUtilities, NSFile, NSString, PrintQueue, Process, PSAsyncMsg, PSKMessages, PSVolume, String, System, TargetPS EXPORTS ForwardingControl = BEGIN Control: TYPE = RECORD [ stop: BOOLEAN _ TRUE, start: BOOLEAN _ FALSE, jobQueueEntry: BOOLEAN _ FALSE, tpQueueEntry: BOOLEAN _ FALSE ]; State: TYPE = RECORD [ stopped: BOOLEAN _ TRUE, forwarding: BOOLEAN _ FALSE, lastForwardingStatus: TargetPSStatus.Communication _ okay, targetPS: XNS.Address _ XNS.nullAddress, tpJob: BOOLEAN _ FALSE, file: FS.OpenFile _ FS.nullOpenFile, trace: ForwardingControl.TraceLevel _ none, qOH: PrintQueue.QueueObjectHandle _ PrintQueue.nilQueueObjectHandle, stopStatus: PrintQueue.ObjectStatus _ canceledInForwarder, --specified in Stop call canceledWhileForwarding: ForwardingControl.CancelProc _ NIL, putAsyncMsgFromKey: PSAsyncMsg.Proc _ NIL, startForwardingTime: BasicTime.GMT _ BasicTime.nullGMT ]; event: CONDITION; stopped: CONDITION; control: Control _ []; state: State _ []; controlMsgs: XMessage.Handle _ PSKMessages.GetHandle[control]; Init: PUBLIC ENTRY PROCEDURE [currentOption: PrintingTypes.Option, priority: Process.Priority, putAsyncMsgFromKey: PSAsyncMsg.Proc] = TRUSTED BEGIN ENABLE UNWIND => NULL; IF currentOption # feps9700 THEN ERROR; state _ [putAsyncMsgFromKey: putAsyncMsgFromKey]; PrintQueue.QueueWatcher[proc: JobQueueEntry, queueStage: merged]; PrintQueue.QueueWatcher[proc: TPQueueEntry, queueStage: tpMerged]; Process.SetTimeout[@event, Process.SecondsToTicks[seconds: 30]]; --check queue every 30 secs Process.Detach[FORK ForwardingControlLoop[priority]]; END; --Init Start: PUBLIC ENTRY PROCEDURE = BEGIN ENABLE UNWIND => NULL; control.start _ TRUE; control.stop _ FALSE; NOTIFY event; END; --Start Stop: PUBLIC ENTRY PROCEDURE [status: PrintQueue.ObjectStatus, canceledWhileForwarding: ForwardingControl.CancelProc _ NIL] = BEGIN ENABLE UNWIND => NULL; state.stopStatus _ status; state.canceledWhileForwarding _ canceledWhileForwarding; control.stop _ TRUE; control.start _ FALSE; NOTIFY event; END; --Stop Stopped: PUBLIC ENTRY PROCEDURE [wither: ForwardingControl.WaitChoice _ dontWait] RETURNS [BOOLEAN] = BEGIN ENABLE UNWIND => NULL; IF wither = wait THEN UNTIL state.stopped DO WAIT stopped; ENDLOOP; RETURN [state.stopped]; END; --Stopped Status: PUBLIC PROCEDURE RETURNS [ forwarding: BOOLEAN, --returns TRUE if forwarding in progress forwardingStatus: TargetPSStatus.Communication --valid if forwarding = TRUE--] = BEGIN ENABLE UNWIND => NULL; forwarding _ state.forwarding; forwardingStatus _ state.lastForwardingStatus; END; --Status SetTargetPrintService: PUBLIC ENTRY PROCEDURE [address: XNS.Address] = BEGIN ENABLE UNWIND => NULL; state.targetPS _ address; END; --SetTargetPrintService ModifyTraceLevel: PUBLIC ENTRY PROCEDURE [trace: ForwardingControl.TraceLevel] = BEGIN ENABLE UNWIND => NULL; state.trace _ trace; END; --ModifyTraceLevel JobQueueEntry: ENTRY PROCEDURE = BEGIN -- called by PrintQueue ENABLE UNWIND => NULL; control.jobQueueEntry _ TRUE; NOTIFY event; IF state.trace = verbose THEN PSAsyncMsg.PutMesaString["//Forwarding JobQEntry"]; END; --JobQueueEntry TPQueueEntry: ENTRY PROCEDURE = BEGIN --called by PrintQueue when TestPattern is queued ENABLE UNWIND => NULL; control.tpQueueEntry _ TRUE; NOTIFY event; IF state.trace = verbose THEN PSAsyncMsg.PutMesaString["//Forwarding TPQEntry"]; END; --TPQueueEntry ForwardingControlLoop: ENTRY PROCEDURE [priority: Process.Priority] = BEGIN ENABLE UNWIND => NULL; Process.SetPriority[priority]; DO --forever SELECT TRUE FROM control.tpQueueEntry AND NOT state.forwarding => BEGIN --over-rides state.stopped state.qOH _ PrintQueue.Requeue[fromQueue: tpMerged, toQueue: forwarding]; IF state.qOH = PrintQueue.nilQueueObjectHandle THEN BEGIN control.tpQueueEntry _ FALSE; LOOP; END; state.tpJob _ TRUE; ForwardDocument[]; END; control.stop => BEGIN --disables forwarding; forwarding in progress is aborted SELECT TRUE FROM state.forwarding => NULL; ENDCASE => BEGIN control.stop _ FALSE; state.stopped _ TRUE; NOTIFY stopped; END; END; control.start => BEGIN state.stopped _ control.start _ FALSE; -- so we don't keep looking here LOOP; -- make another pass END; state.stopped => NULL; state.forwarding => NULL; --so we don't start multiple forwarding operations control.jobQueueEntry => BEGIN state.qOH _ PrintQueue.Requeue[fromQueue: merged, toQueue: forwarding]; IF state.qOH = PrintQueue.nilQueueObjectHandle THEN BEGIN control.jobQueueEntry _ FALSE; LOOP; END; ForwardDocument[]; END; ENDCASE; WAIT event; ENDLOOP; END; --ForwardingControlLoop ForwardDocument: INTERNAL PROCEDURE = BEGIN state.lastForwardingStatus _ okay; --reset before trying to forward new document state.forwarding _ TRUE; state.qOH.currentStatus _ forwarding; Process.Detach[FORK DoForwarding[]]; END; --ForwardDocument DoForwarding: PROCEDURE = BEGIN stringArray: ARRAY [0..2) OF NSString.String; sForwarding: LONG STRING = "//Forwarding ""<1>""; Attempt number: <2>"L; nsForwarding: NSString.String = Str[sForwarding]; sAttempts: LONG STRING _ [10]; forwardingAttempts: CARDINAL _ 0; requestID: System.UniversalID _ System.nullID; WITH q: state.qOH SELECT FROM feps9700 => BEGIN attributesList: ARRAY [0..1) OF NSFile.Attribute; spoolDirectory: NSFile.Handle _ PSVolume.GetDirectory[PSAssignedTypes.tSpooled]; attributesList[0] _ [fileID[q.ivFileID]]; --ID of merged file state.file _ NSFile.Open[ attributes: DESCRIPTOR[attributesList], directory: spoolDirectory, session: session ! NSFile.Error => { PSAsyncMsg.PutMesaString["//CAN'T OPEN MERGED FILE!"L]; GOTO Abort}]; state.startForwardingTime _ BasicTime.Now[]; DO --Keep trying to forward the document until success or cancellation: BEGIN forwardingAttempts _ forwardingAttempts + 1; IF state.trace # none THEN BEGIN stringArray[0] _ state.qOH.fileName; sAttempts.length _ 0; String.AppendDecimal[s: sAttempts, n: forwardingAttempts]; stringArray[1] _ Str[sAttempts]; PSAsyncMsg.ExpandArrayAndPutString[nsForwarding, DESCRIPTOR[stringArray]]; END; q.targetRequestID _ TargetPS.ForwardDocument[ target: state.targetPS, master: state.file, docName: state.qOH.fileName, sender: state.qOH.sender, recipient: state.qOH.recipient, message: state.qOH.operatorMsg, copies: IF state.qOH.bannerOnly THEN 1 ELSE state.qOH.numberCopies, paper: state.qOH.paper, docCreateDate: state.qOH.fileCreateDate, priority: state.qOH.priority, staple: state.qOH.staple, twoSided: state.qOH.twoSided ! TargetPS.Error => { IF state.lastForwardingStatus # why THEN DisplayForwardingStatus[why]; state.lastForwardingStatus _ why; q.forwardingStatus _ why; --update print queue GOTO TryAgain}]; EXITS TryAgain => BEGIN IF control.stop = TRUE THEN GOTO Stop; IF state.lastForwardingStatus # remoteSystemElementNotResponding THEN Process.Pause[Process.SecondsToTicks[30]]; LOOP; END; END; EXIT; --Will always exit loop unless a signal is caught. ENDLOOP; IF state.lastForwardingStatus # okay THEN DisplayForwardingStatus[okay]; state.lastForwardingStatus _ okay; Queue[status: forwarded]; END; --of state.qOH select stmt ENDCASE => ERROR; --engine # feps9700 EXITS Abort => Queue[status: forwardFailure]; Stop => Queue[status: state.stopStatus]; END; --DoForwarding Queue: ENTRY PROCEDURE [status: PrintQueue.ObjectStatus] = BEGIN ENABLE UNWIND => NULL; IF state.qOH = PrintQueue.nilQueueObjectHandle THEN BEGIN IF state.trace # none THEN PSAsyncMsg.PutMesaString["##Can't Queue nilQOH! "]; RETURN; END; IF state.trace # none THEN BEGIN forwardTime: LONG CARDINAL _ 0; sDoneForwarding: LONG STRING _ "//Done Forwarding ""<1>""; status= <2>; seconds= <3>"L; sSeconds: LONG STRING _ [10]; nsDoneForwarding: NSString.String _ Str[sDoneForwarding]; stringArray: ARRAY [0..3) OF NSString.String; startSinceEpoch: LONG CARDINAL _ System.SecondsSinceEpoch[state.startForwardingTime]; endSinceEpoch: LONG CARDINAL _ System.SecondsSinceEpoch[System.GetGreenwichMeanTime[]]; IF endSinceEpoch >= startSinceEpoch THEN forwardTime _ endSinceEpoch - startSinceEpoch; stringArray[0] _ state.qOH.fileName; stringArray[1] _ Str[SELECT status FROM merged => "merged"L, canceledInForwarder => "canceledInForwarder"L, forwardFailure => "forwardFailure"L, ENDCASE => "forwarded"L]; String.AppendLongDecimal[sSeconds, forwardTime ! System.Overflow, String.Overflow, String.StringBoundsFault => CONTINUE]; stringArray[2] _ Str[sSeconds]; PSAsyncMsg.ExpandArrayAndPutString[nsDoneForwarding, DESCRIPTOR[stringArray]] END; state.qOH.currentStatus _ status; IF state.file # NSFile.nullHandle THEN NSFile.Close[state.file, session]; --close interleaved ip file SELECT TRUE FROM status = merged => BEGIN [] _ PrintQueue.Requeue[ qOH: state.qOH, fromQueue: forwarding, toQueue: merged, position: front]; END; status = canceledInForwarder => BEGIN [] _ PrintQueue.Requeue[ qOH: state.qOH, fromQueue: forwarding, toQueue: aborted]; IF state.canceledWhileForwarding # NIL THEN state.canceledWhileForwarding[state.qOH.fileName, status]; END; status # forwarded => [] _ PrintQueue.Requeue[ qOH: state.qOH, fromQueue: forwarding, toQueue: aborted]; ENDCASE => [] _ PrintQueue.Requeue[ qOH: state.qOH, fromQueue: forwarding, toQueue: forwarded]; state.file _ NSFile.nullHandle; state.forwarding _ state.tpJob _ FALSE; state.qOH _ PrintQueue.nilQueueObjectHandle; control.jobQueueEntry _ NOT PrintQueue.Empty[merged]; control.tpQueueEntry _ NOT PrintQueue.Empty[tpMerged]; NOTIFY event; -- in case there's something to do END; --Queue DisplayForwardingStatus: PROCEDURE [why: TargetPSStatus.Communication] = BEGIN insertArray: ARRAY [0..1) OF PSAsyncMsg.Insert _ ALL[]; insertArray[0].m _ MiscUtilities.KeyForCommunicationStatus[why]; state.putAsyncMsgFromKey[ msg: [domain: controlMsgs, key: XKey[mForwardingError]], insertArray: DESCRIPTOR[insertArray]]; END; --DisplayForwardingStatus XKey: PROCEDURE [key: ControlMessages.Key] RETURNS [xKey: XMessage.MsgKey] = {RETURN[ORD[key]]}; Str: PROCEDURE [s: REF TEXT] RETURNS [ns: NSString.String] = INLINE { RETURN[NSString.StringFromMesaString[s]]}; END. -- of ForwardingControlImpl LOG when/who/what 22-Oct-84 10:44:03 - Jacks - Created. 29-Oct-84 11:53:06 - Jacks - Added bannerOnly reference in call to ForwardDocument; added call to TargetPS.ForwardDocument. 16-Nov-84 12:05:05 - Jacks - Updated to second round of 9.0 ps interface changes. 29-Nov-84 15:55:11 - Jacks - Store forwarding status in queue; status=merged NOT restart for retrying. 17-Jan-85 14:46:42 - Jacks - Added reset of lastForwardingStatus in ForwardDocument proc; added prefix "ps" to msg keys for 9.0. 23-Jan-85 15:29:23 - Jacks - Changed retry pause when forwarding error back to 30 sec. 8-Mar-85 15:21:03 - Jacks - Changes to handling forwarding errors: only display one msg for each type of error encountered, display "okay" when successful, don't wait before retrying on remoteSystemElementNotResponding. 17-Jun-85 16:16:35 - Jacks - Added copyright notice; updated to PS Euclid interfaces. 19-Jul-85 18:00:52 - Jacks - Updated to XMessage. 6-Nov-85 14:03:00 - Jacks - Get msg handle from PSKMessages. €ForwardingControlImpl.mesa Copyright (C) Xerox Corporation 1984, 1985. All rights reserved. Last edited by Jacks 6-Nov-85 14:03:03 Tim Diebert: December 29, 1986 11:17:25 am PST Message domain handle: session: NSFile.Session = PSVolume.GetDefaultSession[]; If we're currently forwarding, wait for forwarding proc to notice control.stop and quit forwarding. Then event will be notified again in Queue and we'll come around to the ENDCASE and set stopped to TRUE. First open the interleaved interpress master (merged) file: Pause before retrying, unless Target PS is not responding, in which case we've already waited a long time... Κ Ά˜codešœ™Kšœ@™@Kšœ'™'Kšœ.™.—K˜Kšœ4ΟkœKœ˜ˆK˜š ˜ Kšœœ˜Kšœœ&˜=Kšœœ˜0KšœœN˜ZKšœ œ ˜.Kšœ œ ˜Kšœœ ˜Kšœ œm˜}KšœœD˜QKšœœ ˜!Kšœ œ8˜HKšœ œ ˜Kšœ œ#˜1KšœœA˜MKšœœx˜„Kšœ œ˜(Kšœœ˜%Kšœ œ˜ —K˜šΠlnœœ˜$Kšœr˜yKšœ˜Kš˜K˜šœ œœ˜Kšœœœ˜Kšœœœ˜Kšœœœ˜Kšœœ˜K˜—K˜šœœœ˜Kšœ œœ˜Kšœ œœ˜K˜:Kšœ œ œ ˜(Kšœœœ˜Kšœœ œ˜$K˜+K˜DKšœ;Οc˜SKšœ8œ˜K˜—K™7K˜š Οnœœœ œjœ˜“Kšœœœ˜K˜Kšœœœ˜'K˜˜1K˜—K˜A˜CK˜—KšœAŸ˜\Kšœœ"˜5KšœŸ˜ ——˜K˜š  œœœ œ˜%Kšœœœ˜Kšœœ˜Kšœœ˜Kšœ˜ KšœŸ˜ K˜——˜š  œœœ œ[œ˜ƒKšœœœ˜K˜K˜8Kšœœ˜Kšœœ˜Kšœ˜ KšœŸ˜ K˜——˜š  œœœ œ2œœ˜kKšœœœ˜šœœœ˜,Kšœ ˜ Kšœ˜—Kšœ˜KšœŸ ˜K˜K˜—š œœ œœœŸ(œ0Ÿœ˜·Kšœœœ˜K˜K˜.KšœŸ˜ K˜K˜—š  œœœ œ œ ˜LKšœœœ˜K˜KšœŸ˜K˜K˜—š  œœœ œ(˜VKšœœœ˜K˜KšœŸ˜K˜——˜š   œœ œœŸ˜>Kšœœœ˜Kšœœ˜Kšœ˜ Kšœœ4˜QKšœŸ˜K˜——˜š   œœ œœŸ1˜WKšœœœ˜Kšœœ˜Kšœ˜ Kšœœ3˜PKšœŸ˜K˜——˜š œœ œ˜KKšœœœ˜K˜šœŸ ˜ šœœ˜šœœœœŸ˜QK˜Išœ-œ˜9Kšœœ˜Kšœ˜Kšœ˜—Kšœœ˜K˜Kšœ˜—šœœŸ8˜NKšœA™AKšœM™MKšœ=™=šœœ˜Kšœœ˜šœ˜Kšœœ˜Kšœœ˜Kšœ ˜Kšœ˜——Kšœ˜—šœ˜Kšœ œŸ ˜GKšœŸ˜Kšœ˜—Kšœœ˜KšœœŸ2˜Lšœ˜K˜Gšœ-œ˜9Kšœœ˜Kšœ˜Kšœ˜—K˜Kšœ˜—Kšœ˜—Kšœ˜ Kšœ˜—KšœŸ˜K˜——˜š œœ œ˜+Kšœ#Ÿ-˜PKšœœ˜K˜%Kšœœ˜$KšœŸ˜K˜K˜—š  œ œ˜Kšœ œœ˜-Kšœ œœ0˜HK˜1Kšœ œœ˜Kšœœ˜!K˜.K˜šœœ˜šœ ˜Kšœ;™;Kšœœœ˜1K˜PKšœ*Ÿ˜=˜Kšœ  œ˜(˜+˜K˜7Kšœ ˜ K˜———˜,K˜—šœŸD˜GKš˜K˜,K˜šœœ˜ K˜$K˜K˜:K˜ Kšœ1 œ˜JKšœ˜—K˜˜-K˜K˜K˜K˜K˜K˜Kšœœœœ˜CK˜K˜(K˜K˜˜˜Kšœ"œ˜FK˜!KšœŸ˜.Kšœ ˜———š˜šœ ˜Kšœœœœ˜&Kšœl™lšœ?˜EK˜*—Kšœ˜Kšœ˜——Kšœ˜KšœŸ2˜8šœ˜ K˜——Kšœ#œ˜H˜"K˜—K˜K˜KšœŸ˜—KšœœŸ˜%—šœ˜K˜'K˜(—KšœŸ˜K˜——˜š œœ œ$˜@Kšœœœ˜šœ-œ˜9Kšœœ4˜NKšœ˜Kšœ˜K˜—šœœ˜ Kšœ œœ˜Kšœœœ<˜XKšœ œœ˜K˜9Kšœ œœ˜-K˜Kšœœœ7˜UKšœœœ<˜Xšœ"˜(K˜.K˜—K˜$šœœ˜'K˜K˜.K˜$Kšœ˜—˜.Kšœ@œ˜J—K˜Kšœ5 œ˜MKšœ˜K˜—K˜!šœ ˜&Kšœ#Ÿ˜>—šœœ˜šœ˜˜K˜I—Kšœ˜—šœ ˜%˜K˜:—šœ!œ˜+K˜:—Kšœ˜—˜˜K˜9——šœ˜ ˜K˜;———K˜K˜#Kšœ!œ˜'K˜,Kšœœ˜5Kšœœ˜6KšœŸ"˜0KšœŸ˜ K˜K˜—š œ œ&˜NKšœ œœœ˜7K˜@˜K˜9Kšœ  œ˜&—šœŸ˜K˜K˜——š œ œœ˜LKšœœœ˜K˜—š  œ œœœœœ˜EKšœ$˜*K˜—KšœŸ˜ —K˜Kšœ˜K˜%K˜{K˜QKšœMœ˜fK˜€˜VK˜Ϋ—Kšœ@œ˜U˜1K˜<——…—0?>