-- Copyright (C) 1981, 1983, 1984, 1985 by Xerox Corporation. All rights reserved.
-- ReceiveMail.mesa, Transport Mechanism: Accepting mail from client
-- HGM, 18-Sep-85 3:19:25
-- 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],
LogDefs USING [ShowRejection],
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],
String USING [AppendNumber, AppendString];
ReceiveMail: PROGRAM
IMPORTS LogDefs, PolicyDefs, ProtocolDefs, PupStream, SendDefs, Stream, String
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;
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.