DIRECTORY AlpFile USING [LockOption, PropertyValuePair], AlpineFS USING [ErrorFromStream, FileOptions, StreamOptions, Abort, Open, OpenFile, OpenFileFromStream, OpenOrCreate, StreamFromOpenFile, WriteProperties], Atom USING [MakeAtomFromRefText], BasicTime USING [GMT, nullGMT, FromPupTime, Now], Convert USING [Error, IntFromRope, TimeFromRope], FS USING [Error, nullOpenFile, OpenFile, StreamBufferParms, StreamOptions, Create, GetInfo, Open, PagesForBytes, SetByteCountAndCreatedTime, SetPageCount, StreamFromOpenFile, StreamOpen], GVBasics USING [RName, Timestamp], IO, RefText USING[line, page, TrustTextAsRope], Rope, UserProfile USING [Boolean, CallWhenProfileChanges, ProfileChangedProc], ViewerTools USING [TiogaContents], WalnutKernelDefs USING [LogEntry, LogEntryObject, MsgLogEntry], WalnutParseMsg USING [MsgHeaders, ParseProc, ParseMsgFromStream], WalnutSendOps USING [RFC822Date, RopeFromStream], WalnutStream USING []; WalnutStreamImpl: CEDAR PROGRAM IMPORTS AlpineFS, Atom, BasicTime, Convert, FS, IO, RefText, Rope, UserProfile, WalnutParseMsg, WalnutSendOps EXPORTS WalnutStream = BEGIN OPEN WalnutStream; GMT: TYPE = BasicTime.GMT; ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; LogEntry: TYPE = WalnutKernelDefs.LogEntry; LogEntryObject: TYPE = WalnutKernelDefs.LogEntryObject; MsgLogEntry: TYPE = WalnutKernelDefs.MsgLogEntry; useFromFieldInTOC: BOOL _ UserProfile.Boolean[key: "Walnut.UseFromFieldInTOC", default: FALSE]; entryHeaderRope: ROPE = "*entry* %10g\n"; entryHeaderLen: INT = 19; copyBuffer: REF TEXT = NEW[TEXT[RefText.page]]; field1: REF TEXT _ NEW[TEXT[RefText.line]]; field2: REF TEXT _ NEW[TEXT[RefText.line]]; field3: REF TEXT _ NEW[TEXT[RefText.line]]; field4: REF TEXT _ NEW[TEXT[RefText.line]]; logFileInfo: PUBLIC REF LogFileInfo LogEntryObject = NEW[LogFileInfo LogEntryObject]; createMsg: PUBLIC REF CreateMsg LogEntryObject = NEW[CreateMsg LogEntryObject]; expungeMsgs: PUBLIC REF ExpungeMsgs LogEntryObject = NEW[ExpungeMsgs LogEntryObject]; writeExpungeLog: PUBLIC REF WriteExpungeLog LogEntryObject = NEW[WriteExpungeLog LogEntryObject]; createMsgSet: PUBLIC REF CreateMsgSet LogEntryObject = NEW[CreateMsgSet LogEntryObject]; emptyMsgSet: PUBLIC REF EmptyMsgSet LogEntryObject = NEW[EmptyMsgSet LogEntryObject]; destroyMsgSet: PUBLIC REF DestroyMsgSet LogEntryObject = NEW[DestroyMsgSet LogEntryObject]; addMsg: PUBLIC REF AddMsg LogEntryObject = NEW[AddMsg LogEntryObject]; removeMsg: PUBLIC REF RemoveMsg LogEntryObject = NEW[RemoveMsg LogEntryObject]; moveMsg: PUBLIC REF MoveMsg LogEntryObject = NEW[MoveMsg LogEntryObject]; hasbeenRead: PUBLIC REF HasBeenRead LogEntryObject = NEW[HasBeenRead LogEntryObject]; recordNewMailInfo: PUBLIC REF RecordNewMailInfo LogEntryObject = NEW[RecordNewMailInfo LogEntryObject]; startCopyNewMail: PUBLIC REF StartCopyNewMail LogEntryObject = NEW[StartCopyNewMail LogEntryObject]; endCopyNewMailInfo: PUBLIC REF EndCopyNewMailInfo LogEntryObject = NEW[EndCopyNewMailInfo LogEntryObject]; acceptNewMail: PUBLIC REF AcceptNewMail LogEntryObject = NEW[AcceptNewMail LogEntryObject]; startReadArchiveFile: PUBLIC REF StartReadArchiveFile LogEntryObject = NEW[StartReadArchiveFile LogEntryObject]; endReadArchiveFile: PUBLIC REF EndReadArchiveFile LogEntryObject = NEW[EndReadArchiveFile LogEntryObject]; startCopyReadArchive: PUBLIC REF StartCopyReadArchive LogEntryObject = NEW[StartCopyReadArchive LogEntryObject]; endCopyReadArchiveInfo: PUBLIC REF EndCopyReadArchiveInfo LogEntryObject = NEW[EndCopyReadArchiveInfo LogEntryObject]; Open: PUBLIC PROC[name: ROPE, readOnly: BOOL _ FALSE, pages: INT _ 200, useOldIfFound: BOOL _ FALSE, exclusive: BOOL _ FALSE] RETURNS [strm: STREAM] = { IF name.Find[".alpine]", 0, FALSE] = -1 THEN { -- file elsewhere IF readOnly THEN strm _ FS.StreamOpen[ fileName: name, streamOptions: localStreamOptions, streamBufferParms: streamBufferOption] ELSE { openFile: FS.OpenFile _ FS.nullOpenFile; IF useOldIfFound THEN openFile _ FS.Open[name, $write ! FS.Error => IF error.code = $unknownFile THEN CONTINUE ELSE REJECT]; IF openFile = FS.nullOpenFile THEN openFile _ FS.Create[name: name, keep: 2, pages: pages]; strm _ FS.StreamFromOpenFile[ openFile: openFile, accessRights: $write, streamOptions: localStreamOptions, streamBufferParms: streamBufferOption]; }; } ELSE { -- alpine file openFile: AlpineFS.OpenFile; IF readOnly THEN { openFile _ AlpineFS.Open[name: name, options: alpineFileOptions]; strm _ AlpineFS.StreamFromOpenFile[openFile: openFile, streamOptions: alpineStreamOptions, streamBufferParms: streamBufferOption]; } ELSE { actualPages: INT; lock: AlpFile.LockOption _ IF exclusive THEN [$write, $fail] ELSE [$none, $wait]; openFile _ AlpineFS.OpenOrCreate[ -- AlpineFS ignores the pages param name: name, pages: pages, options: alpineFileOptions]; actualPages _ FS.GetInfo[openFile].pages; IF pages > actualPages THEN FS.SetPageCount[openFile, pages]; strm _ AlpineFS.StreamFromOpenFile[openFile: openFile, accessRights: $write, initialPosition: $start, streamOptions: alpineStreamOptions, streamBufferParms: streamBufferOption]; }; }; }; alpineFileOptions: AlpineFS.FileOptions _ [ updateCreateTime: TRUE, referencePattern: sequential, recoveryOption: $log, finishTransOnClose: TRUE ]; streamBufferOption: FS.StreamBufferParms = [vmPagesPerBuffer: 4, nBuffers: 4]; alpineStreamOptions: AlpineFS.StreamOptions _ [ tiogaRead: FALSE, commitAndReopenTransOnFlush: TRUE, truncatePagesOnClose: FALSE, finishTransOnClose: TRUE, closeFSOpenFileOnClose: TRUE]; localStreamOptions: FS.StreamOptions _ [ tiogaRead: FALSE, commitAndReopenTransOnFlush: TRUE, truncatePagesOnClose: FALSE, finishTransOnClose: TRUE, closeFSOpenFileOnClose: TRUE]; Aborted: PUBLIC PROC [strm: STREAM] RETURNS [aborted: BOOL] = { code: ATOM _ AlpineFS.ErrorFromStream[strm].code; aborted _ (code = $transAborted); }; AbortStream: PUBLIC PROC[strm: STREAM] = { AlpineFS.Abort[AlpineFS.OpenFileFromStream[strm]] }; FlushStream: PUBLIC PROC[strm: STREAM, setCreateDate: BOOL _ FALSE] = { IF setCreateDate THEN { of: AlpineFS.OpenFile = AlpineFS.OpenFileFromStream[strm]; FS.SetByteCountAndCreatedTime[of, -1, BasicTime.Now[]]; }; strm.Flush[] }; SetHighWaterMark: PUBLIC PROC[ strm: STREAM, hwmBytes: INT, numPages: INT, setCreateDate: BOOL] = { of: AlpineFS.OpenFile = AlpineFS.OpenFileFromStream[strm]; prop: highWaterMark AlpFile.PropertyValuePair = [highWaterMark[FS.PagesForBytes[hwmBytes]]]; strm.SetLength[hwmBytes]; strm.Flush[]; -- make it notice the SetLength IF setCreateDate THEN FS.SetByteCountAndCreatedTime[of, -1, BasicTime.Now[]]; AlpineFS.WriteProperties[of, LIST[prop]]; IF numPages = -1 THEN RETURN; IF FS.GetInfo[of].pages <= numPages THEN RETURN; FS.SetPageCount[of, numPages]; }; SetPosition: PUBLIC PROC[strm: STREAM, index: INT] RETURNS[ok: BOOL] = { pos: INT _ IF index = -1 THEN strm.GetLength[] ELSE index; ok _ TRUE; strm.SetIndex[pos ! IO.Error, IO.EndOfStream => {ok _ FALSE; CONTINUE}]; }; ReadRope: PUBLIC PROC[strm: STREAM, len: INT] RETURNS[r: ROPE] = { r _ WalnutSendOps.RopeFromStream[strm, strm.GetIndex[], len ! IO.EndOfStream => CONTINUE]; }; FindNextEntry: PUBLIC PROC[strm: STREAM] RETURNS[startPos: INT] = { ENABLE IO.EndOfStream => GOTO exit; state: INTEGER _ 0; length: INT; initialPos: INT = strm.GetIndex[]; startPos _ -1; DO SELECT strm.GetChar[] FROM '* => IF state = 6 THEN state _ 7 ELSE state _ 1; 'e => IF state = 1 THEN state _ 2 ELSE state _ 0; 'n => IF state = 2 THEN state _ 3 ELSE state _ 0; 't => IF state = 3 THEN state _ 4 ELSE state _ 0; 'r => IF state = 4 THEN state _ 5 ELSE state _ 0; 'y => IF state = 5 THEN state _ 6 ELSE state _ 0; ENDCASE => state _ 0; IF state = 7 THEN { strm.SetIndex[startPos _ strm.GetIndex[] - 7]; [, length] _ CheckForValidPrefix[strm]; IF length # -1 THEN { strm.SetIndex[startPos]; RETURN }; strm.SetIndex[startPos+1]; }; ENDLOOP; EXITS exit => {startPos _ -1; RETURN}; }; ReadEntry: PUBLIC PROC[strm: STREAM, quick: BOOL] RETURNS[le: LogEntry, length: INT] = { ENABLE IO.EndOfStream => ERROR; -- Shouldn't get EOS's type: ATOM; startPos: INT; [startPos, length] _ CheckForValidPrefix[strm]; IF length = -1 THEN RETURN; -- not a valid entry here type _ Atom.MakeAtomFromRefText[strm.GetLine[field1]]; SELECT type FROM $LogFileInfo => { logFileInfo.key _ strm.GetLine[field1]; logFileInfo.internalFileID _ Convert.IntFromRope[RefText.TrustTextAsRope[strm.GetLine[field2]]]; logFileInfo.logSeqNo _ Convert.IntFromRope[RefText.TrustTextAsRope[strm.GetLine[field2]]]; RETURN[logFileInfo, length]; }; $CreateMsg => { createMsg.msg _ strm.GetLine[field1]; createMsg.textLen _ strm.GetInt[]; createMsg.formatLen _ strm.GetInt[]; [] _ strm.GetChar[]; -- glide over the CR after formatLen createMsg.entryStart _ startPos; createMsg.textOffset _ strm.GetIndex[] - startPos; IF quick THEN ScanForHeadersLen[strm, createMsg] ELSE MsgEntryInfoFromStream[strm, createMsg]; strm.SetIndex[startPos+length]; -- consume entire entry RETURN[createMsg, length]; }; $ExpungeMsgs => RETURN[expungeMsgs, length]; $WriteExpungeLog => { writeExpungeLog.internalFileID _ Convert.IntFromRope[RefText.TrustTextAsRope[strm.GetLine[field1]]]; RETURN[writeExpungeLog, length]; }; $CreateMsgSet => { createMsgSet.msgSet _ strm.GetLine[field1]; RETURN[createMsgSet, length]; }; $EmptyMsgSet => { emptyMsgSet.msgSet _ strm.GetLine[field1]; RETURN[emptyMsgSet, length]; }; $DestroyMsgSet => { destroyMsgSet.msgSet _ strm.GetLine[field1]; RETURN[destroyMsgSet, length]; }; $AddMsg => { addMsg.msg _ strm.GetLine[field1]; addMsg.to _ strm.GetLine[field3]; RETURN[addMsg, length]; }; $RemoveMsg => { removeMsg.msg _ strm.GetLine[field1]; removeMsg.from _ strm.GetLine[field2]; RETURN[removeMsg, length]; }; $MoveMsg => { moveMsg.msg _ strm.GetLine[field1]; moveMsg.from _ strm.GetLine[field2]; moveMsg.to _ strm.GetLine[field3]; RETURN[moveMsg, length]; }; $HasBeenRead => { hasbeenRead.msg _ strm.GetLine[field1]; RETURN[hasbeenRead, length]; }; $RecordNewMailInfo => { recordNewMailInfo.logLen _ Convert.IntFromRope[RefText.TrustTextAsRope[strm.GetLine[field1]]]; recordNewMailInfo.when _ Convert.TimeFromRope[RefText.TrustTextAsRope[strm.GetLine[field2]]]; recordNewMailInfo.server _ strm.GetLine[field3]; recordNewMailInfo.num _ Convert.IntFromRope[RefText.TrustTextAsRope[strm.GetLine[field4]]]; RETURN[recordNewMailInfo, length] }; $StartCopyNewMail => RETURN[startCopyNewMail, length]; $EndCopyNewMailInfo => { endCopyNewMailInfo.startCopyPos _ Convert.IntFromRope[RefText.TrustTextAsRope[strm.GetLine[field1]]]; RETURN[endCopyNewMailInfo, length]; }; $AcceptNewMail => RETURN[acceptNewMail, length]; $StartReadArchiveFile => { startReadArchiveFile.file _ strm.GetLine[field1]; startReadArchiveFile.msgSet _ strm.GetLine[field2]; RETURN[startReadArchiveFile, length]; }; $EndReadArchiveFile => RETURN[endReadArchiveFile, length]; $StartCopyReadArchive => RETURN[startCopyReadArchive, length]; $EndCopyReadArchiveInfo => { endCopyReadArchiveInfo.startCopyPos _ Convert.IntFromRope[RefText.TrustTextAsRope[strm.GetLine[field1]]]; RETURN[endCopyReadArchiveInfo, length]; }; ENDCASE => ERROR; }; PeekEntry: PUBLIC PROC [strm: STREAM] RETURNS[ident: ATOM, msgID: REF TEXT, length: INT] = { startPos: INT; BEGIN ENABLE IO.EndOfStream => GOTO eos; [startPos, length] _ CheckForValidPrefix[strm]; IF length = -1 THEN RETURN; -- not a valid entry here ident _ Atom.MakeAtomFromRefText[strm.GetLine[field1]]; SELECT ident FROM $CreateMsg => msgID _ strm.GetLine[field1]; $AddMsg => msgID _ strm.GetLine[field1]; $RemoveMsg => msgID _ strm.GetLine[field1]; $MoveMsg => msgID _ strm.GetLine[field1]; $DestroyMsg => msgID _ strm.GetLine[field1]; $HasBeenRead => msgID _ strm.GetLine[field1]; ENDCASE => NULL; EXITS eos => length _ -1; -- not a valid entry here END; strm.SetIndex[startPos]; }; WriteEntry: PUBLIC PROC[strm: STREAM, le: LogEntry, pos: INT _ -1] RETURNS[startPos: INT] = { entry: ROPE; extra, length: INT _ 0; TRUSTED { WITH le: le SELECT FROM LogFileInfo => entry _ IO.PutFR["LogFileInfo\n%g\n%g\n%g\n", IO.text[le.key], IO.int[le.internalFileID], IO.int[le.logSeqNo] ]; CreateMsg => { entry _ IO.PutFR["CreateMsg\n%g\n%10g %10g\n", IO.text[le.msg], IO.int[le.textLen], IO.int[le.formatLen] ]; extra _ le.textLen + le.formatLen + 1; }; ExpungeMsgs => entry _ "ExpungeMsgs\n"; WriteExpungeLog => entry _ IO.PutFR["WriteExpungeLog\n%g\n", IO.int[le.internalFileID] ]; CreateMsgSet => entry _ IO.PutFR["CreateMsgSet\n%g\n", IO.text[le.msgSet] ]; EmptyMsgSet => entry _ IO.PutFR["EmptyMsgSet\n%g\n", IO.text[le.msgSet] ]; DestroyMsgSet => entry _ IO.PutFR["DestroyMsgSet\n%g\n", IO.text[le.msgSet] ]; AddMsg => entry _ IO.PutFR["AddMsg\n%g\n%g\n", IO.text[le.msg], IO.text[le.to] ]; RemoveMsg => entry _ IO.PutFR["RemoveMsg\n%g\n%g\n", IO.text[le.msg], IO.text[le.from] ]; MoveMsg => entry _ IO.PutFR["MoveMsg\n%g\n%g\n%g\n", IO.text[le.msg], IO.text[le.from], IO.text[le.to] ]; HasBeenRead => entry _ IO.PutFR["HasBeenRead\n%g\n", IO.text[le.msg], ]; RecordNewMailInfo => entry _ IO.PutFR["RecordNewMailInfo\n%g\n%g\n%g\n%g\n", IO.int[le.logLen], IO.time[le.when], IO.text[le.server], IO.int[le.num] ]; StartCopyNewMail => entry _ "StartCopyNewMail\n"; EndCopyNewMailInfo => entry _ IO.PutFR["EndCopyNewMailInfo\n%g\n", IO.int[le.startCopyPos] ]; AcceptNewMail => entry _ "AcceptNewMail\n"; StartReadArchiveFile => entry _ IO.PutFR["StartReadArchiveFile\n%g\n%g\n", IO.text[le.file], IO.text[le.msgSet] ]; EndReadArchiveFile => entry _ "EndReadArchiveFile\n"; StartCopyReadArchive => entry _ "StartCopyReadArchive\n"; EndCopyReadArchiveInfo => entry _ IO.PutFR["EndCopyReadArchiveInfo\n%g\n", IO.int[le.startCopyPos] ]; ENDCASE => ERROR; }; startPos _ IF pos = -1 THEN strm.GetLength[] ELSE pos; strm.SetIndex[startPos]; length _ entry.Length[] + extra + entryHeaderLen; -- for messages strm.PutRope[IO.PutFR[entryHeaderRope, IO.int[length]]]; -- entryHeaderLen (19 characters) strm.PutRope[entry]; }; WriteMsgBody: PUBLIC PROC[strm: STREAM, body: ViewerTools.TiogaContents] = { strm.PutRope[body.contents]; strm.PutRope[body.formatting]; strm.PutChar['\n]; }; Overwrite: PUBLIC PROC[to, from: STREAM, startPos: INT, fromPos: INT _ -1] = { IF startPos = -1 THEN to.SetIndex[to.GetLength[]] ELSE to.SetIndex[startPos]; IF fromPos = -1 THEN from.SetIndex[0] ELSE from.SetIndex[fromPos]; StrmToStrmCopy[to, from]; }; CopyBytes: PUBLIC PROC[from, to: STREAM, num: INT] = { bytes: INT _ num; WHILE bytes >= 512 DO [] _ from.GetBlock[copyBuffer, 0, 512]; to.PutBlock[copyBuffer]; bytes _ bytes - 512; ENDLOOP; IF bytes # 0 THEN { [] _ from.GetBlock[copyBuffer, 0, bytes]; to.PutBlock[copyBuffer]; }; }; StrmToStrmCopy: PROC[to, from: STREAM] = { DO IF from.GetBlock[copyBuffer, 0, 512] = 0 THEN EXIT; to.PutBlock[copyBuffer]; ENDLOOP }; CheckForValidPrefix: PROC [strm: STREAM] RETURNS [startPos, length: INT] = { entryRope: ROPE = "*entry* "; lenRope, prefix: ROPE; startPos _ strm.GetIndex[]; prefix _ WalnutSendOps.RopeFromStream[strm, startPos, entryHeaderLen]; IF NOT prefix.Find[entryRope] = 0 THEN { strm.SetIndex[startPos]; RETURN[startPos, -1]; }; IF NOT prefix.Fetch[entryHeaderLen-1] = '\n THEN { strm.SetIndex[startPos]; RETURN[startPos, -1]; }; lenRope _ prefix.Substr[entryRope.Length[], 10]; length _ Convert.IntFromRope[lenRope ! Convert.Error => { length _ -1; strm.SetIndex[startPos]; CONTINUE }]; }; MsgEntryInfoFromStream: PUBLIC PROC[strm: STREAM, mle: MsgLogEntry] = { date: ROPE = "Date"; subject: ROPE = "Subject"; from: ROPE = "From"; sender: ROPE = "Sender"; to: ROPE = "To"; mh: WalnutParseMsg.MsgHeaders; savedFrom: ROPE; WantThisField: WalnutParseMsg.ParseProc = { SELECT TRUE FROM fieldName.Equal[date, FALSE] => RETURN[TRUE, TRUE]; fieldName.Equal[subject, FALSE] => RETURN[TRUE, TRUE]; fieldName.Equal[from, FALSE] => RETURN[TRUE, TRUE]; fieldName.Equal[sender, FALSE] => RETURN[TRUE, TRUE]; fieldName.Equal[to, FALSE] => RETURN[TRUE, TRUE]; ENDCASE => RETURN[FALSE, TRUE]; }; -- sigh, the joys of re-using the same MsgLogEntry; must clear all entries mle.date _ BasicTime.nullGMT; mle.subject _ NIL; mle.sender _ NIL; mle.to _ NIL; IF strm.PeekChar[] = '\n THEN [] _ strm.GetChar[]; -- formatting madness mh _ WalnutParseMsg.ParseMsgFromStream[strm, mle.textLen, WantThisField]; FOR mhL: WalnutParseMsg.MsgHeaders _ mh, mhL.rest UNTIL mhL=NIL DO fieldName: ROPE = mhL.first.fieldName; SELECT TRUE FROM fieldName.Equal[date, FALSE] => mle.date _ Convert.TimeFromRope[mhL.first.value ! Convert.Error => {mle.date _ BasicTime.Now[]; CONTINUE } ]; fieldName.Equal[subject, FALSE] => mle.subject _ mhL.first.value; fieldName.Equal[sender, FALSE] => { savedFrom _ mle.sender; mle.sender _ mhL.first.value; }; fieldName.Equal[to, FALSE] => mle.to _ mhL.first.value; fieldName.Equal[from, FALSE] => IF mle.sender = NIL THEN mle.sender _ mhL.first.value ELSE savedFrom _ mhL.first.value; ENDCASE => NULL; ENDLOOP; IF useFromFieldInTOC AND savedFrom # NIL THEN mle.sender _ savedFrom; }; ScanForHeadersLen: PROC[strm: STREAM, mle: MsgLogEntry] = { lastWasCR: BOOL _ FALSE; hLen: INT _ 0; WHILE hLen <= mle.textLen DO hLen _ hLen + 1; IF strm.GetChar[] = '\n THEN { IF lastWasCR THEN { mle.headersLen _ hLen; RETURN }; lastWasCR _ TRUE; } ELSE lastWasCR _ FALSE; ENDLOOP; mle.headersLen _ mle.textLen; -- not found but don't cause error }; ConstructMsgID: PUBLIC PROC[ts: GVBasics.Timestamp, gvSender: GVBasics.RName] RETURNS[msgID: ROPE] = { tr: ROPE _ WalnutSendOps.RFC822Date[BasicTime.FromPupTime[ts.time]]; IF gvSender.Fetch[0] = '" THEN { pos: INT = gvSender.Find["\"", 1]; IF pos # -1 THEN gvSender _ Rope.Concat[Rope.Substr[gvSender, 1, pos - 1], Rope.Substr[gvSender, pos+1]]; }; msgID _ IO.PutFR["%g $ %b#%b@%g", [rope[gvSender]], [integer[ts.net]], [integer[ts.host]], [rope[tr]]]; }; GetFileLength: PROC[strm: STREAM] RETURNS[INT] = { RETURN[strm.GetLength[]] }; SetVar: UserProfile.ProfileChangedProc = { useFromFieldInTOC _ UserProfile.Boolean[key: "Walnut.UseFromFieldInTOC", default: FALSE]; }; UserProfile.CallWhenProfileChanges[SetVar]; END. RWalnutStreamImpl.mesa Copyright c 1984 by Xerox Corporation. All rights reserved. Willie-Sue, May 9, 1986 3:22:43 pm PDT Types and procedures dealing with Walnut log streams Last Edited by: Wert, August 31, 1984 8:30:48 pm PDT Last Edited by: Willie-Sue, January 8, 1985 1:18:28 pm PST Last Edited by: Donahue, December 11, 1984 10:58:38 am PST (Changed NextEntryID to return the message id of any entry that pertains to a message) (Changing to use REF TEXT, do preallocation of log entry objects) (Set Buffer options as suggested by Hagmann: 4 buffers @ 4 pages/buffer) (Set Buffer options: 4 buffers @ 8 pages/buffer - getting too many aborts) (Set Buffer options back to: 4 buffers @ 4 pages/buffer) ( Take out all references to version numbers) Types Variables -- the following appear in the other log files Procedures Used for general opening of files -- Opening streams -- Miscellaneous stream operations Reading and writing log entries entry: the rope representation of the log entry write at the end of the stream unless given a pos (for fixing up CreateMsg headers) for debugging ʘšÏb™Jšœ Ïmœ1™Ÿœ˜E—JšœŸœ˜)JšœŸœ˜J˜Jš œ ŸœŸœŸœŸœ˜/J˜Jš œŸœŸœŸœŸœ˜+Jš œŸœŸœŸœŸœ˜+Jš œŸœŸœŸœŸœ˜,Jš œŸœŸœŸœŸœ˜,J™J™.Jšœ Ÿ œŸœ˜UJšœ Ÿ œŸœ˜Ošœ Ÿ œ˜4JšœŸœ˜"—šœŸœŸœ!˜J˜šœ˜šœ%˜%JšœC˜C—JšŸœ!˜'J˜—J˜JšŸœŸœ˜—J˜J˜—š  œŸœŸœŸœŸœŸœ Ÿœ Ÿœ˜\Jšœ Ÿœ˜JšŸœŸœŸœŸœ˜(J˜Jšœ/˜/JšŸœ ŸœŸœ¡˜6J˜Jšœ7˜7J˜šŸœŸ˜Jšœ+˜+Jšœ(˜(Jšœ+˜+Jšœ)˜)Jšœ,˜,Jšœ-˜-J˜JšŸœŸœ˜J˜—šŸ˜Jšœ¡˜.—JšŸœ˜Jšœ˜J˜J˜—š  œŸœŸœŸœŸœŸœ Ÿœ˜]J˜JšœŸœ˜ JšœŸœ˜J˜šŸœŸœŸœŸ˜!J˜˜šœŸœ#˜-JšŸœ˜JšŸœ˜JšŸœ˜Jšœ˜——J˜šœ˜šœŸœ$˜.JšŸœ˜JšŸœ˜JšŸœ˜Jšœ˜—Jšœ&˜&J˜—J˜Jšœ'˜'J˜šœ˜šœŸœ˜)JšŸœ˜J˜——J˜šœ˜šœŸœ˜&JšŸœ˜Jšœ˜——J˜˜šœŸœ˜%JšŸœ˜Jšœ˜—J˜—šœ˜šœŸœ˜'JšŸœ˜Jšœ˜——J˜šœ ˜ šœŸœ˜$JšŸœ˜JšŸœ ˜Jšœ˜——J˜šœ ˜ šœŸœ˜'JšŸœ˜JšŸœ˜Jšœ˜——J˜šœ ˜ šœŸœ˜)JšŸœ˜JšŸœ˜JšŸœ ˜Jšœ˜——J˜šœ˜šœŸœ˜%JšŸœ˜Jšœ˜——J˜šœ˜šœŸœ-˜7JšŸœ˜JšŸœ˜JšŸœ˜JšŸœ ˜Jšœ˜——J˜Jšœ1˜1J˜šœ˜šœŸœ"˜,JšŸœ˜J˜——J˜Jšœ+˜+J˜šœ˜šœŸœ(˜2JšŸœ˜JšŸœ˜Jšœ˜J˜——Jšœ5˜5J˜Jšœ9˜9J˜šœ˜šœŸœ&˜0JšŸœ˜J˜——J˜JšŸœŸœ˜J˜—J˜J™/J™SJ˜Jšœ Ÿœ ŸœŸœ˜6Jšœ˜Jšœ3¡˜BJ˜Jšœ ŸœŸœ¡!˜[J˜J˜J˜J˜—š  œŸ œŸœ&˜LJ˜J˜J˜J˜J™—š   œŸœŸœ Ÿœ Ÿœ Ÿœ ˜NJšŸœŸœŸœ˜MJšŸœŸœŸœ˜BJ˜J˜J˜—š  œŸ œ ŸœŸœ˜6JšœŸœ˜šŸœŸ˜Jšœ'˜'Jšœ˜J˜JšŸœ˜—šŸœ Ÿœ˜Jšœ)˜)Jšœ˜J˜—Jšœ˜J˜—š œŸœ Ÿœ˜*šŸ˜JšŸœ'ŸœŸœ˜3Jšœ˜JšŸ˜—J˜J˜—š  œŸœŸœŸœŸœ˜LJšœ Ÿœ˜JšœŸœ˜J˜Jšœ˜JšœF˜FJ˜šŸœŸœŸœ˜(Jšœ˜JšŸœ˜J˜—šŸœŸœ&Ÿœ˜2Jšœ˜JšŸœ˜J˜—Jšœ0˜0šœ9˜9Jšœ ˜ Jšœ˜JšŸœ˜ —J˜J˜—š œŸœŸœŸœ˜GJšœŸœ ˜Jšœ Ÿœ ˜JšœŸœ ˜JšœŸœ ˜JšœŸœ˜Jšœ˜Jšœ Ÿœ˜šœ+˜+šŸœŸœŸ˜Jš œŸœŸœŸœŸœ˜3Jš œŸœŸœŸœŸœ˜6Jš œŸœŸœŸœŸœ˜3Jš œŸœŸœŸœŸœ˜5Jš œŸœŸœŸœŸœ˜1JšŸœŸœŸœŸœ˜—J˜—J˜Jš¡J˜JJšœ˜JšœŸœ˜Jšœ Ÿœ˜Jšœ Ÿœ˜ J˜JšŸœŸœ¡˜JJšœI˜IšŸœ/ŸœŸœŸ˜BJšœ Ÿœ˜&šŸœŸœŸ˜šœŸœ7˜RJšœ.Ÿœ˜;—JšœŸœ#˜AšœŸœ˜#Jšœ˜Jšœ˜J˜—JšœŸœ˜7šœŸœ˜šŸœŸœŸœ˜5JšŸœ˜!——JšŸœŸœ˜—JšŸœ˜—JšŸœŸœ ŸœŸœ˜EJ˜—J˜š œŸœŸœ˜;Jšœ ŸœŸœ˜JšœŸœ˜šŸœŸ˜Jšœ˜šŸœŸœ˜JšŸœ ŸœŸœ˜4Jšœ Ÿœ˜J˜JšŸœ Ÿœ˜—JšŸœ˜—Jšœ¡"˜AJšœ˜—J˜š  œŸœŸœ3ŸœŸœ˜fJšœŸœ<˜DšŸœŸœ˜ JšœŸœ˜"šŸœ Ÿ˜šœ ˜ JšœN˜N—J˜——šœŸœ˜!JšœE˜E—J˜—J˜Jšœ ™ š   œŸœŸœŸœŸœ˜0JšœŸœ˜—J˜š œ$˜*šœ˜Jšœ>Ÿœ˜E—J˜—J˜J˜+J˜J˜JšŸœ˜—J˜—…—FÄb/