DIRECTORY BasicTime, IO, Menus, Process, RefText, Remind, RemindEdit, Rope, TextNode, TimeParse, TiogaOps, UserProfile, ViewerClasses, ViewerTools, WalnutRegistry, WalnutWindow; RemindWalnut: CEDAR PROGRAM IMPORTS RemindEdit, BasicTime, IO, Process, RefText, Rope, TimeParse, TiogaOps, UserProfile, ViewerTools, WalnutRegistry, WalnutWindow = BEGIN OPEN Remind; ROPE: TYPE = Rope.ROPE; WhiteSpace: IO.BreakProc = { RETURN[SELECT char FROM ' , '\n, '\t, '\l => sepr, ENDCASE => other]; }; PostRemindButton: PROC = TRUSTED { DO IF WalnutRegistry.CurrentWalnutState[] # unknown THEN { walnutUser ¬ TRUE; UNTIL WalnutRegistry.CurrentWalnutState[] # initializing DO Process.Pause[Process.SecondsToTicks[5]]; ENDLOOP; FOR whL: LIST OF WalnutWindow.WalnutHandle ¬ WalnutWindow.GetHandleList[], whL.rest UNTIL whL = NIL DO [] ¬ WalnutWindow.ReplaceInMsgMenu[wH: whL.first, label: "RemindMe", proc: RemindProc]; ENDLOOP; EXIT; }; Process.Pause[Process.SecondsToTicks[60]]; ENDLOOP; }; RemindProc: Menus.ClickProc = { headerSize, msgSize: INT; timeSpecified: BOOLEAN ¬ FALSE; viewer: ViewerClasses.Viewer = NARROW[parent]; rootAny: REF ANY ¬ TiogaOps.ViewerDoc[viewer]; root: TextNode.Ref ¬ NARROW[rootAny]; messageName, rootFile, sel, msgText, subject: ROPE ¬ NIL; dayRope, dateRope, timeRope, titleRope: ROPE ¬ NIL; startRope: ROPE; meeting: Meeting; ps: IO.STREAM; buffer, fieldTag, fieldBody: REF TEXT; GatherField: PROC [skipped: INT] RETURNS [ans: ROPE ¬ NIL] ~ { [] ¬ SkipSpace[ps, TRUE]; IF ps.EndOf[] THEN RETURN; ans ¬ ps.GetLineRope[]; WHILE (NOT ps.EndOf[]) AND White[ps.PeekChar] DO this: INT ~ SkipSpace[ps, FALSE]; IF ps.EndOf[] OR this<=skipped THEN RETURN; ans ¬ ans.Cat["\n", ps.GetLineRope[]]; ENDLOOP; RETURN}; [messageName, rootFile] ¬ WalnutWindow.GetMsgName[viewer]; sel ¬ ViewerTools.GetSelectionContents[]; meeting ¬ NEW[MeetingRec]; msgText ¬ ViewerTools.GetContents[viewer]; msgSize ¬ msgText.Length[]; ps ¬ IO.RIS[msgText]; buffer ¬ RefText.New[200]; WHILE NOT ps.EndOf[] DO fieldTag ¬ ps.GetToken[HeaderBreak, buffer].token; SELECT TRUE FROM RefText.Equal[fieldTag, "\n", TRUE] => EXIT; RefText.Equal[fieldTag, "\r", TRUE] => EXIT; RefText.Equal[fieldTag, "\l", TRUE] => EXIT; ps.EndOf[] => EXIT; RefText.Equal[fieldTag, "Subject:", FALSE] => { [] ¬ SkipSpace[ps, FALSE]; subject ¬ ps.GetLineRope[]}; ENDCASE => fieldBody ¬ ps.GetLine[buffer]; ENDLOOP; headerSize ¬ ps.GetIndex[]; WHILE NOT ps.EndOf[] DO skipped: INT; [fieldTag, skipped] ¬ ps.GetToken[BodyBreak, buffer]; SELECT TRUE FROM fieldTag.length=1 AND BodyBreak[fieldTag[0]]=break => NULL; RefText.Equal[fieldTag, "day", FALSE] => dayRope ¬ GatherField[skipped]; RefText.Equal[fieldTag, "date", FALSE] => dateRope ¬ GatherField[skipped]; RefText.Equal[fieldTag, "time", FALSE] => timeRope ¬ GatherField[skipped]; RefText.Equal[fieldTag, "title", FALSE] => titleRope ¬ GatherField[skipped]; ps.EndOf[] => EXIT; ENDCASE => fieldBody ¬ ps.GetLine[buffer]; ENDLOOP; meeting.start ¬ BasicTime.nullGMT; IF sel.Length[] > 1 THEN { pieces: TimeParse.PiecesType; selRem: ROPE; [meeting.start, pieces] ¬ TimeParse.Parse[sel, BasicTime.Now[], heuristic, FALSE, TRUE !TimeParse.ParseError => GOTO NotHere]; IF pieces=NIL THEN meeting.start ¬ BasicTime.nullGMT; selRem ¬ RemPieces[sel, pieces]; IF selRem.Length[] > 0 THEN titleRope ¬ selRem; EXITS NotHere => titleRope ¬ sel}; IF meeting.start = BasicTime.nullGMT THEN { startRope ¬ Rope.Cat[timeRope, " ", IF dayRope#NIL THEN dayRope ELSE dateRope]; meeting.start ¬ TimeParse.Parse[startRope, BasicTime.Now[], heuristic, FALSE, TRUE !TimeParse.ParseError => { meeting.start ¬ BasicTime.Now[]; CONTINUE}].time; }; meeting.duration ¬ defaultDuration; meeting.explanation ¬ IF titleRope.Length[]>0 THEN titleRope ELSE subject; meeting.more ¬ Rope.Cat[rootFile, " ", messageName]; RemindEdit.SpecifyMeeting[meeting, FALSE]; RETURN}; UpdateDefaults: UserProfile.ProfileChangedProc = { defaultDuration ¬ UserProfile.Number["Remind.Duration", 60]; }; SkipSpace: PROC [stream: IO.STREAM, punctToo: BOOL] RETURNS [n: INT ¬ 0] ~ { WHILE (NOT stream.EndOf[]) DO c: CHAR ~ stream.PeekChar[]; SELECT TRUE FROM White[c] => NULL; punctToo AND (c='* OR c=':) => NULL; ENDCASE => EXIT; n ¬ n + 1; IF c#stream.GetChar[] THEN ERROR; ENDLOOP; RETURN}; White: PROC [char: CHAR] RETURNS [BOOL] ~ {RETURN [char=' OR char='\t]}; HeaderBreak: PROC [char: CHAR] RETURNS [IO.CharClass] --IO.BreakProc-- ~ { RETURN [SELECT char FROM ' , '\t => sepr, '\n, '\r, '\l => break, ENDCASE => other]}; BodyBreak: PROC [char: CHAR] RETURNS [IO.CharClass] --IO.BreakProc-- ~ { RETURN [SELECT char FROM ':, '*, ' , '\t => sepr, '\n, '\r, '\l => break, ENDCASE => other]}; RemPieces: PROC [from: ROPE, pieces: TimeParse.PiecesType] RETURNS [ROPE] ~ { WHILE pieces#NIL DO p: TimeParse.PieceType ~ pieces.first­; flen: INT ~ from.Length[]; resume, dlen: INT; pieces ¬ pieces.rest; FOR resume ¬ p.start+p.len, resume+1 WHILE resume NULL; ', => IF resume#p.start+p.len THEN EXIT; ENDCASE => EXIT; ENDLOOP; dlen ¬ resume - p.start; from ¬ from.Replace[start: p.start, len: dlen, with: NIL]; FOR pl: TimeParse.PiecesType ¬ pieces, pl.rest WHILE pl#NIL DO IF pl.first.start > p.start THEN pl.first.start ¬ pl.first.start - dlen; ENDLOOP; ENDLOOP; RETURN[from]}; defaultDuration: INT ¬ 0; walnutUser: BOOLEAN ¬ FALSE; switchToNew: BOOLEAN ¬ FALSE; UserProfile.CallWhenProfileChanges[UpdateDefaults]; TRUSTED {Process.Detach[FORK PostRemindButton[]]}; END. ( RemindWalnut.mesa Copyright Σ 1990, 1992 by Xerox Corporation. All rights reserved. David Goldberg November 13, 1989 8:28:33 pm PST Peter B. Kessler, January 10, 1990 10:46:47 am PST Theimer, September 10, 1990 2:12 pm PDT Last tweaked by Mike Spreitzer April 23, 1992 11:01 am PDT Adds button to walnut. ELSE IF Basics.IsBound[PeanutWindow.AddCommand] THEN { PeanutWindow.AddCommand[name: "RemindMe", proc: PeanutRemindProc, fork: FALSE]; peanutUser _ TRUE; EXIT; }; PROC [reason: UserProfile.ProfileChangeReason] peanutUser: BOOLEAN _ FALSE; ΚΎ–(cedarcode) style•NewlineDelimiter ™code™Iproc– "Cedar" stylešœ Οeœ7™BK™/K™2K™'K™:—K˜KšΟk œ žœš˜±K˜K™K˜KšΠln œž ˜šžœ˜Kšœžœe˜~—Kšœž œž˜K˜Kšžœžœžœ˜K˜šΠbn œžœ˜Kšžœžœžœžœ ˜EKšœ˜K˜—šΟnœžœžœ˜"šž˜šžœ/žœ˜7Kšœ žœ˜šžœ4ž˜;K˜)Kšžœ˜—š žœžœžœDžœžœž˜fK˜WKšžœ˜—Kšžœ˜K˜—šžœžœ)žœ™6KšœHžœ™OKšœ žœ™Kšžœ™K™—K˜*Kšžœ˜—K˜—K˜š‘ œ˜Kšœžœ˜Kšœžœžœ˜Kšœžœ ˜.Kšœ žœžœ˜.Kšœžœ ˜%Kšœ.žœžœ˜9Kšœ(žœžœ˜3Kšœ žœ˜Kšœ˜Kšœžœžœ˜Kšœžœžœ˜&š ‘ œžœ žœžœžœžœ˜>Kšœžœ˜Kšžœ žœžœ˜K˜šžœžœ žœž˜0Kšœžœžœ˜!Kšžœ žœžœžœ˜+K˜&Kšžœ˜—Kšžœ˜—K˜:K˜)Kšœ žœ ˜K˜*K˜Kšœžœžœ ˜K˜šžœžœ ž˜K˜2šžœžœž˜Kšœžœžœ˜,Kšœžœžœ˜,Kšœžœžœ˜,Kšœžœ˜šœ$žœ˜/Kšœžœ˜K˜—Kšžœ#˜*—Kšžœ˜—K˜šžœžœ ž˜Kšœ žœ˜ K˜5šžœžœž˜Kšœžœ!žœ˜;Kšœžœ$˜HKšœ žœ%˜JKšœ žœ%˜JKšœ!žœ&˜LKšœžœ˜Kšžœ#˜*—Kšžœ˜—K˜"šžœžœ˜Kšœ˜Kšœžœ˜ šœKžœž˜VKšœžœ ˜'—Kšžœžœžœ#˜5K˜ Kšžœžœ˜/Kšžœ˜"—šžœ#žœ˜+Kš œ$žœ žœžœ žœ ˜OšœGžœž˜Ršœ˜K˜ Kšžœ˜——K˜—K˜#Kšœžœžœ žœ ˜KK˜4Kšœ#žœ˜*Kšžœ˜—code2š‘œ$˜2Kšžœ*™.K˜K˜Kšžœžœ(˜HKšžœ˜—Kšžœ˜—Kšžœ˜—K˜Kšœžœ˜Kšœ žœžœ˜Kšœ žœžœ™Kšœ žœžœ˜K˜Kšœ3˜3K˜šžœžœ˜2K˜—Kšžœ˜—…—ˆn