// IfsMailCompose.bcpl -- Compose a mail file
// Copyright Xerox Corporation 1979, 1980, 1981, 1982
// Last modified April 9, 1982 12:38 PM by Taft
get "Ifs.decl"
get "IfsDirs.decl"
get "IfsMail.decl"
get "AltoFileSys.d"
get "IfsRs.decl"
external
[
// outgoing procedures
StartMsg; WriteMNB; FinishMsg
// incoming procedures from other mail modules
AppendRegistry
// incoming procedures from Streams
WriteBlock; SetFilePos; FilePos; FileLength; Closes; Puts
// incoming procedures from Dirs
IFSOpenFile; CloseIFSStream; CloseIFSFile; DeleteFileFromFD
DestroyFD
// incoming procedures - misc
SysAllocateZero; SysFree; MailStat; IFSError; DiskToDisk
DefaultArgs; Zero; MoveBlock; ReadCalendar
DoubleSubtract
// incoming statics
mail; ndbQ; infoVMD; CtxRunning
]
// let msg = StartMsg("firstRecipient", "sender")
// if msg ne 0 then
// [
// let stream = msg!0
// WriteMNB(msg, mbTypeMlbx, "secondRecipient")
// Wss(stream, "To: firstRecipient, secondRecipient")
// Wss(stream, "*NFrom: sender")
// Wss(stream, "*NDate: "); WRITEUDT(stream, 0, true)
// Wss(stream, "*NSubject: Example*N")
// Wss(stream, "This is an example of how to compose a message")
// FinishMsg(msg, true)
// ]
//----------------------------------------------------------------------------
let StartMsg(mlbx, sndr, lvEc; numargs na) = valof
//----------------------------------------------------------------------------
// Builds an Msg structure, and starts a new version of <Mail>New>Mail.
// If mlbx or sndr is supplied, appends MNBs for them to the file.
// If it fails to open the file, lvEc is the error code.
[
if na ls 1 then mlbx = 0
if na ls 2 then sndr = 0
if na ls 3 then lvEc = lv na
// use mail identity to create the file.
let ui = CtxRunning>>RSCtx.userInfo
CtxRunning>>RSCtx.userInfo = mail>>Mail.ui
let stream = IFSOpenFile("<Mail>New>Mail!n", lvEc, modeAppend)
CtxRunning>>RSCtx.userInfo = ui
if stream eq 0 resultis 0
let msg = SysAllocateZero(lenMsg)
msg>>Msg.stream = stream
WriteBlock(stream, lv msg>>Msg.mh, lenMH)
FilePos(stream, lv msg>>Msg.posBlk)
FilePos(stream, lv msg>>Msg.posTxt)
if mlbx ne 0 then WriteMNB(msg, mbTypeMlbx, mlbx)
if sndr ne 0 then WriteMNB(msg, mbTypeSndr, sndr)
resultis msg
]
//----------------------------------------------------------------------------
and WriteMNB(msg, type, name, ec; numargs na) be
//----------------------------------------------------------------------------
// Appends a name block to 'msg'. Assumes the stream is positioned
// at the proper place (i.e. at the end of a previous block or at
// Msg.posBlk if this is the first one.
[
DefaultArgs(lv na, -3, 0)
// if name is unqualified, then append our registry
let dot = 0
for i = name>>String.length to 1 by -1 do
if name>>String.char↑i eq $. then [ dot = i; break ]
if dot eq 0 then name = AppendRegistry(name)
let lenName = name>>String.length rshift 1 +1
let mnb = vec lenMNBHdr; Zero(mnb, lenMNBHdr)
mnb>>MNB.type = type
mnb>>MNB.length = lenMNBHdr + lenName
mnb>>MNB.ec = ec
let stream = msg>>Msg.stream
if type eq mbTypeSndr then FilePos(stream, lv msg>>Msg.posSndr)
WriteBlock(stream, mnb, lenMNBHdr)
WriteBlock(stream, name, lenName)
FilePos(stream, lv msg>>Msg.posTxt)
if dot eq 0 then SysFree(name)
unless type eq mbTypeFree % type eq mbTypeSndr do
msg>>Msg.numActive = msg>>Msg.numActive +1
]
//----------------------------------------------------------------------------
and FinishMsg(msg, ok) = valof
//----------------------------------------------------------------------------
// Finishes off the file described by 'msg', and then destroys msg.
// If 'ok' is true the header is finished and the stream closed.
// Assumes the file is positioned at the end of the text area.
// If 'ok' is false the file is destroyed.
[
let stream = msg>>Msg.stream
test ok
ifso //finish off the header and close the file
[
let lenTxt = lv msg>>Msg.lenTxt
if (FilePos(stream, lenTxt) & 1) eq 1 then Puts(stream, 0) //pad
DoubleSubtract(lenTxt, lv msg>>Msg.posTxt)
MailStat(msTypeLen, lenTxt)
let v = vec 1; v!0 = 0; v!1 = msg>>Msg.numActive
MailStat(msTypeMlbx, v)
ReadCalendar(lv msg>>Msg.date)
FilePos(stream, lv msg>>Msg.posEnd)
SetFilePos(stream, lv msg>>Msg.posBegin)
msg>>Msg.version = mhVersion
msg>>Msg.seal = mhSeal
WriteBlock(stream, lv msg>>Msg.mh, lenMH)
FileLength(stream) //so Closes doesn't truncate
Closes(stream)
//wake up mail process
mail>>Mail.workToDo = true
]
ifnot //destroy the file
[
let fd = CloseIFSStream(stream, true) // leave file locked
if DeleteFileFromFD(fd, false, true) ne 0 then CloseIFSFile(fd)
DestroyFD(fd)
]
SysFree(msg)
resultis 0
]