-- Copyright (C) 1982, 1984 by Xerox Corporation. All rights reserved.
-- Readmail.mesa, Transport Mechanism Mail Server - client reading mail --
-- HGM, 18-Nov-84 0:35:59
-- Andrew Birrell 25-Oct-82 10:53:32 --
DIRECTORY
BodyDefs USING [maxRNameLength, Password, RName],
LogDefs USING [ShowLine],
MailboxDefs USING [
Close, DeleteMessage, FlushAndClose, InaccessibleArchive, MBXHandle,
NextMessage, Open, ReadTOC, SendBody, WriteTOC],
NameInfoDefs USING [AuthenticateInfo, AuthenticateKey],
PolicyDefs USING [CheckOperation, EndOperation],
ProtocolDefs USING [
Failed, Handle, mailServerOutputSocket, maxRemarkLength, MSOperation,
ReceiveMSOperation, ReceivePassword, ReceiveRemark, ReceiveRName, Remark,
SendAck, SendBoolean, SendByte, SendCount, SendNow, SendRemark],
PupStream USING [
CreatePupByteStreamListener, PupAddress, RejectThisRequest, SecondsToTocks],
RestartDefs USING [] --EXPORT only-- ,
String USING [AppendNumber, AppendString, EquivalentSubStrings, SubStringDescriptor];
ReadMail: PROGRAM
IMPORTS
LogDefs, MailboxDefs, NameInfoDefs, PolicyDefs, ProtocolDefs, PupStream,
String
EXPORTS RestartDefs --PROGRAM-- =
BEGIN
EndsWith: PROC [s: STRING, b: STRING] RETURNS [BOOLEAN] =
BEGIN
pattern: String.SubStringDescriptor ← [b, 0, b.length];
target: String.SubStringDescriptor ← [s, s.length - b.length, b.length];
RETURN[
s.length >= b.length AND String.EquivalentSubStrings[@pattern, @target]]
END;
Receive: PROCEDURE [str: ProtocolDefs.Handle, where: PupStream.PupAddress] =
BEGIN OPEN ProtocolDefs;
client: BodyDefs.RName = [BodyDefs.maxRNameLength];
state: {closed, open, inMessage} ← closed;
mbx: MailboxDefs.MBXHandle;
found: BOOLEAN ← FALSE;
Open: PROC =
BEGIN
count: CARDINAL;
[found, count, mbx] ← MailboxDefs.Open[client];
IF found THEN state ← open;
ProtocolDefs.SendCount[str, IF found THEN count ELSE 0];
END;
DO
ENABLE ProtocolDefs.Failed, MailboxDefs.InaccessibleArchive => EXIT;
op: ProtocolDefs.MSOperation;
op ← ProtocolDefs.ReceiveMSOperation[
str !
ProtocolDefs.Failed =>
IF why = noData AND EndsWith[client, ".gv"] THEN RETRY
-- i.e. if caller is an R-Server -- ];
SELECT op FROM
openMBX =>
BEGIN
key: BodyDefs.Password;
info: NameInfoDefs.AuthenticateInfo;
ProtocolDefs.ReceiveRName[str, client];
key ← ProtocolDefs.ReceivePassword[str, [0, 0, 0, 0]];
IF state # closed THEN EXIT;
info ← NameInfoDefs.AuthenticateKey[client, key];
ProtocolDefs.SendByte[str, LOOPHOLE[info]];
IF info = individual THEN Open[];
END;
nextMessage =>
BEGIN
msgExists, archived, deleted: BOOLEAN;
IF state = inMessage THEN state ← open;
-- pretend that not found means empty mailbox --
IF found THEN
IF state # open THEN EXIT
ELSE
BEGIN
[msgExists, archived, deleted] ← MailboxDefs.NextMessage[mbx];
state ← IF deleted THEN open ELSE inMessage;
END
ELSE msgExists ← archived ← deleted ← FALSE;
ProtocolDefs.SendBoolean[str, msgExists];
ProtocolDefs.SendBoolean[str, archived];
ProtocolDefs.SendBoolean[str, deleted];
END;
readTOC =>
BEGIN
remark: ProtocolDefs.Remark = [ProtocolDefs.maxRemarkLength];
IF state # inMessage THEN EXIT;
MailboxDefs.ReadTOC[mbx, remark];
ProtocolDefs.SendRemark[str, remark];
END;
readMessage =>
BEGIN
IF state # inMessage THEN EXIT;
MailboxDefs.SendBody[mbx, str];
END;
writeTOC =>
BEGIN
remark: ProtocolDefs.Remark = [ProtocolDefs.maxRemarkLength];
ProtocolDefs.ReceiveRemark[str, remark];
IF state # inMessage THEN EXIT;
MailboxDefs.WriteTOC[mbx, remark];
ProtocolDefs.SendAck[str];
END;
deleteMessage =>
BEGIN
IF state # inMessage THEN EXIT;
MailboxDefs.DeleteMessage[mbx];
ProtocolDefs.SendAck[str];
END;
flushMBX =>
BEGIN
IF found THEN
BEGIN
IF state = closed THEN EXIT;
MailboxDefs.FlushAndClose[mbx];
state ← closed;
END
ELSE NULL;
ProtocolDefs.SendAck[str];
END;
ENDCASE => EXIT;
ProtocolDefs.SendNow[str];
ENDLOOP;
IF state # closed THEN MailboxDefs.Close[mbx];
str.delete[str];
PolicyDefs.EndOperation[readMail];
END;
ReadMailFilter: PROCEDURE [from: PupStream.PupAddress] =
BEGIN
IF NOT PolicyDefs.CheckOperation[readMail] THEN
BEGIN
s: STRING = [100];
String.AppendString[s, "Rejected ReadMail connection from "L];
String.AppendNumber[s, from.net, 8];
String.AppendString[s, "#"L];
String.AppendNumber[s, from.host, 8];
String.AppendString[s, "#"L];
LogDefs.ShowLine[s];
ERROR PupStream.RejectThisRequest["Server full"L];
END
END;
[] ← PupStream.CreatePupByteStreamListener[
ProtocolDefs.mailServerOutputSocket, Receive, PupStream.SecondsToTocks[120],
ReadMailFilter];
END.