-- Transport Mechanism: User: initial stages of mail retrieval/polling --
-- [Juniper]<DMS>MS>RetrieveInit.mesa
-- Andrew Birrell 28-Apr-81 14:20:56 --
DIRECTORY
BodyDefs USING[ Connect, maxConnectLength,
maxRNameLength, RName, Timestamp ],
NameInfoDefs USING[ Close, Enumerate,
Expand, ExpandInfo, GetConnect, NameType ],
Process USING[ DisableTimeout, InitializeCondition,
InitializeMonitor ],
ProtocolDefs USING[ Init, mailServerOutputSocket, MakeKey ],
PupDefs,
PupTypes,
RetrieveDefs USING[ MBXState, ServerState,
ServerType ],
RetrieveXDefs USING[ GVClose, Handle, HandleObject,
MBXData, MBXPtr, MTPClose, noMBX, NoteChangedMBX,
SendPollProcess, SetMBXState ],
String USING[ AppendString, EquivalentString ],
Storage USING[ Node, String,
Free, FreeString ];
RetrieveInit: MONITOR LOCKS handle USING handle: RetrieveXDefs.Handle
IMPORTS NameInfoDefs,
Process, ProtocolDefs, PupDefs, RetrieveXDefs,
String, Storage
EXPORTS RetrieveDefs, RetrieveXDefs =
BEGIN
Handle: PUBLIC TYPE = RetrieveXDefs.Handle;
HandleObject: PUBLIC TYPE = RetrieveXDefs.HandleObject;
-- low-level utilities: --
KeepString: PROC[keep: POINTER TO STRING, str: STRING] =
BEGIN
IF keep↑ # NIL THEN Storage.FreeString[keep↑];
IF str # NIL
THEN BEGIN
keep↑ ← Storage.String[str.length];
String.AppendString[keep↑, str];
END;
END;
-- Global state control by the client: --
Create: PUBLIC PROCEDURE[ pollingInterval: CARDINAL,
reportChanges: PROCEDURE[RetrieveDefs.MBXState] ← NIL ]
RETURNS[ handle: Handle ] =
BEGIN
handle ← Storage.Node[SIZE[HandleObject]];
BEGIN
handle.MBXChain ← RetrieveXDefs.noMBX;
handle.mbxKnown ← FALSE;
handle.notEmptyMBXCount ← 0;
handle.unknownMBXCount ← 0;
handle.registry ← GV;
-- handle.state ← ;
handle.spareByte ← FALSE;
-- handle.spareByteValue ←;
-- handle.header ← ;
handle.currentMBX ← RetrieveXDefs.noMBX;
handle.messages ← 0;
handle.currentStr ← NIL;
handle.ftpUser ← 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 ← 0;
handle.interval ← pollingInterval;
handle.changes ← reportChanges;
handle.userName ← NIL;
handle.userPwd ← NIL;
handle.userKey ← [0,0,0,0];
END;
Process.InitializeMonitor[@(handle.LOCK)];
Process.InitializeCondition[@(handle.pollCond), 0];
-- the polling process adjusts the timeout on handle.pollCond --
Process.InitializeCondition[@(handle.mbxStateChange), 0];
Process.DisableTimeout[@(handle.mbxStateChange)];
END;
NewUser: PUBLIC ENTRY PROCEDURE[ handle: Handle, user, password: STRING] =
BEGIN
UnsetMailboxes[handle];
IF user = NIL OR user.length = 0
THEN RetrieveXDefs.SetMBXState[handle, badName]
ELSE IF password = NIL OR password.length = 0
THEN RetrieveXDefs.SetMBXState[handle, badPwd]
ELSE BEGIN
KeepString[@(handle.userName), user];
KeepString[@(handle.userPwd), password];
handle.userKey ← ProtocolDefs.MakeKey[handle.userPwd];
RestartPoll[handle];
END;
END;
Destroy: PUBLIC PROCEDURE[ handle: Handle ] =
BEGIN
InnerDestroy[handle];
Storage.Free[handle];
END;
InnerDestroy: ENTRY PROCEDURE[ handle: Handle ] = INLINE
BEGIN
UnsetMailboxes[handle];
KeepString[@handle.userName, NIL];
KeepString[@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 RetrieveXDefs.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;
JOIN handle.sendPoll;
END;
IF handle.currentMBX # RetrieveXDefs.noMBX
THEN BEGIN
IF handle.currentMBX.type = MTP
THEN RetrieveXDefs.MTPClose[handle]
ELSE RetrieveXDefs.GVClose[handle];
handle.currentMBX ← RetrieveXDefs.noMBX;
END;
handle.unknownMBXCount ← handle.notEmptyMBXCount ← 0;
RetrieveXDefs.SetMBXState[handle, unknown];
handle.mbxKnown ← FALSE;
UNTIL handle.MBXChain = RetrieveXDefs.noMBX
DO BEGIN
next: RetrieveXDefs.MBXPtr = handle.MBXChain.next;
IF handle.MBXChain.name # NIL
THEN Storage.FreeString[handle.MBXChain.name];
Storage.Free[handle.MBXChain]; handle.MBXChain ← next;
END;
ENDLOOP;
END;
defaultHost: STRING ← NIL;
defaultReg: STRING ← NIL;
SetMTPRetrieveDefault: PUBLIC --ENTRY?-- PROC[host, reg: STRING] =
BEGIN
KeepString[@defaultHost, IF reg=NIL THEN NIL ELSE host];
KeepString[@defaultReg, IF host=NIL THEN NIL ELSE reg];
END;
FindRegistryAndMailboxes:
PUBLIC INTERNAL PROCEDURE[handle: RetrieveXDefs.Handle] =
BEGIN
registry: BodyDefs.RName = [BodyDefs.maxRNameLength];
registryAddr: PupDefs.PupAddress;
BEGIN
rStart: CARDINAL ← 0;
FOR index: CARDINAL DECREASING IN [0..handle.userName.length)
DO IF handle.userName[index] = '. THEN {rStart ← index+1; EXIT};
ENDLOOP;
FOR index: CARDINAL IN [rStart..handle.userName.length)
WHILE registry.length < registry.maxlength
DO registry[registry.length] ← handle.userName[index];
registry.length ← registry.length + 1;
ENDLOOP;
END;
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;
registryAddr ← addr; 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 # RetrieveXDefs.noMBX THEN ERROR;
IF handle.registry = MTP
THEN BEGIN
default: BOOLEAN = defaultReg # NIL AND
String.EquivalentString[registry, defaultReg];
this: RetrieveXDefs.MBXPtr = AddMBX[handle,
IF default THEN defaultHost ELSE registry];
IF default
THEN FindAddress[handle, this]
ELSE { this.addrState ← known; this.addr ← registryAddr };
handle.mbxKnown ← TRUE;
END
ELSE FindGVMailboxes[handle];
EXITS
noReg => RetrieveXDefs.SetMBXState[handle, cantAuth];
END;
FindGVMailboxes: INTERNAL PROC[handle: RetrieveXDefs.Handle] =
BEGIN
IF handle.registry # GV
THEN ERROR
ELSE BEGIN
Work: INTERNAL PROCEDURE[site:BodyDefs.RName]RETURNS[done:BOOLEAN] =
BEGIN
done ← FALSE;
FindAddress[handle, AddMBX[handle, site] ];
END;
info: NameInfoDefs.ExpandInfo = NameInfoDefs.Expand[handle.userName];
WITH info SELECT FROM
allDown => RetrieveXDefs.SetMBXState[handle, cantAuth];
notFound => RetrieveXDefs.SetMBXState[handle, badName];
group =>
BEGIN
-- this case include individual with forwarding --
NameInfoDefs.Close[members];
handle.mbxKnown ← TRUE;
END;
individual =>
BEGIN
NameInfoDefs.Enumerate[sites, Work];
NameInfoDefs.Close[sites];
handle.mbxKnown ← TRUE;
END;
ENDCASE => ERROR;
END;
END;
AddMBX: INTERNAL PROCEDURE[handle: RetrieveXDefs.Handle,
site:BodyDefs.RName]
RETURNS[this: RetrieveXDefs.MBXPtr] =
BEGIN
mbx: POINTER TO RetrieveXDefs.MBXPtr ← @(handle.MBXChain);
-- skip to end of mailbox chain --
WHILE mbx↑ # RetrieveXDefs.noMBX DO mbx ← @(mbx↑.next); ENDLOOP;
mbx↑ ← Storage.Node[SIZE[RetrieveXDefs.MBXData]];
this ← mbx↑;
this.name ← NIL; KeepString[@(this.name), site];
FOR index: CARDINAL DECREASING IN [0..site.length)
DO IF site[index] = '. THEN { this.type ← GV; EXIT };
REPEAT FINISHED => this.type ← MTP;
ENDLOOP;
this.next ← RetrieveXDefs.noMBX;
this.state ← unknown; this.replyWanted ← TRUE;
handle.unknownMBXCount ← handle.unknownMBXCount + 1;
IF handle.mbxState = allEmpty
THEN RetrieveXDefs.SetMBXState[handle, userOK];
this.addrState ← unknown;
END;
FindAddress: PUBLIC INTERNAL PROC[handle: RetrieveXDefs.Handle,
mbx: RetrieveXDefs.MBXPtr] =
BEGIN
connect: BodyDefs.Connect = [BodyDefs.maxConnectLength];
IF mbx.addrState # unknown THEN ERROR;
IF mbx.type = GV
THEN SELECT NameInfoDefs.GetConnect[mbx.name, connect] FROM
individual => NULL;
allDown => GOTO noAddr;
group, notFound => GOTO badConnect;
ENDCASE => ERROR
ELSE String.AppendString[connect, mbx.name];
mbx↑.addr.socket ← [0,0];
PupDefs.GetPupAddress[@(mbx↑.addr), connect ! PupDefs.PupNameTrouble =>
IF code = errorFromServer THEN GOTO badConnect ELSE GOTO noAddr ];
IF mbx.type = GV
THEN mbx.addr.socket ← ProtocolDefs.mailServerOutputSocket;
mbx.addrState ← known;
EXITS
badConnect =>
{ RetrieveXDefs.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;
ProtocolDefs.Init[];
END.