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 ~ { 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[]; }... ˆSendIPMasterImpl.mesa Copyright c 1984, 1985, 1986 by Xerox Corporation. All rights reserved. Russ Atkinson (RRA) September 23, 1985 7:20:31 pm PDT McCreight, January 30, 1986 5:37:08 pm PST Bill Jackson (bj) October 9, 1986 5:51:15 am PDT Some of the credits above are from FSFileCommandsImpl. Commander Constants UserProfile Tags XferObject, one per callback in progress; I/O Procs Helper PROCs environs.printObjectCreateDate _ UserProfile.Line[CREATEDATE, ""]; TRUSTED { options.body[0] _ [printObjectSize[CARD]] }; TRUSTED { options.body[1] _ [recipientName[ROPE]] }; TRUSTED { options.body[2] _ [message[ROPE]] }; TRUSTED { options.body[3] _ [copyCount[CARDINAL]] }; TRUSTED { options.body[4] _ [pagesToPrint[[beginningPageNumber, endingPageNumber: CARDINAL]]] }; TRUSTED { options.body[5] _ [mediumHint[Medium]] }; TRUSTED { options.body[6] _ [priorityHint[Priority]] }; TRUSTED { options.body[7] _ [releaseKey[XNSAuth.HashedPassword]] }; TRUSTED { options.body[8] _ [staple[BOOL]] }; TRUSTED { options.body[9] _ [twoSided[BOOL]] }; Active PROCs [h: Handle, stream: IO.STREAM, checkAbort: BulkDataCheckAbortProc] RETURNS [abort: BOOL] Commander PROCs To process an argument, open the file, and send its contents to the printer, generate some sensible textual output about the request ID. Allows the user to specify personal defaults for the switches via the user's profile. Snoopy PROCs Init Proc Κ Ζ˜codešœ™Kšœ Οmœ=™HK™5K™*K™0K™Kšœ6™6—K˜šΟk ˜ Kšœ žœžœ˜)Kšœ žœ˜Kšœ žœ˜!Kšœ žœ˜(Kšœ žœ!˜2KšœžœU˜`Kšœžœ˜)Kšœ žœ˜&KšžœžœJ˜RKšœžœ'˜šžœ ž˜šœ ˜ Kšžœ˜Kšœ˜—šžœ˜ šžœ˜Kšžœžœ˜Kšžœžœ6˜A—Kšœ˜——Kšœ˜K˜——šœ ™ K˜šŸ œžœžœžœ žœžœ žœ˜RKšœžœ˜ Kšœžœ˜(Kšœžœ+˜?Kšœžœ˜ Kšœžœ˜K˜Kšœžœ˜3Kšœ$˜$Kšœ5˜5šžœžœ˜$KšœA˜AKšœ"˜"Kšœ˜—šžœ˜Kšœ˜šžœ ž˜Kšœ_˜_—šž˜Kšœ[˜[—Kšœ˜Kšœ:˜:—K˜K˜—šŸ œžœžœ"˜RKšœ žœ*˜:KšžœF˜MKšžœR˜YKšžœ<˜CK˜K˜—šŸ œžœžœ˜2Kšœ žœ˜Kšœ1˜1K˜Kšœ$’œ˜0Kšœ,’œ˜DKšœ(’ œ˜6KšœG˜GKšœ2‘ œ™BKšœ(’ œ˜JKšœ)’œ˜1Kšœ'’œ ˜8Kšœ*’ œ˜KKšœ(’ œ˜6Kšœ'’œ ˜:Kšœ.’ œ˜Kšžœ2˜9Kšžœ5˜