-- file: InstallLaurel.Mesa -- edited by Levin, January 16, 1981 11:14 AM. -- edited by Brotz, April 2, 1981 4:41 PM -- edited by Schroeder, March 14, 1981 12:36 PM. DIRECTORY AltoDefs, AltoFileDefs, Ascii, BFSDefs, ControlDefs, crD: FROM "CoreDefs", csD: FROM "CoreStreamDefs", displayCommon, DMSTimeDefs, drD: FROM "LaurelDriverDefs", dsD: FROM "DisplayDefs", DiskDefs, exD: FROM "ExceptionDefs", FrameDefs, FrameOps, ImageDefs, Inline, intCommon, inD: FROM "InteractorDefs", LaurelHardcopyDefs, lsD: FROM "LaurelStateDefs", MailParse, MiscDefs, ovD: FROM "OverviewDefs", SegmentDefs, Storage, StringDefs, SwapperOps, TimeDefs; InstallLaurel: PROGRAM IMPORTS BFSDefs, crD, csD, disC: displayCommon, DMSTimeDefs, exD, Inline, intC: intCommon, inD, FrameDefs, FrameOps, LaurelHardcopyDefs, lsD, MailParse, MiscDefs, SegmentDefs, Storage, StringDefs, SwapperOps, TimeDefs EXPORTS drD, lsD SHARES lsD = BEGIN OPEN drD; stateFH: SegmentDefs.FileHandle; stateHeaderSeg: SegmentDefs.FileSegmentHandle; stateHeader: POINTER TO lsD.StateHeader; stateSegPages: AltoDefs.PageCount; heapFirstFree: POINTER; heapLimit: POINTER; profileInUserCm: BOOLEAN; videoBackground: PUBLIC dsD.backgtype; logFile: crD.UFileHandle; log: csD.StreamHandle; InitializeState: PROCEDURE[imageFile: SegmentDefs.FileHandle, heapDS: SegmentDefs.DataSegmentHandle] = BEGIN OPEN SegmentDefs; stateFileName: STRING = "Laurel.state"L; GetGlobalFrameSize: PROCEDURE[link: UNSPECIFIED] RETURNS[length: CARDINAL] = BEGIN OPEN ControlDefs; frame: GlobalFrameHandle _ FrameDefs.GlobalFrame[link]; codeSeg: FileSegmentHandle _ FrameOps.CodeHandle[frame]; seg: FileSegmentHandle _ NewFileSegment[codeSeg.file, codeSeg.base, codeSeg.pages, Read]; fcb: FrameCodeBase _ frame.code; prefix: PrefixHandle; p: POINTER; SwapIn[seg]; IF fcb.out THEN fcb.out _ FALSE ELSE fcb.shortbase _ fcb.shortbase - LOOPHOLE[FileSegmentAddress[codeSeg], CARDINAL]; prefix _ p _ FileSegmentAddress[seg] + fcb.offset; length _ (p+prefix.entry[MainBodyIndex].initialpc-1)^; Unlock[seg]; DeleteFileSegment[seg]; END; intCLength: CARDINAL = GetGlobalFrameSize[intC] - SIZE[ControlDefs.GlobalFrame]; disCLength: CARDINAL = GetGlobalFrameSize[disC] - SIZE[ControlDefs.GlobalFrame]; imageFileLength: CARDINAL = GetEndOfFile[imageFile].page; daTableLength: CARDINAL = imageFileLength+3; diskrequest: DiskDefs.DiskRequest; scratchSeg: DataSegmentHandle = NewDataSegment[DefaultBase, 1]; DAs: DESCRIPTOR FOR ARRAY [-1..0) OF AltoFileDefs.vDA; heapLimit _ DataSegmentAddress[heapDS]; heapFirstFree _ heapLimit+AltoDefs.PageSize*heapDS.pages-1; IF (stateFH _ crD.LookupInFileCache[stateFileName]) = NIL THEN BEGIN stateFH _ NewFile[stateFileName, ReadWriteAppend, NewFileOnly]; crD.InsertInFileCache[stateFileName, stateFH]; END ELSE SetFileAccess[stateFH, ReadWriteAppend]; stateSegPages _ Storage.PagesForWords[SIZE[lsD.StateHeader] + intCLength + disCLength]; SetEndOfFile[stateFH, stateSegPages, AltoDefs.BytesPerPage]; stateHeaderSeg _ NewFileSegment[stateFH, 1, stateSegPages, ReadWrite]; SwapIn[stateHeaderSeg]; stateHeader _ FileSegmentAddress[stateHeaderSeg]; stateHeader.cachedHeapTop _ heapDS.VMpage + heapDS.pages; stateHeader.imageFP _ imageFile.fp; stateHeader.imageTime _ lsD.GetWrittenTime[imageFile]; stateHeader.intCOffset _ SIZE[lsD.StateHeader]; stateHeader.disCOffset _ stateHeader.intCOffset + intCLength; stateHeader.headerFF _ stateHeader.disCOffset + disCLength; stateHeader.imageDATableSeg _ lsD.DefineStateSegment[Storage.PagesForWords[daTableLength]]; DAs _ DESCRIPTOR[lsD.SwapInStateSegment[stateHeader.imageDATableSeg], daTableLength]; diskrequest _ DiskDefs.DiskRequest [ ca: DataSegmentAddress[scratchSeg], fixedCA: TRUE, da: @DAs[0], fp: @imageFile.fp, firstPage: 0, lastPage: imageFileLength, action: ReadD, lastAction: ReadD, signalCheckError: FALSE, option: update[cleanup: BFSDefs.GetNextDA]]; MiscDefs.SetBlock[@DAs[-1], AltoFileDefs.fillinDA, daTableLength]; DAs[0] _ imageFile.fp.leaderDA; [] _ BFSDefs.ActOnPages[LOOPHOLE[@diskrequest]]; lsD.WriteStateSegment[stateHeader.imageDATableSeg]; lsD.ReleaseStateSegment[stateHeader.imageDATableSeg]; DeleteDataSegment[scratchSeg]; END; -- of InitializeState InstallState: PROCEDURE[imageFile: SegmentDefs.FileHandle, heapDS: SegmentDefs.DataSegmentHandle] = BEGIN OPEN SegmentDefs; profileFile: FileHandle _ crD.LookupInFileCache[IF profileInUserCm THEN "User.cm"L ELSE "Laurel.profile"L]; fontsWidthsFile: FileHandle _ crD.LookupInFileCache["Fonts.widths"L]; lowestHeapPage: PageNumber = PageFromAddress[heapFirstFree+1]; heapPages: PageCount = heapDS.pages-(lowestHeapPage-heapDS.VMpage); heapFS: FileSegmentHandle; ShrinkHeap: PROCEDURE = BEGIN IF lowestHeapPage = heapDS.VMpage THEN RETURN; SwapperOps.Update[heapDS.VMpage, lowestHeapPage-heapDS.VMpage, SwapperOps.FreePage, FALSE]; heapDS.VMpage _ lowestHeapPage; heapDS.pages _ heapPages; END; IF profileFile = NIL THEN stateHeader.profileFP _ AltoFileDefs.NullFP ELSE BEGIN stateHeader.profileFP _ profileFile.fp; stateHeader.profileTime _ lsD.GetWrittenTime[profileFile]; stateHeader.profileInUserCm _ profileInUserCm; END; IF fontsWidthsFile = NIL THEN stateHeader.fontsWidthsFP _ AltoFileDefs.NullFP ELSE BEGIN stateHeader.fontsWidthsFP _ fontsWidthsFile.fp; stateHeader.fontsWidthsTime _ lsD.GetWrittenTime[fontsWidthsFile]; END; Inline.COPY[to: stateHeader+stateHeader.intCOffset, from: @LOOPHOLE[intC, ControlDefs.GlobalFrameHandle].global[0], nwords: stateHeader.disCOffset-stateHeader.intCOffset]; Inline.COPY[to: stateHeader+stateHeader.disCOffset, from: @LOOPHOLE[disC, ControlDefs.GlobalFrameHandle].global[0], nwords: stateHeader.headerFF-stateHeader.disCOffset]; ShrinkHeap[]; lsD.InstallSegments[stateHeader]; stateHeader.heapSegFirstPage _ GetEndOfFile[stateFH].page+1; stateHeader.heapSegPages _ heapPages; SetEndOfFile[stateFH, stateHeader.heapSegFirstPage+heapPages-1, AltoDefs.BytesPerPage]; heapFS _ NewFileSegment[stateFH, stateHeader.heapSegFirstPage, stateHeader.heapSegPages, Read+Write]; CopyDataToFileSegment[heapDS, heapFS]; -- writes heap to state file stateHeader.heapSegDA _ GetFileSegmentDA[heapFS]; DeleteFileSegment[heapFS]; stateHeaderSeg.write _ TRUE; Unlock[stateHeaderSeg]; DeleteFileSegment[stateHeaderSeg]; END; -- of InstallState AllocateStateNode: PUBLIC PROCEDURE[size: CARDINAL] RETURNS [base: POINTER] = BEGIN base _ heapFirstFree-size+1; IF LOOPHOLE[base, CARDINAL] < LOOPHOLE[heapLimit, CARDINAL] THEN exD.SysBug[]; heapFirstFree _ base-1; END; AllocateStateString: PUBLIC PROCEDURE [chars: CARDINAL] RETURNS [p: STRING] = BEGIN p _ AllocateStateNode[StringDefs.WordsForString[chars]]; p^ _ StringBody[length: 0, maxlength: chars, text: ]; END; BuildInteractor: PROCEDURE = -- establishes static structures for interactor BEGIN InstallFont[]; inD.BuildScreenStructures[]; disC.bitMapReady _ FALSE; intC.haveMailFile _ FALSE; intC.composedMessageEdited _ FALSE; intC.timeMayBeBogus _ FALSE; intC.currentCommand _ NIL; intC.commandType _ noCommand; intC.editorMenuState _ singleLine; intC.target _ intC.source _ inD.TextSelection[mnp: intC.cmTextNbr, start: 0, end: 0, point: 0, mode: char, pendingDelete: FALSE]; intC.actionPoint _ 0; intC.currentSelection _ target; intC.commandMode _ TRUE; intC.runCommandMode _ FALSE; intC.secondarySelectionEnabled _ FALSE; END; -- of BuildInteractor -- InstallFont: PROCEDURE = -- Assumes 'font' points to the font. Sets the charPropTable to describe the font, assuming -- the smudges have already been installed. BEGIN ch: CHARACTER; i: CARDINAL; whiteString: STRING = " "L; punctuationString: STRING = "!@#$%~&*()-`=+[{]};:'"",.<>/?\|_^"L; FOR ch IN dsD.LegalCharacters DO disC.charPropertyTable[ch] _ alphaNumeric; ENDLOOP; disC.charPropertyTable[140C] _ punctuation; FOR i IN [0 .. whiteString.length) DO disC.charPropertyTable[whiteString[i]] _ white; ENDLOOP; disC.charPropertyTable[Ascii.TAB + (ovD.LineBreakValue - 0C)] _ white; disC.charPropertyTable[Ascii.CR + (ovD.LineBreakValue - 0C)] _ white; FOR i IN [0 .. punctuationString.length) DO disC.charPropertyTable[punctuationString[i]] _ punctuation; ENDLOOP; END; -- of InstallFont -- ReadLaurelProfile: PROCEDURE RETURNS [installError: drD.InstallError] = -- Opens Laurel.Profile, parses it, and extracts information for intCommon. BEGIN keyWord: STRING _ [50]; value: STRING _ [100]; laurelProfileHandle: csD.StreamHandle; pH: MailParse.ParseHandle; start: csD.Position _ 0; eof: csD.Position; offEnd: CARDINAL; crSeen: BOOLEAN; -- A LARGE number of local procedures for ReadLaurelProfile follow -- ProcessUserCm: PROCEDURE [section: STRING, proc: PROCEDURE] RETURNS[found: BOOLEAN] = BEGIN OPEN StringDefs; AdvancePastCR: PROCEDURE RETURNS [BOOLEAN] = BEGIN DO IF csD.Read[laurelProfileHandle ! csD.Error => IF reason = ovD.endOfStream THEN EXIT] = Ascii.CR THEN RETURN[TRUE]; ENDLOOP; RETURN[FALSE] END; -- of AdvancePastCR -- found _ TRUE; laurelProfileHandle _ csD.OpenFromName["User.cm"L, intC.user, byte, read, 2 ! csD.Error => IF reason = ovD.fileNotFound THEN {found _ FALSE; CONTINUE}]; IF ~found THEN RETURN; found _ FALSE; BEGIN ENABLE UNWIND => csD.Close[laurelProfileHandle]; DO SELECT csD.Read[laurelProfileHandle ! csD.Error => IF reason = ovD.endOfStream THEN GO TO Done] FROM '[ => BEGIN sectionHeading: STRING _ [9]; sectionHeading.length _ csD.ReadBlock[laurelProfileHandle, @sectionHeading.text, 0, section.length]; IF sectionHeading.length ~= section.length THEN GO TO Done; -- eof IF EquivalentString[sectionHeading, section] THEN EXIT; csD.SetPosition[laurelProfileHandle, csD.GetPosition[laurelProfileHandle] - section.length]; END; Ascii.CR => LOOP; ENDCASE; IF ~AdvancePastCR[] THEN GO TO Done; -- section not found ENDLOOP; -- [section] found; scan past CR IF ~AdvancePastCR[] THEN GO TO Done; -- malformed user.cm; ignore it. found _ TRUE; start _ csD.GetPosition[laurelProfileHandle]; eof _ csD.GetLength[laurelProfileHandle]; DO SELECT csD.Read[laurelProfileHandle ! csD.Error => IF reason = ovD.endOfStream THEN EXIT] FROM '[ => {eof _ csD.GetPosition[laurelProfileHandle] - 1; EXIT}; Ascii.CR => NULL; ENDCASE => IF ~AdvancePastCR[] THEN EXIT; ENDLOOP; csD.SetPosition[laurelProfileHandle, start]; FOR i: csD.Position IN [start..eof) DO IF csD.Read[laurelProfileHandle] ~= Ascii.CR THEN {csD.SetPosition[laurelProfileHandle, i]; EXIT}; ENDLOOP; proc[]; END; -- ENABLE -- GO TO Done; EXITS Done => csD.Close[laurelProfileHandle]; END; -- of ProcessUserCm -- ProcessLaurelProfile: PROCEDURE RETURNS [found: BOOLEAN] = BEGIN found _ TRUE; laurelProfileHandle _ csD.OpenFromName["Laurel.Profile"L, intC.user, byte, read, 2 ! csD.Error => IF reason = ovD.fileNotFound THEN {found _ FALSE; CONTINUE}]; IF ~found THEN RETURN; BEGIN ENABLE UNWIND => csD.Close[laurelProfileHandle]; start _ 0; eof _ csD.GetLength[laurelProfileHandle]; FOR i: csD.Position IN [start..eof) DO IF csD.Read[laurelProfileHandle] ~= Ascii.CR THEN {csD.SetPosition[laurelProfileHandle, i]; EXIT}; ENDLOOP; DoLaurelPart[]; END; -- ENABLE -- csD.Close[laurelProfileHandle]; END; -- of ProcessLaurelProfile -- InitParse: PROCEDURE = BEGIN offEnd _ 0; crSeen _ FALSE; pH _ MailParse.InitializeParse[GetProfileChar, BackupProfileChar]; END; -- of InitParse -- GetProfileChar: PROCEDURE RETURNS [char: CHARACTER] = BEGIN OPEN Ascii; inBravoTrailer: BOOLEAN _ FALSE; DO IF offEnd > 0 OR csD.GetPosition[laurelProfileHandle] >= eof THEN GO TO noChar; IF (char _ csD.Read[laurelProfileHandle]) ~= CR THEN BEGIN IF ~inBravoTrailer THEN IF char = ControlZ THEN inBravoTrailer _ TRUE ELSE EXIT; END ELSE IF ~crSeen THEN EXIT; REPEAT noChar => {char _ CR; offEnd _ offEnd + 1}; ENDLOOP; crSeen _ char = CR; END; -- of GetProfileChar -- BackupProfileChar: PROCEDURE = BEGIN IF offEnd > 0 THEN offEnd _ offEnd - 1 ELSE csD.SetPosition[laurelProfileHandle, csD.GetPosition[laurelProfileHandle] - 1]; END; -- of BackupProfileChar -- WriteStringToLog: PROCEDURE [s: STRING] = BEGIN IF logFile = NIL OR installError = noLog THEN RETURN; IF csD.GetPosition[log] = 0 THEN InitLog[]; csD.WriteBlock[log, @s.text, 0, s.length ! csD.Error => {installError _ noLog; CONTINUE}]; END; -- of WriteStringToLog -- WriteCharToLog: PROCEDURE [char: CHARACTER] = BEGIN IF logFile = NIL OR installError = noLog THEN RETURN; IF csD.GetPosition[log] = 0 THEN InitLog[]; csD.Write[log, char ! csD.Error => {installError _ noLog; CONTINUE}]; END; -- of WriteCharToLog -- WriteLogEntry: PROCEDURE [s: STRING] = BEGIN WriteStringToLog[s]; WriteStringToLog[" "L]; END; -- of WriteLogEntry -- FinishLogEntry: PROCEDURE = {WriteLogEntry[""L]}; WriteBadValueMsgInLog: PROCEDURE [fieldName: STRING] = BEGIN WriteStringToLog["The '"L]; WriteStringToLog[fieldName]; WriteLogEntry["' entry in the profile is specified incorrectly."]; END; -- WriteBadValueMsgInLog -- InitLog: PROCEDURE = BEGIN preamble: STRING = "*start* 00000 00024 UU Date: "L; postamble: STRING = " Subject: Installation Difficulties From: Laurel Laurel discovered the following problem(s) during installation: "L; dateString: STRING _ [DMSTimeDefs.timeStringLength]; csD.WriteBlock[log, @preamble.text, 0, preamble.length ! csD.Error => CONTINUE]; DMSTimeDefs.MapPackedTimeToTimeZoneString [LOOPHOLE[TimeDefs.CurrentDayTime[]], dateString, laurelMsg]; WriteStringToLog[dateString]; WriteStringToLog[postamble]; installError _ inLog; END; -- of InitLog -- FinishLog: PROCEDURE = BEGIN IF installError ~= none THEN BEGIN s: STRING _ [5]; csD.SetPosition[log, 8]; StringDefs.AppendDecimal[s, Inline.LowHalf[csD.GetLength[log]]]; THROUGH [0 .. 5 - s.length) DO WriteCharToLog['0] ENDLOOP; WriteStringToLog[s]; csD.Close[log]; END; END; -- of FinishLog -- DoLaurelPart: PROCEDURE = BEGIN OPEN StringDefs; discard: STRING _ [0]; DO IF ~MailParse.GetFieldName[pH, keyWord] THEN EXIT; SELECT TRUE FROM EquivalentString[keyWord, "Registry"L] => FillFromProfile[@intC.profileRegistry]; EquivalentString[keyWord, "Send"L] => FillFromProfile[@intC.profileSend]; EquivalentString[keyWord, "Retrieve"L] => FillFromProfile[@intC.profileRetrieve]; (EquivalentString[keyWord, "Printer"L] OR EquivalentString[keyWord, "Hardcopy"L]) => FillFromProfile[@intC.hardcopyHost]; EquivalentString[keyWord, "PrintedBy"L] => FillFromProfile[@intC.hardcopyUserName]; EquivalentString[keyWord, "LaurelSupport"L] => FillFromProfile[@intC.bugReportee]; EquivalentString[keyWord, "RunPath"L] => FillFromProfile[@intC.runPath]; EquivalentString[keyWord, "RemoteFilePath"L] => FillFromProfile[@intC.remoteFilePath]; EquivalentString[keyWord, "ArpaHostNames"L] => FillArpaHosts[]; EquivalentString[keyWord, "Font"L] => BEGIN MailParse.GetFieldBody[pH, value, TRUE]; ProcessHardcopyCode[LaurelHardcopyDefs.ParseFont[value]]; END; EquivalentString[keyWord, "HardcopyForm"L] => [] _ LaurelHardcopyDefs.ParseHardcopyForm[pH]; EquivalentString[keyWord, "DefaultHardcopyForm"L] => FillFromProfile[@intC.defaultHardcopyFormName]; EquivalentString[keyWord, "Boundary"L] => BEGIN bad: BOOLEAN _ FALSE; item: {command, toc, dm, cm, bad} _ command; keyNo: CARDINAL; ProcessOne: PROC [n, r, h: STRING, nameInfo: MailParse.NameInfo] RETURNS [BOOLEAN] = BEGIN OPEN StringDefs; val: CARDINAL; IF n.length = 0 OR r.length ~= 0 OR h.length ~= 0 OR nameInfo.nesting # none THEN GO TO bogus; val _ StringToDecimal[n ! InvalidNumber => GO TO bogus]; SELECT item FROM command => IF (keyNo _ val) ~IN [0..9] THEN GO TO bogus; toc => intC.boundarySet[keyNo].toc _ val; dm => intC.boundarySet[keyNo].dm _ val; cm => intC.boundarySet[keyNo].cm _ val; ENDCASE => GO TO bogus; item _ SUCC[item]; RETURN[FALSE]; EXITS bogus => {bad _ TRUE; RETURN[FALSE]}; END; -- of ProcessOne -- MailParse.ParseNameList[pH: pH, process: ProcessOne, suppressWhiteSpace: TRUE]; IF bad THEN WriteBadValueMsgInLog[keyWord]; END; EquivalentString[keyWord, "NewMailTune"L] => FillFromProfile[@intC.newMailTune]; ENDCASE => BEGIN MailParse.GetFieldBody[pH, value]; SELECT TRUE FROM -- Report decommissioned fields. EquivalentString[keyWord, "Authenticate"L], EquivalentString[keyWord, "ForceMTPSend"L], EquivalentString[keyWord, "Herald"L], EquivalentString[keyWord, "HeraldFont"L], EquivalentString[keyWord, "Logo"L], EquivalentString[keyWord, "LogoFont"L], EquivalentString[keyWord, "Poll"L], EquivalentString[keyWord, "DisplayErrorPups"L] => BEGIN WriteStringToLog["The profile field '"L]; WriteStringToLog[keyWord]; WriteLogEntry["' is no longer used."]; END; EquivalentString[keyWord, "Comment"L] => NULL; EquivalentString[keyWord, "C"L] => NULL; EquivalentString[keyWord, "DendroicaStriata"L] => BEGIN pollingInterval: CARDINAL _ StringToDecimal[value]; intC.mailcheckPollingInterval _ IF pollingInterval = 0 THEN 15 ELSE ((pollingInterval + 14) / 15) * 15; -- polling interval will be a multiple of 15 seconds and greater than 0. END; EquivalentString[keyWord, "Leaf"L] => FillProfileBoolean[@intC.leafOk]; EquivalentString[keyWord, "Background"L] => SELECT TRUE FROM EquivalentString[value, "white"L] => videoBackground _ white; EquivalentString[value, "black"L] => videoBackground _ black; ENDCASE => WriteBadValueMsgInLog[keyWord]; EquivalentString[keyWord, "SendMode"L] => SELECT TRUE FROM EquivalentString[value, "mtp"L] => intC.profileSendMode _ mtp; EquivalentString[value, "gv"L] => intC.profileSendMode _ gv; EquivalentString[value, "auto"L] => intC.profileSendMode _ auto; ENDCASE => WriteBadValueMsgInLog[keyWord]; EquivalentString[keyWord, "GVTestingMode"L] => FillProfileBoolean[@intC.gvTestingMode]; EquivalentString[keyWord, "NewFormAfterDelivery"L] => FillProfileBoolean[@intC.newFormAfterDelivery]; EquivalentString[keyWord, "DisplayAfterDelete"L] => FillProfileBoolean[@intC.displayAfterDelete]; EquivalentString[keyWord, "CopiesField"L] => intC.cForCopies _ EquivalentString[value, "c"L]; EquivalentString[keyWord, "Editor"L] => IF EquivalentString[value, "modeless"L] THEN intC.editorType _ modeless; EquivalentString[keyWord, "Copies"L] => BEGIN n: CARDINAL _ 0; n _ StringToDecimal[value ! InvalidNumber => CONTINUE]; IF n IN [1 .. 99] THEN intC.defaultHardCopies _ n; END; EquivalentString[keyWord, "FromField"L] => intC.fromRightX _ inD.leftMargin + StringToDecimal[value ! InvalidNumber => CONTINUE]; EquivalentString[keyWord, "SubjectField"L] => intC.subjectLeftX _ inD.leftMargin + StringToDecimal[value ! InvalidNumber => CONTINUE]; EquivalentString[keyWord, "SubjectFieldExtension"L] => intC.subjectExtensionLeftX _ inD.leftMargin + StringToDecimal[value ! InvalidNumber => CONTINUE]; EquivalentString[keyWord, "Click"L] => FillProfileTicks[@intC.multiClickTimeOut]; EquivalentString[keyWord, "Tap"L] => FillProfileTicks[@intC.tapTimeOut]; EquivalentString[keyWord, "ScrollTimeOut"L] => FillProfileTicks[@intC.continuousScrollTimeOut]; EquivalentString[keyWord, "ScrollDelay"L] => FillProfileTicks[@intC.continuousScrollDelay]; EquivalentString[keyWord, "BracketTimeOut"L] => FillProfileTicks[@intC.nextBracketTimeout]; EquivalentString[keyWord, "BracketDelay"L] => FillProfileTicks[@intC.nextBracketDelay]; EquivalentString[keyWord, "TwoSided"L] => FillProfileBoolean[@intC.twoSidedPrintingDefault]; EquivalentString[keyWord, "Private"L] => FillProfileBoolean[@intC.passwordPrintingDefault]; EquivalentString[keyWord, "WriteProtected"L] => FillProfileBoolean[@intC.disableWriting]; EquivalentString[keyWord, "HomoTollens"L] => intC.controlRedEnabled _ ~EquivalentString[value, "TRUE"L]; EquivalentString[keyWord, "BluePendingDelete"L] => FillProfileBoolean[@intC.bluePendingDelete]; EquivalentString[keyWord, "ErrorKeys"L] => IF EquivalentString[value, "LaurelX"L] THEN intC.exceptionType _ LaurelX; ENDCASE => BEGIN WriteCharToLog['']; WriteStringToLog[keyWord]; WriteLogEntry["' in the profile is unrecognizable."L]; END; END; ENDLOOP; END; -- of DoLaurelPart -- DoHardcopyPart: PROCEDURE = BEGIN OPEN StringDefs; discard: STRING _ [0]; DO IF ~MailParse.GetFieldName[pH, keyWord] THEN EXIT; SELECT TRUE FROM EquivalentString[keyWord, "Press"L] => FillFromProfile[@intC.hardcopyHost]; EquivalentString[keyWord, "PrintedBy"L] => FillFromProfile[@intC.hardcopyUserName]; ENDCASE => MailParse.GetFieldBody[pH, discard]; ENDLOOP; END; -- of DoHardcopyPart -- FillFromProfile: PROCEDURE [s: POINTER TO STRING] = BEGIN MailParse.GetFieldBody[pH, value]; FillProfileString[s, value]; END; -- of FillFromProfile -- FillProfileString: PROCEDURE [s: POINTER TO STRING, value: STRING] = BEGIN IF s^ # NIL THEN RETURN; s^ _ AllocateStateString[value.length]; s^.length _ 0; StringDefs.AppendString[s^, value]; END; -- of FillProfileString -- FillProfileBoolean: PROCEDURE [b: POINTER TO BOOLEAN] = BEGIN b^ _ StringDefs.EquivalentString[value, "TRUE"L] OR StringDefs.EquivalentString[value, "Yes"L]; END; -- of FillProfileBoolean -- FillProfileTicks: PROCEDURE [c: POINTER TO CARDINAL] = BEGIN c^ _(StringDefs.StringToDecimal[value ! StringDefs.InvalidNumber =>CONTINUE]+37)/38; END; -- of FillProfileTicks -- NameIndex: TYPE = [0..5); names: ARRAY NameIndex OF STRING; firstFree: CARDINAL _ FIRST[NameIndex]; FillArpaHosts: PROCEDURE = INLINE BEGIN MailParse.ParseNameList[pH: pH, process: ProcessHost, suppressWhiteSpace: TRUE]; END; -- of FillArpaHosts -- ProcessHost: PROCEDURE[host, ignore1, ignore2: STRING, ignore3: MailParse.NameInfo] RETURNS [BOOLEAN] = BEGIN IF firstFree > LAST[NameIndex] THEN RETURN[FALSE]; names[firstFree] _ AllocateStateString[host.length]; StringDefs.AppendString[names[firstFree], host]; firstFree _ firstFree + 1; RETURN[TRUE] END; -- of ProcessHost -- ProcessHardcopyCode: PROCEDURE [error: ovD.ErrorCode] = BEGIN SELECT error FROM ovD.ok => RETURN; ovD.profileBadFont => -- ParseFont only BEGIN WriteStringToLog["The profile Font entry '"L]; WriteStringToLog[value]; WriteLogEntry["' does not contain a valid font number."L]; END; ovD.badFontsWidths => WriteLogEntry["The file 'Fonts.Widths' is missing or unreadable."L]; ovD.fontNotInFontsWidths => BEGIN IF value.length = 0 THEN WriteStringToLog["A default font"L] ELSE {WriteCharToLog['']; WriteStringToLog[value]; WriteCharToLog['']}; WriteLogEntry[" is not in Fonts.Widths."L]; END; ENDCASE => exD.SysBug[]; intC.hardcopyInstallError _ TRUE; END; -- of ProcessHardcopyCode -- -- Main body of ReadLaurelProfile follows -- installError _ none; -- initialize non-string defaultable fields -- intC.profileRegistry _ NIL; intC.mailFileHandle _ NIL; intC.profileSend _ NIL; intC.profileRetrieve _ NIL; intC.gvTestingMode _ FALSE; intC.autoConfirm _ FALSE; intC.profileSendMode _ auto; intC.profileRetrieveMode _ auto; intC.newFormAfterDelivery _ FALSE; intC.displayAfterDelete _ FALSE; intC.hardcopyHost _ NIL; intC.hardcopyUserName _ NIL; intC.newMailTune _ NIL; intC.bugReportee _ NIL; intC.runPath _ NIL; intC.remoteFilePath _ NIL; intC.leafOk _ FALSE; intC.mailcheckPollingInterval _ 300; intC.multiClickTimeOut _ 10; intC.tapTimeOut _ 10; intC.continuousScrollTimeOut _ 26; intC.continuousScrollDelay _ 5; intC.nextBracketTimeout _ 19; intC.nextBracketDelay _ 19; intC.dateLeftX _ inD.leftMargin + 50; intC.dateRightX _ inD.leftMargin + 100; intC.fromLeftX _ inD.leftMargin + 110; intC.fromRightX _ inD.leftMargin + 250; intC.subjectLeftX _ inD.leftMargin + 260; intC.subjectExtensionLeftX _ inD.leftMargin + 275; videoBackground _ white; intC.cForCopies _ FALSE; intC.disableWriting _ FALSE; intC.controlRedEnabled _ TRUE; intC.bluePendingDelete _ FALSE; intC.pendingDeleteSetByControl _ FALSE; intC.audioEnabled _ FALSE; intC.hardcopyInstallError _ FALSE; intC.editorType _ modal; intC.defaultHardCopies _ 1; intC.passwordPrintingDefault _ FALSE; intC.twoSidedPrintingDefault _ FALSE; intC.exceptionType _ Laurel; intC.boundarySet _ lsD.AllocateStateNode[SIZE[inD.BoundarySetArray]]; intC.boundarySet^ _ ALL[[toc: 12, dm: 19, cm: 16]]; intC.boundarySet[1] _ [toc: 1, dm: 0, cm: 0]; intC.boundarySet[2] _ [toc: 0, dm: 1, cm: 0]; intC.boundarySet[3] _ [toc: 0, dm: 0, cm: 1]; -- acquire profile information IF logFile # NIL THEN log _ csD.Open[logFile, byte, overwrite, 2]; LaurelHardcopyDefs.InitHardcopyFonts[]; InitParse[]; profileInUserCm _ FALSE; BEGIN ENABLE BEGIN MailParse.ParseError => BEGIN context: CARDINAL = 20; s: STRING _ [context]; position: csD.Position _ csD.GetPosition[laurelProfileHandle]; WriteStringToLog["Syntax error in profile near: '"L]; position _ IF position < start + context THEN start ELSE position - context; csD.SetPosition[laurelProfileHandle, position]; s.length _ csD.ReadBlock[laurelProfileHandle, @s.text, 0, context]; WriteStringToLog[s]; WriteCharToLog['']; FinishLogEntry[]; CONTINUE END; csD.Error => BEGIN SELECT reason FROM ovD.diskError, ovD.diskCorrupted => WriteLogEntry["Disk error reading profile!"L]; ENDCASE => installError _ noLog; CONTINUE END; END; IF ~ProcessLaurelProfile[] THEN BEGIN profileInUserCm _ ProcessUserCm[section: "Laurel]"L, proc: DoLaurelPart]; IF profileInUserCm AND installError = none THEN BEGIN MailParse.FinalizeParse[pH]; InitParse[]; [] _ ProcessUserCm[section: "Hardcopy]"L, proc: DoHardcopyPart]; END; END; END; -- of ENABLE -- MailParse.FinalizeParse[pH]; IF Storage.StringLength[intC.profileRegistry] = 0 THEN WriteLogEntry["No 'Registry' field in profile."L] ELSE IF intC.profileRegistry.length > 40 THEN WriteLogEntry["Registry name is too long."L]; -- provide defaults (overwrites only if string is still NIL) FillProfileString[@intC.profileRegistry, "NoRegistry"L]; FillProfileString[@intC.hardcopyHost, ""L]; FillProfileString[@intC.hardcopyUserName, "$"L]; FillProfileString[@intC.defaultHardcopyFormName, "Blank"L]; IF intC.hardcopyUserName[0] = '" AND intC.hardcopyUserName[intC.hardcopyUserName.length-1] = '" THEN BEGIN i: CARDINAL; FOR i IN [0..intC.hardcopyUserName.length-2) DO intC.hardcopyUserName[i] _ intC.hardcopyUserName[i+1]; ENDLOOP; intC.hardcopyUserName.length _ intC.hardcopyUserName.length - 2; END; intC.passwordPrinting _ intC.passwordPrintingDefault; intC.twoSidedPrinting _ intC.twoSidedPrintingDefault; intC.hardCopies _ intC.defaultHardCopies; FillProfileString[@intC.bugReportee, "LaurelSupport.PA"L]; IF firstFree = 0 THEN BEGIN [] _ ProcessHost["PARC-MAXC"L, NIL, NIL, [none, FALSE, normal]]; [] _ ProcessHost["PARC"L, NIL, NIL, [none, FALSE, normal]]; [] _ ProcessHost["MAXC"L, NIL, NIL, [none, FALSE, normal]]; END; intC.arpaGatewayHostNames _ DESCRIPTOR[AllocateStateNode[firstFree], firstFree]; FOR i: CARDINAL IN [0 .. firstFree) DO intC.arpaGatewayHostNames[i] _ names[i] ENDLOOP; value.length _ 0; ProcessHardcopyCode[LaurelHardcopyDefs.InstallHardcopy[]]; FinishLog[]; END; -- of ReadLaurelProfile -- GetImageFileName: PROCEDURE = BEGIN OPEN SegmentDefs; file: FileHandle = FrameOps.CodeHandle[FrameDefs.GlobalFrame[intC]].file; seg: FileSegmentHandle _ NewFileSegment[file, 0, 1, Read]; leader: POINTER TO AltoFileDefs.LD; SwapIn[seg]; leader _ FileSegmentAddress[seg]; intC.imageFileName _ lsD.AllocateStateString [LOOPHOLE[@leader.name, POINTER TO StringDefs.BcplSTRING].length]; StringDefs.BcplToMesaString[LOOPHOLE[@leader.name], intC.imageFileName]; intC.imageFileName.length _ intC.imageFileName.length - 1; -- get rid of dot. -- Unlock[seg]; DeleteFileSegment[seg]; END; -- of GetImageFileName -- CreateLaurelState: PUBLIC PROCEDURE[heapDS: SegmentDefs.DataSegmentHandle] RETURNS [installError: drD.InstallError] = BEGIN error: ovD.ErrorCode; savedCursor: dsD.CursorBitMap; installCursor: dsD.CursorBitMap = [002000B, 001000B, 000400B, 001000B, 002000B, 007600B, 037740B, 177777B, 147631B, 140031B, 142031B, 142037B, 143430B, 160070B, 077760B, 017700B]; imageFile: SegmentDefs.FileHandle = FrameOps.CodeHandle[FrameDefs.GlobalFrame[intC]].file; savedCursor _ dsD.cursorBM^; dsD.cursorBM^ _ installCursor; InitializeState[imageFile, heapDS]; [error, logFile] _ crD.OpenFile[intC.user, "InstallErrors.mail"L, update]; IF (installError _ ReadLaurelProfile[]) ~= none THEN BEGIN -- ensure that state will be recomputed next time. This guarantees that the user -- cannot use Laurel until the profile problem is fixed. If this code is removed, -- Laurel will install the defaults in the state and use them until the user edits -- user.cm or laurel.profile. lpFh: SegmentDefs.FileHandle _ crD.LookupInFileCache["Laurel.profile"L]; profileInUserCm _ FALSE; IF lpFh # NIL THEN crD.FreeCacheEntry[lpFh]; END; IF error # ovD.ok THEN installError _ noLog ELSE [] _ (IF installError = none THEN crD.DeleteFile ELSE crD.CloseFile)[logFile]; BuildInteractor[]; GetImageFileName[]; InstallState[imageFile, heapDS]; dsD.cursorBM^ _ savedCursor; END; -- of CreateLaurelState -- END. -- of InstallLaurel --z19932(635)\f1 13384v14V80v5V311v17V35v115V