DIRECTORY Basics, BasicTime, CrRPC, EnvelopeContentsP0V0, EnvelopeFormatP1517V1, IO, MailBasics, MailFormatExtraTypes, MailFormatP1516V3, MailTransportP17V5, MSBasics, MailParse, MSUtils, RefText, Rope, SystemSite USING [Get, Names], XNSCHItemOps, XNSCHName; MSUtilsImpl: CEDAR PROGRAM IMPORTS BasicTime, CrRPC, EnvelopeContentsP0V0, IO, MailParse, RefText, Rope, SystemSite, XNSCHItemOps, XNSCHName EXPORTS MSUtils ~ BEGIN OPEN EnvelopeContents: EnvelopeContentsP0V0, EnvelopeFormat: EnvelopeFormatP1517V1, MailFormat: MailFormatP1516V3, MailTransport: MailTransportP17V5; ROPE: TYPE ~ Rope.ROPE; STREAM: TYPE ~ IO.STREAM; NameBodyPairList: TYPE = MSUtils.NameBodyPairList; NameBodyPair: TYPE = MSUtils.NameBodyPair; HeaderFromText: PUBLIC PROC [text: ROPE, includeTextAnnotation: BOOL ฌ TRUE, plainText, formatting: ROPE] RETURNS [header: ROPE, errorCode: MailParse.ParseErrorCode ฌ none, index: INT ฌ 0, included: NameBodyPairList, notIncluded: NameBodyPairList] ~ { OPEN MailFormat; Next: PROC RETURNS [c: CHAR] ~ { IF index < length THEN { c ฌ Rope.Fetch[text, index]; index ฌ index + 1; } ELSE c ฌ MailParse.endOfInput; }; AddToIncludedList: PROC [fieldName: ROPE, fieldBody: ROPE] ~ { IF included = NIL THEN lastIncluded ฌ included ฌ LIST[[fieldName, fieldBody]] ELSE lastIncluded ฌ lastIncluded.rest ฌ LIST[[fieldName, fieldBody]]; }; AddToNotIncludedList: PROC [fieldName: ROPE, fieldBody: ROPE] ~ { IF notIncluded = NIL THEN lastNotIncluded ฌ notIncluded ฌ LIST[[fieldName, fieldBody]] ELSE lastNotIncluded ฌ lastNotIncluded.rest ฌ LIST[[fieldName, fieldBody]]; }; NameListFromRope: PROC [names: ROPE] RETURNS [nameList: XNSCHItemOps.NameList] ~ { LocalNext: PROC RETURNS [c: CHAR] ~ { IF localIndex < length THEN { c ฌ Rope.Fetch[names, localIndex]; localIndex ฌ localIndex + 1; } ELSE c ฌ IO.CR; -- this rope doesn't end with a CR so supply one }; EachName: PROC [rName: MailBasics.RName] RETURNS [nameToWrite: ROPE] ~ { IF rName.name = NIL THEN RETURN[NIL]; SELECT rName.ns FROM $xns => AddNameToList[XNSCHName.NameFromRope[rName.name ! XNSCHName.FieldTooLong => RESUME]]; $file => AddPrivateDLToList[rName.name]; ENDCASE => NULL; RETURN[NIL]; }; AddNameToList: PROC [name: XNSCHName.Name] = { IF nameList = NIL THEN lastName ฌ nameList ฌ LIST[name] ELSE lastName ฌ lastName.rest ฌ LIST[name]; }; AddPrivateDLToList: PROC [name: ROPE] = { xnsName: XNSCHName.Name; xnsName.organization ฌ NIL; xnsName.domain ฌ NIL; xnsName.object ฌ name.Concat[":;"]; IF nameList = NIL THEN lastName ฌ nameList ฌ LIST[xnsName] ELSE lastName ฌ lastName.rest ฌ LIST[xnsName]; }; lastName: XNSCHItemOps.NameList; localIndex: INT ฌ 0; length: INT ฌ Rope.Length[names]; localPH: MailParse.ParseHandle ฌ MailParse.InitializeParse[]; MailParse.NameList[localPH, $xns, LocalNext, EachName]; MailParse.FinalizeParse[localPH]; }; AddNameListAttribute: PROC [list: ROPE, value: CARD32, fName: ROPE, fBody: ROPE] ~ { nameList: XNSCHItemOps.NameList ฌ NameListFromRope[list]; tempPos: CARDINAL; [headerItem, pos] ฌ XNSCHItemOps.ItemFromCard32[value, pos, headerItem]; tempPos ฌ pos; [headerItem, pos] ฌ XNSCHItemOps.ItemFromCard16[card: 0, index: pos, item: headerItem]; [headerItem, pos] ฌ ItemFromNameListAsRNames[nameList, pos, headerItem]; [] ฌ XNSCHItemOps.Card16IntoItem[headerItem, pos-tempPos-1, tempPos]; attributeCount ฌ attributeCount + 1; AddToIncludedList[fName, fBody]; }; AddNameAttribute: PROC [name: ROPE, value: CARD32, fName: ROPE, fBody: ROPE] ~ { tempPos: CARDINAL; [headerItem, pos] ฌ XNSCHItemOps.ItemFromCard32[value, pos, headerItem]; tempPos ฌ pos; [headerItem, pos] ฌ XNSCHItemOps.ItemFromCard16[card: 0, index: pos, item: headerItem]; [headerItem, pos] ฌ XNSCHItemOps.ItemFromCard16[0, pos, headerItem]; -- the tag: 0 = xns [headerItem, pos] ฌ XNSCHItemOps.ItemFromName[XNSCHName.NameFromRope[name ! XNSCHName.FieldTooLong => RESUME], pos, headerItem]; [] ฌ XNSCHItemOps.Card16IntoItem[headerItem, pos-tempPos-1, tempPos]; attributeCount ฌ attributeCount + 1; AddToIncludedList[fName, fBody]; }; AddRopeAttribute: PROC [rope: ROPE, value: CARD32, fName: ROPE, fBody: ROPE] ~ { tempPos: CARDINAL; [headerItem, pos] ฌ XNSCHItemOps.ItemFromCard32[value, pos, headerItem]; tempPos ฌ pos; [headerItem, pos] ฌ XNSCHItemOps.ItemFromCard16[card: 0, index: pos, item: headerItem]; [headerItem, pos] ฌ XNSCHItemOps.ItemFromRope[rope, pos, headerItem]; [] ฌ XNSCHItemOps.Card16IntoItem[headerItem, pos-tempPos-1, tempPos]; attributeCount ฌ attributeCount + 1; IF fName # NIL THEN AddToIncludedList[fName, fBody]; }; lastIncluded: NameBodyPairList; lastNotIncluded: NameBodyPairList; textAnnotation: ROPE; length: INT ฌ Rope.Length[text]; pH: MailParse.ParseHandle ฌ MailParse.InitializeParse[]; pos: CARDINAL ฌ 0; attributeCount: CARDINAL ฌ 0; headerItem: XNSCHItemOps.Item; [headerItem, pos] ฌ XNSCHItemOps.ItemFromCard16[card: 0, index: 0, item: headerItem]; { ENABLE MailParse.ParseError => { errorCode ฌ code; GOTO DoneWithError}; DO fieldName: ROPE; fieldBody: ROPE; fieldName ฌ MailParse.GetFieldName[pH, Next]; IF fieldName = NIL THEN EXIT; fieldBody ฌ MailParse.GetFieldBody[pH, Next]; SELECT TRUE FROM Rope.Equal[s1: fieldName, s2: "Subject", case: FALSE] => { AddRopeAttribute[Rope.Substr[fieldBody, 0, 256], subject, fieldName, fieldBody]; }; Rope.Equal[s1: fieldName, s2: "Sender", case: FALSE] => { AddNameAttribute[fieldBody, originator, fieldName, fieldBody]; }; Rope.Equal[s1: fieldName, s2: "From", case: FALSE] => { AddNameListAttribute[fieldBody, authorizingUsers, fieldName, fieldBody]; }; Rope.Equal[s1: fieldName, s2: "To", case: FALSE] => { AddNameListAttribute[fieldBody, primaryRecipients, fieldName, fieldBody]; }; Rope.Equal[s1: fieldName, s2: "cc", case: FALSE] => { AddNameListAttribute[fieldBody, copyRecipients, fieldName, fieldBody]; }; Rope.Equal[s1: fieldName, s2: "Reply-To", case: FALSE] => { AddNameListAttribute[fieldBody, replyToUsers, fieldName, fieldBody]; }; ENDCASE => { maxTextAnnotation: INT ฌ 2000; additionalTextAnnotation: ROPE ฌ Rope.Cat[fieldName, ": ", fieldBody, "\r"]; IF includeTextAnnotation AND (Rope.Length[textAnnotation] + Rope.Length[additionalTextAnnotation] <= maxTextAnnotation) THEN textAnnotation ฌ Rope.Concat[textAnnotation, additionalTextAnnotation] ELSE AddToNotIncludedList[fieldName, fieldBody]; }; ENDLOOP; EXITS DoneWithError => NULL; }; MailParse.FinalizeParse[pH]; IF includeTextAnnotation AND textAnnotation # NIL THEN AddRopeAttribute[textAnnotation, MailFormat.textAnnotation, "Text-Annotation", textAnnotation]; IF ( plainText # NIL ) THEN { AddRopeAttribute[plainText, MailFormatExtraTypes.tiogaPlainText, NIL, NIL]; AddRopeAttribute[formatting, MailFormatExtraTypes.tiogaFormatting, NIL, NIL]; }; [] ฌ XNSCHItemOps.Card16IntoItem[headerItem, attributeCount, 0]; header ฌ ItemToRope[headerItem]; }; maxRefTextLen: NAT ฌ LAST[RefText.TextBound] - 1; ItemToRope: PUBLIC PROC [item: XNSCHItemOps.Item, length: CARDINAL ฌ LAST[CARDINAL]] RETURNS [rope: ROPE] ~ { buf: Basics.Word16; lenToDo: CARD16; start: CARD16 ฌ 0; text: REF TEXT; IF item = NIL THEN RETURN[NIL]; lenToDo ฌ MIN[item.length, length]; text ฌ RefText.ObtainScratch[MIN[maxRefTextLen, lenToDo]]; DO thisLen: CARD16 ฌ MIN[lenToDo, maxRefTextLen/2]; FOR i: CARDINAL IN [start..start+thisLen) DO buf.card ฌ item.body[i]; text ฌ RefText.AppendChar[text, LOOPHOLE[buf.hi]]; text ฌ RefText.AppendChar[text, LOOPHOLE[buf.lo]]; ENDLOOP; rope ฌ Rope.Concat[rope, Rope.FromRefText[text]]; IF ( lenToDo ฌ lenToDo - thisLen ) = 0 THEN EXIT; start ฌ start+thisLen; text.length ฌ 0; -- reset text ENDLOOP; RefText.ReleaseScratch[text]; }; ItemFromNameListAsRNames: PROC [names: XNSCHItemOps.NameList, index: CARDINAL ฌ 0, item: XNSCHItemOps.Item ฌ NIL] RETURNS [newItem: XNSCHItemOps.Item, nextPos: CARDINAL] ~ { countIndex: CARDINAL ฌ index; count: CARDINAL ฌ 0; [item, index] ฌ XNSCHItemOps.ItemFromCard16[0, index, item]; -- place holder for count FOR thisName: XNSCHItemOps.NameList ฌ names, thisName.rest WHILE thisName # NIL DO [item, index] ฌ XNSCHItemOps.ItemFromCard16[0, index, item]; -- the tag: 0 = xns [item, index] ฌ XNSCHItemOps.ItemFromName[thisName.first, index, item]; count ฌ count + 1; ENDLOOP; [] ฌ XNSCHItemOps.Card16IntoItem[item, count, countIndex]; RETURN[item, index]; }; XNSRNameFromRope: PUBLIC PROC [name: ROPE] RETURNS [rName: MSBasics.RName] ~ { xnsRName: MSBasics.CHRName; xnsRName ฌ NEW[MailTransport.RNameObject.xns ฌ [xns[]]]; xnsRName.xns ฌ XNSCHName.NameFromRope[name ! XNSCHName.FieldTooLong => RESUME]; RETURN[xnsRName]; }; StrippedName: PUBLIC PROC[name, domain, organization: ROPE] RETURNS[stripped: ROPE] = { chName: XNSCHName.Name ฌ XNSCHName.NameFromRope[name, domain, organization ! XNSCHName.FieldTooLong => RESUME]; IF thisOrganization = NIL THEN InitNames[]; IF thisOrganization.Equal[chName.organization, FALSE] THEN { IF thisDomain.Equal[chName.domain, FALSE] THEN RETURN[chName.object] ELSE RETURN[Rope.Cat[chName.object, ":", chName.domain]]; }; RETURN[XNSCHName.RopeFromName[chName ! XNSCHName.FieldTooLong => RESUME]]; }; thisDomain, thisOrganization: ROPE; ParseEnvelope: PUBLIC PROC [envelope: MailTransport.Envelope] RETURNS [parsed: MSBasics.Envelope] ~ { h: CrRPC.Handle ฌ CrRPC.CreateClientHandle[$Loopback, NIL]; FOR i: CARDINAL IN [0..envelope.length) DO item: MailTransport.EnvelopeItem ฌ envelope.body[i]; SELECT item.type FROM EnvelopeFormat.postmark => parsed.postmark ฌ EnvelopeContents.PostmarkFromItem[h, item.value].value; EnvelopeFormat.messageID => parsed.msgID ฌ EnvelopeContents.MessageIDFromItem[h, item.value].value; EnvelopeFormat.contentsType => parsed.ctype ฌ EnvelopeContents.ContentsTypeFromItem[h, item.value].value; EnvelopeFormat.tableOfContents => parsed.toc ฌ EnvelopeContents.TableOfContentsFromItem[h, item.value].value; EnvelopeFormat.contentsSize => parsed.size ฌ EnvelopeContents.ContentsSizeFromItem[h, item.value].value; EnvelopeFormat.originator => parsed.originator ฌ EnvelopeContents.OriginatorFromItem[h, item.value].value; EnvelopeFormat.authenticationLevelOfSender => { parsed.authenticationLevel ฌ EnvelopeContents.AuthenticationLevelOfSenderFromItem[h, item.value].value; parsed.authenticationLevelPresent ฌ TRUE; }; EnvelopeFormat.report => { parsed.report ฌ EnvelopeContents.ReportFromItem[h, item.value].value; parsed.reportPresent ฌ TRUE; }; EnvelopeFormat.gatewayPostmark => { parsed.gatewayPostmark ฌ EnvelopeContents.GatewayPostmarkFromItem[h, item.value].value; parsed.gatewayPostmarkPresent ฌ TRUE; }; EnvelopeFormat.priority => { parsed.priority ฌ EnvelopeContents.PriorityFromItem[h, item.value].value; parsed.priorityPresent ฌ TRUE; }; EnvelopeFormat.converted => { parsed.converted ฌ EnvelopeContents.ConvertedFromItem[h, item.value].value; parsed.convertedPresent ฌ TRUE; }; ENDCASE => NULL; ENDLOOP; }; SystemMessageFromEnvelope: PUBLIC PROC [envelope: MSBasics.Envelope] RETURNS [msg: ROPE] ~ { IF NOT envelope.reportPresent THEN RETURN[NIL]; msg ฌ IO.PutFR1["%g\r------------------\r", [rope[RopeFromReport[envelope.report, TRUE]]]]; }; RopeFromEnvelope: PUBLIC PROC [envelope: MSBasics.Envelope, newLines: BOOL ฌ TRUE, indentation: ROPE ฌ NIL] RETURNS [ROPE] ~ { out: STREAM ฌ IO.ROS[]; IF NOT newLines THEN indentation ฌ NIL; IO.PutF[out, "%gPostmark: %g", [rope[indentation]], IO.rope[RopeFromPostmark[envelope.postmark]]]; IO.PutRope[out, IF newLines THEN "\r" ELSE ", "]; IO.PutF[out, "%gSender: %g", [rope[indentation]], IO.rope[RopeFromMSRName[envelope.originator]]]; IO.PutRope[out, IF newLines THEN "\r" ELSE ", "]; IO.PutF[out, "%gMessage-ID: %g", [rope[indentation]], [rope[RopeFromMessageID[envelope.msgID]]]]; IO.PutRope[out, IF newLines THEN "\r" ELSE ", "]; IO.PutF[out, "%gContents-type: %g", [rope[indentation]], IO.rope[RopeFromContentsType[envelope.ctype]]]; IO.PutRope[out, IF newLines THEN "\r" ELSE ", "]; IO.PutF[out, "%gMessage-Size: %g", [rope[indentation]], IO.int[envelope.size]]; IO.PutRope[out, IF newLines THEN "\r" ELSE ", "]; IO.PutF[out, "%gTable-Of-Contents: %g", [rope[indentation]], IO.rope[RopeFromTOC[envelope.toc]]]; IF envelope.authenticationLevelPresent THEN { IO.PutRope[out, IF newLines THEN "\r" ELSE ", "]; IO.PutF[out, "%gAuthentication-Level-Of-Sender: %g", [rope[indentation]], IO.rope[RopeFromAuthenticationLevel[envelope.authenticationLevel]]]; }; IF envelope.gatewayPostmarkPresent THEN { IO.PutRope[out, IF newLines THEN "\r" ELSE ", "]; IO.PutF[out, "%gGateway: %g", [rope[indentation]], [rope[RopeFromPostmark[envelope.gatewayPostmark]]]]; }; IF envelope.priorityPresent THEN { IO.PutRope[out, IF newLines THEN "\r" ELSE ", "]; IO.PutF[out, "%gPriority: %g", [rope[indentation]], [rope[RopeFromPriority[envelope.priority]]]]; }; IF envelope.reportPresent THEN { IO.PutRope[out, IF newLines THEN "\r" ELSE ", "]; IO.PutF[out, "%gReport: %g", [rope[indentation]], [rope[RopeFromReport[envelope.report, FALSE]]]]; }; IF envelope.convertedPresent THEN { IO.PutRope[out, IF newLines THEN "\r" ELSE ", "]; IO.PutF[out, "%gConverted: %g", [rope[indentation]], [rope[RopeFromConverted[envelope.converted]]]]; }; IF newLines THEN IO.PutChar[out, '\r]; RETURN[IO.RopeFromROS[out]]; }; RopeFromMSRName: PUBLIC PROC [name: MSBasics.RName] RETURNS [rope: ROPE] ~ { WITH name SELECT FROM it: MSBasics.CHRName => { rope ฌ XNSCHName.RopeFromName[it.xns] }; it: MSBasics.X400RName => { -- don't know how to print these yet! rope ฌ "Some X.400 O/R name" }; ENDCASE => ERROR }; RopeFromPostmark: PUBLIC PROC [postmark: MSBasics.Postmark] RETURNS [rope: ROPE] ~ { rope ฌ IO.PutFR["\"%g\" @ %g", [rope[RopeFromMSRName[postmark.postedAt]]], [time[BasicTime.FromNSTime[postmark.time]]]]; }; RopeFromContentsType: PUBLIC PROC [contentsType: MSBasics.ContentsType] RETURNS [rope: ROPE] ~ { OPEN MSBasics; rope ฌ SELECT contentsType FROM ctStandardMessage => "InterpersonalMessage", ctReport => "Delivery/NonDelivery-Report", ctNull => "No Content", ENDCASE => IO.PutFR1["contentsType(%g)", [cardinal[contentsType]]]; }; RopeFromPriority: PUBLIC PROC [priority: MSBasics.Priority] RETURNS [rope: ROPE] ~ { rope ฌ SELECT priority FROM nonUrgent => "Non-Urgent", normal => "Normal", urgent => "Urgent", unspecified => "Unspecified", ENDCASE => IO.PutFR1["priority(%g)", [cardinal[ORD[priority]]]]; }; RopeFromMessageID: PUBLIC PROC [msgID: MSBasics.MessageID] RETURNS [rope: ROPE] ~ { rope ฌ IO.PutFLR["%g#%g#%g#%g#%g", LIST[IO.card[msgID[0]], IO.card[msgID[1]], IO.card[msgID[2]], IO.card[msgID[3]], IO.card[msgID[4]]] ]; }; RopeFromAuthenticationLevel: PUBLIC PROC [authLevel: MSBasics.AuthenticationLevelOfSender] RETURNS [rope: ROPE] ~ { rope ฌ SELECT authLevel FROM strong => "Strong", simple => "Simple", foreign => "Foreign", ENDCASE => IO.PutFR1["authLevel(%g)", [cardinal[ORD[authLevel]]]]; }; RopeFromBodyPartType: PUBLIC PROC [bodyPartType: MailTransport.BodyPartType] RETURNS [rope: ROPE] ~ { OPEN MailFormat; rope ฌ SELECT bodyPartType FROM headingBodyPart => "header", vpFolder => "vpFolder", nsTextFile => "nsTextFile", vpDocument => "vpDocument", otherNSFile => "otherNSFile", multinationalNote => "multinationalNote", ia5Note => "ia5Note", pilotFile => "pilotFile", g3Fax => "g3Fax", teletex => "teletex", telex => "telex", iso6937Note => "iso6937Note", interpress => "interpress", ENDCASE => IO.PutFR1["bodyPart(%g)", [cardinal[bodyPartType]]]; }; RopeFromTOC: PUBLIC PROC [toc: MSBasics.TableOfContents] RETURNS [rope: ROPE] ~ { IF toc.length = 0 THEN RETURN["Empty"]; FOR i: CARDINAL IN [0..toc.length) DO IF i > 0 THEN rope ฌ Rope.Concat[rope, ", "]; rope ฌ Rope.Concat[rope, IO.PutFR["(type: %g, size: %g)", [rope[RopeFromBodyPartType[toc[i].type]]], [integer[toc[i].sizeInBytes]]]]; ENDLOOP; }; RopeFromConvertedItem: PUBLIC PROC [item: EnvelopeFormat.ConvertedItem] RETURNS [rope: ROPE] ~ { rope ฌ SELECT item FROM ia5TextToTeletex => "ia5TextToTeletex", teletexToTelex => "teletexToTelex", teletexToIA5Text => "teletexToIA5Text", telexToTeletex => "telexToTeletex", ENDCASE => ERROR; }; RopeFromReason: PUBLIC PROC [reason: EnvelopeFormat.Reason] RETURNS [rope: ROPE] ~ { rope ฌ SELECT reason FROM noSuchRecipient => "noSuchRecipient", noMailboxForRecipient => "noMailboxForRecipient", illegalName => "illegalName", timeout => "timeout", reportNotAllowed => "reportNotAllowed", messageTooLong => "messageTooLong", ambiguousRName => "ambiguousRName", illegalCharacters => "illegalCharacters", unsupportedBodyparts => "unsupportedBodyparts", unsupportedContentsType => "unsupportedContentsType", transientProblem => "transientProblem", contentSyntaxError => "contentSyntaxError", tooManyRecipients => "tooManyRecipients", protocolViolation => "protocolViolation", x400PragmaticConstraintViolation => "x400PragmaticConstraintViolation", x400NoBilateralAgreement => "x400NoBilateralAgreement", accessRightsInsufficientForDL => "accessRightsInsufficientForDL", other => "other", ENDCASE => ERROR; }; RopeFromDelType: PUBLIC PROC [delType: EnvelopeFormat.DelType] RETURNS [rope: ROPE] ~ { rope ฌ SELECT delType FROM contentsTruncated => "contentsTruncated", noProblem => "noProblem", ENDCASE => ERROR; }; RopeFromNonDelType: PUBLIC PROC [nonDelType: EnvelopeFormat.NonDelType] RETURNS [rope: ROPE] ~ { rope ฌ IO.PutFR["(reason: %g, reportCreationPostmark: %g)", [rope[RopeFromReason[nonDelType.reason]]], [rope[RopeFromPostmark[nonDelType.reportCreationPostmark]]]]; }; RopeFromFate: PUBLIC PROC [fate: EnvelopeFormat.Fate] RETURNS [rope: ROPE] ~ { WITH fate SELECT FROM delivered: REF delivered EnvelopeFormat.FateObject => rope ฌ IO.PutFR1["Delivered: %g", [rope[RopeFromDelType[delivered.delivered]]]]; notDelivered: REF notDelivered EnvelopeFormat.FateObject => rope ฌ IO.PutFR1["Not Delivered: %g", [rope[RopeFromNonDelType[notDelivered.notDelivered]]]]; ENDCASE => ERROR; }; RopeFromReportType: PUBLIC PROC [reportType: MailTransport.ReportType] RETURNS [rope: ROPE] ~ { rope ฌ SELECT reportType FROM none => "none", nonDeliveryOnly => "nonDeliveryOnly", all => "all", unknown => "unknown", ENDCASE => IO.PutFR1["reportType(%g)", [cardinal[ORD[reportType]]]]; }; RopeFromRecipient: PUBLIC PROC [recipient: MSBasics.Recipient] RETURNS [rope: ROPE] ~ { rope ฌ IO.PutFR["(name: %g, id: %g, reportType: %g)", [rope[RopeFromMSRName[recipient.name]]], [cardinal[recipient.recipientID]], [rope[RopeFromReportType[recipient.report]]]]; }; RopeFromNonDeliveredRecipient: PUBLIC PROC [recipient: EnvelopeFormat.NonDeliveredRecipient] RETURNS [rope: ROPE] ~ { rope ฌ IO.PutFR["(recipient: %g, reason: %g)", [rope[RopeFromRecipient[recipient.recipient]]], [rope[RopeFromReason[recipient.reason]]]]; }; RopeFromDeliveredRecipient: PUBLIC PROC [recipient: EnvelopeFormat.DeliveredRecipient] RETURNS [rope: ROPE] ~ { rope ฌ IO.PutFR["(recipient: %g, when: %g)", [rope[RopeFromRecipient[recipient.recipient]]], [time[BasicTime.FromNSTime[recipient.when]]]]; }; RopeFromInvalidRecipients: PUBLIC PROC [recipients: EnvelopeFormat.InvalRecip] RETURNS [rope: ROPE] ~ { IF recipients.length = 0 THEN RETURN["No recipients"]; FOR i: CARDINAL IN [0..recipients.length) DO IF i > 0 THEN rope ฌ Rope.Concat[rope, ", "]; rope ฌ Rope.Concat[rope, RopeFromNonDeliveredRecipient[recipients[i]]]; ENDLOOP; }; RopeFromSucList: PUBLIC PROC [succeeded: EnvelopeFormat.SucList] RETURNS [rope: ROPE] ~ { IF succeeded.length = 0 THEN RETURN["Empty"]; FOR i: CARDINAL IN [0..succeeded.length) DO IF i > 0 THEN rope ฌ Rope.Concat[rope, ", "]; rope ฌ Rope.Concat[rope, RopeFromDeliveredRecipient[succeeded[i]]]; ENDLOOP; }; RopeFromFailList: PUBLIC PROC [failed: EnvelopeFormat.FailList] RETURNS [rope: ROPE] ~ { IF failed.length = 0 THEN RETURN["Empty"]; FOR i: CARDINAL IN [0..failed.length) DO IF i > 0 THEN rope ฌ Rope.Concat[rope, ", "]; rope ฌ Rope.Concat[rope, RopeFromNonDeliveredRecipient[failed[i]]]; ENDLOOP; }; RopeFromRepType: PUBLIC PROC [repType: EnvelopeFormat.RepType] RETURNS [rope: ROPE] ~ { WITH repType SELECT FROM dlMember: REF dlMember EnvelopeFormat.RepTypeObject => rope ฌ IO.PutFR["DL name: %g: %g", [rope[RopeFromMSRName[dlMember.dlMember.dlName]]], [rope[RopeFromInvalidRecipients[dlMember.dlMember.invalidDLRecipients]]]]; other: REF other EnvelopeFormat.RepTypeObject => rope ฌ IO.PutFR["Succeeded: %g, Failed: %g", [rope[RopeFromSucList[other.other.succeeded]]], [rope[RopeFromFailList[other.other.failed]]]]; ENDCASE => ERROR; }; RopeFromConverted: PUBLIC PROC [converted: MSBasics.Converted] RETURNS [rope: ROPE] ~ { IF converted.length = 0 THEN RETURN["No conversion"]; FOR i: CARDINAL IN [0..converted.length) DO IF i > 0 THEN rope ฌ Rope.Concat[rope, ", "]; rope ฌ Rope.Concat[rope, RopeFromConvertedItem[converted[i]]]; ENDLOOP; }; RopeFromReport: PUBLIC PROC [report: MSBasics.Report, newLines: BOOL ฌ TRUE] RETURNS [rope: ROPE] ~ { out: STREAM ฌ IO.ROS[]; IO.PutF[out, "Original-Envelope:%g%g%g", [rope[IF newLines THEN "\r" ELSE " {"]], [rope[RopeFromEnvelope[ParseEnvelope[report.originalEnvelope], newLines, " "]]], [rope[IF newLines THEN NIL ELSE "}"]]]; IO.PutRope[out, IF newLines THEN NIL ELSE ", "]; IO.PutF1[out, "Fate-Of-This-Report: %g", [rope[RopeFromFate[report.fateOfThisReport]]]]; IO.PutRope[out, IF newLines THEN "\r" ELSE ", "]; IO.PutF1[out, "Report-Type: %g", [rope[RopeFromRepType[report.reportType]]]]; IO.PutRope[out, IF newLines THEN "\r" ELSE NIL]; RETURN[IO.RopeFromROS[out]]; }; InitNames: PROC = { names: SystemSite.Names ฌ SystemSite.Get[]; thisDomain ฌ names.domain; thisOrganization ฌ names.organization; }; END.  MSUtilsImpl.mesa Copyright ำ 1988, 1989, 1990, 1991, 1992 by Xerox Corporation. All rights reserved. Wes Irish, December 22, 1988 6:25:48 pm PST Willie-sue, January 28, 1993 6:17 pm PST Utilities for manipulating MS stuff... Headers In MS land a header is a BodyPart (specifically, bodyPart 0) and is encoded data. The MailUser interface also treats a header as a BodyPart but it is "text" in "822" format. Takes an "822" header as "text" and converts it into an encoded representation "header" that can be handed to MSSend as the header BodyPart. "text" may actually be a header followed by a message body; the two being delimited by the 822 standard "double-carriage-return". If includeTextAnnotation=TRUE then any input fields that are unknow will be included in the TextAnnotation attribute in the resulting header. errorCode indicates success or the particular problem encountered. If errorCode indicates a problem then errorCode will point close to the point of problems. If errorCode indicates success then index points just past the header. If "text" also included a message body then Rope.Substr[base: text, start: index] will be the portion of the message that should be sent as the message body. included is a list of those fields that were successfully encoded into "header" notIncluded is a list of those fields that were not successfully encoded into "header". i: INT; name _ XNSCHName.RopeFromName[XNSCHName.NameFromRope[name, domain, organization]]; IF thisOrganization = NIL THEN InitNames[]; i _ name.Length[] - thisOrganization.Length[]; stripped _ name; IF i > 0 AND stripped.Fetch[i - 1] = ': AND Rope.EqualSubstrs[s1: stripped, start1: i, s2: thisOrganization, case: FALSE] THEN stripped _ stripped.Substr[len: i - 1] ELSE RETURN; i _ stripped.Length[] - thisDomain.Length[]; IF i > 0 AND stripped.Fetch[i - 1] = ': AND Rope.EqualSubstrs[s1: stripped, start1: i, s2: thisDomain, case: FALSE] THEN stripped _ stripped.Substr[len: i - 1]; Envelopes Note: there are some items in the MailTransport.Envelope that do not exist in MSBasics.Envelope. MSBasics.Envelope contains only the envelope items that appear to be useful to clients. Someday this may need to extended if clients are interested in additional items... -- Required Envelope Items: -- Other Envelope Items (may or may not exist): ส๗–(cedarcode) style•NewlineDelimiter ™code•Mark outsideHeaderšœ™Kšœ ฯeœI™TKšœ+™+K™(K™Kšœฯkœ ™&K™—šž ˜ Kšœ˜K˜ K˜Kšœ˜Kšœ˜Kšžœ˜K˜ K˜Kšœ˜Kšœ˜Kšœ ˜ Kšœ ˜ Kšœ˜Kšœ˜Kšœ˜Kšœ žœ˜Kšœ ˜ Kšœ ˜ —K˜šัbln œžœž˜Kšžœ*žœ?˜rKšžœ˜Kšœž˜K˜šžœ˜Kšฯnœ˜'Kš œ˜&Kš  œ˜Kš  œ˜"K˜—Kšžœžœžœ˜Kšžœžœžœžœ˜K˜Kšœžœ˜2šœžœ˜*K˜—K˜head™Jšœžœฉ™ฎK˜š œžœžœžœžœžœžœ˜iKšžœ žœ5žœD˜‘Kšœ™Kšœžœp™KšœB™BKšœZ™ZK•StartOfExpansion9[base: ROPE, start: INT _ 0, len: INT _ 2147483647]šœๅ™ๅKšœO™OKšœW™WKšžœ ˜š œžœžœžœ˜ šžœ˜šžœ˜K˜K˜K˜——Kšžœ˜K˜—š œžœ žœ žœ˜>šžœ ž˜Kšžœžœ˜;Kšžœ$žœ˜E—K˜—š œžœ žœ žœ˜Ašžœž˜Kšžœ!žœ˜AKšžœ*žœ˜K—K˜—šะbnœžœ žœžœ&˜Ršก œžœžœžœ˜%šžœ˜šžœ˜K˜"K˜K˜——Kšžœžœžœฯc0˜@K˜—šกœžœžœžœ˜HKš žœžœžœžœžœ˜%šžœ ž˜KšœTžœ˜]Kšœ(˜(Kšžœžœ˜—Kšžœžœ˜ K˜—šก œžœ˜.šžœ ž˜Kšžœžœ˜%Kšžœžœ˜+—Kšœ˜—šกœžœžœ˜)Kšœ˜Kšœžœ˜Kšœžœ˜K˜#šžœ ž˜Kšžœžœ ˜(Kšžœžœ ˜.—Kšœ˜—Kšœ ˜ Kšœ žœ˜Kšœžœ˜!K˜=Kšœ7˜7Kšœ!˜!Kšœ˜—š กœžœžœ žœ žœ žœ˜TK˜9Kšœ žœ˜K˜HK˜K–U[card: MSSendImpl.CARD16, index: CARDINAL _ 0B (0), item: CHOpsP2V3.Item _ NIL]˜WK˜HK–U[card: MSSendImpl.CARD16, index: CARDINAL _ 0B (0), item: CHOpsP2V3.Item _ NIL]˜EK˜$Kšœ ˜ Kšœ˜—š  œžœžœ žœ žœ žœ˜PKšœ žœ˜K˜HK˜K–U[card: MSSendImpl.CARD16, index: CARDINAL _ 0B (0), item: CHOpsP2V3.Item _ NIL]˜WKšœFข˜YKšœfžœ˜€K–U[card: MSSendImpl.CARD16, index: CARDINAL _ 0B (0), item: CHOpsP2V3.Item _ NIL]˜EK˜$Kšœ ˜ Kšœ˜—š กœžœžœ žœ žœ žœ˜PKšœ žœ˜K˜HK˜K–U[card: MSSendImpl.CARD16, index: CARDINAL _ 0B (0), item: CHOpsP2V3.Item _ NIL]˜WK˜EK–U[card: MSSendImpl.CARD16, index: CARDINAL _ 0B (0), item: CHOpsP2V3.Item _ NIL]˜EK˜$Kšžœ žœžœ!˜4Kšœ˜—Kšœ˜Kšœ"˜"Kšœžœ˜Kšœžœ˜ K˜8Kšœžœ˜Kšœžœ˜K˜K–U[card: MSSendImpl.CARD16, index: CARDINAL _ 0B (0), item: CHOpsP2V3.Item _ NIL]˜U˜Kšžœ-žœ˜Gšž˜Kšœ žœ˜Kšœ žœ˜K˜-Kšžœ žœžœžœ˜K˜-šžœžœž˜–-[s1: ROPE, s2: ROPE, case: BOOL _ TRUE]šœ/žœ˜:KšœP˜PKšœ˜—–-[s1: ROPE, s2: ROPE, case: BOOL _ TRUE]šœ.žœ˜9Kšœ>˜>Kšœ˜—–-[s1: ROPE, s2: ROPE, case: BOOL _ TRUE]šœ,žœ˜7KšœH˜HKšœ˜—–-[s1: ROPE, s2: ROPE, case: BOOL _ TRUE]šœ*žœ˜5KšœI˜IKšœ˜—–-[s1: ROPE, s2: ROPE, case: BOOL _ TRUE]šœ*žœ˜5KšœF˜FKšœ˜—–-[s1: ROPE, s2: ROPE, case: BOOL _ TRUE]šœ0žœ˜;KšœD˜DKšœ˜—šžœ˜ Kšœžœ˜Kšœžœ.˜Lšžœžœ[˜wKšžœG˜KKšžœ,˜0—K˜——Kšžœ˜—Kšžœžœ˜K˜—Kšœ˜šžœžœžœž˜6Kšœ_˜_—šžœžœžœ˜KšœAžœžœ˜KKšœCžœžœ˜MK˜—K–U[card: MSSendImpl.CARD16, index: CARDINAL _ 0B (0), item: CHOpsP2V3.Item _ NIL]˜@K˜ K˜K˜—šœžœžœ˜1K˜—–9[base: ROPE, start: INT _ 0, len: INT _ 2147483647]š  œžœžœ#žœžœžœžœžœ˜mK˜Kšœ žœ˜Kšœžœ˜Kšœžœžœ˜Kš žœžœžœžœžœ˜Kšœ žœ˜#Kšœžœ˜:šž˜Kšœ žœžœ˜0šžœžœžœž˜,K˜Kšœ žœ ˜2Kšœ žœ ˜2Kšžœ˜—K˜1Kšžœ%žœžœ˜1K˜Kšœข ˜Kšžœ˜—K˜K˜K˜—š กœžœ'žœ žœžœ'žœ˜ญKšœ žœ ˜Kšœžœ˜Kšœ>ข˜Wšžœ8žœ žœž˜RKšœ>ข˜QK˜GK˜Kšžœ˜—K˜:Kšžœ˜Kšœ˜K˜—š œž œžœžœ˜NKšœ˜Kšœ žœ*˜8˜*Kšœžœ˜$—Kšžœ ˜K˜K˜—š   œžœžœžœžœ žœ˜WKšœžœ™Kšœgžœ˜oKšžœžœžœ ˜+šžœ-žœžœ˜Kšžœ˜—K˜K˜—š œžœžœ%žœžœžœžœ˜eKšœžœžœžœ˜šžœ&˜(Kšœžœ žœžœ˜(KšœQ˜QKš œžœ žœžœžœ˜'—Kš žœžœ žœžœžœ˜0KšžœV˜XKšžœžœ žœžœ˜1KšžœK˜MKš žœžœ žœžœžœ˜0Kšžœžœ˜K˜K˜—š  œžœ˜K˜+K˜K˜&K˜K˜———Kšžœ˜—…—S–wฅ