-- AccessOp.mesa -- edited by Schroeder, May 4, 1981 3:09 PM. -- edited by Brotz, February 19, 1981 11:28 AM -- edited by Levin, February 24, 1981 4:51 PM. DIRECTORY BodyDefs, csD: FROM "CoreStreamDefs", exD: FROM "ExceptionDefs", gsD: FROM "GlobalStorageDefs", InlineDefs, intCommon, MailParse, mfD: FROM "MailFormatDefs", opD: FROM "OperationsDefs", ovD: FROM "OverviewDefs", ProcessDefs, RetrieveDefs, StringDefs, vmD: FROM "VirtualMgrDefs"; AccessOp: PROGRAM IMPORTS csD, exD, gsD, InlineDefs, intC: intCommon, mfD, ProcessDefs, RetrieveDefs, StringDefs, vmD EXPORTS opD = BEGIN AccessNewMailOperation: PUBLIC PROCEDURE RETURNS [messagesRead: BOOLEAN] = BEGIN bufferBytes: CARDINAL = 512; breakBuffers: [0..177777B/bufferBytes) = 125; bufferPages: CARDINAL = (bufferBytes+511)/512; buffer: POINTER TO PACKED ARRAY OF CHARACTER _ NIL; parseHandle: mfD.Handle _ NIL; mailFileSH: csD.StreamHandle _ NIL; flashWanted: BOOLEAN _ FALSE; nextCharLimit: CARDINAL; charCount: CARDINAL; BoxNextChar: PROCEDURE RETURNS [lastChar: CHARACTER] = BEGIN lastChar _ IF charCount >= nextCharLimit THEN MailParse.endOfInput -- off the end ELSE csD.Read[mailFileSH]; charCount _ charCount + 1; END; BoxBackupChar: PROCEDURE = BEGIN charCount _ charCount - 1; IF charCount < nextCharLimit THEN csD.SetPosition[mailFileSH, csD.GetPosition[mailFileSH] - 1]; END; BoxPutChar: PROCEDURE [c: CHARACTER] = {csD.Write[mailFileSH, c]}; BoxPositionNextChar: PROCEDURE [page, byte, limit: CARDINAL] = BEGIN nextCharLimit _ limit; charCount _ 0; csD.SetPosition[mailFileSH,csD.MapPageByteToPosition[page,byte]]; END; lastLineUsed: [0..2] _ 0; ReportProgressString: PROCEDURE [s: STRING] = BEGIN lastLineUsed _ 1; exD.AppendStringToExceptionLine[s, 1 ! exD.ExceptionLineOverflow => CONTINUE ]; END; ReportProgress: PROCEDURE [e: exD.Exception] = BEGIN lastLineUsed _ 1; exD.AppendExceptionToExceptionLine[e, 1 ! exD.ExceptionLineOverflow => CONTINUE ]; END; lastException: exD.Exception _ exD.nil; ReportException: PROCEDURE [e:exD.Exception, f:{flash, dontFlash} _ dontFlash] = BEGIN IF lastLineUsed = 2 THEN exD.DisplayExceptionLine[lastException, 1] ELSE lastLineUsed _ lastLineUsed + 1; exD.DisplayExceptionLine[e, lastLineUsed]; lastException _ e; IF f = flash THEN flashWanted _ TRUE; END; -- Code for AccessNewMailOperation messagesRead _ FALSE; BEGIN serverKnown: BOOLEAN _ FALSE; utilityString: STRING = [opD.maxTOCStringLength]; -- [MAX[opD.maxTOCStringLength, BodyDefs.maxRNameLength, 60]] tOCEntry: vmD.TOCFixedPart; tb: vmD.TOCFixedPartPtr = @tOCEntry; tb.deleted _ tb.changed _ tb.seen _ FALSE; tb.mark _ ' ; tb.offsetToHeader _ 0; SELECT RetrieveDefs.MailboxState[intC.retrieveHandle] FROM badName, badPwd => GOTO credentialsError; cantAuth => GOTO noServers; ENDCASE; --ok to try mailFileSH _ csD.Open[fh:intC.mailFileHandle, type:byte, mode:append, nPages:1 ! csD.Error => GOTO csError ]; buffer _ gsD.GetMemoryPages[bufferPages]; DO -- next server ENABLE csD.Error => BEGIN UNTIL RetrieveDefs.NextServer[intC.retrieveHandle].noMore DO ENDLOOP; SELECT reason FROM ovD.diskFull, ovD.fileTooBig => BEGIN ReportProgress[exD.overflow]; csD.Reset[mailFileSH ! csD.Error => GOTO csError ]; csD.Checkpoint[mailFileSH ! csD.Error => GOTO csError ]; ReportException[exD.newMailOverfill]; EXIT; END; ENDCASE; GOTO csError; END; messages: CARDINAL _ 0; connected, archivedReported: BOOLEAN _ FALSE; retProcs: RetrieveDefs.AccessProcs; whyFailed: RetrieveDefs.FailureReason; BEGIN noMore: BOOLEAN; serverState: RetrieveDefs.ServerState; ProcessDefs.Yield[]; [noMore, serverState, retProcs] _ RetrieveDefs.NextServer[intC.retrieveHandle]; IF noMore THEN EXIT; serverKnown _ TRUE; RetrieveDefs.ServerName[intC.retrieveHandle, utilityString]; ReportProgressString[utilityString]; IF StringDefs.EquivalentString[utilityString, intC.user.registry] THEN ReportProgressString[" inbox server "L]; IF serverState # notEmpty THEN BEGIN ReportProgress[IF serverState = empty THEN exD.dotsEmpty ELSE exD.dotsDidntRespond]; LOOP; END; END; DO -- next message firstChunk: BOOLEAN _ TRUE; msgExists, archived, deleted: BOOLEAN; item: BodyDefs.ItemHeader; [msgExists, archived, deleted] _ retProcs.nextMessage[intC.retrieveHandle ! RetrieveDefs.Failed => {whyFailed _ why; GOTO retrieveError} ]; IF NOT connected THEN {connected _ TRUE; ReportProgress[exD.dots]}; IF NOT msgExists THEN EXIT; IF archived AND NOT archivedReported THEN {archivedReported _ TRUE; ReportProgressString["archived messages .. "L]}; IF deleted THEN LOOP; DO item _ retProcs.nextItem[intC.retrieveHandle ! RetrieveDefs.Failed => {whyFailed _ why; GOTO retrieveError} ]; IF item.type = Text OR item.type = LastItem THEN EXIT; ENDLOOP; IF item.type = LastItem THEN LOOP; ProcessDefs.Yield[]; UNTIL item.length = 0 DO -- message chunks breakBytes: CARDINAL = breakBuffers*bufferBytes; tb.textLength _ IF item.length <= breakBytes THEN InlineDefs.LowHalf[item.length] ELSE breakBytes; item.length _ item.length - tb.textLength; IF firstChunk THEN mfD.CreateStamp[tb, BoxPutChar] ELSE BEGIN exD.GetExceptionString[exD.continuationHeader, utilityString]; tb.textLength _ tb.textLength + utilityString.length; mfD.CreateStamp[tb, BoxPutChar]; csD.WriteBlock[mailFileSH, @utilityString.text, 0, utilityString.length]; END; firstChunk _ FALSE; FOR blockCounter: CARDINAL IN [0 .. breakBuffers) DO -- next block bytes: CARDINAL = retProcs.nextBlock[intC.retrieveHandle, DESCRIPTOR[buffer, bufferBytes] ! RetrieveDefs.Failed => {whyFailed _ why; GOTO retrieveError} ]; IF bytes = 0 THEN EXIT; csD.WriteBlock[mailFileSH, buffer, 0, bytes]; ENDLOOP; -- next block ENDLOOP; -- message chunk messages _ messages + 1; REPEAT retrieveError => BEGIN IF NOT connected THEN ReportProgress[exD.dots]; ReportProgress[ SELECT whyFailed FROM communicationFailure => exD.failedSemi, noSuchServer => exD.badServerNameSemi, connectionRejected => exD.busySemi, badCredentials => exD.badCredentialsSemi, ENDCASE => exD.unknownErrorSemi ]; csD.Reset[mailFileSH]; csD.Checkpoint[mailFileSH]; LOOP; -- goes to start of next server loop END; ENDLOOP; -- next message csD.Checkpoint[mailFileSH]; retProcs.accept[intC.retrieveHandle ! RetrieveDefs.Failed => CONTINUE ]; IF messages = 0 THEN ReportProgress[exD.emptySemi] ELSE BEGIN numString: STRING = [6]; StringDefs.AppendNumber[numString,messages,10]; ReportProgressString[numString]; ReportProgress[exD.semi]; messagesRead _ TRUE; END; ENDLOOP; -- next server gsD.ReturnMemoryPages[bufferPages,buffer]; buffer _ NIL; IF NOT serverKnown THEN GOTO noMailboxes; IF messagesRead THEN BEGIN -- extend toc to include new messages ENABLE csD.Error => GOTO csError; p: csD.Position; vmD.GetTOCFixedPart[vmD.GetFirstFreeTOCIndex[] - 1, tb]; BoxPositionNextChar[tb.firstPage, tb.firstByte+tb.offsetToHeader+tb.textLength, 24]; parseHandle _ mfD.InitializeParseHeader[BoxNextChar, BoxBackupChar]; WHILE (p _ csD.GetPosition[mailFileSH]) < csD.GetLength[mailFileSH] DO [tb.firstPage, tb.firstByte] _ csD.MapPositionToPageByte[p]; IF mfD.ParseStamp[BoxNextChar, tb] # ovD.ok THEN exD.SysBug[]; BoxPositionNextChar[tb.firstPage, tb.firstByte+tb.offsetToHeader, tb.textLength]; mfD.ParseHeaderForTOC[utilityString, parseHandle]; IF vmD.ExtendTOC[tb, utilityString] # ovD.ok THEN GOTO tocError; BoxPositionNextChar[tb.firstPage, tb.firstByte+tb.offsetToHeader+tb.textLength, 24]; ENDLOOP; END ELSE ReportException[exD.noNewMail]; EXITS noMailboxes => ReportException[exD.noMailboxes, flash]; credentialsError => ReportException[exD.loginTryAgain, flash]; noServers => ReportException[exD.cantConnect, flash]; tocError => ReportException[exD.tocOverflow, flash]; csError => ReportException[exD.probDiskError, flash]; END; -- of EXITS block IF parseHandle ~= NIL THEN mfD.FinalizeParseHeader[parseHandle]; IF mailFileSH # NIL THEN csD.Destroy[mailFileSH]; IF buffer # NIL THEN gsD.ReturnMemoryPages[bufferPages,buffer]; IF flashWanted THEN exD.FlashExceptionsRegion[]; RETURN; END; -- of AccessNewMailOperation -- END. -- of AccessOp -- z19932(635)\f1