<<>> <> <> <> <> <> <> <> <> <> <> <> <> <> DIRECTORY Args USING [Arg, ArgsGet, Error, NArgs], Commander USING [CommandProc, Register], CommanderOps USING [ArgumentVector, Failed, Parse], FileNames USING [ResolveRelativePath], IO, Process USING [CheckForAbort, Pause, SecondsToTicks], Rope USING [Cat, Concat, Equal, Length, ROPE], PrintingP4V3Aux, SimpleFeedback USING [Append], XNSPrint, XNSPrintExtras; XNSPrintCommandsImpl: CEDAR PROGRAM IMPORTS Args, Commander, CommanderOps, FileNames, IO, PrintingP4V3Aux, Process, Rope, SimpleFeedback, XNSPrint, XNSPrintExtras ~ { OPEN PrintingAux: PrintingP4V3Aux; ROPE: TYPE ~ Rope.ROPE; <> FaxIPMaster: ROPE ~ "FaxIPMaster"; faxdoc: ROPE ~ " [-t -c -h -0 -1 -2 -f -l ]\nSend a master through an XNS based server to a remote FAX machine.\nSwitches:\n -t FAX phone number\n -c print multiple copies\n -h print thru service\n -0 leave plex unspecified\n -1 print one-sided\n -2 print two-sided\n -f \n -l "; faxusage: ROPE ~ Rope.Concat["Usage: FaxIPMaster ", faxdoc]; GetPrintStatus: ROPE = "GetPrintStatus"; statusdoc: ROPE = "{Printer}*\nFind out the status of an XNS based printer."; statususage: ROPE = Rope.Concat["Usage: GetPrintStatus ", statusdoc]; GetPrintProperties: ROPE = "GetPrintProperties"; propdoc: ROPE = "{Printer}*\nFind out the properties of an XNS based printer.\n"; propusage: ROPE = Rope.Concat["Usage: GetPrintProperties ", propdoc]; SendIPMaster: ROPE ~ "SendIPMaster"; senddoc: ROPE ~ " [-0 -1 -2 -a -b -s -c -h -f -l -m -medium ]\nTransmit a master to an XNS based printer.\nSwitches:\n -0 leave plex unspecified\n -1 print one-sided\n -2 print two-sided\n -a correct color (Lamming-Rhodes; includes -b)\n -b balance grays\n -s staple output\n -c print multiple copies\n -f \n -h print on that service\n -l -m include parameter (possibly quoted) in printer message field\n -medium paper size, e.g., -medium usLetter or -medium ([width~229, length~279])"; sendusage: ROPE ~ Rope.Concat["Usage: SendIPMaster ", senddoc]; <> GetPrintPropertiesProc: Commander.CommandProc ~ { ENABLE { CommanderOps.Failed => { msg ¬ errorMsg; GO TO Failed }; XNSPrint.Error => { msg ¬ Sensible[problem, explanation]; GO TO Failed }; }; argsProcessed: NAT ¬ 0; argv: CommanderOps.ArgumentVector ¬ CommanderOps.Parse[cmd: cmd]; out: IO.STREAM ~ cmd.out; CheckProperties: PROC [arg: ROPE] ~ { service: ROPE; properties: XNSPrint.Properties; argsProcessed ¬ argsProcessed + 1; Process.CheckForAbort[]; [service, properties] ¬ XNSPrint.GetPrinterProperties[arg]; IO.PutF[out, " Service: [%g]\n Staple: %g, TwoSided: %g\n Media: ", IO.rope[service], IO.bool[properties.staple], IO.bool[properties.twoSided] ]; IF ( properties.media # NIL ) THEN DisplayMediaList[out, properties.media]; }; FOR i: NAT IN [1..argv.argc) DO printerName: ROPE ~ argv[i]; Process.CheckForAbort[]; IF (Rope.Length[printerName] = 0) THEN LOOP; CheckProperties[printerName]; ENDLOOP; SELECT argsProcessed FROM 0 => { context: XNSPrint.Context; context ¬ XNSPrint.GetDefaults[]; IF (context.printerName = NIL) THEN msg ¬ propusage ELSE CheckProperties[context.printerName]; }; ENDCASE => { NULL }; EXITS Failed => {result ¬ $Failure}; }; GetPrintStatusProc: Commander.CommandProc ~ { ENABLE { CommanderOps.Failed => { msg ¬ errorMsg; GO TO Failed }; XNSPrint.Error => { msg ¬ Sensible[problem, explanation]; GO TO Failed }; }; argsProcessed: NAT ¬ 0; argv: CommanderOps.ArgumentVector ¬ CommanderOps.Parse[cmd: cmd]; out: IO.STREAM ~ cmd.out; CheckPrinter: PROC [arg: ROPE] = { service: ROPE; status: XNSPrint.PrinterStatus; argsProcessed ¬ argsProcessed + 1; Process.CheckForAbort[]; [service, status] ¬ XNSPrint.GetPrinterStatus[arg]; IO.PutFL[out, " Service: [%g]\n Spooler: %g, Formatter: %g, Printer: %g\n Media: ", LIST[ IO.rope[service], IO.rope[PrintingAux.ExposeSpoolerStatus[status.spooler, 0]], IO.rope[PrintingAux.ExposeFormatterStatus[status.formatter, 0]], IO.rope[PrintingAux.ExposeMarkingEngineStatus[status.printer, 0]] ] ]; IF ( status.media # NIL ) THEN DisplayMediaList[out, status.media]; }; FOR i: NAT IN [1..argv.argc) DO printerName: ROPE ~ argv[i]; Process.CheckForAbort[]; IF (Rope.Length[printerName] = 0) THEN LOOP; CheckPrinter[printerName]; ENDLOOP; SELECT argsProcessed FROM 0 => { context: XNSPrint.Context; context ¬ XNSPrint.GetDefaults[]; IF (context.printerName = NIL) THEN msg ¬ statususage ELSE CheckPrinter[context.printerName]; }; ENDCASE => NULL; EXITS Failed => {result ¬ $Failure}; }; FaxMasterProc: Commander.CommandProc ~ { ENABLE { XNSPrint.Error => { msg ¬ Sensible[problem, explanation]; GO TO Failed }; }; context: XNSPrint.Context; request: XNSPrint.PrintRequest; ok: BOOL ¬ TRUE; fullFName, exp: ROPE ¬ NIL; out: IO.STREAM ~ cmd.out; name, phone, copies, host, defaultPlex, oneSided, twoSided, first, last, pages: Args.Arg; FixUpPhone: PROC [in: ROPE] RETURNS [out: ROPE ¬ NIL] ~ { out ¬ IO.PutFR1["//%g//", IO.rope[in]]; }; IF Args.NArgs[cmd] = 0 THEN RETURN[$Failure, faxusage]; [name, phone, copies, host, defaultPlex, oneSided, twoSided, first, last, pages] ¬ Args.ArgsGet[cmd, "%s-t%s-c%i-h%s-0%b-1%b-2%b-f%i-l%i-p%i" ! Args.Error => {ok ¬ FALSE; CONTINUE}]; IF NOT ok THEN RETURN[$Failure, "Command syntax error."]; context ¬ XNSPrint.GetDefaults[]; IF copies.ok THEN context.copyCount ¬ copies.int; IF host.ok THEN context.printerName ¬ host.rope; IF phone.ok THEN context.message ¬ FixUpPhone[phone.rope]; IF defaultPlex.ok AND defaultPlex.bool THEN XNSPrintExtras.SetPlex[context, $default]; IF twoSided.ok AND twoSided.bool THEN XNSPrintExtras.SetPlex[context, $simplex]; IF oneSided.ok AND oneSided.bool THEN XNSPrintExtras.SetPlex[context, $duplex]; IF first.ok THEN context.pageFirst ¬ first.int; IF last.ok THEN context.pageLast ¬ last.int; IF pages.ok THEN context.pageLast ¬ context.pageFirst+pages.int; name.rope ¬ FileNames.ResolveRelativePath[name.rope]; fullFName ¬ name.rope; -- FixUpFilename[name.rope, FALSE]; IO.PutF[out, " Sending %s to %s", IO.rope[fullFName], IO.rope[context.printerName] ]; Process.CheckForAbort[]; request ¬ XNSPrint.PrintFromFile[name.rope, context, AllDone]; IO.PutF[out, "\n Service: [%g]\n RequestID: %g\n", IO.rope[request.distinguishedName], IO.rope[PrintingAux.ExposeRequestID[request.requestID, 0]] ]; EXITS Failed => {result ¬ $Failure}; }; SendMasterProc: Commander.CommandProc ~ { ENABLE { XNSPrint.Error => { msg ¬ Sensible[problem, explanation]; GO TO Failed }; }; context: XNSPrint.Context; request: XNSPrint.PrintRequest; ok: BOOL ¬ TRUE; fullFName, exp: ROPE ¬ NIL; out: IO.STREAM ~ cmd.out; name, copies, host, defaultPlex, oneSided, twoSided, first, last, pages, colorCorr, grayBal, message, stapled, medium: Args.Arg; IF ( FALSE ) THEN { [result, msg] ¬ GetPrintStatusProc[cmd]; IF ( result = $Failure ) THEN RETURN[$Failure, msg]; }; IF Args.NArgs[cmd] = 0 THEN RETURN[$Failure, sendusage]; [name, copies, host, defaultPlex, oneSided, twoSided, first, last, pages, colorCorr, grayBal, message, stapled, medium] ¬ Args.ArgsGet[cmd, "%s-c%i-h%s-0%b-1%b-2%b-f%i-l%i-p%i-a%b-b%b-m%s-s%b-medium%s" ! Args.Error => {ok ¬ FALSE; CONTINUE}]; IF NOT ok THEN RETURN[$Failure, "Command syntax error."]; context ¬ XNSPrint.GetDefaults[]; IF copies.ok THEN context.copyCount ¬ copies.int; IF host.ok THEN context.printerName ¬ host.rope; XNSPrintExtras.SetPlex[context, $default]; IF twoSided.ok AND twoSided.bool THEN XNSPrintExtras.SetPlex[context, $duplex]; IF oneSided.ok AND oneSided.bool THEN XNSPrintExtras.SetPlex[context, $simplex]; IF first.ok THEN context.pageFirst ¬ first.int; IF last.ok THEN context.pageLast ¬ last.int; IF pages.ok THEN context.pageLast ¬ context.pageFirst+pages.int; IF message.ok THEN context.message ¬ message.rope; IF stapled.ok AND stapled.bool THEN XNSPrintExtras.SetStapling[context, $stapled]; IF medium.ok THEN { [] ¬ XNSPrint.GetPrinterProperties[context.printerName]; -- This loads the media list with all the sizes this printer knows about. IF XNSPrint.GetPaperDimensions[medium.rope].width = 0 THEN { CommanderOps.Failed[Rope.Cat["Unknown medium: ", medium.rope, "; use GetPrintProperties to list the known media for this printer"]]; }; context.mediumHint ¬ medium.rope; }; IF grayBal.ok THEN context.message ¬ context.message.Concat["GrayBalanceThisMaster: TRUE\n"]; IF colorCorr.ok THEN context.message ¬ context.message.Concat["ColorCorrectThisMaster: TRUE\n"]; <> name.rope ¬ FileNames.ResolveRelativePath[name.rope]; fullFName ¬ name.rope; -- FixUpFilename[name.rope, FALSE]; IO.PutF[out, " Sending %s to %s", IO.rope[fullFName], IO.rope[context.printerName] ]; Process.CheckForAbort[]; NoteContext[context]; request ¬ XNSPrint.PrintFromFile[name.rope, context, AllDone ! XNSPrint.Error => { IF problem=serviceRetry OR (problem=service AND Rope.Equal[s1: explanation, s2: "Spooling Queue Full"]) OR (problem=connection AND Rope.Equal[s1: explanation, s2: "communication failure"]) THEN { Process.CheckForAbort[]; Process.Pause[Process.SecondsToTicks[5]]; IO.PutF[stream: out, format: " ... %lRETRY%l", v1: [rope["k"]], v2: [rope["K"]]]; RETRY; } }]; IO.PutF[out, "\n Service: [%g]\n RequestID: %g\n", IO.rope[request.distinguishedName], IO.rope[PrintingAux.ExposeRequestID[request.requestID, 0]] ]; EXITS Failed => {result ¬ $Failure}; }; NoteContext: PROC [c: XNSPrint.Context] = { <> IF c = NIL THEN ERROR; }; <> AllDone: XNSPrint.StatusChangedProc ~ { name: ROPE ¬ PrintingAux.ExposeInterpressMasterStatus[request.lastStatus.status, 0]; msg: ROPE ¬ IO.PutFR["print request: %g, status: (%g)", IO.rope[request.fileName], IO.rope[name] ]; SELECT request.lastStatus.status FROM pending, inProgress => { SimpleFeedback.Append[$XNSPrintingUI, oneLiner, $info, msg]; }; completed, completedWithWarning, unknown, rejected, aborted, canceled, held => { SimpleFeedback.Append[$XNSPrintingUI, oneLiner, $info, msg]; XNSPrint.UnRegisterPrintRequest[request]; }; ENDCASE => { NULL }; }; DisplayMediaList: PROC [out: IO.STREAM, m: XNSPrint.Media] ~ { FOR tail: XNSPrint.Media ¬ m, tail.rest WHILE ( tail # NIL ) DO IO.PutF1[out, IF (tail = m) THEN "[ [%g]" ELSE ", [%g]", IO.rope[tail.first]]; ENDLOOP; IO.PutRope[out, " ]\n"]; }; << FSErrorMsg: PROC [error: FS.ErrorDesc] RETURNS [ROPE] ~ { RETURN[Rope.Concat[FSErrorMsgBrief[error], "\n"]]; }; FSErrorMsgBrief: PROC [error: FS.ErrorDesc] RETURNS [ROPE] ~ { SELECT error.group FROM lock => { RETURN[" -- locked!"]; }; ENDCASE => { IF (error.code = $unknownFile) THEN RETURN [" -- not found!"] ELSE RETURN[Rope.Concat["\n -- FS.Error: ", error.explanation]]; }; }; FixUpFilename: PROC [name: ROPE ¬ NIL, copyFrom: BOOL] RETURNS [newName: ROPE] ~ { body: ROPE; platformHost: ROPE ¬ ThisMachine.Name[]; platformVolume: ROPE ¬ File.GetVolumeName[File.SystemVolume[]]; prefix: ROPE; cp: FS.ComponentPositions; [fullFName: newName, cp: cp] ¬ FS.ExpandName[name]; prefix ¬ Rope.Substr[newName, 0, 4]; body ¬ Rope.Substr[newName, 4, Rope.Length[newName]]; IF Rope.Equal[prefix, "[]<>"] THEN { newName ¬ Rope.Cat["[", platformHost, "]<", platformVolume, ">"]; newName ¬ Rope.Cat[newName, body]; } ELSE newName ¬ Rope.Cat[ "[", IF copyFrom THEN FSPseudoServers.TranslateForRead[Rope.Substr[newName, cp.server.start, cp.server.length]].first ELSE FSPseudoServers.TranslateForWrite[Rope.Substr[newName, cp.server.start, cp.server.length]], "]<", Rope.Substr[newName, cp.dir.start, Rope.Length[newName]]]; }; >> Sensible: PROC [problem: XNSPrint.Problem, explanation: ROPE] RETURNS [msg: ROPE] ~ { PROBLEM: ARRAY XNSPrint.Problem OF ROPE ~ ["connection", "file", "name", "protocol", "service", "serviceRetry", "stream", "unknown"]; p: ROPE ~ PROBLEM[problem]; msg ¬ IO.PutFR["XNSPrint.Error(%g): %g", IO.rope[p], IO.rope[explanation]]; }; <> Init: PROC ~ { Commander.Register[FaxIPMaster, FaxMasterProc, faxdoc]; Commander.Register[GetPrintProperties, GetPrintPropertiesProc, propdoc]; Commander.Register[GetPrintStatus, GetPrintStatusProc, statusdoc]; Commander.Register[SendIPMaster, SendMasterProc, senddoc]; }; Init[]; }. <<>>