\begindata{text,538945396}
\textdsversion{12}
\template{default}
\define{global
}
\chapter{1	The CUI Library}


\section{1.1	Introduction}


This paper describes the CUI library 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 overview document (AMS.ovr 
and MsgSrvr.ovr).  You will also need to consult the documentation for the 
message server interface (MsgSrvr.pgr).


 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}


The CUI library is a subroutine library to be shared by all programs that wish 
to talk to the message server and have access to the message database.  It 
includes the procedural interface to SNAP which makes message server calls 
look like normal subroutine calls.  It also includes a cache mechanism which 
makes many calls to the server unnecessary, and also provides a few 
"abstractions of context" which the message server, because of its 
connectionless nature, cannot provide.


The primary abstraction provided by the library is the notion of "cuid".  A 
cuid is simply an integer that the CUI library assigns to each message, which 
is guaranteed to be session-unique -- that is, the integer uniquely identifies 
the message for the duration of the current program run.  Client routines can 
then use the cuid as a "handle" for operations on that message via CUI library 
calls.


It should be noted that the CUI library is still conceptually incomplete. 
 Unlike the message server interface, which has been more carefully planned 
and implemented, the CUI library, and indeed the definition of the line 
between CUI library and client program, is still not very well defined.  Thus 
the set of procedures in the CUI library is likely to change dramatically in 
future releases.


\section{1.3	The Programmer Interface of the CUI Library}


The following variables and subroutines are provided as part of the CUI 
library.  In general, routines from the CUI library should be given preference 
over message server routines whenever it seems possible to do something with 
either one, as the CUI library routines may be able to avoid message server 
calls through the use of information in the CUI library cache.


\italic{A note on parameter conventions}:  All parameter declarations below 
are commented as either /* IN */, /* OUT */, or /* INOUT */, depending on 
whether the parameters are passed in to the library, retrieved from the 
library, or passed to the library, modified, and passed back.


\italic{A note on return values}:  Unless otherwise noted, routines in the CUI 
library return zero on successful completion, and an error code otherwise. 
 The error code is formatted as a message server error code, as documented in 
the message server interface documentation.


\subsection{1.3.1	CUI variables visible to the client program}


The cui maintains a few values which may be of interest to the interface 
program:


\typewriter{#define \index{CUI_MAJORVERSION} ...

#define \index{CUI_MINORVERSION} ...}

\leftindent{These are int constants (defined in CUI.h) that indicate the CUI 
version number.}


\typewriter{int \index{CUI_CuidsInUse}}

\leftindent{This is the number of cuids the library has currently assigned.  A 
cuid <=0 or > CUI_CuidsInUse is invalid.  Although the CUI library always 
checks cuids you pass it to make sure they are valid, client programs may find 
it useful at times to perform this check themselves.}


\typewriter{int \index{CUI_IsMagic}}

\leftindent{This variable is always zero unless the current user is a member 
of the Andrew Message System group.  It can be used for testing new features 
or for debugging purposes.}


\typewriter{long \index{CUI_LastCallFinished}}

\leftindent{This variable is the time (from a call to time(0)) that the last 
call to the message server finished.  It can be used in determining whether or 
not a "keepalive" message to the server is in order.}


\typewriter{int \index{CUI_OnSameHost}}

\leftindent{This variable is non-zero if the server is running on the same 
machine as the client, zero otherwise.}


\typewriter{char \index{CUI_VersionString}[]}

\leftindent{This variable contains the text of the current CUI version string.}


\typewriter{int \index{CUI_SnapIsRunning}}

\leftindent{This variable is non-zero if the process is talking to the message 
server via SNAP, and zero if the message server is linked in, without SNAP.}


\typewriter{int \index{CUIDebugging}}

\leftindent{This variable is zero if debugging is turned off, and otherwise is 
the current debugging level for the cui & library.  The debugging level is a 
bit mask, with each bit representing debugging of a certain kind.  See the 
code for details.}


\typewriter{long \index{mserrcode}}

\leftindent{This is the result of the latest message server call.  It should 
be zero if no error occurred, otherwise its meaning is explained in the 
message server documentation.}


\subsection{1.3.2	Calls Related to Individual Messages}


\typewriter{\index{CUI_AlterSnapshot}(cuid, NewSnapshot, Code, dir)

int     cuid, /* IN */

        Code; /* IN */

char   *NewSnapshot, /* IN */

      **dir; /* OUT */}

\leftindent{This routine alters the snapshot for the message identified by 
cuid.  It is used, among other things, by the deletion and undeletion 
routines.  It returns after setting the directory pointer to point at the name 
of the directory in which the altered message resides.  See the documentation 
for MS_AlterSnapshot for information on the NewSnapshot and Code parameters.}


\typewriter{\index{CUI_CloneMessage}(cuid, DestDirName, Code)

int   cuid,  /* IN */

      Code; /* IN */

char *DestDirName; /* OUT */}

\leftindent{This routine makes a copy of the message identified by cuid.  See 
the documentation for MS_CloneMessage for an explanation of the meaning of the 
DestDirName and Code parameters.}


\typewriter{\index{CUI_DeleteMessage}(cuid)

int   cuid; /* IN */}

\leftindent{This routine deletes the message identified by cuid, using 
CUI_AlterSnapshot.  It also makes a note in its cache that the directory has 
deleted messages and may need to be purged later.}


\typewriter{\index{CUI_UndeleteMessage}(cuid)

int     cuid; /* IN */}

\leftindent{This routine undeletes the message identified by cuid, using 
CUI_AlterSnapshot.


}\typewriter{\index{CUI_GetHeaderContents}(cuid, HeaderName, HeaderTypeNumber, 
HeaderBuf, lim)

char   *HeaderName, /* IN */

       *HeaderBuf; /* OUT */

int     cuid, /* IN */

        HeaderTypeNumber, /* IN */

        lim; /* IN */}

\leftindent{This routine extracts the contents of a specified header from the 
message identified by cuid.  The meaning of the other parameters is the same 
as in the documentation for MS_GetHeaderContents.}


\typewriter{\index{CUI_GetPartialBody}(Buf, BufLim, cuid, offset, remaining, 
ct)

char   *Buf; /* OUT */

int     BufLim, /* IN */

        cuid; /* IN */

long    offset, /* IN */

       *remaining; /* OUT */

int    *ct; /* OUT */}

\leftindent{This routine extracts part of the body of a message identified by 
cuid.  The meaning of the other parameters is the same as in the documentation 
for MS_GetPartialBody.}


\typewriter{\index{CUI_GetBodyToLocalFile}(cuid, FileName, ShouldDelete)

int cuid; /* IN */

char *FileName; /* OUT */

int *ShouldDelete; /* OUT */

}\leftindent{This routine gets the entire body of the message identified by 
cuid into a locally-readable file.  If the file is a temporary file created by 
the file system, the integer ShouldDelete will be set to a non-zero value, 
indicating that you should delete the file when you're through with it.  If 
ShouldDelete is zero, you are being pointed to a real file in the database, 
which is apparently locally readable, and you should NOT delete the file when 
you're done.}


\typewriter{\index{CUI_ReallyGetBodyToLocalFile}(cuid, FileName, ShouldDelete, 
MayFudge)

int cuid; /* IN */

char *FileName; /* OUT */

int *ShouldDelete; /* OUT */

int MayFudge; /* IN */

}\leftindent{This is the same as the previous routine, except that it takes 
the additional parameter MayFudge.  If MayFudge is true, it may just point you 
at the database copy of the file and set ShouldDelete to zero.  If MayFudge is 
false, it will also make a new temporary copy and set ShouldDelete to a 
non-zero value.}


\typewriter{\index{CUI_GetSnapshotFromCUID}(cuid, SnapshotBuf)

int     cuid; /* IN */

char   *SnapshotBuf; /* OUT */}

\leftindent{This routine retrieves the snapshot of the message identified by 
cuid.  The snapshot is returned in SnapshotBuf, which should be big enough to 
hold one (AMS_SNAPSHOTSIZE, defined in AMS.h).}


\typewriter{\index{CUI_MarkAsRead}(cuid)

int     cuid; /* IN */}

\leftindent{This routine marks the message identified by CUID as "seen".  It 
only works if the user has write-access to the message directory in which the 
message resides.}


\typewriter{\index{CUI_MarkAsUnseen}(cuid)

int     cuid; /* IN */}

\leftindent{This routine un-marks the message identified by CUID as "seen". 
 It only works if the user has write-access to the message directory in which 
the message resides.}


\typewriter{\index{CUI_PrintBodyFromCUID}(cuid)

int     cuid; /* IN */}

\leftindent{This routine tells the message server to queue the specified 
message for printing on paper.}


\typewriter{\index{CUI_PrintBodyFromCUIDWithFlags}(cuid, flags, printer)

int cuid, flags; /* BOTH IN */

char *printer;

}\leftindent{This routine is just like the previous, in that it prints the 
message specified.  However, it passes the flags and printer arguments on to 
MS_PrintMessage, to be used as documented in the MS documentation.}


\typewriter{\index{CUI_MarkRepliedTo}(cuid)

int cuid; /* IN */

}\leftindent{This routine marks the message identified by CUID has having been 
replied to.}


\typewriter{\index{CUI_FlagUrgency}(cuid, urgency)

int cuid, urgency; /* BOTH IN */

}\leftindent{This routine marks or unmarks a message as "urgent" -- that is, 
it turns on or off the "urgent" attribute for the message identified by cuid. 
 If urgency is non-zero, it is marked as urgent, otherwise the urgent mark is 
turned off.}


\subsection{1.3.3	Calls Related to User-Defined Attributes

}
\typewriter{\index{CUI_GetAttrName}(dir, which, buf)

char *dir, /* IN */

      *buf; /* OUT */

int which; /* IN */

}\leftindent{This call takes a message folder (dir) and an attribute number 
(which) and returns the name of that attribute, if defined.  (If it is not 
defined, a non-zero return and an error message occur.)  The buf should be big 
enough to hold any attribute name, i.e. AMS_ATTRNAMEMAX.  Returns zero on 
success, non-zero on error.}


\typewriter{\index{CUI_SetAttribute}(cuid, attrname)

int cuid; /* IN */

char *attrname; /* IN */

}\leftindent{This call turns on the attribute named by attrname for the 
message identified by cuid.  See CUI_FixAttribute, below.  Returns zero on 
success, non-zero on error.}


\typewriter{\index{CUI_UnsetAttribute}(cuid, attrname)

int cuid; /* IN */

char *attrname; /* IN */

}\leftindent{This call turns off the attribute named by attrname for the 
message identified by cuid.  See CUI_FixAttribute, below.  Returns zero on 
success, non-zero on error.}


\typewriter{\index{CUI_FixAttribute}(cuid, attrname, Set)

int cuid, Set; /* BOTH IN */

char *attrname; /* IN */

}\leftindent{This call turns on or off (depending on whether Set is non-zero 
or zero, respectively) the attribute named by attrname for the message 
identified by cuid.  If the named attribute does not exist, it will ask the 
user if he wants to create it.  If you're setting an existing attribute and 
know its number, not just its name, the CUI_FixAttributeByNumber call will be 
faster.  Returns zero on success, non-zero on error.}


\typewriter{\index{CUI_FixAttributeByNumber}(cuid, attnum, Set)

int cuid, attnum, Set; /* ALL IN */

}\leftindent{This routine sets or unsets (depending on whether Set is non-zero 
or zero, respectively) the attribute numbered attnum.  It does not check the 
existence of that attribute, but it does check to see that it is in range for 
a valid user-defined attribute.  Returns zero on success, non-zero on error.}


\subsection{1.3.4	Calls Related to Mail Delivery}


\typewriter{\index{CUI_NameReplyFile}(cuid, code, FileName)

int     cuid, /* IN */

        code; /* IN */

char   *FileName; /* OUT */}

\leftindent{This routine prepares a mail reply template file for the message 
identified by cuid.  The file name is returned in the FileName buffer, which 
should be big enough to hold any file name (MAXPATHLEN).  


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.


\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.

}}
\typewriter{\index{CUI_RewriteHeaderLine}(text, realname)

char *text, /* IN */

     **realname; /* OUT */}

\leftindent{This call is the basic engine by which client interfaces should 
validate the "To" and "CC" headers before delivering mail.  The old line is 
passed in the text parameter, and the rewritten line is passed out via the the 
realname parameter, which is allocated by the routine and must be freed by the 
client.


The value returned by this routine is zero if everything went well, and 
otherwise is the number of addresses which were not valid.  realname is ALWAYS 
rewritten, so that it is always better to use realname than text, as at least 
the valid addresses will have been rewritten in canonical format.}


\typewriter{\index{CUI_RewriteHeaderLineInternal}(text, realname, 
 maxdealiases, numfound, externalct, formatct, stripct, trustct)

char *text,  /* IN */

      **newtext; /* OUT */

int maxdealiases,  /* IN */

      *numfound, *externalct, *formatct, *stripct, *trustct; /* ALL OUT */

}\leftindent{This call is just like RewriteHeaderLine, except that it provides 
a few extras.  You get to specify maxdealiases, which is the maximum number of 
personal alias definitions that can invoke other personal alias definitions. 
 (There has to be some maximum to prevent loops; when last we looked, the 
default was 25, and nobody had complained.)  Five additional values are 
returned.  The first, numfound, is the number of separate addresses that were 
found, while the second, externalct, is the number of those addresses that 
were clearly destined to non-local recipients.  The last three are the number 
of the external recipients that have been designated (by the user's 
.AMS_aliases file) as having a set designation for the handling of formatted 
mail, e.g. to always strip out formatting, always send formatting, or always 
trust the delivery system for those users.}


\typewriter{\index{CUI_ValidateFile}(InFile, OutFile)

char *InFile; /* IN */

char *OutFile; /* OUT */

}\leftindent{This call takes a draft mail file (that is, a file containing 
headers and body in RFC822 format), validates all the addresses on the To and 
CC lines, and rewrites the result as a new file, the name of which is 
generated by this routine.  The original file is not deleted; that is the 
responsiblity of the caller.  Nonzero return value indicates success, as 
usual.}


\typewriter{\index{CUI_SubmitMessage}(FileName, DeliveryOpts)

char   *FileName; /* IN */

int     DeliveryOpts; /* IN */}

\leftindent{This is the routine used to submit mail for delivery.  The 
FileName,and DeliveryOpts parameters are the same as in the documentation for 
MS_SubmitMessage.  The primary difference between the CUI_ and MS_ versions of 
this routine are that the CUI_ routines report and handle most errors 
themselves.  }


\typewriter{\index{CUI_ResendMessage}(cuid, Tolist)

int cuid; /* IN */

char *Tolist; /* IN */}

\leftindent{This routine will resend a message to the list of recipients 
(comma-separated) in the Tolist parameter.  This routine internally performs 
all necessary address validation.}


\subsection{1.3.5	Calls Related to Message Directories}


\typewriter{\index{CUI_BuildNickName}(FullName, NickName)

char   *FullName, /* IN */

       *NickName; /* OUT */}

\leftindent{This routine takes a full message directory path name (FullName) 
and produces from it the "nickname" that users want to see -- e.g. 
transforming /cmu/itc/bb/.MESSAGES/andrew/gripes into "andrew.gripes".  The 
NickName buffer should be at least as big as FullName.}


\typewriter{\index{CUI_CheckMailboxes}(DirName)

char   *Dirname; /* IN */}

\leftindent{This routine will check the mailbox associated with the named 
directory.  It is used, for example, in the cui update command, so that if you 
type "update misc" it will first read in new files from your personal Mailbox 
(assuming that misc is your personal mail directory).  If DirName is null, all 
mailboxes on your mspath to which you have appropriate access will be checked.}


\typewriter{\index{CUI_CheckNewMessages}(arg)

char   *arg; /* IN */}

\leftindent{This routine takes one argument, a string, which is searched for a 
"space" character.  Everything before the space character is the name of 
mailbox, and anything after that is the name of a .MS.spec file.  If there is 
no mailbox, the file "~/Mailbox" is used.  Messages are read from the 
appropriate mailbox using MS_ProcessNewMessages (see the documentation), and 
the results are reported to the user as appropriate.}


\typewriter{\index{CUI_CreateNewMessageDirectory}(dir, bodydir)

char   *dir, /* IN */

       *bodydir; /* IN */}

\leftindent{This routine is just like MS_CreateNewMessageDirectory, except 
that it will not overwrite a directory that already exists.  It is preferred 
over the MS_ routine because it reports errors properly and because it may 
eventually make entries in the CUI directory cache, though it does not at 
present.}


\typewriter{\index{CUI_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).  It should, in general, be used instead of MS_SetSubscriptionEntry.}


\typewriter{\index{CUI_HandleMissingFolder}(DirName)

char *DirName;}

\leftindent{This routine should be called every time a folder is found on the 
subscription list which no longer exists (ENOENT is AMS_ERRNO).  This will 
check to see if it has been moved or simply deleted, and will ask the user the 
appropriate questions to alter his subscription list.  NOTE THAT THE PARAMETER 
MUST BE A FULL PATH NAME.}


\typewriter{\index{CUI_RenameDir}(old, new)

char   *old, /* IN */

       *new; /* IN */}

\leftindent{This routine renames a message directory.  It should ALWAYS be 
used instead of MS_RenameDir in order to keep the cui cache consistent.  As 
with MS_RenameDir, the new parameter must be a single level-name (no dots or 
slashes), and the directory can have no children.}


\typewriter{\index{CUI_RemoveDirectory}(DirName)

char   *DirName; /* IN */}

\leftindent{This routine asks the user if he wants to delete the N messages in 
the directory and then, if the user says yes, deletes them with an appropriate 
call to MS_RemoveDirectory.}


\typewriter{\index{CUI_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{\index{CUI_DirectoriesToPurge}() }

\leftindent{This routine returns the number of directories that the CUI 
library knows have deleted messages and should be purged.}


\typewriter{\index{CUI_DoesDirNeedPurging}(DirName)

char *DirName; /* IN */}

\leftindent{This routine returns non-zero only if the named directory is 
cached as needing to be purged.}


\typewriter{\index{CUI_PurgeDeletions}(DirName)

char   *DirName; /* IN */}

\leftindent{This routine purges all deleted messages in the named directory. 
 If DirName is null, then all of the directories known to  have deleted 
messages will be purged.}


\typewriter{\index{CUI_PurgeMarkedDirectories}(Ask, OfferQuit)

Boolean Ask, OfferQuit;}

\leftindent{This routine purges all deleted messages in all directories known 
to have deleted messages.  If Ask is true, it will ask for confirmation first; 
one of the choices offered will be "purge selectively", in which case the 
question will be asked again for each directory to be purged.  If OfferQuit is 
also true, then "Do not quit" will be offered as an additional choice.  This 
routine returns 0 on success, -1 on error, and 1 on a "Do not quit" choice.}


\typewriter{\index{CUI_MarkDirectoryForPurging}(dirname)

char *dirname; /* IN */}

\leftindent{This routine marks the named directory as needing to be purged, so 
that it will be known to the CUI_PurgeMarkedDirectories routine.}


\typewriter{\index{CUI_UnmarkDirectoryForPurging}(dirname)

char *dirname; /* IN */}

\leftindent{This routine marks the named directory as NOT needing to be 
purged, so that it will NOT be known to the CUI_PurgeMarkedDirectories 
routine.}


\typewriter{\index{CUI_DisambiguateDir}(shortname, longname)

char   *shortname; /* IN */

char  **longname; /* IN */}

\leftindent{This routine takes a (typically) user-specified directory name 
shortname (e.g. "andrew.gripes") and produces the appropriate full path name 
for the directory.  The CUI library keeps a cache of directory names, so that 
most of the calls to CUI_DisambiguateDir do NOT result in any calls to the 
message server.  The longname pointer is set to point to the appropriate full 
path name in the CUI library's cache.  This storage is managed by the library 
and should NOT be freed by the client.}


\typewriter{\index{CUI_CacheDirName}(shortname, longname)

char *shortname, *longname; /* IN */}

\leftindent{This routine short-circuits CUI_DisambiguateDir; it tells the 
library that "shortname" is a nickname for "longname", so that the next time 
CUI_DisambiguateDir is called on shortname, the longname answer will be 
returned.  This is primarily useful for saving the information the 
messageserver has provided in the form of a subscription map, which includes 
both forms of the name.}


\typewriter{\index{CUI_GetAMSID}(cuid, id, dir)

int cuid;

char **id, **dir;}

\leftindent{This routine takes a cuid and gives you a pointer to the 
associated message directory name and ID.  The storage pointed to is managed 
by the CUI library and should NOT be freed by the client.}


\typewriter{\index{CUI_GetCUID}(amsid, dirname, IsDup)

char *amsid */

     *dirname; /* IN */

int *IsDup; /* OUT */}

\leftindent{This routine takes an id and dirname and assigns a CUID to the 
message referenced.  If the message has already been assigned a CUID, it uses 
the old one.  This function returns the cuid itself.  It also sets IsDup to be 
non-zero if this message appears in multiple directories, and the directory 
named is NOT the first such directory referenced.}


\typewriter{\index{CUI_ReconstructDirectory}(DirName, TrustTimeStamp)

char   *DirName; /* IN */

int   TrustTimeStamp;  /* IN */}

\leftindent{This routine reconstructs the specified message directory DirName. 
 The TrustTimeStamp integer, if non-zero, indicates that the reconstruction 
should order the message based on the raw time stamp on the body files; 
otherwise, the ordering is based on a (slower) parsing of the "Date" headers. 
 See the documentation for MS_ReconstructDirectory for further details.}


\subsection{1.3.6	Calls Related to User Preferences}


\typewriter{\index{CUI_GetProfileString}(prog, pref, valbuf, lim)

char *prog, /* IN */

     *pref, /* IN */

     *valbuf; /* OUT */

int lim; /* IN */}

\leftindent{This routine gets a string from the user's preferences file. 
 Preferences are formatted as "prog.pref: val".  lim is the maximum size of 
the string to be written in valbuf.  Returns zero on success, -1 on error.}


\typewriter{\index{CUI_GetProfileSwitch}(prog, pref, def)

char *prog, /* IN */

     *pref; /* IN */

int def; /* IN */}

\leftindent{This routine gets a boolean value from the user's preferences 
file.  If there is no such preference, the default def is returned.}


\typewriter{\index{CUI_GetProfileInt}(prog, pref, int)

char *prog, /* IN */

     *pref; /* IN */

int def; /* IN */}

\leftindent{This routine gets an integer value from the user's preferences 
file.  If there is no such preference, the default def is returned.}


\typewriter{\index{CUI_SetProfileString}(prog, pref, val)

char *prog, /* IN */

     *pref, /* IN */

     *val; /* IN */}

\leftindent{This routine sets the user's "prog.pref" preferences to the string 
value given in val.  For switches or integers, a string conversion should be 
performed prior to calling this routine.  It returns 0 on success, -1 on 
errors.}


\subsection{1.3.7	Calls Related to Access of Server and Local Files}


\typewriter{\index{CUI_GenTmpFileName}(nmbuf)

char   *nmbuf; /* IN */}

\leftindent{This routine generates a reasonably unique name for a file to be 
stored on the message server.  It puts that name in nmbuf, which should be big 
enough to hold any path name (MAXPATHLEN).}


\typewriter{\index{CUI_GetFileFromVice}(LocalFile, ViceFile)

char *LocalFile,  /* IN */

     *ViceFile; /* IN */}

\leftindent{This routine copies ViceFile from the server and puts it in the 
locally accessible file LocalFile.}


\typewriter{\index{CUI_StoreFileToVice}(LocalFile, ViceFile)

char *LocalFile, /* IN */

     *ViceFile; /* IN */}

\leftindent{This routine copies LocalFile from the local machine and puts it 
in the file ViceFile which is accessible to the message server.}


\typewriter{\index{CUI_AppendFileToVice}(LocalFile, ViceFile, offset)

char *LocalFile, /* IN */

     *ViceFile; /* IN */

long offset; /* IN */}

\leftindent{This routine copies LocalFile from the local machine and puts it 
in the file ViceFile which is accessible to the message server.  It starts the 
store at the byte specified by offset, and hence can be used to conveniently 
append something to a Vice file.}


\typewriter{\index{CUI_CopyViceFile}(FromFile, ToFile)

char *FromFile, *ToFile; /* BOTH IN */

}\leftindent{This routine copies the Vice file FromFile to the Vice file 
ToFile.}


\typewriter{\index{CUI_CopyViceFileTails}(FromFile, FromSkip, ToFile, ToSkip)

char *FromFile, *ToFile; /* BOTH IN */

long FromSkip, ToSkip; /* BOTH IN */

}\leftindent{This routine appends the last part of the Vice file FromFile 
(skipping FromSkip bytes) to the end of ToFile (skipping ToSkip bytes).  It is 
used in the implementation of CUI_CopyViceFile, and has also proven useful in 
its own right on occasion.}


\subsection{1.3.8	Calls that Handle Active Messages}


There are a number of calls in the CUI library that handle the notion of an 
"active" message.  The easiest way to handle active messages, and the 
recommended way, is to simply call the CUI_ProcessMessageAttributes routine 
every time a message is displayed.  This routine will do all necessary 
interactions with the user, using the interface-provided routines such as 
ChooseFromList (see below).  However, an interface may instead choose to 
handle each type of active message individually, using the routines listed 
after the first routine in this section.


\typewriter{\index{CUI_ProcessMessageAttributes}(cuid, Snapshot)

int cuid; /* IN */

char *Snapshot; /* IN */

}\leftindent{This routine checks each "active" attribute in a message and 
interacts with the user to process that attribute.  If you call it once each 
time you display a message to the user, you never need to use the additional 
routines described in this section, with the possible exception of 
CUI_SetHeaderCustomizationProc.}


\typewriter{int \index{CUI_HandleEnclosure}(cuid, Snapshot)

int cuid;

char *Snapshot;}

\leftindent{When called with the cuid and snapshot of a message that contains 
an enclosure, this routine interacts with the user to allow him to write the 
enclosure to a file or pipe it through a process.}


\typewriter{int \index{CUI_HandleAckRequest}(cuid,Snapshot)

int cuid;

char *Snapshot;

}\leftindent{When called with the cuid and snapshot of a message that contains 
an acknowledgement request, this routine interacts with the user to allow him 
to choose whether or not to send an acknowledgement.}


\typewriter{int \index{CUI_HandleVote}(cuid, Snapshot)

int cuid;

char *Snapshot;}

\leftindent{When called with the cuid and snapshot of a message that contains 
a vote, this routine interacts with the user to allow him to choose whether or 
not to send a vote.}


\typewriter{int \index{CUI_HandleFolderCreationNotice}(cuid, Snapshot)

int cuid;

char *Snapshot;

}\leftindent{When called with the cuid and snapshot of a message that contains 
a folder creation announcement, this routine interacts with the user to allow 
him to choose whether or not to subscribe to the folder.}


\typewriter{int \index{CUI_HandleRedistributionMessage}(cuid, Snapshot)

int cuid;

char *Snapshot;

}\leftindent{When called with the cuid and snapshot of a message that contains 
a redistribution invitation, this routine interacts with the user to allow him 
to choose whether or not to redistribute the message as suggested.}


\typewriter{int \index{CUI_HandleCustomizationMessage}(cuid, Snapshot)

int cuid;

char *Snapshot;

}\leftindent{When called with the cuid and snapshot of a message, this routine 
checks to see if the user has specified any personal customized response to 
the message (in the file ~/.headmagic) and, if so, runs the filter program 
specified by the user.}


\typewriter{int \index{CUI_SetHeaderCustomizationProc}(p, rock)

int (*p)();

long rock;

}\leftindent{This routine is intended to be called at initialization time to 
tell the CUI library that there is an interface-dependent routine that should 
be called on certain user-customization headers, as specified by the user's 
~/.headmagic file.  This can be used to allow an interface to gracefully 
extend the header-based customization facilities beyond those provided by the 
CUI library.}


\subsection{1.3.9	Miscellaneous Calls}


\typewriter{\index{CUI_SetPrinter}(printername)

char *printername; /* IN */

}\leftindent{This routine sets the name of the printer to be used on all 
subsequent printing-related calls that do not explicitly specify a printer 
parameter.  The routine will return zero if the printer name was valid.}


\typewriter{\index{CUI_SetClientSignalHandler}(handler)

int (*handler)()

}\leftindent{This routine sets the procedure that will be called when the 
client process receives a signal.  It is necessary for clients to use this 
rather than the raw UNIX signal mechanism, even if they are indeed UNIX 
clients, in order to make the signal handling work identically in the SNAP and 
no-SNAP version without interfering with the message server's signal handling.}


\leftindent{The handler routine should be declared as taking two parameters:


\typewriter{\indent{Handler(signum, ActNormal)

int signum; /* IN */

int *ActNormal; /* OUT */

}}
Signum is simply the signal received; ActNormal should be set to non-zero by 
this routine if the normal signal-handling behavior is to be carried out after 
the client's signal handling is done.}


\typewriter{\index{CUI_PrefetchMessage}(cuid, GetNext)

int cuid; /* 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 cuid.  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.  This corresponds almost exactly to the MS_PrefetchMessage call, 
except that it understands cuid's.}


\typewriter{\index{CUI_EndConver\typewriter{s}ation}()}

\leftindent{This routine cleans up the SNAP state relevant to the 
client-server connection, and should be called before exiting if possible.}


\typewriter{\index{CUI_GetHeaders}(FullDirName, datefield, ReturnBuf, 
MaxReturn, startbyte, numbytes, bytesleft, RegisterCuids)

char   *FullDirName, /* IN */

       *datefield, /* IN */

       *ReturnBuf; /* OUT */

int     MaxReturn,  /* IN */

        RegisterCuids; /* IN */

long    startbyte, /* IN */

       *numbytes, /* OUT */

       *bytesleft; /* OUT */}

\leftindent{This routine retrieves snapshots from the message server from a 
given directory since a given date.   The FulLDirName, datefield, ReturnBuf, 
MaxReturn, startbyte, numbytes, and bytesleft parameters are the same as 
documented for the MS_HeadersSince call.   However, this routine provides 
additional error reporting.  It also looks at an extra parameter, 
RegisterCuids, which tells it whether or not to enter each of the snapshots in 
the CUID cache.  It is ALWAYS safe to do this; the only time when you do not 
particularly want to do this is if you are going to register them yourself 
afterwards, which is not yet an exported CUI_ routine and hence is not yet 
documented.  In general, unless you known what you are doing, RegisterCuids 
should be non-zero.}


\typewriter{\typewriter{\index{CUI_Initialize}(TimerFunction, Rock)

int (*TimerFunction)(); /* IN */

char *Rock; /* IN */

}}\leftindent{This is the function that is called when the program first 
starts, to initialize the connection to the message server and to initialize 
the CUI library's state.  The TimerFunction is the name of a function which 
will periodically perform updates and keep the message server alive or, in the 
non-SNAP version, will periodically clean up the message server's state.  One 
such function, CUI_InitializeKeepAlives, is provided with the 
machine-dependent module for the cui library, but some interfaces (notably the 
messages program) need to define their own mechanisms for sending the 
keepalives.  The Rock is simply a pointer (to anything) which will be passed 
back to the interface when it needs a "hook" to find its own data.}


\typewriter{\index{CUI_SetClientVersion}(Vers)

char *Vers; /* IN */}

\leftindent{This function should be called after CUI_Initialize to tell the 
CUI library the name and version number of the current interface.  This will 
eventually be automatically placed in Received headers of outgoing mail, for 
debugging/tracing purposes.}


\typewriter{\index{CUI_SetMachineName}(Name)

char *Name; /* IN */}

\leftindent{This function should be called from Machine_Init to tell the CUI 
library the name of the current machine.  This will eventually be 
automatically placed in Received headers of outgoing mail, for 
debugging/tracing purposes.  This routine should not be necessary for anyone 
except those porting a CUI library application to a new machine type.

}
\typewriter{\index{CUI_SetMachineName}(Name)

char *Name; /* IN */}

\leftindent{This function should be called from Machine_Init to tell the CUI 
library the machine type of the current machine.  This will eventually be 
automatically placed in Received headers of outgoing mail, for 
debugging/tracing purposes.  This routine should not be necessary for anyone 
except those porting a CUI library application to a new machine type.}


\typewriter{\index{CUI_ReportAmbig}(name, atype)

char *name, *atype; /* both in */}

\leftindent{This is a stupid little function that does exactly this:


\typewriter{\{

    char ErrorText[1000];


    sprintf(ErrorText, "There is no %s named '%s'.", atype, name);

    ReportError(ErrorText, ERR_WARNING, TRUE);

\}}}


\typewriter{\index{CUI_FreeCaches}()}

\leftindent{This function frees up storage from the cui cache.  All cuids and 
directory pointers previously handed out by the CUI will become invalid.  It 
is intended for use only in a "refresh" situation, e.g. clearing out all the 
headers visible to the user.

}
\typewriter{\index{CUI_PrintUpdates}(dname, nickname)

char *dname,  /* IN */

     *nickname; /* IN */}

\leftindent{This routine will cause the message server to print all new 
messages in the directory named as dname, and to then update the user's 
profile information for that directory.  It is used for print-subscribed 
bulletin boards, which are all updated in the same manner regardless of 
interface.  The nickname parameter is simply the name this routine will use in 
describing its actions to the user.}


\typewriter{\index{CUI_PrintUpdatesWithFlags}(dname, nickname, flags, printer)

char *dname, /* IN */

        *nickname, /* IN */

        *printer; /* IN */

int flags; /* IN */

}\leftindent{This routine is just like CUI_PrintUpdates, except that the flags 
and printer parameters are passed on to MS_PrintMessage, to be used as 
described in the MS documentation.}


\subsection{1.3.10	Calls That Must Be Provided By the Client Program}


\italic{A note on linkage bogosities}:  In addition to the useful routines 
described below, you need to provide the following integer and two routines to 
satisfy the linker:


\leftindent{\typewriter{int \index{Interactive} = 1;

\index{GetTerminalParams}();

\index{SetTerminalParams}();

}
These should not really be necessary, but the only way to get rid of them 
would involve having a machine-dependent module for each interface program; we 
prefer to have only one machine-dependent module in the system, and this is 
the price we've had to pay for it so far.}


The following routines must be provided by each interface program:\smaller{

}
\typewriter{\index{ReportSuccess}(text)

char *text; /* IN */}

\leftindent{Conveys a message (text) to the user which is NOT very bad news.}


\typewriter{\index{ReportError}(text, level, Decode)

char *text; /* IN */

int   level; /* IN */

Boolean Decode; /* IN */}

\leftindent{Conveys an error message (text) to the user.  The level parameter 
indicates the severity of the error, and is one of the symbolic values defined 
in errprintf.h.  The Decode Boolean (== short) is non-zero if the global error 
code mserrcode is believed to contain relevant information.  In that case, 
mserrcode must be decoded.  The meaning of message server error codes is 
explained in the message server documentation, but the best thing to do is to 
start with the CUI's ReportError routine and modify it for your own interface. 
 In particular, it helps to check specially for temporary Vice failures and 
for authentication problems; the CUI code serves as a good generic example.}


\typewriter{\index{GetBooleanFromUser}(prompt, defaultans)

char *prompt; /* IN */

Boolean defaultans; /* IN */}

\leftindent{This routine asks the user a question, given in prompt, and 
returns a non-zero code if the answer was yes.  The default answer is given in 
defaultans.}


\typewriter{\index{ChooseFromList}(QVec, defaultans)

char **QVec; /* IN */

int    defaultans /* IN */}

\leftindent{This routine asks the user a multiple choice question.  QVec is a 
vector of character strings, the first of which is the question.  The 
remaining strings are the choices, with the last choice folled by a null entry 
in QVec.  defaultans specifies the default answer, or is zero if there is no 
default.}


\typewriter{\index{GetStringFromUser}(prompt, buf, len, IsPassword)

char *prompt,  /* IN */

     *buf; /* OUT */

int   len,  /* IN */

      IsPassword; /* IN */}

\leftindent{This routine asks the user a question (prompt), and puts the text 
of the answer in buf, up to len characters.  If IsPassword is non-zero, then 
echoing of the user's input should be suppressed.}


\typewriter{\index{DirectoryChangeHook}(adddir, deldir, rock)

char *adddir, *deldir, *rock; /* IN */}

\leftindent{This routine is called whenever a directory is created, deleted, 
or renamed, to allow the interface to update any relevant user-visible state. 
 The rock is the rock that was last passed to the CUI library via the 
CUI_Initialize call.}


\typewriter{\index{SubscriptionChangeHook}(name, nick, status, rock)

char *name, *nick;

int status;

char *rock;  /* any pointer you like */}

\leftindent{This routine is called whenever the subscription status of a 
folder is changed by the CUI_SetSubscriptionEntry call.  You can use it if you 
want to keep some representation of a folder list that includes subscription 
information.}


\typewriter{\index{HandleTimeout}(name, retries, restarts)

char *name; /* IN */

int   retries,  /* IN */

      restarts; /* IN */}

\leftindent{This routine is called by the CUI library when the message server 
connection times out.  name is the name of the message server call in 
progress, retries is the number of times the operation has been retried, and 
restarts is the number of times the library has tried to reconnect to the 
server.  The routine should return CUI_RPC_RETRY to cause the operation to be 
retried again, CUI_RPC_RESTART to try to reconnect to the server, and 
CUI_RPC_BUGOUT to give up and cause an error message to be propogated up to 
the calling routine.  These constants are defined in CUI.h.}


\typewriter{\index{DidRestart}()}

\leftindent{This routine is called when the CUI reconnects to the message 
server.  The client may want to notify the user of this event.}


\subsection{1.3.11	Calls That May Be Provided By the Interface Program, but 
Need Not Be

}
The following two routines are actually part of the messageserver process, and 
are used when the messageserver wants to send a diagnostic message to the 
user, beyond what it can convey via the RPC error codes.  Unfortunately, when 
the messageserver is on another machine, the user never sees these messages. 
 If the messageserver is linked in to the client process (i.e. SNAP is not 
used), then the client may override these routines and do a better job of 
showing the message to the user.


\typewriter{\index{NonfatalBizarreError}(text)

char *text;}


\typewriter{\index{CriticalBizarreError}(text)

char *text;}

\leftindent{These routines should each take a single string message and 
present it to the user.  The Critical ones are rarer more important errors.}


\subsection{1.3.12	Calls That Must Be Provided In the Machine-Dependent Code}


\typewriter{\index{Machine_HandleClientSignal}(signum, ActNormal)

int signum, *ActNormal;}

\leftindent{This routine must be provided in the machine-dependent code IF you 
are linking the message server in (no snap).  Thus it will probably not be 
necessary on any machine other than UNIX machines, but is mentioned here for 
completeness.  }


\typewriter{\index{Machine_Init}(ThisHost, ThisUser, ThisPassword, len, type, 
IsRecon)

char **ThisHost,  /* OUT */

     **ThisUser,  /* OUT */

     **ThisPassword; /* OUT */

int   *len,  /* OUT */

      *type,  /* OUT */

       IsRecon; /* IN */}

\leftindent{This routine is called from CUI_Initialize or when trying to 
reconnect to the message server.  It is used to configure the message server 
connection.  It should return after setting ThisHost to point to the name of 
the host on which to talk to a message server, setting ThisUser to point to 
the name of the user on the server machine, ThisPassword to point to the 
user's password, type to encode how to interpret the password field, len to 
the len of the password field.  len includes the terminating null for 
unencrypted passwords.  The IsRecon field is non-zero if this is not the first 
time the routine has been called.  The Machine_Init routine \italic{should} 
also call the CUI_SetMachineName and CUI_SetMachineType procedures, to ensure 
that the proper tracing information appears in the Received headers of 
outgoing mail.


The password should be encoded according to the guardian protocol specified in 
the include file "gasp.h", and is typically either GASP_PWD_STRING or 
GASP_PWD_VTOKENS.}


\typewriter{\index{CUI_GenLocalTmpFileName}(nmbuf)

char *nmbuf; /* OUT */}

\leftindent{This routine should generate a valid name for a new local 
temporary file, and write it into nmbuf.}


\typewriter{\index{CUI_InitializeKeepalives}()}

\leftindent{This routine should initiate the sequence of events that will 
cause the client to send periodic keepalive messages to the server.  This 
routine may not be used, if a different parameter is supplied to the 
CUI_Initialize routine, but it must be provided in order to make the CUI 
program do keepalives on any given machine.  If you make the 
CUI_InitializeKeepalives routine a no-op, then everything will still work, but 
your users will see MANY more "Reconnecting to message server, please wait..." 
messages.}


\typewriter{\index{EditLocalFile}(LocalName, FinishedElsewhere)

char *LocalName; /* IN */

int  *FinishedElsewhere; /* OUT */}

\leftindent{This routine is called by cui when it wants to edit a draft piece 
of mail.  The draft is stored in the file named as LocalName.  Generally, the 
file should be edited, FinishedElsewhere should be set to zero, and this 
routine should return zero.  However, on Andrew, if the user is running under 
the window manager then editing the message causes a sendmessage window to be 
created, and cui gets out of the delivery process; in this case, the 
FinishedElsewhere variable must be set to be non-zero.}


\typewriter{\index{RedirectOutput}()}

\leftindent{This routine is called when the cui forks to act as a daemon, and 
redirects output to the console.  Since this will not happen on most machine 
types, this routine may generally be defined as a no-op.}


\typewriter{\index{GetNewPassword}(ptr, IsRecon, ThisUser, ThisHost)

char **ptr,  /* OUT */

      *ThisUser, /* IN */

      *ThisHost; /* IN */

int    IsRecon; /* IN */}

\leftindent{This routine is called when the attempt to authenticate the user 
fails because of a bad password.  IsRecon tells whether this is a reconnection 
attempt or the first authentication attempt.  ThisUser and ThisHost are useful 
in framing the question to ask the user.  The new password should be returned 
by changing the ptr variable to point at an approriate location in static 
storage.}



rcs information about this file:

$Header: 
/afs/andrew.cmu.edu/itc/src/andrew/doc/itc/ams/prog/RCS/LibraryCalls.d,v 1.3 
89/01/18 09:46:43 nsb Exp Locker: jr34 $

$Log: CuiLib.pgr,v $

Revision 1.5  1993/05/04  00:58:25  susan

RCS Tree Split



Revision 1.4.1.1  1993/02/01  23:02:15  rr2b

new R6tape branch



Revision 1.4  1992/12/17  21:57:12  rr2b

disclaimerization

 Revision 1.3  1989/10/27  13:42:46  jr34 added blurb 
about EZ.  Revision 1.2  89/10/27  12:06:04  jr34 reformatted to use 
interactive toc & index.  Revision 1.1  89/09/13  16:43:26  jr34 Initial 
revision

Revision 1.4  89/04/11  15:31:26  jr34 added TrustTimeStamp per nsb.  Revision 
1.3  89/01/18  09:46:43  nsb *** empty log message ***  Revision 1.2  89/01/14 
 13:51:26  nsb Described four new subroutines.  Revision 1.1  88/10/04 
 15:59:41  jr34 Initial revision

Revision 1.2  88/10/04  14:21:09  nsb *** empty log message ***  Revision 1.1 
 88/08/23  12:25:18  jr34 Initial revision

Revision 1.1  88/08/19  17:31:23  jr34 Initial revision

Revision 5.0  88/05/29  20:27:41  ghoti Up to date - tested as of 5/29/88 
bumped version number to 5.0 named "june88"

Revision 1.9  88/04/06  09:49:29  aw0g say CUI_MAJORVERSION and 
CUI_MINORVERSION are declared by #define instead of int. In Machint_Init say 
the the len argument includes the null Add a rcs header and rcs log at the end



[1] ...


[2] ...

 

[3] ...



\begindata{bp,537558784}
\enddata{bp,537558784}
\view{bpv,537558784,1580,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,538945396}
