-- 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.