// IfsMail.decl - Interim File System Interim Mail System
// Copyright Xerox Corporation 1979, 1980, 1981
// Last modified April 1, 1981  10:04 AM by Taft

// Overview
//
// Mail arrives either from a mail user program such as Laurel, or
//  from another mail system such as another Ifs or Maxc, or from
//  some job inside IFS (mailer, printer, etc).
// The Mail Transfer Protocol is spoken over a Byte Stream Protocol
//  connection after rendezvousing at the well known Mail Server socket.
// The IFS mail system uses two types of job: MTPServers and MailJob.
//  An MTPServer accepts mail from the net and queues it for MailJob.
//  MailJob sorts newly arrived mail and forwards queued mail.
//   Sorting consists of enumerating new mail files and appending copies
//    either to a local mailbox or to a queue file for another mail server.
//   Forwarding consists of enumerating the queue files and trying to send
//    them to remote mail servers.  MailJob is an MTP user.

// Control
//
// The entire Mail system can be turned on or off by toggling MS.enabled.
//  If this bit is off, all mail-related activity is disabled:
//   no mail will be stored or retrieved,
//   no mail will be sorted to local mail boxes, and
//   no mail will be forwarded to other sites.
// The Forwarder can be turned on or off by toggling MS.forward.
//  Disabling forwarding allows IFS to support a closed mail community.
//  If this bit is off:
//   no mail will be accepted for non-local mailboxes, and
//   no mail will be forwarded to other sites.

// Distribution lists
//
// A mail server is also an Ftp server.  Requests to retrieve a file
//  are intercepted.  The job is logged in as "Mail", and the requested
//  filename is prefixed with a system parameter string and postfixed
//  with ".dl".  The retrieve is then allowed to proceed.

// Grapevine support
//
// Two system parameters permit an IFS mail server to cooperate with
//  the new mail system which will eventually replace it.
//   If a 'registry' string is specified, recipients ending in ".registry"
//    will be treated as if the registry resolved to the mail server address.
//   If a 'gvName' string is specified, all mail for non-local
//    mailboxes is forwarded there.  If this string is not set by the
//    mail system administrator, mail is forwarded to the recipient
//    name's registry.

// Undeliverable mail
//
// If a message is undeliverable, then it is returned to its sender.
// If the recipient of an undeliverable message is the dead letter
//  department, then the message is discarded without a trace.
//  The name of the dead letter department is a system parameter.
// Otherwise, a new message is created with the following contents:
//
//  To: (sender eq Mailer.ThisHost? DeadLetter, Sender)
//  From: Mailer.ThisHost
//  Subject: Undeliverable mail
//
//  Undeliverable to: <list of recipients>
//  -----------------------
//  <message>

// Statistics
//
// Statistics are kept on five items; three things are recorded:
//  Samples: total number of times a value was recorded.
//  Average: average value of the statistic.
//  Histogarm: eight slot logarithmically scaled histogram of values.
// The five items are:
//  Length (characters) - length of a message received by the mail server.
//  Recipients - the number of recipients (To: plus cc:) of a message.
//  Sort delay (sec) - time between receiving a message and appending
//   copies to local mailboxes or queueing copies for forwarding.
//  Fwd delay (sec) - time between queueing a message for a remote
//   mail server and sucessfully delivering it.
//  Retrieve delay (min) - time between appending a message to a mailbox
//   and the recipient retrieving it.
//  Messages that are discarded as undeliverable are counted.

// File conventions
//
// A Mail File consists of 0 or more Messages.
//  A Message consists of a Header, some Blocks and some Text.
//   A Header (structure MH) describes a message.
//    It contains pointers to the Block and Text areas, lengths, etc.
//   A Block (structure MB) consists of a Type, a Length, and a Body.
//    The Type describes the format of the block.
//    The Length is the length of the block IN WORDS including itself.
//    The Body is arbitrary stuff whose format depends on the block type.
//   The Text is a sequence of bytes.  Its length may be odd,
//    in which case it is followed by a garbage padding byte.
//
// 32-bit byte positions are used in the header.
// All components (Message, Header, Block, Text, etc.) begin on
//  word boundaries and are even numbers of bytes long.
//
// <Mail>New>Mail!* is mail awaiting sorting by MailJob.
// <Mail>Box>User!1 is mail awaiting retrieval by User.
// <Mail>Fwd>Host!1 is mail awaiting forwarding to Host.

manifest
[
socketMail = 7		// well known Pup socket

mhSeal = 110b		// MH seal
mhVersion = 2		// MH format version
msVersion = 1		// MS format version
msStatsVersion = 2	// MS.stats format version

deliveryTimeout = 48	// hours after which a msg is deemed undeliverable
jobInterval = 5*60	// seconds between background MailJob activations
minSortInterval = 5*60	// attempt to sort file no more often than this
minForwardInterval = 10*60 // attempt to forward file no more often than this
eventInterval = 5	// seconds between Mail Events
openTimeout = 5		// seconds to open a file, retrying once a second

maxMailParamChars = 39	// max string length in MS structure
lenMailParamString = (maxMailParamChars+2) rshift 1

fPropTypeMsgID = 300b	// FPROP type private to IFS mail server

// MailBox Exception codes
ecUnspecified = 700	// 0 Unspecified failure
ecCantLocate = 701	// 1 Can't locate mailbox
ecNotResident = 702	// 2 Mailbox isn't local & forwarding disabled
ecNameToAddress = 704	// 4 Unable to convert registry name to address
ecDeliveryTimeout = 705	// Undeliverable after 48 hours
ecIllegalRegistry = 706	// 4 Registry does not resolve to MTP socket
ecNoRegistry = 707	// 4 Name does not contain a registry
ecFwdLoop = 708		// 4 Message forwarding in a loop

// Mail Transfer Protocol No codes
ecMlbxRequired = 710	// 40 MLBX property required.
ecMlbxNotUnamOrCnam = 711 // 41 Mailbox must be User-Name or Connect-Name.
ecNoMailbox = 712	// 41 No mailbox by that name here.
ecMailNotRetrieved = 713 // 110 Mail not retrieved: $P
ecMailNotStored = 714	// 110 Mail not stored: $P
ecSndrRequired = 715	// 110 Sender property missing
ecAnonRetrieve = 716	// 3 Mail-server Retrieve not allowed
ecNoValidMlbx = 717	// 40 No valid recipients for message
ecZeroLengthMsg = 718	// 110 Message has zero length
ecRegistryNotLocal = 719 // 100 Registry is not local

// Mail system IFS error codes
ecBadMsgSeal = 720	// Bad MH.seal in msg $1O
ecEofInHdr = 721	// Unexpected EOF in Hdr area of msg $1O
ecEofInBlk = 722	// Unexpected EOF in Blk area of msg $1O
ecEofInTxt = 723	// Unexpected EOF in Txt area of msg $1O
ecMlbxIndex = 724	// Can't find mlbx index $1D in msg $2O
ecLeaderProps = 725	// FPROP area in leader page $1O overflowed
ecMlbxDelFailed = 726	// Failed to delete mailbox
]

//---------------------------------------------------------------------------
structure Mail:		// Mail System state kept in core
//---------------------------------------------------------------------------
[
wake word		// eventIntervals until next MailJob creation
ctx word		// -> MailJob ctx or 0 if not active
ui word			// -> ui: userName = System, connName = mail
rs word			// -> MTP Rendezvous socket (NOT a -> PupSoc)
msgID word 2		// message ID
flags word =
   [
   enabled bit		// mail system is enabled
   forward bit		// forwarding is enabled
   workToDo bit		// there is work for MailJob
   blank bit 13
   ]
]
manifest lenMail = size Mail/16

//----------------------------------------------------------------------------
structure MSE:		// Mail Statistics Entry
//----------------------------------------------------------------------------
[
max bit 4		// = 7, max histogram entry index
grain bit 4		// log(2) ratio between successive entries
scale bit 4		// log(2) value of first entry
scaleTotal bit 4	// log(2) scale factor for total
calls↑0,1 word		// total number of samples
total↑0,1 word		// (sum of sample values)/(2↑totalScale)
histogram↑0,7 word 2
]
manifest lenMSE = size MSE/16

//----------------------------------------------------------------------------
structure MS:		// Mail System state kept in file <System>Info
//----------------------------------------------------------------------------
[
flags word =
   [
   enabled bit		// mail system enabled
   forward bit		// inter-site forwarding enabled
   blank bit 6
   version byte		// = msVersion
   ]
deadLtr word lenMailParamString  // name of dead letter destination
nameDirDL word lenMailParamString  // directory containing distribution lists
registry word lenMailParamString  // grapevine registry we are part of
gvName word lenMailParamString  // name of grapevine server
blank word 128-4*lenMailParamString
statsVersion word	// = msStatsVersion
stats word =
   [
   timeReset word 2	// time statistics were last reset
   discard word 2	// number of messages discarded
   mseLen @MSE		// length of message in bytes
   mseMlbx @MSE		// number of mailboxes
   mseSort @MSE		// time spent in <Mail>New>Mail
   mseRetr @MSE		// time spent in <Mail>Box>User
   mseFwd @MSE		// time spent in <Mail>Fwd>Host
   ]
]
manifest lenMS = size MS/16
manifest lenMSStats = lenMS - offset MS.stats/16

manifest		// Mail Stat types
[
msTypeDiscard = 1
msTypeLen = 2
msTypeMlbx = 3
msTypeSort = 4
msTypeRetr = 5
msTypeFwd = 6
]

//---------------------------------------------------------------------------
structure MH:		// Message Header
//---------------------------------------------------------------------------
[
seal byte		// = mhSeal
version byte		// = mhVersion
date word 2		// date msg was put in this file
posBlk word 2		// byte pos of first block
posSndr word 2		// byte pos of sender block
numActive word		// number of active recipients
posTxt word 2		// byte pos of text
lenTxt word 2		// length of text in bytes
posBegin word 2		// byte pos of beginning of this message
posEnd word 2		// byte pos of end of this message+1
]
manifest lenMH = size MH/16

//---------------------------------------------------------------------------
structure Msg:		// An MH with some in-core state added
//---------------------------------------------------------------------------
[
stream word		// -> disk stream
hostQ:			// a queue of HQIs
   [
   head word
   tail word
   ]
gvHQI word		// -> HQI for gvName, if there is one
uMsg word		// -> undeliverable message msg or zero if none
mh word = @MH		// Message Header from file
]
manifest lenMsg = size Msg/16

//---------------------------------------------------------------------------
structure HQI:		// Host Queue Item - built by CheckName
//---------------------------------------------------------------------------
[
link word
ec word			// exception code
flags word =
   [
   isLocal bit		// name maps to our address or matches MS.registry
   isPartner bit	// name maps to address of host giving us mail
   used bit		// at least one recipient name mentions this registry
   blank bit 13
   ]
name word		// name string begins here
]
manifest lenHQI = size HQI/16

//---------------------------------------------------------------------------
structure MB:		// Message Block
//---------------------------------------------------------------------------
[
type byte		// defines format of following words
length byte		// of block in words including this word
]
manifest maxLenMB = 1 lshift size MB.length

manifest		// MB.type values
[
mbTypeFree = 1		// Free block
mbTypeMlbx = 2		// MLBX name
mbTypeSndr = 3		// SNDR name
mbTypeExcp = 4		// Mailbox exception
mbTypeTempFree = 5	// See IfsMailForward
mbTypeTempExcp = 6	// "
]

//---------------------------------------------------------------------------
structure MNB:		// MB containing a MailBox or Sender name
//---------------------------------------------------------------------------
[
@MB
blank word		// currently zero
ec word			// exception code
name word 128		// MLBX or SNDR string
]
manifest lenMNBHdr = offset MNB.name/16

//---------------------------------------------------------------------------
structure FPropMsgID:	// leader page file property
//---------------------------------------------------------------------------
[
type bit 8
length bit 8
msgID word 2
]
manifest lenFPropMsgID = size FPropMsgID/16