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: PROCESSNIL;
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: BOOLEANFALSE;
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;
};
}.