-- File: WalnutExtrasImpl.mesa -- Contents: operations invoked by buttons & menus in Walnut Control window -- created May, 1983 by Willie-Sue -- Last edit by: -- Willie-Sue on: June 8, 1983 11:02 am DIRECTORY Buttons USING [ButtonProc], Commander USING [CommandProc, Register], DB, FileIO, IO, MBQueue USING [Flush, QueueClientAction], Menus USING [Menu], Rope, ViewerOps, ViewerTools USING [GetContents, SetContents], WalnutDB, WalnutDBLog, WalnutDisplayerOps, WalnutLog, WalnutRetrieve, WalnutStream, WalnutViewer, WalnutWindow; WalnutExtrasImpl: CEDAR MONITOR IMPORTS DB, Commander, MBQueue, FileIO, IO, Rope, ViewerOps, ViewerTools, WalnutDB, WalnutDisplayerOps, WalnutLog, WalnutRetrieve, WalnutStream, WalnutWindow EXPORTS WalnutWindow SHARES WalnutWindow = BEGIN OPEN IO, WalnutDB, WalnutWindow; -- Walnut types -- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * WalnutQueueEntry: TYPE = REF QueueEntryObject; QueueEntryObject: TYPE = MONITORED RECORD[params: REF ANY, condition: CONDITION]; DoWaitCall: ENTRY PROC[proc: PROC[REF ANY], ra: REF ANY_ NIL] = -- puts proc on Walnut's queue and waits for its execution to finish BEGIN ENABLE UNWIND => NULL; wqe: WalnutQueueEntry_ NEW[QueueEntryObject_ [params: ra]]; QueueExecCall[proc, wqe]; WAIT wqe.condition; END; -- * * * * * * * * * * * * * * * * * * * WalnutExpunge: PUBLIC Commander.CommandProc = {IF walnut # NIL THEN DoWaitCall[ExpungeProc] ELSE InternalDumpMsgs[TRUE, FALSE]}; ExpungeProc: ENTRY PROC[ra: REF ANY] = BEGIN wqe: WalnutQueueEntry; BEGIN ENABLE UNWIND => { NOTIFY wqe.condition}; wqe_ NARROW[ra]; DoExpunge[TRUE, TRUE]; NOTIFY wqe.condition; END; END; DoExpunge: PUBLIC PROC[doUpdates, tailRewrite: BOOL] = BEGIN ok: BOOL; tempLogName: ROPE_ "Walnut.TempLog"; tempLog: IO.STREAM; ChangeWalnutMenu[workingMenu]; TakeDownWalnutViewers[]; WalnutLog.MarkWalnutTransaction[]; MBQueue.Flush[walnutQueue]; tempLog_ FileIO.Open[tempLogName, overwrite]; Report["Dumping message database to ", tempLogName, "..."]; ok_ WalnutLog.ExpungeMsgs [tempLog: tempLog, doUpdates: doUpdates, tailRewrite: (tailRewrite AND enableTailRewrite)]; IF ~ok THEN { Report[" Dump was not successful; suggest you abort & scavenge"]; IF ~UserConfirmed[] THEN {ChangeWalnutMenu[walnutMenu]; RETURN}; ChangeWalnutMenu[workingMenu]; }; IF doUpdates THEN WalnutLog.MarkWalnutTransaction[]; Report["New log and database saved."]; ChangeWalnutMenu[walnutMenu]; []_ DisplayMsgSet[activeMsgSet]; END; -- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * WalnutScavenge: PUBLIC Commander.CommandProc = BEGIN IF walnut # NIL THEN { DoWaitCall[ScavengeProc]; Report["\nScavenge finished ... Restarting"]; RestartWalnut[]; Report[" ...done"]; } ELSE { SetUpTSLog["WalnutScavenge"]; Report["Constructing Walnut from ", walnutLogName, "... "]; DB.DeclareSegment[filePath: walnutSegmentFile, segment: $Walnut]; DoScavenge[startPos: 0, internal: FALSE]; CloseTSLog[]; }; END; ScavengeProc: ENTRY PROC[ra: REF ANY] = BEGIN wqe: WalnutQueueEntry; BEGIN ENABLE UNWIND => { NOTIFY wqe.condition}; wqe_ NARROW[ra]; DoScavenge[startPos: 0, internal: TRUE]; NOTIFY wqe.condition; END; END; DoScavenge: PUBLIC PROC[startPos: INT, internal: BOOL] = BEGIN OPEN WalnutLog; IF DB.TransactionOf[$Walnut]#NIL THEN CloseWalnutTransaction[]; IF walnut # NIL THEN { TakeDownWalnutViewers[]; DestroyAllMsgSetButtons[] }; -- re-initialize the segment to erase it DB.DeclareSegment[filePath: walnutSegmentFile, segment: $Walnut, version: NewOnly]; OpenWalnutTransaction[walnutNullTrans, TRUE]; -- no transaction, noLog IF internal THEN Report[" reading log file from beginning ..."] ELSE Report[" Erasing walnut segment"]; []_ InitializeLog[walnutLogName]; []_ UpdateFromLog[startPos]; CloseWalnutTransaction[]; IF internal THEN OpenWalnutTransaction[NIL, FALSE] -- open with transaction ELSE CloseLogStream[]; END; -- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * GetNewMail: PUBLIC PROC = { IF walnut # NIL THEN DoWaitCall[NewMail, NIL]}; WalnutNewMail: PUBLIC Commander.CommandProc = BEGIN IF walnut # NIL THEN DoWaitCall[NewMail, NIL] ELSE cmd.out.PutRope["Walnut must be running to retrieve new mail"]; END; NewMail: ENTRY PROC[ra: REF ANY] = BEGIN wqe: WalnutQueueEntry; BEGIN ENABLE UNWIND => { NOTIFY wqe.condition}; wqe_ NARROW[ra]; ChangeWalnutMenu[workingMenu]; RetrieveNewMail[]; ChangeWalnutMenu[walnutMenu]; NOTIFY wqe.condition; END; END; DoNewMail: PUBLIC PROC = BEGIN startPos: INT_ WalnutLog.LogLength[TRUE]; numRetrieved: INT_ WalnutRetrieve.RetrieveGVMessages[].numRetrieved; IF numRetrieved # 0 THEN { numNew: INT_ GetMessagesFromLog[startPos]; IF numNew # numRetrieved THEN Report[IO.PutFR["Only %g messages were new", int[numNew]]]; }; END; -- * * * * * * * * * * * * * * * * * * * * * GetMessagesFromLog: PROC[startPos: INT] RETURNS[numNew: INT] = BEGIN anymore, mExisted: BOOL; endPos: INT; sPos: INT_ startPos; msV: Viewer_ NIL; prevMsgSet: MsgSet_ NIL; msg: Msg; msgRec: WalnutLog.MsgRec; newMsgSetList: LIST OF MsgSet; newRelList: LIST OF RelshipMsgSetPair; numNew_ 0; DO [endPos, anymore, msgRec]_ WalnutLog.NextMsgRecFromLog[sPos]; IF ~anymore THEN EXIT; IF msgRec = NIL THEN {sPos_ endPos; LOOP}; [msg, mExisted, newMsgSetList, newRelList]_ MsgRecToMsg[msgRec]; IF ~mExisted THEN numNew_ numNew + 1; FOR mL: LIST OF MsgSet_ newMsgSetList, mL.rest UNTIL mL=NIL DO AddMsgSetButton[msgSet: mL.first, msName: GetName[mL.first], select: FALSE]; ENDLOOP; FOR rL: LIST OF RelshipMsgSetPair_ newRelList, rL.rest UNTIL rL = NIL DO IF ~EqEntities[rL.first.msgSet, prevMsgSet] THEN msV_ FindMSViewer[prevMsgSet_ rL.first.msgSet]; IF msV#NIL THEN WalnutDisplayerOps.AddParsedMsgToMSViewer[msg, msgRec, msV, rL.first.rel]; ENDLOOP; sPos_ endPos; ENDLOOP; RETURN[numNew]; END; -- * * * * * * * * * * * * * * * * * * * * * WalnutDump: PUBLIC Commander.CommandProc = BEGIN IF walnut # NIL THEN -- walnut is up cmd.out.PutRope["Must quit out of Walnut first"] ELSE InternalDumpMsgs[FALSE, FALSE]; END; InternalDumpMsgs: PROC[doUpdates, tailRewrite: BOOL] = BEGIN ok: BOOL; -- walnut window not up, DB may be closed tempLog: IO.STREAM; tempLogName: ROPE_ "Walnut.TempLog"; SetUpTSLog["WalnutExpunge"]; []_ WalnutLog.InitializeLog[walnutLogName]; -- opens segment if necessary tempLog_ FileIO.Open[tempLogName, write]; Report["Dumping message database to Walnut.TempLog ..."]; ok_ WalnutLog.ExpungeMsgs [tempLog: tempLog, doUpdates: doUpdates, tailRewrite: (tailRewrite AND enableTailRewrite)]; IF ~ok THEN { Report[" Dump was not successful; updates not comitted"]; RETURN}; Report["Committing changes ..."]; WalnutLog.CloseWalnutTransaction[]; Report["New log and database saved."]; CloseTSLog[]; END; WalnutReadMailFile: PUBLIC Commander.CommandProc = BEGIN h: IO.STREAM_ IO.RIS[cmd.commandLine]; fName: ROPE_ h.GetToken[WhiteSpace]; IF walnut = NIL THEN SetUpTSLog["ReadOldMail"]; ReadMailFile[fName, h.GetToken[WhiteSpace]]; IF walnut = NIL THEN CloseTSLog[]; END; -- make separate proc so callable by program ReadMailFile: PUBLIC PROC[fName, msgSet: ROPE] = BEGIN mfp: LIST OF ROPE_ LIST[fName, IF msgSet=NIL THEN "Active" ELSE msgSet]; DoWaitCall[ReadMailFileProc, mfp]; END; ReadMailFileProc: ENTRY PROC[ra: REF ANY] = BEGIN wqe: WalnutQueueEntry; BEGIN ENABLE UNWIND => { NOTIFY wqe.condition}; mfp: LIST OF ROPE; wqe_ NARROW[ra]; mfp_ NARROW[wqe.params]; DoReadMailFile[mfp]; NOTIFY wqe.condition; END; END; DoReadMailFile: PROC[mfp: LIST OF ROPE] = BEGIN OPEN WalnutLog; defaultPrefix: ROPE; fStream: IO.STREAM; startPos, numNew: INT; fName: ROPE_ mfp.first; msName: ROPE_ mfp.rest.first; IF fName = NIL THEN {Report["No input file specified so quitting"]; RETURN}; BEGIN IF walnut = NIL THEN -- walnut not running startPos_ InitializeLog[walnutLogName] -- set up WalnutDB & log ELSE { ChangeWalnutMenu[workingMenu]; MarkWalnutTransaction[]; -- get in a good state startPos_ LogLength[TRUE]; }; IF msName = NIL THEN msName_ "Active" ELSE IF ~DoCreateMsgSet[msName, FALSE, FALSE] THEN RETURN; defaultPrefix_ Rope.Cat["Categories: ", msName, "\n"]; fStream_ FileIO.Open[fName, read, oldOnly ! FileIO.OpenFailed => GOTO BadOpen]; Report["Reading messages from ", fName, "... "]; IF ~WalnutStream.ReadOldMailFile[fStream, defaultPrefix] THEN { fStream.Close[]; Report["There were problems reading ", fName]; Report["Bug Confirm to keep messages successfully read, Deny to throw them away"]; IF ~UserConfirmed[] THEN { ResetLogToExpectedLength[]; RETURN}; }; fStream.Close[]; numNew_ GetMessagesFromLog[startPos]; IF numNew = 0 THEN Report[" No messages in ", fName, " were new"] ELSE Report[IO.PutFR[ "%g new messages from %g were added to database", IO.int[numNew], IO.rope[fName]]]; IF walnut = NIL THEN { MarkWalnutTransaction[]; CloseLogStream[]}; EXITS BadOpen => Report["Can't open ", fName, "\n"]; END; IF walnut # NIL THEN ChangeWalnutMenu[walnutMenu]; END; -- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * SizeOfMsgSetButtonProc: PUBLIC Buttons.ButtonProc = { MBQueue.QueueClientAction [walnutQueue, SizeOfMsgSetProc, ViewerTools.GetContents[msgSetText]]; }; SizeOfMsgSetProc: PROC[data: REF ANY] = BEGIN msName: ROPE _ NARROW[data]; msgSet: MsgSet; num: INT; IF msName.Length[] = 0 THEN {Report["No MsgSet specified"]; RETURN}; IF msName.Find[" "] >=0 THEN {Report[" MsgSet names may not contain spaces"]; RETURN}; msgSet_ DeclareMsgSet[msName, OldOnly].msgSet; IF msgSet = NIL THEN {Report["MsgSet: ", msName, " doesn't exist"]; RETURN}; num_ NumInMsgSet[msgSet]; Report[IO.PutFR[" %g msgs in MsgSet %g", IO.int[num], IO.rope[msName]]]; END; -- * * * * * * * * * * CreateMsgSetButtonProc: PUBLIC Buttons.ButtonProc = { MBQueue.QueueClientAction [walnutQueue, CreateMsgSetProc, ViewerTools.GetContents[msgSetText]]; }; CreateMsgSetProc: PROC[data: REF ANY] = BEGIN msName: ROPE_ NARROW[data]; []_ DoCreateMsgSet[msName, TRUE, TRUE]; END; DoCreateMsgSet: PROC[msName: ROPE, doReport, select: BOOL] RETURNS[nameOK: BOOL] = BEGIN msgSet: MsgSet; existed: BOOL; IF msName.Length[] = 0 THEN { Report["No MsgSet specified"]; RETURN[FALSE]}; -- get the entity IF msName.Find[" "] >=0 THEN { Report[" MsgSet names may not contain spaces"]; RETURN[FALSE]}; [msgSet, existed]_ DeclareMsgSet[msName]; IF existed THEN {IF doReport THEN Report["MsgSet: ", msName, " already exists"]} ELSE { WalnutLog.LogCreateMsgSet[msName]; []_ AddMsgSetButton[msgSet, msName, select]; }; RETURN[TRUE]; END; -- * * * * * * * * * * DeleteMsgSetButtonProc: PUBLIC Buttons.ButtonProc = {MBQueue.QueueClientAction [walnutQueue, DeleteMsgSetProc, ViewerTools.GetContents[msgSetText]]; }; DeleteMsgSetProc: PROC[data: REF ANY] = BEGIN msgSet: Entity; msName: ROPE _ NARROW[data]; IF msName.Length[] = 0 THEN { Report["No MsgSet specified"]; RETURN}; -- get the entity msgSet_ DeclareMsgSet[msName, OldOnly].msgSet; -- NIL if not found IF EqEntities[msgSet, activeMsgSet] OR EqEntities[msgSet, deletedMsgSet] THEN { Report[" Can't delete MsgSet: ", msName]; RETURN}; IF DB.Null[msgSet] THEN { Report[msName, " MsgSet doesn't exist"]; RETURN}; IF NumInMsgSet[msgSet] # 0 THEN { Report[" Confirm deletion of messages in MsgSet: ", msName]; IF ~UserConfirmed[] THEN {ChangeWalnutMenu[walnutMenu]; RETURN} }; ChangeWalnutMenu[workingMenu]; WalnutLog.LogDestroyMsgSet[msName]; DeleteMsgSetButton[msgSet]; []_ DestroyMsgSet[msgSet]; ChangeWalnutMenu[walnutMenu]; END; -- * * * * * * * * * * ArchiveButtonProc: PUBLIC Buttons.ButtonProc = BEGIN fileName: ROPE _ ViewerTools.GetContents[fileNameText]; msgSetList: LIST OF MsgSet_ GetSelectedMsgSets[]; MBQueue.QueueClientAction[q: walnutQueue, proc: ArchiveProc, data: NEW[ArchiveDataObj_ [fileName, msgSetList]]]; END; ArchiveData: TYPE = REF ArchiveDataObj; ArchiveDataObj: TYPE = RECORD[fName: ROPE, mL: LIST OF MsgSet]; ArchiveProc: PROC[data: REF ANY] = BEGIN num: INT_ 0; strm: IO.STREAM; archiveData: ArchiveData_ NARROW[data]; fileName: ROPE_ archiveData.fName; msgSetList: LIST OF MsgSet_ archiveData.mL; newRelList: LIST OF Relship_ NIL; -- no used for now msgSet: MsgSet; IF fileName.Length[] = 0 THEN { Report["No Archive file specified"]; RETURN}; IF msgSetList = NIL THEN { Report["No selected MsgSet(s) to archive"]; RETURN}; -- make sure didn't specify same name as log file IF fileName.Find["."] < 0 THEN { fileName_ fileName.Concat[".ArchiveLog"]; ViewerTools.SetContents[fileNameText, fileName] }; IF Rope.Equal[fileName, walnutLogName, FALSE] THEN { Report["Can't archive on log file"]; RETURN}; ChangeWalnutMenu[workingMenu]; strm_ FileIO.Open[fileName, write]; ReportRope["Archiving the MsgSet(s): "]; FOR mL: LIST OF MsgSet_ msgSetList, mL.rest UNTIL mL = NIL DO ReportRope[GetName[msgSet_ mL.first]]; ReportRope[" "]; num_ num + NumInMsgSet[msgSet]; newRelList_ ArchiveMsgSet[msgSet: msgSet, strm: strm, doDelete: FALSE]; ENDLOOP; strm.Close[]; Report[IO.PutFR["\n %g messages archived on file: %g", IO.int[num], IO.rope[fileName]]]; ChangeWalnutMenu[walnutMenu]; END; -- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * DestroyAllMsgSetButtons: PROC = BEGIN selectedMsgSetButtons_ NIL; FOR msb: MsgSetButton_ firstMsgSetButton, msb.next UNTIL msb=NIL DO ViewerOps.DestroyViewer[msb.selector, FALSE]; ENDLOOP; firstMsgSetButton_ lastMsgSetButton_ NIL; ViewerOps.MoveViewer[walnutRulerAfter, walnutRulerAfter.wx, walnutRulerBefore.wy+walnutRulerBefore.wh+14+1, walnutRulerAfter.ww, walnutRulerAfter.wh, FALSE]; ViewerOps.MoveViewer[walnutTS, walnutTS.wx, walnutRulerAfter.wy+walnutRulerAfter.wh+1, walnutTS.ww, walnutTS.wh, FALSE]; ViewerOps.PaintViewer[walnut, client]; END; -- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -- start code Commander.Register["WalnutScavenge", WalnutScavenge, "Rebuilds Mail database from log file"]; Commander.Register["WalnutOldMailReader", WalnutReadMailFile, "Reads Laurel, Hardy or Archive files into Mail database"]; Commander.Register["WalnutExpunge", WalnutExpunge, "Expunges deleted messages"]; Commander.Register["WalnutDump", WalnutDump, "Writes an expunged log file on Walnut.TempLog; does not change database"]; Commander.Register["WalnutNewMail", WalnutNewMail, "Retrieves new mail"]; END. Ê]˜Jš•Ïckœ4œ)œÏk œ žœžœ,žœ žœ%žœ,žœ Ïnœž œžœ2žœ‚žœžœžœžœžœœžRœžœžœ%žœžœ žœžœ ž œŸ œžœžœžœžœžœžœžœžœFœžœžœžœžœžœ>žœžœ)Ÿœžœžœ žœžœžœžœžœŸ œž œžœžœžœžœžœžœžœžœžœžœžœžœŸ œž œžœžœ žœžœ!žœžœBžœŸžœžœžœQžœžœ žœ5žœ žœ˜žœRœŸœžœžœžœ žœžœˆžœcžœdžœžœŸ œž œžœžœžœžœžœžœžœ+žœžœžœžœŸ œž œ žœ žœžœžœžœžœžœžœžœ žœžœ<(œžœzžœœžœ žœ2žœ‰žœ žœžœžœœžœžœRœŸ œžœžœžœ žœžœžœŸœžœžœžœ žœžœžœœžœGžœŸœž œžœžœž œžœžœžœ`žœžœžœŸ œž œžœ žœžœžœ5žœžœ žœ$žœžœ žœ:žœ,Ÿœžœ žœžœ žœžœžœ žœ žœžœžœ>žœžœžœžœ$žœCžœ žœžœžœ žœžœžœHžœ žœžœžœžœ žœžœžœJžœžœžœžœžœ(žœžœžœžœ*žœ8žœžœžœQžœžœžœ žœ,Ÿ œžœžœžœ žœžœœ6žœžœžœžœŸœžœžœžœžœ*œ žœžœžœ`œÇžœžœžœ?žœ„žœŸœžœžœžœžœžœžœžœžœ žœžœKžœ žœžœžœ-Ÿ œžœžœžœžœžœžœžœžœžœžœžœ žœ0žœŸœž œžœžœžœžœžœžœžœžœžœžœžœ žœ%žœžœžœŸœžœžœžœžœžœžœžœ žœžœžœ žœžœžœ žœžœ1žœžœžœ žœžœœ+œžœBœžœ žœ žœžœžœžœžœžœžœžœ~žœ@žœ7žœ¦žœžœžœJžœ žœ3žœžœ>žœžœžœ žœžœ5žœ6žœžœ žœžœ!žœRœŸœžœƒŸœžœžœžœžœ žœžœ%žœžœžœ!žœžœžœ7žœ;žœ žœžœ0žœ œžœBžœŸœžœƒŸœžœžœžœžœ žœžœ$žœžœžœŸœžœ žœžœžœ žœžœ žœžœžœ'žœžœœžœžœ8žœžœ6žœ žœžœ žœ5žœ`œ žœžœžœŸœžœ‚Ÿœžœžœžœžœ!žœžœ žœžœ'žœœ4œžœ"žœ#žœ2žœžœžœžœ1žœžœžœGžœžœ"žœ§žœŸœžœžœ žœ7žœžœfžœ-žœŸ œžœžœŸœžœžœžœžœžœ Ÿ œžœžœžœžœžœ žœžœžœžœ"žœžœ&žœžœ žœœžœžœ-žœžœžœžœ1žœ2œžœžœižœ%žœžœ*žœužœžœžœžœžœžœŸžœžœžœ.žœ žœ4žœSœŸœžœžœžœžœ0žœžœžœ)žœžœ(žœžœyžœ-žœSœžœ˜¡v—…—;$C‡