DIRECTORY
Containers,
Icons USING [IconFlavor],
FS USING [Error, SetKeep],
IO,
Labels USING [Set],
Menus,
MessageWindow USING [Append],
Process USING [Detach, Pause, SecondsToTicks],
Rope,
TypeScript USING [Create],
UserProfile USING [Boolean],
ViewerClasses USING [Viewer],
ViewerEvents USING [EventRegistration, UnRegisterEventProc],
ViewerOps,
ViewerIO USING [CreateViewerStreams],
ViewerSpecs,
WalnutOps
USING [ServerInfo, ActiveMsgSetName,
AcceptNewMail, GetNewMail,
RecordNewMailInfo, RegisterReporter, Shutdown, StartNewMail, UnregisterReporter],
WalnutNewMail USING [DisableMailRetrieval, EnableMailRetrieval],
WalnutSendOps USING [userRName, RegisterReporter, UnregisterReporter],
WalnutControlInternal
USING [
mailNotifyLabel, mustQuitWalnut, WaitCallOutcome, walnutMenu, workingMenu,
ChangeMenu, DoWaitCall],
WalnutDisplayerInternal USING [AddNewMsgsToActive],
WalnutWindowInternal
USING [MailState, MsgSetButton,
firstMsgSetButton, selectedMsgSetButtons, msgSetsTViewer,
personalMailDB, newMailIcon, walnut, walnutEventReg, walnutIcon, walnutTS,
GetButton],
WalnutWindowInternalImpl:
CEDAR
PROGRAM
IMPORTS
Labels, MessageWindow,
FS, IO, Process, Rope, UserProfile,
TypeScript, ViewerEvents, ViewerOps, ViewerIO,
WalnutOps,
WalnutControlInternal,
WalnutNewMail, WalnutSendOps,
WalnutDisplayerInternal, WalnutWindowInternal
EXPORTS WalnutWindowInternal, WalnutWindow =
Report:
PUBLIC
PROC[msg1, msg2, msg3:
ROPE ←
NIL] =
{ ReportRope[msg1, msg2, msg3]; IF wtsOut # NIL THEN wtsOut.PutChar['\n]; };
ReportRope:
PUBLIC
PROC[msg1, msg2, msg3:
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];
RETURN
};
IF msg1#NIL THEN wtsOut.PutRope[msg1];
IF msg2#NIL THEN wtsOut.PutRope[msg2];
IF msg3#NIL THEN wtsOut.PutRope[msg3];
};
RetrieveNewMail:
PUBLIC
PROC = {
Rnm:
PROC = {
ENABLE UNWIND => { ChangeMenu[walnutMenu, FALSE] };
responses: LIST OF WalnutOps.ServerInfo;
complete: BOOL;
numNew, total: INT ← 0;
msB: MsgSetButton ← GetButton[WalnutOps.ActiveMsgSetName];
ChangeMenu[workingMenu, TRUE];
Report["\n Getting new mail from the mail log"];
IF msB.msViewer #
NIL
THEN
IF msB.msViewer.destroyed THEN msB.msViewer ← NIL;
IF msB.msViewer =
NIL
THEN {
-- not displayed
[responses, complete] ← WalnutOps.GetNewMail[msB.msgSet.version, NIL];
numNew ← -1;
WalnutOps.AcceptNewMail[msB.msgSet.version];
}
ELSE
[responses, complete, numNew] ← WalnutDisplayerInternal.AddNewMsgsToActive[msB];
IF ~complete
THEN {
Report[" There were problems with GetNewMail - some messages not available; try again"];
ChangeMenu[walnutMenu, FALSE];
RETURN
};
FOR rL:
LIST
OF WalnutOps.ServerInfo ← responses, rL.rest
UNTIL rL =
NIL
DO
total ← total + rL.first.num; ENDLOOP;
IF total = 0
THEN
Report["No messages were on the newMailLog"]
ELSE {
FOR rL:
LIST
OF WalnutOps.ServerInfo ← responses, rL.rest
UNTIL rL =
NIL
DO
ReportRope[rL.first.server];
IF rL.first.num = 0
THEN
Report[" ... empty"]
ELSE {
IF rL.first.num = 1
THEN Report[" delivered 1 message"]
ELSE Report[IO.PutFR[" delivered %g messages", IO.int[rL.first.num]]];
};
ENDLOOP;
IF (numNew >= 0)
AND (total # numNew)
THEN {
IF numNew = 0
THEN
Report["\nNo new messages added to database"]
ELSE Report[IO.PutFR["\nOnly %g messages were new", IO.int[numNew]] ];
};
};
SetMailState[noMail];
ChangeMenu[walnutMenu, FALSE];
};
[] ← DoWaitCall[Rnm];
};
EnableNewMail:
PUBLIC
PROC = {
progress: BOOL ← UserProfile.Boolean[key: "Walnut.ReportNewMailProgress", default: FALSE];
IF progress
THEN
IF newMailProgressStream =
NIL
THEN {
progressLog:
ROPE ←
Rope.Cat["///Users/", WalnutSendOps.userRName, "/WalnutNewMailProgress.log"];
newMailProgressTS ← TypeScript.Create[
info: [name: "NewMail Retrieval", iconic: FALSE, column: right, openHeight: 64],
paint: FALSE];
ViewerOps.TopViewer[viewer: newMailProgressTS, paint: TRUE];
newMailProgressTS.inhibitDestroy ← TRUE;
newMailProgressStream ←
ViewerIO.CreateViewerStreams[
name: NIL, viewer: newMailProgressTS, backingFile: progressLog].out;
};
WalnutNewMail.EnableMailRetrieval[
reportProc: ReportProc,
progressProc: IF progress THEN ProgressReport ELSE NIL,
getMailLog: GetMailLog,
recordMailInfo: RecordNewMailInfo,
notifyWhenMailRetrieved: NotifyWhenMailRetrieved];
IF newMailProgressTS # NIL THEN newMailProgressTS.inhibitDestroy ← FALSE;
};
DisableNewMail:
PUBLIC
PROC = {
WalnutNewMail.DisableMailRetrieval[];
IF newMailProgressStream #
NIL
THEN {
IF ~newMailProgressTS.destroyed
THEN {
newMailProgressStream.Close[];
ViewerOps.DestroyViewer[newMailProgressTS];
};
newMailProgressStream ← NIL;
newMailProgressTS ← NIL;
};
};
tsLogName: ROPE = "///Temp/Walnut/Walnut.TypescriptLog";
OpenTS:
PUBLIC
PROC[r:
ROPE ←
NIL, doRegister:
BOOL ←
TRUE] = {
FS.SetKeep[tsLogName, 10 ! FS.Error => CONTINUE]; -- if tsLogName doesn't exist
IF wtsOut =
NIL
THEN
{ wtsOut ← ViewerIO.CreateViewerStreams[
NIL, walnutTS, tsLogName].out;
IF r # NIL THEN wtsOut.PutRope[r];
IF doRegister
THEN {
WalnutSendOps.RegisterReporter[wtsOut];
WalnutOps.RegisterReporter[wtsOut];
};
};
};
CloseTS:
PUBLIC
PROC = {
IF wtsOut # NIL THEN wtsOut.Close[];
WalnutSendOps.UnregisterReporter[wtsOut];
WalnutOps.UnregisterReporter[wtsOut];
wtsOut ← NIL;
};
CloseDownWalnut:
PUBLIC
PROC = {
clean up after Walnut
v: Viewer ← walnut;
IF walnut = NIL THEN RETURN; -- not running
walnut.inhibitDestroy ← TRUE;
DisableNewMail[];
ChangeMenu[workingMenu, FALSE];
selectedMsgSetButtons ← firstMsgSetButton ← NIL;
TakeDownWalnutViewers[];
ReportRope["Closing database and saving log ..."];
WalnutOps.Shutdown[];
IF walnutEventReg #
NIL
THEN
ViewerEvents.UnRegisterEventProc[walnutEventReg, destroy];
walnutEventReg ← NIL;
walnut ← NIL; -- don't let others try to use Report
mailNotifyLabel ← NIL;
WalnutSendOps.UnregisterReporter[wtsOut];
WalnutOps.UnregisterReporter[wtsOut];
wtsOut.Close[];
wtsOut ← NIL;
mustQuitWalnut ← NIL;
v.inhibitDestroy ← FALSE;
msgSetsTViewer ← NIL;
ViewerOps.DestroyViewer[v];
};
EnumWalnutViewers:
PUBLIC
PROC[keepSeparate:
BOOL]
RETURNS [msgSetList, msgList:
LIST
OF Viewer] = {
Enum: ViewerOps.EnumProc = {
IF ViewerOps.FetchProp[v, $WalnutMsgSetName] #
NIL
THEN
{ msgSetList← CONS[v, msgSetList]; RETURN[TRUE] };
IF ViewerOps.FetchProp[v, $WalnutMsgName] #
NIL
THEN
{
IF keepSeparate
THEN msgList←
CONS[v, msgList]
ELSE msgSetList← CONS[v, msgSetList];
RETURN[TRUE]
};
};
ViewerOps.EnumerateViewers[Enum]
};
TakeDownWalnutViewers:
PUBLIC
PROC = {
msgSetL, msgL: LIST OF Viewer;
[msgSetL, msgL] ← EnumWalnutViewers[TRUE];
FOR vL:
LIST
OF Viewer ← msgL, vL.rest
UNTIL vL=
NIL
DO
IF ViewerOps.FetchProp[vL.first, $Frozen] = NIL THEN ViewerOps.DestroyViewer[vL.first];
ENDLOOP;
FOR vL:
LIST
OF Viewer ← msgSetL, vL.rest
UNTIL vL=
NIL
DO
ViewerOps.DestroyViewer[vL.first];
ENDLOOP;
};
* * * * * * * * * * support for new mail
newMailProgressTS: Viewer;
newMailProgressStream: STREAM ← NIL;
ReportProc: PROC[r: ROPE] = { Report[r] };
ProgressReport:
PROC[r:
ROPE] = {
IF newMailProgressTS #
NIL
THEN {
IF newMailProgressTS.destroyed
THEN {
newMailProgressTS ← NIL;
newMailProgressStream ← NIL;
};
IF newMailProgressStream # NIL THEN newMailProgressStream.PutRope[r];
};
};
GetMailLog:
PROC
RETURNS[strm:
STREAM] = {
outcome: WalnutControlInternal.WaitCallOutcome;
Gml:
PROC =
{ strm ← WalnutOps.StartNewMail[] };
IF (outcome ← DoWaitCall[Gml]) = ok
THEN {
SetMailState[retrieving];
RETURN;
};
IF outcome = notRunning THEN Process.Pause[Process.SecondsToTicks[20]];
outcome ← DoWaitCall[Gml]; -- try again
IF outcome = ok THEN SetMailState[retrieving];
};
RecordNewMailInfo:
PROC[logLen:
INT, server:
ROPE, num:
INT]
RETURNS[ok: BOOL] = {
Rnml:
PROC = {
ok ← FALSE;
WalnutOps.RecordNewMailInfo[logLen, server, num];
ok ← TRUE;
};
[] ← DoWaitCall[Rnml];
};
NotifyWhenMailRetrieved:
PROC[ok:
BOOL, someMail:
BOOL] = {
IF ~someMail THEN { SetMailState[noMail]; RETURN};
SetMailState[thereIsMail];
IF personalMailDB
THEN {
autoNewMail: BOOL ← UserProfile.Boolean[key: "Walnut.AutoNewMail", default: FALSE];
IF autoNewMail
THEN
TRUSTED { Process.Detach[FORK RetrieveNewMail[] ] };
};
};
SetMailState:
PUBLIC
PROC[mailState: MailState] = {
status: ROPE;
icon: Icons.IconFlavor ← walnutIcon;
IF walnut = NIL THEN RETURN;
SELECT mailState
FROM
noMail => status ← "There is no new mail at %g";
retrieving => status ← "Mail is being retrieved at %g";
thereIsMail => {
icon ← newMailIcon;
status ← "You have new mail at %g";
};
gvWaiting => status ← "Waiting (15 sec) for initial grapevine response at %g";
noGV => status ← "No mailbox state reported from grapevine at %g";
noServers => status ← "All of the mail servers are down at %g";
gvMail => status ← "Mail on grapevine at %g";
ENDCASE => NULL;
IF walnut.icon # icon
THEN {
walnut.icon← icon;
IF walnut.iconic THEN ViewerOps.PaintViewer[walnut, all];
};
Labels.Set[mailNotifyLabel, IO.PutFR[status, IO.time[]] ];
};