-- File: WalnutWindowImpl.mesa
-- Contents: Top level Viewer for Walnut; initializes database & displays control window
-- Last Edited by: Willie-Sue, December 13, 1982 9:16 am
-- created February, 1981 by Willie-Sue & Rick
-- Last edit by:
-- Willie-Sue on: June 8, 1983 3:25 pm
DIRECTORY
Atom USING [GetPName],
Buttons USING [ButtonProc],
CedarSnapshot USING [Register, CheckpointProc, RollbackProc],
CIFS USING [Error],
Commander USING [CommandProc, Register],
CommandTool USING [DoCommand],
Containers,
DB,
DBEnvironment USING [PilotTransRecord],
DBFileAlpine USING [CreateTransaction],
Labels,
FileIO,
GVRetrieve USING [MBXState],
Icons USING [IconFlavor, NewIconFromFile],
IO,
MBQueue USING [Action, Create, DequeueAction, Flush, QueueClientAction],
Menus USING [AppendMenuEntry, CreateEntry, CreateMenu, Menu, MenuProc],
MessageWindow USING [Append],
Process USING [Detach],
Rope,
Rules USING [Create],
Runtime USING [IsBound],
Transaction USING [nullHandle],
UserCredentials USING [GetUserCredentials],
UserProfile USING[Boolean, CallWhenProfileChanges, ProfileChangedProc, Token],
ViewerEvents USING [EventProc, EventRegistration, RegisterEventProc, UnRegisterEventProc],
ViewerOps,
ViewerSpecs USING[openLeftWidth, openRightTopY, openRightWidth],
ViewerTools USING [SetSelection],
ViewerIO USING [CreateViewerStreams, GetViewerFromStream],
WalnutDB,
WalnutDBLog,
WalnutDisplayerOps,
WalnutLog,
WalnutRetrieve,
WalnutSendMail,
WalnutStream,
WalnutViewer,
WalnutWindow;
WalnutWindowImpl: CEDAR MONITOR
IMPORTS
DB, DBFileAlpine,
Atom, Commander, CommandTool,
Containers, Icons, Labels, MBQueue, Menus, MessageWindow, Rules,
CedarSnapshot, CIFS, IO, Process, Rope, Runtime, Transaction,
UserCredentials, UserProfile,
ViewerEvents, ViewerOps, ViewerTools, ViewerIO, ViewerSpecs,
WalnutDB, WalnutDBLog, WalnutDisplayerOps, WalnutLog, WalnutRetrieve,
WalnutSendMail, WalnutViewer, WalnutWindow
EXPORTS WalnutWindow
SHARES WalnutWindow =
BEGIN OPEN IO, WalnutDB, WalnutWindow;
-- Walnut Viewers types and global data
ROPE: TYPE = Rope.ROPE;
InitialNotifyLabel: ROPE = "Waiting for Grapevine response... ";
walnutVersion: ROPE← "Walnut 4.2";
walnut: PUBLIC Viewer← NIL;
wtsOut: IO.STREAM← NIL;
walnutIcon: PUBLIC Icons.IconFlavor← tool;
newMailIcon: PUBLIC Icons.IconFlavor← tool;
msgSetIcon: PUBLIC Icons.IconFlavor← tool;
msgIcon: PUBLIC Icons.IconFlavor← tool;
iconFilePathName: PUBLIC ROPE← NIL;
alpineNeeded: BOOL← FALSE;
walnutEventReg: ViewerEvents.EventRegistration← NIL;
mustQuitWalnut: ROPE← NIL;
previousUser: ROPE← NIL;
doingCheckpoint: BOOL← FALSE;
rollbackFinished: CONDITION;
initialActiveIconic: PUBLIC BOOL← FALSE;
initialActiveRight: PUBLIC BOOL← TRUE;
initialActiveOpen: PUBLIC BOOL← TRUE;
msgSetBorders: PUBLIC BOOL← FALSE;
enableTailRewrite: PUBLIC BOOL← FALSE;
walnutRulerBefore, walnutRulerAfter, walnutTS: PUBLIC Viewer;
msgSetText: PUBLIC Viewer; -- the text argument for Create/Delete MsgSet
fileNameText: PUBLIC Viewer; -- fileName for Archiving
mailNotifyLabel: PUBLIC Viewer; -- is there new mail or not
walnutSegmentFile: PUBLIC ROPE;
walnutLogName: PUBLIC ROPE;
logFileIsPilotFile: PUBLIC BOOL← TRUE;
walnutQueue: PUBLIC Queue;
walnutNullTrans: PUBLIC DB.Transaction;
responseSynch: CONDITION;
userHasResponded, userConfirmed: BOOL← FALSE;
-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
BuildWalnut: PUBLIC ENTRY Commander.CommandProc =
BEGIN ENABLE UNWIND => NULL;
IF walnut # NIL THEN
{ IF doingCheckpoint THEN WAIT rollbackFinished;
Report["\nWalnut already running"]; RETURN
};
IF Rope.Length[UserCredentials.GetUserCredentials[].name] = 0 THEN
{ IF cmd # NIL THEN cmd.out.PutRope["Please Login"]; RETURN};
IF ~BuildWalnutControlWindow[] THEN RETURN;
IF ~StartOrRestartWalnut[TRUE] THEN RETURN;
Report["\n", walnutVersion];
MBQueue.Flush[walnutQueue]; -- for good measure
TRUSTED { Process.Detach[FORK WalnutNotifier[]] };
END;
BuildWalnutControlWindow: INTERNAL PROC RETURNS[ok: BOOL] =
BEGIN
bt: Viewer;
walnutWidth: INTEGER;
transOK: BOOL← TRUE;
IF iconFilePathName=NIL THEN iconFilePathName← "Walnut.icons"; -- try local one first
IF walnutIcon = tool THEN
BEGIN ENABLE CIFS.Error => GOTO notFound;
walnutIcon← Icons.NewIconFromFile[iconFilePathName, 0];
EXITS
notFound =>
BEGIN ENABLE CIFS.Error => { iconFilePathName← NIL; CONTINUE};
iconFilePathName← "/Indigo/Cedar/Walnut/Walnut.icons";
walnutIcon ← Icons.NewIconFromFile[iconFilePathName, 0];
END;
END;
IF iconFilePathName#NIL THEN SetWalnutIcons[iconFilePathName];
newMailIcon← Icons.NewIconFromFile[iconFilePathName, 5];
walnut← ViewerOps.CreateViewer[
flavor: $Container,
info: [name: "Walnut", iconic: FALSE, column: right, scrollable: FALSE,
icon: walnutIcon, openHeight: ViewerSpecs.openRightTopY/4]];
walnut.inhibitDestroy← TRUE;
walnutWidth← IF walnut.column = right THEN ViewerSpecs.openRightWidth ELSE
ViewerSpecs.openLeftWidth;
ViewerOps.SetMenu[walnut, blankMenu];
mailNotifyLabel← WalnutViewer.FirstLabel[name: InitialNotifyLabel, parent: walnut];
bt← WalnutViewer.ImmediateButton[name: "Archive", proc: ArchiveButtonProc,
border: TRUE, sib: mailNotifyLabel, fork: FALSE, newLine: TRUE];
bt← WalnutViewer.ImmediateButton
[name: "on File:", proc: FileNameProc, border: FALSE, sib: bt];
fileNameText← WalnutViewer.NextRightTextViewer[sib: bt, w: walnutWidth];
Containers.ChildXBound[walnut, fileNameText];
bt← WalnutViewer.ImmediateButton[name: "Create", proc: CreateMsgSetButtonProc,
border: TRUE, sib: bt, fork: FALSE, newLine: TRUE];
bt← WalnutViewer.ImmediateButton[name: "Delete", proc: DeleteMsgSetButtonProc,
border: TRUE, sib: bt, fork: FALSE];
bt← WalnutViewer.ImmediateButton[name: "SizeOf", proc: SizeOfMsgSetButtonProc,
border: TRUE, sib: bt, fork: FALSE];
bt← WalnutViewer.ImmediateButton[
name: "MsgSet:", proc: MsgSetNameProc, border: FALSE, sib: bt];
msgSetText← WalnutViewer.NextRightTextViewer[sib: bt, w: walnutWidth];
Containers.ChildXBound[walnut, msgSetText];
bt← walnutRulerBefore← WalnutViewer.MakeRuler[sib: bt, h: 2];
walnutRulerAfter← Rules.Create[
info: [parent: walnut, wy: bt.wy+bt.wh+14+2, ww: walnutWidth, wh: 2]];
Containers.ChildXBound[walnut, walnutRulerAfter];
walnutTS← WalnutViewer.MakeTypescript[sib: walnutRulerAfter];
wtsOut← ViewerIO.CreateViewerStreams[NIL, walnutTS].out;
TRUSTED
BEGIN
DO
IF ~Runtime.IsBound[WalnutSendMail.RegisterReporter] THEN
{IF ~ContinueThisWalnut["WalnutSend"] THEN RETURN[FALSE] ELSE LOOP};
IF alpineNeeded AND ~Runtime.IsBound[DBFileAlpine.CreateTransaction] THEN
{IF ~ContinueThisWalnut["AlpineUserImpls"] THEN RETURN[FALSE] ELSE LOOP};
IF ~Runtime.IsBound[DB.DeclareSegment] THEN
{IF ~ContinueThisWalnut["Cypress"] THEN RETURN[FALSE] ELSE LOOP};
EXIT;
ENDLOOP;
END;
ViewerOps.SetMenu[walnut, workingMenu];
walnutEventReg←
ViewerEvents.RegisterEventProc[proc: QuitProc, event: destroy, filter: walnut];
WalnutDB.RegisterUpdatesPendingProc[SetWalnutUpdatesPending];
WalnutSendMail.RegisterReporter[wtsOut];
DB.Initialize[nCachePages: 256];
RETURN[TRUE];
END;
ContinueThisWalnut: INTERNAL PROC[who: ROPE] RETURNS[reTry: BOOL]=
BEGIN
v: Viewer;
err: ROPE;
Report[IO.PutFR["Loading and starting %g", IO.rope[who]]];
err← CommandTool.DoCommand["Run", who].err;
IF err.Length[] = 0 THEN RETURN[TRUE];
Report[err];
IF err.Find["There are unbound imports", 0, FALSE] >= 0 THEN RETURN[TRUE];
Report["Click Continue to push on anyway, Quit to quit out of Walnut"];
IF InternalConfirm[startupConfirmMenu] THEN RETURN[TRUE];
msgSetText← mailNotifyLabel← NIL;
v← walnut;
walnut← NIL;
wtsOut.Close[];
wtsOut← NIL;
ViewerOps.DestroyViewer[v];
RETURN[FALSE]
END;
RestartWalnut: PUBLIC ENTRY PROC =
BEGIN ENABLE UNWIND => NULL;
BEGIN
IF DB.TransactionOf[$Walnut]#NIL THEN
WalnutLog.CloseWalnutTransaction[ ! DB.Aborted => GOTO dbAborted];
EXITS
dbAborted => DB.AbortTransaction[DB.TransactionOf[$Walnut]];
END;
IF ~StartOrRestartWalnut[FALSE] THEN RETURN;
Report["Restart finished"];
END;
StartOrRestartWalnut: INTERNAL PROC[firstTime: BOOL← FALSE] RETURNS[BOOL] =
BEGIN OPEN WalnutLog, WalnutDBLog;
ENABLE
BEGIN
UNWIND => GOTO mustQuit;
DB.Failure =>
{ Report["Failure: what: ", Atom.GetPName[what], "; info: ", info]; GOTO mustQuit};
END;
transOK: BOOL← TRUE;
curVersion: GreenwichMeanTime;
curLength, expectedLength: INT;
DB.DeclareSegment[filePath: walnutSegmentFile, segment: $Walnut];
OpenWalnutTransaction[NIL, FALSE ! -- does InitializeDBVars
DB.InternalError => transOK← FALSE;
WalnutDBLog.SchemaMismatch => {curVersion← schemaVersion; transOK← FALSE}
];
IF ~transOK THEN
{ Report[
PutFR["Database schema is of %g, but Walnut wants it to be %g\nYou Must Scavenge",
time[curVersion], time[WalnutDBLog.SchemaVersionTime]]];
Report["Click Confirm to Scavenge, Deny to quit"];
IF ~InternalConfirm[] THEN { CloseDownWalnut[]; RETURN[FALSE]};
DoScavenge[startPos: 0, internal: TRUE];
};
curLength← InitializeLog[walnutLogName];
IF GetCopyInProgress[] THEN
{ ReportRope[" Recovering from interrupted Expunge ..."];
WalnutLog.FinishExpunge[];
Report[" done"];
};
expectedLength← GetExpectedLogLength[];
IF curLength < expectedLength THEN
{ Report["Log length is less than expected; you Must Scavenge"];
Report["Click Confirm to Scavenge, Deny to quit"];
IF ~InternalConfirm[] THEN { CloseDownWalnut[]; RETURN[FALSE]};
DoScavenge[startPos: 0, internal: TRUE]
};
WalnutRetrieve.OpenConnection[WalnutSendMail.userRName];
ChangeWalnutMenu[workingMenu];
IF (expectedLength← GetExpectedDBLogPos[]) # curLength THEN
{ ReportRope["Updating database from log file ..."];
IF expectedLength = 0 THEN DoScavenge[startPos: 0, internal: TRUE]
ELSE
{ []← WalnutLog.UpdateFromLog[expectedLength];
WalnutLog.MarkWalnutTransaction[]; -- commit what's been read
};
};
ShowMsgSetButtons[];
IF ~walnut.iconic THEN ViewerOps.PaintViewer[walnut, client];
-- check how much space is left (if any) in the control window for a typescript)
IF firstTime THEN
{ dif: INTEGER;
wH: INTEGER← walnut.ch;
IF (dif← (wH-walnutRulerAfter.cy)) < 64 THEN
{ ViewerOps.SetOpenHeight[walnut, wH + (64-dif)];
IF ~walnut.iconic THEN ViewerOps.ComputeColumn[walnut.column]
};
};
FixUpWalnutViewers[];
IF firstTime AND initialActiveOpen THEN []← DisplayMsgSet[activeMsgSet];
ChangeWalnutMenu[walnutMenu];
doingCheckpoint← FALSE;
BROADCAST rollbackFinished;
walnut.inhibitDestroy← FALSE;
RETURN[TRUE];
EXITS
mustQuit =>
{ Report["Aborting start or restart; click quit when ready"];
[]← InternalConfirm[forceQuitMenu];
CloseDownWalnut[];
RETURN[FALSE]
};
END;
FixUpWalnutViewers: PROC =
BEGIN
msgSetList, msgList: LIST OF Viewer;
v: Viewer;
fullName: ROPE;
[msgSetList, msgList]← EnumWalnutViewers[TRUE];
FOR vL: LIST OF Viewer← msgSetList, vL.rest UNTIL vL=NIL DO
fullName← NARROW[ViewerOps.FetchProp[v← vL.first, $Entity]];
WalnutDisplayerOps.FixUpMsgSetViewer[fullName.Substr[14], v];
ENDLOOP;
FOR vL: LIST OF Viewer← msgList, vL.rest UNTIL vL=NIL DO
fullName← NARROW[ViewerOps.FetchProp[v← vL.first, $Entity]];
WalnutDisplayerOps.FixUpMsgViewer[fullName.Substr[11], v];
ENDLOOP;
END;
-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
WalnutNotifier: PROC =
BEGIN OPEN MBQueue;
DO
BEGIN ENABLE
BEGIN
ABORTED => {Flush[walnutQueue]; LOOP};
DB.Aborted => GOTO dbAborted;
END;
action: Action← DequeueAction[walnutQueue];
WITH action SELECT FROM
e1: Action.user =>
e1.proc[e1.parent, e1.clientData, e1.mouseButton, e1.shift, e1.control];
e2: Action.client =>
{ IF e2.proc = ClosingWalnut THEN {Flush[walnutQueue]; RETURN};
e2.proc[e2.data];
};
ENDCASE => ERROR;
EXITS
dbAborted =>
{ Flush[walnutQueue];
DB.AbortTransaction[DB.TransactionOf[$Walnut]];
Report["\nDatabase transaction was aborted ... Restarting ..."];
RestartWalnut[];
};
END;
ENDLOOP;
END;
-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
QueueExecCall: PUBLIC ENTRY PROC[proc: PROC[REF ANY], ra: REF ANY] =
BEGIN ENABLE UNWIND => NULL;
IF walnut # NIL THEN IF doingCheckpoint THEN WAIT rollbackFinished;
MBQueue.QueueClientAction[walnutQueue, proc, ra];
END;
-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
SetWalnutIcons: PROC[file: ROPE] =
BEGIN
newMailIcon← Icons.NewIconFromFile[file, 5];
msgSetIcon← Icons.NewIconFromFile[file, 1];
msgIcon← Icons.NewIconFromFile[file, 2];
END;
EstablishFileNames: PROC =
BEGIN
sName: ROPE← walnutSegmentFile;
lName: ROPE;
SELECT sName.Fetch[0] FROM
'< => {sName← Rope.Concat["[Luther.Alpine]", sName]; alpineNeeded← TRUE};
'[ => IF sName.Find["Local", 0, FALSE] < 0 THEN alpineNeeded← TRUE;
ENDCASE => sName← Rope.Concat["[Local]", sName];
-- check for extension
IF Rope.Find[sName, "."] > 0 THEN walnutSegmentFile← sName -- has extension
ELSE walnutSegmentFile← Rope.Concat[sName, ".Segment"];
IF ~alpineNeeded THEN
{ walnutNullTrans← NEW[DBEnvironment.PilotTransRecord← [trans: Transaction.nullHandle]];
lName← walnutSegmentFile.Substr[7, walnutSegmentFile.Find[".", 8]-7];
}
ELSE
{ sPos: INT← walnutSegmentFile.Find[">"]+1;
lName← walnutSegmentFile.Substr[0, walnutSegmentFile.Find[".", sPos]];
walnutNullTrans← NIL;
};
IF walnutLogName.Length[]=0 THEN walnutLogName← lName.Concat[".DBLog"]
ELSE IF walnutLogName.Find["."] < 0 THEN
walnutLogName← walnutLogName.Concat[".DBLog"];
logFileIsPilotFile← (walnutLogName.Fetch[0] # '[ );
alpineNeeded← alpineNeeded OR ~logFileIsPilotFile;
END;
-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
ChangeWalnutMenu: PUBLIC PROC[menu: Menus.Menu] =
BEGIN
walnut.menu← menu;
ViewerOps.PaintViewer[walnut, menu];
END;
UserConfirmed: PUBLIC ENTRY PROC RETURNS[BOOL] =
BEGIN ENABLE UNWIND => NULL;
RETURN[InternalConfirm[confirmMenu]];
END;
InternalConfirm: INTERNAL PROC[m: Menus.Menu← NIL] RETURNS[BOOL] =
BEGIN
ChangeWalnutMenu[IF m = NIL THEN confirmMenu ELSE m];
IF walnut.iconic THEN ViewerOps.BlinkIcon[walnut, 0] ELSE ViewerOps.BlinkIcon[walnutTS];
UNTIL userHasResponded DO WAIT responseSynch; ENDLOOP;
userHasResponded← FALSE;
ChangeWalnutMenu[workingMenu];
RETURN[userConfirmed];
END;
---------------------------
walnutMenu: PUBLIC Menus.Menu← Menus.CreateMenu[];
workingMenu: PUBLIC Menus.Menu← Menus.CreateMenu[];
confirmMenu: Menus.Menu← Menus.CreateMenu[];
blankMenu: Menus.Menu← Menus.CreateMenu[];
startupConfirmMenu: Menus.Menu← Menus.CreateMenu[];
forceQuitMenu: Menus.Menu← Menus.CreateMenu[];
BuildWalnutMenu: PROC =
{ OPEN Menus;
AppendMenuEntry[walnutMenu, CreateEntry["NewForm", NewMsgProc]];
AppendMenuEntry[walnutMenu,
WalnutViewer.CreateMenuEntry[walnutQueue, "NewMail", NewMailProc]];
AppendMenuEntry[walnutMenu,
WalnutViewer.CreateMenuEntry[walnutQueue, "Commit", MyCommitProc]];
AppendMenuEntry[walnutMenu,
WalnutViewer.CreateMenuEntry[q: walnutQueue, name: "Expunge", proc: MenuExpunge,
guarded: TRUE]];
AppendMenuEntry[walnutMenu,
WalnutViewer.CreateMenuEntry[walnutQueue, "CloseAll", CloseAllProc]];
AppendMenuEntry[workingMenu, CreateEntry["NewForm", NewMsgProc]];
AppendMenuEntry[confirmMenu, CreateEntry["NewForm", NewMsgProc]];
AppendMenuEntry[confirmMenu, CreateEntry["Confirm", WWConfirmProc]];
AppendMenuEntry[confirmMenu, CreateEntry["Deny", WWDenyProc]];
AppendMenuEntry[startupConfirmMenu, CreateEntry["Continue", WWConfirmProc]];
AppendMenuEntry[startupConfirmMenu, CreateEntry["Quit", WWDenyProc]];
AppendMenuEntry[forceQuitMenu, CreateEntry["Quit", WWConfirmProc]];
};
NewMsgProc: Menus.MenuProc = { WalnutSendMail.WalnutSendProc[fromExec: FALSE]};
-- Create a new blank form in a viewer for user to send msg with.
MenuExpunge: Menus.MenuProc =
{ DoExpunge[doUpdates: TRUE, tailRewrite: mouseButton=red]};
MyCommitProc: Menus.MenuProc =
{ ChangeWalnutMenu[workingMenu];
WalnutLog.MarkWalnutTransaction[];
ChangeWalnutMenu[walnutMenu]
};
NewMailProc: Menus.MenuProc =
{ ChangeWalnutMenu[workingMenu];
RetrieveNewMail[];
ChangeWalnutMenu[walnutMenu]
};
RetrieveNewMail: PUBLIC ENTRY PROC =
BEGIN ENABLE UNWIND => NULL;
thisUser: ROPE;
IF doingCheckpoint THEN WAIT rollbackFinished;
thisUser← UserCredentials.GetUserCredentials[].name;
IF ~Rope.Equal[thisUser, previousUser, FALSE] THEN
{ r: ROPE← "User has changed";
Report[IO.PutFR
["******%g may not retrieve %g's new mail", IO.rope[thisUser], IO.rope[previousUser]]];
Report["You will be forced to quit out of Walnut; you should then Login to the exec"];
MBQueue.Flush[walnutQueue];
MBQueue.QueueClientAction[walnutQueue, QuitWalnut, r];
}
ELSE DoNewMail[];
END;
CloseAllProc: Menus.MenuProc =
BEGIN
msgSetList, msgList: LIST OF Viewer;
[msgSetList, msgList]← EnumWalnutViewers[TRUE];
FOR vL: LIST OF Viewer← msgList, vL.rest UNTIL vL=NIL DO
ViewerOps.DestroyViewer[vL.first]; ENDLOOP;
FOR vL: LIST OF Viewer← msgSetList, vL.rest UNTIL vL=NIL DO
ViewerOps.CloseViewer[vL.first]; ENDLOOP;
MyCommitProc[parent];
ViewerOps.CloseViewer[walnut];
END;
QuitProc: ViewerEvents.EventProc =
BEGIN
IF walnutEventReg = NIL THEN RETURN[FALSE];
TRUSTED {Process.Detach[ FORK QuitWalnut[NIL]]};
RETURN[TRUE];
END;
QuitWalnut: ENTRY PROC[ra: REF ANY ] =
BEGIN ENABLE UNWIND => NULL;
IF ra # NIL THEN
{ msg: ROPE← NARROW[ra];
IF walnut = NIL THEN RETURN; -- something funny
walnut.inhibitDestroy← TRUE;
TakeDownWalnutViewers[]; -- make the user notice
ViewerOps.BlinkIcon[walnut, IF walnut.iconic THEN 0 ELSE 1];
Report["**********", msg];
Report["You MUST quit out of Walnut; Click Quit when ready"];
[]← InternalConfirm[forceQuitMenu];
};
CloseDownWalnut[]
END;
WWDenyProc: ENTRY Menus.MenuProc =
{ ENABLE UNWIND => NULL;
userConfirmed← FALSE;
userHasResponded← TRUE;
BROADCAST responseSynch
};
WWConfirmProc: ENTRY Menus.MenuProc =
{ ENABLE UNWIND => NULL;
userConfirmed← TRUE;
userHasResponded← TRUE;
BROADCAST responseSynch
};
----------------------------
MsgSetNameProc: Buttons.ButtonProc =
BEGIN
ViewerTools.SetSelection[msgSetText, NIL];
END;
FileNameProc: Buttons.ButtonProc =
BEGIN
ViewerTools.SetSelection[fileNameText, NIL];
END;
CloseDownWalnut: INTERNAL PROC[doCommit: BOOL← TRUE] =
-- clean up after Walnut
BEGIN ENABLE UNWIND => CONTINUE;
v: Viewer← walnut;
walnut.inhibitDestroy← TRUE;
MBQueue.Flush[walnutQueue];
IF walnutEventReg # NIL THEN
ViewerEvents.UnRegisterEventProc[walnutEventReg, destroy];
walnutEventReg← NIL;
ChangeWalnutMenu[workingMenu];
ReportRope["Saving log ..."];
[]← WalnutLog.LogLength[doFlush: TRUE];
WalnutDB.UnRegisterUpdatesPendingProc[SetWalnutUpdatesPending];
selectedMsgSetButtons← firstMsgSetButton← lastMsgSetButton← NIL;
TakeDownWalnutViewers[];
BEGIN
IF DB.TransactionOf[$Walnut]#NIL THEN
{ IF doCommit THEN WalnutLog.CloseWalnutTransaction[ ! DB.Aborted => GOTO dbAborted]
ELSE DB.AbortTransaction[DB.TransactionOf[$Walnut]]
};
EXITS
dbAborted => DB.AbortTransaction[DB.TransactionOf[$Walnut]];
END;
WalnutLog.CloseLogStream[];
walnut← NIL; -- don't let others try to use Report
WalnutRetrieve.CloseConnection[]; -- NOP if no open connection
lastStateReported← unknown;
msgSetText← mailNotifyLabel← NIL;
WalnutSendMail.UnregisterReporter[wtsOut];
wtsOut.Close[];
wtsOut← NIL;
mustQuitWalnut← NIL;
MBQueue.QueueClientAction[walnutQueue, ClosingWalnut, NIL];
v.inhibitDestroy← FALSE;
doingCheckpoint← FALSE;
ViewerOps.DestroyViewer[v];
END;
ClosingWalnut: PROC[ra: REF ANY] = {NULL};
EnumWalnutViewers: PROC[keepSeparate: BOOL]
RETURNS [msgSetList, msgList: LIST OF Viewer] =
BEGIN
Enum: ViewerOps.EnumProc =
BEGIN
ra: REF ANY; fullName: ROPE;
IF (ra← ViewerOps.FetchProp[v, $Entity]) = NIL THEN RETURN[TRUE];
fullName← NARROW[ra];
IF fullName.Find["Walnut!"] # 0 THEN RETURN[TRUE];
IF ~keepSeparate THEN msgSetList← CONS[v, msgSetList]
ELSE
{ IF fullName.Find["!MsgSet!", 6] = 6 THEN msgSetList← CONS[v, msgSetList]
ELSE msgList← CONS[v, msgList];
};
RETURN[TRUE];
END;
ViewerOps.EnumerateViewers[Enum]
END;
TakeDownWalnutViewers: PUBLIC PROC =
BEGIN
FOR vL: LIST OF Viewer← EnumWalnutViewers[FALSE].msgSetList, vL.rest UNTIL vL=NIL DO
ViewerOps.DestroyViewer[vL.first];
ENDLOOP;
END;
-- **********************************************************************
SetWalnutUpdatesPending: PUBLIC PROC[newVersion: BOOL] =
BEGIN
old: BOOL;
IF walnut = NIL OR walnut.destroyed THEN RETURN;
old← walnut.newVersion;
IF newVersion#old THEN
{walnut.newVersion← newVersion; ViewerOps.PaintViewer[walnut, caption]};
END;
UncomittedUpdates: PUBLIC ENTRY PROC RETURNS[updatesPending: BOOL] =
{ ENABLE UNWIND => NULL; RETURN[walnut.newVersion]};
-- **********************************************************************
Report: PUBLIC PROC[msg1, msg2, msg3, msg4: ROPE← NIL] =
{ IF wtsOut = NIL THEN
{ IF msg1#NIL THEN MessageWindow.Append[msg1];
IF msg2#NIL THEN MessageWindow.Append[msg2];
IF msg3#NIL THEN MessageWindow.Append[msg3];
IF msg4#NIL THEN MessageWindow.Append[msg4];
RETURN
};
IF msg1#NIL THEN wtsOut.PutRope[msg1];
IF msg2#NIL THEN wtsOut.PutRope[msg2];
IF msg3#NIL THEN wtsOut.PutRope[msg3];
IF msg4#NIL THEN wtsOut.PutRope[msg4];
wtsOut.PutChar[CR];
};
ReportRope: PUBLIC PROC[msg1: ROPE] =
{ IF wtsOut # NIL THEN wtsOut.PutRope[msg1] ELSE MessageWindow.Append[msg1];
};
-- **********************************************************************
-- ***** typescript log file when Walnut Control Window not up
SetUpTSLog: PUBLIC ENTRY PROC[who: ROPE] =
{ ENABLE UNWIND => NULL;
v: Viewer;
wtsOut← ViewerIO.CreateViewerStreams[
name: "WalnutTS", backingFile: "Walnut.TypescriptLog"].out;
v← ViewerIO.GetViewerFromStream[wtsOut];
v.inhibitDestroy← TRUE;
wtsOut.PutRope["Writing Walnut typescript info to Walnut.TypescriptLog"];
wtsOut.PutRope[IO.PutFR["\n******Call to %g at %g\n", rope[who], time[]]];
};
CloseTSLog: PUBLIC ENTRY PROC =
{ ENABLE UNWIND => NULL;
v: Viewer← ViewerIO.GetViewerFromStream[wtsOut];
wtsOut.Close[];
wtsOut← NIL;
v.inhibitDestroy← FALSE;
ViewerOps.DestroyViewer[v];
};
-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
lastStateReported: GVRetrieve.MBXState← unknown;
WatchMailBox: PUBLIC PROC[newState: GVRetrieve.MBXState] =
-- This is called when the condition of the mailbox changes
BEGIN
showTime: BOOL← TRUE;
status: ROPE;
icon: Icons.IconFlavor← walnutIcon;
IF walnut = NIL THEN RETURN;
IF walnut.destroyed THEN RETURN;
IF newState = unknown THEN RETURN;
IF (lastStateReported = notEmpty) AND (newState = someEmpty OR newState = allEmpty) THEN
status← "New mail was read"
ELSE
{ SELECT newState FROM
badName => {status← "Your user name is invalid, please log in"; showTime← FALSE};
badPwd => {status← "Your password is invalid"; showTime← FALSE};
cantAuth => {status← "Can't check your credentials at this time"; showTime← FALSE};
userOK => {status← "Your credentials are OK"; showTime← FALSE};
allDown => status← "All of the mail servers are down";
someEmpty => status← "All of the mail servers checked are empty";
allEmpty => status← "There is no new mail";
notEmpty => {status← "You have new mail"; icon← newMailIcon};
ENDCASE => status← "Bad State!";
};
lastStateReported ← newState;
IF walnut.icon # icon THEN
{ walnut.icon← icon; IF walnut.iconic THEN ViewerOps.PaintViewer[walnut, all]};
Labels.Set[mailNotifyLabel,
IF showTime THEN Rope.Concat[status, IO.PutFR[" at %g", time[]]] ELSE status];
END;
----------------------------
SetWalnutProfileVars: ENTRY UserProfile.ProfileChangedProc = CHECKED
BEGIN ENABLE UNWIND => NULL;
prevSegmentFile, prevLogName, curUser: ROPE;
enableTailRewrite← UserProfile.Boolean[key: "Walnut.EnableTailRewrite", default: FALSE];
initialActiveIconic← UserProfile.Boolean[key: "Walnut.InitialActiveIconic", default: FALSE];
initialActiveRight← UserProfile.Boolean[key: "Walnut.InitialActiveRight", default: TRUE];
initialActiveOpen← UserProfile.Boolean[key: "Walnut.InitialActiveOpen", default: FALSE];
msgSetBorders← UserProfile.Boolean[key: "Walnut.MsgSetButtonBorders", default: FALSE];
prevSegmentFile← walnutSegmentFile;
walnutSegmentFile←
UserProfile.Token[key: "Walnut.WalnutSegmentFile", default: "Walnut.Segment"];
prevLogName← walnutLogName;
walnutLogName←
UserProfile.Token[key: "Walnut.WalnutLogFile", default: "Walnut.DBLog"];
EstablishFileNames[];
curUser← UserCredentials.GetUserCredentials[].name;
IF walnut = NIL THEN {previousUser← curUser; RETURN};
IF ~Rope.Equal[previousUser, curUser, FALSE]
THEN mustQuitWalnut← "Logged-in user changed"
ELSE IF ~Rope.Equal[prevSegmentFile, walnutSegmentFile, FALSE]
THEN mustQuitWalnut← "segment file changed"
ELSE IF ~Rope.Equal[prevLogName, walnutLogName, FALSE]
THEN mustQuitWalnut← "log file changed";
IF mustQuitWalnut # NIL THEN
{ MBQueue.Flush[walnutQueue];
IF reason # rollBack THEN
MBQueue.QueueClientAction[walnutQueue, QuitWalnut, mustQuitWalnut];
};
previousUser← curUser;
END;
----------------------------
WalnutCheckpointProc: ENTRY CedarSnapshot.CheckpointProc =
BEGIN ENABLE UNWIND => NULL;
IF walnut = NIL THEN RETURN;
MBQueue.Flush[walnutQueue];
ChangeWalnutMenu[workingMenu];
BEGIN
WalnutLog.CloseWalnutTransaction[ ! DB.Aborted => GOTO dbAborted];
EXITS
dbAborted => DB.AbortTransaction[DB.TransactionOf[$Walnut]];
END;
WalnutLog.CloseLogStream[];
WalnutRetrieve.CloseConnection[];
lastStateReported← unknown;
doingCheckpoint← TRUE;
END;
WalnutRollbackProc: ENTRY CedarSnapshot.RollbackProc =
{ ENABLE UNWIND => NULL;
IF walnut = NIL THEN RETURN;
TRUSTED
{IF mustQuitWalnut#NIL THEN Process.Detach[FORK QuitWalnut[mustQuitWalnut]]
ELSE Process.Detach[FORK RestartWalnut[]];
};
};
walnutQueue← MBQueue.Create[pushModel: FALSE]; -- queue for menu/button pushes
BuildWalnutMenu[];
Commander.Register["Walnut", BuildWalnut, "For retrieving and sending mail"];
-- clean up Walnut at checkpoint time
TRUSTED {CedarSnapshot.Register[c: WalnutCheckpointProc, r: WalnutRollbackProc]};
UserProfile.CallWhenProfileChanges[SetWalnutProfileVars];
END.