RetrieveInit.mesa: initial stages of mail retrieval/polling
Copyright © 1985 by Xerox Corporation. All rights reserved.
Birrell, August 29, 1983 11:54 am
Russ Atkinson (RRA) May 21, 1985 4:31:04 pm PDT
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 = {
Handle: PUBLIC TYPE = GVRetrieveInternal.Handle;
HandleObject: PUBLIC TYPE = GVRetrieveInternal.HandleObject;
Global state control by the client:
Create:
PUBLIC
PROC [ pollingInterval:
CARDINAL, reportChanges:
PROC [GVRetrieve.MBXState] ←
NIL ]
RETURNS [ handle: Handle ] = {
handle ← NEW[HandleObject];
{
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];
};
};
NewUser:
PUBLIC
ENTRY
PROC [ handle: Handle, user, password: Rope.
ROPE] = {
UnsetMailboxes[handle];
IF user.Length[] = 0
THEN GVRetrieveInternal.SetMBXState[handle, badName]
ELSE
IF password.Length[] = 0
THEN GVRetrieveInternal.SetMBXState[handle, badPwd]
ELSE {
handle.userName ← user;
handle.userPwd ← password;
handle.userKey ← GVBasics.MakeKey[handle.userPwd];
RestartPoll[handle];
};
};
Close:
PUBLIC
ENTRY
PROC [handle: Handle] = {
UnsetMailboxes[handle];
handle.userName ← NIL;
handle.userPwd ← NIL;
};
RestartPoll:
INTERNAL
PROC [handle: Handle] = {
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;
};
UnsetMailboxes:
INTERNAL
PROC [handle: Handle] = {
IF handle.polling
THEN {
sendPoll: PROCESS ← NIL;
handle.pollWanted ← FALSE;
BROADCAST handle.pollCond;
WHILE handle.polling DO WAIT handle.pollCond ENDLOOP;
sendPoll ← handle.sendPoll;
IF sendPoll #
NIL
THEN
TRUSTED {
RRA: Wait for the sendPoll process to finish. Also show that we do not need another JOIN.
handle.sendPoll ← NIL;
JOIN sendPoll;
};
};
IF handle.currentMBX # GVRetrieveInternal.noMBX
THEN {
GVRetrieveInternal.GVClose[handle];
handle.currentMBX ← GVRetrieveInternal.noMBX;
};
handle.unknownMBXCount ← handle.notEmptyMBXCount ← 0;
GVRetrieveInternal.SetMBXState[handle, unknown];
handle.mbxKnown ← FALSE;
handle.MBXChain ← GVRetrieveInternal.noMBX;
};
FindRegistryAndMailboxes:
PUBLIC
INTERNAL
PROC [handle: GVRetrieveInternal.Handle] = {
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];
{
called: BOOLEAN ← FALSE;
Work:
INTERNAL
PROC [addr:PupDefs.PupAddress]
RETURNS [stop:
BOOLEAN] =
{
IF called
THEN { handle.registry ← GV; stop ← TRUE }
ELSE { handle.registry ← MTP; called ← TRUE; stop ← FALSE };
};
handle.registry ← GV; -- default if registry isn't in NLS
[] ← PupDefs.EnumeratePupAddresses[registry, Work ! PupDefs.PupNameTrouble =>
IF code = errorFromServer THEN CONTINUE ELSE GOTO noReg ];
};
IF handle.MBXChain # GVRetrieveInternal.noMBX THEN ERROR;
IF handle.registry =
MTP
THEN {
FindAddress[handle, AddMBX[handle, registry]];
handle.mbxKnown ← TRUE;
}
ELSE FindGVMailboxes[handle];
EXITS
noReg => GVRetrieveInternal.SetMBXState[handle, cantAuth];
};
FindGVMailboxes:
INTERNAL
PROC [handle: GVRetrieveInternal.Handle] = {
IF handle.registry #
GV
THEN ERROR
ELSE
TRUSTED {
info: GVNames.ExpandInfo = GVNames.Expand[handle.userName];
WITH info
SELECT
FROM
allDown => GVRetrieveInternal.SetMBXState[handle, cantAuth];
notFound => GVRetrieveInternal.SetMBXState[handle, badName];
group =>
{
this case includes individual with forwarding
handle.mbxKnown ← TRUE;
};
individual =>
{
FOR site: GVNames.RListHandle ← sites, site.rest UNTIL site = NIL
DO FindAddress[handle, AddMBX[handle, site.first] ] ENDLOOP;
handle.mbxKnown ← TRUE;
};
ENDCASE => ERROR;
};
};
AddMBX:
INTERNAL
PROC [handle: GVRetrieveInternal.Handle, site: GVBasics.RName]
RETURNS [this: GVRetrieveInternal.MBXPtr] = {
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;
};
FindAddress:
PUBLIC
INTERNAL
PROC [handle: GVRetrieveInternal.Handle, mbx: GVRetrieveInternal.MBXPtr] = {
connect: GVBasics.Connect;
info: GVNames.ConnectInfo;
IF mbx.addrState # unknown THEN ERROR;
IF mbx.type = GV
THEN {
[info, connect] ← GVNames.GetConnect[mbx.name];
SELECT info
FROM
individual => NULL;
allDown => GOTO noAddr;
group, notFound => GOTO badConnect;
ENDCASE => ERROR;
}
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;
};
WaitForMail:
PUBLIC
ENTRY
PROC [handle: Handle] = {
WHILE handle.mbxState # notEmpty DO WAIT handle.mbxStateChange ENDLOOP;
};
}.