-- SendParser.mesa -- Edited by Levin, February 17, 1981 10:49 AM -- Edited by Schroeder, March 5, 1981 2:07 PM -- Edited by Brotz, March 7, 1983 11:16 AM DIRECTORY Ascii USING [CR, SP], Core USING [DMSUser], csD: FROM "CoreStreamDefs" USING [Destroy, EndOfStream, Open, Read, Reset, SetPosition, StreamHandle, WriteBlock], dsD: FROM "DisplayDefs" USING [SetCursor], exD: FROM "ExceptionDefs" USING [cantExpand, deliveryToDL, DisplayException, expandingMsg], LaurelSendDefs USING [AbortPoint, FromState, GetCharPosition, InitReadChar, InsertRecipientInList, InsertReplyToField, MoveUnderline, ReadChar, ReportError, ReportProgress, RetryThis, SendMode], MailParseDefs USING [endOfList, FinalizeParse, GetFieldBody, GetFieldName, InitializeParse, maxFieldNameSize, maxRecipientLength, ParseError, ParseHandle, ParseNameList], opD: FROM "OperationsDefs" USING [Expand, FileError], Storage USING [Free, Node], String USING [AppendChar, AppendString, AppendSubString, EquivalentString, StringBoundsFault, SubStringDescriptor], vmD: FROM "VirtualMgrDefs" USING [CharIndex]; SendParser: PROGRAM IMPORTS csD, exD, dsD, LaurelSendDefs, MailParseDefs, opD, Storage, String EXPORTS LaurelSendDefs = BEGIN OPEN LaurelSendDefs; ParseForSend: PUBLIC PROCEDURE [user: Core.DMSUser, expandPublicDLs: BOOLEAN, sendMode: SendMode, userFeedback: BOOLEAN] RETURNS [unexpandedPublicDLs: CARDINAL, fromState: FromState, replyTo: BOOLEAN] = BEGIN pH: MailParseDefs.ParseHandle; -- DL Expander DLEntry: TYPE = RECORD [next: DLHandle, start, end: vmD.CharIndex, isFile: BOOLEAN, name: StringBody]; DLHandle: TYPE = POINTER TO DLEntry; dlHead, currentDL: DLHandle _ NIL; dlBuffer: csD.StreamHandle; AcceptDL: PROCEDURE [name: STRING, isFile: BOOLEAN] = BEGIN dl: DLHandle; lastDL: DLHandle _ NIL; FOR dl _ dlHead, dl.next UNTIL dl = NIL DO IF String.EquivalentString[name, @dl.name] THEN RETURN; lastDL _ dl; ENDLOOP; dl _ Storage.Node[SIZE[DLEntry]+(name.length+1)/2]; dl^ _ [next: NIL, start: errorStart, end: errorEnd-1, isFile: isFile, name: [length: 0, maxlength: name.length, text: ]]; IF currentDL # NIL THEN BEGIN dl.start _ currentDL.start; dl.end _ currentDL.end; END; String.AppendString[@dl.name, name]; IF lastDL = NIL THEN dlHead _ dl ELSE lastDL.next _ dl; END; -- of AcceptDL -- FlushDLList: PROCEDURE = BEGIN dl: DLHandle; UNTIL dlHead = NIL DO dl _ dlHead.next; Storage.Free[dlHead]; dlHead _ dl; ENDLOOP; csD.Destroy[dlBuffer]; END; -- of FlushDLList -- ProcessDLList: PROCEDURE = BEGIN char: CHARACTER; havePH: BOOLEAN _ FALSE; GetDLChar: PROCEDURE RETURNS [CHARACTER] = BEGIN char _ csD.Read[dlBuffer ! csD.EndOfStream => {char _ MailParseDefs.endOfList; CONTINUE}]; IF char = Ascii.CR THEN char _ Ascii.SP; RETURN[char]; END; -- of GetDLChar -- ReportProgress[exD.expandingMsg, NIL, TRUE]; dlBuffer _ csD.Open[NIL, byte, write]; BEGIN ENABLE UNWIND => {IF havePH THEN MailParseDefs.FinalizeParse[pH]; FlushDLList[]}; FOR currentDL _ dlHead, currentDL.next UNTIL currentDL = NIL DO MoveUnderline[currentDL.start, currentDL.end]; publicDLExpansion _ ~currentDL.isFile; DO CopyFileToCoreStream[dlBuffer, @currentDL.name ! opD.FileError => BEGIN AbortPoint[]; IF reason = cantConnect AND RetryThis[NIL, exD.cantExpand] THEN {ReportProgress[exD.expandingMsg, NIL, TRUE]; LOOP}; ReportError[dlExpandError, errorString, currentDL.start, currentDL.end]; END]; EXIT; ENDLOOP; AbortPoint[]; pH _ MailParseDefs.InitializeParse[GetDLChar]; havePH _ TRUE; MailParseDefs.ParseNameList[pH, ProcessName ! MailParseDefs.ParseError, String.StringBoundsFault => ReportError[dlSyntaxError, NIL, currentDL.start, currentDL.end]]; MailParseDefs.FinalizeParse[pH]; havePH _ FALSE; csD.Reset[dlBuffer]; ENDLOOP; END; -- ENABLE UNWIND FlushDLList[]; END; -- of ProcessDLList -- ProcessName: PROCEDURE [name, registry: STRING, isFile, ignored: BOOLEAN] RETURNS [write: BOOLEAN] = BEGIN publicDL, noRegistry: BOOLEAN; recipient: STRING _ [MailParseDefs.maxRecipientLength]; errorEnd _ GetCharPosition[]; IF isFile AND name[0] = '" THEN BEGIN -- remove quotes from file names (private dls). Ignore / quoting convention-there -- shouldn't be strange characters in private dl names anyway. snDesc: String.SubStringDescriptor _ [name, 1, name.length - 2]; String.AppendSubString[recipient, @snDesc]; END ELSE String.AppendString[recipient, name]; SELECT TRUE FROM (noRegistry _ registry.length = 0) AND publicDLExpansion => -- catches file name or no registry in remote DL ReportError[illegalRecipient, NIL, currentDL.start, currentDL.end]; isFile => AcceptDL[recipient, TRUE]; (publicDL _ recipient[recipient.length - 1] = '^) AND expandPublicDLs => BEGIN String.AppendChar[recipient, '.]; String.AppendString[recipient, IF noRegistry THEN user.registry ELSE registry]; AcceptDL[recipient, FALSE]; END; ENDCASE => BEGIN String.AppendChar[recipient, '.]; String.AppendString[recipient, IF noRegistry THEN user.registry ELSE registry]; InsertRecipientInList[recipient]; haveRecipient _ TRUE; IF publicDL THEN unexpandedPublicDLs _ unexpandedPublicDLs + 1; END; AbortPoint[]; errorStart _ errorEnd; RETURN[FALSE] END; -- of ProcessName -- ProcessFromName: PROCEDURE [name, registry: STRING, isFile, ignored: BOOLEAN] RETURNS [write: BOOLEAN] = BEGIN SELECT fromState FROM needsFrom => IF String.EquivalentString[name, user.name] AND String.EquivalentString[registry, user.registry] THEN fromState _ ok ELSE fromState _ needsSender; ENDCASE => fromState _ needsSender; END; -- of ProcessFromName -- -- beginning of code of ParseForSend fieldName: STRING _ [MailParseDefs.maxFieldNameSize]; publicDLExpansion, haveRecipient: BOOLEAN _ FALSE; errorStart, errorEnd: vmD.CharIndex; unexpandedPublicDLs _ 0; replyTo _ FALSE; fromState _ needsFrom; InitReadChar[]; pH _ MailParseDefs.InitializeParse[ReadChar]; DO -- Until message processed or error detected errorStart _ GetCharPosition[]; IF ~MailParseDefs.GetFieldName [pH, fieldName ! MailParseDefs.ParseError => GO TO syntaxError] THEN EXIT; IF String.EquivalentString[fieldName, "Date"L] OR String.EquivalentString[fieldName, "Sender"L] THEN GOTO syntaxError; errorStart _ GetCharPosition[]; SELECT TRUE FROM String.EquivalentString[fieldName, "To"L], String.EquivalentString[fieldName, "cc"L], String.EquivalentString[fieldName, "c"L], String.EquivalentString[fieldName, "bcc"L] => MailParseDefs.ParseNameList[pH, ProcessName ! MailParseDefs.ParseError, String.StringBoundsFault => GO TO syntaxError]; String.EquivalentString[fieldName, "From"L] => BEGIN IF fromState # needsFrom THEN GO TO syntaxError; MailParseDefs.ParseNameList[pH, ProcessFromName ! MailParseDefs.ParseError, String.StringBoundsFault => GO TO syntaxError]; IF fromState = needsFrom THEN GO TO syntaxError; END; ENDCASE => BEGIN IF String.EquivalentString[fieldName, "Reply-To"L] THEN replyTo _ TRUE; MailParseDefs.GetFieldBody [pH, fieldName ! MailParseDefs.ParseError => GO TO syntaxError]; END; REPEAT syntaxError => BEGIN MailParseDefs.FinalizeParse[pH]; errorEnd _ GetCharPosition[]; ReportError[messageSyntaxError, NIL, MIN[errorStart, errorEnd - 1], errorEnd]; END; ENDLOOP; -- Main message parsing loop MailParseDefs.FinalizeParse[pH]; IF userFeedback AND sendMode = blue AND ~replyTo AND (dlHead # NIL OR unexpandedPublicDLs # 0) THEN {exD.DisplayException[exD.deliveryToDL]; InsertReplyToField[user]}; IF dlHead # NIL THEN ProcessDLList[]; IF ~haveRecipient THEN ReportError[noRecipientsSpecified, NIL, 0, 0]; END; -- of ParseForSend -- CopyFileToCoreStream: PROCEDURE [stream: csD.StreamHandle, file: STRING] = -- Assumes that stream is write, byte, positioned at 0. Will copy contents of file -- into stream, using a backing temp file if the file is longer than one page. BEGIN AcceptBlock: PROCEDURE [p: POINTER, bytes: CARDINAL] RETURNS [BOOLEAN] = BEGIN IF bytes > 0 THEN csD.WriteBlock[stream, p, 0, bytes]; RETURN[TRUE]; END; -- of AcceptBlock -- opD.Expand[file, AcceptBlock]; dsD.SetCursor[hourGlass]; csD.SetPosition[stream, 0]; END; -- of CopyFileToCoreStream -- END. -- of SendParser --(635)\f1