-- File: WalnutSendOpsImpl.mesa
-- Contents: More procs for WalnutSend
-- Created by Willie-Sue, December 13, 1983
-- Last Edited by: Willie-Sue, May 1, 1984 4:47:57 pm PDT
DIRECTORY
GVAnswer USING [MakeHeader],
Menus,
IO,
Rope,
RopeIO USING [GetRope],
RuntimeError USING [BoundsFault],
TiogaOps USING [ Pattern, Ref, Location,
      CreateSimplePattern,
      GetSelection, InsertRope, SelectDocument, SelectPoint,
      SelectionRoot, SelectionSearch, SetSelection, ToPrimary],
ViewerOps,
ViewerClasses,
ViewerTools,
WalnutSendInternal,
WalnutSendOps;
WalnutSendOpsImpl: CEDAR MONITOR
IMPORTS
IO, Rope, RuntimeError,
GVAnswer,
Menus,
RopeIO, TiogaOps,
ViewerOps,
WalnutSendInternal, WalnutSendOps
EXPORTS
WalnutSendInternal, WalnutSendOps
SHARES Menus =
BEGIN OPEN WalnutSendOps, WalnutSendInternal;
-- ************************************************************************
nullIndex: INT = LAST[INT];
Answer: PUBLIC PROC[msgHeaders: ROPE, who: Viewer← NIL] RETURNS [v: Viewer] =
BEGIN
notOk: BOOL;
errorIndex: INT;
answer: ROPE;
answerForm: WalnutSendOps.Form;
AnswerGetChar: PROC[pos: INT] RETURNS[CHAR] = {RETURN[msgHeaders.Fetch[pos]]};
[notOk, answer, errorIndex]← GVAnswer.MakeHeader[AnswerGetChar, msgHeaders.Length[],
   simpleUserName, defaultRegistry];
IF notOk THEN
{ start, end: INT← errorIndex;
BEGIN ENABLE RuntimeError.BoundsFault => {start← 0; end← 1; CONTINUE};
IF start = nullIndex THEN start← 0
ELSE
{UNTIL msgHeaders.Fetch[start] = '\n DO start← start - 1; ENDLOOP;
start← start + 1};
IF end = nullIndex THEN end← start + 1
ELSE
{UNTIL msgHeaders.Fetch[end] = '\n DO end← end + 1; ENDLOOP;
end← end - 1};
END;
IF who # NIL THEN ShowErrorFeedback[who, start, end];
SenderReport[IO.PutFR[
"\nSyntax error in line starting at pos %g (in message being answered)",
  IO.int[start]]];
RETURN };
answerForm ← NEW[ WalnutSendOps.FormRec ←
  [formText: answerText, fields: ParseAnswerHeader[answer] ] ];
v← BuildSendViewer[TRUE, FALSE, answerForm, who];
ClearFileAssoc[v];
GrabFocus[v];
END;
ParseAnswerHeader: PROC[header: ROPE] RETURNS[fields: LIST OF ROPE] =
{ HeaderLines: ARRAY[0..3] OF Rope.ROPE;
startPos: INT ← Rope.Find[header, ": ", 0];
endOfLine: INT ← Rope.Find[header, "\n", startPos];
FOR i: INT IN [0..3] DO
HeaderLines[i] ← Rope.Substr[header, startPos+2, endOfLine-startPos-2];
startPos ← Rope.Find[header, ": ", endOfLine];
IF startPos = -1 THEN EXIT ELSE endOfLine ← Rope.Find[header, "\n", startPos]
ENDLOOP;
RETURN[ LIST[ HeaderLines[0], HeaderLines[1], HeaderLines[2], HeaderLines[3] ] ] };
Forward: PUBLIC PROC[msg: Viewer, who: Viewer← NIL] RETURNS[v: Viewer] =
TRUSTED
BEGIN
forwardForm: WalnutSendOps.Form =
NEW[WalnutSendOps.FormRec ← [formText: forwardText, fields: NIL]];
messagePattern: TiogaOps.Pattern = TiogaOps.CreateSimplePattern["ForwardedMessage"];
headerPattern: TiogaOps.Pattern = TiogaOps.CreateSimplePattern["MessageHeader"];
pstart, pend: TiogaOps.Location;
root: TiogaOps.Ref;
found: BOOL;
v← BuildSendViewer[TRUE, FALSE, forwardForm, who];
ClearFileAssoc[v];
TiogaOps.SelectDocument[v];
root ← TiogaOps.SelectionRoot[];
pstart ← TiogaOps.Location[ root, 0 ];
TiogaOps.SelectPoint[ v, pstart ];
found ← TiogaOps.SelectionSearch[pattern: headerPattern];
IF found THEN
{ [ ,pstart, pend, , , ] ← TiogaOps.GetSelection[];
TiogaOps.SetSelection[viewer: v, start: pstart, end: pend,
       level: word, pendingDelete: TRUE];
TiogaOps.InsertRope[ msg.name ] };
found ← TiogaOps.SelectionSearch[pattern: messagePattern];
IF NOT found THEN RETURN;
[ ,pstart, pend, , , ] ← TiogaOps.GetSelection[];
TiogaOps.SetSelection[ viewer: v, start: pstart, end: pend, level: node, pendingDelete: TRUE ];
TiogaOps.SelectDocument[ viewer: msg, which: secondary ];
TiogaOps.ToPrimary[];
UnsetNewVersion[v];
GrabFocus[v]
END;
ClearFileAssoc: PUBLIC PROC[v: Viewer] =
BEGIN
IF v.file # NIL THEN v.file← NIL;
 v.name← sendCaption;
 ViewerOps.PaintViewer[v, caption];
END;
SenderNewVersion: PUBLIC PROC[viewer: Viewer] =
BEGIN OPEN Menus;
menu: Menus.Menu = viewer.menu;
 firstForm: Menus.MenuEntry = Menus.GetLine[formsMenu, 0];

 getEntry: Menus.MenuEntry← Menus.FindEntry[menu, "Get"];
IF getEntry # NIL THEN Menus.SetGuarded[getEntry, TRUE];
 getEntry← Menus.FindEntry[menu, "Default"];
IF getEntry # NIL THEN Menus.SetGuarded[getEntry, TRUE];
 getEntry← Menus.FindEntry[menu, "PrevMsg"];
IF getEntry # NIL THEN Menus.SetGuarded[getEntry, TRUE];

FOR i: Menus.MenuLine IN [1..5) DO
  thisLine: Menus.MenuEntry = Menus.GetLine[menu, i];
  IF thisLine = NIL THEN EXIT;
IF Rope.Equal[thisLine.name, firstForm.name] THEN
FOR entry: MenuEntry ← thisLine, entry.link UNTIL entry = NIL DO
  SetGuarded[entry, TRUE]
ENDLOOP;
ENDLOOP;
 ViewerOps.PaintViewer[viewer, menu];  -- show as guarded
 viewer.newVersion← TRUE;
END;
UnsetNewVersion: PUBLIC PROC[viewer: Viewer] =
BEGIN OPEN Menus;
 menu: Menu = viewer.menu;
 firstForm: Menus.MenuEntry = Menus.GetLine[formsMenu, 0];

 getEntry: Menus.MenuEntry← Menus.FindEntry[menu, "Get"];
IF getEntry # NIL THEN Menus.SetGuarded[getEntry, FALSE];
 getEntry← Menus.FindEntry[menu, "Default"];
IF getEntry # NIL THEN Menus.SetGuarded[getEntry, FALSE];
 getEntry← Menus.FindEntry[menu, "PrevMsg"];
IF getEntry # NIL THEN Menus.SetGuarded[getEntry, FALSE];

FOR i: Menus.MenuLine IN [1..5) DO
thisLine: Menus.MenuEntry = Menus.GetLine[menu, i];
  IF thisLine = NIL THEN EXIT;
IF Rope.Equal[thisLine.name, firstForm.name] THEN
FOR entry: MenuEntry ← thisLine, entry.link UNTIL entry = NIL DO
  SetGuarded[entry, FALSE]
ENDLOOP;
ENDLOOP;
 ViewerOps.PaintViewer[viewer, menu];  -- show as unguarded
 viewer.newVersion← FALSE;
 ViewerOps.PaintViewer[viewer, caption];
END;
-- * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
TiogaTextFromStrm: PUBLIC PROC[strm: IO.STREAM, startPos: INT← 0, len: INTLAST[INT]]
RETURNS[contents: TiogaContents] =
-- returns NIL IF endOfStream encountered during read
BEGIN ENABLE IO.EndOfStream => GOTO TooShort;
 fulltext: ROPE;
 formatPos: INT;

 strm.SetIndex[startPos];
IF len = LAST[INT] THEN len ← strm.GetLength[] - startPos;
 fulltext← RopeIO.GetRope[strm, len];
 contents← NEW[ViewerTools.TiogaContentsRec];

IF (formatPos← fulltext.Find["\000\000"]) < 0 THEN  -- no formatting
  { contents.contents← fulltext; RETURN};

 contents.contents← fulltext.Substr[len: formatPos];
 contents.formatting← fulltext.Substr[formatPos];

EXITS TooShort => RETURN[NIL];
END;
END.