<> <> <> <> <> DIRECTORY FS USING [ComponentPositions, PagesForBytes, ExpandName], IO, Menus, Rope, TiogaMenuOps USING [PrevPlace], TiogaOps USING [SearchDir, FindText], UserProfile USING [Token], ViewerBLT USING[ChangeNumberOfLines], ViewerClasses USING [Viewer], ViewerOps, ViewerTools USING [GetSelectionContents], WalnutNewMail USING [CheckGrapevine], WalnutOps USING [ActiveMsgSetName, DeletedMsgSetName, MsgSet, CreateMsgSet, DestroyMsgSet, LogLength, MsgSetExists, SizeOfDatabase, SizeOfMsgSet, WriteArchiveFile], WalnutSendOps USING [WalnutSendProc], WalnutControlInternal USING [walnutRootFile, DoWaitCall], WalnutDisplayerInternal USING [QDisplayMsgSet], WalnutPrintOps USING [PrintMsgSet], WalnutWindowInternal USING [MsgSetButton, msgSetsVersion, msgSetsTViewer, walnut, walnutQueue, walnutTS, AddMsgSetButton, DeleteMsgSetButton, GetButton, GetSelectedMsgSets, Report, ReportRope, RetrieveNewMail], WalnutViewer USING [CreateMenuEntry], WalnutWindow USING [EnumWalnutViewers, Expunge]; WalnutWindowMenuImpl: CEDAR MONITOR IMPORTS FS, Menus, IO, Rope, UserProfile, TiogaMenuOps, TiogaOps, ViewerBLT, ViewerOps, ViewerTools, WalnutNewMail, WalnutOps, WalnutControlInternal, WalnutDisplayerInternal, WalnutPrintOps, WalnutSendOps, WalnutViewer, WalnutWindow, WalnutWindowInternal EXPORTS WalnutControlInternal = BEGIN OPEN WalnutControlInternal, WalnutWindowInternal; <> ROPE: TYPE = Rope.ROPE; Viewer: TYPE = ViewerClasses.Viewer; responseSynch: CONDITION; userHasResponded, userConfirmed: BOOL_ FALSE; noMsgSetsSelected: ROPE = "No seleted MsgSet(s)"; <<* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *>> <<>> ChangeMenu: PUBLIC ENTRY PROC[m: Menus.Menu, isBusy: BOOL] = { ENABLE UNWIND => NULL; InternalChangeMenu[m, isBusy] }; InternalChangeMenu: INTERNAL PROC[menu: Menus.Menu, isBusy: BOOL] = { oldCount, newCount: Menus.MenuLine; IF walnut = NIL THEN RETURN; oldCount _ Menus.GetNumberOfLines[walnut.menu]; newCount _ Menus.GetNumberOfLines[menu]; walnut.menu _ menu; IF oldCount # newCount THEN ViewerBLT.ChangeNumberOfLines[walnut, newCount]; ViewerOps.PaintViewer[walnut, menu]; walnut.newVersion _ isBusy; ViewerOps.PaintViewer[walnut, caption]; }; GetUserResponse: PUBLIC ENTRY PROC[m: Menus.Menu _ NIL] RETURNS[BOOL] = { ENABLE UNWIND => NULL; InternalChangeMenu[IF m = NIL THEN confirmMenu ELSE m, FALSE]; IF walnut.iconic THEN ViewerOps.BlinkIcon[walnut, 0] ELSE ViewerOps.BlinkIcon[walnutTS]; UNTIL userHasResponded DO WAIT responseSynch; ENDLOOP; userHasResponded _ FALSE; InternalChangeMenu[workingMenu, FALSE]; RETURN[userConfirmed]; }; <<>> <<* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *>> walnutMenu: PUBLIC Menus.Menu; workingMenu: PUBLIC Menus.Menu _ Menus.CreateMenu[]; confirmMenu: Menus.Menu _ Menus.CreateMenu[]; blankMenu: PUBLIC Menus.Menu _ Menus.CreateMenu[]; startupConfirmMenu: Menus.Menu _ Menus.CreateMenu[]; forceQuitMenu: PUBLIC Menus.Menu _ Menus.CreateMenu[]; maybeQuitMenu: PUBLIC Menus.Menu _ Menus.CreateMenu[]; scavMenu: PUBLIC Menus.Menu _ Menus.CreateMenu[]; mailDBMenu: PUBLIC Menus.Menu _ Menus.CreateMenu[]; readOnlyDBMenu: PUBLIC Menus.Menu _ Menus.CreateMenu[]; nonMailDBMenu: PUBLIC Menus.Menu _ Menus.CreateMenu[]; BuildWalnutMenus: PUBLIC PROC = { OPEN Menus; <> AppendMenuEntry[mailDBMenu, CreateEntry["Sender", NewSenderProc]]; AppendMenuEntry[mailDBMenu, CreateEntry["NewMail", NewMailProc]]; AppendMenuEntry[mailDBMenu, WalnutViewer.CreateMenuEntry[walnutQueue, "CloseAll", CloseAllProc]]; AppendMenuEntry[mailDBMenu, CreateEntry["MsgSetOps", MsgSetOpsProc]]; AppendMenuEntry[mailDBMenu, WalnutViewer.CreateMenuEntry[walnutQueue, "NumMsgs", NumMsgsProc]]; AppendMenuEntry[mailDBMenu, WalnutViewer.CreateMenuEntry[walnutQueue, "ExpInfo", ExpungeInfo]]; AppendMenuEntry[mailDBMenu, CreateEntry["Find", FindProc]]; <<>> <> AppendMenuEntry[mailDBMenu, CreateEntry[name: "Exp", proc: MenuExpunge, guarded: TRUE], 1]; AppendMenuEntry[mailDBMenu, CreateEntry["Delete", DeleteMsgSetsProc], 1]; AppendMenuEntry[mailDBMenu, CreateEntry["SizeOf", SizeOfMsgSetsProc], 1]; AppendMenuEntry[mailDBMenu, CreateEntry["Print", PrintMsgSetsProc], 1]; AppendMenuEntry[mailDBMenu, CreateEntry["Create", CreateMsgSetButtonProc], 1]; AppendMenuEntry[mailDBMenu, CreateEntry["Archive", ArchiveButtonProc], 1]; AppendMenuEntry[mailDBMenu, CreateEntry["Append", AppendButtonProc], 1]; AppendMenuEntry[mailDBMenu, CreateEntry["PrevPlace", PrevPlaceProc], 1]; Menus.ChangeNumberOfLines[mailDBMenu, 1]; <> AppendMenuEntry[readOnlyDBMenu, CreateEntry["Sender", NewSenderProc]]; AppendMenuEntry[readOnlyDBMenu, WalnutViewer.CreateMenuEntry[walnutQueue, "CloseAll", CloseAllProc]]; AppendMenuEntry[readOnlyDBMenu, CreateEntry["SizeOf", SizeOfMsgSetsProc]]; AppendMenuEntry[readOnlyDBMenu, WalnutViewer.CreateMenuEntry[walnutQueue, "NumMsgs", NumMsgsProc]]; AppendMenuEntry[readOnlyDBMenu, CreateEntry["MsgSetOps", MsgSetOpsProc]]; AppendMenuEntry[readOnlyDBMenu, CreateEntry["Find", FindProc]]; AppendMenuEntry[readOnlyDBMenu, CreateEntry["Print", PrintMsgSetsProc],1]; AppendMenuEntry[readOnlyDBMenu, CreateEntry["Archive", ArchiveButtonProc], 1]; AppendMenuEntry[readOnlyDBMenu, CreateEntry["Append", AppendButtonProc], 1]; AppendMenuEntry[readOnlyDBMenu, CreateEntry["PrevPlace", PrevPlaceProc], 1]; Menus.ChangeNumberOfLines[readOnlyDBMenu, 1]; <> AppendMenuEntry[nonMailDBMenu, CreateEntry["Sender", NewSenderProc]]; AppendMenuEntry[nonMailDBMenu, WalnutViewer.CreateMenuEntry[walnutQueue, "CloseAll", CloseAllProc]]; AppendMenuEntry[nonMailDBMenu, CreateEntry["MsgSetOps", MsgSetOpsProc]]; AppendMenuEntry[nonMailDBMenu, WalnutViewer.CreateMenuEntry[walnutQueue, "NumMsgs", NumMsgsProc]]; AppendMenuEntry[nonMailDBMenu, WalnutViewer.CreateMenuEntry[walnutQueue, "ExpInfo", ExpungeInfo]]; AppendMenuEntry[nonMailDBMenu, CreateEntry["Find", FindProc]]; <<>> <> AppendMenuEntry[nonMailDBMenu, CreateEntry[name: "Exp", proc: MenuExpunge, guarded: TRUE], 1]; AppendMenuEntry[nonMailDBMenu, CreateEntry["Delete", DeleteMsgSetsProc], 1]; AppendMenuEntry[nonMailDBMenu, CreateEntry["SizeOf", SizeOfMsgSetsProc], 1]; AppendMenuEntry[nonMailDBMenu, CreateEntry["Print", PrintMsgSetsProc], 1]; AppendMenuEntry[nonMailDBMenu, CreateEntry["Create", CreateMsgSetButtonProc], 1]; AppendMenuEntry[nonMailDBMenu, CreateEntry["Archive", ArchiveButtonProc], 1]; AppendMenuEntry[nonMailDBMenu, CreateEntry["Append", AppendButtonProc], 1]; AppendMenuEntry[nonMailDBMenu, CreateEntry["PrevPlace", PrevPlaceProc], 1]; Menus.ChangeNumberOfLines[nonMailDBMenu, 1]; AppendMenuEntry[workingMenu, CreateEntry["Sender", NewSenderProc]]; AppendMenuEntry[confirmMenu, CreateEntry["Sender", NewSenderProc]]; 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]]; AppendMenuEntry[maybeQuitMenu, CreateEntry["Quit", WWConfirmProc]]; AppendMenuEntry[maybeQuitMenu, CreateEntry["Retry", WWDenyProc]]; AppendMenuEntry[scavMenu, CreateEntry["Quit", WWDenyProc]]; AppendMenuEntry[scavMenu, CreateEntry["Scavenge", WWConfirmProc]]; }; NewSenderProc: Menus.MenuProc = { WalnutSendOps.WalnutSendProc[fromExec: FALSE]}; <> MsgSetOpsProc: Menus.MenuProc = { v: Viewer = NARROW[parent]; count: NAT = Menus.GetNumberOfLines[v.menu]; newCount: NAT = IF count = 2 THEN 1 ELSE 2; Menus.ChangeNumberOfLines[v.menu, newCount]; ViewerBLT.ChangeNumberOfLines[v, newCount]; }; MenuExpunge: Menus.MenuProc = { ENABLE UNWIND => ChangeMenu[walnutMenu, FALSE]; ChangeMenu[workingMenu, TRUE]; WalnutWindow.Expunge[]; }; ExpungeInfo: Menus.MenuProc = { len: INT _ WalnutOps.LogLength[]; numIn: INT _ WalnutOps.SizeOfMsgSet[WalnutOps.DeletedMsgSetName].messages; total: INT _ WalnutOps.SizeOfDatabase[].messages; Report[IO.PutFR[" The log file is %g bytes (%g pages) long", IO.int[len], IO.int[FS.PagesForBytes[len]]]]; Report[IO.PutFR[ " There are %g deleted msgs, (%g total msgs)", IO.int[numIn], IO.int[total] ]]; }; NumMsgsProc: Menus.MenuProc = { messages, msgSets: INT; [messages, msgSets] _ WalnutOps.SizeOfDatabase[]; Report[IO.PutFR["There are %g messages & %g msgSets in this database", IO.int[messages], IO.int[msgSets] ]]; }; NewMailProc: Menus.MenuProc = { IF mouseButton = blue THEN WalnutNewMail.CheckGrapevine[] ELSE WalnutWindowInternal.RetrieveNewMail[] }; CloseAllProc: Menus.MenuProc = { msgSetList, msgList: LIST OF Viewer; mpViewer: Viewer; [msgSetList, msgList] _ WalnutWindow.EnumWalnutViewers[TRUE]; FOR vL: LIST OF Viewer _ msgList, vL.rest UNTIL vL=NIL DO IF ViewerOps.FetchProp[vL.first, $Frozen] = NIL THEN ViewerOps.DestroyViewer[vL.first]; ENDLOOP; FOR vL: LIST OF Viewer _ msgSetList, vL.rest UNTIL vL=NIL DO ViewerOps.CloseViewer[vL.first]; ENDLOOP; IF (mpViewer _ ViewerOps.FindViewer["NewMail Retrieval"]) # NIL THEN ViewerOps.CloseViewer[mpViewer]; ViewerOps.CloseViewer[walnut]; }; 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 }; -- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * <<"immediate" buttons that gather some parameters and then queue the real proc to call>> CreateMsgSetButtonProc: Menus.MenuProc = { msName: ROPE _ ViewerTools.GetSelectionContents[]; Cmsb: PROC = { IF msName.Length[] = 0 THEN { Report["No MsgSet name specified"]; RETURN}; IF msName.Find[" "] >=0 THEN { Report[" MsgSet names may not contain spaces"]; RETURN}; IF WalnutOps.MsgSetExists[msName, WalnutWindowInternal.msgSetsVersion].exists THEN Report["MsgSet: ", msName, " already exists"] ELSE { WalnutOps.CreateMsgSet[msName, WalnutWindowInternal.msgSetsVersion]; [] _ AddMsgSetButton[msName, TRUE]; WalnutWindowInternal.msgSetsVersion _ WalnutWindowInternal.msgSetsVersion + 1; }; }; [] _ DoWaitCall[Cmsb]; }; SizeOfMsgSetsProc: Menus.MenuProc = { Sms: PROC = { msgSetList: LIST OF MsgSetButton _ GetSelectedMsgSets[]; msgSet: ROPE; IF msgSetList = NIL THEN { Report[noMsgSetsSelected]; RETURN}; FOR mL: LIST OF MsgSetButton _ msgSetList, mL.rest UNTIL mL=NIL DO num: INT _ WalnutOps.SizeOfMsgSet[msgSet _ mL.first.msgSet.name].messages; Report[IO.PutFR[" %g msgs in MsgSet %g", IO.int[num], IO.rope[msgSet]]]; ENDLOOP; }; [] _ DoWaitCall[Sms]; }; DeleteMsgSetsProc: Menus.MenuProc = { Dms: PROC = { msgSetList: LIST OF MsgSetButton _ GetSelectedMsgSets[]; name: ROPE; someInDeleted: BOOL; anyDeleted: BOOL _ TRUE; IF msgSetList = NIL THEN { Report[noMsgSetsSelected, " to delete"]; RETURN}; ChangeMenu[workingMenu, TRUE]; FOR mL: LIST OF MsgSetButton _ msgSetList, mL.rest UNTIL mL=NIL DO name _ mL.first.msgSet.name; IF name.Equal[WalnutOps.DeletedMsgSetName, FALSE] THEN { Report["Can't delete the Deleted MsgSet"]; LOOP}; IF WalnutOps.SizeOfMsgSet[name].messages # 0 THEN { Report[" Confirm deletion of messages in MsgSet: ", name]; IF ~GetUserResponse[] THEN { ChangeMenu[walnutMenu, FALSE]; RETURN } }; DeleteMsgSetButton[name]; someInDeleted _ WalnutOps.DestroyMsgSet[ mL.first.msgSet, WalnutWindowInternal.msgSetsVersion]; anyDeleted _ anyDeleted OR someInDeleted; IF ~name.Equal[WalnutOps.ActiveMsgSetName, FALSE] THEN Report["MsgSet: ", name, " has been deleted"] ELSE Report["Msgs have been removed from Active"]; WalnutWindowInternal.msgSetsVersion _ WalnutWindowInternal.msgSetsVersion + 1; ENDLOOP; IF anyDeleted THEN RedisplayDeleted[]; ChangeMenu[walnutMenu, FALSE]; }; [] _ DoWaitCall[Dms]; }; PrintMsgSetsProc: PUBLIC Menus.MenuProc = { Pms: PROC = { msgSetList: LIST OF MsgSetButton _ GetSelectedMsgSets[]; IF msgSetList = NIL THEN { Report[noMsgSetsSelected, " to print"]; RETURN }; ChangeMenu[workingMenu, TRUE]; FOR mL: LIST OF MsgSetButton _ msgSetList, mL.rest UNTIL mL=NIL DO IF ~WalnutPrintOps.PrintMsgSet[mL.first.msgSet.name] THEN EXIT; ENDLOOP; ChangeMenu[walnutMenu, FALSE]; }; [] _ DoWaitCall[Pms]; }; ArchiveButtonProc: Menus.MenuProc = { ArchiveOrAppend[FALSE, mouseButton=blue] }; AppendButtonProc: Menus.MenuProc = { ArchiveOrAppend[TRUE, mouseButton=blue] }; ArchiveOrAppend: PROC[append, destroyMsgSets: BOOL] = { fileName: ROPE _ ViewerTools.GetSelectionContents[]; msgSetList: LIST OF MsgSetButton _ GetSelectedMsgSets[]; AorA: PROC = { ENABLE UNWIND => ChangeMenu[walnutMenu, FALSE]; anyInDeleted: BOOL _ FALSE; msList: LIST OF WalnutOps.MsgSet; ChangeMenu[workingMenu, TRUE]; FOR mL: LIST OF MsgSetButton _ msgSetList, mL.rest UNTIL mL=NIL DO msList _ CONS[mL.first.msgSet, msList]; ENDLOOP; IF ~DoArchive[fileName, msList, append] THEN { ChangeMenu[walnutMenu, FALSE]; RETURN }; IF ~destroyMsgSets THEN { ChangeMenu[walnutMenu, FALSE]; RETURN }; FOR mL: LIST OF MsgSetButton _ msgSetList, mL.rest UNTIL mL = NIL DO someInDeleted: BOOL; name: ROPE; DeleteMsgSetButton[name _ mL.first.msgSet.name]; -- ignores Active & Deleted IF ~name.Equal[WalnutOps.DeletedMsgSetName, FALSE] THEN someInDeleted _ WalnutOps.DestroyMsgSet[ mL.first.msgSet, WalnutWindowInternal.msgSetsVersion ]; anyInDeleted _ anyInDeleted OR someInDeleted; ENDLOOP; IF anyInDeleted THEN RedisplayDeleted[]; ChangeMenu[walnutMenu, FALSE]; }; [] _ DoWaitCall[AorA]; }; DoArchive: PUBLIC PROC[fileName: ROPE, msList: LIST OF WalnutOps.MsgSet, append: BOOL] RETURNS[ok: BOOL] = { fullName: ROPE; num: INT _ 0; ok _ FALSE; IF fileName.Length[] = 0 THEN { Report["No Archive file specified"]; RETURN}; IF msList = NIL THEN { Report[noMsgSetsSelected, " to archive"]; RETURN}; <> BEGIN cp: FS.ComponentPositions; wDir: ROPE _ UserProfile.Token["Walnut.DefaultArchiveDir"]; [fullName, cp, ] _ FS.ExpandName[fileName, wDir]; IF cp.ext.length = 0 THEN fullName _ fullName.Concat[".ArchiveLog"]; END; IF Rope.Equal[fullName, walnutRootFile, FALSE] THEN { Report["Can't archive on log file"]; RETURN}; IF append THEN Report["Appending msgs to the file: ", fileName]; ReportRope["Archiving the MsgSet(s): "]; FOR mL: LIST OF WalnutOps.MsgSet _ msList, mL.rest UNTIL mL = NIL DO msName: ROPE = mL.first.name; this: INT _ WalnutOps.SizeOfMsgSet[msName].messages; ReportRope[msName, IO.PutFR[" (%g messages) ", IO.int[this]]]; num _ num + this; WalnutOps.WriteArchiveFile[file: fullName, msgSetList: LIST[mL.first], append: append]; append _ TRUE; -- always true after the first write ENDLOOP; Report[IO.PutFR["\n %g messages archived on file: %g", IO.int[num], IO.rope[fullName]]]; RETURN[TRUE] }; RedisplayDeleted: PROC = { msb: MsgSetButton _ GetButton[WalnutOps.DeletedMsgSetName]; IF msb.msViewer = NIL THEN RETURN; [] _ WalnutDisplayerInternal.QDisplayMsgSet[msb, msb.msViewer, FALSE]; }; FindProc: Menus.MenuProc = { IF ~TiogaOps.FindText[ viewer: WalnutWindowInternal.msgSetsTViewer, whichDir: GetDirection[mouseButton], which: feedback, case: ~shift] THEN ViewerOps.BlinkIcon[WalnutWindowInternal.msgSetsTViewer]; }; PrevPlaceProc: Menus.MenuProc = { TiogaMenuOps.PrevPlace[WalnutWindowInternal.msgSetsTViewer] }; GetDirection: PROC[mb: Menus.MouseButton] RETURNS[sd: TiogaOps.SearchDir] = { SELECT mb FROM red => RETURN[forwards]; yellow => RETURN[anywhere]; blue => RETURN[backwards]; ENDCASE; }; <<* * * * * * * * * *>> END.