-- AppendOp.mesa
-- Edited by Schroeder, Wednesday Nov. 5, 1980 2:32 pm PST.
-- Edited by Brotz, November 30, 1981 10:41 AM

DIRECTORY
csD: FROM "CoreStreamDefs" USING [Close, GetLength, OpenFromName, Position, Read,
Reset, SetPosition, StreamHandle, Write, WriteBlock],
exD: FROM "ExceptionDefs" USING [moveTargetExists],
inD: FROM "InteractorDefs" USING [AskUserToConfirm],
mfD: FROM "MailFormatDefs" USING [CreateStamp, ParseStamp],
opD: FROM "OperationsDefs" USING [NoMoveReason],
tsD: FROM "TOCSelectionDefs" USING [FirstSelectedEntry, NextSelectedEntry],
vmD: FROM "VirtualMgrDefs" USING [GetTOCFixedPart, PageNumber, TOCFixedPart,
TOCFixedPartPtr, TOCHandle, TOCIndex],
VMDefs USING [Deactivate, Error, Page, pageByteSize, PageNumber, ReadPage];

AppendOp: PROGRAM
IMPORTS csD, inD, mfD, tsD, vmD, VMDefs
EXPORTS opD =

BEGIN


NoMessagesMoved: PUBLIC ERROR [reason: opD.NoMoveReason] = CODE;
-- May be raised by AppendMailToFileOperation if no messages are actually moved.


AppendMailToFileOperation: PUBLIC PROCEDURE
[toc: vmD.TOCHandle, key: CARDINAL, appendFileName: STRING] =
-- Opens the appendFile named, appends all undeleted selected messages to that file with
-- stamps, closes append file. Skips any messages in the range that are deleted.
-- May raise NoMessagesMoved.
BEGIN
outputSH: csD.StreamHandle ← csD.OpenFromName[appendFileName, byte, append];
tOCEntry: vmD.TOCFixedPart;
tb: vmD.TOCFixedPartPtr = @tOCEntry;
b, putCount, bytesToCopy, bytesOnThisPage, inBufferStart: CARDINAL;
messageIndex: vmD.TOCIndex;
inBuffer: VMDefs.Page;
inBufferPageNumber: VMDefs.PageNumber;
failureState: opD.NoMoveReason ← noUndeleted;

-- internal procedures of AppendMailToFileOperation

AGetChar: PROCEDURE RETURNS [CHARACTER] =
BEGIN
RETURN[csD.Read[outputSH]];
END; -- of AGetChar --

APutChar: PROCEDURE [c: CHARACTER] =
BEGIN
putCount ← putCount + 1;
csD.Write[outputSH, c];
END; -- of AGetChar --

-- code for AppendMailToFileOperation

BEGIN -- for EXITS --
ENABLE VMDefs.Error =>
BEGIN
csD.Reset[outputSH];
failureState ← IF reason = resources THEN diskFull ELSE diskError;
GOTO bailOut;
END;
position: csD.Position = csD.GetLength[outputSH];
IF position # 0 THEN
BEGIN -- see if target file looks like a mail file.
stampOk: BOOLEAN;
csD.SetPosition[outputSH, 0];
stampOk ← mfD.ParseStamp[AGetChar, tb];
csD.Reset[outputSH];
IF ~stampOk THEN
{IF ~inD.AskUserToConfirm[exD.moveTargetExists] THEN GOTO bailOut};
END;
FOR messageIndex ← tsD.FirstSelectedEntry[toc, key],
tsD.NextSelectedEntry[toc, key, messageIndex] UNTIL messageIndex = 0
DO -- loop for each message
vmD.GetTOCFixedPart[toc, key, messageIndex, tb];
IF ~tb.deleted THEN
BEGIN -- copy this message --
IF tb.changed THEN
BEGIN
putCount ← 0;
mfD.CreateStamp[tb, APutChar];
b ← tb.firstByte + putCount;
tb.firstPage ← tb.firstPage + b / 512;
tb.firstByte ← b MOD 512;
tb.offsetToHeader ← tb.offsetToHeader - putCount;
END;
inBufferPageNumber ← tb.firstPage;
inBufferStart ← tb.firstByte;
bytesToCopy ← tb.offsetToHeader + tb.textLength;
UNTIL bytesToCopy = 0 DO
inBuffer ← VMDefs.ReadPage[[toc.mailFile, inBufferPageNumber], 2];
bytesOnThisPage ← MIN[bytesToCopy, VMDefs.pageByteSize - inBufferStart];
csD.WriteBlock[outputSH, inBuffer, inBufferStart, bytesOnThisPage
! UNWIND => VMDefs.Deactivate[inBuffer]];
inBufferStart ← 0;
inBufferPageNumber ← inBufferPageNumber + 1;
bytesToCopy ← bytesToCopy - bytesOnThisPage;
VMDefs.Deactivate[inBuffer];
ENDLOOP;
failureState ← ok;
END; -- copy this message --
ENDLOOP; -- loop for each message
EXITS
bailOut => NULL;
END; -- of EXITS block

csD.Close[outputSH];
IF failureState # ok THEN ERROR NoMessagesMoved[failureState];
END; -- of AppendMailToFileOperation --


END. -- of AppendOp --