<<>> <> <> <> <> <> <> <> <> <> <> DIRECTORY <> BasicTime USING [Now], Containers, Icons USING [IconFlavor], FS USING [Error, OpenFile, Create, SetKeep, StreamFromOpenFile], IO, Labels USING [Set], MailUtils USING [Credentials, GetUserCredentials], Menus, MessageWindow USING [Append], Process USING [Detach, Pause, SecondsToTicks], Rope, SendMailOps USING [RegisterReporter, <> UnregisterReporter], TypeScript USING [Create], UserProfile USING [Boolean], ViewerClasses USING [Viewer], ViewerOps, ViewerIO USING [CreateViewerStreams], ViewerSpecs, WalnutDefs USING [CheckReportProc, Error], WalnutOps USING [AcceptNewMail, ActiveName, GetNewMail, RecordNewMailInfo, RegisterReporter, ServerInfo, StartNewMail, UnregisterReporter, WalnutOpsHandle], WalnutNewMail USING [DisableMailRetrieval, EnableMailRetrieval], WalnutInternal USING [AddNewMsgsToActive, ChangeMenu, CloseDownWalnut, DoWaitCall, FixUpWalnutViewers, GetButton, MailState, QDisplayMsg, QDisplayMsgSet, ShowMsgSetButtons, WaitCallOutcome, workingMenu], WalnutWindowPrivate USING [IconState, MsgAndHandle, MsgSetButton, MsgSetInfo, WalnutHandle, WalnutHandleRec], WalnutWindow USING [GetHandleForMail, OutCome]; WalnutWindowInternalImpl: CEDAR PROGRAM IMPORTS <> BasicTime, Labels, MailUtils, MessageWindow, FS, IO, Process, <> SendMailOps, UserProfile, TypeScript, ViewerOps, ViewerIO, WalnutDefs, WalnutOps, WalnutNewMail, WalnutInternal, WalnutWindow EXPORTS WalnutInternal, WalnutWindow = BEGIN OPEN WalnutInternal; ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; Viewer: TYPE = ViewerClasses.Viewer; WalnutHandle: TYPE = WalnutWindowPrivate.WalnutHandle; WalnutHandleRec: PUBLIC TYPE = WalnutWindowPrivate.WalnutHandleRec; MsgSetButton: TYPE = WalnutWindowPrivate.MsgSetButton; MsgSetInfo: TYPE = WalnutWindowPrivate.MsgSetInfo; MsgAndHandle: TYPE = WalnutWindowPrivate.MsgAndHandle; crTimeToFlushCount: CARDINAL ¬ 3; timeToFlushCount: CARDINAL ¬ 10; <<* * * * * * * * * * * * exported to WalnutWindow>> ReportFormat: PUBLIC PROC[wH: WalnutHandle, format: ROPE ¬ NIL, v1, v2, v3, v4, v5: IO.Value ¬ [null[]] ] = { IF wH.wtsOut # NIL THEN wH.wtsOut.PutFL[format, LIST[v1, v2, v3, v4, v5]] }; Report: PUBLIC PROC[wH: WalnutHandle, msg1, msg2, msg3: ROPE ¬ NIL] = { ReportRope[wH, msg1, msg2, msg3]; IF wH.wtsOut = NIL THEN RETURN; wH.wtsOut.PutChar['\n]; IF (wH.crCount ¬ wH.crCount + 1) > crTimeToFlushCount THEN { wH.wtsOut.Flush[]; wH.reportCount ¬ wH.crCount ¬ 0; }; IF (wH.reportCount ¬ wH.reportCount + 1) > timeToFlushCount THEN { wH.wtsOut.Flush[]; wH.reportCount ¬ wH.crCount ¬ 0; }; }; ReportRope: PUBLIC PROC[wH: WalnutHandle, msg1, msg2, msg3: ROPE ¬ NIL] = { IF wH.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 wH.wtsOut.PutRope[msg1]; IF msg2#NIL THEN wH.wtsOut.PutRope[msg2]; IF msg3#NIL THEN wH.wtsOut.PutRope[msg3]; }; DisplayMsg: PUBLIC PROC[wH: WalnutHandle, msg: ROPE, oldV: Viewer, shift, paint: BOOL] RETURNS[v: Viewer] = { Dm: PROC = { -- don't open if iconic v ¬ QDisplayMsg[wH: wH, msg: msg, oldV: oldV, shift: shift, openIfIconic: FALSE, paint: paint] }; [] ¬ DoWaitCall[wH, Dm]; }; DisplayMsgSet: PUBLIC PROC[wH: WalnutHandle, msgSet: ROPE, shift, repaint: BOOL] RETURNS[v: Viewer] = { Dms: PROC = { v ¬ QDisplayMsgSet[wH, GetButton[wH, msgSet], NIL, shift, repaint]; }; [] ¬ DoWaitCall[wH, Dms]; }; CurrentVersion: PUBLIC PROC[wH: WalnutHandle, msName: ROPE] RETURNS[version: INT ¬ 0] = { Dms: PROC = { version ¬ GetButton[wH, msName].msgSet.version }; [] ¬ DoWaitCall[wH, Dms] }; QueueCall: PUBLIC PROC[ wH: WalnutHandle, proc: PROC[wH: WalnutHandle] RETURNS[doReset: BOOL]] RETURNS[outCome: WalnutWindow.OutCome] = { Qc: PROC = { IF ~proc[wH] THEN RETURN; ShowMsgSetButtons[wH]; FixUpWalnutViewers[wH]; }; outCome ¬ DoWaitCall[wH, Qc]; }; Shutdown: PUBLIC PROC[wH: WalnutHandle] = { Sd: PROC = { [] ¬ CloseDownWalnut[wH] }; [] ¬ DoWaitCall[wH, Sd]; }; <<* * * * * * * * * * * * exported to WalnutWindow>> GetNewMail: PUBLIC PROC[wH: WalnutHandle] = { Rnm: PROC = { ENABLE UNWIND => { ChangeMenu[wH, wH.walnutMenu, FALSE] }; responses: LIST OF WalnutOps.ServerInfo; complete: BOOL; numNew, total: INT ¬ 0; msB: MsgSetButton ¬ GetButton[wH, WalnutOps.ActiveName]; ChangeMenu[wH, workingMenu, TRUE]; IF msB.msViewer # NIL THEN IF msB.msViewer.destroyed THEN msB.msViewer ¬ NIL; IF msB.msViewer = NIL THEN { -- not displayed [responses, complete] ¬ WalnutOps.GetNewMail[wH.opsH, msB.msgSet.version, NIL]; numNew ¬ -1; WalnutOps.AcceptNewMail[wH.opsH, msB.msgSet.version]; } ELSE [responses, complete, numNew] ¬ AddNewMsgsToActive[msB]; IF ~complete THEN { Report[wH, " There were problems with GetNewMail - some messages not available; try again"]; ChangeMenu[wH, wH.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[wH, "No messages were on the newMailLog"] ELSE { FOR rL: LIST OF WalnutOps.ServerInfo ¬ responses, rL.rest UNTIL rL = NIL DO ReportRope[wH, rL.first.server]; IF rL.first.num = 0 THEN Report[wH, " ... empty"] ELSE { IF rL.first.num = 1 THEN Report[wH, " delivered 1 message"] ELSE ReportFormat[wH, " delivered %g messages\n", [integer[rL.first.num]] ]; }; ENDLOOP; IF (numNew >= 0) AND (total # numNew) THEN { IF numNew = 0 THEN Report[wH, "\nNo new messages added to database"] ELSE ReportFormat[wH, "\nOnly %g messages were new", [integer[numNew]] ]; }; }; <<-- XXX Don't put the flag down if the active msg set is iconic>> IF msB.msViewer # NIL THEN IF ( NOT msB.msViewer.iconic ) OR ( NOT UserProfile.Boolean[key: "Walnut.AutoNewMail", default: FALSE] ) THEN IF wH.personalMailDB THEN SetMailState[wH, noMail]; ChangeMenu[wH, wH.walnutMenu, FALSE]; }; [] ¬ DoWaitCall[wH, Rnm]; }; EnableNewMail: PUBLIC PROC[wH: WalnutHandle] = { gvMail: BOOL ~ UserProfile.Boolean["Walnut.gvMail", TRUE]; xnsMail: BOOL ~ UserProfile.Boolean["Walnut.xnsMail", TRUE]; progress: BOOL = UserProfile.Boolean[key: "Walnut.ReportNewMailProgress", default: FALSE]; progressLog: ROPE = "/tmp/WalnutNewMailProgress.log"; <> credentials: LIST OF MailUtils.Credentials ¬ MailUtils.GetUserCredentials[ SELECT TRUE FROM ( gvMail AND xnsMail ) => NIL, gvMail => $gv, xnsMail => $xns, ENDCASE => $xns]; FS.SetKeep[progressLog, 5 ! FS.Error => CONTINUE]; IF wH.newMailRetrievalStream = NIL THEN IF progress THEN { wH.newMailRetrievalViewer ¬ TypeScript.Create[ info: [name: "NewMail Retrieval", iconic: FALSE, column: right, openHeight: 64], paint: FALSE]; ViewerOps.TopViewer[viewer: wH.newMailRetrievalViewer, paint: TRUE]; wH.newMailRetrievalViewer.inhibitDestroy ¬ TRUE; wH.newMailRetrievalStream ¬ ViewerIO.CreateViewerStreams[ name: NIL, viewer: wH.newMailRetrievalViewer, backingFile: progressLog].out; } ELSE { of: FS.OpenFile = FS.Create[progressLog, TRUE, 2, TRUE, 5]; wH.newMailRetrievalStream ¬ FS.StreamFromOpenFile[of, $write]; }; WalnutNewMail.EnableMailRetrieval[ opsHandle: wH.opsH, registeredUsers: credentials, reportProc: ReportProc, progressProc: ProgressReport, getMailLog: GetMailLog, recordMailInfo: RecordNewMailInfo, notifyWhenMailRetrieved: NotifyWhenMailRetrieved]; IF wH.newMailRetrievalViewer # NIL THEN wH.newMailRetrievalViewer.inhibitDestroy ¬ FALSE; }; DisableNewMail: PUBLIC PROC[wH: WalnutHandle] = { IF NOT wH.personalMailDB THEN RETURN; WalnutNewMail.DisableMailRetrieval[wH.opsH]; IF wH.newMailRetrievalStream # NIL THEN { IF wH.newMailRetrievalViewer = NIL THEN wH.newMailRetrievalStream.Close[] ELSE IF ~wH.newMailRetrievalViewer.destroyed THEN { wH.newMailRetrievalStream.Close[]; ViewerOps.DestroyViewer[wH.newMailRetrievalViewer]; }; wH.newMailRetrievalStream ¬ NIL; wH.newMailRetrievalViewer ¬ NIL; wH.personalMailDB ¬ FALSE; }; }; tempName: ROPE = "/tmp/Walnut.TypescriptLog"; OpenTS: PUBLIC PROC[wH: WalnutHandle, r: ROPE, doRegister: BOOL] = { <> logName: ROPE = tempName; FS.SetKeep[logName, 7 ! FS.Error => CONTINUE]; -- if tsLogName doesn't exist IF wH.wtsOut = NIL THEN { wH.wtsOut ¬ ViewerIO.CreateViewerStreams[NIL, wH.walnutTS, logName].out; IF r # NIL THEN wH.wtsOut.PutRope[r]; IF doRegister THEN { SendMailOps.RegisterReporter[wH.wtsOut]; WalnutOps.RegisterReporter[wH.opsH, wH.wtsOut]; }; }; }; CloseTS: PUBLIC PROC[wH: WalnutHandle] = { IF wH.wtsOut # NIL THEN wH.wtsOut.Close[]; SendMailOps.UnregisterReporter[wH.wtsOut]; WalnutOps.UnregisterReporter[wH.opsH, wH.wtsOut]; wH.wtsOut ¬ NIL; }; GetWalnutViewers: PUBLIC PROC[wH: WalnutHandle] RETURNS [msgSetList, msgList, wallabyList: LIST OF Viewer] = { RETURN[wH.msgSetViewerList, wH.msgViewerList, wH.wallabyViewerList]; }; TakeDownWalnutViewers: PUBLIC PROC[wH: WalnutHandle] = { FOR vL: LIST OF Viewer ¬ wH.msgViewerList, vL.rest UNTIL vL=NIL DO IF NOT vL.first.destroyed AND ViewerOps.FetchProp[vL.first, $Frozen] = NIL THEN ViewerOps.DestroyViewer[vL.first]; vL.first ¬ NIL; ENDLOOP; FOR vL: LIST OF Viewer ¬ wH.msgSetViewerList, vL.rest UNTIL vL=NIL DO IF NOT vL.first.destroyed THEN ViewerOps.DestroyViewer[vL.first]; vL.first ¬ NIL; ENDLOOP; FOR vL: LIST OF Viewer ¬ wH.wallabyViewerList, vL.rest UNTIL vL=NIL DO IF NOT vL.first.destroyed THEN ViewerOps.DestroyViewer[vL.first]; vL.first ¬ NIL; ENDLOOP; wH.msgViewerList ¬ NIL; wH.msgSetViewerList ¬ NIL; wH.wallabyViewerList ¬ NIL; }; <<>> <<* * * * * * * * * * support for new mail>> newMailCount: CARDINAL ¬ 0; newMailProgressTimeToFlush: CARDINAL ¬ 10; ReportProc: WalnutDefs.CheckReportProc = { wH: WalnutHandle = CheckMailHandle[opsH]; IF wH # NIL THEN ReportFormat[wH, format, v1, v2, v2]; }; ProgressReport: WalnutDefs.CheckReportProc = { wH: WalnutHandle = CheckMailHandle[opsH]; IF wH = NIL THEN RETURN; IF wH.newMailRetrievalViewer # NIL THEN IF wH.newMailRetrievalViewer.destroyed THEN { wH.newMailRetrievalViewer ¬ NIL; wH.newMailRetrievalStream ¬ NIL; }; IF wH.newMailRetrievalStream # NIL THEN { wH.newMailRetrievalStream.PutF[format, v1, v2, v3]; IF (newMailCount ¬ newMailCount + 1) > newMailProgressTimeToFlush THEN { newMailCount ¬ 0; wH.newMailRetrievalStream.Flush[]; }; }; }; GetMailLog: PROC[opsHandle: WalnutOps.WalnutOpsHandle] RETURNS[strm: STREAM] = { wH: WalnutHandle = CheckMailHandle[opsHandle]; outcome: WaitCallOutcome; Gml: PROC = { strm ¬ WalnutOps.StartNewMail[opsHandle] }; IF wH = NIL THEN RETURN; IF (outcome ¬ DoWaitCall[wH, Gml]) = ok THEN { SetMailState[wH, retrieving]; RETURN; }; IF outcome = notRunning THEN Process.Pause[Process.SecondsToTicks[10]]; outcome ¬ DoWaitCall[wH, Gml]; -- try again IF outcome = ok THEN SetMailState[wH, retrieving]; }; RecordNewMailInfo: PROC[opsHandle: WalnutOps.WalnutOpsHandle, logLen: INT, server: ROPE, num: INT] RETURNS[ok: BOOL ¬ FALSE] = { wH: WalnutHandle = CheckMailHandle[opsHandle]; Rnml: PROC = { ok ¬ FALSE; WalnutOps.RecordNewMailInfo[opsHandle, logLen, server, num]; ok ¬ TRUE; }; IF wH = NIL THEN RETURN[FALSE]; IF wH.opsH # opsHandle THEN ERROR WalnutDefs.Error[$control, $WrongOpsHandle, "RecordNewMailInfo"]; [] ¬ DoWaitCall[wH, Rnml]; }; CheckMailHandle: PROC[opsH: WalnutOps.WalnutOpsHandle] RETURNS[wH: WalnutHandle] = { wH ¬ WalnutWindow.GetHandleForMail[]; IF wH = NIL THEN RETURN; IF wH.opsH # opsH THEN ERROR WalnutDefs.Error[$control, $WrongOpsHandle]; }; NotifyWhenMailRetrieved: PROC[opsHandle: WalnutOps.WalnutOpsHandle, ok: BOOL, someMail: BOOL] = { autoNewMail: BOOL; wH: WalnutHandle = CheckMailHandle[opsHandle]; IF wH = NIL OR ~wH.personalMailDB THEN RETURN; IF ~(wH.someMail ¬ someMail) THEN { SetMailState[wH, noMail]; RETURN}; SetMailState[wH, thereIsMail]; autoNewMail ¬ UserProfile.Boolean[key: "Walnut.AutoNewMail", default: FALSE]; IF autoNewMail THEN TRUSTED { Process.Detach[FORK GetNewMail[wH] ] }; }; SetMailState: PUBLIC PROC[wH: WalnutHandle, mailState: MailState] = { status: ROPE; iconState: WalnutWindowPrivate.IconState ¬ regular; IF wH.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 => { iconState ¬ haveNewMail; status ¬ "You have new mail at %g"; }; waiting => status ¬ "Waiting (10 sec) for initial mail server response at %g"; noState => status ¬ "No mailbox state reported at %g"; noServers => status ¬ "All of the mail servers are down at %g"; someMail => status ¬ "Mail on some server(s) at %g"; ENDCASE => NULL; IF wH.whichIcon # iconState THEN { wH.walnut.icon ¬ wH.iconSet[wH.whichIcon ¬ iconState]; IF wH.walnut.iconic THEN ViewerOps.PaintViewer[wH.walnut, all]; }; Labels.Set[wH.mailNotifyLabel, IO.PutFR1[status, [time[BasicTime.Now[]]]] ]; }; END.