-- Transport Mechanism: User: Access to mail on GV servers -- -- [Juniper]<DMS>MS>RetrieveGV.mesa -- 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: 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: 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: 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; IF handle.header.length > 0 THEN InnerSkipItem[handle]; WHILE why # sstChange DO [,why,] ← Stream.GetBlock[handle.currentStr, [@buffer, 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: 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; IF handle.state # inBody THEN ERROR WrongCallSequence[]; [bytes, why, sst] ← Stream.GetBlock[handle.currentStr, [ BASE[buffer], 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; 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, [@buffer, 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: 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.