DIRECTORY Atom USING [GetPName], BasicTime USING [Now, Period], Buttons USING [ButtonProc, Create], Commander USING [CommandProc, Register], Icons USING [IconFlavor, NewIconFromFile], InputFocus USING [GetInputFocus], List USING [Length, LORA], MailSend USING [Abort, GetRegisteredSendProcsList, MailSendProcsRef], MailSendSidedoor USING [AbortSendProc], Menus USING [AppendMenuEntry, CopyEntry, CreateEntry, FindEntry, Menu, MenuEntry, MenuProc, MouseButton, ReplaceMenuEntry, targetNotFound], IO, PFS, PFSNames, PopUpSelection USING [Request], Process USING [Detach, MsecToTicks, SetTimeout, Ticks], Rope, TEditInputOps USING [DoFindPlaceholders], TEditSplit USING[ Split ], TextEdit USING [GetNewlineDelimiter], TextNode USING [Root], Tioga, TiogaAccess, TiogaAccessViewers, TiogaMenuOps USING[ tiogaMenu, Empty, Load, Store ], TiogaOps USING [ Ref, Location, CancelSelection, GetSelection, IsComment, StepForward, ViewerDoc ], TypeScript USING [Create], ViewerEvents USING [EventProc, EventRegistration, RegisterEventProc, UnRegisterEventProc], ViewerOps USING [AddProp, BlinkIcon, ComputeColumn, CreateViewer, DestroyViewer, FetchProp, MoveBelowViewer, OpenIcon, PaintViewer, SaveViewer, SetMenu, SetNewVersion], ViewerIO USING [CreateViewerStreams, GetViewerFromStream], ViewerTools USING [EnableUserEdits, GetSelectionContents, InhibitUserEdits, SelPos, SelPosRec, SetSelection, SetTiogaContents, TiogaContents, TiogaContentsRec], ViewerClasses USING [Viewer], UserProfile USING [Boolean, CallWhenProfileChanges, Number, ProfileChangedProc, ListOfTokens, Token], SendMailInternal, SendMailOps; SendMailControlImpl: CEDAR MONITOR IMPORTS Atom, BasicTime, Buttons, Commander, IO, List, PFS, PFSNames, PopUpSelection, Process, Rope, Icons, InputFocus, MailSend, Menus, SendMailInternal, SendMailOps, TEditInputOps, TEditSplit, TextNode, TextEdit, TiogaAccess, TiogaAccessViewers, TiogaMenuOps, TiogaOps, TypeScript, ViewerEvents, ViewerIO, ViewerOps, ViewerTools, UserProfile EXPORTS SendMailInternal, SendMailOps SHARES ViewerClasses = BEGIN OPEN SendMailOps, SendMailInternal; -- Global types & variables STREAM: TYPE = IO.STREAM; ROPE: TYPE = Rope.ROPE; Viewer: TYPE = ViewerClasses.Viewer; TiogaContents: TYPE = ViewerTools.TiogaContents; OutBoxMsg: TYPE = SendMailOps.OutBoxMsg; viewerStart: ViewerTools.SelPos = NEW[ViewerTools.SelPosRec ¬ [0, 0]]; alwaysOpenSender: BOOL ¬ FALSE; destroyAfterSend: BOOL ¬ FALSE; senderList: LIST OF SenderInfo ¬ NIL; popUpFormsList: LIST OF ROPE ¬ NIL; popUpFormsFileNames: LIST OF ROPE ¬ NIL; sendingSynch: CONDITION; iconicSender: BOOL ¬ TRUE; -- make iconic initially only senderIcon: Icons.IconFlavor ¬ tool; edittingIcon: Icons.IconFlavor ¬ tool; notSentIcon: Icons.IconFlavor ¬ tool; labelFont: PUBLIC ROPE ¬ NIL; -- font to use for printing of header labels reporter: STREAM ¬ NIL; senderTS: Viewer ¬ NIL; senderEvent: ViewerEvents.EventRegistration; defaultText: PUBLIC ViewerTools.TiogaContents; answerText: PUBLIC ViewerTools.TiogaContents; forwardText: PUBLIC ViewerTools.TiogaContents; SenderPropRec: TYPE = RECORD[proc: PROC[Viewer, ATOM, REF ANY], data: REF ANY]; SenderPropValue: TYPE = REF SenderPropRec; SenderProp: TYPE = RECORD[key: ATOM, value: SenderPropValue]; senderPropsList: LIST OF SenderProp ¬ NIL; FileStatus: TYPE = {illegalName, local, remote, notFound, otherError}; SendMailCmd: Commander.CommandProc = { [] ¬ CreateSendViewer[fromExec: TRUE]}; CreateSendViewer: PUBLIC PROC[fromExec: BOOL, transport: ATOM ¬ NIL] RETURNS[which: ATOM ¬ NIL] = { senderInfo: SenderInfo; IF fromExec THEN fromExec ¬ ~alwaysOpenSender; IF ~fromExec THEN iconicSender ¬ FALSE; [] ¬ CheckDefault[]; senderInfo ¬ BuildSender[ paint: TRUE, iconic: iconicSender, form: defaultForm, forceNew: alwaysNewSender]; IF ~iconicSender THEN GrabFocus[senderInfo.senderV]; iconicSender ¬ FALSE; -- iconic only the first time }; GrabFocus: PUBLIC ENTRY PROC[senderV: Viewer] = { ENABLE UNWIND => NULL; IF senderV.iconic THEN RETURN; ViewerTools.SetSelection[senderV, viewerStart]; [] ¬ TEditInputOps.DoFindPlaceholders[next: TRUE, gotoend: FALSE]; }; BuildSendViewer: PUBLIC PROC[paint, iconic: BOOL, form: SendMailOps.Form ¬ NIL, who: Viewer ¬ NIL, forceNew: BOOL ¬ FALSE, transport: ATOM ¬ NIL] RETURNS[v: Viewer, which: ATOM ¬ NIL] = { senderInfo: SenderInfo; newForm: SendMailOps.Form = IF form # NIL THEN form ELSE CheckDefault[]; senderInfo ¬ BuildSender[paint, iconic, newForm, who, forceNew, transport]; RETURN[senderInfo.senderV, which]; }; CheckDefault: PROC RETURNS[form: SendMailOps.Form] = { IF simpleUserNameList = NIL THEN SendMailInit[firstTime]; -- check for login IF defaultForm.fields = NIL THEN RETURN; IF defaultForm.fields.rest = NIL THEN RETURN; IF defaultForm.fields.rest.rest = NIL THEN RETURN; RETURN[defaultForm]; }; BuildSender: ENTRY PROC[paint, iconic: BOOL, form: SendMailOps.Form, who: Viewer ¬ NIL, forceNew: BOOL ¬ FALSE, transport: ATOM ¬ NIL] RETURNS[senderInfo: SenderInfo] = { ENABLE UNWIND => IF senderInfo # NIL AND senderInfo.senderV # NIL THEN senderInfo.senderV.inhibitDestroy ¬ FALSE; senderV: Viewer; form1: SendMailOps.Form ¬ form; trx: ATOM ¬ transport; IF ~forceNew THEN FOR sL: LIST OF SenderInfo ¬ senderList, sL.rest UNTIL sL=NIL DO senderInfo ¬ sL.first; IF ~(senderInfo.senderV.newVersion) AND (senderInfo.sendHandle = NIL) AND ~senderInfo.senderV.destroyed AND (senderInfo.senderV.file = NIL ) THEN { senderV ¬ senderInfo.senderV; IF senderV.link # NIL THEN InternalDestroySplits[senderV]; senderV.inhibitDestroy ¬ TRUE; IF TiogaOps.GetSelection[feedback].viewer = senderV THEN TiogaOps.CancelSelection[feedback]; IF senderV.iconic THEN { -- inlined a call to ClearOpenEvent ra: REF ANY ¬ ViewerOps.FetchProp[senderV, $SendMailOpsForm]; IF ra # NIL THEN { form: SendMailOps.Form = NARROW[ra]; ViewerEvents.UnRegisterEventProc[senderInfo.openEvent, open]; senderInfo.openEvent ¬ NIL; }; IF (who # NIL) AND (senderV.column = who.column) THEN { ViewerOps.OpenIcon[icon: senderV, paint: FALSE]; ViewerOps.MoveBelowViewer[altered: senderV, static: who, paint: TRUE] } ELSE ViewerOps.OpenIcon[senderV]; }; IF form # NIL THEN InsertForm[senderInfo, form, TRUE] ELSE TiogaMenuOps.Empty[senderV]; ViewerOps.PaintViewer[senderV, menu]; senderV.inhibitDestroy ¬ FALSE; RETURN }; ENDLOOP; -- need to create a new sender senderV ¬ ViewerOps.CreateViewer[ flavor: $Text, info: [ name: sendCaption, column: IF who#NIL THEN who.column ELSE left, iconic: iconic, icon: senderIcon], paint: who = NIL]; IF who # NIL THEN { ViewerOps.MoveBelowViewer[altered: senderV, static: who, paint: FALSE]; ViewerOps.ComputeColumn[column: senderV.column, paint: TRUE] }; senderV.inhibitDestroy ¬ TRUE; senderInfo ¬ NEW[SenderInfoObject ¬ [senderV: senderV]]; TRUSTED { Process.SetTimeout[@senderInfo.timeToWait, halfSecTicks] }; HowCanWeSend[senderInfo, transport]; ViewerOps.SetMenu[senderV, senderInfo.thisMenu]; ViewerOps.AddProp[senderV, $SenderInfo, senderInfo]; FOR spl: LIST OF SenderProp ¬ senderPropsList, spl.rest UNTIL spl=NIL DO ViewerOps.AddProp[senderV, spl.first.key, spl.first.value]; ENDLOOP; senderList ¬ CONS[senderInfo, senderList]; senderInfo.destroyEvent ¬ ViewerEvents.RegisterEventProc[ proc: DestroySendViewer, event: destroy, filter: senderV, before: TRUE]; senderInfo.closeEvent ¬ ViewerEvents.RegisterEventProc[ proc: CloseSendViewer, event: close, filter: senderV, before: TRUE]; senderInfo.editEvent ¬ ViewerEvents.RegisterEventProc[ proc: FirstEditSendViewer, event: edit, filter: senderV, before: TRUE]; IF form # NIL THEN InsertForm[senderInfo, form, TRUE] ELSE TiogaMenuOps.Empty[senderV]; senderV.inhibitDestroy ¬ FALSE; IF iconic AND ~senderV.iconic THEN ViewerOps.PaintViewer[senderV, all]; }; HowCanWeSend: PROC[senderInfo: SenderInfo, transport: ATOM] = { senderInfo.thisMenu ¬ sendMenu; }; -- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * SendMailInit: UserProfile.ProfileChangedProc = { defaultFormFile: ROPE ¬ UserProfile.Token[key: "SendMailTool.DefaultForm", default: NIL]; answerFormFile: ROPE ¬ UserProfile.Token[key: "SendMailTool.AnswerForm", default: NIL]; forwardFormFile: ROPE ¬ UserProfile.Token[key: "SendMailTool.ForwardForm", default: NIL]; formContents: ViewerTools.TiogaContents ¬ NIL; isDefault: BOOL ¬ TRUE; defaultFields: LIST OF ROPE ¬ NIL; DoUserNameAndRegistry[]; IF localRNameList # NIL THEN defaultFields ¬ LIST[NIL, NIL, localRNameList.first]; needToAuthenticate ¬ TRUE; outBoxLength ¬ UserProfile.Number[key: "SendMailTool.OutBoxLength", default: 1]; replyToSelf ¬ UserProfile.Boolean[key: "SendMailTool.ReplyToSelf", default: FALSE]; destroyAfterSend ¬ UserProfile.Boolean[key: "SendMailTool.DestroyAfterSend", default: FALSE]; alwaysNewSender ¬ UserProfile.Boolean[key: "SendMailTool.AlwaysNewSender", default: FALSE]; alwaysOpenSender ¬ UserProfile.Boolean[key: "SendMailTool.AlwaysOpenSender", default: FALSE]; IF defaultFormFile = NIL THEN defaultFormFile ¬ Rope.Concat[initDir, "SendMailStandardSend.form"] ELSE isDefault ¬ FALSE; formContents ¬ GetSendForm[defaultFormFile]; IF formContents # NIL THEN { defaultText ¬ defaultForm.formText ¬ formContents; defaultForm.fields ¬ IF isDefault THEN defaultFields ELSE NIL; } ELSE { defaultText ¬ defaultForm.formText ¬ standardDefaultText; defaultForm.fields ¬ defaultFields; }; formContents ¬ NIL; IF answerFormFile = NIL THEN answerFormFile ¬ Rope.Concat[initDir, "SendMailStandardAnswer.form"]; formContents ¬ GetSendForm[answerFormFile]; IF formContents # NIL THEN answerText ¬ formContents ELSE answerText ¬ standardAnswerText; formContents ¬ NIL; IF forwardFormFile = NIL THEN forwardFormFile ¬ Rope.Concat[initDir, "SendMailStandardForward.form"]; formContents ¬ GetSendForm[forwardFormFile]; IF formContents # NIL THEN forwardText ¬ formContents ELSE forwardText ¬ standardForwardText; labelFont ¬ UserProfile.Token[key: "SendMailTool.MsgHeadersLooks", default: "sb"]; SetFormsList[]; }; DisplayTxtInSender: ENTRY PROC[senderV: Viewer, txt: ROPE] = { ENABLE UNWIND => NULL; senderInfo: SenderInfo ¬ NARROW[ViewerOps.FetchProp[senderV, $SenderInfo]]; tc: ViewerTools.TiogaContents ¬ NEW[ViewerTools.TiogaContentsRec]; tc.contents ¬ txt; InternalDisplayTioga[senderInfo, tc, TRUE]; }; ClearSendViewer: PUBLIC ENTRY PROC[senderV: Viewer] = { ENABLE UNWIND => NULL; senderInfo: SenderInfo ¬ NARROW[ViewerOps.FetchProp[senderV, $SenderInfo]]; IF senderInfo = NIL THEN RETURN; -- not a sender InsertForm[senderInfo, defaultForm, TRUE] }; StuffForm: PUBLIC ENTRY PROC[v: Viewer, contents: TiogaContents] = { ENABLE UNWIND => NULL; senderInfo: SenderInfo ¬ NARROW[ViewerOps.FetchProp[v, $SenderInfo]]; IF senderInfo = NIL THEN RETURN; -- not a sender InternalDisplayTioga[senderInfo, contents, TRUE] }; AddToSenderProps: PUBLIC ENTRY PROC [key: ATOM, proc: PROC[Viewer, ATOM, REF ANY], data: REF ANY] = { ENABLE UNWIND => NULL; senderPropsList ¬ CONS[[key: key, value: NEW[SenderPropRec ¬ [proc, data]]], senderPropsList]; }; RemoveFromSenderProps: PUBLIC ENTRY PROC[key: ATOM] = { ENABLE UNWIND => NULL; sp: LIST OF SenderProp; IF senderPropsList = NIL THEN RETURN; FOR spl: LIST OF SenderProp ¬ senderPropsList, spl.rest UNTIL spl = NIL DO IF spl.first.key = key THEN IF spl = senderPropsList THEN { senderPropsList ¬ senderPropsList.rest; RETURN} ELSE { sp.rest ¬ spl.rest; RETURN}; sp ¬ spl; ENDLOOP; }; AddToSendMenu: PUBLIC ENTRY PROC[label: ROPE, proc: Menus.MenuProc] = { ENABLE UNWIND => NULL; old: Menus.MenuEntry ¬ Menus.FindEntry[sendMenu, label]; IF old = NIL THEN Menus.AppendMenuEntry[sendMenu, Menus.CreateEntry[label, proc]]; FOR sL: LIST OF SenderInfo ¬ senderList, sL.rest UNTIL sL = NIL DO thisMenu: Menus.Menu; v: Viewer = sL.first.senderV; IF v = NIL OR v.destroyed THEN LOOP; old ¬ Menus.FindEntry[thisMenu ¬ sL.first.senderV.menu, label]; IF old = NIL THEN { Menus.AppendMenuEntry[thisMenu, Menus.CreateEntry[label, proc]]; ViewerOps.PaintViewer[sL.first.senderV, menu]; }; ENDLOOP; }; ReplaceInSendMenu: PUBLIC ENTRY PROC[label: ROPE, proc: Menus.MenuProc] RETURNS[oldFound: BOOL] = { ENABLE UNWIND => NULL; DoReplace: PROC[thisMenu: Menus.Menu] RETURNS[foundIt: BOOL ¬ TRUE]= { old: Menus.MenuEntry = Menus.FindEntry[thisMenu, label]; new: Menus.MenuEntry = Menus.CreateEntry[label, proc]; Menus.ReplaceMenuEntry[thisMenu, old, new ! Menus.targetNotFound => { foundIt ¬ FALSE ; CONTINUE }]; IF NOT foundIt THEN Menus.AppendMenuEntry[thisMenu, new]; }; oldFound ¬ DoReplace[sendMenu]; FOR sL: LIST OF SenderInfo ¬ senderList, sL.rest UNTIL sL = NIL DO v: Viewer = sL.first.senderV; thisFound: BOOL; IF v = NIL OR v.destroyed THEN LOOP; thisFound ¬ DoReplace[sL.first.senderV.menu]; oldFound ¬ thisFound AND oldFound; ViewerOps.PaintViewer[sL.first.senderV, menu]; ENDLOOP; }; RemoveFromSendMenu: PUBLIC ENTRY PROC[name: ROPE] = { ENABLE UNWIND => NULL; old: Menus.MenuEntry ¬ Menus.FindEntry[sendMenu, name]; IF old = NIL THEN RETURN; Menus.ReplaceMenuEntry[sendMenu, old ! Menus.targetNotFound => CONTINUE]; FOR sL: LIST OF SenderInfo ¬ senderList, sL.rest UNTIL sL = NIL DO thisMenu: Menus.Menu; v: Viewer = sL.first.senderV; IF v = NIL OR v.destroyed THEN LOOP; old ¬ Menus.FindEntry[thisMenu ¬ sL.first.senderV.menu, name]; IF old # NIL THEN { Menus.ReplaceMenuEntry[thisMenu, old ! Menus.targetNotFound => CONTINUE]; ViewerOps.PaintViewer[sL.first.senderV, menu]; }; ENDLOOP; }; -- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -- Menu procedures NewMsgFormProc: ENTRY PROC[viewer: Viewer] = { ENABLE UNWIND => NULL; NewMsgForm[viewer] }; PrevMsgProc: ENTRY PROC[viewer: Viewer, blueButton: BOOL] = { ENABLE UNWIND => NULL; senderInfo: SenderInfo ¬ NARROW[ViewerOps.FetchProp[viewer, $SenderInfo]]; tc: TiogaContents; IF viewer.link#NIL THEN InternalDestroySplits[viewer]; ClearFileAssoc[viewer]; [] ¬ CheckDefault[]; IF outBox = NIL THEN InsertForm[senderInfo, defaultForm, TRUE] ELSE { IF outBox.next = NIL THEN tc ¬ IF blueButton THEN outBox.sentTC ELSE outBox.replaceTC ELSE { -- more than one previous message which: INT; obm: OutBoxMsg ¬ outBox; outBoxList: LIST OF ROPE ¬ LIST[outBox.subject]; last: LIST OF ROPE ¬ outBoxList; FOR oB: OutBoxMsg ¬ outBox.next, oB.next UNTIL oB = NIL DO last.rest ¬ LIST[oB.subject]; last ¬ last.rest; ENDLOOP; which ¬ PopUpSelection.Request[header: "OutBox", choice: outBoxList, position: $Mouse]; IF which = 0 THEN RETURN; last ¬ outBoxList; FOR i: INT IN [1..which) DO obm ¬ obm.next; ENDLOOP; tc ¬ IF blueButton THEN obm.sentTC ELSE obm.replaceTC; }; IF TiogaOps.GetSelection[feedback].viewer = viewer THEN TiogaOps.CancelSelection[feedback]; ViewerTools.SetTiogaContents[viewer, tc]; UnsetNewVersion[viewer]; }; }; NewSenderClickProc: Buttons.ButtonProc = { senderInfo: SenderInfo; [] ¬ CheckDefault[]; senderInfo ¬ BuildSender[paint: TRUE, iconic: FALSE, form: defaultForm, forceNew: TRUE]; GrabFocus[senderInfo.senderV]; }; NewSenderProc: PROC = { senderInfo: SenderInfo; [] ¬ CheckDefault[]; senderInfo ¬ BuildSender[paint: TRUE, iconic: FALSE, form: defaultForm, forceNew: TRUE]; GrabFocus[senderInfo.senderV]; }; NewMsgForm: INTERNAL PROC[viewer: Viewer] = { senderInfo: SenderInfo ¬ NARROW[ViewerOps.FetchProp[viewer, $SenderInfo]]; [] ¬ CheckDefault[]; InsertForm[senderInfo, defaultForm, TRUE]; ClearFileAssoc[viewer]; }; -- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * DestroySendViewer: ViewerEvents.EventProc = { senderInfo: SenderInfo ¬ NARROW[ViewerOps.FetchProp[viewer, $SenderInfo]]; IF senderInfo = NIL THEN RETURN[FALSE]; IF senderInfo.senderV # NIL THEN senderInfo.senderV.file ¬ NIL; IF ViewerOps.FetchProp[viewer, $DestroySenderProc] = NIL THEN RETURN[FALSE]; TRUSTED {Process.Detach[FORK CheckForDestroy[viewer, senderInfo]]}; RETURN[TRUE]; }; EntryInsertForm: PUBLIC ENTRY PROC[senderInfo: SenderInfo, form: SendMailOps.Form] = { ENABLE UNWIND => NULL; InsertForm[senderInfo, form, TRUE] }; EntryPlaceHolders: PUBLIC ENTRY PROC[senderInfo: SenderInfo, fieldsList: LIST OF ROPE] = { ENABLE UNWIND => NULL; DoPlaceHolders[senderInfo.senderV, fieldsList] }; CloseSendViewer: ViewerEvents.EventProc = { senderInfo: SenderInfo ¬ NARROW[ViewerOps.FetchProp[viewer, $SenderInfo]]; IF senderInfo = NIL THEN RETURN[FALSE]; IF senderInfo.dontClose THEN { SenderReport[format: " **** Sender cannot be closed right now\n", blink: TRUE]; RETURN[TRUE] }; viewer.icon ¬ IF viewer.newVersion THEN edittingIcon ELSE senderIcon; RETURN[FALSE]; }; FirstEditSendViewer: ViewerEvents.EventProc = { OPEN Menus; senderInfo: SenderInfo ¬ NARROW[ViewerOps.FetchProp[viewer, $SenderInfo]]; IF senderInfo = NIL THEN RETURN[FALSE]; SenderNewVersion[viewer]; -- show as guarded RETURN[FALSE]; }; CheckForDestroy: ENTRY PROC[senderV: Viewer, senderInfo: SenderInfo] = { ENABLE UNWIND => NULL; okToDestroy: BOOL ¬ TRUE; IF senderV.destroyed THEN RETURN; -- woops IF senderV.newVersion THEN {InternalReport["\nConfirm quitting with last message unsent"]; IF okToDestroy ¬ SendingConfirm[senderInfo] THEN senderV.newVersion ¬ FALSE; }; IF ~okToDestroy THEN RETURN; IF senderInfo.destroyEvent # NIL THEN ViewerEvents.UnRegisterEventProc[senderInfo.destroyEvent, destroy]; IF senderInfo.closeEvent # NIL THEN ViewerEvents.UnRegisterEventProc[senderInfo.closeEvent, close]; IF senderInfo.editEvent # NIL THEN ViewerEvents.UnRegisterEventProc[senderInfo.editEvent, edit]; IF senderInfo.openEvent # NIL THEN ViewerEvents.UnRegisterEventProc[senderInfo.openEvent, open]; IF senderInfo.focusEvent # NIL THEN ViewerEvents.UnRegisterEventProc[senderInfo.focusEvent, setInputFocus]; senderInfo.destroyEvent ¬ NIL; senderInfo.closeEvent ¬ NIL; senderInfo.editEvent ¬ NIL; senderInfo.openEvent ¬ NIL; senderInfo.focusEvent ¬ NIL; TRUSTED {Process.Detach[FORK ViewerOps.DestroyViewer[senderV]]}; }; LockViewerOpen: PUBLIC ENTRY PROC[viewer: Viewer] = { ENABLE UNWIND => NULL; senderInfo: SenderInfo ¬ NARROW[ViewerOps.FetchProp[viewer, $SenderInfo]]; IF senderInfo = NIL THEN RETURN; senderInfo.dontClose ¬ TRUE; }; ReleaseOpenViewer: PUBLIC ENTRY PROC[viewer: Viewer] = { ENABLE UNWIND => NULL; senderInfo: SenderInfo ¬ NARROW[ViewerOps.FetchProp[viewer, $SenderInfo]]; IF senderInfo = NIL THEN RETURN; senderInfo.dontClose ¬ FALSE; }; SenderReport: PUBLIC ENTRY PROC[ format: ROPE, v1, v2,v3: IO.Value ¬ [null[]], blink: BOOL ¬ FALSE] = { ENABLE UNWIND => NULL; InternalReport[format, v1, v2, v3, blink] }; InternalReport: INTERNAL PROC[ format: ROPE, v1, v2,v3: IO.Value ¬ [null[]], blink: BOOL ¬ FALSE] = { done: BOOL ¬ FALSE; tries: INT ¬ 0; ReallyReport: PROC = { IF reporter = NIL THEN { senderTS ¬ TypeScript.Create[ info: [name: "SendMail", iconic: FALSE, column: right, openHeight: 64]]; reporter ¬ ViewerIO.CreateViewerStreams[NIL, senderTS].out; senderEvent ¬ ViewerEvents.RegisterEventProc[ proc: DestroyReporter, event: destroy, filter: senderTS, before: TRUE]; }; IF blink THEN { viewer: Viewer = ViewerIO.GetViewerFromStream[reporter]; -- NIL for $Dribble class IF viewer # NIL THEN ViewerOps.BlinkIcon[viewer]; }; reporter.PutF[format, v1, v2, v3]; done ¬ TRUE; }; DO ReallyReport[ ! IO.Error => IF ec = StreamClosed THEN { reporter ¬ NIL; IF ( tries ¬ tries + 1) > 2 THEN REJECT; CONTINUE } ]; IF done THEN RETURN; ENDLOOP; }; ReporterClump: TYPE = RECORD [reporters: SEQUENCE count: CARD16 OF STREAM]; maxReporters: CARD16 ¬ 16; registeredReporters: REF ReporterClump ¬ NEW[ReporterClump[maxReporters]]; DestroyReporter: ENTRY ViewerEvents.EventProc = { ENABLE UNWIND => NULL; IF senderEvent # NIL THEN ViewerEvents.UnRegisterEventProc[senderEvent, destroy]; senderEvent ¬ NIL; senderTS ¬ NIL; FOR i: CARD16 IN [0..maxReporters) DO IF registeredReporters[i] # reporter THEN LOOP; registeredReporters[i] ¬ NIL; EXIT; ENDLOOP; reporter ¬ NIL; RETURN[FALSE]; }; RegisterReporter: PUBLIC ENTRY PROC[strm: STREAM] = { IF senderTS # NIL THEN { reporter.Close[]; ViewerEvents.UnRegisterEventProc[senderEvent, destroy]; senderEvent ¬ NIL; ViewerOps.DestroyViewer[senderTS]; senderTS ¬ NIL; reporter ¬ NIL; }; IF reporter = NIL THEN reporter ¬ strm; FOR i: CARD16 IN [0.. maxReporters) DO IF registeredReporters[i] = strm THEN EXIT; IF registeredReporters[i] # NIL THEN LOOP; registeredReporters[i] ¬ strm; EXIT; ENDLOOP; }; UnregisterReporter: PUBLIC ENTRY PROC[strm: STREAM] = { ENABLE UNWIND => NULL; IF reporter = strm THEN reporter ¬ NIL; FOR i: CARD16 IN [0.. maxReporters) DO IF registeredReporters[i] # strm THEN LOOP; registeredReporters[i] ¬ NIL; ENDLOOP; IF reporter = NIL THEN FOR i: CARD16 IN [0.. maxReporters) DO IF registeredReporters[i] = NIL THEN LOOP; reporter ¬ registeredReporters[i]; EXIT; ENDLOOP; }; DenySendProc: ENTRY Menus.MenuProc = { ENABLE UNWIND => NULL; viewer: Viewer ¬ NARROW[parent]; senderInfo: SenderInfo ¬ NARROW[ViewerOps.FetchProp[viewer, $SenderInfo]]; senderInfo.confirmed ¬ FALSE; senderInfo.userResponded ¬ TRUE; BROADCAST sendingSynch; }; ConfirmSendProc: ENTRY Menus.MenuProc = { ENABLE UNWIND => NULL; viewer: Viewer ¬ NARROW[parent]; senderInfo: SenderInfo ¬ NARROW[ViewerOps.FetchProp[viewer, $SenderInfo]]; senderInfo.confirmed ¬ TRUE; senderInfo.userResponded ¬ TRUE; BROADCAST sendingSynch; }; AbortSendProc: ENTRY Menus.MenuProc = { ENABLE UNWIND => NULL; viewer: Viewer ¬ NARROW[parent]; senderInfo: SenderInfo ¬ NARROW[ViewerOps.FetchProp[viewer, $SenderInfo]]; ViewerOps.SetMenu[viewer, blankMenu]; senderInfo.aborted ¬ TRUE; }; ReplyToSelfProc: ENTRY Menus.MenuProc = { ENABLE UNWIND => NULL; viewer: Viewer ¬ NARROW[parent]; senderInfo: SenderInfo ¬ NARROW[ViewerOps.FetchProp[viewer, $SenderInfo]]; senderInfo.replyToResponse ¬ self; senderInfo.userResponded ¬ TRUE; BROADCAST sendingSynch; }; ReplyToAllProc: ENTRY Menus.MenuProc = { ENABLE UNWIND => NULL; viewer: Viewer ¬ NARROW[parent]; senderInfo: SenderInfo ¬ NARROW[ViewerOps.FetchProp[viewer, $SenderInfo]]; senderInfo.replyToResponse ¬ all; senderInfo.userResponded ¬ TRUE; BROADCAST sendingSynch; }; ReplyToCancelProc: ENTRY Menus.MenuProc = { ENABLE UNWIND => NULL; viewer: Viewer ¬ NARROW[parent]; senderInfo: SenderInfo ¬ NARROW[ViewerOps.FetchProp[viewer, $SenderInfo]]; senderInfo.replyToResponse ¬ cancel; senderInfo.userResponded ¬ TRUE; BROADCAST sendingSynch; }; ReplyToResponse: PUBLIC ENTRY PROC[senderInfo: SenderInfo] RETURNS [HowToReplyTo] = { ENABLE UNWIND => NULL; senderV: Viewer ¬ senderInfo.senderV; ViewerOps.BlinkIcon[senderV, IF senderV.iconic THEN 0 ELSE 1]; UNTIL senderInfo.userResponded DO WAIT sendingSynch; ENDLOOP; senderInfo.userResponded ¬ FALSE; RETURN[senderInfo.replyToResponse]; }; CheckForAbortSend: PUBLIC ENTRY PROC[senderInfo: SenderInfo] RETURNS[BOOL] = { ENABLE UNWIND => NULL; IF senderInfo.aborted THEN { InternalReport[" Aborting delivery ...\n"]; IF senderInfo.sendHandle#NIL THEN MailSend.Abort[senderInfo.sendHandle]; IF senderInfo.aborted THEN senderInfo.senderV.inhibitDestroy ¬ FALSE; }; RETURN[senderInfo.aborted]; }; halfSecTicks: Process.Ticks = Process.MsecToTicks[500]; SenderAbortProc: PUBLIC ENTRY MailSendSidedoor.AbortSendProc = { ENABLE UNWIND => NULL; FOR sL: LIST OF SenderInfo ¬ senderList, sL.rest UNTIL sL = NIL DO elapsed, waitTime: INT; IF sL.first.sendHandle # msH THEN LOOP; IF NOT lastTime THEN RETURN[sL.first.aborted]; IF ( elapsed ¬ BasicTime.Period[sL.first.startSendTime, BasicTime.Now[]] ) < ( waitTime ¬ UserProfile.Number["SendMailTool.SendWaitSeconds", 8] ) THEN { IF elapsed < 0 THEN RETURN[sL.first.aborted]; -- strange FOR i: INT IN [0..2*(waitTime-elapsed)) DO WAIT sL.first.timeToWait; IF sL.first.aborted THEN RETURN[TRUE]; ENDLOOP; ViewerOps.SetMenu[sL.first.senderV, blankMenu]; WAIT sL.first.timeToWait; -- 1/2 sec more RETURN[sL.first.aborted]; }; ENDLOOP; RETURN[FALSE]; -- strange but don't argue }; Confirmation: PUBLIC ENTRY PROC[senderInfo: SenderInfo] RETURNS [BOOL] = { ENABLE UNWIND => NULL; RETURN[SendingConfirm[senderInfo]]}; SendingConfirm: INTERNAL PROC[senderInfo: SenderInfo] RETURNS [BOOL] = { senderV: Viewer ¬ senderInfo.senderV; oldM: Menus.Menu ¬ ChangeMenu[senderV, confirmMenu]; ViewerOps.BlinkIcon[senderV, IF senderV.iconic THEN 0 ELSE 1]; UNTIL senderInfo.userResponded DO WAIT sendingSynch; ENDLOOP; ViewerOps.SetMenu[senderV, oldM]; senderInfo.userResponded ¬ FALSE; RETURN[senderInfo.confirmed]; }; ChangeMenu: PROC[v: Viewer, menu: Menus.Menu] RETURNS [oldM: Menus.Menu] = { oldM ¬ v.menu; ViewerOps.SetMenu[v, menu]; }; MessageSendProc: PUBLIC Menus.MenuProc = { self: Viewer ¬ NARROW[parent]; transport: ATOM ¬ NARROW[clientData]; iHadFocus: BOOL ¬ InputFocus.GetInputFocus[].owner = self; ViewerTools.InhibitUserEdits[self]; IF self.link#NIL THEN DestroySplits[self]; IF ( ( transport = $xns ) AND control ) THEN transport ¬ $newXNS; TRUSTED { Process.Detach[FORK SendProc[self, mouseButton, iHadFocus, transport, TRUE]] }; }; MessageUSendProc: Menus.MenuProc = { self: Viewer ¬ NARROW[parent]; transport: ATOM ¬ NARROW[clientData]; iHadFocus: BOOL ¬ InputFocus.GetInputFocus[].owner = self; ViewerTools.InhibitUserEdits[self]; IF self.link#NIL THEN DestroySplits[self]; TRUSTED { Process.Detach[FORK SendProc[self, mouseButton, iHadFocus, transport, FALSE]] }; }; MessageSendCheckedProc: Menus.MenuProc = { self: Viewer ¬ NARROW[parent]; transport: ATOM ¬ NARROW[clientData]; iHadFocus: BOOL ¬ InputFocus.GetInputFocus[].owner = self; hasComments: BOOL ¬ FALSE; ViewerTools.InhibitUserEdits[self]; FOR next: TiogaOps.Ref ¬ TiogaOps.ViewerDoc[self], TiogaOps.StepForward[next] UNTIL next = NIL DO IF hasComments ¬ TiogaOps.IsComment[next] THEN EXIT; ENDLOOP; IF hasComments THEN { TRUSTED { Process.Detach[FORK CheckProc[self, mouseButton, iHadFocus, transport]] }; RETURN; }; IF self.link#NIL THEN DestroySplits[self]; TRUSTED {Process.Detach[FORK SendProc[self, mouseButton, iHadFocus, transport, TRUE]]}; }; lf: CHAR ~ '\l; cr: CHAR ~ '\r; ForceCRLFProc: Menus.MenuProc = { self: Viewer ~ NARROW[parent]; input: TiogaAccess.Reader ¬ TiogaAccessViewers.FromViewer[self]; output: TiogaAccess.Writer ¬ TiogaAccess.Create[]; root: Tioga.Node ~ TextNode.Root[TiogaAccess.GetLocation[input].node]; changeTo: CHAR ~ Rope.Fetch[TextEdit.GetNewlineDelimiter[root], 0]; changeFrom: CHAR ~ IF changeTo = lf THEN cr ELSE lf; UNTIL input.EndOf[] DO char: TiogaAccess.TiogaChar ¬ input.Get[]; IF char.charSet = 0 THEN IF char.char = changeFrom THEN char.char ¬ changeTo; output.Put[char]; ENDLOOP; TiogaAccess.DoneWith[input]; TiogaAccessViewers.WriteViewer[output, self]; SendMailInternal.SenderNewVersion[self]; -- show as editted ViewerOps.PaintViewer[self, caption]; }; CheckProc: PROC[self: Viewer, mouseButton: Menus.MouseButton, iHadFocus: BOOL, transport: ATOM] = { senderInfo: SenderInfo = NARROW[ViewerOps.FetchProp[self, $SenderInfo]]; SenderReport["\n*** Message to be sent contains comment nodes - are you sure you want to send it?"]; IF ~Confirmation[senderInfo] THEN { SenderReport[" Message NOT sent"]; ViewerTools.EnableUserEdits[self]; RETURN; }; IF self.link#NIL THEN DestroySplits[self]; SendProc[self, mouseButton, iHadFocus, transport, TRUE]; }; SendProc: PROC[viewer: Viewer, mouseButton: Menus.MouseButton, iHadFocus: BOOL, transport: ATOM, sendFormatted: BOOL] = { OPEN ViewerOps; sendOK: BOOL; senderInfo: SenderInfo = NARROW[ViewerOps.FetchProp[viewer, $SenderInfo]]; viewer.newVersion ¬ TRUE; viewer.name ¬ "Sending ..."; PaintViewer[viewer, caption]; viewer.file ¬ NIL; IF sendFormatted THEN sendOK ¬ SendMailOps.Send[v: viewer, doClose: mouseButton=blue, transport: transport] ELSE sendOK ¬ SendMailOps.SendUnformatted[v: viewer, doClose: mouseButton=blue, transport: transport]; IF ~sendOK THEN SenderNewVersion[viewer]; viewer.name ¬ viewer.label ¬ sendCaption; viewer.icon ¬ IF sendOK THEN senderIcon ELSE notSentIcon; PaintViewer[viewer, caption]; ViewerTools.EnableUserEdits[viewer]; IF sendOK THEN { AfterSendInsert: ENTRY PROC = { ENABLE UNWIND => NULL; InsertForm[senderInfo, defaultForm, FALSE] }; IF mouseButton=blue AND destroyAfterSend THEN {DestroyViewer[viewer]; RETURN}; UnsetNewVersion[viewer]; AfterSendInsert[]; }; }; SenderSplitProc: Menus.MenuProc = { self: Viewer = NARROW[parent]; newV: Viewer; nsI, senderInfo: SenderInfo; TEditSplit.Split[self]; FOR newV ¬ self.link, newV.link UNTIL newV.link = self DO ENDLOOP; senderInfo ¬ NARROW[ViewerOps.FetchProp[self, $SenderInfo]]; ViewerOps.AddProp[newV, $SenderInfo, nsI ¬ NEW[SenderInfoObject]]; nsI.senderV ¬ newV; nsI.sendingTransports ¬ senderInfo.sendingTransports; nsI.thisMenu ¬ senderInfo.thisMenu; nsI.replyToResponse ¬ senderInfo.replyToResponse; nsI.numCharsToDelete ¬ senderInfo.numCharsToDelete; nsI.currentOutBox ¬ senderInfo.currentOutBox; nsI.dontClose ¬ senderInfo.dontClose; nsI.successfullySent ¬ senderInfo.successfullySent; nsI.userResponded ¬ senderInfo.userResponded; nsI.confirmed ¬ senderInfo.confirmed; nsI.aborted ¬ senderInfo.aborted; nsI.startSendTime ¬ senderInfo.startSendTime; nsI.validateFlag ¬ senderInfo.validateFlag; nsI.sendHandle ¬ senderInfo.sendHandle; TRUSTED { Process.SetTimeout[@nsI.timeToWait, halfSecTicks] }; nsI.destroyEvent ¬ ViewerEvents.RegisterEventProc[ proc: DestroySendViewer, event: destroy, filter: newV, before: TRUE]; nsI.closeEvent ¬ ViewerEvents.RegisterEventProc[ proc: CloseSendViewer, event: close, filter: newV, before: TRUE]; nsI.editEvent ¬ ViewerEvents.RegisterEventProc[ proc: FirstEditSendViewer, event: edit, filter: newV, before: TRUE]; newV.icon ¬ self.icon }; DestroySplits: ENTRY PROC[keepThisOne: Viewer] = { ENABLE UNWIND => NULL; InternalDestroySplits[keepThisOne] }; InternalDestroySplits: PUBLIC PROC[keepThisOne: Viewer] = { next: Viewer ¬ keepThisOne.link; next2: Viewer; sI: SenderInfo; DO IF next = keepThisOne THEN EXIT; sI ¬ NARROW[ViewerOps.FetchProp[next, $SenderInfo]]; IF sI # NIL THEN { IF sI.destroyEvent # NIL THEN ViewerEvents.UnRegisterEventProc[sI.destroyEvent, destroy]; IF sI.closeEvent # NIL THEN ViewerEvents.UnRegisterEventProc[sI.closeEvent, close]; IF sI.editEvent # NIL THEN ViewerEvents.UnRegisterEventProc[sI.editEvent, edit]; sI.destroyEvent ¬ NIL; sI.closeEvent ¬ NIL; sI.editEvent ¬ NIL; }; next2 ¬ next.link; IF sI # NIL THEN ViewerOps.DestroyViewer[next]; -- DON'T FORK here next ¬ next2; ENDLOOP; -- make sure this sender is on the list of senders FOR sL: LIST OF SenderInfo ¬ senderList, sL.rest UNTIL sL=NIL DO IF sL.first.senderV = keepThisOne THEN RETURN; ENDLOOP; sI ¬ NARROW[ViewerOps.FetchProp[keepThisOne, $SenderInfo]]; IF sI = NIL THEN RETURN; senderList ¬ CONS[sI, senderList]; }; SenderPlacesProc: Menus.MenuProc = Menus.CopyEntry[ Menus.FindEntry[ TiogaMenuOps.tiogaMenu, "Places" ] ].proc; SenderLevelsProc: Menus.MenuProc = Menus.CopyEntry[ Menus.FindEntry[ TiogaMenuOps.tiogaMenu, "Levels" ] ].proc; SenderGetFormProc: ENTRY PROC[self: Viewer, filename: ROPE] = { ENABLE UNWIND => NULL; fileStatus: FileStatus; exp, fName: ROPE; IF filename.Length[] = 0 THEN RETURN; [fileStatus, exp, fName] ¬ CheckForFile[filename]; IF fileStatus = local OR fileStatus = remote THEN { tc: ViewerTools.TiogaContents ¬ GetSendForm[fName]; senderInfo: SenderInfo ¬ NARROW[ViewerOps.FetchProp[self, $SenderInfo]]; InternalDisplayTioga[senderInfo, tc, TRUE]; ClearFileAssoc[self]; } ELSE ErrorReport[exp]; }; SenderGetFileProc: Menus.MenuProc = { self: Viewer = NARROW[parent]; filename: ROPE ¬ ViewerTools.GetSelectionContents[]; IF filename.Length[] = 0 THEN RETURN; LoadFile[self, filename]; }; SenderFormsProc: Menus.MenuProc = { viewer: Viewer = NARROW[parent]; which: INT; sel: LIST OF ROPE ¬ popUpFormsFileNames; blueButton: BOOL = mouseButton = blue; IF popUpFormsList = NIL THEN RETURN; which ¬ PopUpSelection.Request["Forms", popUpFormsList]; SELECT which FROM <= 0 => RETURN; -- no selection 1 => { NewSenderProc[]; RETURN }; 2 => { NewMsgFormProc[viewer]; RETURN }; 3 => { PrevMsgProc[viewer, blueButton]; RETURN }; ENDCASE => which ¬ which - 3; FOR i: INT IN [1..which) DO sel ¬ sel.rest; ENDLOOP; SenderGetFormProc[viewer, sel.first]; }; SenderStoreProc: Menus.MenuProc = { self: Viewer ¬ NARROW[parent]; fileName: Rope.ROPE = ViewerTools.GetSelectionContents[]; status: FileStatus; exp: Rope.ROPE; [status, exp] ¬ CheckForFile[fileName]; SELECT status FROM local, notFound => { TiogaMenuOps.Store[self, fileName]; IF mouseButton # blue THEN { IF ~self.newVersion THEN UnsetNewVersion[self] } ELSE IF ~self.newVersion THEN ViewerOps.SetNewVersion[self]; }; ENDCASE => BadSaveOrStore[status, exp, fileName]; }; SenderSaveProc: Menus.MenuProc = { self: Viewer ¬ NARROW[parent]; status: FileStatus; exp: Rope.ROPE; IF self.file = NIL THEN { SenderReport["\nCan't save - no file name\n"]; RETURN }; [status, exp] ¬ CheckForFile[self.name]; SELECT status FROM local, notFound => { [] ¬ ViewerOps.SaveViewer[ self ]; IF mouseButton # blue THEN { IF ~self.newVersion THEN UnsetNewVersion[self] } ELSE IF ~self.newVersion THEN ViewerOps.SetNewVersion[self]; }; ENDCASE => BadSaveOrStore[status, exp, self.name]; }; -- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * LoadFile: PROC[self: Viewer, filename: ROPE, noName: BOOL ¬ FALSE] = { status: FileStatus; s, fName, nameToUse: ROPE; EntryErrorReport: ENTRY PROC[exp: ROPE] = INLINE { ENABLE UNWIND => NULL; ErrorReport[exp]; }; [status, s, fName] ¬ CheckForFile[filename, FALSE]; IF status = notFound THEN { [status, s, fName] ¬ CheckForFile[filename]; -- try .form extension nameToUse ¬ fName; } ELSE nameToUse ¬ filename; IF status = local OR status = remote THEN { self.file ¬ NIL; -- make sure that no one else thinks you're saving something TiogaMenuOps.Load[ self, nameToUse ]; ViewerTools.EnableUserEdits[ self ]; -- in case remote file specified IF noName THEN { self.name ¬ sendCaption; ViewerOps.PaintViewer[self, caption]; self.file ¬ NIL; -- don't want any file association }; GrabFocus[self]; UnsetNewVersion[self]; } ELSE EntryErrorReport[s]; }; CheckForFile: PROC[name: ROPE, addExt: BOOL ¬ TRUE] RETURNS[fileStatus: FileStatus ¬ local, explanation, fName: ROPE] = { pathName: PFS.PATH ¬ PFS.PathFromRope[name]; fullPath: PFS.PATH; fullPath ¬ PFS.FileLookup[pathName, IF addExt THEN LIST[".form"] ELSE NIL ! PFS.Error => CONTINUE]; IF fullPath = NIL THEN { explanation ¬ IO.PutFR1["%g not found", [rope[name]] ]; fileStatus ¬ notFound; } ELSE fName ¬ PFS.RopeFromPath[fullPath]; }; ErrorReport: INTERNAL PROC[exp: ROPE] = { InternalReport[format: "\n%g\n", v1: [rope[exp]], blink: TRUE]; }; BadSaveOrStore: ENTRY PROC[status: FileStatus, exp, name: ROPE] = { ENABLE UNWIND => NULL; SELECT status FROM notFound => InternalReport[format: "Can't store on remote file: \"%g\"\n", v1: [rope[name]], blink: TRUE]; illegalName, otherError => ErrorReport[exp]; ENDCASE => ERROR; }; -- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -- read the user profile line for message forms and add one menu entry for each SetFormsList: PROC = { OPEN Menus; fLLast: LIST OF ROPE ¬ NIL; popUpFormsFileNames ¬ UserProfile.ListOfTokens[key: "SendMailTool.MsgForms", default: NIL]; popUpFormsList ¬ NIL; FOR fl: LIST OF ROPE ¬ popUpFormsFileNames, fl.rest UNTIL fl = NIL DO form: ROPE ¬ fl.first; shortName: ROPE; fullPath: PFS.PATH; IF form.Length[] = 0 THEN LOOP; -- zero length name not allowed shortName ¬ PFSNames.ComponentRope[PFSNames.ShortName[PFS.PathFromRope[form]]]; shortName ¬ shortName.Substr[0, shortName.Index[0, "."]]; IF fLLast = NIL THEN popUpFormsList ¬ fLLast ¬ LIST[shortName] ELSE { fLLast.rest ¬ LIST[shortName]; fLLast ¬ fLLast.rest; }; ENDLOOP; popUpFormsList ¬ CONS["NewSender", CONS["Default Form", CONS["Previous Msg", popUpFormsList]]]; }; -- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -- Start code: create menus and register ourselves DoInit: PROC = { OPEN Menus; pL: LIST OF MailSend.MailSendProcsRef ¬ MailSend.GetRegisteredSendProcsList[]; len: INT; TRUSTED { len ¬ List.Length[LOOPHOLE[pL, List.LORA]] }; FOR procs: LIST OF MailSend.MailSendProcsRef ¬ MailSend.GetRegisteredSendProcsList[], procs.rest UNTIL procs = NIL DO tName: ROPE ¬ IF ( len = 1 ) THEN NIL ELSE Atom.GetPName[procs.first.which]; name: ROPE ¬ Rope.Concat[tName, "Send"]; AppendMenuEntry[sendMenu, CreateEntry[name: name, proc: MessageSendProc, clientData: procs.first.which, fork: FALSE, guarded: procs.first.which = $gv]]; IF (procs.first.which = $xns) THEN AppendMenuEntry[sendMenu, CreateEntry[name: Rope.Concat[tName, "USend"], proc: MessageUSendProc, clientData: procs.first.which, fork: FALSE]]; ENDLOOP; AppendMenuEntry[sendMenu, CreateEntry["Get", SenderGetFileProc]]; AppendMenuEntry[sendMenu, CreateEntry[name: "Store", proc: SenderStoreProc, guarded: TRUE]]; AppendMenuEntry[sendMenu, CreateEntry["Save", SenderSaveProc]]; AppendMenuEntry[sendMenu, CreateEntry["Forms", SenderFormsProc]]; AppendMenuEntry[sendMenu, CreateEntry["CR/LF", ForceCRLFProc]]; AppendMenuEntry[sendMenu, CreateEntry["Split", SenderSplitProc]]; AppendMenuEntry[sendMenu, CreateEntry["Places", SenderPlacesProc]]; AppendMenuEntry[sendMenu, CreateEntry["Levels", SenderLevelsProc]]; AppendMenuEntry[sendingMenu, CreateEntry["StopSending!", AbortSendProc]]; AppendMenuEntry[confirmMenu, CreateEntry["Confirm", ConfirmSendProc]]; AppendMenuEntry[confirmMenu, CreateEntry["Deny", DenySendProc]]; AppendMenuEntry[replyToMenu, CreateEntry["Self", ReplyToSelfProc]]; AppendMenuEntry[replyToMenu, CreateEntry["All", ReplyToAllProc]]; AppendMenuEntry[replyToMenu, CreateEntry["Cancel", ReplyToCancelProc]]; Commander.Register["SendMail", SendMailCmd, "Mail sending tool"]; Commander.Register["SendMailTool", SendMailCmd, "Mail sending tool"]; SendMailInit[firstTime]; UserProfile.CallWhenProfileChanges[SendMailInit]; { path: ROPE = "SendMailTool.icons"; senderIcon ¬ Icons.NewIconFromFile[path, 6]; IF senderIcon = unInit THEN senderIcon ¬ tool ELSE { edittingIcon ¬ Icons.NewIconFromFile[path, 9]; notSentIcon ¬ Icons.NewIconFromFile[path, 19]; }; }; IF UserProfile.Boolean["SendMailTool.GlobalSenderButton", FALSE] THEN [] ¬ Buttons.Create[info: [name: "Sender"], proc: NewSenderClickProc]; }; initDir: ROPE ~ PFS.RopeFromPath[PFS.GetWDir[]]; DoInit[]; END. SendMailControlImpl.mesa Copyright Σ 1984, 1989, 1990, 1991, 1992, 1993 by Xerox Corporation. All rights reserved. Willie-Sue, February 2, 1990 5:44:01 pm PST Willie-s, April 26, 1993 6:33 pm PDT Theimer, April 30, 1990 10:39 pm PDT Contents: Control module for SendMail Last Edited by: Willie-Sue, January 17, 1984 10:20:02 am PST Last Edited by: Donahue, October 7, 1983 9:42 am ************************************************************************ check for user name being set in defaultForm * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * be paranoid here IF defaultForm.fields.rest.rest.first = NIL THEN IF simpleUserNameList = NIL THEN SendMailInit[firstTime]; -- fixes up defaultForm ViewerOps.PaintViewer[senderV, menu]; -- shouldn't be necessary let's sidestep this issue for now removes the named button from the sender menu, if such a button exists; no errors make sure that there is no file pointed to so that you don't get something saved in UnSavedDocumentCache should take senderInfo off of chain of senderInfo's, but why bother? check if any comment nodes, and alert user if so for now, we assume single character newline delimiter - beware crlf assume cr and lf are the only values now find the newest link in the chain to copy properties Κ-Ψ•NewlineDelimiter –(cedarcode) style˜codešΟb™Kšœ ΟeœO™ZK™+K™$K™$K™Kšœ%™%—K˜Kšœ<™˜EKšœ$˜$Kšœ0˜0Kšœ4˜4K˜š ŸœŸœŸœ(ŸœŸœŸ˜HKšœ;˜;KšŸœ˜—K˜Kšœ Ÿœ˜*K˜Kšœ~Ÿœ˜„K˜KšœvŸœ˜|K˜KšœxŸœ˜~K˜Kš ŸœŸœŸœŸœŸœ˜WKšœ&‘™?KšœŸœ˜KšŸœŸœŸœ%˜G—Kšœ˜K˜—š  œŸœ$Ÿœ˜?K™!K˜K˜——K˜Kš‘X˜X˜š  œ$˜0KšœŸœ?Ÿœ˜YKšœŸœ>Ÿœ˜WKšœŸœ?Ÿœ˜YKšœ*Ÿœ˜.Kšœ ŸœŸœ˜Kš œŸœŸœŸœŸœ˜"K˜K˜Kš ŸœŸœŸœŸœŸœŸœ˜RKšœŸœ˜K˜PKšœLŸœ˜SKšœVŸœ˜]˜KšœBŸœ˜I—˜KšœCŸœ˜J—K˜šŸœŸœŸœD˜aKšŸœ Ÿœ˜—K˜,šŸœŸœŸœ˜K˜2Kš œŸœ ŸœŸœŸœ˜>Kšœ˜šŸœ˜K˜9K˜#Kšœ˜——K˜KšœŸœ˜KšŸœŸœŸœF˜bK˜+šŸœŸœŸœ˜4KšŸœ!˜%—K˜KšœŸœ˜KšŸœŸœŸœH˜eK˜,šŸœŸœŸœ˜5KšŸœ#˜'—K˜K˜RKšœ˜Kšœ˜——˜š œŸœŸœŸœ˜>KšŸœŸœŸœ˜KšœŸœ,˜KKšœ Ÿœ˜BK˜Kšœ%Ÿœ˜+Kšœ˜——˜š œŸœŸœŸœ˜7KšŸœŸœŸœ˜KšœŸœ,˜KKš ŸœŸœŸœŸœ‘˜1Kšœ$Ÿœ˜)Kšœ˜——˜š  œŸœŸœŸœ(˜DKšŸœŸœŸœ˜KšœŸœ&˜EKš ŸœŸœŸœŸœ‘˜1Kšœ+Ÿœ˜0Kšœ˜——K˜˜š œŸœŸœŸœŸœŸœ ŸœŸœŸœ ŸœŸœ˜ešŸœŸœŸœ˜˜KšŸœŸœ2˜L——K˜——˜š  œŸœŸœŸœŸœ˜7KšŸœŸœŸœ˜KšœŸœŸœ ˜KšŸœŸœŸœŸœ˜%š ŸœŸœŸœ(ŸœŸœŸ˜JšŸœŸ˜šŸœŸ˜Kšœ*Ÿœ˜1—šŸ˜KšœŸœ˜——K˜ KšŸœ˜—K˜——˜š   œŸœŸœŸœŸœ˜GKšŸœŸœŸœ˜K˜8šŸœŸœŸ˜Kšœ@˜@—š ŸœŸœŸœ"ŸœŸœŸ˜BK˜Kšœ˜Kš ŸœŸœŸœ ŸœŸœ˜$K˜?šŸœŸœŸœ˜Kšœ@˜@Kšœ.˜.K˜—KšŸœ˜—Kšœ˜K˜—š  œŸœŸœŸœŸœ˜GKšœŸœ Ÿœ˜KšŸœŸœŸœ˜š   œŸœŸœ ŸœŸœ˜FKšœ8˜8Kšœ6˜6šœC˜CKšœ ŸœŸœ˜ —KšŸœŸœ Ÿœ&˜9K˜—K˜K˜K˜š ŸœŸœŸœ"ŸœŸœŸ˜BKšœ˜Kšœ Ÿœ˜Kš ŸœŸœŸœ ŸœŸœ˜$K˜-KšœŸœ ˜"Kšœ.˜.KšŸœ˜—Kšœ˜K˜—š  œŸœŸœŸœŸœ˜5K™QKšŸœŸœŸœ˜K˜7KšŸœŸœŸœŸœ˜Kšœ>Ÿ œ˜Iš ŸœŸœŸœ"ŸœŸœŸ˜BK˜Kšœ˜Kš ŸœŸœŸœ ŸœŸœ˜$K˜>šŸœŸœŸœ˜Kšœ>Ÿ œ˜IKšœ.˜.K˜—KšŸœ˜—Kšœ˜——K˜Kš‘X˜XKš‘˜˜š œŸœŸœ˜.KšŸœŸœŸœ˜Kšœ˜Kšœ˜——˜š  œŸœŸœŸœ˜>KšŸœŸœŸœ˜KšœŸœ+˜JK˜KšŸœ ŸœŸœ˜6Kšœ˜K˜KšŸœ ŸœŸœ%Ÿœ˜>šœŸœ˜š ŸœŸœŸœŸœ ŸœŸœ˜VšŸœ‘!˜(KšœŸœ˜ K˜Kš œ ŸœŸœŸœŸœ˜0KšœŸœŸœŸœ˜ šŸœ&ŸœŸœŸ˜:Kšœ Ÿœ ˜K˜KšŸœ˜—K˜WKšŸœ ŸœŸœ˜K˜šŸœŸœŸœ Ÿ˜K˜KšŸœ˜—KšœŸœ Ÿœ Ÿœ˜6Kšœ˜——šŸœ1Ÿ˜7Kšœ#˜#—Kšœ)˜)Kšœ˜K˜—Kšœ˜——˜š œ˜*Kšœ˜K˜Kšœ Ÿœ ŸœŸœ˜XKšœ˜Kšœ˜K˜—š  œŸœ˜Kšœ˜K˜Kšœ Ÿœ ŸœŸœ˜XKšœ˜Kšœ˜——˜š  œŸœŸœ˜-KšœŸœ+˜JK˜Kšœ$Ÿœ˜*Kšœ˜Kšœ˜——K˜Kš‘X˜X˜š œ˜-KšœŸœ+˜JKš ŸœŸœŸœŸœŸœ˜'KšŸœŸœŸœŸœ˜?Kšœh™hKš Ÿœ3ŸœŸœŸœŸœ˜LKšŸœŸœ'˜CKšŸœŸœ˜ Kšœ˜——˜š œŸœŸœŸœ2˜TKš œŸœŸœŸœŸœ˜>——˜š œŸœŸœŸœ%ŸœŸœŸœ˜XKšœŸœŸœŸœ3˜J——˜š œ˜+KšœŸœ+˜JKš ŸœŸœŸœŸœŸœ˜'šŸœŸ˜šœLŸœ˜RKšŸœŸœ˜ —Kšœ˜—Kšœ ŸœŸœŸœ ˜EKšŸœŸœ˜Kšœ˜——˜š œ˜/KšŸœ˜ KšœŸœ+˜JKš ŸœŸœŸœŸœŸœ˜'Kšœ‘˜-KšŸœŸœ˜Kšœ˜——˜š œŸœŸœ-˜HKšŸœŸœŸœ˜Kšœ ŸœŸœ˜KšŸœŸœŸœ‘˜+šŸœŸ˜šœ?˜?KšŸœ*ŸœŸœ˜L—Kšœ˜—KšŸœŸœŸœ˜K˜šŸœŸœŸ˜%KšœC˜C—K˜šŸœŸœŸ˜#Kšœ?˜?—K˜šŸœŸœŸ˜"Kšœ=˜=—K˜šŸœŸœŸ˜"Kšœ=˜=—K˜šŸœŸœŸ˜#KšœG˜G—K˜KšœŸœ˜KšœŸœ˜KšœŸœ˜KšœŸœ˜KšœŸœ˜K˜KšœD™DK™KšŸœŸœ$˜@Kšœ˜——˜š œŸœŸœŸœ˜5KšŸœŸœŸœ˜KšœŸœ+˜JKšŸœŸœŸœŸœ˜ KšœŸœ˜Kšœ˜——˜š œŸœŸœŸœ˜8KšŸœŸœŸœ˜KšœŸœ+˜JKšŸœŸœŸœŸœ˜ KšœŸœ˜Kšœ˜K˜—š  œŸœŸœŸœ Ÿœ ŸœŸœŸœ˜gKšŸœŸœŸœ˜Kšœ)˜)Kšœ˜—K˜š œŸœŸœ Ÿœ ŸœŸœŸœ˜eKšœŸœŸœ˜KšœŸœ˜š  œŸœ˜šŸœ ŸœŸœ˜Kšœ?Ÿœ"˜fKšœ(Ÿœ˜;KšœoŸœ˜uKšœ˜—šŸœŸ˜ šœ;‘˜TKšŸœ ŸœŸœ˜1—Kšœ˜—Kšœ"˜"KšœŸœ˜ K˜—šŸ˜šœŸœ ŸœŸœ˜7Kšœ Ÿœ˜KšŸœŸœŸœ˜(KšŸœ˜ —KšŸœŸœŸœ˜KšŸœ˜—Kšœ˜——˜Kš œŸœŸœ ŸœŸœŸœŸœ˜KKšœŸœ˜KšœŸœŸœ˜J—˜š œŸœ˜1KšŸœŸœŸœ˜KšŸœŸœŸœ8˜QKšœŸœ˜Kšœ Ÿœ˜šŸœŸœŸœŸ˜%KšŸœ#ŸœŸœ˜/KšœŸœ˜KšŸœ˜KšŸœ˜—Kšœ Ÿœ˜KšŸœŸœ˜Kšœ˜——˜š  œŸœŸœŸœŸœ˜5šŸœ ŸœŸ˜šœ˜Kšœ7˜7KšœŸœ˜Kšœ"˜"Kšœ Ÿœ˜Kšœ Ÿœ˜—Kšœ˜—KšŸœ ŸœŸœ˜'šŸœŸœŸœŸ˜&KšŸœŸœŸœ˜+KšŸœŸœŸœŸœ˜*K˜KšŸœ˜KšŸœ˜—Kšœ˜——˜š  œŸœŸœŸœŸœ˜7KšŸœŸœŸœ˜KšŸœŸœ Ÿœ˜'šŸœŸœŸœŸ˜&KšŸœŸœŸœ˜+KšœŸœ˜KšŸœ˜—šŸœ ŸœŸ˜šŸœŸœŸœŸ˜&KšŸœŸœŸœŸœ˜*K˜"KšŸœ˜KšŸœ˜——Kšœ˜——˜š  œŸœ˜&KšŸœŸœŸœ˜KšœŸœ ˜ KšœŸœ+˜JKšœŸœ˜KšœŸœ˜ KšŸ œ˜Kšœ˜——˜š œŸœ˜)KšŸœŸœŸœ˜KšœŸœ ˜ KšœŸœ+˜JKšœŸœ˜KšœŸœ˜ KšŸ œ˜Kšœ˜——˜š  œŸœ˜'KšŸœŸœŸœ˜KšœŸœ ˜ KšœŸœ+˜JKšœ%˜%KšœŸœ˜Kšœ˜——˜š œŸœ˜)KšŸœŸœŸœ˜KšœŸœ ˜ KšœŸœ+˜JK˜"KšœŸœ˜ KšŸ œ˜Kšœ˜——˜š œŸœ˜(KšŸœŸœŸœ˜KšœŸœ ˜ KšœŸœ+˜JK˜!KšœŸœ˜ KšŸ œ˜Kšœ˜——˜š œŸœ˜+KšŸœŸœŸœ˜KšœŸœ ˜ KšœŸœ+˜JK˜$KšœŸœ˜ KšŸ œ˜Kšœ˜——˜š  œŸœŸœŸœŸœ˜UKšŸœŸœŸœ˜K˜%KšœŸœŸœŸœ˜>KšŸœŸœŸœŸœ˜=KšœŸœ˜!KšŸœ˜#Kšœ˜——˜š  œŸœŸœŸœŸœŸœ˜NKšŸœŸœŸœ˜šŸœŸœ˜Kšœ+˜+KšŸœŸœŸœ'˜HKšŸœŸœ%Ÿœ˜EKšœ˜—KšŸœ˜Kšœ˜——˜šœ7˜7K˜—š œŸœŸœ#˜@KšŸœŸœŸœ˜š ŸœŸœŸœ"ŸœŸœŸ˜BKšœŸœ˜KšŸœŸœŸœ˜'KšŸœŸœ ŸœŸœ˜.šŸœŸœ˜˜KšŸœ ŸœŸœ‘ ˜8šŸœŸœŸœŸ˜*KšŸœ˜KšŸœŸœŸœŸœ˜&KšŸœ˜—Kšœ/˜/KšŸœ‘˜)KšŸœ˜K˜—KšŸœ˜—KšŸœŸœ‘˜*Kšœ˜K˜—š   œŸœŸœŸœŸœŸœ˜HKš œŸœŸœŸœŸœ˜>——˜š  œŸœŸœŸœŸœ˜HK˜%K˜4KšœŸœŸœŸœ˜>KšŸœŸœŸœŸœ˜=Kšœ!˜!KšœŸœ˜!KšŸœ˜Kšœ˜——˜š  œŸœŸœ˜LK˜Kšœ˜Kšœ˜——˜š œŸœ˜*KšœŸœ ˜Kšœ ŸœŸœ ˜%Kšœ Ÿœ+˜:Kšœ#˜#KšŸœ ŸœŸœ˜*KšŸœŸœ Ÿœ˜AKšŸœŸœ3Ÿœ˜YKšœ˜——˜š œ˜$KšœŸœ ˜Kšœ ŸœŸœ ˜%Kšœ Ÿœ+˜:Kšœ#˜#KšŸœ ŸœŸœ˜*KšŸœŸœ3Ÿœ˜ZKšœ˜K˜—š œ˜*KšœŸœ ˜Kšœ ŸœŸœ ˜%Kšœ Ÿœ+˜:Kšœ ŸœŸœ˜Kšœ#˜#Kšœ0™0šŸœJ˜MšŸœŸœŸ˜KšŸœ(ŸœŸœ˜4KšŸœ˜——šŸœ Ÿœ˜KšŸœŸœ7˜TKšŸœ˜K˜—KšŸœ ŸœŸœ˜*KšŸœŸœ3Ÿœ˜WKšœ˜K˜—KšœŸœ˜šœŸœ˜K˜—š  œ˜!KšœŸœ ˜K˜@K˜2K˜FKšœ8 ™CKšœ Ÿœ5˜CK™$Kš œ ŸœŸœŸœŸœ˜6šŸœŸ˜K˜*KšŸœŸœŸœŸœ˜MKšœ˜KšŸœ˜—Kšœ˜K˜-Kšœ)‘˜;K˜%K˜——˜š  œŸœ:Ÿœ Ÿœ˜cKšœŸœ)˜HKšœd˜dšŸœŸœ˜#Kšœ"˜"Kšœ"˜"KšŸœ˜K˜—KšŸœ ŸœŸœ˜*Kšœ2Ÿœ˜8K˜K˜—š  œŸœ<Ÿœ ŸœŸœ˜yKšŸœ ˜KšœŸœ˜ KšœŸœ+˜JKšœŸœ˜K˜Kšœ˜KšœŸœ˜K˜šŸœŸœV˜kKšŸœb˜f—KšŸœ Ÿœ˜)K˜K˜)KšœŸœŸœ Ÿœ ˜9Kšœ˜Kšœ$˜$šŸœŸœ˜š œŸœŸœ˜Kš œŸœŸœŸœ&Ÿœ˜F—KšŸœŸœŸœŸœ˜NKšœ˜Kšœ˜Kšœ˜—Kšœ˜——˜š œ˜#KšœŸœ ˜Kšœ ˜ Kšœ˜Kšœ˜Kšœ8™8KšŸœŸœŸœŸœ˜BK˜Kšœ Ÿœ)˜K˜˜2Kšœ@Ÿœ˜F—˜0Kšœ<Ÿœ˜B—˜/Kšœ?Ÿœ˜E—K˜Kšœ˜——˜š  œŸœŸœ˜0KšœŸœŸœŸœ'˜>——˜š œŸœŸœ˜;K˜ Kšœ˜Kšœ˜šŸ˜KšŸœŸœŸœ˜ KšœŸœ)˜4šŸœŸœŸœ˜šŸœŸœŸ˜Kšœ<˜<—KšŸœŸœŸœ8˜SKšŸœŸœŸœ6˜PKšœŸœ˜KšœŸœ˜KšœŸœ˜Kšœ˜—K˜KšŸœŸœŸœ!‘˜CK˜ KšŸœ˜—Kš‘3˜3š ŸœŸœŸœ"ŸœŸœŸ˜@KšŸœ ŸœŸœ˜.KšŸœ˜—K˜KšœŸœ0˜;KšŸœŸœŸœŸœ˜Kšœ Ÿœ˜"Kšœ˜——˜š œ˜"KšœL˜L——˜š œ˜"KšœL˜L——˜š œŸœŸœŸœ˜?KšŸœŸœŸœ˜Kšœ˜Kšœ Ÿœ˜KšŸœŸœŸœ˜%K˜K˜2šŸœŸœŸœ˜3K˜3KšœŸœ)˜HKšœ%Ÿœ˜+Kšœ˜Kšœ˜—KšŸœ˜Kšœ˜——˜š œ˜%KšœŸœ ˜Kšœ Ÿœ&˜4KšŸœŸœŸœ˜%Kšœ˜Kšœ˜——˜š œ˜#KšœŸœ ˜ KšœŸœ˜ KšœŸœŸœŸœ˜(Kšœ Ÿœ˜&KšŸœŸœŸœŸœ˜$K˜8šŸœŸ˜KšœŸœ‘œ˜#KšœŸœ˜!KšœŸœ˜(Kšœ(Ÿœ˜1KšŸœ˜—K˜šŸœŸœŸœ Ÿ˜K˜KšŸœ˜—Kšœ%˜%Kšœ˜K˜—š œ˜#KšœŸœ ˜KšœŸœ&˜9Kšœ˜Kšœ Ÿœ˜K˜'šŸœŸ˜šœ˜Kšœ#˜#šŸœŸ˜KšœŸœŸœ˜2KšŸœŸœŸœ˜<—Kšœ˜—KšŸœ*˜1—Kšœ˜——˜š œ˜"KšœŸœ ˜Kšœ˜Kšœ Ÿœ˜KšŸœ ŸœŸœ2Ÿœ˜RK˜K˜(šŸœŸ˜šœ˜K˜"šŸœŸ˜KšœŸœŸœ˜2KšŸœŸœŸœ˜<—K˜—KšŸœ+˜2—Kšœ˜——K˜Kš‘H˜H˜š  œŸœŸœ ŸœŸœ˜FKšœ˜KšœŸœ˜š  œŸœŸœŸœŸœ˜2KšŸœŸœŸœ˜Kšœ˜K˜—Kšœ,Ÿœ˜3šŸœŸœ˜Kšœ.‘˜DK˜K˜KšŸœ˜—Kšœ˜šŸœŸœŸ˜)šœŸœ‘<˜OKšœ%˜%Kšœ&‘ ˜FšŸœŸ˜˜Kšœ%˜%Kšœ Ÿœ‘"˜4—Kšœ˜—Kšœ˜Kšœ˜—Kšœ˜—KšŸœ˜Kšœ˜——˜š   œŸœŸœ ŸœŸœ˜3šœŸœ5Ÿœ˜FK˜—Kšœ ŸœŸœŸœ˜-Kšœ ŸœŸœ˜Kšœ ŸœŸœŸœŸœ ŸœŸœŸœ Ÿœ˜cšŸœ ŸœŸœ˜KšœŸœ&Ÿ˜7K˜Kšœ˜KšŸœ Ÿœ˜(—Kšœ˜——˜š  œŸœŸœŸœ˜)Kšœ9Ÿœ˜?Kšœ˜——˜š œŸ œ Ÿœ˜CKšŸœŸœŸœ˜šŸœŸ˜šœ ˜ KšœXŸœ˜^—Kšœ,˜,—KšŸœŸœ˜Kšœ˜K˜——Kš‘H˜HKš‘O˜O˜š  œŸœ˜KšŸœ˜ Kš œŸœŸœŸœŸœ˜˜Kšœ@Ÿœ˜E—KšœŸœ˜K˜š ŸœŸœŸœŸœ ŸœŸœŸ˜EKšœŸœ ˜Kšœ Ÿœ˜Kšœ ŸœŸ˜KšŸœŸœŸœ‘˜@K˜Kšœ6Ÿœ˜OK˜9šŸœ ŸœŸœŸœ ˜>šŸœ˜KšœŸœ ˜K˜K˜——KšŸœ˜—K˜˜KšŸœŸœŸœ#˜N—Kšœ˜——K˜Kš‘H˜HKš‘3˜3K˜š œŸœ˜KšŸœ˜ KšœŸœŸœC˜NKšœŸœ˜ KšŸœŸœ Ÿœ˜7š ŸœŸœŸœOŸœ ŸœŸ˜uKš œŸœŸœ ŸœŸœŸœ"˜LKšœŸœ˜(KšœnŸœ%˜˜šŸœŸ˜"Kšœ†Ÿœ˜Ž—KšŸœ˜—K˜KšœA˜AKšœUŸœ˜\Kšœ?˜?KšœA˜AK˜?KšœA˜AKšœC˜CKšœC˜CK˜KšœI˜IK˜KšœF˜FKšœ@˜@K˜KšœC˜CKšœA˜AKšœG˜G—˜KšœA˜AKšœE˜EKšœ˜Kšœ1˜1K˜šœ˜KšœŸœ˜"K˜,šŸœŸœ˜-šŸœ˜K˜.K˜.K˜——Kšœ˜—K˜šŸœ8ŸœŸ˜EK˜F—Kšœ˜K˜—Kšœ ŸœŸœŸœ ˜0K˜ K˜KšŸœ˜—…—•Ηψ