-- Copyright (C) 1981, 1984, 1985 by Xerox Corporation. All rights reserved. -- RetrieveGV.mesa, Transport Mechanism: User: Access to mail on GV servers -- -- HGM, 15-Sep-85 7:58:31 -- Mark Johnson 12-Nov-81 10:22:52 -- -- Andrew Birrell 21-Jan-81 17:08:41 -- DIRECTORY BodyDefs USING [ItemHeader, ItemLength, RName, Timestamp], Inline USING [LowHalf], NameInfoDefs USING [AuthenticateInfo], ProtocolDefs USING [ CreateStream, DestroyStream, Init, Failed, FailureReason, Handle, mailServerOutputSocket, ReceiveAck, ReceiveBoolean, ReceiveByte, ReceiveCount, ReceiveItemHeader, ReceiveRemark, ReceiveRName, ReceiveTimestamp, SendNow, SendMSOperation, SendPassword, SendRemark, SendRName], PupDefs USING [PupAddress], PupStream USING [StreamClosing], RetrieveDefs USING [Failed, FailureReason], RetrieveXDefs USING [Handle, ServerAddress], Stream USING [ Block, CompletionCode, GetBlock, Handle, SubSequenceType, TimeOut]; RetrieveGV: MONITOR LOCKS handle USING handle: RetrieveXDefs.Handle IMPORTS Inline, ProtocolDefs, PupStream, RetrieveDefs, RetrieveXDefs, Stream EXPORTS RetrieveXDefs = BEGIN Fail: PROC [why: ProtocolDefs.FailureReason] = { ERROR RetrieveDefs.Failed[ IF why = protocolError THEN unknownFailure ELSE communicationFailure]}; WrongCallSequence: ERROR = CODE; GVNextMessage: PUBLIC ENTRY PROCEDURE [handle: RetrieveXDefs.Handle] RETURNS [msgExists: BOOLEAN, archived: BOOLEAN, deleted: BOOLEAN] = BEGIN ENABLE { ProtocolDefs.Failed => Fail[why]; UNWIND => NULL}; IF handle.state = beforeMBX THEN BEGIN addr: PupDefs.PupAddress ← RetrieveXDefs.ServerAddress[handle]; -- we exited by a signal if the address wasn't available -- addr.socket ← ProtocolDefs.mailServerOutputSocket; IF handle.currentStr # NIL THEN ERROR; handle.currentStr ← ProtocolDefs.CreateStream[handle.currentMBX.addr]; ProtocolDefs.SendMSOperation[handle.currentStr, openMBX]; ProtocolDefs.SendRName[handle.currentStr, handle.userName]; ProtocolDefs.SendPassword[ str: handle.currentStr, pw: handle.userKey, key: [0, 0, 0, 0]]; ProtocolDefs.SendNow[handle.currentStr]; BEGIN info: NameInfoDefs.AuthenticateInfo = LOOPHOLE[ProtocolDefs.ReceiveByte[ handle.currentStr]]; SELECT info FROM allDown => ERROR RetrieveDefs.Failed[communicationFailure]; notFound, group, badPwd => ERROR RetrieveDefs.Failed[badCredentials]; individual => NULL; ENDCASE => ERROR RetrieveDefs.Failed[unknownFailure]; END; handle.messages ← ProtocolDefs.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; ProtocolDefs.SendMSOperation[handle.currentStr, nextMessage]; ProtocolDefs.SendNow[handle.currentStr]; msgExists ← ProtocolDefs.ReceiveBoolean[handle.currentStr]; archived ← ProtocolDefs.ReceiveBoolean[handle.currentStr]; deleted ← ProtocolDefs.ReceiveBoolean[handle.currentStr]; IF msgExists THEN handle.state ← beforeBody ELSE ERROR; END; END; GVReadTOC: PUBLIC ENTRY PROCEDURE [handle: RetrieveXDefs.Handle, text: LONG STRING] = BEGIN ENABLE { ProtocolDefs.Failed => Fail[why]; UNWIND => NULL}; WHILE handle.state = inBody DO [] ← InnerNextItem[handle]; ENDLOOP; IF handle.state # beforeBody THEN ERROR WrongCallSequence[]; ProtocolDefs.SendMSOperation[handle.currentStr, readTOC]; ProtocolDefs.SendNow[handle.currentStr]; ProtocolDefs.ReceiveRemark[handle.currentStr, text]; END; GVStartMessage: PUBLIC ENTRY PROCEDURE [ handle: RetrieveXDefs.Handle, postmark: LONG POINTER TO BodyDefs.Timestamp ← NIL, sender: BodyDefs.RName ← NIL, returnTo: BodyDefs.RName ← NIL] = BEGIN ENABLE { ProtocolDefs.Failed => Fail[why]; UNWIND => NULL}; InnerStartMessage[handle, postmark, sender, returnTo]; END; InnerStartMessage: INTERNAL PROCEDURE [ handle: RetrieveXDefs.Handle, postmark: LONG POINTER TO BodyDefs.Timestamp ← NIL, sender: BodyDefs.RName ← NIL, returnTo: BodyDefs.RName ← NIL] = BEGIN WHILE handle.state = inBody DO [] ← InnerNextItem[handle]; ENDLOOP; IF handle.state # beforeBody THEN ERROR WrongCallSequence[]; ProtocolDefs.SendMSOperation[handle.currentStr, readMessage]; ProtocolDefs.SendNow[handle.currentStr]; handle.state ← inBody; handle.header ← ProtocolDefs.ReceiveItemHeader[handle.currentStr]; IF handle.header.type # PostMark THEN ERROR; IF postmark # NIL THEN postmark↑ ← ProtocolDefs.ReceiveTimestamp[handle.currentStr] ELSE InnerSkipItem[handle]; handle.header ← ProtocolDefs.ReceiveItemHeader[handle.currentStr]; IF handle.header.type # Sender THEN ERROR; IF sender # NIL THEN ProtocolDefs.ReceiveRName[handle.currentStr, sender] ELSE InnerSkipItem[handle]; handle.header ← ProtocolDefs.ReceiveItemHeader[handle.currentStr]; IF handle.header.type # ReturnTo THEN ERROR; IF returnTo # NIL THEN ProtocolDefs.ReceiveRName[handle.currentStr, returnTo] ELSE InnerSkipItem[handle]; handle.header.length ← 0; -- no more data in this item -- END; GVNextItem: PUBLIC ENTRY PROCEDURE [handle: RetrieveXDefs.Handle] RETURNS [itemHeader: BodyDefs.ItemHeader] = BEGIN ENABLE { ProtocolDefs.Failed => Fail[why]; UNWIND => NULL}; IF handle.state # inBody THEN InnerStartMessage[handle]; RETURN[InnerNextItem[handle]] END; InnerNextItem: INTERNAL PROCEDURE [handle: RetrieveXDefs.Handle] RETURNS [itemHeader: BodyDefs.ItemHeader] = BEGIN IF handle.state # inBody THEN ERROR WrongCallSequence[]; IF handle.header.length > 0 OR handle.spareByte THEN InnerSkipItem[handle]; handle.header ← ProtocolDefs.ReceiveItemHeader[handle.currentStr]; -- arrange for InnerSkip to include padding byte -- handle.spareByte ← handle.header.length MOD 2 # 0; IF handle.header.type = LastItem THEN BEGIN why: Stream.CompletionCode ← normal; buffer: CHARACTER; bufferAddr: LONG POINTER ← @buffer; IF handle.header.length > 0 THEN InnerSkipItem[handle]; WHILE why # sstChange DO [, why, ] ← Stream.GetBlock[ handle.currentStr, [LOOPHOLE[bufferAddr], 0, 1] ! PupStream.StreamClosing, Stream.TimeOut => Fail[communicationError]]; ENDLOOP; handle.state ← beforeBody; END; itemHeader ← handle.header; END; GVNextBlock: PUBLIC ENTRY PROCEDURE [ handle: RetrieveXDefs.Handle, buffer: LONG DESCRIPTOR FOR PACKED ARRAY OF CHARACTER] RETURNS [bytes: CARDINAL] = BEGIN -- returns 0 forever if we're at the end of the item -- ENABLE { ProtocolDefs.Failed => Fail[why]; UNWIND => NULL}; why: Stream.CompletionCode; sst: Stream.SubSequenceType; bufferAddr: LONG POINTER ← BASE[buffer]; IF handle.state # inBody THEN ERROR WrongCallSequence[]; [bytes, why, sst] ← Stream.GetBlock[ handle.currentStr, [ LOOPHOLE[bufferAddr], 0, IF LENGTH[buffer] > handle.header.length THEN Inline.LowHalf[ handle.header.length] ELSE LENGTH[buffer]] ! PupStream.StreamClosing, Stream.TimeOut => Fail[communicationError]]; IF why # normal THEN ERROR; handle.header.length ← handle.header.length - bytes; END; InnerSkipItem: INTERNAL PROCEDURE [handle: RetrieveXDefs.Handle] = BEGIN length: CARDINAL = 128; buffer: PACKED ARRAY [0..length) OF CHARACTER; bufferAddr: LONG POINTER ← @buffer; used: CARDINAL; why: Stream.CompletionCode; sst: Stream.SubSequenceType; 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 BEGIN wanted: CARDINAL = IF handle.header.length > length THEN length ELSE Inline.LowHalf[handle.header.length]; [used, why, sst] ← Stream.GetBlock[ handle.currentStr, [LOOPHOLE[bufferAddr], 0, wanted] ! PupStream.StreamClosing, Stream.TimeOut => Fail[communicationError]]; IF why # normal THEN ERROR; handle.header.length ← handle.header.length - used; END; ENDLOOP; END; GVWriteTOC: PUBLIC ENTRY PROCEDURE [ handle: RetrieveXDefs.Handle, text: LONG STRING] = BEGIN ENABLE { ProtocolDefs.Failed => Fail[why]; UNWIND => NULL}; WHILE handle.state = inBody DO [] ← InnerNextItem[handle]; ENDLOOP; IF handle.state # beforeBody THEN ERROR WrongCallSequence[]; ProtocolDefs.SendMSOperation[handle.currentStr, writeTOC]; ProtocolDefs.SendRemark[handle.currentStr, text]; ProtocolDefs.SendNow[handle.currentStr]; ProtocolDefs.ReceiveAck[handle.currentStr]; handle.state ← beforeBody; END; GVDeleteMessage: PUBLIC ENTRY PROCEDURE [handle: RetrieveXDefs.Handle] = BEGIN ENABLE { ProtocolDefs.Failed => Fail[why]; UNWIND => NULL}; WHILE handle.state = inBody DO [] ← InnerNextItem[handle]; ENDLOOP; IF handle.state # beforeBody THEN ERROR WrongCallSequence[]; ProtocolDefs.SendMSOperation[handle.currentStr, deleteMessage]; ProtocolDefs.SendNow[handle.currentStr]; ProtocolDefs.ReceiveAck[handle.currentStr]; handle.state ← beforeBody; END; GVAccept: PUBLIC INTERNAL PROCEDURE [handle: RetrieveXDefs.Handle] = BEGIN ENABLE { ProtocolDefs.Failed => Fail[why]; UNWIND => NULL}; IF handle.state # afterMBX THEN ERROR WrongCallSequence[]; ProtocolDefs.SendMSOperation[handle.currentStr, flushMBX]; ProtocolDefs.SendNow[handle.currentStr]; ProtocolDefs.ReceiveAck[handle.currentStr]; END; GVClose: PUBLIC INTERNAL PROCEDURE [handle: RetrieveXDefs.Handle] = BEGIN IF handle.currentStr # NIL THEN ProtocolDefs.DestroyStream[handle.currentStr]; handle.currentStr ← NIL; handle.state ← beforeMBX; END; ProtocolDefs.Init[]; END.