-- Transport Mechanism: Accepting mail from client -- [Juniper]<Grapevine>MS>ReceiveMail.mesa -- Andrew Birrell 30-Mar-81 13:40:41 -- M. D. Schroeder 7-Feb-83 13:16:31 DIRECTORY BodyDefs USING[ maxRNameLength, Password, RName ], LogDefs USING[ WriteLogEntry ], PolicyDefs USING[ CheckOperation, EndOperation ], ProtocolDefs, PupDefs USING[ PupAddress ], PupStream USING[ CreatePupByteStreamListener, RejectThisRequest, SecondsToTocks, StreamClosing ], RestartDefs USING[ ], SendDefs USING[ AddRecipient, AddToItem, CheckValidity, Create, Destroy, Expand, ExpandInfo, Handle, Send, SendFromClient, StartItem, StartSendInfo ], Stream USING[ Block, CompletionCode, GetBlock, TimeOut ]; ReceiveMail: PROGRAM IMPORTS LogDefs, PolicyDefs, ProtocolDefs, PupStream, SendDefs, Stream EXPORTS RestartDefs --PROGRAM-- = BEGIN ClientReceiver: PROC[str: ProtocolDefs.Handle, from: PupDefs.PupAddress] = BEGIN state: {idle, started, noItem, inItem} ← idle; handle: SendDefs.Handle = SendDefs.Create[]; -- "block" is used for re-blocking incoming bytes of an item -- -- at top of loop, block.stopIndexPlusOne is buffered bytes in block -- -- at top of loop, block.startIndex is undefined -- blockLength: CARDINAL = 128; blockData: PACKED ARRAY [0..blockLength) OF CHARACTER; block: Stream.Block ← [@blockData, 0, 0]; ForceBlock: PROC = BEGIN block.startIndex ← 0; SendDefs.AddToItem[handle, DESCRIPTOR[@blockData, block.stopIndexPlusOne] ]; block.stopIndexPlusOne ← 0; END; validate: BOOLEAN; op: ProtocolDefs.MSOperation; DO BEGIN ENABLE ProtocolDefs.Failed, PupStream.StreamClosing, Stream.TimeOut => EXIT; SELECT (op ← ProtocolDefs.ReceiveMSOperation[str]) FROM startSend => BEGIN sender: BodyDefs.RName = [BodyDefs.maxRNameLength]; returnTo: BodyDefs.RName = [BodyDefs.maxRNameLength]; key: BodyDefs.Password; info: SendDefs.StartSendInfo; IF state # idle THEN GOTO badState; ProtocolDefs.ReceiveRName[str, sender]; key ← ProtocolDefs.ReceivePassword[str, [0,0,0,0]]; ProtocolDefs.ReceiveRName[str, returnTo]; validate ← ProtocolDefs.ReceiveBoolean[str]; info ← SendDefs.SendFromClient[handle: handle, fromNet: from.net, fromHost: from.host, senderKey: key, sender: sender, returnTo: returnTo, validate: validate ]; ProtocolDefs.SendByte[str, LOOPHOLE[info]]; ProtocolDefs.SendNow[str]; IF info = ok THEN state ← started; END; addRecipient => BEGIN recipient: BodyDefs.RName = [BodyDefs.maxRNameLength]; IF state # started THEN GOTO badState; ProtocolDefs.ReceiveRName[str, recipient]; SendDefs.AddRecipient[handle, recipient]; END; checkValidity => BEGIN MyNotify: PROC[n: CARDINAL, bad: BodyDefs.RName] = BEGIN ProtocolDefs.SendCount[str, n]; ProtocolDefs.SendRName[str, bad]; END; ok: CARDINAL; IF state # started THEN GOTO badState; ok ← SendDefs.CheckValidity[handle, MyNotify]; ProtocolDefs.SendCount[str, 0]; ProtocolDefs.SendCount[str, ok]; ProtocolDefs.SendNow[str]; state ← noItem; END; startItem => BEGIN IF state = started THEN state ← noItem; IF state = inItem THEN { ForceBlock[]; state ← noItem }; IF state # noItem THEN GOTO badState; SendDefs.StartItem[handle, LOOPHOLE[ProtocolDefs.ReceiveCount[str]]]; state ← inItem; END; addToItem => BEGIN length: CARDINAL; IF state # inItem THEN GOTO badState; length ← ProtocolDefs.ReceiveCount[str]; WHILE length > 0 DO used: CARDINAL; why: Stream.CompletionCode; block.startIndex ← block.stopIndexPlusOne; block.stopIndexPlusOne ← IF blockLength - block.startIndex < length THEN blockLength ELSE block.startIndex+length; [used,why,] ← Stream.GetBlock[str, block]; IF why # normal THEN GOTO protocolError; length ← length - used; block.stopIndexPlusOne ← block.startIndex + used; IF block.stopIndexPlusOne >= blockLength THEN BEGIN IF block.stopIndexPlusOne > blockLength THEN ERROR; ForceBlock[]; END; ENDLOOP; END; send => BEGIN IF state = started THEN state ← noItem; IF state = inItem THEN { ForceBlock[]; state ← noItem }; IF state # noItem THEN GOTO badState; SendDefs.Send[handle]; ProtocolDefs.SendAck[str]; ProtocolDefs.SendNow[str]; state ← idle; END; expand => BEGIN name: BodyDefs.RName = [BodyDefs.maxRNameLength]; info: SendDefs.ExpandInfo; ExpandWork: PROC[n: BodyDefs.RName] = BEGIN ProtocolDefs.SendBoolean[str, TRUE]; ProtocolDefs.SendRName[str, n]; END; ProtocolDefs.ReceiveRName[str, name]; info ← SendDefs.Expand[name, ExpandWork];--shouldn't signal-- ProtocolDefs.SendBoolean[str, FALSE]; -- end -- ProtocolDefs.SendByte[str, LOOPHOLE[info]]; ProtocolDefs.SendNow[str]; END; ENDCASE => GOTO protocolError; EXITS protocolError => EXIT; badState => EXIT; END; ENDLOOP; PolicyDefs.EndOperation[clientInput]; SendDefs.Destroy[handle]; ProtocolDefs.DestroyStream[str]; END; ClientFilter: PROC[from: PupDefs.PupAddress] = BEGIN IF NOT PolicyDefs.CheckOperation[clientInput] THEN BEGIN LogDefs.WriteLogEntry["Rejected ClientInput connection"L]; ERROR PupStream.RejectThisRequest["Server full"L] END; END; [] ← PupStream.CreatePupByteStreamListener[ ProtocolDefs.mailServerInputSocket, ClientReceiver, PupStream.SecondsToTocks[60], ClientFilter ]; END.