MailRetrieveOneImpl.mesa
Copyright Ó 1988, 1989, 1990, 1991, 1992 by Xerox Corporation. All rights reserved.
Doug Terry, December 12, 1988 6:06:03 pm PST
Wes Irish, December 22, 1988 6:11:51 pm PST
Willie-sue, November 3, 1992 11:41 am PST
Operations for retrieval of electronic mail messages. Modules register procs for particular mail services.
DIRECTORY
IO,
IOTioga,
MailBasics,
MailBasicsItemTypes,
MailBasicsMoreItemTypes,
MailMessage,
MailRetrieve,
MailUtils,
NodeProps,
Rope,
TextEdit,
Tioga,
TiogaAccess,
TiogaIO,
UserProfile USING [Boolean];
MailRetrieveOneImpl: CEDAR MONITOR
IMPORTS IO, IOTioga, MailRetrieve, MailUtils, NodeProps, Rope, TextEdit, TiogaAccess, TiogaIO, UserProfile
EXPORTS MailMessage
~ BEGIN
STREAM: TYPE ~ IO.STREAM;
ROPE: TYPE ~ Rope.ROPE;
Exported procedures
ReadOneMessageX: PUBLIC PROC [handle: MailRetrieve.Handle, timeStamp: MailBasics.Timestamp, sender: ROPE, stream: IO.STREAM ¬ NIL]
RETURNS [m, formatting: ROPE ¬ NIL, bodyLength, formatLen, formatPos: INT ¬ 0] ~ {
[m, formatting, bodyLength, formatLen, formatPos] ¬ DoReadOne[FALSE, handle, timeStamp, sender, stream]
};
ReadOneMessage: PUBLIC PROC [handle: MailRetrieve.Handle, timeStamp: MailBasics.Timestamp, sender: ROPE, stream: IO.STREAM ¬ NIL]
RETURNS [m, formatting: ROPE ¬ NIL, bodyLength, formatLen, formatPos: INT ¬ 0] ~ {
[m, formatting, bodyLength, formatLen, formatPos] ¬ DoReadOne[TRUE, handle, timeStamp, sender, stream]
};
DoReadOne: PROC [deleteLeadingCR: BOOL, handle: MailRetrieve.Handle, timeStamp: MailBasics.Timestamp, sender: ROPE, stream: IO.STREAM ¬ NIL]
RETURNS [m, formatting: ROPE ¬ NIL, bodyLength, formatLen, formatPos: INT ¬ 0] ~ {
ENABLE MailRetrieve.Failed => { GOTO failed };
header, plainText, formattedHeader, bodies: ROPE ¬ NIL;
sysMessage, attachments, unknowns: ROPE ¬ NIL;
buttonRope: ROPE ¬ NIL;
buttonType: MailBasics.ItemType;
MakeButton: PROC[type: MailBasics.ItemType] ~ {
IF UserProfile.Boolean["MailUser.MakeButtonForSerializedFile", FALSE] THEN {
buttonRope ← MailRetrieve.GetItemAsRope[handle];
buttonType ← type
}
ELSE bodies ← bodies.Concat[MailRetrieve.GetItemAsRope[handle] ];
};
DO
item: MailBasics.ItemHeader ~ MailRetrieve.NextItem[handle];
SELECT item.type FROM
MailBasicsItemTypes.envelope => {
NULL;
};
MailBasicsItemTypes.header => header ¬ MailRetrieve.GetItemAsRope[handle];
MailBasicsItemTypes.plainTextForFormatting => plainText ¬ MailRetrieve.GetItemAsRope[handle];
MailBasicsItemTypes.formattedHeader => formattedHeader ¬ MailRetrieve.GetItemAsRope[handle];
MailBasicsItemTypes.systemMessage =>
sysMessage ¬ sysMessage.Concat[MailRetrieve.GetItemAsRope[handle] ];
MailBasicsItemTypes.ia5Note,
MailBasicsItemTypes.text,
MailBasicsItemTypes.multinationalNote =>
bodies ¬ bodies.Concat[MailRetrieve.GetItemAsRope[handle] ];
MailBasicsMoreItemTypes.hasAttachment => MakeButton[item.type];
MailBasicsItemTypes.fullFormatting =>
formatting ¬ formatting.Concat[MailRetrieve.GetItemAsRope[handle] ];
MailBasicsItemTypes.tioga1 =>
formatting ¬ formatting.Concat[MailRetrieve.GetItemAsRope[handle] ];
MailBasicsItemTypes.gGW => { NULL };
MailBasicsItemTypes.pilotFile => { NULL };
MailBasicsItemTypes.tioga2 => { NULL };
MailBasicsItemTypes.walnutLog => { NULL };
MailBasicsItemTypes.capability => { NULL };
MailBasicsItemTypes.audio => { NULL }; -- we may use this someday
MailBasicsItemTypes.messageComposer => { NULL };
MailBasicsItemTypes.lastItem => {
EXIT
};
ENDCASE =>
unknowns ¬ unknowns.Concat[IO.PutFR["\r\r==>Discarded ItemType: %g (length %g bytes)<==\r",
[rope[MailUtils.RopeFromItemType[item.type]]],
[integer[item.length]]
] ];
ENDLOOP;
assemble the message from its parts
{
next: ROPE;
this is a hack so that formatting from SmallTalk will work
IF formatting # NIL THEN unknowns ¬ NIL;
SELECT TRUE FROM
attachments # NIL => { next ¬ attachments; attachments ¬ NIL };
unknowns # NIL => { next ¬ unknowns; unknowns ¬ NIL };
ENDCASE => { next ¬ bodies; bodies ¬ NIL };
SELECT TRUE FROM
sysMessage # NIL => {
foo: ROPE ¬ IO.PutFR["Date: %g\rSender: %g\r", [time[MailUtils.GetTimeFromPostmark[timeStamp]]], [rope[sender]] ];
pos: INT ¬ sysMessage.Find["Report-Type: DL name:"];
dlOK: BOOL ¬ FALSE;
IF pos # -1 THEN {
pos2: INT ¬ sysMessage.Find[" (", pos];
IF pos2 # -1 THEN {
foo ¬ foo.Cat["Subject: Report for dl: ", sysMessage.Substr[pos, pos2-pos+1], "\r"];
dlOK ¬ TRUE;
};
};
IF NOT dlOK THEN
foo ¬ foo.Concat["Subject: Delivery / Non-Delivery Report information\r"];
foo ¬ foo.Cat[sysMessage, "\r"];
IF stream # NIL THEN stream.PutRope[foo]
ELSE m ¬ foo.Cat[sysMessage, "\r"];
bodyLength ¬ foo.Length[];
IF header # NIL THEN header ¬ IO.PutFR1["---------- Original-Header:\r%g\r----------\r", [rope[header]] ];
bodies ¬ header.Concat[bodies];
formatting ¬ NIL; -- won't be correct so toss
};
plainText # NIL => { -- don't want headers in this case
ch: CHAR ~ plainText.Fetch[0];
IF deleteLeadingCR THEN
IF ( ch = '\r ) OR ( ch = '\l ) THEN plainText ¬ plainText.Substr[1]; -- tioga stuff
IF stream # NIL THEN stream.PutRope[plainText] ELSE m ¬ plainText;
bodyLength ¬ plainText.Length[];
next ¬ NIL; -- kill multinationalnote part of message
};
ENDCASE => {
hL: INT = header.Length[];
numCRs: INT ¬ 0;
IF header # NIL THEN {
IF header.Fetch[hL-2] = '\r THEN numCRs ¬ numCRs + 1;
IF header.Fetch[hL-1] = '\r THEN numCRs ¬ numCRs + 1;
IF ( next # NIL ) AND ( next.Fetch[0] = '\r ) THEN numCRs ¬ numCRs + 1;
IF numCRs < 2 THEN header ¬ header.Concat["\r"];
IF stream # NIL THEN stream.PutRope[header]
ELSE m ¬ header;
bodyLength ¬ header.Length[];
};
};
IF stream # NIL THEN stream.PutRope[next] ELSE m ¬ m.Concat[next];
bodyLength ¬ bodyLength + next.Length[];
IF attachments # NIL THEN {
IF stream # NIL THEN stream.PutRope[attachments] ELSE m ¬ m.Concat[attachments];
bodyLength ¬ bodyLength + attachments.Length[];
};
IF unknowns # NIL THEN {
IF stream # NIL THEN stream.PutRope[unknowns] ELSE m ¬ m.Concat[unknowns];
bodyLength ¬ bodyLength + unknowns.Length[];
};
IF bodies # NIL THEN {
IF stream # NIL THEN stream.PutRope[bodies] ELSE m ¬ m.Concat[bodies];
bodyLength ¬ bodyLength + bodies.Length[];
};
};
IF buttonRope # NIL THEN {
props: IOTioga.PropList;
out: STREAM;
reader: TiogaAccess.Reader;
root: Tioga.Node;
posSlash, posAfter: INT;
fullRope: ROPE;
cr: ROPE ~ "\r";
pair: TiogaIO.Pair;
IF formatting # NIL THEN ERROR MailRetrieve.Failed[$malformedMsg, "a message has both a buttonRope and formatting"];
out ← IOTioga.CreateTiogaAccessStream[];
out.PutRope[m];
posSlash ← Rope.Find[buttonRope, "/"];
posAfter ← Rope.Find[buttonRope, "(", posSlash];
out.PutRope[buttonRope.Substr[0, posSlash]];
props ← IOTioga.PropPut[NIL, $Postfix, thePostfixValue];
props ← IOTioga.PropPut[props, $ButtonData, theButtonDataValue];
IOTioga.SetCharProps[out, props];
out.PutRope[Rope.Substr[buttonRope, posSlash, posAfter-posSlash-1]];
IOTioga.SetCharProps[out, NIL];
out.PutRope[Rope.Substr[buttonRope, posAfter-1]];
root ← TiogaAccess.WriteNode[IOTioga.WriterFromStream[out]];
TextEdit.PutProp[node: root, name: $NewlineDelimiter, value: cr];
pair ¬ TiogaIO.ToPair[root];
m ¬ pair.contents;
formatting ¬ pair.formatting;
};
IF stream # NIL THEN {
stream.PutRope[m];
bodyLength ¬ bodyLength + m.Length[];
};
IF ( formatting # NIL ) AND ( stream # NIL ) THEN {
formatPos ¬ stream.GetIndex[];
stream.PutRope[formatting];
formatLen ¬ formatting.Length[]
};
IF stream # NIL THEN stream.PutChar['\r];
RETURN;
EXITS
failed => RETURN[NIL, NIL, -1, -1, -1];
};
theButtonDataRope: ROPE ~ "Poppy1
Class: PopUpButton
MessageHandler: CommandTool
Menu: (
(<Concat \"CVV \" <ButtonText> \" \" <BaseName <ButtonText>> > \"Display ViewPoint Document\" \"Execute CVV.command\")
(<Concat \"Deserialize \" <ButtonText> > \"Deserialize\" \"Deserialize file\")
(<Send Tioga <Concat \" \\\"\" <ButtonText> \"\\\"\">> \"Stuff filename\" \"Stuff filename at the current insertion point\")
()
()
()
(<Concat \"Delete \" <ButtonText> > \"Delete\" \"Delete file\")
)
Feedback: (
(MouseMoved <SetCursor bullseye>)
)";
theButtonDataValue: REF ~ NodeProps.DoSpecs[$ButtonData, theButtonDataRope];
thePostfixRope: ROPE ~ "1.0 outlineBoxBearoff 1.0 outlineBoxThickness";
thePostfixValue: REF ~ NodeProps.DoSpecs[$Postfix, thePostfixRope];
END.