-- Transport Mechanism: User: main loop of access to mailboxes --

-- [Juniper]<DMS>MS>RetrieveMail.mesa

-- Andrew Birrell  21-Jan-81 17:26:03 --

DIRECTORY
BodyDefs	USING[ ItemHeader, ItemLength, RName, Timestamp ],
PupDefs		USING[ PupAddress ],
RetrieveDefs	USING[ AccessProcs, FailureReason, MBXState, ServerState,
		       ServerType ],
RetrieveXDefs	USING[ FindAddress, GVAccept, GVClose, GVDeleteMessage,
		       GVNextBlock, GVNextItem, GVNextMessage, GVReadTOC,
		       GVStartMessage, GVWriteTOC, Handle, HandleObject,
		       MBXPtr, MTPAccept, MTPClose, MTPNextBlock,
		       MTPNextItem, MTPNextMessage, NoteChangedMBX,
		       noMBX ],
String		USING[ AppendString ];

RetrieveMail: MONITOR LOCKS handle USING handle: RetrieveXDefs.Handle
   IMPORTS RetrieveXDefs, String
   EXPORTS RetrieveDefs, RetrieveXDefs =

BEGIN

Handle:       PUBLIC TYPE = RetrieveXDefs.Handle;
HandleObject: PUBLIC TYPE = RetrieveXDefs.HandleObject;



MailboxState: PUBLIC ENTRY PROCEDURE[handle: Handle]
              RETURNS[state: RetrieveDefs.MBXState] =
   BEGIN
   ENABLE UNWIND => NULL;
   DO SELECT handle.mbxState FROM
        unknown, userOK => WAIT handle.mbxStateChange;
      ENDCASE => EXIT;
   ENDLOOP;
   RETURN[handle.mbxState]
   END;


-- Client access to his mail: --


WrongCallSequence: ERROR = CODE;

ServerName: PUBLIC ENTRY PROCEDURE[ handle: Handle,
                serverName: BodyDefs.RName ] =
   BEGIN
   IF handle.currentMBX = RetrieveXDefs.noMBX THEN ERROR WrongCallSequence[];
   serverName.length ← 0;
   String.AppendString[serverName, handle.currentMBX.name];
   END;

ServerAddress: PUBLIC INTERNAL PROC[handle: RetrieveXDefs.Handle]
                            RETURNS[ PupDefs.PupAddress ] =
   BEGIN
   IF handle.currentMBX = RetrieveXDefs.noMBX THEN ERROR WrongCallSequence[];
   IF handle.currentMBX.addrState = unknown
   THEN RetrieveXDefs.FindAddress[handle, handle.currentMBX];
   SELECT handle.currentMBX.addrState FROM
     unknown => ERROR Failed[communicationFailure];
     bad =>     ERROR Failed[noSuchServer];
     known =>   RETURN[handle.currentMBX.addr];
   ENDCASE => ERROR;
   END;

NextServer: PUBLIC ENTRY PROCEDURE[handle: Handle]
            RETURNS[ noMore: BOOLEAN,
                     state: RetrieveDefs.ServerState,
                     procs: RetrieveDefs.AccessProcs ] =
   BEGIN
   ENABLE UNWIND => NULL;
   DO SELECT handle.mbxState FROM
        unknown, userOK => WAIT handle.mbxStateChange;
      ENDCASE => EXIT;
   ENDLOOP;
   IF handle.currentMBX = RetrieveXDefs.noMBX
   THEN BEGIN
        handle.currentMBX ← handle.MBXChain;
        handle.newPollWanted ← TRUE; BROADCAST handle.pollCond;
        WHILE handle.newPollWanted DO WAIT handle.mbxStateChange ENDLOOP;
        END
   ELSE BEGIN
        IF handle.currentMBX.type = MTP
        THEN RetrieveXDefs.MTPClose[handle]
        ELSE RetrieveXDefs.GVClose[handle];
        handle.currentMBX ← handle.currentMBX.next;
        END;
   IF handle.currentMBX = RetrieveXDefs.noMBX
   THEN BEGIN
        noMore ← TRUE;
        END
   ELSE BEGIN
        noMore ← FALSE;
        WHILE handle.currentMBX.replyWanted
        DO WAIT handle.mbxStateChange ENDLOOP;
        state ← handle.currentMBX.state;
        IF handle.currentMBX.type = MTP
        THEN BEGIN
             handle.state ← beginning;
             procs ← [ nextMessage: RetrieveXDefs.MTPNextMessage,
                       nextItem:    RetrieveXDefs.MTPNextItem,
                       nextBlock:   RetrieveXDefs.MTPNextBlock,
                       accept:      Accept,
                       extra:       MTP[] ];
             END
        ELSE BEGIN
             handle.header ← [type: LastItem, length: 0];
             handle.spareByte ← FALSE;
             handle.state ← beforeMBX;
             procs ← [ nextMessage: RetrieveXDefs.GVNextMessage,
                       nextItem:    RetrieveXDefs.GVNextItem,
                       nextBlock:   RetrieveXDefs.GVNextBlock,
                       accept:      Accept,
                       extra: GV[
                         readTOC:       RetrieveXDefs.GVReadTOC,
                         startMessage:  RetrieveXDefs.GVStartMessage,
                         writeTOC:      RetrieveXDefs.GVWriteTOC,
                         deleteMessage: RetrieveXDefs.GVDeleteMessage ] ];
             END;
        END;
   END;


Accept: ENTRY PROCEDURE[ handle: Handle ] =
   BEGIN
   ENABLE UNWIND => NULL;
   IF handle.currentMBX.type = MTP
   THEN RetrieveXDefs.MTPAccept[handle]
   ELSE RetrieveXDefs.GVAccept[handle];
   RetrieveXDefs.NoteChangedMBX[handle, handle.currentMBX, empty];
   END;


Failed: PUBLIC ERROR[why: RetrieveDefs.FailureReason] = CODE;


END.