WalnutOpsMiscImpl.mesa
Copyright Ó 1984, 1987, 1988, 1992 by Xerox Corporation. All rights reserved.
Willie-Sue, June 29, 1988 4:54:23 pm PDT
Donahue, April 10, 1986 2:49:04 pm PST
Jack Kent, April 22, 1987 9:42:57 pm PDT
Doug Terry, August 30, 1990 8:25 am PDT
Includes what used to be WalnutSchemaImpl, plus other stuff
Willie-s, April 27, 1992 1:43 pm PDT
DIRECTORY
Atom USING [PutProp],
BasicTime USING [GMT, nullGMT, OutOfRange],
Convert USING [TimeFromRope],
IO,
LoganBerry,
LoganBerryEntry,
Rope USING [ROPE, Cat],
WalnutDefs USING [LogInfo, SchemaMismatch, WalnutOpsHandle],
WalnutOpsInternal USING [],
WalnutRoot USING [CommitAndContinue, RootHandle, RootHandleRec],
WalnutSchema;
WalnutOpsMiscImpl: CEDAR PROGRAM
IMPORTS
Atom, BasicTime, Convert, IO, LoganBerry, LoganBerryEntry, Rope,
WalnutDefs, WalnutRoot
EXPORTS
WalnutSchema, WalnutDefs
= BEGIN OPEN WalnutSchema;
Types
GMT: TYPE = BasicTime.GMT;
ROPE: TYPE = Rope.ROPE;
LogInfo: TYPE = WalnutDefs.LogInfo;
WalnutOpsHandle: TYPE = WalnutDefs.WalnutOpsHandle;
RootHandle: TYPE = WalnutRoot.RootHandle;
RootHandleRec: PUBLIC TYPE = WalnutRoot.RootHandleRec;
SchemaHandle: TYPE = WalnutSchema.SchemaHandle;
SchemaHandleRec: PUBLIC TYPE = WalnutSchema.SchemaHandleRec;
Signals and Errors
SchemaMismatch: PUBLIC SIGNAL[explanation: ROPE ¬ NIL] = CODE;
VersionMismatch: PUBLIC SIGNAL[explanation: ROPE ¬ NIL] = CODE;
Error: PUBLIC SIGNAL [who, code: ATOM, explanation: ROPE ¬ NIL] = CODE;
Variables
completeSchemaVersionDate: GMT = Convert.TimeFromRope["June 29, 1988 12:20:00 pm PDT"];
simpleSchemaVersionDate: GMT = Convert.TimeFromRope["June 29, 1988 4:54:19 pm PDT"];
schemaDateField: ATOM = $SchemaDate;
gSchemaDateInfoName: ROPE = "SchemaDInfo";
Schema procedures
Initialize: PUBLIC PROC [opsH: WalnutOpsHandle] RETURNS[ok: BOOL] = {
initializes the database schema, and commits it to the database.
sH: SchemaHandle;
schemaDate: BasicTime.GMT = ( IF opsH.completeSchema THEN completeSchemaVersionDate ELSE simpleSchemaVersionDate );
BEGIN
schemaRelship: LoganBerry.Entry ¬ LoganBerry.ReadEntry[db: opsH.db, key: $Key, value: gSchemaDateInfoName].entry;
IF schemaRelship = NIL THEN {
schemaRelship ¬ LIST[[$Key, gSchemaDateInfoName], [schemaDateField, LoganBerryEntry.T2V[schemaDate]]];
LoganBerry.WriteEntry[db: opsH.db, entry: schemaRelship];
}
ELSE {
date: BasicTime.GMT = LoganBerryEntry.V2T[LoganBerryEntry.GetAttr[schemaRelship, schemaDateField]];
IF date # schemaDate THEN
ERROR WalnutDefs.SchemaMismatch[TimesToRope[date, schemaDate]]
};
opsH.schemaHandle ¬ sH ¬ NEW[SchemaHandleRec];
END;
the following is needed for the rest of the initialization, for type info
Atom.PutProp[segment, $WalnutSchemaHandle, sH];
Atom.PutProp[$WalnutLB, $WalnutSchemaHandle, sH];
key values (or prefixes) for various types of entries and their associated attribute types
sH.gRootInfo ¬ "RootInfo";
sH.gRootFileStamp ¬ $RootFileStamp; -- rootFile create date for this db (gmt)
sH.gRootFileKey ¬ $RootFileKey; -- key from rootFile for this db (rope)
sH.gMailFor ¬ $MailFor;  -- RName (rope)
sH.gLogInfo ¬ "LogInfo";
sH.gLogFileID ¬ $LogFileID;       -- int
sH.gOpInProgressPos ¬ $OpInProgressPos;   -- int - long running operation Pos
sH.gFirstDestroyedMsgPos ¬ $FirstDestroyedMsgPos; -- int
sH.gBytesInDestroyedMsgs ¬ $BytesInDestroyedMsgs; -- int
sH.gTimeOfLastScavenge ¬ $TimeOfLastScavenge; -- gmt
sH.gParseLogInfo ¬ "ParseLogInfo";
sH.gParseLogInProgress ¬ $ParseLogInProgress; -- bool
sH.gParseLogPos ¬ $ParseLogPos;  -- int
sH.gExpungeInfo ¬ "ExpungeInfo";
sH.gLogExpungePhase ¬ $LogExpungePhase;   -- int
sH.gExpungeFileID ¬ $ExpungeFileID;     -- int
sH.gCurrentLogPos ¬ $CurrentLogPos;     -- int
sH.gExpungeLogPos ¬ $ExpungeLogPos;     -- int
sH.gTimeOfLastExpunge ¬ $TimeOfLastExpunge;  -- gmt
sH.gNewMailInfo ¬ "NewMailInfo";
sH.gNewMailLogLength ¬ $NewMailLogLength;  -- int
sH.gCopyNewMailLogPos ¬ $CopyNewMailLogPos;  -- int
sH.gAcceptNewMailLogPos ¬ $AcceptNewMailLogPos;  -- int
sH.gAddingServerMsgs ¬ $AddingServerMsgs;  -- bool
sH.gLastNewMailTimeStamp ¬ $LastNewMailTimeStamp; -- time
sH.gReadArchiveInfo ¬ "ReadArchiveInfo";
sH.gReadArchiveLogPos ¬ $ReadArchiveLogPos;  -- int
sH.gCopyReadArchiveLogPos ¬ $CopyReadArchiveLogPos; -- int
sH.gVersionInfo ¬ "VersionInfo";
sH.gMsgCount ¬ $MsgCount; -- int (number of msgs)
sH.gMsgSetCount ¬ $MsgSetCount; -- int (number of msgSets)
sH.gMsgSetsVersion ¬ $MsgSetsVersion; -- int (version number for msgSets)
sH.sBasicInfo ¬ "Server-"; -- One per Server
sH.sBIOf ¬ $ServerName;  -- Server
sH.sBINum ¬ $Num;  -- int (number of msgs)
sH.msBasicInfo ¬ "MsgSet-"; -- One per MsgSet
sH.msBIOf ¬ $PrintNameIs;   -- MsgSet
sH.msBICount ¬ $Count;   -- int (number of member msgs)
sH.msBIVersion ¬ $Version;  -- int
sH.msPrintNameIs ¬ $PrintNameIs; -- rope
sH.mMsgInfo ¬ "Msg-"; -- One per Msg
sH.mMIOf ¬ $MsgID;    -- Msg
sH.mMIHerald ¬ $Herald;   -- rope
sH.mMIShortNameLen ¬ $ShortNameLen;  -- int (for icon label, etc)
sH.mMIEntryStart ¬ $EntryStart;  -- int (start of entry in log)
sH.mMITextOffset ¬ $TextOffset;  -- int (offset for text)
sH.mMITextLen ¬ $TextLen;  -- int (length of text)
sH.mMIFormatLen ¬ $FormatLen;  -- int (length of formatting)
sH.mMIDate ¬ $Date;   -- time
sH.mMISubject ¬ $Subject;   -- Subject (truncated to 20 chars)
sH.mMISubjectText ¬ $SubjectText;  -- rope (up to 99 chars)
sH.mMIIsInReplyTo ¬ $IsInReplyTo;  -- bool
sH.mMISender ¬ $Sender;   -- Address (only one allowed)
sH.mDisplayInfo ¬ "MsgDisplay-"; -- One per Msg
sH.mDIOf ¬ $MsgID;    -- Msg
sH.mDITOCHeadEntry ¬ $TOCHeadEntry; -- rope
sH.mDIHasBeenRead ¬ $HasBeenRead;  -- bool
sH.mInfo ¬ "MsgShow-"; -- One per Msg
sH.mInfoOf ¬ $InfoOf;   -- Msg
sH.mDateIs ¬ $DateIs;  -- time
sH.mShowIs ¬ $ShowIs;  -- Unaccepted
sH.cdRelation ¬ "MsgCd-"; -- One per Msg
sH.cdMsg ¬ $Msg;   -- Msg
sH.cdMsgSet ¬ $MsgSet;   -- MsgSet (multiple allowed)
sH.cdDate ¬ $DateIs;   -- time (of the Msg)
sH.toRelation ¬ "MsgTo-"; -- One per Msg
sH.toMsg ¬ $Msg;   -- Msg
sH.toAddress ¬ $Address;   -- Address (multiple allowed)
sH.toDate ¬ $DateIs;   -- time (of the Msg)
sH.ccRelation ¬ "MsgCc-"; -- One per Msg
sH.ccMsg ¬ $Msg;   -- Msg
sH.ccAddress ¬ $Address;   -- Address (multiple allowed)
sH.ccDate ¬ $DateIs;   -- time (of the Msg)
sH.fromRelation ¬ "MsgFrom-"; -- One per Msg
sH.fromMsg ¬ $Msg;   -- Msg
sH.fromAddress ¬ $Address;  -- Address (multiple allowed)
sH.fromDate ¬ $DateIs;   -- time (of the Msg)
check for relships
BEGIN
gr: LoganBerry.Entry ¬ LoganBerry.ReadEntry[db: opsH.db, key: $Key, value: sH.gRootInfo].entry;
IF gr = NIL THEN {
init: LoganBerry.Entry ¬ LIST[
[$Key, sH.gRootInfo], [sH.gRootFileStamp, LoganBerryEntry.T2V[BasicTime.nullGMT]], [sH.gRootFileKey, NIL], [sH.gMailFor, NIL] ];
LoganBerry.WriteEntry[db: opsH.db, entry: init];
init ¬ LIST[ [$Key, sH.gLogInfo],
[sH.gLogFileID, LoganBerryEntry.I2V[0]], [sH.gOpInProgressPos, LoganBerryEntry.I2V[0]], [sH.gFirstDestroyedMsgPos, LoganBerryEntry.I2V[0]], [sH.gBytesInDestroyedMsgs, LoganBerryEntry.I2V[0]],
[sH.gTimeOfLastScavenge, LoganBerryEntry.T2V[BasicTime.nullGMT]] ];
LoganBerry.WriteEntry[db: opsH.db, entry: init];
init ¬ LIST[ [$Key, sH.gParseLogInfo], [sH.gParseLogInProgress, LoganBerryEntry.B2V[FALSE]], [sH.gParseLogPos, LoganBerryEntry.I2V[0]] ];
LoganBerry.WriteEntry[db: opsH.db, entry: init];
init ¬ LIST[ [$Key, sH.gExpungeInfo],
[sH.gLogExpungePhase, LoganBerryEntry.I2V[0]], [sH.gExpungeFileID, LoganBerryEntry.I2V[0]], [sH.gCurrentLogPos, LoganBerryEntry.I2V[0]], [sH.gExpungeLogPos, LoganBerryEntry.I2V[0]],
[sH.gTimeOfLastExpunge, LoganBerryEntry.T2V[BasicTime.nullGMT]]
];
LoganBerry.WriteEntry[db: opsH.db, entry: init];
init ¬ LIST[ [$Key, sH.gNewMailInfo],
[sH.gNewMailLogLength, LoganBerryEntry.I2V[0]], [sH.gCopyNewMailLogPos, LoganBerryEntry.I2V[0]], [sH.gAcceptNewMailLogPos, LoganBerryEntry.I2V[0]],
[sH.gAddingServerMsgs, LoganBerryEntry.B2V[FALSE]], [sH.gLastNewMailTimeStamp, LoganBerryEntry.T2V[BasicTime.nullGMT]]
];
LoganBerry.WriteEntry[db: opsH.db, entry: init];
init ¬ LIST[ [$Key, sH.gReadArchiveInfo], [sH.gReadArchiveLogPos, LoganBerryEntry.I2V[0]], [sH.gCopyReadArchiveLogPos, LoganBerryEntry.I2V[0]] ];
LoganBerry.WriteEntry[db: opsH.db, entry: init];
MsgCount: 0, MsgSetCount: 2, MsgSetsVersion: 1
init ¬ LIST[ [$Key, sH.gVersionInfo], [sH.gMsgCount, LoganBerryEntry.I2V[0]], [sH.gMsgSetCount, LoganBerryEntry.I2V[2]], [sH.gMsgSetsVersion, LoganBerryEntry.I2V[1]] ];
LoganBerry.WriteEntry[db: opsH.db, entry: init];
};
END;
Commit what we've done
WalnutRoot.CommitAndContinue[opsH];
RETURN[TRUE];
};
SetSchemaVersion: PUBLIC PROC[opsH: WalnutOpsHandle] = {
this doesn't commit, so it can be used by NewWalnutUser
schemaDate: BasicTime.GMT = ( IF opsH.completeSchema THEN completeSchemaVersionDate ELSE simpleSchemaVersionDate );
schemaRelship: LoganBerry.Entry ¬ LoganBerry.ReadEntry[db: opsH.db, key: $Key, value: gSchemaDateInfoName].entry;
IF schemaRelship # NIL
THEN {
LoganBerryEntry.SetAttr[schemaRelship, schemaDateField, LoganBerryEntry.T2V[schemaDate]];
LoganBerry.WriteEntry[db: opsH.db, entry: schemaRelship, replace: TRUE];
}
ELSE {
schemaRelship ¬ LIST[[$Key, gSchemaDateInfoName], [schemaDateField, LoganBerryEntry.T2V[schemaDate]]];
LoganBerry.WriteEntry[db: opsH.db, entry: schemaRelship];
};
WalnutRoot.CommitAndContinue[];
};
GetSchemaVersion: PUBLIC PROC[opsH: WalnutOpsHandle]
RETURNS[actual, shouldBe: BasicTime.GMT] = {
to be used by NewWalnutUser
schemaRelship: LoganBerry.Entry ¬ LoganBerry.ReadEntry[db: opsH.db, key: $Key, value: gSchemaDateInfoName].entry;
shouldBe ¬ ( IF opsH.completeSchema THEN completeSchemaVersionDate ELSE simpleSchemaVersionDate );
actual ¬ IF schemaRelship # NIL THEN
LoganBerryEntry.V2T[LoganBerryEntry.GetAttr[schemaRelship, schemaDateField]] ELSE BasicTime.nullGMT;
};
TimesToRope: PROC[is, shouldBe: BasicTime.GMT] RETURNS[ROPE] = {
isR, shouldR: ROPE;
isR ¬ IO.PutFR1[NIL, [time[is]]
! BasicTime.OutOfRange => {
isR ¬ IF is = BasicTime.nullGMT THEN "nullGMT" ELSE "OutOfRange";
CONTINUE }];
shouldR ¬ IO.PutFR1[NIL, [time[shouldBe]]
! BasicTime.OutOfRange => {
shouldR ¬ IF shouldBe = BasicTime.nullGMT THEN "nullGMT" ELSE "OutOfRange";
CONTINUE }];
RETURN[Rope.Cat["\nSchema is of: ", isR, " but should be of: ", shouldR]];
};
END.