-- Copyright (C) 1981, 1984  by Xerox Corporation. All rights reserved. 
-- RetrieveMail.mesa, Transport Mechanism: User: main loop of access to mailboxes --

-- HGM: 10-Dec-84 23:52:22
-- Andrew Birrell  21-Jan-81 17:26:03 --

DIRECTORY
  BodyDefs USING [ItemHeader, ItemLength, RName, Timestamp],
  PupDefs USING [PupAddress],
  RetrieveDefs USING [
    AccessProcs, FailureReason, MBXState, ServerState],
  RetrieveXDefs USING [
    FindAddress, GVAccept, GVClose, GVDeleteMessage, GVNextBlock, GVNextItem,
    GVNextMessage, GVReadTOC, GVStartMessage, GVWriteTOC, Handle, HandleObject,
    MBXPtr, 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
      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;
      handle.header ← [type: LastItem, length: 0];
      handle.spareByte ← FALSE;
      handle.state ← beforeMBX;
      procs ← [
        nextMessage: RetrieveXDefs.GVNextMessage,
        nextItem: RetrieveXDefs.GVNextItem,
        nextBlock: RetrieveXDefs.GVNextBlock, accept: Accept,
        readTOC: RetrieveXDefs.GVReadTOC,
        startMessage: RetrieveXDefs.GVStartMessage,
        writeTOC: RetrieveXDefs.GVWriteTOC,
        deleteMessage: RetrieveXDefs.GVDeleteMessage];
      END;
    END;


  Accept: ENTRY PROCEDURE [handle: Handle] =
    BEGIN
    ENABLE UNWIND => NULL;
    RetrieveXDefs.GVAccept[handle];
    RetrieveXDefs.NoteChangedMBX[handle, handle.currentMBX, empty];
    END;


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


  END.