-- File: WalnutRetrieveParseImpl.mesa
-- Contents: Implementation of the parsing of text into MsgRecs
-- Last edit by:
-- Rick on: XXX
-- Willie-Sue on: September 9, 1983 4:10 pm

DIRECTORY
 GVMailParse USING [endOfInput, ParseError, ParseHandle,
     FinalizeParse, GetFieldBody, GetFieldName, InitializeParse],
 Rope,
IO,
 WalnutLog USING [MsgRec],
 WalnutParse USING [MessageFieldIndex, MessageInfo, ParseStatus, messageParseArray],
 WalnutRetrieve;

WalnutRetrieveParseImpl: CEDAR PROGRAM
IMPORTS
GVMailParse, IO, Rope, WalnutParse
EXPORTS
WalnutRetrieve =

BEGIN OPEN GVMailParse;

ROPE: TYPE = Rope.ROPE;

-- turn the strm into records

ParseMsgIntoFields: PUBLIC PROC[msg: WalnutLog.MsgRec, strm: IO.STREAM, msgLength: INT]
  RETURNS[s: WalnutParse.ParseStatus, sPos, mPos: INT] =
BEGIN
mLF: WalnutParse.MessageInfo;
startPos: INT← strm.GetIndex[];
lastCharPos: INT← startPos + msgLength;

NextChar: PROC[] RETURNS [ch: CHAR] =
{ IF mPos > lastCharPos THEN ch← endOfInput
  ELSE ch← strm.GetChar[ ! IO.EndOfStream => {ch← endOfInput; CONTINUE}];
mPos← mPos + 1;
};
SimpleField: PROC[index: WalnutParse.MessageFieldIndex, fieldBody: ROPE] =
BEGIN
SELECT index FROM
  senderF => msg.inMsgSender← fieldBody;
  replyToF, ccF, cF, bccF => NULL;
  fromF => msg.from← fieldBody;
  dateF => msg.date← fieldBody;
  subjectF => msg.subject← fieldBody;
  inReplyToF => msg.inReplyTo← fieldBody;
  toF => msg.to← fieldBody;
  voiceF => msg.voiceID← fieldBody;
ENDCASE => ERROR;
END;

 CategoriesField
: PROC[fB: ROPE] RETURNS [LIST OF ROPE] =
BEGIN
end: INT← fB.Length[];
p: INT← Rope.SkipOver[fB, 0, " \n"];
r: ROPE;
IF p # end THEN r← Rope.Substr[fB, p, end-p+1] ELSE {r← fB; p← 0};
IF (p← Rope.Find[fB, "',", p]) < 0 THEN RETURN[CONS[r, NIL]]
ELSE RETURN[CONS[r, CategoriesField[Rope.Substr[r, p+1, end-p]]]];
END;

pH: ParseHandle← InitializeParse[];
BEGIN
field: ROPENIL;
s← ok;  -- good status
 mPos← startPos;

DO
found, fieldNotRecognized: BOOLTRUE;
sPos← mPos;
[field, found]← GetFieldName[pH, NextChar ! ParseError => GOTO parseErrorExit];
IF ~found THEN EXIT;

FOR i: WalnutParse.MessageFieldIndex IN WalnutParse.MessageFieldIndex DO
{ mLF← WalnutParse.messageParseArray[i];
IF Rope.Equal[mLF.name, field, FALSE] THEN-- ignore case
{ fieldNotRecognized← FALSE;
SELECT mLF.fType FROM
    simpleRope, rNameList => SimpleField[i, GetFieldBody[pH, NextChar]];
    rCatList => msg.categoriesList← CategoriesField[GetFieldBody[pH, NextChar]];
   ENDCASE => ERROR;
   };
};
ENDLOOP;
IF fieldNotRecognized THEN
  []← GetFieldBody[pH, NextChar, TRUE]; -- anything not recognized
ENDLOOP;

-- leaves strm positioned at the beginning of the body of the message
FinalizeParse[pH];
EXITS
  parseErrorExit => { FinalizeParse[pH]; RETURN[syntaxError, sPos, mPos]};
END;
END;
END.