<> <> <> <> <<>> DIRECTORY BasicTime USING [GMT, nullGMT, ToNSTime], CedarProcess USING [Fork, ForkableProc, Process], CHNameP2V0 USING [Name], CrRPC USING [BulkDataXferProc, CreateClientHandle, DestroyClientHandle, Handle], FS USING [StreamOpen], IO USING [Close, EndOf, GetBlock, PutBlock, STREAM], RefText USING [ObtainScratch, ReleaseScratch], Rope USING [ROPE], UserCredentials USING [Get, CredentialsChangeProc, RegisterForChange], UserProfile USING [Boolean, CallWhenProfileChanges, Line, Number, ProfileChangedProc], XNS USING [Address, unknownSocket], XNSCH USING [LookupAddressFromRope], XNSStream USING [waitForever], PrintingP4V3, XNSPrintRequestManager; XNSPrintRequestManagerImpl: CEDAR MONITOR IMPORTS BasicTime, CedarProcess, CrRPC, FS, IO, PrintingP4V3, RefText, UserCredentials, UserProfile, XNSCH EXPORTS XNSPrintRequestManager ~ { OPEN CHName: CHNameP2V0, Printing: PrintingP4V3, XNSPrintRequestManager; ROPE: TYPE ~ Rope.ROPE; <> 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"; <<>> <> <<>> pendingPrintRequests: PrintRequestList _ NIL; userContext: Context; watcherProcess: CedarProcess.Process; <> <<>> ListChanged: PUBLIC CONDITION; RegisterPrintRequest: PUBLIC ENTRY PROC [request: PrintRequest, update: StatusChangedProc _ NIL] ~ { pendingPrintRequests _ CONS[request, pendingPrintRequests]; NOTIFY ListChanged; }; UnRegisterPrintRequest: PUBLIC ENTRY PROC [request: PrintRequest] ~ { SELECT TRUE FROM (pendingPrintRequests = NIL) => { RETURN; }; (pendingPrintRequests.first = request) => { pendingPrintRequests _ pendingPrintRequests.rest; }; ENDCASE => { FOR tail: PrintRequestList _ pendingPrintRequests, tail.rest WHILE (tail.rest # NIL) DO IF (tail.rest.first = request) THEN { tail.rest _ tail.rest.rest; EXIT; }; ENDLOOP; }; NOTIFY ListChanged; }; GetPrintRequestList: PUBLIC ENTRY PROC RETURNS [list: PrintRequestList] ~ { list _ pendingPrintRequests; }; <<>> <> WaitTilListChanged: ENTRY PROC ~ { WAIT ListChanged; }; WatchRequestList: CedarProcess.ForkableProc ~ { DO WaitTilListChanged[]; ENDLOOP; }; <<>> <> <<>> GetPrinterProperties: PUBLIC PROC [printer: ROPE] RETURNS [service: CHName.Name, answer: Printing.PrinterProperties] ~ { addr: XNS.Address; h: CrRPC.Handle; [service, addr] _ XNSCH.LookupAddressFromRope[printer]; addr.socket _ XNS.unknownSocket; -- Kluge for CH bug h _ CrRPC.CreateClientHandle[class~$SPP, remote~addr]; answer _ Printing.GetPrinterProperties[h]; CrRPC.DestroyClientHandle[h]; }; GetPrinterStatus: PUBLIC PROC [printer: ROPE] RETURNS [service: CHName.Name, answer: Printing.PrinterStatus] ~ { addr: XNS.Address; h: CrRPC.Handle; [service, addr] _ XNSCH.LookupAddressFromRope[printer]; addr.socket _ XNS.unknownSocket; -- Kluge for CH bug h _ CrRPC.CreateClientHandle[class~$SPP, remote~addr]; answer _ Printing.GetPrinterStatus[h]; CrRPC.DestroyClientHandle[h]; }; GetPrintRequestStatus: PUBLIC PROC [request: PrintRequest] RETURNS [status: RequestStatus] ~ { addr: XNS.Address; h: CrRPC.Handle; service: CHName.Name; realStatus: Printing.RequestStatus; [service, addr] _ XNSCH.LookupAddressFromRope[request.context.printerName]; addr.socket _ XNS.unknownSocket; -- Kluge for CH bug h _ CrRPC.CreateClientHandle[class~$SPP, remote~addr]; realStatus _ Printing.GetPrintRequestStatus[h, request.requestID]; CrRPC.DestroyClientHandle[h]; FOR i: CARDINAL IN [0..realStatus.length) DO WITH realStatus.body[i] SELECT FROM v: status Printing.JobStatus => { status.status _ v.status; }; v: statusMessage Printing.JobStatus => { status.statusMessage _ v.statusMessage; }; ENDCASE => { ERROR }; ENDLOOP; }; PrintFromFile: PUBLIC PROC [file: ROPE, context: Context, update: StatusChangedProc _ NIL] RETURNS [request: PrintRequest] ~ { addr: XNS.Address; h: CrRPC.Handle; s: IO.STREAM; s _ FS.StreamOpen[file < IF (error.group # $bug)>> <> ]; request _ CreatePrintRequest[context]; request.fileName _ file; request.ipMasterStream _ s; [request.distinguishedName, addr] _ XNSCH.LookupAddressFromRope[context.printerName]; addr.socket _ XNS.unknownSocket; -- Kluge for CH bug h _ CrRPC.CreateClientHandle[class~$SPP, remote~addr, timeoutMsec~XNSStream.waitForever]; h.clientData _ request; request.requestID _ Printing.Print[h, Xfer, request.attributes, request.options]; CrRPC.DestroyClientHandle[h]; IF (s # NIL) THEN IO.Close[s]; IF (update # NIL) THEN RegisterPrintRequest[request, update]; }; PrintFromStream: PUBLIC PROC [s: IO.STREAM, context: Context, update: StatusChangedProc _ NIL] RETURNS [request: PrintRequest] ~ { addr: XNS.Address; h: CrRPC.Handle; request _ CreatePrintRequest[context]; request.ipMasterStream _ s; [request.distinguishedName, addr] _ XNSCH.LookupAddressFromRope[context.printerName]; addr.socket _ XNS.unknownSocket; -- Kluge for CH bug h _ CrRPC.CreateClientHandle[class~$SPP, remote~addr]; h.clientData _ request; request.requestID _ Printing.Print[h, Xfer, request.attributes, request.options]; CrRPC.DestroyClientHandle[h]; IF (update # NIL) THEN RegisterPrintRequest[request, update]; }; 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]; }; <> GetDefaults: PUBLIC PROC [context: Context _ NIL] RETURNS [newContext: Context] ~ { newContext _ IF (context = NIL) THEN NEW[ContextObject] ELSE context; newContext.senderName _ UserCredentials.Get[].name; newContext.message _ UserProfile.Line[BANNER, ""]; newContext.printObjectName _ UserProfile.Line[CFNAME, "No File Name"]; newContext.copyCount _ UserProfile.Number[COPYCOUNT, 1]; newContext.printObjectCreateDate _ BasicTime.ToNSTime[BasicTime.nullGMT]; <> newContext.printerName _ UserProfile.Line[IPPRINTER, "Huh? -- no printer!"]; newContext.releaseKey _ UserProfile.Number[KEY, 0]; newContext.mediumHint _ UserProfile.Line[MEDIUM, "paper"]; newContext.recipientName _ UserProfile.Line[PIGEONHOLE, newContext.senderName]; newContext.pageFirst _ UserProfile.Number[PAGEFIRST, 1]; newContext.pageLast _ UserProfile.Number[PAGELAST, 177777B]; newContext.printObjectSize _ UserProfile.Number[PRINTSIZE, 0]; newContext.priorityHint _ UserProfile.Line[PRIORITY, "normal"]; newContext.stapled _ UserProfile.Boolean[STAPLED, FALSE]; newContext.twoSided _ UserProfile.Boolean[TWOSIDED, TRUE]; }; CreateAttributes: PUBLIC PROC [context: Context] RETURNS [attributes: Printing.PrintAttributes] ~ { attributes _ NEW[ Printing.PrintAttributesObject[3] ]; TRUSTED { attributes.body[0] _ [printObjectName[context.printObjectName]] }; TRUSTED { attributes.body[1] _ [printObjectCreateDate[context.printObjectCreateDate]] }; TRUSTED { attributes.body[2] _ [senderName[context.senderName]] }; }; CreateOptions: PUBLIC PROC [context: Context] RETURNS [options: Printing.PrintOptions] ~ { options _ NEW[ Printing.PrintOptionsObject[5] ]; TRUSTED { options.body[0] _ [recipientName[context.recipientName]] }; TRUSTED { options.body[1] _ [message[context.message]] }; TRUSTED { options.body[2] _ [copyCount[context.copyCount]] }; TRUSTED { options.body[3] _ [staple[context.stapled]] }; TRUSTED { options.body[4] _ [twoSided[context.twoSided]] }; }; CreatePrintRequest: PUBLIC PROC [context: Context] RETURNS [request: PrintRequest] ~ { privateContext: Context _ NEW [ContextObject _ context^]; request _ NEW[PrintRequestObject]; request.context _ privateContext; request.update _ NIL; request.distinguishedName _ [NIL, NIL, NIL]; request.requestID _ ALL[0]; request.lastStatus _ [unknown, "uninitialized lastStatus"]; request.attributes _ CreateAttributes[context]; request.options _ CreateOptions[context]; request.fileName _ context.printObjectName; request.ipMasterStream _ NIL; }; NewProfile: UserProfile.ProfileChangedProc ~ { userContext _ GetDefaults[userContext]; }; NewUser: UserCredentials.CredentialsChangeProc ~ { userContext _ GetDefaults[userContext]; }; <> Init: ENTRY PROC ~ { watcherProcess _ CedarProcess.Fork[WatchRequestList]; userContext _ GetDefaults[]; UserProfile.CallWhenProfileChanges[NewProfile]; UserCredentials.RegisterForChange[NewUser]; }; Init[]; }... <<>>