-- file: InsertMailMain.Mesa -- edited by Brotz, December 15, 1980 11:29 AM DIRECTORY Ascii, crD: FROM "CoreDefs", dsD: FROM "DisplayDefs", exD: FROM "ExceptionDefs", inD: FROM "InteractorDefs", Inline, InsertMailDefs, intCommon: FROM "IntCommon", MailParse, mfD: FROM "MailFormatDefs", opD: FROM "OperationsDefs", ovD: FROM "OverviewDefs", Storage, String, tsD: FROM "TOCSelectionDefs", vmD: FROM "VirtualMgrDefs"; InsertMailMain: PROGRAM IMPORTS crD, dsD, exD, inD, Inline, intC: intCommon, mfD, Storage, String, tsD, vmD EXPORTS InsertMailDefs SHARES vmD = BEGIN OPEN crD, vmD; -- Purpose: a runnable bcd that inserts the current composed message into the current mail -- file. The message will be inserted just before the first message selected in the TOC, or -- if no messages are selected, at the end of the mail file. A stamp for this message is -- created. The table of contents file is also edited to contain an entry for this new -- message. No cleanup actions are performed on the current mail file or table of contents -- file. bytesPerStamp: CARDINAL = 24; InsertVMInMailFile: PUBLIC PROCEDURE [message: vmD.VirtualMessagePtr, tocIndex: TOCIndex _ 0] = BEGIN cmLength: CARDINAL _ GetMessageSize[message]; messageLength: CARDINAL _ cmLength; insertionLength: CARDINAL _ messageLength + bytesPerStamp; tocString: STRING _ [opD.maxTOCStringLength]; tocPtr: POINTER TO TOC; tocPage, mailPage, newMailPage, insertPage, destPage: PageNumber; mailByte, newMailByte, insertByte: PageByte; extraPages, extraMailPages: CARDINAL; tocWord: CARDINAL[0 .. 256]; needNewTocPage: BOOLEAN; mailFile, tocFile: UFileHandle; fp, newEntryTOCFp: TOCFixedPart; hdrHandle: mfD.Handle; charIndex: ovD.CharIndex _ 0; NextCharForParseHeader: PROCEDURE RETURNS [char: CHARACTER] = BEGIN IF charIndex >= cmLength THEN RETURN[MailParse.endOfInput]; char _ GetMessageChar[message, charIndex]; charIndex _ charIndex + 1; END; -- of NextCharForParseHeader -- BackupCharForParseHeader: PROCEDURE = BEGIN charIndex _ charIndex - 1; END; -- of BackupCharForParseHeader -- FindTOCInsertionPoint: PROCEDURE [index: TOCIndex, string: STRING] RETURNS [page: PageNumber, word: CARDINAL[0 .. 256], needNewPage: BOOLEAN] = BEGIN erc: ovD.ErrorCode; roomNeeded: CARDINAL = SIZE[TOCFixedPart] + String.WordsForString[string.length]; buffer: POINTER _ Storage.Pages[1]; tocPageHdr: POINTER TO TOCPageHdr _ LOOPHOLE[buffer]; firstFreeWord: CARDINAL; IF tocPtr.indexFF = 0 OR index > tocPtr.indexFF THEN exD.SysBug[]; FOR page _ 1, page + 1 UNTIL page >= tocPtr.filePageFF DO IF tocPtr.pageTableHeader[page] > index THEN EXIT; ENDLOOP; page _ page - 1; -- page is now the page on which index is found. IF page > 0 AND tocPtr.pageTableHeader[page] = index THEN BEGIN -- it's the first entry on page. Maybe it will fit on the previous page. [erc, ] _ ReadPages[buffer, 512, page - 1, tocFile]; IF erc # ovD.ok THEN exD.SysBug[]; firstFreeWord _ FirstFreeWord[buffer, tocPageHdr.numberOfEntries]; IF roomNeeded + firstFreeWord <= 256 THEN {Storage.FreePages[buffer]; RETURN[page - 1, firstFreeWord, FALSE]}; END; -- Check if new entry will fit on page. [erc, ] _ ReadPages[buffer, 512, page, tocFile]; IF erc # ovD.ok THEN exD.SysBug[]; firstFreeWord _ FirstFreeWord[buffer, tocPageHdr.numberOfEntries]; needNewPage _ (firstFreeWord + roomNeeded > 256); word _ FirstFreeWord[buffer, index - tocPtr.pageTableHeader[page]]; Storage.FreePages[buffer]; END; -- of FindTOCInsertionPoint -- -- WriteCompactionMark: PROCEDURE = -- BEGIN -- buffer: POINTER _ Storage.Pages[1]; -- array: POINTER TO PACKED ARRAY [0 .. 0) OF CHARACTER _ LOOPHOLE[buffer]; -- erc: ovD.ErrorCode; -- IF mailByte # 0 THEN -- BEGIN -- [erc, ] _ crD.ReadPages[buffer, 512, mailPage, mailFile]; -- IF erc # ovD.ok THEN exD.SysBug[]; -- END; -- array[mailByte] _ 003C; -- erc _ WritePages[buffer, mailByte + 1, mailPage, mailFile]; -- IF erc # ovD.ok THEN exD.SysBug[]; -- Storage.FreePages[buffer]; -- END; MoveUpInMailFile: PROCEDURE = BEGIN bufferSize: CARDINAL = 6; outBuffer: POINTER _ Storage.Pages[bufferSize]; outArray: POINTER TO PACKED ARRAY [0 .. 0) OF CHARACTER _ LOOPHOLE[outBuffer]; inBuffer: POINTER _ Storage.Pages[bufferSize]; inArray: POINTER TO PACKED ARRAY [0 .. 0) OF CHARACTER _ LOOPHOLE[inBuffer]; inPage, outPage, inPageBase, outPageBase: PageNumber; outByte, inByte, outBufferBytes: CARDINAL; ReadInBuffer: PROCEDURE = BEGIN erc: ovD.ErrorCode; inPageBase _ IF inPage < bufferSize THEN insertPage ELSE MAX[insertPage, inPage - bufferSize]; inByte _ (inPage - inPageBase - 1) * 512 + (IF inByte > 0 THEN inByte ELSE 512); inPage _ inPageBase; [erc, ] _ ReadPages[inBuffer, bufferSize * 512, inPageBase, mailFile]; -- always read a full buffer, since reading past eof does no harm. IF erc # ovD.ok THEN exD.SysBug[]; END; -- of ReadInBuffer -- WriteOutBuffer: PROCEDURE = BEGIN erc: ovD.ErrorCode; erc _ WritePages[outBuffer, outBufferBytes, outPageBase, mailFile]; IF erc # ovD.ok THEN exD.SysBug[]; outPage _ outPageBase; outPageBase _ IF outPage < bufferSize THEN destPage ELSE MAX[destPage, outPage - bufferSize]; outByte _ outBufferBytes _ (outPage - outPageBase) * 512; END; -- of WriteOutBuffer -- CopyBytes: PROCEDURE = BEGIN bytesToCopy: CARDINAL _ MIN[inByte, outByte]; inByte _ inByte - bytesToCopy; outByte _ outByte - bytesToCopy; FOR i: CARDINAL IN [0 .. bytesToCopy) DO outArray[outByte + i] _ inArray[inByte + i]; ENDLOOP; END; -- of CopyBytes -- inPage _ mailPage + 1; inByte _ (mailByte + 1) MOD 512; outPage _ newMailPage + 1; outByte _ (newMailByte + 1) MOD 512; destPage _ insertPage + (insertByte + insertionLength) / 512; outPageBase _ IF outPage < bufferSize THEN destPage ELSE MAX[destPage, outPage - bufferSize]; outByte _ outBufferBytes _ (outPage - outPageBase - 1) * 512 + (IF outByte > 0 THEN outByte ELSE 512); ReadInBuffer[]; DO CopyBytes[]; IF (inByte = 0 AND inPageBase = insertPage) OR (outByte = 0 AND outPageBase = destPage) THEN BEGIN IF destPage = insertPage THEN {outByte _ inByte _ insertByte; CopyBytes[]}; WriteOutBuffer[]; EXIT; END; IF inByte = 0 THEN ReadInBuffer[]; IF outByte = 0 THEN WriteOutBuffer[]; ENDLOOP; Storage.FreePages[outBuffer]; Storage.FreePages[inBuffer]; END; -- of MoveUpInMailFile -- InsertStampAndMessage: PROCEDURE = BEGIN buffer: POINTER _ Storage.Pages[1]; array: POINTER TO PACKED ARRAY [0 .. 0) OF CHARACTER _ LOOPHOLE[buffer]; outPage: PageNumber _ insertPage; outIndex: CARDINAL _ insertByte; erc: ovD.ErrorCode; stampIndex: CARDINAL _ 0; stamp: STRING _ [bytesPerStamp]; PutCharsInStamp: PROCEDURE [char: CHARACTER] = BEGIN stamp[stampIndex] _ char; stampIndex _ stampIndex + 1; END; -- of PutCharsInStamp -- CopyBytesOfStamp: PROCEDURE = BEGIN erc: ovD.ErrorCode; bytesToCopy: CARDINAL; stampIndex _ 0; UNTIL stampIndex = bytesPerStamp DO bytesToCopy _ MIN[512 - outIndex, bytesPerStamp - stampIndex]; FOR i: CARDINAL IN [0 .. bytesToCopy) DO array[outIndex + i] _ stamp[stampIndex + i]; ENDLOOP; stampIndex _ stampIndex + bytesToCopy; outIndex _ (outIndex + bytesToCopy) MOD 512; erc _ WritePages[buffer, IF outPage = newMailPage THEN newMailByte + 1 ELSE 512, outPage, mailFile]; IF erc # ovD.ok THEN exD.SysBug[]; IF stampIndex = bytesPerStamp AND outIndex > 0 THEN EXIT; outPage _ outPage + 1; IF outPage = destPage THEN BEGIN [erc, ] _ ReadPages[buffer, 512, outPage, mailFile]; IF erc # ovD.ok THEN exD.SysBug[]; END; ENDLOOP; END; -- of CopyBytesOfStamp -- CopyBytesOfMessage: PROCEDURE = BEGIN erc: ovD.ErrorCode; messageIndex: ovD.CharIndex _ 0; bytesToCopy: CARDINAL; get: POINTER TO CharCache _ @message.get; char: CHARACTER; UNTIL messageIndex = messageLength DO bytesToCopy _ MIN[512 - outIndex, messageLength - messageIndex]; FOR i: CARDINAL IN [messageIndex .. messageIndex + bytesToCopy) DO char _ Inline.BITAND[IF i IN [get.first .. get.free) THEN get.string[i + get.floor - get.first] ELSE GetMessageChar[message, i], ovD.CharMask]; array[outIndex + i - messageIndex] _ char; ENDLOOP; messageIndex _ messageIndex + bytesToCopy; outIndex _ (outIndex + bytesToCopy) MOD 512; erc _ WritePages[buffer, IF outPage = newMailPage THEN newMailByte + 1 ELSE 512, outPage, mailFile]; IF erc # ovD.ok THEN exD.SysBug[]; IF messageIndex = messageLength THEN EXIT; outPage _ outPage + 1; IF outPage = destPage THEN BEGIN [erc, ] _ ReadPages[buffer, 512, outPage, mailFile]; IF erc # ovD.ok THEN exD.SysBug[]; END; ENDLOOP; END; -- of CopyBytesOfMessage -- newEntryTOCFp _ TOCFixedPart [changed: TRUE, deleted: FALSE, seen: FALSE, bogus: FALSE, mark: ' , firstPage: insertPage, firstByte: insertByte, bugTrap: bugTrapValue, offsetToHeader: bytesPerStamp, textLength: messageLength]; mfD.CreateStamp[@newEntryTOCFp, PutCharsInStamp]; stamp.length _ bytesPerStamp; [erc, ] _ ReadPages[buffer, 512, insertPage, mailFile]; IF erc # ovD.ok THEN exD.SysBug[]; CopyBytesOfStamp[]; CopyBytesOfMessage[]; Storage.FreePages[buffer]; END; -- of InsertStampAndMessage -- FlushTOC: PROCEDURE = BEGIN erc: ovD.ErrorCode; mtPtr: MemoryTableEntryPtr; FOR mtPtr _ tocPtr.memoryHeader, mtPtr.next UNTIL mtPtr = NIL DO IF mtPtr.state = dirty THEN BEGIN erc _ WritePages[mtPtr.address, 512, mtPtr.filePageNumber, tocFile]; IF erc # ovD.ok THEN exD.SysBug[]; END; mtPtr.state _ unused; ENDLOOP; END; -- of FlushTOC -- ShiftTOCTail: PROCEDURE = BEGIN bufferSize: CARDINAL = 6; buffer: POINTER _ Storage.Pages[bufferSize]; page: PageNumber _ tocPtr.filePageFF; nPages: CARDINAL; erc: ovD.ErrorCode; UNTIL page = tocPage + 1 DO nPages _ MIN[bufferSize, page - tocPage - 1]; page _ page - nPages; [erc, ] _ ReadPages[buffer, nPages * 512, page, tocFile]; IF erc # ovD.ok THEN exD.SysBug[]; erc _ WritePages[buffer, nPages * 512, page + 1, tocFile]; IF erc # ovD.ok THEN exD.SysBug[]; ENDLOOP; FOR p: PageNumber DECREASING IN (tocPage + 1 .. tocPtr.filePageFF] DO tocPtr.pageTableHeader[p] _ tocPtr.pageTableHeader[p - 1]; ENDLOOP; tocPtr.filePageFF _ tocPtr.filePageFF + 1; Storage.FreePages[buffer]; END; -- of ShiftTOCTail -- InsertTOCEntry: PROCEDURE = BEGIN erc: ovD.ErrorCode; roomNeeded: CARDINAL = SIZE[TOCFixedPart] + String.WordsForString[tocString.length]; tocPageBuffer: POINTER _ Storage.Pages[1]; tocPageArray: POINTER TO ARRAY [0 .. 0) OF WORD _ LOOPHOLE[tocPageBuffer]; tocPageHeader: POINTER TO TOCPageHdr _ LOOPHOLE[tocPageBuffer]; newEntryTOCFpArray: POINTER TO ARRAY [0 .. 0) OF WORD _ LOOPHOLE[@newEntryTOCFp]; newEntryTOCStringArray: POINTER TO ARRAY [0 .. 0) OF WORD _ LOOPHOLE[tocString]; nEntries, firstFreeWord, wordsToCopy: CARDINAL; firstEntry: TOCIndex _ tocPtr.pageTableHeader[tocPage]; [erc, ] _ ReadPages[tocPageBuffer, 512, tocPage, tocFile]; IF erc # ovD.ok THEN exD.SysBug[]; nEntries _ tocPageHeader.numberOfEntries; firstFreeWord _ FirstFreeWord[tocPageBuffer, nEntries]; wordsToCopy _ firstFreeWord - tocWord; IF needNewTocPage THEN BEGIN nextPageBuffer: POINTER _ Storage.Pages[1]; nextPageArray: POINTER TO ARRAY [0 .. 0) OF WORD _ LOOPHOLE[nextPageBuffer]; nextPageHeader: POINTER TO TOCPageHdr _ LOOPHOLE[nextPageBuffer]; nextPageHeader.garbageDetector _ tOCType; IF tocWord + roomNeeded <= 256 THEN BEGIN -- new entry fits on tocPage. FOR i: CARDINAL IN [0 .. wordsToCopy) DO nextPageArray[SIZE[TOCPageHdr] + i] _ tocPageArray[tocWord + i]; ENDLOOP; FOR i: CARDINAL IN [SIZE[TOCPageHdr] + wordsToCopy .. 256) DO nextPageArray[i] _ 0; ENDLOOP; FOR i: CARDINAL IN [0 .. SIZE[TOCFixedPart]) DO tocPageArray[tocWord + i] _ newEntryTOCFpArray[i]; ENDLOOP; FOR i: CARDINAL IN [0 .. roomNeeded - SIZE[TOCFixedPart]) DO tocPageArray[tocWord + SIZE[TOCFixedPart] + i] _ newEntryTOCStringArray[i]; ENDLOOP; FOR i: CARDINAL IN [tocWord + roomNeeded .. 256) DO tocPageArray[i] _ 0; ENDLOOP; tocPtr.pageTableHeader[tocPage + 1] _ [tocIndex]; -- will be incremented later. tocPageHeader.numberOfEntries _ tocIndex - firstEntry + 1; nextPageHeader.numberOfEntries _ nEntries - (tocIndex - firstEntry); END ELSE BEGIN -- new entry must go on next page. FOR i: CARDINAL IN [0 .. SIZE[TOCFixedPart]) DO nextPageArray[SIZE[TOCPageHdr] + i] _ newEntryTOCFpArray[i]; ENDLOOP; FOR i: CARDINAL IN [0 .. roomNeeded - SIZE[TOCFixedPart]) DO nextPageArray[SIZE[TOCPageHdr] + SIZE[TOCFixedPart] + i] _ newEntryTOCStringArray[i]; ENDLOOP; FOR i: CARDINAL IN [0 .. wordsToCopy) DO nextPageArray[SIZE[TOCPageHdr] + roomNeeded + i] _ tocPageArray[tocWord +i]; ENDLOOP; FOR i: CARDINAL IN [SIZE[TOCPageHdr] + roomNeeded + wordsToCopy .. 256) DO nextPageArray[i] _ 0; ENDLOOP; FOR i: CARDINAL IN [tocWord .. 256) DO tocPageArray[i] _ 0; ENDLOOP; tocPtr.pageTableHeader[tocPage + 1] _ [tocIndex - 1]; -- will be incremented later. tocPageHeader.numberOfEntries _ tocIndex - firstEntry; nextPageHeader.numberOfEntries _ nEntries - (tocIndex - firstEntry) + 1; END; erc _ WritePages[nextPageBuffer, 512, tocPage + 1, tocFile]; IF erc # ovD.ok THEN exD.SysBug[]; Storage.FreePages[nextPageBuffer]; END ELSE BEGIN -- insert all on tocPage FOR i: CARDINAL DECREASING IN [0 .. wordsToCopy) DO tocPageArray[tocWord + roomNeeded + i] _ tocPageArray[tocWord + i]; ENDLOOP; FOR i: CARDINAL IN [firstFreeWord + roomNeeded .. 256) DO tocPageArray[i] _ 0; ENDLOOP; FOR i: CARDINAL IN [0 .. SIZE[TOCFixedPart]) DO tocPageArray[tocWord + i] _ newEntryTOCFpArray[i]; ENDLOOP; FOR i: CARDINAL IN [0 .. roomNeeded - SIZE[TOCFixedPart]) DO tocPageArray[tocWord + SIZE[TOCFixedPart] + i] _ newEntryTOCStringArray[i]; ENDLOOP; tocPageHeader.numberOfEntries _ nEntries + 1; END; erc _ WritePages[tocPageBuffer, 512, tocPage, tocFile]; IF erc # ovD.ok THEN exD.SysBug[]; FOR p: PageNumber IN (tocPage .. tocPtr.filePageFF) DO tocPtr.pageTableHeader[p] _ [tocPtr.pageTableHeader[p] + 1]; ENDLOOP; tocPtr.indexFF _ tocPtr.indexFF + 1; tocPtr.firstChange _ MIN[tocPtr.firstChange, tocIndex]; FOR t: TOCIndex IN (tocIndex .. tocPtr.indexFF) DO GetTOCFixedPart[t, @fp]; fp.firstPage _ fp.firstPage + (fp.firstByte + insertionLength) / 512; fp.firstByte _ (fp.firstByte + insertionLength) MOD 512; PutTOCFixedPart[t, @fp]; ENDLOOP; Storage.FreePages[tocPageBuffer]; END; -- of InsertTOCEntry -- -- main code for InsertCMInMailFile. tocPtr _ GetTOCPtr[]; IF ~intC.cmTextNbr.haveMessage OR ~intC.haveMailFile OR ~tocPtr.open THEN {exD.DisplayExceptionString["No message or mail file"L]; RETURN}; mailFile _ tocPtr.mailFile; tocFile _ tocPtr.file; hdrHandle _ mfD.InitializeParseHeader[NextCharForParseHeader, BackupCharForParseHeader]; mfD.ParseHeaderForTOC[tocString, hdrHandle]; mfD.FinalizeParseHeader[hdrHandle]; tocString^ _ StringBody[length: tocString.length, maxlength: tocString.length, text: ]; -- Get TOC file insertion point. FlushTOC[]; IF tocIndex = 0 THEN tocIndex _ IF tsD.TOCSelectionEmpty[] THEN 1 ELSE tsD.LastSelectedEntry[] + 1; [tocPage, tocWord, needNewTocPage] _ FindTOCInsertionPoint[tocIndex, tocString]; -- Compute extra space required for mail file and TOC file. [ , mailPage, mailByte] _ UFileLength[mailFile]; extraMailPages _ (mailByte + insertionLength + 1) / 512; extraPages _ extraMailPages + (IF needNewTocPage THEN 1 ELSE 0); IF (tocPtr.filePageFF > tOCPageTableSize AND needNewTocPage) OR mailFile.UFileObjectType = alto AND extraPages > CountAltoFreePages[] THEN {exD.DisplayExceptionString["Insertion will not fit on disk on in TOC"L]; RETURN}; -- Get mail file insertion point. IF tocIndex = tocPtr.indexFF THEN {insertPage _ mailPage; insertByte _ mailByte} ELSE {GetTOCFixedPart[tocIndex, @fp]; insertByte _ fp.firstByte; insertPage _ fp.firstPage}; inD.IndicateCommandBusy[intC.mailFileCommandHouse]; newMailPage _ mailPage + (mailByte + insertionLength) / 512; newMailByte _ (mailByte + insertionLength) MOD 512; -- Write compaction mark at end of mail file. -- WriteCompactionMark[]; vmD.SetTOCValidity[FALSE]; -- Shift mail file tail down by message + stamp length. MoveUpInMailFile[]; -- Insert message and stamp. InsertStampAndMessage[]; IF UFileTruncate[newMailPage, newMailByte, mailFile] # ovD.ok THEN exD.SysBug[]; -- Flush Virtual TOC buffers. FlushTOC[]; -- Rewrite TOC entries in tail and shift TOC file tail down if necessary. IF needNewTocPage THEN ShiftTOCTail[]; -- Insert new TOC entry. InsertTOCEntry[]; vmD.SetTOCValidity[TRUE]; -- Redisplay TOC and DM. tsD.SetTOCSelection[tocIndex]; dsD.ClearRectangle[inD.leftMargin, inD.rightMargin, intC.tocTextNbr.topY, intC.tocTextNbr.bottomY]; inD.DisplayTOCTail[intC.tocTextNbr, intC.tocTextNbr.lines, intC.tocTextNbr.lines.linePair.index, 1]; inD.UpdateTOCThumbLine[]; inD.IndicateCommandFinished[intC.mailFileCommandHouse]; intC.dmTextNbr.haveMessage _ FALSE; intC.composedMessageEdited _ FALSE; inD.IndicateCommandBusy[intC.displayCommandHouse]; inD.DisplayMessageCommand[intC.displayCommandHouse, TRUE]; inD.IndicateCommandFinished[intC.displayCommandHouse]; -- Done. END; -- of InsertCMInMailFile -- FirstFreeWord: PROCEDURE [buffer: POINTER, entries: CARDINAL] RETURNS [word: CARDINAL[0 .. 256]] = BEGIN p: TOCFixedPartPtr _ LOOPHOLE[buffer + SIZE[TOCPageHdr]]; THROUGH [1 .. entries] DO p _ WordsInTOCEntry[p] + p; ENDLOOP; RETURN[p - buffer]; END; -- of FirstFreeWord -- WordsInTOCEntry: PROCEDURE [hPtr: HardTOCAddress] RETURNS [CARDINAL] = -- Copied from VirtTOC.mesa. BEGIN fWords: CARDINAL = SIZE[TOCFixedPart]; s: STRING = LOOPHOLE[hPtr + fWords, STRING]; RETURN[fWords + String.WordsForString[s.maxlength]]; END; -- of WordsInTOCEntry -- END. -- of InsertMailMain --z20461x0(529)\f1 18196f0