<> <> <> <> <> 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.