DIRECTORY GVBasics USING[ ItemHeader, ItemLength, RName, Timestamp ], GVNames USING[ AuthenticateInfo ], GVProtocol USING[ Close, CreateStream, Failed, FailureReason, Handle, ReceiveAck, ReceiveBoolean, ReceiveByte, ReceiveBytes, ReceiveCount, ReceiveItemHeader, ReceiveRemark, ReceiveRName, ReceiveTimestamp, SendNow, SendMSOperation, SendPassword, SendRemark, SendRName ], GVRetrieve USING[ Failed, FailureReason ], GVRetrieveInternal USING[ Handle, HandleObject, NoteChangedMBX, ServerAddress ], IO USING[ CharsAvail, CreateStreamProcs, CreateStream, EndOfStream, STREAM, StreamProcs, UnsafeBlock ], PupDefs USING[ PupAddress ], PupStream USING[ ConsumeMark, StreamClosing, TimeOut ], Rope USING[ ROPE ]; RetrieveGV: CEDAR MONITOR LOCKS handle USING handle: GVRetrieveInternal.Handle IMPORTS GVProtocol, GVRetrieve, GVRetrieveInternal, IO, PupStream EXPORTS GVRetrieve, GVRetrieveInternal = BEGIN Handle: PUBLIC TYPE = GVRetrieveInternal.Handle; HandleObject: PUBLIC TYPE = GVRetrieveInternal.HandleObject; Fail: PROC[why: GVProtocol.FailureReason, text: Rope.ROPE] = { ERROR GVRetrieve.Failed[IF why = protocolError THEN unknownFailure ELSE communicationFailure, text] }; WrongCallSequence: ERROR = CODE; NextMessage: PUBLIC ENTRY PROCEDURE[ handle: GVRetrieveInternal.Handle ] RETURNS[ msgExists: BOOLEAN, archived: BOOLEAN, deleted: BOOLEAN ] = BEGIN ENABLE { GVProtocol.Failed => Fail[why, text]; UNWIND => NULL }; IF handle.state = beforeMBX THEN BEGIN addr: PupDefs.PupAddress _ GVRetrieveInternal.ServerAddress[handle]; -- we exited by a signal if the address wasn't available -- IF handle.currentStr # NIL THEN ERROR; IF handle.currentMBX.type # GV THEN ERROR GVRetrieve.Failed[communicationFailure, "Can't access MTP mailboxes from Cedar"]; handle.currentStr _ GVProtocol.CreateStream[handle.currentMBX.addr, MSRetrieve]; GVProtocol.SendMSOperation[handle.currentStr, openMBX]; GVProtocol.SendRName[handle.currentStr, handle.userName]; GVProtocol.SendPassword[str:handle.currentStr, pw:handle.userKey]; GVProtocol.SendNow[handle.currentStr]; BEGIN info: GVNames.AuthenticateInfo = LOOPHOLE[GVProtocol.ReceiveByte[handle.currentStr]]; SELECT info FROM allDown => ERROR GVRetrieve.Failed[communicationFailure, "You mailbox server can't contact an authentication server"]; notFound, group, badPwd => ERROR GVRetrieve.Failed[badCredentials, "Your mailbox server doesn't like your name or password"]; individual => NULL; ENDCASE => ERROR GVRetrieve.Failed[unknownFailure, "Unknown return code from mailbox"]; END; handle.messages _ GVProtocol.ReceiveCount[handle.currentStr]; handle.state _ afterMessage; END; WHILE handle.state = inBody DO [] _ InnerNextItem[handle]; ENDLOOP; IF handle.state = beforeBody THEN handle.state _ afterMessage; -- handle.state is now afterMessage or afterMBX -- IF handle.messages = 0 THEN { handle.state _ afterMBX; RETURN[FALSE,FALSE,FALSE] } ELSE BEGIN handle.messages _ handle.messages-1; GVProtocol.SendMSOperation[handle.currentStr, nextMessage]; GVProtocol.SendNow[handle.currentStr]; msgExists _ GVProtocol.ReceiveBoolean[handle.currentStr]; archived _ GVProtocol.ReceiveBoolean[handle.currentStr]; deleted _ GVProtocol.ReceiveBoolean[handle.currentStr]; IF msgExists THEN handle.state _ beforeBody ELSE ERROR; END; END; ReadTOC: PUBLIC ENTRY PROC[handle: GVRetrieveInternal.Handle] RETURNS[ Rope.ROPE ] = BEGIN ENABLE { GVProtocol.Failed => Fail[why, text]; UNWIND => NULL }; WHILE handle.state = inBody DO [] _ InnerNextItem[handle]; ENDLOOP; IF handle.state # beforeBody THEN ERROR WrongCallSequence[]; GVProtocol.SendMSOperation[handle.currentStr, readTOC]; GVProtocol.SendNow[handle.currentStr]; RETURN[GVProtocol.ReceiveRemark[handle.currentStr]]; END; StartMessage: PUBLIC ENTRY PROCEDURE[handle: GVRetrieveInternal.Handle] RETURNS[ postmark: GVBasics.Timestamp, sender: GVBasics.RName, returnTo: GVBasics.RName ] = BEGIN ENABLE { GVProtocol.Failed => Fail[why, text]; UNWIND => NULL }; [postmark, sender, returnTo] _ InnerStartMessage[handle]; END; InnerStartMessage: INTERNAL PROCEDURE[handle: GVRetrieveInternal.Handle] RETURNS[ postmark: GVBasics.Timestamp, sender: GVBasics.RName, returnTo: GVBasics.RName ] = BEGIN WHILE handle.state = inBody DO [] _ InnerNextItem[handle]; ENDLOOP; IF handle.state # beforeBody THEN ERROR WrongCallSequence[]; GVProtocol.SendMSOperation[handle.currentStr, readMessage]; GVProtocol.SendNow[handle.currentStr]; handle.state _ inBody; handle.header _ GVProtocol.ReceiveItemHeader[handle.currentStr ]; IF handle.header.type # PostMark THEN ERROR; postmark _ GVProtocol.ReceiveTimestamp[handle.currentStr]; handle.header _ GVProtocol.ReceiveItemHeader[handle.currentStr]; IF handle.header.type # Sender THEN ERROR; sender _ GVProtocol.ReceiveRName[handle.currentStr]; handle.header _ GVProtocol.ReceiveItemHeader[handle.currentStr]; IF handle.header.type # ReturnTo THEN ERROR; returnTo _ GVProtocol.ReceiveRName[handle.currentStr]; handle.header.length _ 0; -- no more data in this item -- END; NextItem: PUBLIC ENTRY PROCEDURE[handle: GVRetrieveInternal.Handle] RETURNS[itemHeader: GVBasics.ItemHeader] = BEGIN ENABLE { GVProtocol.Failed => Fail[why, text]; UNWIND => NULL }; IF handle.state # inBody THEN [] _ InnerStartMessage[handle]; RETURN[ InnerNextItem[handle] ] END; InnerNextItem: INTERNAL PROCEDURE[handle: GVRetrieveInternal.Handle] RETURNS[itemHeader: GVBasics.ItemHeader ] = BEGIN IF handle.state # inBody THEN ERROR WrongCallSequence[]; IF handle.header.length > 0 OR handle.spareByte THEN InnerSkipItem[handle]; handle.header _ GVProtocol.ReceiveItemHeader[handle.currentStr]; handle.itemLength _ handle.header.length; -- arrange for InnerSkip to include padding byte -- handle.spareByte _ handle.header.length MOD 2 # 0; IF handle.header.type = LastItem THEN BEGIN IF handle.header.length > 0 THEN InnerSkipItem[handle]; [] _ PupStream.ConsumeMark[handle.currentStr ! PupStream.StreamClosing => Fail[communicationError, text]; PupStream.TimeOut => Fail[communicationError, "Mailbox server not sending data"]]; handle.state _ beforeBody; END; itemHeader _ handle.header; END; GVGetChar: PROC[self: IO.STREAM] RETURNS[CHAR] = { RETURN[EntryGetChar[NARROW[self.streamData]]] }; EntryGetChar: ENTRY PROC[handle: GVRetrieveInternal.Handle] RETURNS[CHAR] = BEGIN ENABLE { GVProtocol.Failed => Fail[why, text]; UNWIND => NULL }; IF handle.header.length = 0 THEN ERROR IO.EndOfStream[handle.currentStr]; RETURN[ LOOPHOLE[GVProtocol.ReceiveByte[handle.currentStr]] ] END; GVUnsafeGetBlock: UNSAFE PROCEDURE[ self: IO.STREAM, block: IO.UnsafeBlock ] RETURNS[ nBytesRead: INT ] = UNCHECKED{ RETURN[EntryUnsafeGetBlock[NARROW[self.streamData], block]] }; EntryUnsafeGetBlock: ENTRY UNSAFE PROC[handle: GVRetrieveInternal.Handle, block: IO.UnsafeBlock] RETURNS[nBytesRead: INT] = UNCHECKED BEGIN -- returns 0 forever if we're at the end of the item -- ENABLE { GVProtocol.Failed => CHECKED{ Fail[why, text] }; UNWIND => NULL }; amount: INT = MIN[block.count, handle.header.length]; IF handle.state # inBody THEN ERROR WrongCallSequence[]; GVProtocol.ReceiveBytes[handle.currentStr, [block.base, block.startIndex, block.startIndex+amount]]; handle.header.length _ handle.header.length - amount; RETURN[amount] END; GVEndOf: PROC[self: IO.STREAM] RETURNS[BOOL] = { RETURN[EntryEndOf[NARROW[self.streamData]]] }; EntryEndOf: ENTRY PROC[handle: GVRetrieveInternal.Handle] RETURNS[BOOL] = BEGIN RETURN[handle.header.length = 0] END; GVGetLength: PROC[self: IO.STREAM] RETURNS[length: INT] = { RETURN[EntryGetLength[NARROW[self.streamData]]] }; EntryGetLength: ENTRY PROC[handle: GVRetrieveInternal.Handle] RETURNS[length: INT] = BEGIN RETURN[handle.itemLength] END; GVCharsAvail: PROC[self: IO.STREAM, wait: BOOL] RETURNS[INT] = { RETURN[IF EntryCharsAvail[NARROW[self.streamData]] THEN 1 ELSE 0] }; EntryCharsAvail: ENTRY PROC[handle: GVRetrieveInternal.Handle] RETURNS[BOOL] = BEGIN RETURN[handle.header.length > 0 AND handle.currentStr.CharsAvail[]>0] END; GVCloseStream: PROC[self: IO.STREAM, abort: BOOL _ FALSE] = { EntryCloseStream[NARROW[self.streamData], abort] }; EntryCloseStream: ENTRY PROC[handle: GVRetrieveInternal.Handle, abort: BOOL _ FALSE] = BEGIN InnerSkipItem[handle] END; myStreamProcs: REF IO.StreamProcs = IO.CreateStreamProcs[ variety: $input, class: $Grapevine, getChar: GVGetChar, endOf: GVEndOf, getLength: GVGetLength, charsAvail: GVCharsAvail, unsafeGetBlock: GVUnsafeGetBlock, close: GVCloseStream ]; GetItem: PUBLIC ENTRY PROC[handle: GVRetrieveInternal.Handle] RETURNS[IO.STREAM] = BEGIN IF handle.state # inBody THEN ERROR WrongCallSequence[]; RETURN[IO.CreateStream[myStreamProcs, handle] ]; END; InnerSkipItem: INTERNAL PROCEDURE[ handle: GVRetrieveInternal.Handle ] = BEGIN length: CARDINAL = 128; buffer: PACKED ARRAY[0..length)OF CHARACTER; IF handle.state # inBody THEN ERROR WrongCallSequence[]; IF handle.spareByte THEN handle.header.length _ handle.header.length+1; handle.spareByte _ FALSE; WHILE handle.header.length > 0 DO TRUSTED BEGIN wanted: INT = MIN[handle.header.length, length]; GVProtocol.ReceiveBytes[handle.currentStr, [LOOPHOLE[LONG[@buffer]], 0, wanted] ! GVProtocol.Failed => Fail[communicationError, text] ]; handle.header.length _ handle.header.length - wanted; END; ENDLOOP; END; WriteTOC: PUBLIC ENTRY PROCEDURE[handle: GVRetrieveInternal.Handle, entry: Rope.ROPE] = BEGIN ENABLE { GVProtocol.Failed => Fail[why, text]; UNWIND => NULL }; WHILE handle.state = inBody DO [] _ InnerNextItem[handle]; ENDLOOP; IF handle.state # beforeBody THEN ERROR WrongCallSequence[]; GVProtocol.SendMSOperation[handle.currentStr, writeTOC]; GVProtocol.SendRemark[handle.currentStr, entry]; GVProtocol.SendNow[handle.currentStr]; GVProtocol.ReceiveAck[handle.currentStr]; handle.state _ beforeBody; END; DeleteMessage: PUBLIC ENTRY PROCEDURE[handle: GVRetrieveInternal.Handle] = BEGIN ENABLE { GVProtocol.Failed => Fail[why, text]; UNWIND => NULL }; WHILE handle.state = inBody DO [] _ InnerNextItem[handle]; ENDLOOP; IF handle.state # beforeBody THEN ERROR WrongCallSequence[]; GVProtocol.SendMSOperation[handle.currentStr, deleteMessage]; GVProtocol.SendNow[handle.currentStr]; GVProtocol.ReceiveAck[handle.currentStr]; handle.state _ beforeBody; END; Accept: PUBLIC ENTRY PROCEDURE[ handle: GVRetrieveInternal.Handle ] = BEGIN ENABLE { GVProtocol.Failed => Fail[why, text]; UNWIND => NULL }; IF handle.state # afterMBX THEN ERROR WrongCallSequence[]; GVProtocol.SendMSOperation[handle.currentStr, flushMBX]; GVProtocol.SendNow[handle.currentStr]; GVProtocol.ReceiveAck[handle.currentStr]; GVRetrieveInternal.NoteChangedMBX[handle, handle.currentMBX, empty]; END; GVClose: PUBLIC INTERNAL PROCEDURE[handle: GVRetrieveInternal.Handle] = BEGIN ENABLE { GVProtocol.Failed => Fail[why, text]; UNWIND => NULL }; IF handle.currentStr # NIL THEN GVProtocol.Close[handle.currentStr]; handle.currentStr _ NIL; handle.state _ beforeMBX; END; END. ΆRetrieveGV.mesa: Access to mail on GV servers Copyright c 1985 by Xerox Corporation. All rights reserved. Birrell, August 29, 1983 12:04 pm MBrown, September 17, 1983 8:12 pm Κ ˜˜codešœ-™-Kšœ Οmœ1™šžœžœ˜.Kšžœ˜Kšžœ˜#—K˜—Kšœžœžœ˜ K˜K˜šŸ œžœžœž œ%˜Hšžœ žœ˜Kšœ žœ˜Kšœ žœž˜—Kšžœ)žœžœ˜@Kšžœ˜šžœž˜ K˜DKšΟc;˜;Kšžœžœžœžœ˜&Kšžœž˜KšžœžœR˜\KšœP˜PK˜7K˜9K˜BK˜&šž˜˜ Kšžœ,˜4—šžœž˜Kšœ žœf˜v˜Kšžœ]˜b—Kšœžœ˜—KšžœžœG˜W—Kšžœ˜K˜=K˜Kšžœ˜—Kšžœžœžœ˜CKšžœžœ˜>Kš 2˜2Kšžœ˜Kš žœžœžœžœžœ˜;šžœž˜ K˜$K˜;K˜&K˜9K˜8K˜7Kšžœ ˜ Kšžœ˜Kšžœžœ˜ Kšžœ˜—Kšžœ˜K˜—š Ÿœžœžœžœ$žœžœ˜TKšž˜Kšžœ)žœžœ˜@Kšžœžœžœ˜CKšžœžœžœ˜Kš œžœžœžœžœžœ˜F—K˜š Ÿœžœžœ$žœžœ˜NKšž˜Kšžœžœ"˜EKšžœ˜—K˜š Ÿ œžœžœžœ žœžœ˜;Kšœžœ˜5—K˜š Ÿœžœžœ+žœžœ˜VKšž˜Kšœ˜Kšžœ˜—K˜šœžœžœžœ˜9K˜#Kšœ˜Kšœ˜K˜Kšœ˜Kšœ!˜!K˜—K˜šŸœžœžœžœ$žœžœžœ˜RKšž˜Kšžœžœžœ˜8Kšžœžœ'˜0Kšžœ˜—K˜šŸ œžœž œ'˜HKšž˜Kšœžœ˜Kš œžœžœ žœž œ˜,Kšžœžœžœ˜8Kšžœžœ/˜GKšœžœ˜Kšžœ˜šžœžœž˜Kšœžœžœ˜0šœ,žœžœ˜OKšœ9˜9—Kšœ5˜5Kšžœ˜—Kšžœ˜Kšžœ˜K˜—šŸœžœžœž œ#˜CKšœ žœ˜Kšž˜Kšžœ)žœžœ˜@Kšžœžœžœ˜CKšžœžœžœ˜