-- Transport Mechanism: User: initial stages of mail retrieval/polling -- -- [Juniper]MS>RetrieveInit.mesa -- Andrew Birrell 23-Jan-81 11:14:09 -- DIRECTORY BodyDefs USING[ Connect, maxConnectLength, maxRNameLength, oldestTime, 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; [] _ PupDefs.EnumeratePupAddresses[registry, Work ! PupDefs.PupNameTrouble => IF code = errorFromServer THEN GOTO badReg 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 badReg => RetrieveXDefs.SetMBXState[handle, badName]; 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.