-- Copyright (C) 1981, 1984 by Xerox Corporation. All rights reserved.
-- RetrieveInit.mesa, Transport Mechanism: User: initial stages of mail retrieval/polling --
-- HGM: 11-Dec-84 0:02:10
-- Andrew Birrell 28-Apr-81 14:20:56 --
DIRECTORY
BodyDefs USING [Connect, maxConnectLength, 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],
RetrieveXDefs USING [
GVClose, Handle, HandleObject, MBXData, MBXPtr, noMBX,
NoteChangedMBX, SendPollProcess, SetMBXState],
String USING [AppendString],
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.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
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
IF handle.MBXChain # RetrieveXDefs.noMBX THEN ERROR;
FindGVMailboxes[handle];
END;
FindGVMailboxes: INTERNAL PROC [handle: RetrieveXDefs.Handle] =
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;
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];
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;
SELECT NameInfoDefs.GetConnect[mbx.name, connect] FROM
individual => NULL;
allDown => GOTO noAddr;
group, notFound => GOTO badConnect;
ENDCASE => ERROR;
mbx↑.addr.socket ← [0, 0];
PupDefs.GetPupAddress[
@(mbx↑.addr), connect !
PupDefs.PupNameTrouble =>
IF code = errorFromServer THEN GOTO badConnect ELSE GOTO noAddr];
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.