MailRetrieve.mesa
Copyright Ó 1988, 1991 by Xerox Corporation. All rights reserved.
Doug Terry, December 12, 1988 6:06:18 pm PST
Wes Irish, December 22, 1988 3:19:55 pm PST
Willie-Sue, May 4, 1989 4:41:00 pm PDT
Operations for retrieval of electronic mail messages. Modeled after GVRetrieve.mesa.
DIRECTORY
IO USING [STREAM],
MailBasics USING [ItemHeader, RName, Timestamp],
Rope USING [ROPE];
MailRetrieve: CEDAR DEFINITIONS
~ BEGIN
No procedures in this interface other than the message accessing procs ever raise a SIGNAL or ERROR.
STREAM: TYPE ~ IO.STREAM;
ROPE: TYPE ~ Rope.ROPE;
MailRetrieveProcsRef: TYPE = REF MailRetrieveProcs;
MailRetrieveProcs: TYPE = RECORD [
which: ATOM,
Close: PROC[ref: REF],
NewUser: PROC [handle: Handle, user: MailBasics.RName, password: ROPE, pollingInterval: CARDINAL, reportChanges: PROC[Handle, MBXState] ] RETURNS[REF],
MailboxState: PROC [ref: REF] RETURNS [mboxState: MBXState],
NextServer: PROC [ref: REF] RETURNS
[noMore: BOOLEAN, state: MailRetrieve.ServerState, type: MailRetrieve.ServerType],
ServerName: PROC [ref: REF] RETURNS [serverName: MailBasics.RName],
UserName: PROC [ref: REF] RETURNS [userName: MailBasics.RName],
NextMessage: PROC [ref: REF] RETURNS [msgExists, archived, deleted, read: BOOL],
StartMessage: PROC [ref: REF] RETURNS [postmark: MailBasics.Timestamp, sender: MailBasics.RName, returnTo: MailBasics.RName],
NextItem: PROC [ref: REF] RETURNS [ih: MailBasics.ItemHeader, currentItem: IO.STREAM],
GetItem: PROC [ref: REF] RETURNS [IO.STREAM],
GetItemAsRope: PROC [ref: REF] RETURNS [ROPE],
GetItemViaCallback: PROC [ref: REF, proc: MailRetrieve.GetItemCallback],
MarkMessage: PROC [ref: REF],
DeleteMessage: PROC [ref: REF],
Accept: PROC [ref: REF]
];
Handles
Handle: TYPE = REF;
This interface is intended to be able to be used by multiple clients. They are distinguished by a "handle", created by "Create" and destroyed by the garbage collector. "Close" should be called when you're finished with the handle as a hint to release resources.
Create: PROC [pollingInterval: CARDINAL, reportChanges: PROC [Handle, MBXState] ¬ NIL] RETURNS [Handle];
Must be called before any other entries in this interface. Can be called many times. "pollingInterval" is the interval in seconds to wait between successive inbox checks and "reportChanges" (if provided) is called whenever the state of the user's authentication or mailboxes changes; "reportChanges" will not be called if the state changes to "unknown" or "userOK".
Close: PROC [handle: Handle];
Releases resources used by this handle. Further use of this handle is illegal.
Authentication and Mailbox Polling
NewUser: PROC [handle: Handle, user: MailBasics.RName, password: ROPE];
Provides new user name and password, and starts authentication and mailbox checking. This can be called several times to associate several mailboxes with the handle.
MBXState: TYPE = { unknown, badName, badPwd, cantAuth, userOK, allDown, someEmpty, allEmpty, notEmpty };
Records current state of the user's mailboxes. Initially "unknown". Set to "badName", "badPwd", "cantAuth" or "userOK" after authentication check. Set to "allDown", "someEmpty", "allEmpty", or "notEmpty" after mail polling is complete. "someEmpty" means not all servers replied and none had mail; "allEmpty" means all replied and none had mail; "notEmpty" means at least one has mail; "allDown" means none replied.
MailboxState: PROC [handle: Handle] RETURNS [state: MBXState];
Returns the current mailbox state. Will not return "unknown" or "userOK" (These change to "cantAuth" or "allDown" after suitable timeouts if necessary.)
Access to Mailboxes
The intended use is as follows.
The user has a number of mailboxes, each of which is on a mail server of some type (e.g. a MTP, Grapevine, or XNS mail server). To access all of a client's mail, call "NextServer" repeatedly until it returns noMore=TRUE. For each successful call of "NextServer", if the ServerState is "notEmpty" use the mailbox access procedures to read the mail in the mailbox (otherwise there is no point in using the mailbox access procedures, since the mailbox is either empty or inaccessible).
To read the mail in the mailbox, call "NextMessage" until it returns msgExists=FALSE. The first call of "NextMessage" for each server will attempt to create a stream to the server (signalling if it fails). While accessing a mailbox, "Failed" may be signalled at any time if the communication system fails (because of network or server error). If "Failed" is signalled, no further operations on this mailbox are allowed. For each message that exists and is not deleted, the message may be manipulated by the other procedures provided.
"NextItem" may be called to access in sequence the items which are the contents of the message body. Note that the ItemHeader contains the item type and length in bytes. The first item will be the guaranteed recipient list. The message body is followed by an item of type "LastItem". Within an item, use an IO.STREAM may be used to access the data of the item. EndOf[] will be true at the end of the item. Calling NextItem closes any IO.STREAM on a current item (even if the entire item has not been read yet) and moves on to the next item.
You may call "DeleteMessage" to remove this single message from the mailbox; "StartMessage", "NextItem" or "NextBlock" may not be called after calling "DeleteMessage" for this message.
At any time within a message, you may call "NextMessage" to skip the remainder of this message.
At any time within a mailbox, you may call "Accept". This terminates reading the mailbox and deletes all messages from the mailbox. Calling "accept" will not delete any messages which you haven't been given a chance to read. No other operations on the mailbox are allowed after calling "accept". If you call "NextServer" without having called "accept", the mailbox is closed (if necessary) without deleting the messages (except those which were deleted by calling "deleteMessage").
ServerType: TYPE = ATOM;
Valid types of servers include $xns, $gv, $mtp.
ServerState: TYPE = { unknown, empty, notEmpty };
"unknown" means the server didn't reply to mail check packets; in this case, for efficiency, you should NOT call "NextMessage". There is no point in calling NextMessage if the ServerState is "empty".
NextServer: PROC [handle: Handle, reset: BOOLEAN ¬ FALSE] RETURNS [noMore: BOOLEAN, state: ServerState, type: ServerType];
Returns information about the next server in the mailbox site list of the user (or the first server if reset=TRUE), and that server becomes the "current server". If there is no such server, noMore=TRUE, in which case the next call to "NextServer" will start a new sequence of mail retrieval. If the state is "unknown", attempting to access the mailbox is inadvisable, as the server is probably down. If the state is "empty", there may in fact be mail, as the state is only a hint obtained by polling.
ServerName: PROC [handle: Handle] RETURNS [serverName: MailBasics.RName];
Provides the name of the current server. For MTP registries, this will be equivalent to the registry name.
UserName: PROC [handle: Handle] RETURNS [userName: MailBasics.RName];
Provides the name of the current mailbox being accessed.
FailureReason: TYPE = ATOM;
One of:
$communicationFailure, -- server or network down --
$noSuchServer, -- server name incorrect --
$connectionRejected, -- server full, mbx busy, etc --
$badCredentials, -- name/pwd rejected --
$unknownFailure -- protocol violation or unknown error: likely to be permanent --
Failed: ERROR [why: FailureReason, text: ROPE];
May be signalled by any of the procedures that handle messages.
NextMessage: PROC [handle: Handle]
RETURNS [msgExists, archived, deleted, read: BOOLEAN];
Returns information about the next message in the mailbox, and that message becomes the "current message". If there is no such message, msgExists=FALSE. If deleted=TRUE then the message is really just a placeholder and has been removed from the mailbox; you should not attempt to access the message. Returning archived=TRUE indicates that the message has been spilled to some file server, and accessing it is likely to be much slower. If read=TRUE then the message is not new, i.e. it has been previously marked as being read.
StartMessage: PROC [handle: Handle]
RETURNS [postmark: MailBasics.Timestamp,
sender: MailBasics.RName,
returnTo: MailBasics.RName];
Returns information from the envelope of the message.
NextItem: PROC [handle: Handle] RETURNS [MailBasics.ItemHeader];
Skips the remainder of any previous item, then delivers the header of the next item.
GetItem: PROC [handle: Handle] RETURNS [STREAM];
Provides an IO stream for reading the current item.
GetItemAsRope: PROC [handle: Handle] RETURNS [ROPE];
Provides the current item as a ROPE. This is probably the most convenient and possible even the most efficient way to get the contents of an item for small to moderate sized items. It is perfectly acceptable for clients to get items solely through this call.
GetItemViaCallback: PROC [handle: Handle, proc: GetItemCallback];
Provides the current item via a callback. This is probably the most efficient for LARGE items and/or items that the client is putting directly to disk, the network, etc.
GetItemCallback: TYPE ~ PROC [s: STREAM, checkAbort: PROC RETURNS [BOOL]] RETURNS [abort: BOOL];
This is the type of PROC that you must provide to GetItemViaCallback.
MarkMessage: PROC [handle: Handle];
Marks current message as being read.
DeleteMessage: PROC [handle: Handle];
Deletes current message.
Accept: PROC [handle: Handle];
Flush the mailbox entirely (and irrecoverably).
RegisterMailRetrieveProcs: PROC[newProcs: MailRetrieveProcsRef];
GetRegisteredRetrieveProcsList: PROC RETURNS[LIST OF MailRetrieveProcsRef];
in case anyone wants them
GetRegisteredRetrieveMailProcs: PROC[which: ATOM] RETURNS[MailRetrieveProcsRef];
END.