Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!watmath!clyde!caip!topaz!think!mit-eddie!genrad!decvax!cwruecmp!hal!ncoast!allbery From: allbery@ncoast.UUCP (Brandon S. Allbery) Newsgroups: net.sources Subject: IMS (mail system) Part 2/2 Message-ID: <1297@ncoast.UUCP> Date: Mon, 21-Jul-86 22:16:41 EDT Article-I.D.: ncoast.1297 Posted: Mon Jul 21 22:16:41 1986 Date-Received: Wed, 23-Jul-86 08:48:21 EDT Reply-To: allbery@ncoast.UUCP (Brandon S. Allbery) Organization: Cleveland Public Access UNIX, Cleveland, OH Lines: 1192 #! /bin/sh if test -r "ndir.c"; then echo "File ndir.c exists. Enter new name or RETURN to skip. (. to replace.)" read newname case "$newname" in ".") newname="ndir.c" esac else newname="ndir.c" fi if test -z "$newname"; then echo "shx - $newname (skipped)" else case "$newname" in "$sfile") echo "shx - $sfile (as $newname)" ;; *) echo "shx - $newname" esac sed 's/^X//' << '--EOF:ndir.c--' > "$newname" X#include X#include "ndir.h" X X#ifndef BSD X X/* X * close a directory. X */ Xclosedir(dirp) X register DIR *dirp; X{ X close(dirp->dd_fd); X dirp->dd_fd = -1; X dirp->dd_loc = 0; X free(dirp); X} X X X X/* X * open a directory. X */ XDIR * Xopendir(name) X char *name; X{ X register DIR *dirp; X register int fd; X X if ((fd = eopen(name, 0)) == -1) X return NULL; X if ((dirp = (DIR *)malloc(sizeof(DIR))) == NULL) { X close (fd); X return NULL; X } X dirp->dd_fd = fd; X dirp->dd_loc = 0; X return dirp; X} X X X X/* X * read an old style directory entry and present it as a new one X */ X#define ODIRSIZ 14 X Xstruct olddirect { X ino_t od_ino; X char od_name[ODIRSIZ]; X}; X X/* X * get next entry in a directory. X */ Xstruct direct * Xreaddir(dirp) X register DIR *dirp; X{ X register struct olddirect *dp; X static struct direct dir; X X for (;;) { X if (dirp->dd_loc == 0) { X dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, X DIRBLKSIZ); X if (dirp->dd_size <= 0) X return NULL; X } X if (dirp->dd_loc >= dirp->dd_size) { X dirp->dd_loc = 0; X continue; X } X dp = (struct olddirect *)(dirp->dd_buf + dirp->dd_loc); X dirp->dd_loc += sizeof(struct olddirect); X if (dp->od_ino == 0) X continue; X dir.d_ino = dp->od_ino; X strncpy(dir.d_name, dp->od_name, ODIRSIZ); X dir.d_name[ODIRSIZ] = '\0'; /* insure null termination */ X dir.d_namlen = strlen(dir.d_name); X dir.d_reclen = DIRBLKSIZ; X return (&dir); X } X} X X#endif BSD --EOF:ndir.c-- fi if test -r "eopen.c"; then echo "File eopen.c exists. Enter new name or RETURN to skip. (. to replace.)" read newname case "$newname" in ".") newname="eopen.c" esac else newname="eopen.c" fi if test -z "$newname"; then echo "shx - $newname (skipped)" else case "$newname" in "$sfile") echo "shx - $sfile (as $newname)" ;; *) echo "shx - $newname" esac sed 's/^X//' << '--EOF:eopen.c--' > "$newname" X#include X#include X Xextern int errno; Xstatic int __pop_pid = -1; X XFILE *efopen(file, mode) Xchar *file, *mode; { X int alevel, chmg; X FILE *fp; X X switch (mode[0]) { X case 'r': X alevel = 4; X break; X case 'w': X case 'a': X alevel = 2; X break; X } X if (mode[1] == '+') X alevel = 6; X chmg = 0; X if (access(file, alevel) < 0) X if (errno != ENOENT) X return (FILE *) 0; X else X chmg = 1; X if ((fp = fopen(file, mode)) == (FILE *) 0) X return (FILE *) 0; X if (chmg) X chown(file, getuid(), getgid()); X return fp; X} X Xeopen(file, mode) Xchar *file; { X int alevel, fd, chmg; X X switch (mode & 3) { X case 0: X alevel = 4; X break; X case 1: X alevel = 2; X break; X case 2: X alevel = 6; X break; X } X chmg = 0; X if (access(file, alevel) < 0) X if (errno != ENOENT) X return -1; X else X chmg = 1; X if ((fd = open(file, mode)) == -1) X return -1; X if (chmg) X chown(file, getuid(), getgid()); X return fd; X} X XFILE *epopen(cmd, mode) Xchar *mode; { X FILE *pfp; X int pfd[2]; X int pmode; X X pmode = (*mode == 'r'? 1: 0); X pipe(pfd); X switch (__pop_pid = fork()) { X case -1: X return (FILE *) 0; X case 0: X setgid(getgid()); X setuid(getuid()); X close(pmode); X dup(pfd[pmode]); X close(pfd[!pmode]); X close(pfd[pmode]); X execl("/bin/sh", "sh", "-c", cmd, (char *) 0); X _exit(100); X default: X close(pfd[pmode]); X return fdopen(pfd[!pmode], mode); X } X} X Xpclose(fp) XFILE *fp; { X int status; X X fclose(fp); X if (__pop_pid == -1) X return -1; X while (wait(&status) != __pop_pid) X ; X return status; X} --EOF:eopen.c-- fi if test -r "ims.h"; then echo "File ims.h exists. Enter new name or RETURN to skip. (. to replace.)" read newname case "$newname" in ".") newname="ims.h" esac else newname="ims.h" fi if test -z "$newname"; then echo "shx - $newname (skipped)" else case "$newname" in "$sfile") echo "shx - $sfile (as $newname)" ;; *) echo "shx - $newname" esac sed 's/^X//' << '--EOF:ims.h--' > "$newname" X#include X#include X#include X#include X#include X#include X#include X#include X#include "ndir.h" X X#define IMSINIT "/usr/lib/imsinit" X#define IMSALIAS "/usr/lib/imsaliases" X X#ifndef USG X#define strchr index X#define strrchr rindex X#endif USG X Xextern int readmsg(), printmsg(), reply(), gomsg(), mailto(), listmsg(), X forward(), byebye(), help(), setfolder(), readmbox(), savemsg(), X delmsg(), undelmsg(), nxbyebye(), expunge(), nextmsg(), prevmsg(), X varops(), foldlist(), aliasops(), unalias(); X Xextern char *location(); Xextern char *strchr(); Xextern char *strrchr(); Xextern char *getenv(); Xextern FILE *efopen(); Xextern char *mlocation(); Xextern char *mflocation(); Xextern char *calloc(); Xextern char *realloc(); Xextern FILE *epopen(); Xextern char *basename(); Xextern char *getlogin(); Xextern struct passwd *getpwnam(); Xextern struct tm *localtime(); X Xextern char folder[]; Xextern char cabinet[]; Xextern char pager[]; Xextern char sysmbox[]; Xextern char prompt[]; Xextern char sender[]; Xextern char mailbox[]; Xextern char editor[]; Xextern char printcmd[]; Xextern char savefolder[]; Xextern char autonext[]; Xextern char autoread[]; Xextern char askappend[]; Xextern char lines[]; Xextern char edforward[]; Xextern char alicount[]; Xextern int msg; X X#ifdef USG X#define SYSMAILBOX "/usr/mail/%s" X#else X#define SYSMAILBOX "/usr/spool/mail/%s" X#define strchr index X#define strrchr rindex X#endif USG X X#ifndef USG X#include X#define TERMIO sgttyb X#define TIO_GET TIOCGETP X#define TIO_SET TIOCSETN X#define TIO_ERASE sg_erase X#else USG X#include X#define TERMIO termio X#define TIO_GET TCGETA X#define TIO_SET TCSETAW X#define TIO_ERASE c_cc[VERASE] X#endif USG --EOF:ims.h-- fi if test -r "ndir.h"; then echo "File ndir.h exists. Enter new name or RETURN to skip. (. to replace.)" read newname case "$newname" in ".") newname="ndir.h" esac else newname="ndir.h" fi if test -z "$newname"; then echo "shx - $newname (skipped)" else case "$newname" in "$sfile") echo "shx - $sfile (as $newname)" ;; *) echo "shx - $newname" esac sed 's/^X//' << '--EOF:ndir.h--' > "$newname" X/* dir.h 4.4 82/07/25 */ X X#ifdef BSD X#include X#else X X/* X * A directory consists of some number of blocks of DIRBLKSIZ X * bytes, where DIRBLKSIZ is chosen such that it can be transferred X * to disk in a single atomic operation (e.g. 512 bytes on most machines). X * X * Each DIRBLKSIZ byte block contains some number of directory entry X * structures, which are of variable length. Each directory entry has X * a struct direct at the front of it, containing its inode number, X * the length of the entry, and the length of the name contained in X * the entry. These are followed by the name padded to a 4 byte boundary X * with null bytes. All names are guaranteed null terminated. X * The maximum length of a name in a directory is MAXNAMLEN. X * X * The macro DIRSIZ(dp) gives the amount of space required to represent X * a directory entry. Free space in a directory is represented by X * entries which have dp->d_reclen >= DIRSIZ(dp). All DIRBLKSIZ bytes X * in a directory block are claimed by the directory entries. This X * usually results in the last entry in a directory having a large X * dp->d_reclen. When entries are deleted from a directory, the X * space is returned to the previous entry in the same directory X * block by increasing its dp->d_reclen. If the first entry of X * a directory block is free, then its dp->d_ino is set to 0. X * Entries other than the first in a directory do not normally have X * dp->d_ino set to 0. X */ X#define DIRBLKSIZ 512 X#define MAXNAMLEN 255 X Xstruct direct { X long d_ino; /* inode number of entry */ X short d_reclen; /* length of this record */ X short d_namlen; /* length of string in d_name */ X char d_name[MAXNAMLEN + 1]; /* name must be no longer than this */ X}; X X/* X * The DIRSIZ macro gives the minimum record length which will hold X * the directory entry. This requires the amount of space in struct direct X * without the d_name field, plus enough space for the name with a terminating X * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary. X */ X#ifdef DIRSIZ X#undef DIRSIZ X#endif X#define DIRSIZ(dp) \ X ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3)) X X#ifndef KERNEL X/* X * Definitions for library routines operating on directories. X */ Xtypedef struct _dirdesc { X int dd_fd; X long dd_loc; X long dd_size; X char dd_buf[DIRBLKSIZ]; X} DIR; X#ifndef NULL X#define NULL 0 X#endif Xextern DIR *opendir(); Xextern struct direct *readdir(); Xextern closedir(); X#endif KERNEL X X#endif BSD --EOF:ndir.h-- fi if test -r "ims.1"; then echo "File ims.1 exists. Enter new name or RETURN to skip. (. to replace.)" read newname case "$newname" in ".") newname="ims.1" esac else newname="ims.1" fi if test -z "$newname"; then echo "shx - $newname (skipped)" else case "$newname" in "$sfile") echo "shx - $sfile (as $newname)" ;; *) echo "shx - $newname" esac sed 's/^X//' << '--EOF:ims.1--' > "$newname" X.TH IMS LOCAL X.ds i \fBims\fR X.SH NAME X\*i \- Intelligent Message System X.SH SYNOPSIS X.B \*i X[ -i ] X.br X.B \*i X.I \*i-command-string X.SH DESCRIPTION X\*i is a mail system intended to replace X.BR mail (1) Xfor regular use. It uses X.B mail Xto send messages, in order to retain compatibility with other mailers. X.PP X\*i implements a true ``folder'' mechanism for handling mail. A mail Xcabinet (by default X.IR $HOME/.mail ) Xis established the first time the program is run, as is a standard Xfolder (by default X.IR incoming-mail ). XOn entry, mail is read into files in the standard folder, unless the X.I -i Xoption is given or an X.I \*i-command-string Xis specified. The message pointer is then set to the first new message Xand a command prompt is issued. X.PP XThere are two ways to use \*i: X.IR "interactive mode" , Xwhich issues a prompt until a X.I quit Xor X.I xit Xcommand is issued or a X.I control-D Xis typed, and X.IR "command mode" , Xwhich executes the command line and then exits as if the X.I xit Xcommand had been issued. The two modes are described in detail below. X.SH SETUP X\*i understands a number of environment variables, supports variables of Xits own, and provides reasonable defaults for anything not specified. XThe environment variables, \*i variables, and their meanings are described Xin Table 1 at the end of this document. X.PP XEnvironment variables are specified in the usual way (see X.IR sh (1) Xor X.IR csh (1) Xfor examples). \*i variables are set in the file specified by the X.I IMSINIT Xvariable, or $HOME/.imsinit if no X.I IMSINIT Xenvironment variable exists. They may also be set by the X.I set Xcommand from within \*i. XThere is also a system IMSINIT file, X.IR /usr/lib/imsinit . X.PP XThe X.I IMSINIT Xfile contains assignment statements of the form: X.sp X.nf X.ce X\fIvariable\fR = \fIvalue\fR X.fi X.sp XA X.I value Xmay be a single word or quoted text; if quoted, the value may comprise Xseveral lines of the X.I IMSINIT Xfile, but this is discouraged because few, if any, \*i commands make use Xof multiple-line values. The X.I print-command Xvariable is a possible exception. X.SH COMMANDS X\*i supports a large number of commands for manipulating messages and Xfolders. They are detailed below. X.nr i) 5 X.de LS X.PP X.ns X.in +5n+\\n(i)n X.ll -5n X.. X.de LI X.sp X.ti -\\n(i)n X\fB\\$1\fR \- X.. X.de L+ X.sp X.ti -\\n(i)n X\fB\\$1\fR X.br X.ns X.. X.de LE X.ll X.in X.PP X.ns X.. X.LS X.LI delete XDelete the named message, or the current message. If X.I type-next-automatically Xis affirmative, a X.I type Xcommand is executed with no arguments afterward. X.LI undelete XRestore a message deleted with the X.I delete Xcommand. Note that if X.I xit Xis used to exit \*i, deleted messages will remain deleted but will also Xremain recoverable; an X.I expunge Xcommand, either explicit or via the X.I quit Xcommand, is required to physically delete messages. X.LI expunge XPhysically delete messages marked for deletion with the X.I delete Xcommand. An implicit X.I expunge Xis done by the X.I quit Xcommand. Unless an X.I expunge Xis performed, deleted messages still exist and are recoverable with X.IR undelete . X