<<>> <> <> <> <> <> <> <> <<>> <> <> <> <> <<(Changed StripForIcon to remove all registry information from icon labels)>> <> <> DIRECTORY Ascii USING [ Letter ], Atom USING [ GetPName ], IO, MailSend USING [ GetRegisteredSendProcsList, MailSendProcsRef], Menus, PopUpSelection USING [Request], Rope, SendMailOps USING [Answer, CreateRopeForTextNode, CreateSendViewer, Forward, ReSend], TEditSplit USING[ Split ], TEditDocument USING [TEditDocumentData, maxClip], TiogaOps USING [CancelSelection, GetSelection, RestoreSelB, SaveSelB, SelectDocument, SetStyle, ViewerDoc], TiogaMenuOps USING[ tiogaMenu, AllLevels ], UserProfile USING [Boolean, ListOfTokens, Token], ViewerClasses USING [Viewer], ViewerEvents USING [ EventRegistration, EventProc, ViewerEvent, RegisterEventProc, UnRegisterEventProc ], ViewerLocks USING[ CallUnderWriteLock ], ViewerOps USING [AddProp, CreateViewer, DestroyViewer, FetchProp, GrowViewer, OpenIcon, PaintViewer, SetMenu, SetNewVersion], ViewerTools USING [TiogaContents, EnableUserEdits, InhibitUserEdits, SetTiogaContents], WalnutFilter USING [MenuExtras], WalnutOps USING [MsgSet, GetCategories, GetMsgSize, GetMsgShortName, GetMsg, MsgExists], WalnutViewer USING [CreateMenuEntry], WalnutInternal USING [AddorAppendTo, DoWaitCall, GetButton, HowToPrint, msgIcon, MsgPrintProc, RemoveFrom], WalnutWindow USING [GetHandleList, GetRootFileForHandle, Report, ReportFormat, ReportRope], WalnutWindowPrivate USING [MsgAndHandle, MsgAndHandleRec, MsgSetButton, WalnutHandle, WalnutHandleRec]; WalnutMsgDisplayerImpl: CEDAR MONITOR IMPORTS Ascii, Atom, MailSend, PopUpSelection, Rope, SendMailOps, TiogaMenuOps, TiogaOps, TEditSplit, Menus, UserProfile, ViewerEvents, ViewerLocks, ViewerOps, ViewerTools, WalnutFilter, WalnutOps, WalnutInternal, WalnutViewer, WalnutWindow EXPORTS WalnutInternal, WalnutWindow SHARES ViewerClasses = BEGIN OPEN WalnutInternal; ROPE: TYPE = Rope.ROPE; TiogaContents: TYPE = ViewerTools.TiogaContents; Viewer: TYPE = ViewerClasses.Viewer; MsgSet: TYPE = WalnutOps.MsgSet; MsgSetButton: TYPE = WalnutWindowPrivate.MsgSetButton; WalnutHandle: TYPE = WalnutWindowPrivate.WalnutHandle; WalnutHandleRec: PUBLIC TYPE = WalnutWindowPrivate.WalnutHandleRec; MsgAndHandle: TYPE = WalnutWindowPrivate.MsgAndHandle; MsgAndHandleRec: TYPE = WalnutWindowPrivate.MsgAndHandleRec; pruneHeaders: BOOLEAN ¬ UserProfile.Boolean["Walnut.PruneHeaders", FALSE]; unprunedHeaders: LIST OF ROPE ¬ UserProfile.ListOfTokens["Walnut.UnprunedHeaders", LIST["subject", "from", "to", "cc", "date"]]; <<-------------------------->> <> GetMsgName: PUBLIC PROC[v: Viewer] RETURNS[mName: ROPE, rootFile: ROPE] = { <> msgAndWH: MsgAndHandle = NARROW[ViewerOps.FetchProp[v, $WalnutMsgName]]; IF msgAndWH = NIL THEN RETURN; rootFile ¬ WalnutWindow.GetRootFileForHandle[msgAndWH.wH]; RETURN[msgAndWH.msg, rootFile]; }; InternalAddToMsgMenu: PUBLIC PROC[wH: WalnutHandle, label: ROPE, proc: Menus.MenuProc, clientData: REF ANY ¬ NIL, onQueue: BOOL] = { FOR wHL: LIST OF WalnutHandle ¬ (IF wH # NIL THEN LIST[wH] ELSE WalnutWindow.GetHandleList[]), wHL.rest UNTIL wHL = NIL DO new: Menus.MenuEntry = IF onQueue THEN WalnutViewer.CreateMenuEntry[wHL.first.walnutQueue, label, proc, clientData] ELSE Menus.CreateEntry[label, proc, clientData]; Menus.AppendMenuEntry[wHL.first.msgMenu, new]; Menus.AppendMenuEntry[wHL.first.frozenMsgMenu, Menus.CopyEntry[new]]; ChangeMsgMenus[wHL.first]; ENDLOOP; }; InternalReplaceInMsgMenu: PUBLIC PROC[wH: WalnutHandle, label: ROPE, proc: Menus.MenuProc, clientData: REF ANY ¬ NIL, onQueue: BOOL] RETURNS[oldFound: BOOL] = { DoReplace: PROC[thisMenu: Menus.Menu] RETURNS[foundIt: BOOL ¬ TRUE]= { old: Menus.MenuEntry = Menus.FindEntry[thisMenu, label]; new: Menus.MenuEntry = IF onQueue THEN WalnutViewer.CreateMenuEntry[wH.walnutQueue, label, proc, clientData] ELSE Menus.CreateEntry[label, proc, clientData]; Menus.ReplaceMenuEntry[thisMenu, old, new ! Menus.targetNotFound => { foundIt ¬ FALSE ; CONTINUE }]; IF NOT foundIt THEN Menus.AppendMenuEntry[thisMenu, new]; }; FOR wHL: LIST OF WalnutHandle ¬ (IF wH # NIL THEN LIST[wH] ELSE WalnutWindow.GetHandleList[]), wHL.rest UNTIL wHL = NIL DO old: Menus.MenuEntry = Menus.FindEntry[wH.msgMenu, label]; thisFound: BOOL; oldFound ¬ DoReplace[wH.msgMenu]; thisFound ¬ DoReplace[wH.frozenMsgMenu]; oldFound ¬ thisFound AND oldFound; ChangeMsgMenus[wH]; ENDLOOP; }; RemoveFromMsgMenu: PUBLIC PROC[wH: WalnutHandle, name: ROPE] = { FOR wHL: LIST OF WalnutHandle ¬ (IF wH # NIL THEN LIST[wH] ELSE WalnutWindow.GetHandleList[]), wHL.rest UNTIL wHL = NIL DO old: Menus.MenuEntry ¬ Menus.FindEntry[wHL.first.msgMenu, name]; IF old # NIL THEN Menus.ReplaceMenuEntry[wHL.first.msgMenu, old ! Menus.targetNotFound => CONTINUE ]; old ¬ Menus.FindEntry[wHL.first.frozenMsgMenu, name]; IF old # NIL THEN Menus.ReplaceMenuEntry[wHL.first.frozenMsgMenu, old ! Menus.targetNotFound => CONTINUE ]; ChangeMsgMenus[wH]; ENDLOOP; }; <<* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *>> <<>> QDisplayMsg: PUBLIC PROC[wH: WalnutHandle, msg: ROPE, oldV: Viewer, shift, openIfIconic, paint: BOOL] RETURNS[v: Viewer] = { contents: TiogaContents; herald, shortName: ROPE; iconName, date: ROPE; maH: MsgAndHandle = NEW[MsgAndHandleRec ¬ [msg, wH]]; LockedSetMenu: PROC = { ViewerOps.SetMenu[v, wH.msgMenu]; IF UserProfile.Boolean["Walnut.MsgViewerPlaces", FALSE] THEN MsgPlacesProc[v, NIL, $red]; }; IF ~WalnutOps.MsgExists[wH.opsH, msg] THEN RETURN[NIL]; [contents, herald, shortName] ¬ WalnutOps.GetMsg[wH.opsH, msg]; contents ¬ PruneHeaderFields[contents]; herald ¬ wH.identifierPrefix.Concat[herald]; iconName ¬ Rope.Substr[shortName, 0, shortName.Length[] - 9]; date ¬ Rope.Substr[shortName, shortName.Length[] - 9]; IF oldV # NIL AND ~oldV.destroyed THEN { oldV.name ¬ herald; ViewerOps.PaintViewer[oldV, caption]; v ¬ oldV; } ELSE { v ¬ ViewerOps.CreateViewer[flavor: $Text, paint: paint, info: [name: herald, icon: msgIcon, scrollable: TRUE, iconic: FALSE] ]; wH.msgViewerList ¬ CONS[v, wH.msgViewerList]; ViewerLocks.CallUnderWriteLock[LockedSetMenu, v]; IF shift THEN ViewerOps.GrowViewer[v]; shift ¬ FALSE; -- so don't end up toggling the Grow ViewerOps.AddProp[v, $DestroyMsgDisplayer, ViewerEvents.RegisterEventProc[DestroyMsgDisplayer, destroy, v]]; }; ViewerOps.AddProp[v, $WalnutMsgName, maH ]; <<>> <> v.label ¬ Rope.Cat[wH.identifierPrefix, StripForIcon[iconName], " .", date]; ShowMsgInMsgViewer[v, contents, shift, openIfIconic, paint]; }; FixUpMsgViewer: PUBLIC PROC[wH: WalnutHandle, msg: ROPE, v: Viewer] = { IF (msg.Length[] = 0) OR v.destroyed THEN RETURN; IF QDisplayMsg[wH, msg, v, FALSE, TRUE, TRUE].v = NIL THEN { WalnutWindow.ReportFormat[wH, "Msg: %g doesn't exist; destroying viewer", [rope[msg]] ]; ViewerOps.DestroyViewer[v]; }; }; DisplayMsgFromMsgSet: PUBLIC PROC[wH: WalnutHandle, msg: ROPE, msViewer: Viewer, shift: BOOL] = { v: Viewer = NARROW[ViewerOps.FetchProp[msViewer, $LastSpawned]]; newV: Viewer; newV ¬ QDisplayMsg[wH, msg, v, shift, TRUE, TRUE]; IF newV = v THEN RETURN; ViewerOps.AddProp[newV, $WhoSpawnedMe, msViewer]; ViewerOps.AddProp[msViewer, $LastSpawned, newV]; }; <<***********************************************************>> <> MsgForwardProc: Menus.MenuProc = { self: Viewer ¬ NARROW[parent]; fw: Viewer; self.inhibitDestroy ¬ TRUE; fw ¬ SendMailOps.Forward[self, self]; IF UserProfile.Boolean["Walnut.EditedForwardSenders", FALSE] OR mouseButton = blue THEN ViewerOps.SetNewVersion[fw]; self.inhibitDestroy ¬ FALSE; }; MsgReSendProc: Menus.MenuProc = { self: Viewer ¬ NARROW[parent]; self.inhibitDestroy ¬ TRUE; [] ¬ SendMailOps.ReSend[self, self]; self.inhibitDestroy ¬ FALSE; }; MsgAnswerProc: Menus.MenuProc = { OPEN TiogaOps; self: Viewer ¬ NARROW[parent]; transport: ATOM ¬ NARROW[clientData]; ans: Viewer; msgR: ROPE; self.inhibitDestroy ¬ TRUE; TRUSTED { msgR ¬ SendMailOps.CreateRopeForTextNode[LOOPHOLE[ViewerDoc[self]]]}; ans ¬ SendMailOps.Answer[msgR, self, transport]; IF UserProfile.Boolean["Walnut.EditedAnswerSenders", FALSE] OR mouseButton = blue THEN ViewerOps.SetNewVersion[ans]; self.inhibitDestroy ¬ FALSE; }; MsgOpsProc: Menus.MenuProc = { ChoicesFromMenuEntry: PROC [me: Menus.MenuEntry] RETURNS [choices: LIST OF ROPE] ~ { l: LIST OF ROPE ¬ NIL; IF me = NIL THEN RETURN[NIL]; choices ¬ LIST[me.name]; me ¬ me.link; l ¬ choices; WHILE me # NIL DO l.rest ¬ LIST[me.name]; me ¬ me.link; l ¬ l.rest; ENDLOOP; }; ConcatLists: PROC [l1, l2: LIST OF ROPE] RETURNS [LIST OF ROPE] ~ { l: LIST OF ROPE ¬ l1; WHILE l.rest # NIL DO l ¬ l.rest; ENDLOOP; l.rest ¬ l2; RETURN[l1]; }; self: Viewer = NARROW[parent]; msgAndwH: MsgAndHandle = NARROW[ViewerOps.FetchProp[self, $WalnutMsgName]]; msg: ROPE = msgAndwH.msg; wH: WalnutHandle = msgAndwH.wH; choices: LIST OF ROPE ¬ LIST["Sender", "Categories", "AddTo", "Remove From ...", "SizeOf", "msgID", "Toggle Header Pruning", "Interpress2.0Print", "Interpress3.0Print", "MakeEditable"]; moreChoices: LIST OF ROPE; moreProcs: Menus.MenuEntry; which: INT; moreProcs ¬ WalnutFilter.MenuExtras[$msgops]; moreChoices ¬ ChoicesFromMenuEntry[moreProcs]; choices ¬ ConcatLists[choices, moreChoices]; which ¬ PopUpSelection.Request["MsgOps", choices]; SELECT which FROM 1 => [] ¬ SendMailOps.CreateSendViewer[fromExec: FALSE]; 2 => [] ¬ PopUpCategories[self, wH, msg]; -- Categories 3 => { -- AddTo mL: LIST OF ROPE = WalnutOps.GetCategories[wH.opsH, msg]; from: MsgSetButton = GetButton[wH, mL.first]; FOR mlx: MsgSetButton ¬ wH.selectedMsgSetButtons, mlx.selected UNTIL mlx = NIL DO AddorAppendTo[wH: wH, msg: msg, isAdd: TRUE, fromButton: from, toButton: mlx]; ENDLOOP; }; 4 => { -- Remove From ... mL: LIST OF ROPE; which: INT; from: ROPE; [which, mL] ¬ PopUpCategories[self, wH, msg]; IF which = 0 THEN RETURN; FOR i: INT IN [1..which] DO from ¬ mL.first; mL ¬ mL.rest; ENDLOOP; RemoveFrom[msg, GetButton[wH, from]]; }; 5 => { textLen, formatLen: INT; [textLen, formatLen] ¬ WalnutOps.GetMsgSize[wH.opsH, msg]; IF formatLen # 0 THEN WalnutWindow.ReportFormat[wH, "Formatted Msg \" %g\" has %g bytes of text\n", [rope[msg]], [integer[textLen]] ] ELSE WalnutWindow.ReportFormat[wH, "Msg \"%g\" has %g bytes of text\n", [rope[msg]], [integer[textLen]] ]; }; 6 => MsgGvId[wH, msg, mouseButton # red]; 7 => ToggleHeaderPruning[self, wH, msg]; 8 => MsgPrint[wH: wH, self: self, howToPrint: ip2]; 9 => MsgPrint[wH: wH, self: self, howToPrint: ip3]; 10 => { MsgFreezeProc[parent]; ViewerTools.EnableUserEdits[self]; }; ENDCASE => IF moreChoices # NIL THEN { i: INT ¬ 11; plist: Menus.MenuEntry ¬ moreProcs; WHILE i < which AND plist # NIL DO i ¬ i + 1; plist ¬ plist.link; ENDLOOP; IF i = which AND plist # NIL THEN plist.proc[parent, clientData, mouseButton, shift, control]; }; }; PopUpCategories: PROC[self: Viewer, wH: WalnutHandle, msg: ROPE] RETURNS[which: INT, mL: LIST OF ROPE] = { IF ViewerOps.FetchProp[self, $Frozen] # NIL AND ~WalnutOps.MsgExists[wH.opsH, msg] THEN { WalnutWindow.ReportFormat[wH, "Msg %g in a frozen viewer doesn't exist in this database", [rope[msg]] ]; RETURN[0, NIL] }; which ¬ PopUpSelection.Request["Categories", mL ¬ WalnutOps.GetCategories[wH.opsH, msg] ]; }; MsgFreezeProc: Menus.MenuProc = { self: Viewer = NARROW[parent]; msViewer: Viewer = NARROW[ViewerOps.FetchProp[self, $WhoSpawnedMe]]; frozen: Menus.MenuEntry = Menus.FindEntry[self.menu, "Freeze"]; IF frozen # NIL THEN FreezeViewer[self]; <> IF self.link # NIL THEN -- you are part of a split viewer FOR newV: Viewer ¬ self.link, newV.link UNTIL newV = self DO FreezeViewer[newV] ENDLOOP; <> IF msViewer # NIL THEN ViewerOps.AddProp[msViewer, $LastSpawned, NIL] }; FreezeViewer: PROC[ v: Viewer ] = { msgAndwH: MsgAndHandle = NARROW[ViewerOps.FetchProp[v, $WalnutMsgName]]; ViewerOps.AddProp[ v, $Frozen, v ]; ViewerOps.SetMenu[v, msgAndwH.wH.frozenMsgMenu]; }; MsgSplitProc: Menus.MenuProc = { self: Viewer = NARROW[parent]; newV: Viewer; frozen: REF ANY = ViewerOps.FetchProp[self, $Frozen]; TEditSplit.Split[self]; <> FOR newV ¬ self.link, newV.link UNTIL newV.link = self DO ENDLOOP; ViewerOps.AddProp[ newV, $WalnutMsgName, ViewerOps.FetchProp[self, $WalnutMsgName] ]; ViewerOps.AddProp[ newV, $WhoSpawnedMe, ViewerOps.FetchProp[ self, $WhoSpawnedMe ] ]; IF frozen # NIL THEN FreezeViewer[newV] ELSE ViewerOps.AddProp[ newV, $DestroyMsgDisplayer, ViewerEvents.RegisterEventProc[DestroyMsgDisplayer, destroy, newV] ]; newV.icon ¬ msgIcon; }; DestroyMsgDisplayer: ViewerEvents.EventProc = { eventProc: ViewerEvents.EventRegistration; next: Viewer = viewer.link; spawner: Viewer = NARROW[ ViewerOps.FetchProp[viewer, $WhoSpawnedMe] ]; IF ViewerOps.FetchProp[viewer, $Frozen] # NIL THEN RETURN; -- you're not involved IF spawner # NIL THEN ViewerOps.AddProp[ spawner, $LastSpawned, next ]; eventProc ¬ NARROW[ ViewerOps.FetchProp[viewer, $DestroyMsgDisplayer]]; ViewerEvents.UnRegisterEventProc[ eventProc, destroy]; }; MsgPlacesProc: Menus.MenuProc = Menus.CopyEntry[ Menus.FindEntry[ TiogaMenuOps.tiogaMenu, "Places" ] ].proc; MsgLevelsProc: Menus.MenuProc = Menus.CopyEntry[ Menus.FindEntry[ TiogaMenuOps.tiogaMenu, "Levels" ] ].proc; <<* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *>> MsgCategories: PUBLIC PROC[wH: WalnutHandle, msg: ROPE] = { Mc: PROC = { msL: LIST OF ROPE ¬ WalnutOps.GetCategories[wH.opsH, msg]; first: BOOL ¬ TRUE; shortName: ROPE = WalnutOps.GetMsgShortName[wH.opsH, msg]; WalnutWindow.ReportFormat[wH, " %g is in: ", [rope[shortName]] ]; IF msL = NIL THEN { WalnutWindow.Report[wH, "no MsgSets! This is a bug."]; RETURN }; FOR mL: LIST OF ROPE ¬ msL, mL.rest UNTIL mL=NIL DO IF first THEN first ¬ FALSE ELSE WalnutWindow.ReportRope[wH, ", "]; WalnutWindow.ReportRope[wH, mL.first]; ENDLOOP; WalnutWindow.ReportRope[wH, "\n"]; }; [] ¬ DoWaitCall[wH, Mc]; }; MsgGvId: PUBLIC PROC[wH: WalnutHandle, msg: ROPE, all: BOOL] = { Mg: PROC = { WalnutWindow.Report[wH, "gv postmark for msg is: ", msg]; }; [] ¬ DoWaitCall[wH, Mg]; }; MsgPrint: PROC[wH: WalnutHandle, self: Viewer, howToPrint: HowToPrint] = { Mp: PROC = { MsgPrintProc[wH, self, howToPrint] }; [] ¬ DoWaitCall[wH, Mp]; }; <<* * * * * * * * * * * * * * * * * * * * * * * * * * * *>> ChangeMsgMenus: PROC[wH: WalnutHandle] = { <<-- a menu was changed - update all msg viewers for wH>> FOR vL: LIST OF Viewer ¬ wH.msgViewerList, vL.rest UNTIL vL = NIL DO msgAndWH: MsgAndHandle; v: Viewer = vL.first; IF v.destroyed THEN LOOP; msgAndWH ¬ NARROW[ViewerOps.FetchProp[v, $WalnutMsgName]]; IF ViewerOps.FetchProp[v, $Frozen] = NIL THEN ViewerOps.SetMenu[v, wH.msgMenu] ELSE ViewerOps.SetMenu[v, wH.frozenMsgMenu]; ENDLOOP; }; plainTextStyle: PUBLIC ROPE ¬ UserProfile.Token[key: "Walnut.PlainTextStyle", default: "cedar"]; ShowMsgInMsgViewer: PROC[v: Viewer, contents: TiogaContents, shift, open, paint: BOOL] = { painted: BOOL ¬ FALSE; KillFeedbackSel[v]; IF v.link # NIL THEN DestroySplitMsgDisplayers[v]; <> BEGIN WITH v.data SELECT FROM tdd: TEditDocument.TEditDocumentData => IF tdd.clipLevel # TEditDocument.maxClip THEN painted ¬ TRUE ENDCASE; END; IF contents.formatting.IsEmpty[] AND NOT Rope.Equal[plainTextStyle, "cedar"] THEN { -- Plain Text ViewerTools.SetTiogaContents[v, contents, FALSE]; TiogaOps.SaveSelB[]; TiogaOps.SelectDocument[viewer: v, level: point]; TiogaOps.SetStyle[plainTextStyle, root]; v.newVersion ¬ FALSE; -- Is there a ``better'' way to do this? IF paint THEN ViewerOps.PaintViewer[v, all]; TiogaOps.RestoreSelB[]; } ELSE { -- Tioga formatted; needn't reset the style ViewerTools.SetTiogaContents[v, contents, NOT painted AND paint]; TiogaMenuOps.AllLevels[v]; }; ViewerTools.InhibitUserEdits[v]; IF v.iconic THEN { IF ~open THEN RETURN; ViewerOps.OpenIcon[v, shift] } ELSE IF shift THEN ViewerOps.GrowViewer[v] }; <> KillFeedbackSel: PROC[v: Viewer] = { OPEN TiogaOps; who: Viewer ¬ GetSelection[feedback].viewer; IF who = v THEN CancelSelection[feedback]; }; DestroySplitMsgDisplayers: ENTRY PROC[keepThisOne: Viewer] = { ENABLE UNWIND => NULL; next: Viewer ¬ keepThisOne.link; next2: Viewer; event: ViewerEvents.EventRegistration; DO IF next = keepThisOne THEN EXIT; IF (event ¬ NARROW[ViewerOps.FetchProp[next, $DestroyMsgDisplayer]]) = NIL THEN LOOP; ViewerEvents.UnRegisterEventProc[event, destroy]; next2 ¬ next.link; ViewerOps.DestroyViewer[next]; -- DON'T FORK here next ¬ next2; ENDLOOP; }; StripForIcon: PROC[name: ROPE] RETURNS[ iconLabel: ROPE ] = { start: INT; dot: INT; suffixLength: NAT; <> start ¬ 0; WHILE (dot ¬ Rope.Find[Rope.Substr[name, start], "."]) # -1 DO length: INT = Rope.Length[name]; dot ¬ dot+start; IF length - dot < 2 THEN EXIT; suffixLength ¬ 0; WHILE dot+1+suffixLength < length AND Ascii.Letter[Rope.Fetch[name, dot+1+suffixLength]] DO suffixLength ¬ suffixLength+1 ENDLOOP; IF suffixLength >= 0 THEN { name ¬ Rope.Replace[name, dot, suffixLength+1]; start ¬ dot } ELSE start ¬ dot+suffixLength+1 ENDLOOP; iconLabel ¬ Rope.Substr[name, 0, Rope.Length[name]-1] }; PruneHeaderFields: PROC [msg: TiogaContents] RETURNS [new: TiogaContents] ~ { <> <> start, end: INT; contents: ROPE ¬ msg.contents; keptHeader: BOOLEAN ¬ FALSE; IF NOT pruneHeaders OR NOT Rope.IsEmpty[msg.formatting] THEN RETURN[msg]; start ¬ 0; end ¬ Rope.SkipTo[s: contents, pos: start, skip: "\n\r\l"]; WHILE start < end DO -- while not end of header IF NOT (Rope.Fetch[contents, start] = ' OR Rope.Fetch[contents, start] = '\t) THEN { -- new header line (not continuation of previous header) keptHeader ¬ FALSE; FOR uphL: LIST OF ROPE _ unprunedHeaders, uphL.rest WHILE uphL # NIL AND keptHeader = FALSE DO IF Rope.IsPrefix[prefix: uphL.first, subject: Rope.Substr[contents, start], case: FALSE] THEN keptHeader ¬ TRUE; ENDLOOP; }; IF NOT keptHeader THEN contents ¬ Rope.Replace[base: contents, start: start, len: end-start+1, with: NIL] ELSE start ¬ end + 1; end ¬ Rope.SkipTo[s: contents, pos: start, skip: "\n\r\l"]; ENDLOOP; msg.contents ¬ contents; RETURN[msg]; }; ToggleHeaderPruning: PROC [self: Viewer, wH: WalnutHandle, msg: ROPE] RETURNS [] ~ { IF pruneHeaders THEN { pruneHeaders ¬ FALSE; WalnutWindow.Report[wH, "Header pruning turned off."]; } ELSE { pruneHeaders ¬ TRUE; unprunedHeaders ¬ UserProfile.ListOfTokens["Walnut.UnprunedHeaders", LIST["subject", "from", "to", "cc", "date"]]; WalnutWindow.Report[wH, "Header pruning turned on."]; }; [] ¬ QDisplayMsg[wH: wH, msg: msg, oldV: self, shift: FALSE, openIfIconic: TRUE, paint: TRUE]; }; CreateMsgMenu: PUBLIC PROC[wH: WalnutHandle] = { OPEN Menus; added: Menus.MenuEntry; msgMenu: Menus.Menu ¬ Menus.CreateMenu[]; frozenMsgMenu: Menus.Menu ¬ Menus.CreateMenu[]; AppendMenuEntry[ msgMenu, WalnutViewer.CreateMenuEntry[wH.walnutQueue, "Freeze", MsgFreezeProc]]; <<>> <> FOR procs: LIST OF MailSend.MailSendProcsRef ¬ MailSend.GetRegisteredSendProcsList[], procs.rest UNTIL procs = NIL DO name: ROPE ¬ Rope.Concat[Atom.GetPName[procs.first.which], "Answer"]; Menus.AppendMenuEntry[ msgMenu, Menus.CreateEntry[name: name, proc: MsgAnswerProc, clientData: procs.first.which]]; Menus.AppendMenuEntry[ frozenMsgMenu, Menus.CreateEntry[name: name, proc: MsgAnswerProc, clientData: procs.first.which]]; ENDLOOP; AppendMenuEntry[msgMenu, WalnutViewer.CreateMenuEntry[wH.walnutQueue, "Forward", MsgForwardProc]]; AppendMenuEntry[msgMenu, WalnutViewer.CreateMenuEntry[wH.walnutQueue, "ReSend", MsgReSendProc]]; AppendMenuEntry[msgMenu, Menus.CreateEntry["MsgOps", MsgOpsProc]]; AppendMenuEntry[ msgMenu, WalnutViewer.CreateMenuEntry[wH.walnutQueue, "Split", MsgSplitProc]]; AppendMenuEntry[ msgMenu, WalnutViewer.CreateMenuEntry[wH.walnutQueue, "Places", MsgPlacesProc]]; AppendMenuEntry[ msgMenu, WalnutViewer.CreateMenuEntry[wH.walnutQueue, "Levels", MsgLevelsProc]]; added ¬ WalnutFilter.MenuExtras[$msg]; UNTIL added = NIL DO me: Menus.MenuEntry ¬ added; added ¬ added.link; Menus.AppendMenuEntry[msgMenu, me]; ENDLOOP; wH.msgMenu ¬ msgMenu; AppendMenuEntry[ frozenMsgMenu, Menus.CreateEntry["Forward", MsgForwardProc]]; AppendMenuEntry[ frozenMsgMenu, Menus.CreateEntry["ReSend", MsgReSendProc]]; AppendMenuEntry[ frozenMsgMenu, Menus.CreateEntry["MsgOps", MsgOpsProc]]; AppendMenuEntry[ frozenMsgMenu, Menus.CreateEntry["Split", MsgSplitProc]]; AppendMenuEntry[ frozenMsgMenu, Menus.CreateEntry["Places", MsgPlacesProc]]; AppendMenuEntry[ frozenMsgMenu, Menus.CreateEntry["Levels", MsgLevelsProc]]; added ¬ WalnutFilter.MenuExtras[$msg]; UNTIL added = NIL DO me: Menus.MenuEntry ¬ added; added ¬ added.link; Menus.AppendMenuEntry[frozenMsgMenu, me]; ENDLOOP; wH.frozenMsgMenu ¬ frozenMsgMenu; }; END. Change Log. WSH on March 4, 1983: take out all DBText stuff