-- Copyright (C) 1981, 1984, 1985 by Xerox Corporation. All rights reserved. -- RetrieveInit.mesa, Transport Mechanism: User: initial stages of mail retrieval/polling -- -- HGM: 15-Sep-85 8:03:07 -- Andrew Birrell 28-Apr-81 14:20:56 -- DIRECTORY BodyDefs USING [Connect, maxConnectLength, RName, Timestamp], Heap USING [systemZone], 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]; RetrieveInit: MONITOR LOCKS handle USING handle: RetrieveXDefs.Handle IMPORTS Heap, NameInfoDefs, Process, ProtocolDefs, PupDefs, RetrieveXDefs, String EXPORTS RetrieveDefs, RetrieveXDefs = BEGIN Handle: PUBLIC TYPE = RetrieveXDefs.Handle; HandleObject: PUBLIC TYPE = RetrieveXDefs.HandleObject; -- low-level utilities: -- KeepString: PROC [keep: LONG POINTER TO LONG STRING, str: LONG STRING] = BEGIN Heap.systemZone.FREE[keep]; IF str # NIL THEN BEGIN keep↑ ← Heap.systemZone.NEW[StringBody[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 ← Heap.systemZone.NEW[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: LONG 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]; Heap.systemZone.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; Heap.systemZone.FREE[@handle.MBXChain.name]; Heap.systemZone.FREE[@handle.MBXChain]; handle.MBXChain ← next; END; ENDLOOP; 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: LONG POINTER TO RetrieveXDefs.MBXPtr ← @(handle.MBXChain); -- skip to end of mailbox chain -- WHILE mbx↑ # RetrieveXDefs.noMBX DO mbx ← @(mbx↑.next); ENDLOOP; mbx↑ ← Heap.systemZone.NEW[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.