<> <> <> <> <> <<>> <> DIRECTORY BasicTime USING [GMT, nullGMT, ToNSTime], CHNameP2V0 USING [Name], CHLookUp USING [AddressFromRope], Commander USING [CommandProc, Register], CommandTool USING [ArgumentVector, Failed, Parse], CrRPC USING [BulkDataSource, BulkDataXferProc, CreateClientHandle, DestroyClientHandle, Handle], File USING [GetVolumeName, SystemVolume], FileNames USING [ResolveRelativePath], FS USING [ComponentPositions, Error, ErrorDesc, ExpandName, FileInfo, StreamOpen], FSPseudoServers USING [TranslateForRead, TranslateForWrite], IO USING [Close, EndOf, GetBlock, PutBlock, PutRope, STREAM], PrintingP4V3 USING [GetPrintRequestStatus, Print, PrintAttributes, PrintAttributesObject, PrintOptions, PrintOptionsObject, RequestID, RequestStatus, Time], PrintingP4V3Aux USING [ExposeRequestID], Process USING [CheckForAbort], RefText USING [ObtainScratch, ReleaseScratch], Rope USING [Cat, Concat, Equal, Fetch, Length, ROPE, Substr], ThisMachine USING [Name], UserCredentials USING [Get, CredentialsChangeProc, RegisterForChange], UserProfile USING [Boolean, CallWhenProfileChanges, Line, Number, ProfileChangedProc], XNS USING [Address]; SendIPMasterImpl: CEDAR PROGRAM IMPORTS BasicTime, CHLookUp, Commander, CommandTool, CrRPC, File, FileNames, FS, FSPseudoServers, IO, PrintingP4V3, PrintingP4V3Aux, Process, RefText, Rope, ThisMachine, UserCredentials, UserProfile ~ { Handle: TYPE ~ CrRPC.Handle; ROPE: TYPE ~ Rope.ROPE; STREAM: TYPE ~ IO.STREAM; PrintAttributes: TYPE ~ PrintingP4V3.PrintAttributes; PrintOptions: TYPE ~ PrintingP4V3.PrintOptions; RequestID: TYPE ~ PrintingP4V3.RequestID; Time: TYPE ~ PrintingP4V3.Time; <> SendIPMaster: ROPE ~ "///Commands/SendIPMaster"; doc: ROPE ~ "{IPMaster}*\nTransmit a master to an XNS based printer.\nSwitches: "; usage: ROPE ~ Rope.Concat["Usage: SendIPMaster ", doc]; <<>> <> DEFSWITCHES: ROPE ~ "SendIPMaster.DefaultSwitchesLine"; BANNER: ROPE ~ "Hardcopy.Banner"; CFNAME: ROPE ~ "Hardcopy.CFName"; COPYCOUNT: ROPE ~ "Hardcopy.CopyCount"; CREATEDATE: ROPE ~ "Hardcopy.CreateDate"; IPPRINTER: ROPE ~ "Hardcopy.InterpressPrinter"; KEY: ROPE ~ "Hardcopy.Key"; MEDIUM: ROPE ~ "Hardcopy.Medium"; PIGEONHOLE: ROPE ~ "Hardcopy.PigeonHole"; PAGEFIRST: ROPE ~ "Hardcopy.PageFirst"; PAGELAST: ROPE ~ "Hardcopy.PageLast"; PRINTSIZE: ROPE ~ "Hardcopy.PrintSize"; PRIORITY: ROPE ~ "Hardcopy.Priority"; STAPLED: ROPE ~ "Hardcopy.Stapled"; TWOSIDED: ROPE ~ "Hardcopy.TwoSided"; <<>> <> PrintRequest: TYPE ~ REF PrintRequestObject; PrintRequestObject: TYPE ~ RECORD [ attributes: PrintAttributes, ipMasterStream: STREAM, options: PrintOptions, requestID: RequestID, service: ROPE]; Environs: TYPE ~ REF EnvironsObject; EnvironsObject: TYPE ~ RECORD [ copyCount: INT, message: ROPE, mediumHint: ROPE, pageFirst: INT, pageLast: INT, printerName: ROPE, printObjectCreateDate: Time, printObjectName: ROPE, printObjectSize: INT, priorityHint: ROPE, recipientName: ROPE, releaseKey: INT, senderName: ROPE, stapled: BOOL, twoSided: BOOL ]; staticEnvirons: Environs; <> <<>> DecodeRequestID: PROC [out: STREAM, requestID: RequestID] ~ { msg: ROPE; msg _ Rope.Concat[PrintingP4V3Aux.ExposeRequestID[requestID, 0], "\n"]; IO.PutRope[out, msg]; }; 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]]]; }; GetAttributes: PROC [environs: Environs] RETURNS [attributes: PrintAttributes] ~ { attributes _ NEW[ PrintingP4V3.PrintAttributesObject[3] ]; TRUSTED { attributes.body[0] _ [printObjectName[environs.printObjectName]] }; TRUSTED { attributes.body[1] _ [printObjectCreateDate[environs.printObjectCreateDate]] }; TRUSTED { attributes.body[2] _ [senderName[environs.senderName]] }; }; GetDefaults: PROC RETURNS [environs: Environs] ~ { environs _ NEW[EnvironsObject]; environs.senderName _ UserCredentials.Get[].name; environs.message _ UserProfile.Line[BANNER, ""]; environs.printObjectName _ UserProfile.Line[CFNAME, "No File Name"]; environs.copyCount _ UserProfile.Number[COPYCOUNT, 1]; environs.printObjectCreateDate _ BasicTime.ToNSTime[BasicTime.nullGMT]; <> environs.printerName _ UserProfile.Line[IPPRINTER, "Huh? -- no printer!"]; environs.releaseKey _ UserProfile.Number[KEY, 0]; environs.mediumHint _ UserProfile.Line[MEDIUM, "paper"]; environs.recipientName _ UserProfile.Line[PIGEONHOLE, environs.senderName]; environs.pageFirst _ UserProfile.Number[PAGEFIRST, 1]; environs.pageLast _ UserProfile.Number[PAGELAST, 177777B]; environs.printObjectSize _ UserProfile.Number[PRINTSIZE, 0]; environs.priorityHint _ UserProfile.Line[PRIORITY, "normal"]; environs.stapled _ UserProfile.Boolean[STAPLED, FALSE]; environs.twoSided _ UserProfile.Boolean[TWOSIDED, TRUE]; }; GetRequest: PROC [environs: Environs] RETURNS [request: PrintRequest] ~ { request _ NEW[PrintRequestObject]; request.attributes _ GetAttributes[environs]; request.ipMasterStream _ NIL; request.options _ GetOptions[environs]; request.requestID _ ALL[0]; request.service _ environs.printerName; }; GetOptions: PROC [environs: Environs] RETURNS [options: PrintOptions] ~ { options _ NEW[ PrintingP4V3.PrintOptionsObject[5] ]; <<>> TRUSTED { options.body[0] _ [recipientName[environs.recipientName]] }; TRUSTED { options.body[1] _ [message[environs.message]] }; TRUSTED { options.body[2] _ [copyCount[environs.copyCount]] }; TRUSTED { options.body[3] _ [staple[environs.stapled]] }; TRUSTED { options.body[4] _ [twoSided[environs.twoSided]] }; <> <> <> <> <> <> <> <> <> <> }; <> GetPrintRequestStatus: PROC [destRope: ROPE, printRequestID: RequestID] RETURNS [states: PrintingP4V3.RequestStatus] ~ { addr: XNS.Address; h: Handle; service: CHNameP2V0.Name; [addr, service] _ CHLookUp.AddressFromRope[destRope]; h _ CrRPC.CreateClientHandle[class~$SPP, remote~addr]; states _ PrintingP4V3.GetPrintRequestStatus[h, printRequestID]; CrRPC.DestroyClientHandle[h]; }; Print: PROC [request: PrintRequest] ~ { addr: XNS.Address; h: Handle; master: CrRPC.BulkDataSource; service: CHNameP2V0.Name; [addr, service] _ CHLookUp.AddressFromRope[request.service]; master _ Xfer; h _ CrRPC.CreateClientHandle[class~$SPP, remote~addr]; h.clientData _ request; request.requestID _ PrintingP4V3.Print[h, master, request.attributes, request.options]; CrRPC.DestroyClientHandle[h]; }; Xfer: CrRPC.BulkDataXferProc <<[h: Handle, stream: IO.STREAM, checkAbort: BulkDataCheckAbortProc] RETURNS [abort: BOOL]>> ~ { bufSize: NAT ~ 1024; buf: REF TEXT ~ RefText.ObtainScratch[bufSize]; request: PrintRequest _ NARROW [h.clientData]; abort _ FALSE; DO IF IO.EndOf[request.ipMasterStream] THEN EXIT; IF (abort _ checkAbort[h]) THEN EXIT; [] _ IO.GetBlock[request.ipMasterStream, buf]; IO.PutBlock[stream, buf]; ENDLOOP; RefText.ReleaseScratch[buf]; }; <> SendMaster: Commander.CommandProc ~ { out: STREAM ~ cmd.out; environ: Environs; request: PrintRequest; switches: PACKED ARRAY CHAR['a..'z] OF BOOL _ ALL[FALSE]; ProcessSwitches: PROC [environ: Environs, arg: ROPE] ~ { sense: BOOL _ TRUE; FOR index: INT IN [0..Rope.Length[arg]) DO char: CHAR _ Rope.Fetch[arg, index]; SELECT char FROM '- => LOOP; '~ => {sense _ NOT sense; LOOP}; IN ['a..'z] => switches[char] _ sense; IN ['A..'Z] => switches[char + ('a-'A)] _ sense; ENDCASE; sense _ TRUE; ENDLOOP; }; ProcessArgument: PROC [arg: ROPE] ~ { argsProcessed _ argsProcessed + 1; Process.CheckForAbort[]; <> <> <> request.ipMasterStream _ FS.StreamOpen[FileNames.ResolveRelativePath[arg] ! FS.Error => IF (error.group # $bug) THEN {msg _ FSErrorMsg[error]; ERROR CommandTool.Failed[msg]}]; Print[request]; -- i'm unsure of using the requestID side effect, but.. DecodeRequestID[out, request.requestID]; IF (request.ipMasterStream # NIL) THEN IO.Close[request.ipMasterStream]; }; argsProcessed: NAT _ 0; argv: CommandTool.ArgumentVector _ CommandTool.Parse[cmd: cmd, starExpand: FALSE ! CommandTool.Failed => {msg _ errorMsg; GO TO failed}]; environ _ NEW[EnvironsObject _ staticEnvirons^]; ProcessSwitches[environ, UserProfile.Line[DEFSWITCHES]]; <> FOR i: NAT IN [1..argv.argc) DO arg: ROPE ~ argv[i]; Process.CheckForAbort[]; IF (Rope.Length[arg] = 0) THEN LOOP; IF (Rope.Fetch[arg, 0] = '-) THEN { ProcessSwitches[environ, arg]; LOOP; }; environ.printObjectName _ FixUpFilename[arg, FALSE]; { fullFName: ROPE; attachedTo: ROPE; keep: CARDINAL; bytes: INT; created: BasicTime.GMT; [fullFName, attachedTo, keep, bytes, created] _ FS.FileInfo[name~arg, remoteCheck~FALSE]; environ.printObjectCreateDate _ BasicTime.ToNSTime[created]; }; request _ GetRequest[environ]; IO.PutRope[out, Rope.Cat["Sending: ", environ.printObjectName, "\n"]]; ProcessArgument[arg]; request _ NIL; -- we should cache these for later status requests! ENDLOOP; SELECT argsProcessed FROM 0 => msg _ usage; ENDCASE => NULL; EXITS failed => {result _ $Failure}; }; <> NewProfile: UserProfile.ProfileChangedProc ~ { staticEnvirons _ GetDefaults[]; }; NewUser: UserCredentials.CredentialsChangeProc ~ { staticEnvirons _ GetDefaults[]; }; <> Init: PROC ~ { Commander.Register[key: SendIPMaster, proc: SendMaster, doc: doc, clientData: NIL, interpreted: TRUE]; UserProfile.CallWhenProfileChanges[NewProfile]; UserCredentials.RegisterForChange[NewUser]; }; Init[]; }...