\begindata{text,539630556} \textdsversion{12} \template{default} \define{global } \chapter{1 The Andrew Message System Server-Client Interface } \section{1.1 Introduction} This paper describes the server-client interface of the Andrew Message System. It presumes a basic familiarity with the normal use and function of the system. For such information, please consult the introductory documents (AMS.ovr and MsgSrvr.ovr). If you are using EZ to read this document, you can open an interactive Table of Contents window by choosing \bold{Table of Contents} from the \italic{Page} menu card. Clicking on a heading in the Table of Contents window that appears scrolls this document to bring the heading into view. \section{1.2 Basic Concepts} \subsection{1.2.1 Message Server and Clients} The central concept in the design of the Andrew Message System is the client-server split. The \italic{message server} is a process which runs on an Andrew workstation (attached to the Vice file system, if the machine is at a Vice site), and performs various operations on a message database. It performs these actions in response to explicit remote procedure calls from a \italic{client} program, such as the cui or messages programs. Clients never access the database directly, even if they are running on an Andrew workstation; all database access is channeled through the message server. This allows client programs to run on a wide variety of machines (such as IBM PC's) not necessarily connected to the file system. The communication between the client and server consists of a set of approximately forty remote procedure calls, which permit various operations on structures defined in a shared header file, "AMS.h". The structures defined in AMS.h are the portable representations of the database; they do not necessarily have any relation to the actual structures stored in the file system, but are translated by the message server. It is worth noting that all RPC calls in the message system use fixed size buffers; thus certain calls need to be repeated in order to get a complete answer. It is also worth noting that all calls are designed to be idempotent, and that the architecture is designed so that a server can die at any moment, with the client automatically reconnecting and continuing its work without any loss of context. These goals are nearly completely met, with a few exceptions that will be noted as necessary. \subsection{1.2.2 Messages} The most basic entity in the message system is, naturally, a \italic{message}. A message is simply an ASCII string of unbounded length, formatted as a mail message according to then Internet standard, RFC 822. As explained in that standard, each message contains a set of \italic{headers} (which may be viewed as attribute/value pairs, and can be retrieved as such by the client from the message server), and a \italic{body}, which is the text of the message. \subsection{1.2.3 Message Directories} Messages are grouped together in \italic{message directories}. A message directory is simply a collection of messages and other message directories. The structure of messages and directories corresponds closely to the UNIX structure of files and directories. \subsection{1.2.4 Snapshots} Within a message directory, several different pieces of information are stored regarding the individual messages within that directory. This information is collected together in a single fixed-length structure called a \italic{snapshot}. Snapshots are the structure most commonly exchanged between servers and clients; they contain all of the "fast" information, that is, all of the information which can be obtained more quickly than the message itself. Snapshots consist of seven sub-structures, known as the caption, id, date, attributes, chain, midhash, and replyhash. Because different machines do not represent structures identically, message snapshots are NOT passed as structures. Rather, a snapshot is passed as a byte array of fixed size, and its components are accessed via machine-independent macros, as described below. (The include file AMS.h is required here. It is automatically included by CUI.h, for clients, and by MS.h, for the messageserver itself.) \subsection{1.2.5 Captions} The \italic{caption} is a one line summary of the message, to be shown, for example, to a user to help him decide whether or not to view the body of the message. It most typically contains the date, subject, and sender of the message, separated by TAB characters, but this formatting is *not* required, and different applications may put entirely different information into the caption. However, the snapshot should be an ASCII string. The caption is accessed as AMS_CAPTION(Snapshot). \subsection{1.2.6 Message Ids} The \italic{id} is a unique identifier that is associated with the message. No two messages will ever be given the same ID, provided a few assumptions about the world are met. (For example, provided that new two machines ever have the same internet address, and that the same machine never runs with its clock at the same time twice, and so on.) If the same message appears in multiple directories, should have the same id. The id is an 18-digit ASCII string which is encoded in a base-64 alphabet defined in the message system code. The id is accessed as AMS_ID(Snapshot). \subsection{1.2.7 Dates} The \italic{date} is an ordering field, by which messages in a directory are ordered. As the name suggests, this is usually a date, but an application could conceivably use a different ordering criterion. The date is a 6 character ASCII string, conventionally a UNIX date encoded in base 64. This is accessed as AMS_DATE(Snapshot). \subsection{1.2.8 Attributes} The \italic{attributes} of a message is a set of bits encoding certain facts about the message. Specifically, each bit encodes whether a certain "attribute" of a message is true or not. For example, there is a bit that encodes whether or not the message is marked as "deleted". This is accessed as AMS_ATTRIBUTES(Snapshot). However, there are also macros for picking out (and setting) individual attributes, e.g. AMS_GET_ATTRIBUTE(Snapshot, AMS_ATT_DELETED) (or AMS_SET_ATTRIBUTE(...)). The list of defined attribute values is in AMS.h. This macro is also used for accessing user-defined attributes by number. For user defined attribute #i, you would use macros like AMS_GET_ATTRIBUTE(Snapshot, AMS_ATT_UATTR(i)). To map the attribute numbers to names within a given folder, there are specialized messageserver calls. Other macros defined in AMS.h useful for attributes include AMS_NUM_UATTRS, which is the number of user-defined attributes available, and AMS_ATTRNAMEMAX, which is the maximum length of the name of a user-defined attribute. \subsection{1.2.9 Chains} The \italic{chain} of a message is a network-byte-order integer that can be used to find "related" messages within a folder. If one message is clearly marked (by In-Reply-To or References headers) as being a reply to another, then they should have the same chain value. The chain is accessed as AMS_CHAIN(Snapshot). Although it is in network byte order, this is probably irrelevant to the client, who really only needs to check for equality of chain values. Typical code for accessing the chain looks something like this, unfortunately: \example{bcopy(AMS_CHAIN(SBuf), &refint, sizeof(unsigned long)); ThisChain = ntohl(refint); } The midhash and replyhash are also network-byte-order integers. They are hash values for the MessageID and In-ReplyTo/References headers, with a special bit to flag duplicate references. In general, they should be ignored by the client, as they are used only by the messageserver in constructing and maintaining the CHAIN field. They are included in the visible Snapshot structure only as an extreme convenience to the messageserver, not as good software engineering practice. Clients should leave them alone. \section{1.3 Message Server Routines Available to Clients} There are approximately forty message server routines that may be called via RPC from the client program. Some of these are intended to be called frequently by application programs, while others are intended primarily for the use of the CUI library; in general, application programs should call CUI library routines instead of MS routines in several cases, as there are extra things going on there involving caching and abstractions of context. In the discussion below, the message server calls have been separated into seven categories. These are for the calls that relate to information about messages, calls that relate to information about message directories, calls that relate to mail delivery, calls that relate to remote file access, calls that relate to personal subscription/profile information, calls primarily for debugging purposes, and miscellaneous calls. \leftindent{\description{\italic{A note about convention}: For each parameter, I have appended a comment to indicate whether the parameter is a value passed in to the server, a result passed back, or something that has a value passed in which is modified and passed back. These are flagged by /* IN */, /* OUT */, and /* INOUT */, respectively.}} \description{\leftindent{\italic{A note about return codes}: All message server routines return zero upon successfull completion. If an error occurs, they will return a non-zero long integer error code, which actually consists of four separate error-encoding bytes packed together via macros defined in the include file mserrno.h. These can be pulled apart with other macros to obtain four separate error codes: \indent{\bold{AMS_ERRNO}: The actual error code. This will be either a value from the standard unix errno.h include file, or from the extended set of errors with prefix "EMS" in mserrno.h. These constants may be mapped on to short explanatory strings using the standard UNIX libarry's character array sys_errlist[], or, if the values are greater than or equal to EMSBASE and less than or equal to EMSLASTERROR, in the character array ms_errlist[]. \bold{AMS_ERRCAUSE}: The local context in which the error occurred, typically a UNIX system call. These codes are defined by constants in mserrno.h prefixed by "EIN_", and may be mapped onto explanatory strings in the character array ms_errcauselist[] as long as they are less than or equal to EIN_LASTERRORLOCATION. \bold{AMS_ERRVIA}: The larger context in which the error occurred, typically a message server top-level routine. These codes are defined by constants in mserrno.h prefixed by "EVIA_", and may be mapped onto explanatory strings in the character array ms_errivalist[] as long as they are less than or equal to EVIA_LASTERROR. \bold{AMS_RPCERRNO}: The error code for errors in SNAP remote procedure calls. If AMS_RPCERRNO is non-zero, the other three error values are not trustworthy and should be ignored. These codes are defined by constants in mserrno.h prefixed by "RPC_", and may be mapped onto explanatory strings in the character array rpc_errlist[] as long as they are less than or equal to RPC_LASTERROR. } Each client program needs to provide a routine called ReportError, which decodes a message server error code and presents the error information to the user. For a better understanding of message server error codes, consult the ReportError routines for the cui or messages programs. By convention, all clients set the global variable "mserrcode" to the result of each message server call. That is, each message server call is performed by a statement of the form "mserrcode = MS_WHATEVER(...)". The error reporting routines assume that the mserrcode variable is relevant if the 'Decode' parameter is set -- see the CUI library documentation for details. }} \subsection{1.3.1 Calls that relate to information about messages} \typewriter{\smaller{\index{MS_HeadersSince}(FullDirName, datefield, ReturnBuf, MaxReturn, startbyte, numbytes, bytesleft) char *FullDirName, /* IN */ *datefield, /* IN */ *ReturnBuf; /* OUT */ int MaxReturn, /* IN */ startbyte, /* IN */ *numbytes, /* OUT */ *bytesleft; /* OUT */}} \leftindent{This routine, which properly should be called MS_SnapshotsSince, is used to retrieve a set of snapshots from the message server. Specifically, it is used to retrieve snapshots from the directory named with a full path name in the FullDirName parameter for which the ordering date is greater than the date specified in the datefield parameter. The datefield parameter is a six byte, null-terminated string encoding the UNIX date in base 64. The message server will pack snapshots into ReturnBuf, packing at most MaxReturn bytes. It will ignore an initial number of bytes specified in startbyte. Note that MaxReturn and startbyte should be multiples of AMS_SNAPSHOTSIZE, as defined in AMS.h. The message server will place the number of bytes that were actually packed in the numbytes parameter, and the number of bytes remaining beyond what was packed in the bytesleft parameter. This routine is intended to be called repeatedly, with increasing values for startbyte, until the returned bytesleft is zero.} \typewriter{\smaller{\index{MS_GetPartialBody}(DirName, id, Buf, BufLim, offset, remaining, ct) char *DirName, /* IN */ *id, /* IN */ *Buf; /* OUT */ int BufLim, /* IN */ offset, /* IN */ *remaining, /* OUT */ *ct; /* OUT */}} \leftindent{The CUI_GetPartialBody routine is preferred for client interfaces. This routine is used to get the body of a message from the server. The message is identified by a directory name (DirName) and an id (id). (The id was presumably obtained by the client via an earlier call to MS_HeadersSince, but clients need not maintain the entire snapshot in order to keep a "handle" on the message; if they keep the directory name and ID, they can retrieve any information they need regarding the message.) Part of the body (at most BufLim bytes) will be packed into the return buffer (Buf), starting at the specified byte position (offset). The server will place a count of the number of bytes returned in the ct parameter, and the number of bytes remaining after the portion returned in the remaining parameter.} \typewriter{\smaller{\index{MS_GetSnapshot}(dirname, id, SnapshotBuf) char *dirname, /* IN */ *id; /* IN */ char *SnapshotBuf; /* OUT */}} \leftindent{The CUI_GetSnapshotFromCUID call is preferred for client interfaces. This routine takes a directory name and id and returns the complete snapshot. SnapshotBuf should be big enough to hold a snapshot, as specified in AMS_SNAPSHOTSIZE in AMS.h.} \smaller{\typewriter{\index{MS_GetNthSnapshot}(DirName, n, SnapshotBuf) char *DirName, /* IN */ *SnapshotBuf; /* OUT */ int n; /* IN */}} \leftindent{This call will get a particular snapshot from the message server; specifically, it will get the n\superscript{th} snapshot in the named directory. SnapshotBuf should be at least as big as AMS_SNAPSHOTSIZE. If N is -1, the last snapshot in the folder will be returned.} \smaller{\typewriter{\index{MS_GetHeaderContents}(dirname, id, HeaderName, HeaderTypeNumber, HeaderBuf, lim) char *dirname, /* IN */ *id, /* IN */ *HeaderName; /* IN */ char *HeaderBuf; /* OUT */ int HeaderTypeNumber, /* IN */ lim; /* }}IN */ \leftindent{The CUI_GetHeaderContents routine is preferred for client interfaces. This routine allows the client program to take advantage of the message parsing routines built into the message server. It causes the server to read in the message specified by dirname and id, parse it, and return the contents of a specified header. The header to be sought should be either specified by name in HeaderName or by number in HeaderTypeNumber. (The legal values for HeaderTypeNumber are specified in the include file AMSHEADPARSE.h.) It is somewhat faster to search by header number. If you are searching by HeaderName, then HeaderTypeNumber should be less than zero. The server will pack the contents of the header, up to lim bytes, in Headerbuf. MS_HeaderContents exists largely for historical reasons; its use is discouraged, as clients are perfectly capable of parsing messages themselves. MS_HeaderContents may be phased out in a future version of the system.} \typewriter{\smaller{\index{MS_AlterSnapshot}(dirname, id, NewSnapshot, Code) char *dirname, *id, *NewSnapshot; int Code;}} \leftindent{In general, this routine should not be used by clients; use CUI_AlterSnapshot instead. This routine is the basic engine for changing existing entries in a message directory. It can be used to change any part of the snapshot of a message. The message, as usual, is identified by dirname and id. A new value for the snapshot for that message is given in the NewSnapshot parameter. The way in which that new value is to be used is specified by the Code parameter, which should be one of the following constants defined in AMS.h: \leftindent{\bold{ASS_REPLACE_ALL}: The snapshot is simply replaced by the new snapshot. \bold{ASS_REPLACE_ATTRIBUTES}: The attributes are replaced by the attributes in the new snapshot, but everything else is left unchanged. \bold{ASS_REPLACE_ATT_CAPT}: The attributes AND caption fields are replaced by those in the new snapshot, and everything else is left unchanged. \bold{ASS_OR_ATTRIBUTES}: The attributes in the two snapshots are OR'ed together, with everything else left unchanged. (This is used, for example, to mark a message as deleted.) \bold{ASS_AND_ATTRIBUTES}: The attributes in the two snapshots are AND'ed together, with everything else left unchanged. (This is used, for example, to mark a message as undeleted.)} Note that the AMS_DATE field will NEVER be altered by this call.} \typewriter{\smaller{\index{MS_CloneMessage}(SourceDirName, id, DestDirName, Code) char *SourceDirName, /* IN */ *id, /* IN */ *DestDirName; /* IN */ int Code; /* IN */}} \leftindent{CUI_CloneMessage is preferrred over MS_CloneMessage for client interfaces. This routine makes a copy of a message. The message that currently exists in the directory SourceDirName, with the specified id, is copied into the directory DestDirName. The semantics of the operation depend on the value of the Code variable: \leftindent{\bold{MS_CLONE_COPY}: The message is simply copied to the new directory. \bold{MS_CLONE_COPYDEL}: The message is copied, and marked for deletion in the old directory. \bold{MS_CLONE_APPEND}: The message is copied to the new directory and the date field is changed to position the message at the end of that directory (the date is set to the current time or greater). \bold{MS_CLONE_APPENDDEL}: The message is appended as in MS_CLONE_APPEND, and marked for deletion in the old directory. \bold{MS_CLONE_SYMLINK}: (NOT YET IMPLEMENTED) The message is created in the new directory with its body a symbolic link to the body in the old directory. \bold{ MS_CLONE_MOVE}: (NOT YET IMPLEMENTED) The message is moved from the old directory to the new one, effectively deleting and purging it from the old one. }} \smaller{\typewriter{long \index{MS_EditMessage} (dirname, id, NewBodyFile, Reparse) char *dirname, /* IN */ *id, /* IN */ *NewBodyFile; /* IN */ int Reparse; /* IN */}} \leftindent{This routine is used to change the contents of a message. The body of the message identified by dirname and id is replaced by the contents of the file NewBodyFile. If the integer Reparse is nonzero, then the body file is reparsed and the snapshot is rebuilt accordingly. However, the AMS_DATE field will NEVER be altered by this call.} \typewriter{\smaller{\index{MS_PrintMessage}(DirName, id, flags, printer) char *DirName, /* IN */ *id, /* IN */ *printer; int flags; /* IN */}} \leftindent{The CUI_PrintBodyFromCUID routine is preferred for client interfaces. This routine queues the message identified by DirName and id for printing. If GoFast is non-zero, the printing will not take place immediately, but will instead take place the next time the message server updates its state. (The server updates its state after a minute of inactivity; in single-process non-SNAP versions, the state updates typically happen at regular intervals, regardless of activity.) The printing may also take place sooner if the number of calls to MS_PrintMessage exceeds the size of the message server's printing queue. The flags value is a bit vector that can be used to specify certain printing options, to wit: \leftindent{\bold{AMS_PRINT_FIXED} -- Print the body in a fixed-width font \bold{AMS_PRINT_ROT13} -- Print the body using the netnews Rot13 simple decryption scheme.} The printer value is the name of a printer to print on. If it is null, the default printer will be used. The printer name is validated by the messageserver, to prevent confusing and persistent errors later (since the message server maintains, in effect, its own print queue). You can use the MS_PrintMessage call to JUST validate a printer name by passing in null values for DirName and id; in this case, if the printer is good, you will get EINVAL returned as AMS_ERRNO, whereas if it is bad, you will get EMSBADPRINTER. (Sites can use the AndrewSetup file to customize the algorithm by which printer names are validated.)} \smaller{\typewriter{\index{MS_PurgeDeletedMessages}(dirname) char *dirname; /* IN */}} \leftindent{This routine simply purges the named directory of all messages marked with the "deleted" attribute.} \typewriter{\smaller{\index{MS_Epoch}(dirname, date64) char *dirname; /* IN */ char *date64; /* IN */}} \leftindent{This routine deletes all messages from a message directory \italic{and all its subdirectories} whose date field is less than the date given in base 64 as date64. It is intended primarily for use in bboard purging. } \subsection{1.3.2 Calls that relate to information about message directories} \smaller{\typewriter{\index{MS_CreateNewMessageDirectory}(DirName, Overwrite, BodyDirName) char *DirName; /* IN */ int Overwrite; /* IN */ char *BodyDirName; /* IN */}} \leftindent{The CUI_CreateNewMessageDirectory routine is preferred for client interfaces. This routine creates a new message directory, using the path name given in DirName. If Overwrite is non-zero, the call will NOT return an error if the directory already exists, but will zero the directory file. Typically, BodyDirName should be the same as DirName; if it is not, then all message bodies for the directory will be assumed to live elsewhere, in the directory BodyDirName. The feature whereby bodies can live elsewhere has not been extensively tested.} \typewriter{\smaller{\index{MS_ReconstructDirectory}(DirName, NumGood, NumBad, TrustTimeStamp) char *DirName; /* IN */ int *NumGood, /* OUT */ *NumBad, /* OUT */ TrustTimeStamp; /* IN */}} \leftindent{This routine reconstructs the directory file for the message directory DirName, and is typically needed only if that file has become corrupted, an extremely rare event. If TrustTimeStamp is non-zero, then the timestamp on the body files will be used for the date field; otherwise, the date header from the message itself will be parsed and used. The routine places the number of files that were successfully parsed and entered in the directory file in the NumGood variable, and the number of failures in NumBad. Typically, NumBad should be zero, but an extremely mis-formatted file in the directory itself, as well as transient errors such as the file system going down, can cause NumBad to be non-zero. Typically the message server will print some error messages to the console if some files can not be dealt with properly during reconstruction.} \smaller{\typewriter{\index{MS_ScavengeDirectory}((DirName, Recurse, numgood, numbad, quiet, Purge) char *DirName; /* IN */ int Recurse, /* IN */ int *numgood, /* OUT */ int *numbad /* OUT */ int quiet, Purge; /* BOTH IN */}} \leftindent{This procedure will scavenge the named directory, looking for any mismatches between the actual message bodies in the directory and the entries in the index file .MS_MsgDir. If Recurse is non-zero, it will do the same thing recursively for all subdirectories. If quiet is zero, it will print out a lot of informative junk a long the way (although in the case of a remote messageserver, these messages will go to the console of that machine). If Purge is non-zero, each directory will be purged after it is scavenged. The number of directories successfully scavenged will be returned in numgood, while the number that could not be scavenged will be returned in numbad.} \smaller{\typewriter{long \index{MS_MergeDirectories} (SourceDirName, DestDirName) char *SourceDirName, /* IN */ *DestDirName; /* IN */}} \leftindent{This routine will merge the directory SourceDirName into the directory DestDirName. SourceDirName will cease to exist, and DestDirName will contain the union of the two old directories. Clients should use CUI_MergeDirectories rather than MS_MergeDirectories.} \typewriter{\smaller{long \index{MS_GetDirInfo} (DirName, ProtCode, MsgCount) char *DirName; /* IN */ int *ProtCode, /* OUT */ *MsgCount; /* OUT */}} \leftindent{This routine returns information about the named directory. The number of messages in the directory is returned in MsgCount, and the protection status of that directory for the current user is returned in ProtCode as one of the following codes, defined in AMS.h: \leftindent{\bold{AMS_DIRPROT_READ}: The user has read-only access, and the directory is neither a local, external, nor official bboard. \bold{AMS_DIRPROT_LOCALBB}: The user has read-only access, and the directory is in the "LOCAL" domain, as referenced by $LOCAL in the mspath and as defined in the site configuration source file siteconfig.c. Note that this value will not be returned for elements in this domain if the user has extra (e.g. administrative) rights. \bold{AMS_DIRPROT_OFFBB}: The user has read-only access, and the directory is in the $OFFICIAL domain, as defined previously for $LOCAL. \bold{AMS_DIRPROT_EXTBB}: The user has read-only access, and the directory is in the $EXTERNAL domain, as defined previously for $LOCAL. \bold{AMS_DIRPROT_MODIFY}: The user has read and write access. \bold{AMS_DIRPROT_MBOX}: The user has read and write access, and may also process incoming mail from the associated Mailbox. \bold{AMS_DIRPROT_FULLMAIL}: The user has read and write access, and may also process incoming mail from the associated Mailbox, and it is one of his private mail directories. \bold{AMS_DIRPROT_AWFUL}: The user has no access, or the combination of access rights on the various relevant directories is horribly muddled.}} \smaller{\typewriter{long \index{MS_RemoveDirectory} (DirName, MaxRemovals) char *DirName; /* IN */ int MaxRemovals; /* IN */}} \leftindent{This routine deletes the message directory DirName and all its contents. It will not remove anything, however, if the directory has sub-directories, or if the number of messages in the directory is greater than MaxRemovals. (This latter check helps prevent people from deleting a directory they believe is empty moments after someone else has added something to it.)} \typewriter{\smaller{long \index{MS_CheckMissingFolder}(oldname, newname) char *oldname; /* IN */ char *newname; /* out */}} \leftindent{This routine will check to see if the folder named by oldname, which presumably no longer exists (AMS_ERRNO was ENOENT), has been replaced by another folder in the system's ChangedSubscriptions file. If so, the new name will be placed in newname; otherwise, newname will be returned as the null string.} \typewriter{\smaller{long \index{MS_RenameDir}(OldName, NewName, NewFullName) char *OldName, /* IN */ *NewName, /* IN */ *NewFullName; /* OUT */}} \leftindent{This routine renames a directory. In the current implementation, the directory must have no children. The OldName is the full pathname of the existing directory. NewName is a shorthand for what it is being renamed to. NewFullName is the new full path name of the directory. Thus for example, if you call it with OldName "/foo/bar/baz" and NewName "hello", NewFullName will be returned as "/foo/bar/hello".} \typewriter{\smaller{\index{MS_InstallWelcomeMessage}(ParentName, InitDir, InitFile, ShortName) char *ParentName, /* IN */ *InitDir, /* IN */ *InitFile, /* IN */ *ShortName; /* IN */}} \leftindent{This routine is intended to be called immediately after a directory is created, and is used to install an initial message on a new directory and its parent directory, if it has one. The message installed in the parent directory will have the "new directory" attribute set, and an appropriate X-Andrew-DirectoryCreation header in the body, so that subscribers to the parent directory will automatically be asked if they want to subscribe to the new child. If InitDir is non-null, then the new message will be created by copying an old message. That old message will be found in the directory InitDir, with id InitFile. If InitDir is null, then InitFIle must be the full path name of an RFC822 message which will be used as the text of the welcome message. The ParentDir is the name of the parent directory, while ShortName is the name of the subdirectory within the parent directory (\italic{not} the full path name, simply the last element of the name of the new directory).} \typewriter{\smaller{\index{MS_MatchFolderName}(pat, fname) char *pat, /* IN */ *fname; /* OUT */ }}\leftindent{This routine is called to get a list of folder names matching a given pattern. Currently, the pattern is simply a prefix, and you will thus get a list of all folder names starting with the string given as pat. The list is written out, one folder name to a line, in short (non-canonical) form, in a temporary file, the name of which is returned in fname.} \subsection{1.3.3 Calls that relate to mail delivery} \typewriter{\smaller{\index{MS_NameReplyFile}(DirName, id, code, FileName) char *DirName, /* IN */ *id, /* IN */ *FileName; /* OUT */ int code; /* IN */}} \leftindent{Clients should not call this, but should call CUI_NameReplyFile instead. This routine will cause the message server to build a template for a new piece of outgoing mail. That template will contain entries for standard headers such as To: and CC:, some of which may be filled in. The mail is typically generated in response to an existing message, identified by DirName and id. The template is written out to a file by the message server, which returns the name of the file to the client in FileName. The precise contents of the file are determined by the code value, which should be one of the following values defined in AMS.h: \leftindent{\bold{AMS_REPLY_FRESH}: The DirName and id are ignored, and a template for a fresh piece of mail is generated. This is typically not necessary, but is included for completeness to simplify some conceivable mail generation algorithms. \bold{AMS_REPLY_SENDER}: The mail is generated as a reply to the sender of the original message. \bold{AMS_REPLY_WIDE}: The mail is generated as a reply to the recipients of the original message. (This is typically the To, CC, and Resent-To lines, but may be overridden by the X-Andrew-WideReply header.) \bold{AMS_REPLY_WIDER}: The mail is generated as a reply to both the sender and recipients of the original message. \bold{AMS_REPLY_FORWARD}: The mail is generated as an attempt to forward the original message; all that is filled in initially is the subject header and the body. If the message being forwarded was in Andrew Toolkit (BE2) format, that formatting is stripped out. \bold{AMS_REPLY_FORWARD_FMT}: Same as AMS_REPLY_FORWARD, except that BE2 formatting is preserved; this should only be used by interfaces that understand the BE2 datastream. \bold{AMS_REPLY_REDRAFT}: The mail is considered to be a draft message which is now to be considered again for sending. Several headers and the body are filled in.}} \smaller{\typewriter{\index{MS_ValidateAndReplaceChunk}(FileName, inaddr, outaddr, outaddrsize, which, outcode)}} \leftindent{This routine is a "worker" routine that, unfortunately, could not be made entirely internal to the message server. It is intended to be used ONLY by the CUI_RewriteHeaderLine function. Rather than document its extremely bizarre semantics, I will here only encourage programmers to use the CUI_RewriteHeaderLine routine instead. Note that the ugliness of MS_ValidateAndReplaceChunk is calculated and was done knowingly; there were serious tradeoffs between what we wanted to do on the client and server ends. Thus this is probably a permanent piece of the architecture, just an ugly one. Use the CUI library call. } \typewriter{\smaller{\index{MS_WriteAllMatchesToFile}(ambigname, filename) char *ambigname; /* IN */ char *filename; /* OUT */}} \leftindent{This routine takes a mail address and writes all possible matches to it in a file. This is also intended for use ONLY by the CUI_RewriteHeaderLine call.} \typewriter{\smaller{\index{MS_SubmitMessage}(FileName, DeliveryOptions, ErrorMessage, ErrMsgLimit, ClientProgram) char *FileName, /* IN */ *ErrorMessage,/* OUT */ *ClientProgram; /* IN */ int BlindStatus, /* IN */ ErrMsgLimit; /* IN */}} \leftindent{Interfaces should use CUI_SubmitMessage instead of MS_SubmitMessage. This routine causes the message server to delivery mail that has been composed by the client and stored as a file accessible to the server (presumably using MS_StorePartialFile). The client should have already validated the recipients in the To and CC headers using MS_RewriteHeader or CUI_RewriteHeaderLine. The message server will deliver the mail to the addresses listed in the To and CC headers. The mail is read from the file FileName, which will be deleted if delivery is successful. Certain delivery failures will cause an additional error code to be written into returncode; this is the code returned by the qclose (like pclose) on the delivery process, and may be susceptible to further analysis. The value DeliveryOptions tells the server several things about the delivery, e.g. whether or not to keep a blind copy. It should be an OR-ing of bits defined in AMS.h: \leftindent{\bold{AMS_SEND_BLINDYES} -- Keep a blind copy. \bold{AMS_SEND_BLINDNO} -- Do not keep a blind copy. \bold{AMS_SEND_ISRESEND} -- Write "ReSent-From" instead of "From", etc. \bold{AMS_SEND_ILLEGAL} -- Don't complain about non-Ascii bytes or long lines \bold{AMS_SEND_UNFORMATTED} -- Strip out any Andrew Toolkit (BE2) formatting before sending } The blind copy will be sent to the user through the mail unless the "bccto" option is used, in which case it will be appended directly to an appropriate message directory. Messages from the delivery system will be placed in the ErrorMessage buffer when one of the EMSDROPOFF codes is returned; some of these indicate errors, others exceptional conditions that are worth noting, even though mail delivery succeeded anyway. The ClientProgram variable should be the name and version number of the client interface. Anything other than letters and digits in this string will be converted to dots to ensure compliance with RFC822 requirements for Received headers.} \subsection{1.3.4 Calls that relate to remote file access} \smaller{\typewriter{\index{MS_DisambiguateFile}(source, target, AccessCode) char *source, /* IN */ *target; /* OUT */ short AccessCode; /* IN */}} \leftindent{This routine is used to resolve a file name (source) that the user has typed and to return a valid full path name (target). The resolution involves the interpretation of tilde-prefixes, and a search path down the user's mspath. This is the routine that can turn "andrew/gripes" into "/cmu/itc/bb/.MESSAGES/andrew/gripes". Note that the conversion of "andrew.gripes" to "andrew/gripes" must still be performed by the interface program. AccessCode should be one of four values, defined in AMS.h. If it is AMS_DISAMB_EXISTS, then any matching file name is satisfactory. If it is AMS_DISAMB_DIREXISTS, it must be the name of a valid message directory. If it is AMS_DISAMB_FILEEXISTS, it must be the name of an existing file. If it is AMS_DISAMB_FILEMAYBECREATED, it must be the name of a file which at least has an existing parent. (It does NOT check to make sure that the file may be created by the current user.) In general, client programs should \italic{not ever} call MS_Disambiguate file with AccessCode == AMS_DISAMB_DIREXISTS. If that is what you want to do, you should call the CUI library routine CUI_DisambiguateDir, which caches all directory information to avoid repetitive calls to the server.} \typewriter{\smaller{\index{MS_GetPartialFile}(FileName, Buf, BufLim, offset, remaining, ct) char *FileName, /* IN */ *Buf; /* OUT */ int BufLim, /* IN */ offset, /* IN */ *remaining, /* OUT */ *ct; /*OUT */}} \leftindent{This routine allows the client to retrieve a file from the server, even if the client is not on Vice or the file is on the server's local disk. The File is named as FileName, and a portion of it is returned in Buf. The portion begins at position offset in the file and continues for up to BufLim bytes. The server returns a count of the bytes returned in the ct variable, and the number of bytes remaining until the end of the file in the remaining variable. The intent is for the client to call this routine repeatedly, with increasing values for offset, until the return value of remaining is 0.} \smaller{\typewriter{\index{MS_StorePartialFile}(FileName, startpos, len, mode, Truncate, WhatToStore) char *FileName, /* IN */ *WhatToStore; /* IN */ int startpos, /* IN */ len, /* IN */ mode, /* IN */ Truncate; /* IN */}} \leftindent{This routine is the inverse of MS_GetPartialFile, and is used to cause the server to store a file. The file will be stored under the name given as FileName, and the server will write len bytes from the buffer WhatToStore after doing an lseek to position startpos. The file will be opened with protection mode (standard UNIX protection codes), and will be truncated after the write if the Truncate parameter is nonzero.} \typewriter{\smaller{long MS_UnlinkFile (FileName) char *FileName; /* IN */}} \leftindent{This routine will cause the server to unlink (delete) the named file. } \smaller{\typewriter{\index{MS_WriteUnscribedBodyFile}(DirName, id, FileName) char *DirName, /* IN */ *id, /* IN */ *FileName; /* OUT */}} \leftindent{This routine takes the message identified by DirName and id, runs it through the appropriate routines to strip out multi-media formatting, and writes the result in a temporary file, the name of which is returned in FileName. When you're done with the file, you should delete it with MS_UnlinkFile.} \subsection{1.3.5 Calls that relate to personal subscription/profile information} \smaller{\typewriter{\index{MS_GetSearchPathEntry}(which, buf, lim) int which, /* IN */ lim; /* IN */ char *buf; /* OUT */}} \leftindent{This routine is used to retrieve path names from the user's mspath, the search path used for finding message directories. The which parameter is an integer that tells which entry is of interest; 0 is the first entry, and so on. The routine will return an error code with AMS_ERRNO set to ERANGE if which is out of range. Otherwise it will copy the path name into buf, up to lim bytes. The which parameter may also take on a negative value -- these are defined in AMS.h as AMS_MAILPATH, AMS_LOCALPATH, AMS_EXTERNALPATH, and AMS_OFFICIALPATH, and are used to access portions of the mspath by their meaning rather than by their order.} \typewriter{\smaller{\index{MS_FindMailbox}(pathelt, Buf) int pathelt; /* IN */ char *Buf; /* OUT */}} \leftindent{This routine takes an integer which is an index into the user's mspath list and returns the name of the associated mailbox, if any, from which new messages should be read. It will return an error code if the user does not have the right to read files from the mailbox, or if the user's mspath preference has not marked this path element as having a mailbox worth checking.} \smaller{\typewriter{\index{MS_NameSubscriptionMapFile}(Root, MapFile) char *Root; /* IN */ char *MapFile; /* }}OUT */ \leftindent{This routine takes a pathname Root, which should be the full path name of the root of message directory tree (a .MESSAGES directory), and will build a file that encodes the subscription status of all messages within that directory for the current user. The name of that file is then returned as MapFile. The format of the subscription map file is simply a series of lines, each of which contains a message directory name followed by a space and an integer. The integer is one of the valid subscription statuses defined in AMS.h, such as AMS_UNSUBSCRIBED, AMS_ASKSUBSCRIBED, etc. If the "Root" parameter is NULL, then the map is built for all things the current user subscribes to, and nothing else; this is a reasonably fast operation, since that information is typically already in the server's memory.} \typewriter{\smaller{\index{MS_NameChangedMapFile}(MapFile, MailOnly, ListAll, NumChanged, NumUnavailable, NumMissingFolders, NumSlowpokes, NumFastFellas) char *MapFile; /* out */ int MailOnly, /* in */ ListAll, /* in */ NumChanged, /* out */ NumUnavailable, /* out */ NumMissingFolders, /* out */ NumSlowpokes, /* out */ NumFastFellas; /* out */}} \leftindent{This is just like the MS_NameSubscriptionMap call, except that the file it builds contains only those folders to which you are subscribed that actually have new messages. Also, there is an extra integer at the end of each line, to be described in a moment. The input parameter MailOnly tells this call to only look at mail folders. The ListAll parameter tells it to list even those things you are subscribed to that do NOT have new messages. However, the last thing on each line in the file is a Boolean integer which is zero if there is nothing new and the line was included only because ListAll was non-zero. The return values are the MapFile name and a number of counters that detail how well the search worked out. NumChanged is the number of folders which need to be looked at. NumUnavailable is the number that could not be checked due to Vice or network errors. NumMissingFolders is the number of things on the subscription list that no longer exist (these are always included in the mapfile, so that the interface will itself be able to discover their non-existence and take appropriate action, namely calling CUI_HandleMissingFolder). Finally, NumSlowpokes and NumFastFellas tell how many of the folders could be checked quickly (via the master update file mechanism) and how many required the slower check of actually opening the folder.} \typewriter{\smaller{\index{MS_SetSubscriptionEntry}(FullName, NickName, status) char *FullName; /* IN */ char *NickName; /* IN */ int status; /* IN */}} \leftindent{This routine alters the user's subscription status for the directory named as FullName. It sets the nickname (the name the user will see during subscription updating) and the subscription status (as defined in AMS.h). ** CLIENT ROUTINES SHOULD USE CUI_SetSubscriptionEntry instead. **} \smaller{\typewriter{\index{MS_GetSubscriptionEntry}(FullName, NickName, status) char *FullName; /* IN */ char *NickName; /* OUT */ int *status; /* OUT */ }} \leftindent{This routine retrieves information about the user's subscription status for the directory FullName. It returns the directory's nickname, and the status, as defined in AMS.h} \typewriter{\smaller{\index{MS_GetNextSubsEntry}(FullName, NickName, status) char *FullName; /* INOUT */ char *NickName; /* OUT */ int *status; /* OUT */ }} \leftindent{This routine is just like MS_GetSubscriptionEntry, except that it retrieves information about the succeeding subscription entry. If FullName is the null string, it returns information about the first subscription entry, while otherwise it returns information about the succeeding subscription entry. If FullName is the last subscription entry, it returns with FullName null.} \smaller{\typewriter{\index{MS_RebuildSubscriptionMaps}()}} \leftindent{This routine rebuilds the subscription map files for every element on the user's mspath to which he has write access. This routine is called by the CUI rebuild command, and should never be necessary since the release of version 3.1 of the messages program (3.11 of CUI).} \typewriter{\smaller{\index{MS_RebuildMasterUpdateFiles}(NumFastGood, NumSlowGood, NumBad, NumAbsent, NumProbablyGood) int *NumFastGood, /* out */ *NumSlowGood, /* out */ *NumBad, /* out */ *NumProbablyGood, /* out */ *NumAbsent; /* out */ }}\leftindent{This routine rebuilds the master update files for every element of your mspath to which you have write access and in which a master update file already exists. The return values tell how many entries in that file were good; the "Fast" and "Slow" refer simply to how easily it good be determined that those entries were good. NumBad is a count of bogus entries in the master update file; these should be very rare, and correspond to Vice going down at just the wrong moment. NumAbsent is the number of lines that had to be added to the master update file because there was no corresponding line there before. NumProbablyGood is a count of the number of entries that looked bad (and used to be counted in NumBad) but reflect changes less than 15 minutes old. Such entries probably would have been picked up soon by the normal mechanism, and hence were not really "bad", merely symptomatic of a sort of race condition in the checking.} \typewriter{\smaller{\index{MS_RebuildOneMasterUpdateFile}(PathElt, NumFastGood, NumSlowGood, NumBad, NumAbsent, NumProbablyGood) char *PathElt; /* IN */ int *NumFastGood, *NumSlowGood, *NumBad, *NumAbsent, *NumProbablyGood; /* ALL OUT */ }}\leftindent{This routine is just like the previous one, except that it only rebuilds the master update file for a single element of your mspath, named in the PathElt argument.} \typewriter{\smaller{\index{MS_SetAssociatedTime}(FullName, newvalue) char *FullName, /* IN */ *newvalue; /* IN */}} \leftindent{This routine sets the user's profiling information to note that the last element the user has seen in the directory FullName was time-stamped with the base 64-encoded time newvalue. This is the information that is used in checking for new messages; typically, the newvalue is the AMS_DATE of the snapshot of the last message seen.} \smaller{\typewriter{\index{MS_GetAssociatedTime}(FullName, Answer, lim) char *FullName, /* IN */ *Answer; /* OUT */ int lim; /* IN */}} \leftindent{This routine retrieves the user's profiling information, specifically the date field of the last message seen on the directory FullName. The base 64 date is stored in Answer, up to lim bytes. (The lim parameter is probably silly; the size of a date is defined as AMS_DATESIZE anyway.)} \subsection{1.3.6 Calls That Relate To User-Defined Attributes} As usual, it is likely that the client will want to use the CUI_ library calls, which provide more suitable abstractions. \typewriter{\smaller{\index{MS_GetDirAttributes}(Dirname, AttrCt, Attrs, SepChar, ShowEmpty) char *Dirname; /* IN */ int *AttrCt; /* OUT */ char *Attrs; /* OUT */ int SepChar, ShowEmpty; /* IN */}} \leftindent{This routine is used by the client to get the names of all the attributes in a folder. The folder is named as Dirname. The Attrs buffer is used to return the names of all the attributes defined in that folder, separated by the character passed in as SepChar. (The Attrs buffer should be big enough to hold all possible attribute names, i.e. AMS_NUM_UATTRS * AMS_ATTRNAMEMAX.) The number of attributes defined are returned as AttrCt. Finally, ShowEmpty is a flag passed in that, if nonzero, tells the messageserver to include the phrase defined as UNUSEDATTRNAME (again, in AMS.h) everywhere that an unused attribute appears as a "place holder". To make sense of this, imagine that you first created an attribute called "foo", and then one called "bar", and then deleted the "foo" attribute. Now, the "bar" attribute happens to remain attribute #2, even though the total number of defined attributes is only 1. If ShowEmpty is non zero, then the UNUSEDATTRNAME will preced the "bar" name, making it possible to map names to numbers. If ShowEmpty is zero, such unused attributes are skipped, and the list is useful only, for example, for telling the user what attribute exists. Most of this is hidden behind CUI library routines, if you want to avoid understanding it.} \typewriter{\smaller{\index{MS_AddAttribute}(Dirname, Newname, AttNum) char *Dirname, *Newname; /* both IN */ int *AttNum; /* OUT */}} \leftindent{This routine can be used to add a new attribute to a folder. The folder is named as Dirname, and the attribute is named as Newname; the messageserver returns the attribute number assigned to the new attribute. Likely errors include ERANGE, if there are too many attributes in the folder to define a new one, and EMSATTREXISTS, when an attribute with that name already exists.} \typewriter{\smaller{\index{MS_DeleteAttr}(DirName, AttrName) char *DirName, *AttrName; /* BOTH IN */} }\leftindent{This routine can be used to delete an existing attribute in a folder. The folder name and attribute name are the two input parameters.} \subsection{1.3.7 Calls primarily for debugging purposes} \typewriter{\smaller{\index{MS_GetVersion}(Buf, lim) char *Buf; /* OUT */ int lim; /* IN */}} \leftindent{This routine packs a string that defines the message server version into the buffer Buf, up to lim bytes.} \smaller{\typewriter{\index{MS_DebugMode}(level, snap, malloc) int level, /* IN */ snap, /* IN */ malloc; /* IN */}} \leftindent{This routine sets the message server debugging values. level is the debug level for the actual ms code; it is a bit map, defined in MS.h. snap is the SNAP debug mask, as defined in the SNAP code. malloc is the CheckLevel for the ITC malloc, as defined in the malloc documentation.} By default, message server debugging will show up in the console. This is not what you want. You want to use the following routine: \typewriter{\smaller{\index{MS_OpenDebuggingPipescript}(DoIt) int DoIt; /* IN */ }} \leftindent{This routine causes the message server's debugging output to be redirected to a new pipescript process if DoIt is nonzero, or reset to where it used to be if DoIt is zero. } \smaller{\typewriter{\index{MS_Die}()}} \leftindent{This routine kills the message server. The CUI library will probably try to reconnect you automatically the next time you try to do anything else of interest. Nonetheless, its always fun.} \subsection{1.3.8 Miscellaneous calls} \typewriter{\smaller{\index{MS_GetConfigurationParameters} (MailDomain, len, UseAmsDelivery, UseNameSep, DeliveryType) int *UseAmsDelivery, /* OUT */ *UseNameSep, /* OUT */ *DeliveryType, /* OUT */ len; /* IN */ char *MailDomain; /* OUT */ }}\leftindent{This routine allows the client to get various configuration information from the messageserver. In particular, the MailDomain is the host to give in the return address for outgoing mail (not generally needed by clients, but occasionally relevant). It will be truncated to the buffer length specified as len. UseAmsDelivery is a ternary value specifying whether MailDomain uses the AMS mail delivery system: 0 means the answer is not known, -1 means that MailDomain does not use the AMS mail delivery system, and a value greater than 0 means that MailDomain indeed uses the AMS mail delivery system. If MailDomain runs the AMS delivery system, the value of UseNameSep describes how MailDomain prefers that its return addresses be composed. A value for UseNameSep less than 0 means that return addresses are to be in the userid+@MailDomain form; a value of 0 means that it is unknown how MailDomain formats its return addresses (but the userid+ form is always safe); and a value greater than 0 is an ascii value of a separator character to be used instead of the spaces in the user's full name (e.g., a pw_gecos field). The values for DeliveryType are constants with names beginning with defined in the $ANDREWDIR/include/dropoff.h file. These values describe how the message delivery system is going to work, with -1 (DT_UNK) meaning it is unknown, 0 (DT_AMS) meaning normal AMS dropoff, and values greater than 0 (DT_CANNOT, DT_NONAMS, ...) meaning some kind of restricted dropoff due to an unusual intercellular configuration.} \typewriter{\smaller{ \index{MS_AndrewDir} (AndrewDir, len) char *AndrewDir; /* OUT */ int len; /* IN */ }}\leftindent{This routine returns at most len characters indicating the directory where all andrew software is rooted, typically but not necessarily "/usr/andrew".} \typewriter{\smaller{\index{MS_GenTempFileName}(Buf) char *Buf; /* OUT */ }}\leftindent{This routine generates a temporary file name "guaranteed" to be world-unique (at least on the server end...) The guarantee is weaker on System V or other sites that configure the file name limit to 14 characters.} \typewriter{\smaller{\index{MS_ProcessNewMessages}(SourceDir, NumGood, NumBad, NumLocks, ParseSpecFile, resultcode, FirstError, Buf, buflim) char *SourceDir, /* IN */ *ParseSpecFile, /* IN */ *Buf; /* OUT */ int *NumGood, /* OUT */ *NumBad, /* OUT */ *NumLocks, /* OUT */ *resultcode, /* OUT */ *FirstError, /* OUT */ buflim; /* IN */}} \leftindent{This routine reads new messages from the mailbox directory SourceDir and puts them into message directories. It returns five integer parameters: NumGood is the number of files read successfully from the mailbox, NumBad is the number of files that could not be read or posted properly and were hence left in the mailbox, and NumLocks is the number of files in the mailbox that were locked by another process (presumably a delivery process) and were less than 20 minutes old. (After 20 minutes the locks are overridden.) FirstError is the mserrcode from the first error; it contains more specific information about why the first of the errors occurred. In order to decide which directory to add new messages to, the server reads a program which is written in a special language and is found in the file ParseSpecFile. If the ParseSpecFile parameter is null, the server looks for a file called ".MS.spec" in the parent of the mailbox directory. If there is no such file, it simply adds messages to a directory which is named by doing the equivalent of SourceDir/../.MESSAGES/misc. The programming of Spec Files is a black art, and is documented separately. NOTE: As of mid-1988, the FLAMES language (for "Filtering Language for the Andrew MEssage System") has begun to supersede Spec Files. The server now looks first for a file called ".AMS.flames" before it looks for ".MS.spec". Since FLAMES is a scaled-down Lisp interpreter, it can have some pretty complex error messages; hence the buffer Buf which is passed in to this routine, along with its length, buflim. If and only if a Lisp error occurs while executing a FLAMES function, Buf will come back as something other than the empty string. Hopefully, this "something other" will be something useful. I wouldn't say that the programming of FLAMES files is a black art. It's gray at worst. However, it too is documented separately.} \typewriter{\smaller{\index{MS_AppendFileToFolder}(FileName, FolderName) char *FileName, *FolderName; /* BOTH IN */}} \leftindent{This routine takes the message that is stored in the named file and appends it as a new message onto the end of the named folder. If it succeeds, it then deletes the original file (to assure idempotence of the operation, naturally.) Obviously errors occur and are returned if the file is inaccessible or unparseable, or if the folder does not exist can not be opened for writing.} \typewriter{\smaller{\index{MS_CheckAuthentication}(Authenticated) int *Authenticated; /* OUT */}} \leftindent{This routine will set the integer Authenticated to be 1 if the server is properly authenticated (or if it is not on Vice at all), and 0 if their are authentication problems. It may also return errors, which are most likely to be RPC transmission errors or Vice/pioctl failures.} \smaller{\typewriter{\index{MS_UpdateState}()}} \leftindent{This routine causes the message server to update all of its state to the file system. This may include storing the .MS.subscriptions file, storing the .MS.profile file, storing open message directories (.MS_MsgDir files), printing messages that have been queued for printing, reaping "zombie" processes, and probably some other stuff besides. It is generally called as a cleanup message by a terminating client. However, the MS_FastUpdateState routine is better for keepalives.} \smaller{\typewriter{\index{MS_FastUpdateState}()}} \leftindent{This routine is just like MS_UpdateState, except it skips certain time-consuming and non-critical functions like printing. It is ideal for client "keepalive" or "checkpoint" messages.} \typewriter{\smaller{\index{MS_ReInitialize}()}} \leftindent{This causes the message server to re-read the user's preferences and to perform certain associated operations. It should be called by each client when he first connects to a message server, to ensure that any changes that the user has made to his preference file will take place, as he expects, when he runs a new program.} \smaller{\typewriter{\index{MS_ConvertOldMail}(good, bad) int *good, *bad; /* OUT */}} \leftindent{This routine will convert an old Maillib directory, used by the old ReadMail program, into messages format. It will NOT preserve ReadMail class information. A script that will aid in the conversion of ReadMail classes is available from the author; it should be used\italic{ instead} of the convert routine when class preservation is essential.} \typewriter{\smaller{\smaller{\bigger{\index{MS_TakeHints}(DoAll, ProtFailures) int DoAll, /* IN */ *ProtFailures; /* OUT */}}}} \leftindent{This routine will update the Master Update file for bboard directories by processing the HINT files that have been left. If DoAll is non-zero, it will pick up all hint files, otherwise it will try to ignore the hints left by servers on other machines. It returns a count of the number of hints that could not be taken, generally due to protection failures, in ProtFailures.} \typewriter{\smaller{\index{MS_PrefetchMessage}(DirName, id, GetNext) char *DirName, *id; /* IN */ int MailOnly; /* IN */}} \leftindent{On a Vice system, this call will tell venus to prefetch a message body file. The message is identified by the DirName and id. If the GetNext field is non-zero, then the message fetched will be the one AFTER the one named. If the message is the last one in a folder and GetNext is non-zero, the error code returned will be EINVAL for AMS_ERRNO. On a non-Vice system, this call is a no-op. If the id is null, then the .MS_MsgDir file (the directory file) will be pre-fetched.} \smaller{\typewriter{\index{MS_GetNewMessageCount}(FullDirName, numnew, numtotal, LastOldDate, InsistOnFetch) char *FullDirName, /* IN */ *LastOldDate; /* OUT */ int *numnew, /* OUT */ *numtotal, /* OUT */ InsistOnFetch; /* IN */}} \leftindent{This routine will check a directory for new messages. It will fill in the total number of messages and the number that are new to the current user in the numtotal and numnew variables. It will also fill in the date stamp of the last old message in the LastOldDate buffer; this buffer must be at least as big as AMS_DATESIZE. If InistOnFetch is zero, however, the above description is not quite accurate. In this case, the system will sometimes come up with a quick, short answer that there are no new messages. In this case, the LastOldDate and numtotal fields will not be filled in properly; numtotal will be -1 to indicate that this is the case.} \typewriter{\smaller{\index{MS_DoIHaveMail}(count) int *count; /* OUT */}} \leftindent{This routine returns in count the number of pieces of new mail in the user's mailbox.} \smaller{\typewriter{\index{MS_SetDeathKnell}(dk) int dk; /* IN */}} \leftindent{This routine sets the amount of time the message server will wait patiently with no activity before it quietly and willfully kills itself.} \typewriter{\smaller{\index{MS_ParseDate}(indate, year, month, day, hour, min, sec, wday, gtm) char *indate; /* IN */ int *year, *month, *day, *hour, *min, *sec, *wday; /* ALL OUT */ long *gtm; /* OUT */}} \leftindent{This routine parses the date in the indate string and returns its interpretation of the date, with the appropriate parts in the appropriate places. gtm is the time as expressed in UNIX gtime() or time(0) format. The date parser invoked here is extremely amazing, and you wouldn't want to have to port it to your client machine.} \typewriter{\smaller{\index{MS_HandlePreference}(prog, pref, InVal, OutVal, OutLim, opcode, resulti, defaulti)}} \leftindent{This routine is a worker routine for the CUI_GetProfileXXX and CUI_SetProfileString calls. You should not use it directly, but should call the CUI_ routines instead. } \typewriter{\smaller{\index{MS_SetCleanupZombies}(doit) int doit;}} \leftindent{This routine is a FAKE message server call. If you call it in the SNAPified version, an error message will be printed. However, it is useful in the non-SNAPified versions of programs that want to handle their own zombie processes. If doit is non-zero (the default), the messageserver will continue to clean up all zombie processes; if it is zero, such behavior will be disabled, and you'd better have your own process cleaning up zombies. If you don't know what Zombies are on UNIX, you should try not to learn unless you need to. However, if you start running out of processes, that might be your problem.} \begindata{bp,537558784} \enddata{bp,537558784} \view{bpv,537558784,1573,0,0} Copyright 1992 Carnegie Mellon University and IBM. All rights reserved. \smaller{\smaller{$Disclaimer: Permission to use, copy, modify, and distribute this software and its documentation for any purpose is hereby granted without fee, provided that the above copyright notice appear in all copies and that both that copyright notice, this permission notice, and the following disclaimer appear in supporting documentation, and that the names of IBM, Carnegie Mellon University, and other copyright holders, not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. IBM, CARNEGIE MELLON UNIVERSITY, AND THE OTHER COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL IBM, CARNEGIE MELLON UNIVERSITY, OR ANY OTHER COPYRIGHT HOLDER BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. $ }}\enddata{text,539630556}