<> <> <> <> <> <> DIRECTORY BasicTime USING [GMT, MonthOfYear, Now, nullGMT, Unpack, Unpacked], Convert USING [RopeFromInt, RopeFromTime], IO USING [BreakProc, Close, CreateStream, CreateStreamProcs, EndOfStream, Error, Flush, GetBlock, GetChar, GetIndex, GetInfo, GetLength, GetTokenRope, int, PutChar, PutFR, PutRope, RIS, rope, RopeFromROS, ROS, SetIndex, STREAM, StreamProcs], GVNames USING [IsMemberDirect, Membership], Process USING [Detach], RefText USING [AppendChar, ObtainScratch, ReleaseScratch], Rope USING [Cat, Concat, Equal, Fetch, Find, FromRefText, IsEmpty, Length, ROPE, Substr], ViewerIO USING [CreateViewerStreams, GetViewerFromStream], MT USING [CheckFromField, Info, ParseHeaders, PrintHeaders, TranslateToArpa, TranslateToGrapevine], SMTPControl USING [arpaExceptions, deadLetterName, deadLetterSenderName, defaultLogAcceptPriority, longGVMSName, notifyManagerNames], SMTPDescr USING [CopyForReturn, Create, CreateFailed, Descr, EnumerateRawRecipients, GetArpaReversePath, GetFormat, GetGvSender, GetPrecedeMsgText, GetReturnPathLine, RawRecipProc, RetrieveMsgStream, Unparse, WrongState], SMTPQueue USING [AddNewMessage], SMTPSupport USING [LogPriority], SMTPSyntax USING [EnumerateGVItems, GVItemProc]; SMTPSupportImpl: CEDAR MONITOR IMPORTS BasicTime, Convert, IO, GVNames, Process, RefText, Rope, ViewerIO, MT, SMTPControl, SMTPDescr, SMTPQueue, SMTPSyntax EXPORTS SMTPSupport = BEGIN ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; Descr: TYPE = SMTPDescr.Descr; <> currentLogAcceptPriority: PUBLIC SMTPSupport.LogPriority _ SMTPControl.defaultLogAcceptPriority; Log: PUBLIC PROC [priority: SMTPSupport.LogPriority, note1, note2, note3, note4, note5, note6, note7, note8, note9, note10: Rope.ROPE _ NIL] = { now: BasicTime.GMT _ BasicTime.Now[]; IF priority >= currentLogAcceptPriority THEN WriteToLog[priority, now, note1, note2, note3, note4, note5, note6, note7, note8, note9, note10]; IF priority >= ATTENTION THEN { -- notify managers ENABLE SMTPDescr.CreateFailed => CONTINUE; date: ROPE _ Rope.Cat["Date: ", RFC822Date[now], "\n"]; from: ROPE _ Rope.Cat["From: ", SMTPControl.deadLetterSenderName, "\n"]; to: ROPE _ Rope.Cat["To: ", SMTPControl.notifyManagerNames.first, "\n"]; subject: ROPE _ "Subject: Confusion in Mail Gateway\n\n"; header: ROPE _ Rope.Cat[date, from, to, subject]; descr: Descr _ SMTPDescr.Create[ gvSender: SMTPControl.deadLetterSenderName, rawRecipients: SMTPControl.notifyManagerNames, format: arpa, -- don't have GV items msgStream: IO.RIS[Rope.Cat[header, Rope.Cat[note1, note2, note3, note4, note5], Rope.Cat[note6, note7, note8, note9, note10]]]]; ForkNewMessage[descr, "ATTENTION"]; }; }; ForkNewMessage: PROC [descr: Descr, queue: ROPE] = TRUSTED { Process.Detach[FORK SMTPQueue.AddNewMessage[descr, queue]]; }; HeaderParseError: PUBLIC PROC [recipList: LIST OF ROPE, descr: Descr] = { ENABLE SMTPDescr.CreateFailed => CONTINUE; now: BasicTime.GMT _ BasicTime.Now[]; date: ROPE _ Rope.Cat["Date: ", RFC822Date[now], "\n"]; from: ROPE _ Rope.Cat["From: ", SMTPControl.deadLetterSenderName, "\n"]; to: ROPE _ Rope.Cat["To: ", SMTPControl.arpaExceptions.first, "\n"]; subject: ROPE _ "Subject: Parsing Error in Message Header\n\n"; header: ROPE _ Rope.Cat[date, from, to, subject]; getReturnPathLine: ROPE _ SMTPDescr.GetReturnPathLine[descr]; getPrecedeMsgText: ROPE _ SMTPDescr.GetPrecedeMsgText[descr]; msgStream: IO.STREAM; errors: IO.STREAM _ IO.ROS[]; before: IO.STREAM _ IO.ROS[]; after: IO.STREAM _ IO.ROS[]; info: MT.Info; body: ROPE; new: Descr; msgStream _ SMTPDescr.RetrieveMsgStream[descr]; SELECT SMTPDescr.GetFormat[descr] FROM arpa => { info _ MT.ParseHeaders[file: msgStream, errStream: errors]; msgStream.Close[]; MT.PrintHeaders[info, before]; MT.TranslateToGrapevine[info]; MT.PrintHeaders[info, after]; }; gv => { -- Copied from SMTPSendImpl AssignTextStream: SMTPSyntax.GVItemProc = { currentIndex: INT; IF itemHeader.type # Text THEN RETURN; currentIndex _ msgStream.GetIndex[]; msgStream _ CreateSubrangeStream[ origStream: msgStream, min: currentIndex, max: currentIndex+itemHeader.length]; continue _ FALSE; }; SMTPSyntax.EnumerateGVItems[GVStream: msgStream, proc: AssignTextStream]; info _ MT.ParseHeaders[file: msgStream, errStream: errors]; msgStream.Close[]; MT.PrintHeaders[info, before]; MT.TranslateToArpa[info]; MT.PrintHeaders[info, after]; }; ENDCASE => ERROR; body _ Rope.Cat[body, "Recipients: "]; FOR rest: LIST OF ROPE _ recipList, rest.rest UNTIL rest = NIL DO IF rest # recipList THEN body _ Rope.Cat[body, ", "]; body _ Rope.Cat[body, rest.first]; ENDLOOP; body _ Rope.Cat[body, "\n\n"]; body _ Rope.Cat[body, IO.RopeFromROS[errors], "\n"]; body _ Rope.Cat[body, "Before translation:\n\n", IO.RopeFromROS[before], "\n\n"]; body _ Rope.Cat[body, "After translation:\n\n"]; IF getReturnPathLine # NIL THEN body _ Rope.Cat[body, getReturnPathLine, "\n"]; IF getPrecedeMsgText # NIL THEN body _ Rope.Cat[body, getPrecedeMsgText, "\n"]; body _ Rope.Cat[body, IO.RopeFromROS[after], "\n\n"]; new _ SMTPDescr.Create[ gvSender: SMTPControl.deadLetterSenderName, rawRecipients: SMTPControl.arpaExceptions, format: arpa, -- don't have GV items msgStream: IO.RIS[Rope.Cat[header, body]]]; ForkNewMessage[new, "HeaderParseError"]; }; Undeliverable: PROC [why: ROPE, descr: Descr] = { ENABLE SMTPDescr.CreateFailed => CONTINUE; now: BasicTime.GMT _ BasicTime.Now[]; date: ROPE _ Rope.Cat["Date: ", RFC822Date[now], "\n"]; from: ROPE _ Rope.Cat["From: ", SMTPControl.deadLetterSenderName, "\n"]; to: ROPE _ Rope.Cat["To: ", SMTPControl.deadLetterName, "\n"]; subject: ROPE _ "Subject: Undeliverable mail notification\n\n"; header: ROPE _ Rope.Cat[date, from, to, subject]; getReturnPathLine: ROPE _ SMTPDescr.GetReturnPathLine[descr]; getPrecedeMsgText: ROPE _ SMTPDescr.GetPrecedeMsgText[descr]; msgStream: IO.STREAM; errors: IO.STREAM _ IO.ROS[]; before: IO.STREAM _ IO.ROS[]; info: MT.Info; sender, body: ROPE; new: Descr; msgStream _ SMTPDescr.RetrieveMsgStream[descr]; SELECT SMTPDescr.GetFormat[descr] FROM arpa => { sender _ SMTPDescr.GetArpaReversePath[descr]; info _ MT.ParseHeaders[file: msgStream, errStream: errors]; msgStream.Close[]; MT.PrintHeaders[info, before]; }; gv => { -- Copied from SMTPSendImpl AssignTextStream: SMTPSyntax.GVItemProc = { currentIndex: INT; IF itemHeader.type # Text THEN RETURN; currentIndex _ msgStream.GetIndex[]; msgStream _ CreateSubrangeStream[ origStream: msgStream, min: currentIndex, max: currentIndex+itemHeader.length]; continue _ FALSE; }; sender _ SMTPDescr.GetGvSender[descr]; SMTPSyntax.EnumerateGVItems[GVStream: msgStream, proc: AssignTextStream]; info _ MT.ParseHeaders[file: msgStream, errStream: errors]; msgStream.Close[]; MT.PrintHeaders[info, before]; }; ENDCASE => ERROR; body _ Rope.Cat[why, "\n\nThe message will be sent to:\n", sender, ".\n\n"]; body _ Rope.Cat[body, "The header of the message was:\n--------------------\n"]; IF getReturnPathLine # NIL THEN body _ Rope.Cat[body, getReturnPathLine, "\n"]; IF getPrecedeMsgText # NIL THEN body _ Rope.Cat[body, getPrecedeMsgText, "\n"]; body _ Rope.Cat[body, IO.RopeFromROS[before], "\n\n"]; new _ SMTPDescr.Create[ gvSender: SMTPControl.deadLetterSenderName, rawRecipients: LIST[SMTPControl.deadLetterName], format: arpa, -- don't have GV items msgStream: IO.RIS[Rope.Cat[header, body]]]; ForkNewMessage[new, "Undeliverable"]; }; WriteToLog: ENTRY PROC [priority: SMTPSupport.LogPriority, now: BasicTime.GMT, note1, note2, note3, note4, note5, note6, note7, note8, note9, note10: Rope.ROPE _ NIL] = { <> logViewerOut.PutRope[Convert.RopeFromTime[from: now, start: hours, end: seconds, useAMPM: FALSE, includeZone: FALSE]]; logViewerOut.PutRope[" "]; IF priority > noteworthy THEN { logViewerOut.PutRope[logPriorityNames[priority]]; logViewerOut.PutRope[": "]; }; logViewerOut.PutRope[note1]; logViewerOut.PutRope[note2]; logViewerOut.PutRope[note3]; logViewerOut.PutRope[note4]; logViewerOut.PutRope[note5]; logViewerOut.PutRope[note6]; logViewerOut.PutRope[note7]; logViewerOut.PutRope[note8]; logViewerOut.PutRope[note9]; logViewerOut.PutRope[note10]; logViewerOut.PutChar['\n]; logViewerOut.Flush[]; }; logPriorityNames: PUBLIC ARRAY SMTPSupport.LogPriority OF ROPE _ ["verbose", "noteworthy", "Important", "ATTENTION", "CRITICAL"]; logViewerIn, logViewerOut: STREAM; -- initialized below <> <> letNonMembersPlay: BOOL _ TRUE; goodGuys, badGuys: LIST OF ROPE; AuthorizationCheck: PUBLIC PROC [sender: ROPE] RETURNS [ok: BOOLEAN] = { RETURN[TRUE]}; <> < GV DL => Arpa>> <> <> <> <> <> <> <> <> <