PeanutRetrieveImpl.mesa
Copyright © 1984, 1985, 1986 Xerox Corporation. All rights reserved.
Created by Paxton, April 1, 1983 2:17 pm
Last edited by Bill Paxton, May 12, 1983 4:11 pm
Last edited by: Pausch, July 14, 1983 3:26 pm
Michael Plass, July 30, 1986 3:02:43 pm PDT
Doug Wyatt, September 6, 1985 2:43:38 pm PDT
Last Edited by: Gasbarro June 16, 1986 5:03:42 pm PDT
Pier, May 21, 1986 3:23:37 pm PDT
DIRECTORY
BasicTime USING [FromPupTime, GMT, Now, Unpack, Unpacked],
CedarProcess USING [SetPriority],
Convert USING [RopeFromUnpackedTime],
FS USING [Error, ExpandName, GetName, nullOpenFile, Open, OpenFile],
GVBasics USING [ItemHeader, ItemType, RName, Timestamp],
GVRetrieve USING [Accept, Close, Create, Failed, GetItem, Handle, MailboxState, MBXState, NewUser, NextItem, NextMessage, NextServer, ServerName, ServerState, StartMessage],
IO USING [GetBlock, int, PutFR, rope, STREAM, time],
MessageWindow USING [Append, Blink],
PeanutProfile USING [activeMailFile, automaticNewMail, workingDirectory],
PeanutRetrieve USING [],
PeanutSendMail USING [simpleUserName, userRName],
PeanutWindow USING [dirtyMessageSetIcon, messageSetIcon, OutputRope, SetNewMail],
Process USING [Detach],
PutGet USING [FromFileC, FromRope],
Rope USING [Cat, Concat, Equal, Fetch, Find, FromChar, FromRefText, Index, Length, ROPE, Size, Substr],
TEditDisplay USING [EstablishLine],
TEditDocument USING [TEditDocumentData],
TextEdit USING [DocFromNode, FromRope],
TextNode USING [Body, FirstChild, LastSibling],
TiogaFileOps USING [InsertNode, SetContents, SetFormat],
TiogaMenuOps USING [DefaultMenus, FirstLevelOnly],
TiogaOps USING [CancelSelection, GetSelection, LastChild, Location, Lock, LockSel, Next, Parent, PutProp, SelectBranches, SelectionGrain, SelectPoint, SetSelection, ToSecondary, Unlock, UnlockSel, ViewerDoc],
TiogaOpsDefs USING [],
UserCredentials USING [Get],
ViewerClasses USING [Lock, Viewer],
ViewerEvents USING [RegisterEventProc, ViewerEvent],
ViewerOps USING [AddProp, EnumerateViewers, EnumProc, FetchProp, OpenIcon, PaintViewer, SaveViewer, SetNewVersion],
ViewerTools USING [MakeNewTextViewer];
PeanutRetrieveImpl: CEDAR MONITOR
IMPORTS BasicTime, CedarProcess, Convert, FS, GVRetrieve, IO, MessageWindow, PeanutProfile, PeanutSendMail, PeanutWindow, Process, PutGet, Rope, TEditDisplay, TextEdit, TextNode, TiogaFileOps, TiogaMenuOps, TiogaOps, UserCredentials, ViewerEvents, ViewerOps, ViewerTools
EXPORTS PeanutRetrieve, TiogaFileOps, TiogaOpsDefs
= BEGIN
************************************************************************
ROPE: TYPE = Rope.ROPE;
Viewer: TYPE = ViewerClasses.Viewer;
RName: TYPE = GVBasics.RName;
RefTextNode: TYPE = REF NodeBody;
NodeBody: PUBLIC TYPE = TextNode.Body;
TiogaCTRL: GVBasics.ItemType = Tioga1; -- an item containing tioga formatting
ReportRope: PROCEDURE [r: ROPE] = { PeanutWindow.OutputRope[r] };
GetNewMsgs: PUBLIC ENTRY PROC [open: BOOLTRUE] =
{ ENABLE UNWIND => NULL; [] ← InternalGetNewMsgs[open]; };
peanutProp: ATOM = $PeanutMailFileName;
SetMailFileName: PROC[v: Viewer, name: ROPE] = {
ViewerOps.AddProp[viewer: v, prop: peanutProp, val: name];
ViewerOps.AddProp[viewer: v, prop: $IconLabel, val: v.label];
};
GetMailFileName: PROC[v: Viewer] RETURNS[ROPE] = {
WITH ViewerOps.FetchProp[viewer: v, prop: peanutProp] SELECT FROM
rope: ROPE => RETURN[rope];
ENDCASE => RETURN[NIL];
};
FindMailViewer: PUBLIC PROC[name: ROPE] RETURNS[viewer: Viewer ← NIL] = {
Enumerate top level viewers, looking for one with a matching $PeanutMailFile property
Test: ViewerOps.EnumProc -- PROC[v: Viewer] RETURNS[continue: BOOL ← TRUE] -- = {
rope: ROPE = GetMailFileName[v];
IF rope#NIL AND Rope.Equal[rope, name, FALSE] THEN { viewer ← v; RETURN[FALSE] };
};
ViewerOps.EnumerateViewers[Test];
};
GetMailViewer: PUBLIC ENTRY PROC[name: ROPE] RETURNS [mailViewer: Viewer] = {
Make this an entry so don't have two Get's at once for same mail file
ENABLE UNWIND => NULL;
mailViewer ← InternalGetMailViewer[name];
};
MakeMailDoc: PROC[fileName: ROPE] RETURNS [mailDoc: RefTextNode] = {
styleProp: ROPE = "(mail) style";
mailDoc ← TextEdit.DocFromNode[TextEdit.FromRope[fileName]];
TiogaOps.PutProp[mailDoc, $Prefix, styleProp];
};
InternalGetMailViewer: INTERNAL PROC[name: ROPE] RETURNS[mailViewer: Viewer] = {
mailViewer ← FindMailViewer[name];
IF mailViewer=NIL THEN {
wDir: ROPE ← PeanutProfile.workingDirectory;
shortName: ROPE ← name.Concat[".mail"];
longName: ROPEFS.ExpandName[name: shortName, wDir: wDir].fullFName;
fileName: ROPE ← longName;
mailDoc: RefTextNode ← NIL;
file: FS.OpenFile ← FS.nullOpenFile;
file ← FS.Open[longName ! FS.Error => IF error.code=$unknownFile THEN CONTINUE];
IF file=FS.nullOpenFile THEN {
styleProp: ROPE = "(mail) style";
mailDoc ← TextEdit.DocFromNode[TextEdit.FromRope[shortName]];
TiogaOps.PutProp[mailDoc, $Prefix, styleProp];
}
ELSE {
mailDoc ← PutGet.FromFileC[file];
fileName ← FS.GetName[file].fullFName;
};
mailViewer ← ViewerTools.MakeNewTextViewer[info: [
name: longName, file: fileName, label: name, data: mailDoc,
icon: PeanutWindow.messageSetIcon, iconic: TRUE],
paint: FALSE];
SetMailFileName[mailViewer, name];
ViewerOps.PaintViewer[mailViewer, all];
[] ← ViewerEvents.RegisterEventProc[proc: MessageSetHasBeenEdited,
event: edit, filter: mailViewer, before: TRUE];
[] ← ViewerEvents.RegisterEventProc[proc: MessageSetHasBeenSaved,
event: save, filter: mailViewer, before: FALSE];
TiogaMenuOps.DefaultMenus[mailViewer];
TiogaMenuOps.FirstLevelOnly[mailViewer];
};
};
InternalGetNewMsgs: INTERNAL PROC [open: BOOLTRUE] RETURNS [numRetrieved: INT] =
reads any new mail
{
allOK: BOOLTRUE;
mailViewer: Viewer;
firstHeader: RefTextNode;
StashNewMessages: PROC [retrieveOK: BOOL] RETURNS[doRemoteFlush: BOOL] =
{
allOK ← allOK AND retrieveOK;
ViewerOps.SaveViewer[mailViewer]; -- doesn't return until the save is complete
don't do remote flush if NOT retrieveOK
RETURN[retrieveOK AND flushRemoteMail AND mailViewer#NIL AND NOT mailViewer.destroyed];
};
mailViewer ← InternalGetMailViewer[PeanutProfile.activeMailFile];
[numRetrieved, firstHeader] ← AddNewMessages[StashNewMessages, mailViewer];
IF numRetrieved = 0 THEN {
ReportRope["\nNo messages were retrieved"]; RETURN};
IF mailViewer.iconic AND PeanutProfile.automaticNewMail THEN NULL
ELSE {
WITH mailViewer.data SELECT FROM
tdd: TEditDocument.TEditDocumentData => {
TEditDisplay.EstablishLine[tdd, [firstHeader,0]];
ViewerOps.PaintViewer[mailViewer, client];
};
ENDCASE => NULL;
};
IF NOT allOK THEN ReportRope["\nSome messages may not have been retrieved"];
IF open AND mailViewer.iconic THEN ViewerOps.OpenIcon[mailViewer];
};
***********************************************************************
MessageSetHasBeenEdited: PROC[viewer: Viewer,
event: ViewerEvents.ViewerEvent, before: BOOL] RETURNS[abort: BOOLFALSE] = {
IF before THEN {
viewer.icon ← PeanutWindow.dirtyMessageSetIcon;
IF viewer.iconic THEN ViewerOps.PaintViewer[viewer: viewer, hint: all]; };
};
MessageSetHasBeenSaved: PROC [viewer: Viewer,
event: ViewerEvents.ViewerEvent, before: BOOL] RETURNS[abort: BOOLFALSE] = {
IF NOT before THEN {
viewer.icon ← PeanutWindow.messageSetIcon;
IF viewer.iconic THEN ViewerOps.PaintViewer[viewer: viewer, hint: all]; };
};
CopyMessages: PUBLIC PROC [to: ROPE, delete: BOOL] = {
sourceViewer, destViewer: Viewer;
destDoc, sourceDoc, destLast, sourceLast, afterSource: RefTextNode;
start, end: TiogaOps.Location;
level: TiogaOps.SelectionGrain;
caretBefore, pendingDelete: BOOL;
lockedPrimary, lockedSecondary, lockedDest, lockedSource: BOOLFALSE;
TopParent: PROC [node, root: RefTextNode] RETURNS [parent: RefTextNode] = {
DO
parent ← TiogaOps.Parent[node];
IF parent=root THEN RETURN [node];
node ← parent;
ENDLOOP };
Cleanup: PROC = {
IF lockedPrimary THEN TiogaOps.UnlockSel[primary];
IF lockedSecondary THEN TiogaOps.UnlockSel[secondary];
IF lockedDest THEN TiogaOps.Unlock[destDoc];
IF lockedSource THEN TiogaOps.Unlock[sourceDoc];
};
destViewer ← GetMailViewer[to];
TiogaOps.LockSel[primary]; lockedPrimary ← TRUE;
[sourceViewer, start, end, level, caretBefore, pendingDelete] ← TiogaOps.GetSelection[];
IF sourceViewer=NIL OR sourceViewer.class.flavor#$Text THEN {
TiogaOps.UnlockSel[primary]; ReportRope["\nSelect message(s)."]; RETURN };
TiogaOps.LockSel[secondary]; lockedSecondary ← TRUE;
destDoc ← TiogaOps.ViewerDoc[destViewer];
TiogaOps.Lock[destDoc]; lockedDest ← TRUE;
sourceDoc ← TiogaOps.ViewerDoc[sourceViewer];
IF sourceDoc#destDoc THEN { TiogaOps.Lock[sourceDoc]; lockedSource ← TRUE };
destLast ← TiogaOps.LastChild[destDoc];
sourceLast ← TopParent[end.node, sourceDoc];
afterSource ← TiogaOps.Next[sourceLast];
TiogaOps.SelectBranches[ -- source
viewer: sourceViewer, level: branch, caretBefore: FALSE,
pendingDelete: delete, which: primary,
start: TopParent[start.node, sourceDoc], end: sourceLast];
TiogaOps.SelectBranches[ -- destination
viewer: destViewer, start: destLast, end: destLast,
level: branch, caretBefore: FALSE, pendingDelete: FALSE, which: secondary];
TiogaOps.ToSecondary[];
IF NOT delete THEN -- restore original selection
TiogaOps.SetSelection[sourceViewer, start, end, level, caretBefore, pendingDelete, primary]
ELSE IF afterSource # NIL THEN TiogaOps.SelectPoint[sourceViewer, [afterSource,0], primary]
ELSE TiogaOps.CancelSelection[primary];
Cleanup[];
ReportRope[IF delete THEN "\nMoved to " ELSE "\nCopied to "];
ReportRope[to];
};
***********************************************************************
msgPollingInterval: INT← 300;  -- Number of seconds between mailbox polling.
flushRemoteMail: BOOLEANTRUE;
gvRetrieveHandle: GVRetrieve.Handle← NIL; -- cookie for receiving messages.
OpenConnection: PUBLIC PROC[user: RName] = {
This establishes a retrieve connection, and sets up a Mail Polling proc
CloseConnection[];
NewUser[user] ;
};
CloseConnection: PUBLIC PROC[] = {
This closes the connection, and invalidates the connection handle.
IF gvRetrieveHandle # NIL THEN{
GVRetrieve.Close[gvRetrieveHandle]; gvRetrieveHandle← NIL};
};
NewUser: PUBLIC PROC[user: RName] = {
Establish a new user on this connection.
IF gvRetrieveHandle = NIL THEN
gvRetrieveHandle ← GVRetrieve.Create[ msgPollingInterval, WatchMailBox ];
GVRetrieve.NewUser[gvRetrieveHandle, user, UserCredentials.Get[].password ] ;
} ;
lastStateReported: GVRetrieve.MBXState ← unknown;
WatchMailBox: PROC[newState: GVRetrieve.MBXState] = {
This is called when the condition of the mailbox changes
status: ROPENIL;
IF newState = unknown THEN RETURN;
PeanutWindow.SetNewMail[newState=notEmpty];
SELECT newState FROM
badName => status ← "Your user name is invalid, please log in";
badPwd => status ← "Your password is invalid";
cantAuth => status ← "Can't check your credentials at this time";
userOK => status ← "Your credentials are OK";
allDown, someEmpty, allEmpty, notEmpty => NULL;
ENDCASE => status ← "Bad MBXState!";
IF status#NIL THEN {
PeanutWindow.OutputRope["\n"];
PeanutWindow.OutputRope[status];
};
IF newState=notEmpty AND lastStateReported#notEmpty
AND PeanutProfile.automaticNewMail THEN {
mailViewer: Viewer = FindMailViewer[PeanutProfile.activeMailFile];
IF mailViewer=NIL OR mailViewer.iconic THEN TRUSTED{Process.Detach[FORK ReadMail[]]};
};
};
OldWatchMailBox: PROC[newState: GVRetrieve.MBXState] = {
This is called when the condition of the mailbox changes
ActiveMailFileNotOpen: PROC RETURNS [BOOL] = {
mailViewer: Viewer = FindMailViewer[PeanutProfile.activeMailFile];
RETURN [mailViewer=NIL OR mailViewer.iconic]
};
showTime: BOOLTRUE;
status: ROPE;
IF newState = unknown THEN RETURN;
IF (lastStateReported = notEmpty) AND (newState = someEmpty OR newState = allEmpty) THEN
{ status← NIL; PeanutWindow.SetNewMail[FALSE] }
ELSE SELECT newState FROM
badName => {status← "\nYour user name is invalid, please log in"; showTime← FALSE};
badPwd => {status← "\nYour password is invalid"; showTime← FALSE};
cantAuth => {status← "\nCan't check your credentials at this time"; showTime← FALSE};
userOK => {status← "\nYour credentials are OK"; showTime← FALSE};
allDown => status← "\nAll of the mail servers are down";
someEmpty => status← "\nAll of the mail servers checked are empty";
allEmpty => {status← NIL; PeanutWindow.SetNewMail[FALSE]};
notEmpty => {status← NIL; PeanutWindow.SetNewMail[TRUE];
IF lastStateReported#notEmpty AND PeanutProfile.automaticNewMail
AND ActiveMailFileNotOpen[] THEN TRUSTED {Process.Detach[FORK ReadMail[]]}
};
ENDCASE => status← "\nBad State!";
lastStateReported ← newState;
IF status # NIL THEN {
ReportRope[status];
IF showTime THEN ReportRope[IO.PutFR[" at %g", IO.time[]]];
};
};
ReadMail: ENTRY PROC = {
ENABLE UNWIND => NULL;
numRetrieved: INT;
CedarProcess.SetPriority[background];
IF (numRetrieved ← InternalGetNewMsgs[FALSE])=0 THEN RETURN;
MessageWindow.Append[IO.PutFR["New mail retrieved: %g", IO.time[]], TRUE];
MessageWindow.Blink[] };
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
MessageState: TYPE = { noMore, wasArchived, wasDeleted, OK, retrieveFailed } ;
AddNewMessages: PUBLIC PROC[
FinishedWithServer: PROC[BOOL] RETURNS[BOOL], mailViewer: Viewer]
RETURNS[numRetrieved: INT, firstHeader: RefTextNode] = {
This is the routine that actually reads the mail & makes the log entry.
It calls FinishedWithServer to commit the log before it flushes any particular mail server.
serverKnown: BOOLEANFALSE;
mailDoc: RefTextNode ← TiogaOps.ViewerDoc[mailViewer];
IF gvRetrieveHandle = NIL THEN {   -- Open the connection if it's closed.
gvRetrieveHandle ← GVRetrieve.Create[ msgPollingInterval, WatchMailBox ] ;
GVRetrieve.NewUser[gvRetrieveHandle, PeanutSendMail.userRName,
UserCredentials.Get[].password];
} ;
SELECT gvRetrieveHandle.MailboxState[] FROM
badName, badPwd => GOTO credentialsError;
cantAuth => GOTO noServers;
ENDCASE; --ok to try
numRetrieved← 0;
ReportRope[IO.PutFR["\nCheck for new mail for %g: %g", IO.rope[PeanutSendMail.userRName], IO.time[]]];
DO       -- Loops over servers.
m, formatting: ROPE;
messageState: MessageState;
timeStamp: GVBasics.Timestamp;
gvSender: RName;
messages: CARDINAL ← 0;   -- the number of messages read from server.
archivedReported: BOOLEANFALSE;  -- seen an archived message?
Cycle through the servers, until you find one that has mail.
If it has mail, then go for it.
noMore: BOOLEAN;    -- TRUE if no more servers.
serverState: GVRetrieve.ServerState; -- The state of the server.
headerNode: RefTextNode;
serverName: ROPE ;
headerNode ← TiogaOps.LastChild[mailDoc];
Step through the servers.
[noMore, serverState] ← gvRetrieveHandle.NextServer[];
IF noMore THEN EXIT;   -- Last server? Then done.
serverKnown ← TRUE;
serverName ← gvRetrieveHandle.ServerName[];
ReportRope["\n"]; ReportRope[serverName]; ReportRope[": "];
IF serverState # notEmpty THEN {
IF serverState = empty THEN ReportRope["empty"]
ELSE ReportRope["didn't respond"] ;
LOOP;      -- Skip to the next server.
};
DO
[messageState, m, formatting, timeStamp, gvSender] ← ReadMessageRecord[] ;
SELECT messageState FROM
noMore => EXIT ;
wasArchived => IF NOT archivedReported THEN
{ archivedReported ← TRUE; ReportRope["(archived messages exist)"]};
OK => NULL;
wasDeleted => NULL;
retrieveFailed => EXIT;
ENDCASE => ERROR;
IF NOT (messageState = wasDeleted) THEN {
DeleteTrailingCRs: PROC [m: ROPE] RETURNS [ROPE] = {
len: INT ← Rope.Size[m];
WHILE len > 0 AND Rope.Fetch[m, len-1] = '\n DO len ← len-1; ENDLOOP;
RETURN [Rope.Substr[m,0,len]] };
GetField: PROC[message, fieldName: ROPE] RETURNS[contents: ROPE] = {
start: INT ← 0;
DO cr: INT ~ Rope.Index[s1: message, pos1: start, s2: "\n"];
IF cr=start THEN EXIT;
IF Rope.Find[s1: message, s2: fieldName, pos1: start, case: FALSE]=start THEN {
i: INT ← start+Rope.Length[fieldName];
IF Rope.Fetch[message, i]=': THEN {
i ← i+1;
IF Rope.Fetch[message, i]=' THEN i ← i+1;
RETURN[Rope.Substr[message, i, cr-i]];
};
};
start ← cr+1;
ENDLOOP;
RETURN[NIL];
};
GetFieldContents: PROC [name: ROPE, maxLen: INT] RETURNS [ROPE] = {
contents: ROPE ~ GetField[m, name];
len: INT ~ Rope.Length[contents];
IF len=0 THEN RETURN["?"]
ELSE IF len<=maxLen THEN RETURN[contents]
ELSE RETURN[Rope.Concat[Rope.Substr[base: contents, len: maxLen-3], "..."]]
};
GetDateFromGMT: PROC[time: BasicTime.GMT] RETURNS[ROPE] = {
Returns a string of the form dd-mmm-yy (for example, 17-Nov-83)
unpacked: BasicTime.Unpacked = BasicTime.Unpack[time];
day: NAT = unpacked.day;
month: ROPE = Convert.RopeFromUnpackedTime[unpacked, months, months];
year: NAT = unpacked.year;
RETURN[IO.PutFR["%2g-%g-%02g",
IO.int[day], IO.rope[month.Substr[len: 3]], IO.int[year MOD 100]]];
};
AppendNextMessage: PROC = {
headerDate, headerName, headerSubject, header: ROPE;
messageNode: RefTextNode;
headerNode ← TiogaFileOps.InsertNode[headerNode, FALSE];
IF firstHeader=NIL THEN firstHeader ← headerNode;
TiogaFileOps.SetFormat[headerNode, "header"];
headerDate ← GetDateFromGMT[BasicTime.FromPupTime[timeStamp.time]];
IF Rope.Equal[gvSender, PeanutSendMail.userRName, FALSE] OR
Rope.Equal[gvSender, PeanutSendMail.simpleUserName, FALSE] THEN
headerName ← Rope.Concat["To: ", GetFieldContents["To", 15]]
ELSE headerName ← GetFieldContents["From", 32];
headerSubject ← GetFieldContents["Subject", 45];
header ← Rope.Cat[
Rope.Concat["\t", headerDate],
Rope.Concat["\t", headerName],
Rope.Concat["\t", headerSubject]
];
TiogaFileOps.SetContents[headerNode, header];
IF formatting=NIL THEN {
messageNode ← TiogaFileOps.InsertNode[headerNode, TRUE];
TiogaFileOps.SetContents[messageNode, DeleteTrailingCRs[m]] }
ELSE {
messageRoot, messageFirst, messageLast, headerN: RefTextNode;
messageRoot ← PutGet.FromRope[Rope.Cat[Rope.FromChar['\n],m,formatting]];
Restore leading CR. Get back a root node.
messageFirst ← TextNode.FirstChild[messageRoot];
headerN ← headerNode;
headerN.child ← messageFirst;
messageLast ← TextNode.LastSibling[messageFirst];
messageLast.last ← TRUE; messageLast.next ← headerN;
messageRoot.child ← NIL; messageRoot.props ← NIL;
Clear out the links from the messageRoot to help garbage collection.
};
ViewerOps.SetNewVersion[mailViewer];
ReportRope["."];
messages ← messages + 1;
};
TiogaOps.Lock[mailDoc];
AppendNextMessage[ ! UNWIND => TiogaOps.Unlock[mailDoc] ];
TiogaOps.Unlock[mailDoc];
};
ENDLOOP ; -- Finished reading messages from this server.
Flush the mailbox if desired, we've stashed the messages.
IF FinishedWithServer[messageState#retrieveFailed] THEN
gvRetrieveHandle.Accept[ ! GVRetrieve.Failed =>
{ReportRope["\nFlush of remote messages failed; you may get these messages again"];
CONTINUE}];
IF messageState#retrieveFailed THEN ReportRope[
IO.PutFR[": retrieved %g messages.", IO.int[messages] ]];
numRetrieved← numRetrieved + messages;
ENDLOOP ; -- End of servers loop, exit.
IF NOT serverKnown THEN GOTO noMailboxes;
EXITS  -- The error reporter for this routine.
noMailboxes => ReportRope[" No mail boxes"];
credentialsError => ReportRope[" Credentials error"];
noServers => ReportRope[" No servers responding"];
};
bogusItems: INT ← 0;
ReadMessageRecord: PROC RETURNS
[messageState: MessageState, m, formatting: ROPE,
timeStamp: GVBasics.Timestamp, gvSender: RName] = {
This routine reads the messages on this connection, returning messageState = noMore
when there aren't any more.
ENABLE GVRetrieve.Failed --[why: FailureReason, text: ROPE]-- => {
ReportRope[SELECT why FROM
communicationFailure => "Communication failure",
noSuchServer => "No such server",
connectionRejected => "Connection rejected",
badCredentials => "Bad credentials",
unknownFailure => "Unknown failure",
ENDCASE => "Undefined error"];
IF text.Size[]>0 THEN { ReportRope[" -- "]; ReportRope[text] };
GOTO gvFailed;
};
msgExists, archived, deleted: BOOLEAN;
item: GVBasics.ItemHeader;
blockSize: NAT = 500;
block: REF TEXTNIL;
m ← NIL;
[msgExists, archived, deleted] ← GVRetrieve.NextMessage[ gvRetrieveHandle ];
IF archived THEN messageState ← wasArchived ELSE messageState← OK;
IF deleted THEN { messageState ← wasDeleted; RETURN};
IF NOT msgExists THEN { messageState ← noMore; RETURN};
Now read all the items in the message, terminating on the LastItem, and
skipping the ones that we're not yet interested in.
[timeStamp, gvSender, ] ← GVRetrieve.StartMessage[ gvRetrieveHandle ] ;
DO
ReadItem: PROC[h: GVRetrieve.Handle] RETURNS[rope: ROPENIL] = {
stream: IO.STREAM = GVRetrieve.GetItem[h];
IF block=NIL THEN block ← NEW[TEXT[blockSize]];
WHILE stream.GetBlock[block]>0 DO
rope ← rope.Concat[Rope.FromRefText[block]];
ENDLOOP;
};
item ← GVRetrieve.NextItem[gvRetrieveHandle];
SELECT item.type FROM
PostMark, Sender, ReturnTo => bogusItems ← bogusItems+1;
Recipients => NULL;
Text => m ← ReadItem[gvRetrieveHandle];
TiogaCTRL => formatting ← ReadItem[gvRetrieveHandle];
Capability => NULL;
Audio => NULL;
updateItem => NULL;
reMail => NULL;
LastItem => EXIT;
ENDCASE => LOOP;
ENDLOOP;
EXITS
gvFailed => messageState← retrieveFailed;
} ;
END.