THE GRAPEVINE INTERFACE Appendix: The Cedar Grapevine Interfaces This appendix contains those interfaces of the Cedar Grapevine client interface which were referred to earlier in this document. DIRECTORY Rope USING [ROPE]; GVBasics: CEDAR DEFINITIONS = BEGIN GVString: TYPE = Rope.ROPE; maxGVStringLength: CARDINAL = 64; RName: TYPE = GVString; maxRNameLength: CARDINAL = maxGVStringLength; Connect: TYPE = GVString; maxConnectLength: CARDINAL = maxGVStringLength; Remark: TYPE = GVString; maxRemarkLength: CARDINAL = maxGVStringLength; Password: TYPE = ARRAY[0..3] OF CARDINAL; MakeKey: PROC[Rope.ROPE] RETURNS[ Password ]; Timestamp: TYPE = MACHINE DEPENDENT RECORD[ net: [0..256), -- the PUP net number -- host: [0..256), -- the PUP host number -- time: PackedTime]; PackedTime: TYPE = LONG CARDINAL; oldestTime: Timestamp = [net:0, host:0, time:0]; RopeFromTimestamp: PROC[Timestamp] RETURNS[Rope.ROPE]; ItemHeader: TYPE = MACHINE DEPENDENT RECORD[ type: ItemType, length: ItemLength ]; Item: TYPE = REF ItemHeader; ItemLength: TYPE = INT; ItemType: TYPE = MACHINE DEPENDENT { PostMark(10B), Sender(20B), ReturnTo(30B), Recipients(40B), Text(1010B), Capability(1020B), Audio(1030B), updateItem(2000B), reMail(2100B), LastItem(LAST[CARDINAL]) }; END. DIRECTORY GVBasics USING[ Connect, GVString, oldestTime, Password, MakeKey, Remark, RName, Timestamp ], Rope USING[ ROPE ]; GVNames: CEDAR DEFINITIONS IMPORTS GVBasics = BEGIN Outcome: TYPE = { -- possible outcomes of RS operations -- noChange, -- updates and timestamped enquiries -- group, individual, notFound, -- any -- protocolError, wrongServer, allDown, -- any -- badPwd, -- authentication and updates -- outOfDate, notAllowed -- updates -- }; NameType: TYPE = Outcome[noChange..badPwd]; -- outcomes for enquiries -- RListHandle: TYPE = LIST OF GVBasics.RName; ExpandInfo: TYPE = RECORD[ SELECT type: NameType[noChange..allDown] FROM noChange => NULL, group => [ members: RListHandle, stamp: GVBasics.Timestamp, count: INT ], individual => [ sites: RListHandle, stamp: GVBasics.Timestamp, count: INT ], notFound => NULL, protocolError => NULL, wrongServer => NULL, allDown => NULL, ENDCASE ]; Expand: PROC[name: GVBasics.RName, oldStamp: GVBasics.Timestamp _ GVBasics.oldestTime, reporter: ReporterProc _ NIL] RETURNS[ ExpandInfo ]; MemberInfo: TYPE = RECORD[ SELECT type: NameType[noChange..allDown] FROM noChange => NULL, group => [ members: RListHandle, stamp: GVBasics.Timestamp, count: INT ], individual => NULL, notFound => NULL, protocolError => NULL, wrongServer => NULL, allDown => NULL, ENDCASE ]; GetMembers: PROC[name: GVBasics.RName, oldStamp: GVBasics.Timestamp _ GVBasics.oldestTime] RETURNS[ MemberInfo ] = INLINE { RETURN[ GetList[name, oldStamp, members] ] }; GetOwners: PROC[name: GVBasics.RName, oldStamp: GVBasics.Timestamp _ GVBasics.oldestTime] RETURNS[ MemberInfo ] = INLINE { RETURN[ GetList[name, oldStamp, owners] ] }; GetFriends: PROC[name: GVBasics.RName, oldStamp: GVBasics.Timestamp _ GVBasics.oldestTime] RETURNS[ MemberInfo ] = INLINE { RETURN[ GetList[name, oldStamp, friends] ] }; GetList: PROC[name: GVBasics.RName, oldStamp: GVBasics.Timestamp, list: ListType, reporter: ReporterProc _ NIL] RETURNS[MemberInfo]; StampInfo: TYPE = NameType[noChange..allDown]; CheckStamp: PROC[name: GVBasics.RName, oldStamp: GVBasics.Timestamp _ GVBasics.oldestTime, reporter: ReporterProc _ NIL] RETURNS[ StampInfo ]; ConnectInfo: TYPE = NameType[group..allDown]; GetConnect: PROC[name: GVBasics.RName, reporter: ReporterProc _ NIL] RETURNS[ info: ConnectInfo, connect: GVBasics.Connect ]; RemarkInfo: TYPE = NameType[group..allDown]; GetRemark: PROC[name: GVBasics.RName, reporter: ReporterProc _ NIL] RETURNS[ info: RemarkInfo, remark: GVBasics.Remark ]; GetEntryInfo: TYPE = RECORD[ name: GVBasics.RName, stamp: GVBasics.Timestamp, body: SELECT type: * FROM group => [ remark: GVBasics.Remark, remarkStamp: GVBasics.Timestamp, members: GetEntryList, owners: GetEntryList, friends: GetEntryList], individual => [ password: GVBasics.Password, passwordStamp: GVBasics.Timestamp, connect: GVBasics.Connect, connectStamp: GVBasics.Timestamp, forward: GetEntryList, sites: GetEntryList], notFound => NULL, dead => NULL, ENDCASE ]; GetEntryList: TYPE = RECORD[ current: RListHandle, currentStamps: LIST OF GVBasics.Timestamp, deleted: RListHandle, deletedStamps: LIST OF GVBasics.Timestamp]; GetEntry: PRIVATE PROC[name: GVBasics.RName, reporter: ReporterProc _ NIL] RETURNS[rc: NameType[group..allDown], info: REF GetEntryInfo]; AuthenticateInfo: TYPE = NameType[group..badPwd]; Authenticate: PROC[name: GVBasics.RName, password: Rope.ROPE] RETURNS[ AuthenticateInfo ] = INLINE { RETURN[ AuthenticateKey[name, GVBasics.MakeKey[password]] ] }; AuthenticateKey: PROC[name: GVBasics.RName, key: GVBasics.Password, reporter: ReporterProc _ NIL] RETURNS[ AuthenticateInfo ]; Membership: TYPE = { yes, no, notGroup, allDown }; IsMemberDirect: PROC[name: GVBasics.RName, member: GVBasics.RName] RETURNS[ Membership ] = INLINE { RETURN[IsInList[name, member, direct, self, members]] }; IsOwnerDirect: PROC[name: GVBasics.RName, owner: GVBasics.RName] RETURNS[ Membership ] = INLINE { RETURN[IsInList[name, owner, direct, self, owners]] }; IsFriendDirect: PROC[name: GVBasics.RName, friend: GVBasics.RName] RETURNS[ Membership ] = INLINE { RETURN[IsInList[name, friend, direct, self, friends]] }; IsMemberClosure: PROC[name: GVBasics.RName, member: GVBasics.RName] RETURNS[ Membership ] = INLINE { RETURN[IsInList[name, member, closure, self, members]] }; IsOwnerClosure: PROC[name: GVBasics.RName, owner: GVBasics.RName] RETURNS[ Membership ] = INLINE { RETURN[IsInList[name, owner, closure, self, owners]] }; IsFriendClosure:PROC[name: GVBasics.RName, friend: GVBasics.RName] RETURNS[ Membership ] = INLINE { RETURN[IsInList[name, friend, closure, self, friends]] }; IsMemberUpArrow:PROC[name: GVBasics.RName, member: GVBasics.RName] RETURNS[ Membership ] = INLINE { RETURN[IsInList[name, member, upArrow, self, members]] }; IsOwnerUpArrow: PROC[name: GVBasics.RName, owner: GVBasics.RName] RETURNS[ Membership ] = INLINE { RETURN[IsInList[name, owner, upArrow, self, owners]] }; IsFriendUpArrow:PROC[name: GVBasics.RName, friend: GVBasics.RName] RETURNS[ Membership ] = INLINE { RETURN[IsInList[name, friend, upArrow, self, friends]] }; MembershipLevel: TYPE = MACHINE DEPENDENT { direct(0), closure(1), upArrow(2) }; MembershipGrade: TYPE = MACHINE DEPENDENT { self(0), registry(1) }; ListType: TYPE = MACHINE DEPENDENT { members(0), owners(1), friends(2) }; IsInList: PROC[name: GVBasics.RName, member: GVBasics.RName, level: MembershipLevel, grade: MembershipGrade, acl: ListType, reporter: ReporterProc _ NIL] RETURNS[Membership]; CreateIndividual: PROC[user: GVBasics.RName, password: GVBasics.Password, individual: GVBasics.RName, newPwd: GVBasics.Password ] RETURNS[Outcome] = INLINE { RETURN[ Update[user, password, CreateIndividual, individual, NIL, newPwd] ] }; DeleteIndividual: PROC[user: GVBasics.RName, password: GVBasics.Password, individual: GVBasics.RName] RETURNS[Outcome] = INLINE { RETURN[ Update[user, password, DeleteIndividual, individual] ] }; CreateGroup: PROC[user: GVBasics.RName, password: GVBasics.Password, group: GVBasics.RName] RETURNS[Outcome] = INLINE { RETURN[ Update[user, password, CreateGroup, group] ] }; DeleteGroup: PROC[user: GVBasics.RName, password: GVBasics.Password, group: GVBasics.RName] RETURNS[Outcome] = INLINE { RETURN[ Update[user, password, DeleteGroup, group] ] }; SetPassword: PROC[user: GVBasics.RName, password: GVBasics.Password, individual: GVBasics.RName, newPwd: GVBasics.Password] RETURNS[Outcome] = INLINE { RETURN[ Update[user, password, ChangePassword, individual, NIL, newPwd] ] }; SetConnect: PROC[user: GVBasics.RName, password: GVBasics.Password, individual: GVBasics.RName, connect: GVBasics.Connect] RETURNS[Outcome] = INLINE { RETURN[ Update[user, password, ChangeConnect, individual, connect] ] }; SetRemark: PROC[user: GVBasics.RName, password: GVBasics.Password, group: GVBasics.RName, remark: GVBasics.Remark] RETURNS[Outcome] = INLINE { RETURN[ Update[user, password, ChangeRemark, group, remark] ] }; AddMailbox: PROC[user: GVBasics.RName, password: GVBasics.Password, individual: GVBasics.RName, site: GVBasics.RName] RETURNS[Outcome] = INLINE { RETURN[ Update[user, password, AddMailBox, individual, site] ] }; AddForward: PROC[user: GVBasics.RName, password: GVBasics.Password, individual: GVBasics.RName, dest: GVBasics.RName] RETURNS[Outcome] = INLINE { RETURN[ Update[user, password, AddForward, individual, dest] ] }; AddMember: PROC[user: GVBasics.RName, password: GVBasics.Password, group: GVBasics.RName, member: GVBasics.RName] RETURNS[Outcome] = INLINE { RETURN[ Update[user, password, AddMember, group, member] ] }; AddOwner: PROC[user: GVBasics.RName, password: GVBasics.Password, group: GVBasics.RName, owner: GVBasics.RName] RETURNS[Outcome] = INLINE { RETURN[ Update[user, password, AddOwner, group, owner] ] }; AddFriend: PROC[user: GVBasics.RName, password: GVBasics.Password, group: GVBasics.RName, friend: GVBasics.RName] RETURNS[Outcome] = INLINE { RETURN[ Update[user, password, AddFriend, group, friend] ] }; RemoveMailbox: PROC[user: GVBasics.RName, password: GVBasics.Password, individual: GVBasics.RName, site: GVBasics.RName] RETURNS[Outcome] = INLINE { RETURN[ Update[user, password, DeleteMailBox, individual, site] ] }; RemoveForward: PROC[user: GVBasics.RName, password: GVBasics.Password, individual: GVBasics.RName, dest: GVBasics.RName] RETURNS[Outcome] = INLINE { RETURN[ Update[user, password, DeleteForward, individual, dest] ] }; RemoveMember: PROC[user: GVBasics.RName, password: GVBasics.Password, group: GVBasics.RName, member: GVBasics.RName] RETURNS[Outcome] = INLINE { RETURN[ Update[user, password, DeleteMember, group, member] ] }; RemoveOwner: PROC[user: GVBasics.RName, password: GVBasics.Password, group: GVBasics.RName, owner: GVBasics.RName] RETURNS[Outcome] = INLINE { RETURN[ Update[user, password, DeleteOwner, group, owner] ] }; RemoveFriend: PROC[user: GVBasics.RName, password: GVBasics.Password, group: GVBasics.RName, friend: GVBasics.RName] RETURNS[Outcome] = INLINE { RETURN[ Update[user, password, DeleteFriend, group, friend] ] }; Update: PROC[ user: GVBasics.RName, password: GVBasics.Password, op: RSOperation, target: GVBasics.RName, value: GVBasics.GVString _ NIL, newPwd: GVBasics.Password _ NULL, list: RListHandle _ NIL, reporter: ReporterProc _ NIL] RETURNS[Outcome]; RSOperation: TYPE = MACHINE DEPENDENT { NoOp(0), Expand(1), ReadMembers(2), ReadOwners(3), ReadFriends(4), ReadEntry(5), CheckStamp(6), ReadConnect(7), ReadRemark(8), Authenticate(9), CreateRegistry(10), -- not implemented DeleteRegistry(11), -- not implemented CreateIndividual(12), DeleteIndividual(13), CreateGroup(14), DeleteGroup(15), ChangePassword(16), ChangeConnect(17), ChangeRemark(18), AddMember(19), AddMailBox(20), AddForward(21), AddOwner(22), AddFriend(23), DeleteMember(24), DeleteMailBox(25), DeleteForward(26), DeleteOwner(27), DeleteFriend(28), AddSelf(29), DeleteSelf(30), AddListOfMembers(31), NewName(32), IdentifyCaller(33),--internal to GVNamesImpl IsMemberDirect(40), -- archaic IsOwnerDirect(41), -- archaic IsFriendDirect(42), -- archaic IsMemberClosure(43), -- archaic IsOwnerClosure(44), -- archaic IsFriendClosure(45), -- archaic IsInList(46), ReadMailboxes(60), -- not implemented (255) }; ReporterProc: TYPE = PROC[Rope.ROPE]; SetServerInfo: TYPE = { badName, allDown, noRoute, ok }; SetServer: PROC[Rope.ROPE] RETURNS[ SetServerInfo ]; END. DIRECTORY GVBasics USING[ RName ], PupDefs USING[ PupAddress ]; GVLocate: CEDAR DEFINITIONS = BEGIN FoundState: TYPE = { allDown, notFound, found }; FoundServerInfo: TYPE = RECORD[ SELECT t: FoundState FROM allDown => NULL, notFound => NULL, found => [where: PupDefs.PupAddress], ENDCASE ]; FindNearestServer: PROC[list: GVBasics.RName, accept: PROC[PupDefs.PupAddress]RETURNS[BOOLEAN] ] RETURNS[ FoundServerInfo ]; FindLocalServer: PROC[listl: GVBasics.RName ] RETURNS[ FoundState, GVBasics.RName ]; FindRegServer: PROC[ who: GVBasics.RName, accept: PROC[PupDefs.PupAddress]RETURNS[BOOLEAN] ] RETURNS[ FoundServerInfo ]; AcceptFirst: PROC[PupDefs.PupAddress]RETURNS[BOOLEAN]; END. DIRECTORY GVBasics USING[ ItemHeader, RName, Timestamp ], IO USING[ STREAM ], Rope USING[ ROPE ]; GVRetrieve: CEDAR DEFINITIONS = BEGIN ROPE: TYPE = Rope.ROPE; Handle: TYPE = REF HandleObject; HandleObject: TYPE; Create: PROC[pollingInterval: CARDINAL, reportChanges: PROCEDURE[MBXState] _ NIL] RETURNS[Handle]; Close: PROC[Handle]; NewUser: PROC[ handle: Handle, user: GVBasics.RName, password: ROPE]; MBXState: TYPE = { unknown, badName, badPwd, cantAuth, userOK, allDown, someEmpty, allEmpty, notEmpty }; MailboxState: PROC[ handle: Handle] RETURNS[ state: MBXState]; WaitForMail: PROC[ handle: Handle ]; ServerType: TYPE = { MTP, GV }; ServerState: TYPE = { unknown, empty, notEmpty }; NextServer: PROC[ handle: Handle ] RETURNS[ noMore: BOOLEAN, state: ServerState, type: ServerType ]; ServerName: PROC[ handle: Handle] RETURNS [serverName: GVBasics.RName]; FailureReason: TYPE = { communicationFailure, -- server or network down -- noSuchServer, -- server name incorrect -- connectionRejected, -- server full, mbx busy, etc -- badCredentials, -- name/pwd rejected -- unknownFailure -- protocol violation or unknown MTP error: likely to be permanent -- }; Failed: ERROR[why: FailureReason, text: ROPE]; NextMessage: PROC[handle: Handle] RETURNS[msgExists, archived, deleted: BOOLEAN]; StartMessage: PROC[handle: Handle ] RETURNS[postmark: GVBasics.Timestamp, sender: GVBasics.RName, returnTo: GVBasics.RName]; NextItem: PROC[handle: Handle] RETURNS[GVBasics.ItemHeader]; GetItem: PROC[handle: Handle] RETURNS[IO.STREAM]; Accept: PROC[handle: Handle]; ReadTOC: PROC[handle: Handle] RETURNS[ ROPE ]; WriteTOC: PROC[handle: Handle, entry:ROPE ]; DeleteMessage: PROC[handle: Handle] ; END. DIRECTORY Rope USING[ ROPE ], GVBasics USING[ ItemType, Password, RName ]; GVSend: CEDAR DEFINITIONS = BEGIN ROPE: TYPE = Rope.ROPE; Handle: TYPE = REF Object; Object: TYPE; Create: PROCEDURE RETURNS[handle: Handle]; SendFailed: ERROR [ why: Rope.ROPE, notDelivered: BOOLEAN ] ; StartSendInfo: TYPE = MACHINE DEPENDENT { ok, badPwd, badSender, badReturnTo, allDown }; StartSend: PROC[ handle: Handle, senderPwd: ROPE, sender: GVBasics.RName, returnTo: GVBasics.RName _ NIL, validate: BOOLEAN ] RETURNS[ StartSendInfo ]; SendFromClient: PROC[ handle: Handle, fromNet: [0..256) _ 0, fromHost: [0..256) _ 0, senderKey: GVBasics.Password, sender: GVBasics.RName, returnTo: GVBasics.RName, validate: BOOLEAN ] RETURNS[ StartSendInfo ]; AddRecipient: PROC[ handle: Handle, recipient: GVBasics.RName ]; CheckValidity: PROC[ handle: Handle, notify: PROCEDURE[INT,GVBasics.RName] ] RETURNS[ ok: INT ]; StartItem: PROC[ handle: Handle, type: GVBasics.ItemType ]; StartText: PROC[ handle: Handle ] = INLINE{ StartItem[handle,Text] }; AddToItem: PROC[ handle: Handle, buffer: ROPE ]; Send: PROC[ handle: Handle ]; Abort: PROC[ handle: Handle ]; ExpandInfo: TYPE = MACHINE DEPENDENT { ok, notFound, individual, allDown} ; ExpandFailed: ERROR[why: Rope.ROPE]; Expand: PROC[name: GVBasics.RName, work: PROC[GVBasics.RName]] RETURNS[ ExpandInfo ]; END. 9ฦGrapevineUser - public DEFS for basic types GVBasics.mesa Andrew Birrell June 24, 1983 5:25 pm Note that incompatible changes to these definitions may require the cooperation of all mail servers and their clients, and the flushing of the mail server filestores. The following types are basic to the transport mechanism. "Connect", "Password" and "Remark" don't really occur in message bodies, but this is the most stable defs file for them. They are used by public clients of the transport mechanism. Most strings occurring inside Grapevine are restricted in length. An R-Name (Recipient-name) is the basic name within the transport mechanism. It is of the form SN.Reg ( Simple-Name . Registry ). The representation is as a ROPE of up to maxRNameLength characters. In message bodies, R-Names occupy an integral number of words. "Connect" is the representation of a connect-site for an individual (typically a server). It is a string which is either an NLS name or a PUP address. "Remark" is the representation of a remark associated with a group, or of a TOC entry in a mailbox. It is a human readable string. "Password" is the representation of an individual's encryption key. It is intended to be used with the DES encryption algorithm. Note that this is not the same as DESFace.Key (today), not even if you use LOOPHOLE. The following definitions are concerned with the layout of "message bodies". A message body is the internal representation of a message within and between mail servers. It is also sent to the client when he retrieves his mail. A message body contains a number of "items". Items are used to represent such things as postmark, recipients, sender, as well as the message text (if any), or other content of the message such as audio or capabilities. Some items are mandatory and always occur precisely once, others may occur any number of times (including zero). Each Item has a header, followed by the number of bytes of data specified by the header, followed by an extra byte if its length is odd. Thus items always start at a word boundary. A complete message body consists of the mandatory items followed by the optional ones. Used as UID's for messages and for database updates The number of seconds since midnight, January 1, 1901 GMT Returns "3#14@123456789", for example. Layout of items Each item consists of an ItemHeader followed by a variable length array, containing the number of bytes specified by the length. The item is followed by an extra byte if its length is odd. Number of data bytes in the item, excluding header Mandatory items: the item contains a timestamp giving the originating host and approximate time at which the message was given to the transport mechanism. the item contains precisely one R-Name, being that of the sender of this message the item contains precisely one R-Name, being that of the client to whom non-delivery of the message should be notified the item contains a sequence of R-Names, being the intended recipients of this message, as provided by the sender Items used solely by clients: the item contains a sequence of characters forming a textual message the item contains a capability the item is an audio message Items used in registration server internal mail: the item contains a registration server entry the item is internal mail to a mail server, containing precisely one R-Name, indicating that the corresponding mailbox should be re-mailed Mandatory last item: the item contains no data, and always occurs as the last item in a message body GrapevineUser: Client access to the R-Server database GVNames.mesa Andrew Birrell September 22, 1983 10:25 am "Expand" returns mailbox site names for individuals, membership list for groups. If the old stamp is still current, returns "noChange". Will not return "noChange" if the old stamp is defaulted. "GetMembers" returns the membership list for a group. If the old stamp is still current, returns "noChange". Will not return "noChange" if the old stamp is defaulted. "CheckStamp" performs basic name validation, also telling the caller the name type. If the old stamp is still current, returns "noChange". Will not return "noChange" if the old stamp is defaulted. "GetConnect" returns the connect-site for an individual. The connect-site is either an NLS name or a net-address. "GetRemark" returns the remark for a group. The remark is a human readable string.. "GetEntry" is mainly for use by Maintain. It returns the entire contents of a database entry. Consult a wizard before using GetEntry "Authenticate" checks a user name and password. Access control primitives Updates Creation and Deletion Updates to single-valued components Adding to list-valued components Removing from list-valued components Enquiries (also 60..69) Updates 60..69 reserved for more enquiries "ReporterProc" is primarily to allow Maintain to report progress to its user. Consult a wizard before using this facility. "SetServer" provides a server hint, primarily used by Maintain. Consult a wizard before using this facility. GrapevineUser (Cedar) - Location of servers GVLocate.mesa Andrew Birrell May 13, 1983 1:29 pm returns TRUE GrapevineUser (Cedar) - public DEFS for retrieval of messages GVRetrieve.mesa Andrew Birrell September 1, 1982 10:08 am No procedures in this interface other than the message accessing procs ever raise a SIGNAL or ERROR. 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 (particularly any BSP connection). -- 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". Releases resources used by this handle. Further use of this handle is illegal. AUTHENTICATION AND MAILBOX POLLING Provides new user name and password, and starts authentication and mailbox checking. 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. Returns the current mailbox state. Will not return "unknown" or "userOK" (These change to "cantAuth" or "allDown" after suitable timeouts if necessary.) returns only when there is likely to be mail for the user Possible ERRORS: none ACCESS TO MAILBOXES The intended use is as follows. The user has a number of mailboxes, each of which is on an MTP server or xon a Grapevine 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 NOTE: If the user has a mailbox on an MTP server, calling "NextMessage" for that mailbox will raise "Failed[communicationFailure]". If "NextMessage" returns deleted=TRUE it indicates that 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. For each message that exists and is not deleted, the message may be manipulated by the other procedures provided. "ReadTOC" may be used to read any TOC entry for the message (giving length=0 if there is no TOC entry), then "StartMessage" may be called to read the guaranteed properties of the message; these are not available for MTP servers; these may not be called after you have called "NextItem" for this message. "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 entrie item has not been read yet) and moves on to the next item. You may call "WriteTOC" to change or create a TOC entry for the message, or you may call "DeleteMessage" to remove this single message from the mailbox; "ReadTOC", "StartMessage", "NextItem" or "NextBlock" may not be called after calling "WriteTOC" or "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"). "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". Returns information about the next server in the mailbox site list of the user, 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. Provides the name of the current server. For MTP registries, this will be equivalent to the registry name. May be signalled by any of the procedures that handle messages. Skips the remainder of any previous item, then delivers the header of the next item. Provides an IO stream for reading the current item. Flush the mailbox entirely (and irrecoverably). "ReadTOC", "WriteTOC" and "DeleteMessage" are useful mainly for Lily. GrapevineUser (Cedar) - public DEFS for client sending mail GVSend.mesa Andrew Birrell May 12, 1983 1:34 pm These defs allow clients to inject messages into the mail system. They are designed so that they can be used by multiple processes creating different messages; the state of creation of a single message is represented by a "Handle". The interface is also designed so that it may be implemented either by transmission over the network to a remote mail server, or by calls on a local mail server. For any one Handle, the following calls must be made in the order: StartSend, AddRecipient, AddRecipient, AddRecipient, . . . CheckValidity {iff "validate=TRUE" when "StartSend" was called}, StartItem, (AddToItem, AddToItem, . . .), StartItem, (...), . . . Send Abort may be called at any point to abandon the sequence. A Handle may be re-used. "Abort" happens implicitly if needed sometime after the last reference to the Handle goes away. "StartSend" raises no signals that may be caught by the client. The ERROR "SendFailed" may be raised by any of AddRecipient, CheckValidity, StartItem, AddToItem, or Send if some communication failure occurs. If it is raised, the client should generally catch it, go back to the start of the message, and re-call "StartSend". "StartSend" will then attempt to find a better mail server to talk to. Only when "StartSend" returns "allDown" is it not possible to send the message. The client may want to inform the user if thisre-try mechanism has been invoked. Starts a message. If "returnTo" is NIL, the sender name is used as return-to name. "validate" says whether recipient names should be validated during the communication with the mail server. Note: this procedure is intended for use only by the remote server. Starts a message. "fromNet" and "fromHost" are ignored if the mail server is remote. "validate" says whether recipient names should be validated during the communication with the mail server. Adds to the recipient list. Must be called after all the recipients have been given, iff the "validate" argument to "StartSend" was TRUE. Calls "notify" for each bad recipient. The arguments to "notify" are the recipient number (counting from 1) and name of an illegal recipient. Returns the number of valid recipients. If any recipients were invalid, delivery of the message is still allowed. Start a message body item. The type must not be "Postmark", "Sender", "ReturnTo", or "Recipients". Add the data to the current message body item. Commit to sending the message; returns only when the mail server has commited to delivering the message. Abandon the message. May be called at any time. If the name will be interpreted by the mail server as a distribution list, enumerates the names which are direct members of that list. This is intended for use only if the user wants to inspect the contents. Note that the contents may change, or the name may become invalid, before delivery of any message. "Expand" works even if the list has to be read from an MTP server. May raise "ExpandFailed". If ExpandFailed is raised, some communication error has occurred; you should re-call Expand, which will try another server. Note that failure of Expand may be caused by failure of some remote server; you may still be able to send a message successfully. "notFound" means the name is invalid; "individual" means the name specifies an individual; "allDown" means either all mail servers are inaccessible, or some other server (possibly MTP) needed for the expansion is inaccessible. สฟ–"blueandwhite" style–A(firstPageNumber) 29 .cvx .def (oneSidedFormat) {.true} .cvx .def˜Iblock•Mark centerHeaderšœฯsœ œ˜headšœ)˜)Ibody˜€M˜M˜Jšฯi+™+Jšž ™ Jšž%™%Icode˜šฯk ˜ NšœŸœŸœ˜—N˜Nšœ ŸœŸ œ˜N˜NšŸ˜N˜Jšžฆ™ฆJ˜Jšž๏™๏J˜J˜Nšœ ŸœŸœ˜N˜šœŸœ˜!JšžA™A—N˜N˜šœŸœ ˜Jšž‡™‡—N˜NšœŸœ˜-N˜N˜šœ Ÿœ ˜Jšž—™——N˜NšœŸœ˜/N˜N˜šœ Ÿœ ˜Jšžƒ™ƒ—N˜NšœŸœ˜.N˜N˜š œ ŸœŸœŸœŸœ˜)JšžƒะciT™ื—N˜NšฯnœŸœŸœŸœ ˜-N˜N˜N˜N˜Jšžย™ยJ˜J˜š œ ŸœŸœŸ œŸœ˜+Jšž3™3Nšœฯc˜(Nšœข˜)N˜N˜—šœ ŸœŸœŸœ˜!Jšž0  ™9N˜—N˜0N˜šกœŸœ ŸœŸœ˜6Jšž&™&—N˜N˜Jšž™N˜š œ ŸœŸœŸ œŸœ˜,N˜N˜Jšž 0™ฝN˜—NšœŸœŸœ ˜N˜šœ ŸœŸœ˜Jšž2™2—N˜šœ ŸœŸœŸ œ˜$šž™šœ˜Jšž‰™‰—šœ ˜ JšžP™P—šœ˜Jšžw™w—šœ˜Jšžq™q——šž™šœ ˜ JšžD™D—šœ˜Jšž™—šœ ˜ Jšž™——šž0™0šœ˜Jšž-™-—šœ˜JšžŠ™Š——šž™šœ ŸœŸœ˜JšžO™O——N˜—N˜NšŸœ˜I pagebreak™Jšž  ž™6Jš ž™ Jšž+™+N™šŸ ˜ Nšœ ŸœO˜]NšœŸœŸœ˜N˜—šœ ŸœŸ ˜NšŸœ ˜—N˜NšŸ˜N˜šœ Ÿœข(˜:Nšœ ข'˜1Nšœข ˜&Nšœ%ข ˜.Nšœข ˜(Nšœข ˜#N˜N˜—Nšœ Ÿœข˜HN˜Nšœ ŸœŸœŸœ˜+N˜N˜N˜šœ ŸœŸœŸœ#Ÿ˜HNšœ Ÿœ˜˜ N˜NšœŸœ˜ —˜#N˜NšœŸœ˜ —Nšœ Ÿœ˜NšœŸœ˜NšœŸœ˜Nšœ Ÿœ˜NšŸœ˜ —N˜šกœŸœdŸœŸœ˜‹Jšžย™ยN˜N˜N˜—šœ ŸœŸœŸœ#Ÿ˜HNšœ Ÿœ˜˜ N˜NšœŸœ˜ —NšœŸœ˜Nšœ Ÿœ˜NšœŸœ˜NšœŸœ˜Nšœ Ÿœ˜NšŸœ˜ N˜—šก œŸœJŸœŸ˜yNšœŸœ'˜/Jšž‹ ™งN˜—šก œŸœJŸœŸ˜xNšœŸœ&˜.N˜—šก œŸœJŸœŸ˜yNšœŸœ'˜/—N˜šกœŸœ^ŸœŸœ ˜„N˜N˜N˜—Nšœ Ÿœ˜.N˜šก œŸœdŸœŸœ˜ŽJšžล™ลN˜N˜N˜—Nšœ Ÿœ˜-N˜šก œŸœ0ŸœŸœ1˜}JšžXะikž™rN˜N˜N˜—Nšœ Ÿœ˜,N˜šก œŸœ0ŸœŸœ.˜yJšžT™TN˜N˜N˜—šœŸœŸœ˜Nšœ˜Nšœ˜šœŸœ Ÿ˜šœ ˜ Nšœ˜Nšœ ˜ Nšœ˜Nšœ˜Nšœ˜—šœ˜Nšœ˜Nšœ"˜"Nšœ˜Nšœ!˜!Nšœ˜Nšœ˜—Nšœ Ÿœ˜NšœŸœ˜ —NšŸœ˜ —N˜šœŸœŸœ˜Nšœ˜NšœŸœŸœ˜*Nšœ˜NšœŸœŸœ˜+—N˜Nš กœŸ œ0ŸœŸœ%Ÿœ˜‰šž†™†N˜N˜N˜—NšœŸœ˜1N˜šก œŸœ&Ÿœ˜=NšŸœŸ˜$NšœŸœ8˜@Jšž/™/N˜—šกœŸœHŸœ˜aNšŸœ˜N˜N˜N˜—Jšž™N˜Nšœ Ÿœ"˜2N˜šกœŸœ.ŸœŸ˜aNšœŸœ2˜:N˜—šก œŸœ-ŸœŸ˜_NšœŸœ0˜8N˜—šกœŸœ.ŸœŸ˜aNšœŸœ2˜:N˜—šกœŸœ.ŸœŸ˜bNšœŸœ3˜;N˜—šกœŸœ-ŸœŸ˜`NšœŸœ1˜9N˜—šกœŸœ.ŸœŸ˜aNšœŸœ3˜;N˜—šกœŸœ.ŸœŸ˜aNšœŸœ3˜;N˜—šกœŸœ-ŸœŸ˜`NšœŸœ1˜9N˜—šกœŸœ.ŸœŸ˜aNšœŸœ3˜;—N˜NšœŸœŸœŸ œ'˜PNšœŸœŸœŸ œ˜CNšœ ŸœŸœŸ œ'˜IN˜šกœŸœ‡Ÿœ˜™NšŸœ ˜N˜N˜N˜N˜—Jšž™J˜J˜Jšž™N˜šกœŸœkŸœ Ÿ˜›NšœŸœ7Ÿœ˜PN˜—šกœŸœOŸœ Ÿ˜NšœŸœ;˜CN˜—šก œŸœJŸœ Ÿ˜uNšœŸœ1˜9N˜—šก œŸœJŸœ Ÿ˜uNšœŸœ3˜;N˜N˜N˜N˜—Jšž#™#N˜šก œŸœjŸœ Ÿ˜•NšœŸœ5Ÿœ˜NN˜—šก œŸœjŸœ Ÿ˜”NšœŸœA˜IN˜—šก œŸœcŸœ Ÿ˜ŒNšœŸœ:˜BN˜N˜N˜N˜—Jšž ™ N˜šก œŸœeŸœ Ÿ˜NšœŸœ;˜CN˜—šก œŸœeŸœ Ÿ˜NšœŸœ;˜CN˜—šก œŸœbŸœ Ÿ˜‹NšœŸœ7˜?N˜—šกœŸœaŸœ Ÿ˜‰NšœŸœ5˜=N˜—šก œŸœbŸœ Ÿ˜‹NšœŸœ7˜?N˜N˜N˜N˜—Jšž$™$N˜šก œŸœeŸœ Ÿ˜’NšœŸœ>˜FN˜—šก œŸœeŸœ Ÿ˜’NšœŸœ>˜FN˜—šก œŸœbŸœ Ÿ˜ŽNšœŸœ:˜BN˜—šก œŸœaŸœ Ÿ˜ŒNšœŸœ8˜@N˜—šก œŸœbŸœ Ÿ˜ŽNšœŸœ:˜BN˜N˜—šกœŸœ˜ Nšœ˜N˜N˜N˜NšœŸœ˜NšœŸœ˜!NšœŸœ˜NšœŸœ˜NšŸœ ˜N˜—šœ ŸœŸœŸ œ˜'Nšœ˜šž™Nšœ ˜ Nšœ˜Nšœ˜Nšœ˜Nšœ ˜ Nšœ˜Nšœ˜Nšœ˜Nšœ˜—šž™Nšœข˜&Nšœข˜&Nšœ˜Nšœ˜Nšœ˜Nšœ˜Nšœ˜Nšœ˜Nšœ˜Nšœ˜Nšœ˜Nšœ˜Nšœ ˜ Nšœ˜Nšœ˜Nšœ˜Nšœ˜Nšœ˜Nšœ˜Nšœ ˜ Nšœ˜Nšœ˜Nšœ ˜ Nšœข˜,Nšœข ˜Nšœข ˜Nšœข ˜Nšœข ˜Nšœข ˜Nšœข ˜Nšœ ˜ —šž"™"Nšœข˜%—Nšœ˜N˜N˜N˜—N˜šก œŸœŸœŸœ˜%Jšž{™{—N˜N˜N˜NšœŸœ%˜8N˜šก œŸœŸœŸœ˜4Jšžm™mN˜—NšŸœ˜O™Jšž+™+Jšž ™ Jšž$™$N˜šŸ ˜ Nšœ Ÿœ ˜NšœŸœ˜—N˜Nšœ Ÿœ˜N˜NšŸ˜N˜Nšœ Ÿœ ˜0N˜šœŸœŸœ˜šŸœŸ˜Nšœ Ÿœ˜Nšœ Ÿœ˜N˜%—NšŸœ˜ N˜—š กœŸœŸœŸœŸœŸœ˜|N˜—šกœŸœŸœ˜TN˜—š ก œŸœŸœŸœŸœŸœ˜xN˜—šก œŸœŸœŸœ˜6Jšž ™ N˜—NšŸœ˜O™Jšž=™=Jšž™Jšž*™*N˜šŸ ˜ Nšœ Ÿœ!˜/NšŸœŸœŸœ˜NšœŸœŸœ˜—N˜Nšœ ŸœŸ œ˜N˜NšŸ˜N˜NšŸœŸœŸœ˜N˜Jšžd™dN˜N˜šœŸœŸœ˜ Jšž† &™ฌN˜—NšœŸœ˜N˜N˜š กœŸœŸœŸ œ ŸœŸœ ˜bJšž๑™๑N˜N˜—šกœŸœ ˜JšžO™ON˜N˜N˜N˜—Jšž"™"N˜N˜šกœŸœ2Ÿœ˜EJšžT™TN˜N˜—šœ ŸœZ˜hJšžฆ™ฆN˜—šก œŸœŸœ˜>Jšž™™™N˜N˜—šก œŸœ˜$Jšž9™9Jšž™N˜N˜N˜N˜N˜—Jšž™J˜J˜Jšž™J˜Jšžล™ลJ˜Jšžฅ™ฅJ˜Jšžƒ™ƒJ˜Jšžฐ™ฐJ˜Jšžฏ™ฏJ˜Jšžข™ขJ˜Jšžž™žJ˜Jšž_™_J˜Jšžๅ™ๅJ˜Nšœ ŸœŸœŸœ˜N˜šœ Ÿœ ˜1Jšžศ™ศN˜—šก œŸœŸœ Ÿœ)˜dJšžิ™ิN˜N˜—šก œŸœŸœ˜GJšžk™kN˜N˜—šœŸœ˜Nšœข˜2Nšœข˜)Nšœข ˜4Nšœข˜'NšœขE˜TNšœ˜—N˜šœŸœŸœ˜.Jšž?™?N˜N˜—šก œŸœŸœŸœ˜QN˜—šก œŸœŸœQ˜}N˜—šกœŸœŸœ˜