WalnutParseMsgImpl.mesa - procedures for parsing streams
Copyright © 1984, 1985 by Xerox Corporation. All rights reserved.
Willie-Sue, December 6, 1984 2:01:27 pm PST
Russ Atkinson (RRA) March 21, 1985 0:42:18 am PST
DIRECTORY
GVMailParse,
IO,
Rope,
RopeList USING [Append],
WalnutParseMsg,
WalnutSendOps USING [defaultRegistry];
WalnutParseMsgImpl:
CEDAR
PROGRAM
IMPORTS GVMailParse, IO, Rope, RopeList, WalnutParseMsg, WalnutSendOps
EXPORTS WalnutParseMsg = BEGIN OPEN WalnutParseMsg;
messageParseArray:
PUBLIC
ARRAY MessageFieldIndex
OF MessageInfo ←
[ ["Reply-to", simpleRope],
-- this is really wrong, a special case for now
["Sender", simpleRope],
["From", simpleRope],
["To", rNameList],
["cc", rNameList],
["c", rNameList],
["bcc", rNameList],
["Date", simpleRope],
["Subject", simpleRope],
["Categories", rCatList],
["In-reply-to", simpleRope],
["VoiceFileID", simpleRope]
];
ParseMsgFromStream:
PUBLIC PROC[strm:
IO.
STREAM, len:
INT, proc: ParseProc]
RETURNS[msgHeaders: MsgHeaders] =
expects strm to be the beginning of a message; parses the header fields looking for fields, calling proc with each fieldName as found; if proc=NIL THEN return all fields
BEGIN OPEN GVMailParse;
mPos: INT← 0;
pH: GVMailParse.ParseHandle← GVMailParse.InitializeParse[];
NextChar: PROC[] RETURNS [ch: CHAR] =
{
IF mPos > len
THEN ch← endOfInput
ELSE ch← strm.GetChar[ ! IO.EndOfStream => {mPos← len; ch← endOfInput; CONTINUE} ];
mPos← mPos + 1;
};
msgHeaders← NIL;
BEGIN ENABLE ParseError => GOTO parseErrorExit;
fieldName: ROPE← NIL;
found: BOOL;
wantThisField, continue: BOOL← TRUE;
msgHeaders← NIL;
DO
[fieldName, found]← GVMailParse.GetFieldName[pH, NextChar];
IF ~found THEN EXIT;
IF proc # NIL THEN [wantThisField, continue]← proc[fieldName];
IF wantThisField
THEN
msgHeaders← CONS[[fieldName, GVMailParse.GetFieldBody[pH, NextChar]], msgHeaders]
ELSE []← GVMailParse.GetFieldBody[pH, NextChar, TRUE];
IF ~continue THEN EXIT;
ENDLOOP;
GVMailParse.FinalizeParse[pH];
EXITS
parseErrorExit => { GVMailParse.FinalizeParse[pH]; RETURN[msgHeaders]};
END;
END;
Parse:
PUBLIC PROC[text:
ROPE]
RETURNS[status: SendParseStatus, sPos, mPos:
INT, rList:
LIST
OF
ROPE] =
BEGIN
OPEN GVMailParse;
mLF: MessageInfo;
lastCharPos: INT← text.Length[] - 1;
lastCharIsCR: BOOL← (text.Fetch[lastCharPos] = '\n);
GetNextChar: PROC[] RETURNS [ch: CHAR] =
{
IF mPos <= lastCharPos
THEN ch← text.Fetch[mPos]
ELSE
IF (mPos=lastCharPos+1)
AND ~lastCharIsCR
THEN ch← '\n
ELSE ch← endOfInput;
mPos← mPos + 1;
};
RNameListField:
PROC[index: WalnutParseMsg.MessageFieldIndex] =
BEGIN
fieldBody, fbEnd: LIST OF ROPE← NIL;
AnotherRName:
PROC[r1, r2:
ROPE, isFile, isNested:
BOOL]
RETURNS [
ROPE,
BOOLEAN] =
BEGIN
name: ROPE ← CanonicalName[r1, r2];
countOfRecipients: INT← 0; -- too lazy to figure this out now
IF fbEnd=
NIL
THEN fbEnd← fieldBody←
CONS[name,
NIL]
ELSE fbEnd← fbEnd.rest← CONS[name, NIL];
IF isFile
THEN status← includesPrivateDL
ELSE
IF name.Find["^"] < 0
THEN countOfRecipients← countOfRecipients + 1
ELSE IF status # includesPrivateDL THEN status← includesPublicDL;
RETURN[NIL, FALSE];
END;
ParseNameList[pH, GetNextChar, AnotherRName,
NIL];
SELECT index
FROM
toF, ccF, cF, bccF =>
IF rList =
NIL
THEN rList← fieldBody
ELSE rList← RopeList.Append[rList, fieldBody];
ENDCASE => NULL;
END;
pH: ParseHandle;
field: ROPE← NIL;
fieldNotRecognized: BOOL;
mPos← 0; -- where we are in the fulltext
status← ok; -- start with good status
pH← InitializeParse[];
DO
sPos← mPos;
[field, fieldNotRecognized]← GetFieldName[pH, GetNextChar ! ParseError =>
{ FinalizeParse[pH]; GOTO errorExit}];
IF ~fieldNotRecognized THEN EXIT;
FOR i: WalnutParseMsg.MessageFieldIndex
IN WalnutParseMsg.MessageFieldIndex
DO
{ mLF← WalnutParseMsg.messageParseArray[i];
IF Rope.Equal[WalnutParseMsg.messageParseArray[i].name, field,
FALSE]
THEN
{ fieldNotRecognized←
FALSE;
IF mLF.fType = rNameList
THEN
RNameListField[i ! ParseError => GOTO errorExit]
ELSE []← GetFieldBody[pH, GetNextChar, TRUE];
};
};
ENDLOOP;
IF fieldNotRecognized
THEN
[]← GetFieldBody[pH, GetNextChar, TRUE]; -- skip anything not recognized
ENDLOOP;
FinalizeParse[pH];
EXITS
errorExit => RETURN[syntaxError, sPos, mPos, NIL];
END;
CanonicalName:
PUBLIC
PROC [simpleName, registry:
ROPE]
RETURNS[name:
ROPE] =
BEGIN
name← simpleName;
IF registry.Length[] = 0
THEN name← name.Cat[".", WalnutSendOps.defaultRegistry]
ELSE name← name.Cat[".", registry];
END;
END.