-- Copyright (C) 1981, 1983, 1984, 1985 by Xerox Corporation. All rights reserved. -- ReceiveMail.mesa, Transport Mechanism: Accepting mail from client -- HGM, 19-Mar-86 20:57:28 -- Mark Johnson 24-Nov-81 16:51:13 -- Andrew Birrell 30-Mar-81 13:40:41 -- Brenda Hankins 24-Feb-83 9:16:16 DIRECTORY BodyDefs USING [maxRNameLength, Password, RName, Timestamp], LogDefs USING [ShowRejection], PolicyDefs USING [CheckOperation, EndOperation], ProtocolDefs USING [ DestroyStream, Failed, Handle, mailServerInputSocket, MSOperation, ReceiveBoolean, ReceiveCount, ReceiveMSOperation, ReceivePassword, ReceiveRName, SendAck, SendBoolean, SendByte, SendCount, SendNow, SendRName, SendTimestamp], PupDefs USING [PupAddress], PupStream USING [ CreatePupByteStreamListener, RejectThisRequest, SecondsToTocks, StreamClosing], RestartDefs USING [], SendDefs USING [ AddRecipient, AddToItem, CheckValidity, Create, Destroy, Expand, ExpandInfo, GetStamp, 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; blockAddr: LONG POINTER = @blockData; block: Stream.Block ← [blockAddr, 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; getStamp => BEGIN stamp: BodyDefs.Timestamp ← SendDefs.GetStamp[handle]; ProtocolDefs.SendTimestamp[str, stamp]; 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.ShowRejection["ClientInput", from]; -- No L ERROR PupStream.RejectThisRequest["Server full"L] END; END; [] ← PupStream.CreatePupByteStreamListener[ ProtocolDefs.mailServerInputSocket, ClientReceiver, PupStream.SecondsToTocks[ 60], ClientFilter]; END.