GrapevineUser (Cedar): initial stages of mail retrieval/polling
RetrieveInit.mesa
Andrew Birrell 28-Apr-81 14:20:56
Last Edited by: Birrell, August 29, 1983 11:54 am
DIRECTORY
BasicTime USING[ Now ],
GVBasics USING[ Connect, MakeKey, RName, Timestamp ],
GVNames USING[ ConnectInfo, Expand, ExpandInfo, GetConnect, NameType, RListHandle ],
PupDefs,
PupTypes,
GVRetrieve USING[ MBXState, ServerState, ServerType ],
GVRetrieveInternal USING[ GVClose, Handle, HandleObject, MBXData, MBXPtr, noMBX, NoteChangedMBX, SendPollProcess, SetMBXState ],
Rope USING[ Find, Length, ROPE, Substr ];
RetrieveInit:
CEDAR
MONITOR
LOCKS handle
USING handle: GVRetrieveInternal.Handle
IMPORTS BasicTime, GVBasics, GVNames, PupDefs, GVRetrieveInternal, Rope
EXPORTS GVRetrieve, GVRetrieveInternal =
BEGIN
Handle: PUBLIC TYPE = GVRetrieveInternal.Handle;
HandleObject: PUBLIC TYPE = GVRetrieveInternal.HandleObject;
-- Global state control by the client: --
Create:
PUBLIC
PROCEDURE[ pollingInterval:
CARDINAL,
reportChanges: PROCEDURE[GVRetrieve.MBXState] ← NIL ]
RETURNS[ handle: Handle ] =
BEGIN
handle ← NEW[HandleObject];
BEGIN
handle.MBXChain ← GVRetrieveInternal.noMBX;
handle.mbxKnown ← FALSE;
handle.notEmptyMBXCount ← 0;
handle.unknownMBXCount ← 0;
handle.registry ← GV;
handle.state ← ;
handle.spareByte ← FALSE;
handle.spareByteValue ←
handle.header ← ;
handle.currentMBX ← GVRetrieveInternal.noMBX;
handle.messages ← 0;
handle.currentStr ← NIL;
handle.mbxState ← badName;
handle.polling ← FALSE;
handle.pollWanted ← FALSE;
handle.newPollWanted ← FALSE;
handle.pollReplying ← FALSE;
handle.mbxStateChange ←
handle.pollCond ← ;
handle.pollID ← [0,1];
handle.sendPoll ← ;
handle.pollStarted ← BasicTime.Now[];
handle.interval ← pollingInterval;
handle.changes ← reportChanges;
handle.userName ← NIL;
handle.userPwd ← NIL;
handle.userKey ← [0,0,0,0];
END;
END;
NewUser:
PUBLIC
ENTRY
PROCEDURE[ handle: Handle, user, password: Rope.
ROPE] =
BEGIN
UnsetMailboxes[handle];
IF user.Length[] = 0
THEN GVRetrieveInternal.SetMBXState[handle, badName]
ELSE
IF password.Length[] = 0
THEN GVRetrieveInternal.SetMBXState[handle, badPwd]
ELSE
BEGIN
handle.userName ← user;
handle.userPwd ← password;
handle.userKey ← GVBasics.MakeKey[handle.userPwd];
RestartPoll[handle];
END;
END;
Close:
PUBLIC
ENTRY
PROC[handle: Handle] =
BEGIN
UnsetMailboxes[handle];
handle.userName ← NIL;
handle.userPwd ← NIL;
END;
RestartPoll:
INTERNAL
PROCEDURE[handle: Handle] =
BEGIN
handle.pollID.b ← handle.pollID.b + 1; --to ignore old poll replies--
IF NOT handle.polling
THEN handle.sendPoll ← FORK GVRetrieveInternal.SendPollProcess[handle];
handle.polling ← handle.pollWanted ← TRUE;
handle.newPollWanted ← TRUE; BROADCAST handle.pollCond;
END;
UnsetMailboxes:
INTERNAL
PROCEDURE[handle: Handle] =
BEGIN
IF handle.polling
THEN
BEGIN
handle.pollWanted ← FALSE; BROADCAST handle.pollCond;
WHILE handle.polling DO WAIT handle.pollCond ENDLOOP;
TRUSTED{ JOIN handle.sendPoll };
END;
IF handle.currentMBX # GVRetrieveInternal.noMBX
THEN
BEGIN
GVRetrieveInternal.GVClose[handle];
handle.currentMBX ← GVRetrieveInternal.noMBX;
END;
handle.unknownMBXCount ← handle.notEmptyMBXCount ← 0;
GVRetrieveInternal.SetMBXState[handle, unknown];
handle.mbxKnown ← FALSE;
handle.MBXChain ← GVRetrieveInternal.noMBX;
END;
FindRegistryAndMailboxes:
PUBLIC
INTERNAL
PROC[handle: GVRetrieveInternal.Handle] =
BEGIN
length: INT = handle.userName.Length[];
firstRegChar: INT = handle.userName.Find["."]+1; -- =0 if no dot found
registry: Rope.ROPE = handle.userName.Substr[firstRegChar, length-firstRegChar];
BEGIN
called: BOOLEAN ← FALSE;
Work:
INTERNAL
PROC[addr:PupDefs.PupAddress]
RETURNS[stop:
BOOLEAN] =
BEGIN
IF called
THEN { handle.registry ← GV; stop ← TRUE }
ELSE { handle.registry ← MTP; called ← TRUE; stop ← FALSE };
END;
handle.registry ← GV; -- default if registry isn't in NLS --
[] ← PupDefs.EnumeratePupAddresses[registry, Work ! PupDefs.PupNameTrouble =>
IF code = errorFromServer THEN CONTINUE ELSE GOTO noReg ];
END;
IF handle.MBXChain # GVRetrieveInternal.noMBX THEN ERROR;
IF handle.registry = MTP
THEN
BEGIN
FindAddress[handle, AddMBX[handle, registry]];
handle.mbxKnown ← TRUE;
END
ELSE FindGVMailboxes[handle];
EXITS
noReg => GVRetrieveInternal.SetMBXState[handle, cantAuth];
END;
FindGVMailboxes:
INTERNAL
PROC[handle: GVRetrieveInternal.Handle] =
BEGIN
IF handle.registry # GV
THEN ERROR
ELSE
TRUSTED
BEGIN
info: GVNames.ExpandInfo = GVNames.Expand[handle.userName];
WITH info
SELECT
FROM
allDown => GVRetrieveInternal.SetMBXState[handle, cantAuth];
notFound => GVRetrieveInternal.SetMBXState[handle, badName];
group =>
BEGIN
-- this case includes individual with forwarding --
handle.mbxKnown ← TRUE;
END;
individual =>
BEGIN
FOR site: GVNames.RListHandle ← sites, site.rest UNTIL site = NIL
DO FindAddress[handle, AddMBX[handle, site.first] ] ENDLOOP;
handle.mbxKnown ← TRUE;
END;
ENDCASE => ERROR;
END;
END;
AddMBX:
INTERNAL
PROCEDURE[handle: GVRetrieveInternal.Handle, site: GVBasics.RName]
RETURNS[this: GVRetrieveInternal.MBXPtr] =
BEGIN
last: GVRetrieveInternal.MBXPtr ← NIL;
-- skip to end of mailbox chain --
FOR old: GVRetrieveInternal.MBXPtr ← handle.MBXChain, old.next UNTIL old = NIL
DO last ← old ENDLOOP;
this ← NEW[GVRetrieveInternal.MBXData];
IF last = NIL THEN handle.MBXChain ← this ELSE last.next ← this;
this.name ← site;
this.type ← IF site.Find["."] < 0 THEN MTP ELSE GV;
this.next ← GVRetrieveInternal.noMBX;
this.state ← unknown; this.replyWanted ← TRUE;
handle.unknownMBXCount ← handle.unknownMBXCount + 1;
IF handle.mbxState = allEmpty THEN GVRetrieveInternal.SetMBXState[handle, userOK];
this.addrState ← unknown;
END;
FindAddress:
PUBLIC
INTERNAL
PROC[handle: GVRetrieveInternal.Handle, mbx: GVRetrieveInternal.MBXPtr] =
BEGIN
connect: GVBasics.Connect;
info: GVNames.ConnectInfo;
IF mbx.addrState # unknown THEN ERROR;
IF mbx.type = GV
THEN
BEGIN
[info, connect] ← GVNames.GetConnect[mbx.name];
SELECT info
FROM
individual => NULL;
allDown => GOTO noAddr;
group, notFound => GOTO badConnect;
ENDCASE => ERROR;
END
ELSE connect ← mbx.name;
mbx^.addr ← PupDefs.GetPupAddress[[0,0], connect ! PupDefs.PupNameTrouble =>
IF code = errorFromServer THEN GOTO badConnect ELSE GOTO noAddr ];
mbx.addrState ← known;
EXITS
badConnect =>
{ GVRetrieveInternal.NoteChangedMBX[handle,mbx,empty];
mbx.addrState ← bad };
noAddr => NULL;
END;
WaitForMail:
PUBLIC
ENTRY
PROCEDURE[handle: Handle] =
BEGIN
WHILE handle.mbxState # notEmpty DO WAIT handle.mbxStateChange ENDLOOP;
END;
END.