Sync with most of NetBSD's changes, including:

*) Sync with 4.4BSD-Lite2
 *) Set usecs for utimes()
 *) Add 'inc' command and 'autoinc' option that check for new mail
    manually and automatically, respectively
 *) Use POSIX signal handling and tty semantics
 *) Handle long lines correctly when paging messages
 *) Add ability to explicitly search 'To:' line
 *) Various manpage cleanups
 *) Support overriding '~/.mailrc' with $MAILRC
 *) Support 'askbcc' and 'asksub' options
 *) Fix various bugs

Reviewed by:	ru (mail.1)
Obtained from:	NetBSD
This commit is contained in:
Mike Heffner 2001-12-18 20:52:09 +00:00
parent fdb33f08ef
commit 856f23ed35
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=88150
18 changed files with 438 additions and 156 deletions

View File

@ -345,9 +345,9 @@ alter(name)
if (stat(name, &sb))
return;
tv[0].tv_sec = time((time_t *)0) + 1;
tv[1].tv_sec = sb.st_mtime;
tv[0].tv_usec = tv[1].tv_usec = 0;
(void)gettimeofday(&tv[0], (struct timezone *)NULL);
tv[0].tv_sec++;
TIMESPEC_TO_TIMEVAL(&tv[1], &sb.st_mtimespec);
(void)utimes(name, tv);
}

View File

@ -33,7 +33,7 @@
#ifndef lint
#if 0
static char sccsid[] = "@(#)cmd1.c 8.1 (Berkeley) 6/6/93";
static char sccsid[] = "@(#)cmd1.c 8.2 (Berkeley) 4/20/95";
#endif
static const char rcsid[] =
"$FreeBSD$";
@ -111,7 +111,7 @@ scroll(arg)
case 0:
case '+':
s++;
if (s * size > msgCount) {
if (s * size >= msgCount) {
printf("On last screenful of messages\n");
return (0);
}
@ -460,3 +460,26 @@ folders()
(void)run_command(cmd, 0, -1, -1, dirname, NULL, NULL);
return (0);
}
/*
* Update the mail file with any new messages that have
* come in since we started reading mail.
*/
int
inc(v)
void *v;
{
int nmsg, mdot;
nmsg = incfile();
if (nmsg == 0)
printf("No new mail.\n");
else if (nmsg > 0) {
mdot = newfileinfo(msgCount - nmsg);
dot = &message[mdot - 1];
} else
printf("\"inc\" command failed...\n");
return (0);
}

View File

@ -33,7 +33,7 @@
#ifndef lint
#if 0
static char sccsid[] = "@(#)cmd3.c 8.1 (Berkeley) 6/6/93";
static char sccsid[] = "@(#)cmd3.c 8.2 (Berkeley) 4/20/95";
#endif
static const char rcsid[] =
"$FreeBSD$";
@ -357,7 +357,7 @@ rexit(e)
{
if (sourcing)
return (1);
exit(e);
exit(0);
/*NOTREACHED*/
}
@ -423,7 +423,9 @@ unset(arglist)
errs = 0;
for (ap = arglist; *ap != NULL; ap++) {
if ((vp2 = lookup(*ap)) == NULL) {
if (!sourcing) {
if (getenv(*ap))
unsetenv(*ap);
else if (!sourcing) {
printf("\"%s\": undefined variable\n", *ap);
errs++;
}
@ -552,7 +554,7 @@ file(argv)
{
if (argv[0] == NULL) {
newfileinfo();
newfileinfo(0);
return (0);
}
if (setfile(*argv) < 0)

View File

@ -120,5 +120,6 @@ const struct cmd cmdtab[] = {
{ "core", core, M|NOLIST, 0, 0 },
{ "#", null, M|NOLIST, 0, 0 },
{ "clobber", clobber, M|RAWLIST, 0, 1 },
{ "inc", inc, T|NOLIST, 0, 0 },
{ 0, 0, 0, 0, 0 }
};

View File

@ -80,14 +80,19 @@ collect(hp, printheaders)
FILE *fbuf;
int lc, cc, escape, eofcount, fd, c, t;
char linebuf[LINESIZE], tempname[PATHSIZE], *cp, getsub;
int omask;
sigset_t nset;
int longline, lastlong, rc; /* So we don't make 2 or more lines
out of a long input line. */
collf = NULL;
/*
* Start catching signals from here, but we're still die on interrupts
* until we're in the main loop.
*/
omask = sigblock(sigmask(SIGINT) | sigmask(SIGHUP));
(void)sigemptyset(&nset);
(void)sigaddset(&nset, SIGINT);
(void)sigaddset(&nset, SIGHUP);
(void)sigprocmask(SIG_BLOCK, &nset, NULL);
if ((saveint = signal(SIGINT, SIG_IGN)) != SIG_IGN)
(void)signal(SIGINT, collint);
if ((savehup = signal(SIGHUP, SIG_IGN)) != SIG_IGN)
@ -99,7 +104,7 @@ collect(hp, printheaders)
(void)rm(tempname);
goto err;
}
sigsetmask(omask & ~(sigmask(SIGINT) | sigmask(SIGHUP)));
(void)sigprocmask(SIG_UNBLOCK, &nset, NULL);
noreset++;
(void)snprintf(tempname, sizeof(tempname),
@ -131,6 +136,8 @@ collect(hp, printheaders)
escape = ESCAPE;
eofcount = 0;
hadintr = 0;
lastlong = 0;
longline = 0;
if (!setjmp(colljmp)) {
if (getsub)
@ -163,14 +170,17 @@ collect(hp, printheaders)
}
break;
}
lastlong = longline;
longline = c == LINESIZE - 1;
eofcount = 0;
hadintr = 0;
if (linebuf[0] == '.' && linebuf[1] == '\0' &&
value("interactive") != NULL &&
value("interactive") != NULL && !lastlong &&
(value("dot") != NULL || value("ignoreeof") != NULL))
break;
if (linebuf[0] != escape || value("interactive") == NULL) {
if (putline(collf, linebuf) < 0)
if (linebuf[0] != escape || value("interactive") == NULL ||
lastlong) {
if (putline(collf, linebuf, !longline) < 0)
goto err;
continue;
}
@ -182,7 +192,7 @@ collect(hp, printheaders)
* Otherwise, it's an error.
*/
if (c == escape) {
if (putline(collf, &linebuf[1]) < 0)
if (putline(collf, &linebuf[1], !longline) < 0)
goto err;
else
break;
@ -298,9 +308,11 @@ collect(hp, printheaders)
(void)fflush(stdout);
lc = 0;
cc = 0;
while (readline(fbuf, linebuf, LINESIZE) >= 0) {
lc++;
if ((t = putline(collf, linebuf)) < 0) {
while ((rc = readline(fbuf, linebuf, LINESIZE)) >= 0) {
if (rc != LINESIZE - 1)
lc++;
if ((t = putline(collf, linebuf,
rc != LINESIZE - 1)) < 0) {
(void)Fclose(fbuf);
goto err;
}
@ -388,13 +400,13 @@ collect(hp, printheaders)
if (collf != NULL)
rewind(collf);
noreset--;
(void)sigblock(sigmask(SIGINT) | sigmask(SIGHUP));
(void)sigprocmask(SIG_BLOCK, &nset, NULL);
(void)signal(SIGINT, saveint);
(void)signal(SIGHUP, savehup);
(void)signal(SIGTSTP, savetstp);
(void)signal(SIGTTOU, savettou);
(void)signal(SIGTTIN, savettin);
(void)sigsetmask(omask);
(void)sigprocmask(SIG_UNBLOCK, &nset, NULL);
return (collf);
}
@ -576,10 +588,13 @@ collstop(s)
int s;
{
sig_t old_action = signal(s, SIG_DFL);
sigset_t nset;
(void)sigsetmask(sigblock(0) & ~sigmask(s));
(void)sigemptyset(&nset);
(void)sigaddset(&nset, s);
(void)sigprocmask(SIG_UNBLOCK, &nset, NULL);
(void)kill(0, s);
(void)sigblock(sigmask(s));
(void)sigprocmask(SIG_BLOCK, &nset, NULL);
(void)signal(s, old_action);
if (colljmp_p) {
colljmp_p = 0;

View File

@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)def.h 8.2 (Berkeley) 3/21/94
* @(#)def.h 8.4 (Berkeley) 4/20/95
*
* $FreeBSD$
*/

View File

@ -30,7 +30,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)extern.h 8.1 (Berkeley) 6/6/93
* @(#)extern.h 8.2 (Berkeley) 4/20/95
*
* $FreeBSD$
*/
@ -147,6 +147,8 @@ int igcomp __P((const void *, const void *));
int igfield __P((char *[]));
int ignore1 __P((char *[], struct ignoretab *, const char *));
int igshow __P((struct ignoretab *, const char *));
int inc __P((void *));
int incfile __P((void));
void intr __P((int));
int isdate __P((char []));
int isdir __P((char []));
@ -163,7 +165,7 @@ struct var *
int mail __P((struct name *,
struct name *, struct name *, struct name *, char *, char *));
void mail1 __P((struct header *, int));
void makemessage __P((FILE *));
void makemessage __P((FILE *, int));
void mark __P((int));
int markall __P((char [], int));
int matchsender __P((char *, int));
@ -175,19 +177,19 @@ void mespipe __P((FILE *, char []));
int messize __P((int *));
int metamess __P((int, int));
int more __P((int *));
int newfileinfo __P((void));
int newfileinfo __P((int));
int next __P((int *));
int null __P((int));
void parse __P((char [], struct headline *, char []));
int pcmdlist __P((void));
int pdot __P((void));
void prepare_child __P((int, int, int));
void prepare_child __P((sigset_t *, int, int));
int preserve __P((int *));
void prettyprint __P((struct name *));
void printgroup __P((char []));
void printhead __P((int));
int puthead __P((struct header *, FILE *, int));
int putline __P((FILE *, char *));
int putline __P((FILE *, char *, int));
int pversion __P((int));
void quit __P((void));
int quitcmd __P((void));
@ -199,7 +201,8 @@ int respond __P((int *));
int retfield __P((char *[]));
int rexit __P((int));
int rm __P((char *));
int run_command __P((char *, int, int, int, char *, char *, char *));
int run_command __P((char *, sigset_t *, int, int, char *, char *,
char *));
int save __P((char []));
int save1 __P((char [], int, const char *, struct ignoretab *));
void savedeadletter __P((FILE *));
@ -211,12 +214,13 @@ void scaninit __P((void));
int schdir __P((char **));
int screensize __P((void));
int scroll __P((char []));
int sendmessage __P((struct message *, FILE *, struct ignoretab *, char *));
int sendmessage __P((struct message *, FILE *, struct ignoretab *,
char *));
int sendmail __P((char *));
int set __P((char **));
int setfile __P((char *));
void setmsize __P((int));
void setptr __P((FILE *));
void setptr __P((FILE *, off_t));
void setscreensize __P((void));
int shell __P((char *));
void sigchild __P((int));
@ -224,7 +228,8 @@ void sort __P((char **));
int source __P((char **));
void spreserve __P((void));
void sreset __P((void));
int start_command __P((char *, int, int, int, char *, char *, char *));
int start_command __P((char *, sigset_t *, int, int, char *, char *,
char *));
void statusput __P((struct message *, FILE *, char *));
void stop __P((int));
int stouch __P((int []));

View File

@ -33,7 +33,7 @@
#ifndef lint
#if 0
static char sccsid[] = "@(#)fio.c 8.1 (Berkeley) 6/6/93";
static char sccsid[] = "@(#)fio.c 8.2 (Berkeley) 4/20/95";
#endif
static const char rcsid[] =
"$FreeBSD$";
@ -60,16 +60,17 @@ extern int wait_status;
* Set up the input pointers while copying the mail file into /tmp.
*/
void
setptr(ibuf)
setptr(ibuf, offset)
FILE *ibuf;
off_t offset;
{
int c, count;
char *cp, *cp2;
struct message this;
FILE *mestmp;
off_t offset;
int maybe, inhead;
char linebuf[LINESIZE], pathbuf[PATHSIZE];
int omsgCount;
/* Get temporary file. */
(void)snprintf(pathbuf, sizeof(pathbuf), "%s/mail.XXXXXXXXXX", tmpdir);
@ -77,10 +78,23 @@ setptr(ibuf)
err(1, "can't open %s", pathbuf);
(void)rm(pathbuf);
msgCount = 0;
if (offset == 0) {
msgCount = 0;
} else {
/* Seek into the file to get to the new messages */
(void)fseek(ibuf, offset, SEEK_SET);
/*
* We need to make "offset" a pointer to the end of
* the temp file that has the copy of the mail file.
* If any messages have been edited, this will be
* different from the offset into the mail file.
*/
(void)fseek(otf, 0L, SEEK_END);
offset = ftell(otf);
}
omsgCount = msgCount;
maybe = 1;
inhead = 0;
offset = 0;
this.m_flag = MUSED|MNEW;
this.m_size = 0;
this.m_lines = 0;
@ -90,7 +104,7 @@ setptr(ibuf)
if (fgets(linebuf, sizeof(linebuf), ibuf) == NULL) {
if (append(&this, mestmp))
errx(1, "temporary file");
makemessage(mestmp);
makemessage(mestmp, omsgCount);
return;
}
count = strlen(linebuf);
@ -150,21 +164,25 @@ setptr(ibuf)
/*
* Drop the passed line onto the passed output buffer.
* If a write error occurs, return -1, else the count of
* characters written, including the newline.
* characters written, including the newline if requested.
*/
int
putline(obuf, linebuf)
putline(obuf, linebuf, outlf)
FILE *obuf;
char *linebuf;
int outlf;
{
int c;
c = strlen(linebuf);
(void)fwrite(linebuf, sizeof(*linebuf), c, obuf);
fprintf(obuf, "\n");
if (outlf) {
fprintf(obuf, "\n");
c++;
}
if (ferror(obuf))
return (-1);
return (c + 1);
return (c);
}
/*
@ -212,20 +230,27 @@ setinput(mp)
* a dynamically allocated message structure.
*/
void
makemessage(f)
makemessage(f, omsgCount)
FILE *f;
int omsgCount;
{
int size = (msgCount + 1) * sizeof(struct message);
size_t size;
struct message *nmessage;
if (message != 0)
(void)free(message);
if ((message = malloc((unsigned)size)) == NULL)
err(1, "Out of memory");
dot = message;
size -= sizeof(struct message);
size = (msgCount + 1) * sizeof(struct message);
nmessage = (struct message *)realloc(message, size);
if (nmessage == NULL)
errx(1, "Insufficient memory for %d messages\n",
msgCount);
if (omsgCount == 0 || message == NULL)
dot = nmessage;
else
dot = nmessage + (dot - message);
message = nmessage;
size -= (omsgCount + 1) * sizeof(struct message);
(void)fflush(f);
(void)lseek(fileno(f), (off_t)sizeof(*message), 0);
if (read(fileno(f), (char *)message, size) != size)
if (read(fileno(f), (char *)&message[omsgCount], size) != size)
errx(1, "Message temporary file corrupted");
message[msgCount].m_size = 0;
message[msgCount].m_lines = 0;
@ -263,7 +288,7 @@ rm(name)
}
static int sigdepth; /* depth of holdsigs() */
static int omask;
static sigset_t nset, oset;
/*
* Hold signals SIGHUP, SIGINT, and SIGQUIT.
*/
@ -271,8 +296,13 @@ void
holdsigs()
{
if (sigdepth++ == 0)
omask = sigblock(sigmask(SIGHUP)|sigmask(SIGINT)|sigmask(SIGQUIT));
if (sigdepth++ == 0) {
(void)sigemptyset(&nset);
(void)sigaddset(&nset, SIGHUP);
(void)sigaddset(&nset, SIGINT);
(void)sigaddset(&nset, SIGQUIT);
(void)sigprocmask(SIG_BLOCK, &nset, &oset);
}
}
/*
@ -283,7 +313,7 @@ relsesigs()
{
if (--sigdepth == 0)
(void)sigsetmask(omask);
(void)sigprocmask(SIG_SETMASK, &oset, NULL);
}
/*

View File

@ -33,7 +33,7 @@
#ifndef lint
#if 0
static char sccsid[] = "@(#)head.c 8.1 (Berkeley) 6/6/93";
static char sccsid[] = "@(#)head.c 8.2 (Berkeley) 4/20/95";
#endif
static const char rcsid[] =
"$FreeBSD$";

View File

@ -33,7 +33,7 @@
#ifndef lint
#if 0
static char sccsid[] = "@(#)lex.c 8.1 (Berkeley) 6/6/93";
static char sccsid[] = "@(#)lex.c 8.2 (Berkeley) 4/20/95";
#endif
static const char rcsid[] =
"$FreeBSD$";
@ -68,7 +68,7 @@ setfile(name)
FILE *ibuf;
int i, fd;
struct stat stb;
char isedit = *name != '%';
char isedit = *name != '%' || getuserid(myname) != getuid();
char *who = name[1] ? name + 1 : myname;
char tempname[PATHSIZE];
static int shudclob;
@ -136,8 +136,14 @@ setfile(name)
err(1, "%s", tempname);
(void)fcntl(fileno(itf), F_SETFD, 1);
(void)rm(tempname);
setptr(ibuf);
setptr(ibuf, 0);
setmsize(msgCount);
/*
* New mail may have arrived while we were reading
* the mail file, so reset mailsize to be where
* we really are in the file...
*/
mailsize = ftell(ibuf);
(void)Fclose(ibuf);
relsesigs();
sawcom = 0;
@ -149,6 +155,36 @@ setfile(name)
return (0);
}
/*
* Incorporate any new mail that has arrived since we first
* started reading mail.
*/
int
incfile()
{
int newsize;
int omsgCount = msgCount;
FILE *ibuf;
ibuf = Fopen(mailname, "r");
if (ibuf == NULL)
return (-1);
holdsigs();
newsize = fsize(ibuf);
if (newsize == 0)
return (-1); /* mail box is now empty??? */
if (newsize < mailsize)
return (-1); /* mail box has shrunk??? */
if (newsize == mailsize)
return (0); /* no new mail */
setptr(ibuf, mailsize);
setmsize(msgCount);
mailsize = ftell(ibuf);
(void)Fclose(ibuf);
relsesigs();
return (msgCount - omsgCount);
}
int *msgvec;
int reset_on_stop; /* do a reset() if stopped */
@ -178,6 +214,8 @@ commands()
* string space, and flush the output.
*/
if (!sourcing && value("interactive") != NULL) {
if ((value("autoinc") != NULL) && (incfile() > 0))
printf("New mail has arrived.\n");
reset_on_stop = 1;
printf("%s", prompt);
}
@ -411,6 +449,8 @@ execute(linebuf, contxt)
unstack();
return (0);
}
if (com == NULL)
return (0);
if (value("autoprint") != NULL && com->c_argtype & P)
if ((dot->m_flag & MDELETED) == 0) {
muvec[0] = dot - &message[0] + 1;
@ -431,7 +471,7 @@ setmsize(sz)
int sz;
{
if (msgvec != 0)
if (msgvec != NULL)
(void)free(msgvec);
msgvec = calloc((unsigned)(sz + 1), sizeof(*msgvec));
}
@ -523,10 +563,13 @@ stop(s)
int s;
{
sig_t old_action = signal(s, SIG_DFL);
sigset_t nset;
(void)sigsetmask(sigblock(0) & ~sigmask(s));
(void)sigemptyset(&nset);
(void)sigaddset(&nset, s);
(void)sigprocmask(SIG_UNBLOCK, &nset, NULL);
(void)kill(0, s);
(void)sigblock(sigmask(s));
(void)sigprocmask(SIG_BLOCK, &nset, NULL);
(void)signal(s, old_action);
if (reset_on_stop) {
reset_on_stop = 0;
@ -556,7 +599,7 @@ announce()
{
int vec[2], mdot;
mdot = newfileinfo();
mdot = newfileinfo(0);
vec[0] = mdot;
vec[1] = 0;
dot = &message[mdot - 1];
@ -572,23 +615,24 @@ announce()
* Return a likely place to set dot.
*/
int
newfileinfo()
newfileinfo(omsgCount)
int omsgCount;
{
struct message *mp;
int u, n, mdot, d, s;
char fname[PATHSIZE+1], zname[PATHSIZE+1], *ename;
for (mp = &message[0]; mp < &message[msgCount]; mp++)
for (mp = &message[omsgCount]; mp < &message[msgCount]; mp++)
if (mp->m_flag & MNEW)
break;
if (mp >= &message[msgCount])
for (mp = &message[0]; mp < &message[msgCount]; mp++)
for (mp = &message[omsgCount]; mp < &message[msgCount]; mp++)
if ((mp->m_flag & MREAD) == 0)
break;
if (mp < &message[msgCount])
mdot = mp - &message[0] + 1;
else
mdot = 1;
mdot = omsgCount + 1;
s = d = 0;
for (mp = &message[0], n = 0, u = 0; mp < &message[msgCount]; mp++) {
if (mp->m_flag & MNEW)

View File

@ -33,7 +33,7 @@
#ifndef lint
#if 0
static char sccsid[] = "@(#)list.c 8.2 (Berkeley) 4/19/94";
static char sccsid[] = "@(#)list.c 8.4 (Berkeley) 5/1/95";
#endif
static const char rcsid[] =
"$FreeBSD$";
@ -686,6 +686,49 @@ matchsender(str, mesg)
return (*cp == '\0');
}
/*
* See if the passed name received the passed message number. Return true
* if so.
*/
static char *to_fields[] = { "to", "cc", "bcc", NULL };
int
matchto(str, mesg)
char *str;
int mesg;
{
struct message *mp;
char *cp, *cp2, *backup, **to;
str++;
/* null string matches nothing instead of everything */
if (*str == '\0')
return (0);
mp = &message[mesg - 1];
for (to = to_fields; *to != NULL; to++) {
cp = str;
cp2 = hfield(*to, mp);
if (cp2 != NULL) {
backup = cp2;
while (*cp2 != '\0') {
if (*cp == '\0')
return (1);
if (toupper(*cp++) != toupper(*cp2++)) {
cp2 = ++backup;
cp = str;
}
}
if (*cp == '\0')
return (1);
}
}
return (0);
}
/*
* See if the given string matches inside the subject field of the
* given message. For the purpose of the scan, we ignore case differences.
@ -715,8 +758,11 @@ matchsubj(str, mesg)
*/
if (value("searchheaders") && (cp = strchr(str, ':')) != NULL) {
/* Check for special case "/To:" */
if (strncasecmp(str, "To:", 3) == 0)
return (matchto(cp, mesg));
*cp++ = '\0';
cp2 = hfield(str, mp);
cp2 = hfield(*str != '\0' ? str : "subject", mp);
cp[-1] = ':';
str = cp;
} else {

View File

@ -29,14 +29,15 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
.\" @(#)mail.1 8.2 (Berkeley) 12/30/93
.\" @(#)mail.1 8.8 (Berkeley) 4/28/95
.\" $FreeBSD$
.\"
.Dd December 30, 1993
.Dd April 28, 1995
.Dt MAIL 1
.Os
.Sh NAME
.Nm mail
.Nm mail ,
.Nm Mail
.Nd send and receive mail
.Sh SYNOPSIS
.Nm
@ -174,7 +175,7 @@ and
moving backwards and forwards, and
simple numbers.
.Pp
.Ss Disposing of mail.
.Ss Disposing of mail
After examining a message you can
.Ic delete
.Pq Ic d
@ -219,7 +220,7 @@ which prints the first few lines of a message could be used in
.Dq Li top \&*
to print the first few lines of all messages.
.Pp
.Ss Replying to or originating mail.
.Ss Replying to or originating mail
You can use the
.Ic reply
command to
@ -245,7 +246,7 @@ message or to a shell to run some commands.
(These options
are given in the summary below.)
.Pp
.Ss Ending a mail processing session.
.Ss Ending a mail processing session
You can end a
.Nm
session with the
@ -260,7 +261,7 @@ Unexamined messages go back to the post office.
.Fl f
option above).
.Pp
.Ss Personal and system wide distribution lists.
.Ss Personal and system wide distribution lists
It is also possible to create a personal distribution lists so that,
for instance, you can send mail to
.Dq Li cohorts
@ -293,7 +294,7 @@ System wide
are not expanded when the mail is sent,
but any reply returned to the machine will have the system wide
alias expanded as all mail goes through
.Xr sendmail .
.Xr sendmail 8 .
.Pp
.Ss Network mail (ARPA, UUCP, Berknet)
See
@ -392,7 +393,7 @@ listed on the
list.
If the
.Ic alternates
command is given with no argument, the current set of alternate
command is given with no argument, the current set of alternative
names is displayed.
.It Ic chdir
.Pq Ic c
@ -505,13 +506,17 @@ If
.Ic ignore
is executed with no arguments, it lists the current set of
ignored fields.
.It Ic inc
Incorporate any new messages that have arrived while mail
is being read.
The new messages are added to the end of the message list,
and the current message is reset to be the first new mail message.
This does not renumber the existing message list, nor does
does it cause any changes made so far to be saved.
.It Ic mail
.Pq Ic m
Takes as argument login names and distribution group names and sends
mail to those people.
.It Ic more
.Pq Ic \&mo
Takes a list of messages and invokes the pager on that list.
.It Ic mbox
Indicate that a list of messages be sent to
.Ic mbox
@ -522,10 +527,12 @@ action for messages if you do
have the
.Ic hold
option set.
.It Ic more
.Pq Ic \&mo
Takes a list of messages and invokes the pager on that list.
.It Ic next
.Pq Ic n
.Ic ( n ,
like
(
.Ic \&+
or
.Tn CR )
@ -572,14 +579,14 @@ A synonym for
.Ic reply .
.It Ic retain
Add the list of header fields named to the
.Ar retained list
Only the header fields in the retain list
.Em "retained list" .
Only the header fields in the retained list
are shown on your terminal when you print a message.
All other header fields are suppressed.
The
.Ic Type
.Ic type
and
.Ic Print
.Ic print
commands can be used to print a message in its entirety.
If
.Ic retain
@ -788,11 +795,11 @@ Cause the named string to become the current subject field.
.It Ic \&~\&t Ns Ar name ...
Add the given names to the direct recipient list.
.It Ic \&~\&v
Invoke an alternate editor (defined by the
Invoke an alternative editor (defined by the
.Ev VISUAL
option) on the
message collected so far.
Usually, the alternate editor will be a
Usually, the alternative editor will be a
screen editor.
After you quit the editor, you may resume appending
text to the end of your message.
@ -838,17 +845,28 @@ to be appended to the end rather than prepended.
This should always be set (preferably in one of the system-wide
.Pa mail.rc
files).
.It Ar ask
.It Ar ask , asksub
Causes
.Nm
to prompt you for the subject of each message you send.
If
you respond with simply a newline, no subject field will be sent.
.It Ar askbcc
Causes you to be prompted for additional blind carbon copy recipients at the
end of each message.
Responding with a newline indicates your
satisfaction with the current list.
.It Ar askcc
Causes you to be prompted for additional carbon copy recipients at the
end of each message.
Responding with a newline indicates your
satisfaction with the current list.
.It Ar autoinc
Causes new mail to be automatically incorporated when it arrives.
Setting this is similar to issuing the
.Ic inc
command at each prompt, except that the current message is not
reset when new mail arrives.
.It Ar autoprint
Causes the
.Ic delete
@ -921,9 +939,38 @@ commands.
.It Ar quiet
Suppresses the printing of the version when first invoked.
.It Ar searchheaders
If this option is set, then a message-list specifier in the form ``/x:y''
will expand to all messages containing the substring ``y'' in the header
field ``x''. The string search is case insensitive.
If this option is set, then a message-list specifier in the form
.Dq Li / Ns Ar x Ns Li : Ns Ar y
will expand to all messages containing the substring
.Dq Ar y
in the header field
.Dq Ar x .
The string search is case insensitive.
If
.Dq Ar x
is ommitted, it will default to the
.Dq Li Subject
header field.
The form
.Dq Li /to: Ns Ar y
is a special case, and will expand
to all messages containing the substring
.Dq Ar y
in the
.Dq Li To ,
.Dq Li Cc
or
.Dq Li Bcc
header fields.
The check for
.Qq Li "to"
is case sensitive, so that
.Dq Li /to: Ns Ar y
can be used to limit the search for
.Dq Ar y
to just the
.Dq Li To:
field.
.It Ar verbose
Setting the option
.Ar verbose
@ -963,7 +1010,7 @@ If set, will be used to initialize the Reply-To field for outgoing
messages.
.It Ev SHELL
Pathname of the shell to use in the
.Ic !\&
.Ic \&!
command and the
.Ic \&~!
escape.
@ -1040,6 +1087,9 @@ Post office.
User's old mail.
.It Pa ~/.mailrc
File giving initial mail commands.
This can be overridden by setting the
.Ev MAILRC
environment variable.
.It Pa /tmp/R*
Temporary files.
.It Pa /usr/share/misc/mail.*help
@ -1081,3 +1131,9 @@ Usually,
is just a link to
.Nm Mail ,
which can be confusing.
.Pp
The name of the
.Ic alternates
list is incorrect English (it should be
.Dq alternatives ) ,
but is retained for compatibility.

View File

@ -39,7 +39,7 @@ static char copyright[] =
#ifndef lint
#if 0
static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/6/93";
static char sccsid[] = "@(#)main.c 8.2 (Berkeley) 4/20/95";
#endif
static const char rcsid[] =
"$FreeBSD$";
@ -67,7 +67,7 @@ main(argc, argv)
int i;
struct name *to, *cc, *bcc, *smopts;
char *subject, *replyto;
char *ef;
char *ef, *rc;
char nosrc = 0;
sig_t prevint;
@ -228,7 +228,9 @@ Usage: %s [-EiInv] [-s subject] [-c cc-addr] [-b bcc-addr] to-addr ...\n\
* Expand returns a savestr, but load only uses the file name
* for fopen, so it's safe to do this.
*/
load(expand("~/.mailrc"));
if ((rc = getenv("MAILRC")) == NULL)
rc = "~/.mailrc";
load(expand(rc));
replyto = value("REPLYTO");
if (!rcvmode) {
@ -290,16 +292,16 @@ hdrstop(signo)
void
setscreensize()
{
struct termios tbuf;
struct winsize ws;
struct termios tio;
speed_t speed = 0;
speed_t speed;
if (ioctl(1, TIOCGWINSZ, (char *)&ws) < 0)
ws.ws_col = ws.ws_row = 0;
if (tcgetattr(1, &tio) != -1)
speed = cfgetospeed(&tio);
if (speed <= 0)
if (tcgetattr(1, &tbuf) < 0)
speed = B9600;
else
speed = cfgetospeed(&tbuf);
if (speed < B1200)
screenheight = 9;
else if (speed == B1200)

View File

@ -296,6 +296,7 @@ outof(names, fo, hp)
if (ispipe) {
int pid;
char *sh;
sigset_t nset;
/*
* XXX
@ -306,9 +307,12 @@ outof(names, fo, hp)
*/
if ((sh = value("SHELL")) == NULL)
sh = _PATH_CSHELL;
pid = start_command(sh,
sigmask(SIGHUP)|sigmask(SIGINT)|sigmask(SIGQUIT),
image, -1, "-c", fname, NULL);
(void)sigemptyset(&nset);
(void)sigaddset(&nset, SIGHUP);
(void)sigaddset(&nset, SIGINT);
(void)sigaddset(&nset, SIGQUIT);
pid = start_command(sh, &nset, image, -1, "-c", fname,
NULL);
if (pid < 0) {
senderr++;
goto cant;

View File

@ -110,6 +110,7 @@ Popen(cmd, mode)
int p[2];
int myside, hisside, fd0, fd1;
int pid;
sigset_t nset;
FILE *fp;
if (pipe(p) < 0)
@ -125,7 +126,8 @@ Popen(cmd, mode)
hisside = fd0 = p[READ];
fd1 = -1;
}
if ((pid = start_command(cmd, 0, fd0, fd1, NULL, NULL, NULL)) < 0) {
(void)sigemptyset(&nset);
if ((pid = start_command(cmd, &nset, fd0, fd1, NULL, NULL, NULL)) < 0) {
(void)close(p[READ]);
(void)close(p[WRITE]);
return (NULL);
@ -141,14 +143,17 @@ Pclose(ptr)
FILE *ptr;
{
int i;
int omask;
sigset_t nset, oset;
i = file_pid(ptr);
unregister_file(ptr);
(void)fclose(ptr);
omask = sigblock(sigmask(SIGINT)|sigmask(SIGHUP));
(void)sigemptyset(&nset);
(void)sigaddset(&nset, SIGINT);
(void)sigaddset(&nset, SIGHUP);
(void)sigprocmask(SIG_BLOCK, &nset, &oset);
i = wait_child(i);
(void)sigsetmask(omask);
(void)sigprocmask(SIG_SETMASK, &oset, NULL);
return (i);
}
@ -219,7 +224,8 @@ file_pid(fp)
int
run_command(cmd, mask, infd, outfd, a0, a1, a2)
char *cmd;
int mask, infd, outfd;
sigset_t *mask;
int infd, outfd;
char *a0, *a1, *a2;
{
int pid;
@ -233,7 +239,8 @@ run_command(cmd, mask, infd, outfd, a0, a1, a2)
int
start_command(cmd, mask, infd, outfd, a0, a1, a2)
char *cmd;
int mask, infd, outfd;
sigset_t *mask;
int infd, outfd;
char *a0, *a1, *a2;
{
int pid;
@ -259,10 +266,12 @@ start_command(cmd, mask, infd, outfd, a0, a1, a2)
}
void
prepare_child(mask, infd, outfd)
int mask, infd, outfd;
prepare_child(nset, infd, outfd)
sigset_t *nset;
int infd, outfd;
{
int i;
sigset_t eset;
/*
* All file descriptors other than 0, 1, and 2 are supposed to be
@ -272,12 +281,13 @@ prepare_child(mask, infd, outfd)
dup2(infd, 0);
if (outfd >= 0)
dup2(outfd, 1);
for (i = 1; i <= NSIG; i++)
if (mask & sigmask(i))
for (i = 1; i < NSIG; i++)
if (nset != NULL && sigismember(nset, i))
(void)signal(i, SIG_IGN);
if ((mask & sigmask(SIGINT)) == 0)
if (nset == NULL || !sigismember(nset, SIGINT))
(void)signal(SIGINT, SIG_DFL);
(void)sigsetmask(0);
(void)sigemptyset(&eset);
(void)sigprocmask(SIG_SETMASK, &eset, NULL);
}
int
@ -353,14 +363,18 @@ int
wait_child(pid)
int pid;
{
int mask = sigblock(sigmask(SIGCHLD));
sigset_t nset, oset;
struct child *cp = findchild(pid);
(void)sigemptyset(&nset);
(void)sigaddset(&nset, SIGCHLD);
(void)sigprocmask(SIG_BLOCK, &nset, &oset);
while (!cp->done)
sigpause(mask);
(void)sigsuspend(&oset);
wait_status = cp->status;
delchild(cp);
(void)sigsetmask(mask);
(void)sigprocmask(SIG_SETMASK, &oset, NULL);
return ((WIFEXITED(wait_status) && WEXITSTATUS(wait_status)) ? -1 : 0);
}
@ -371,12 +385,16 @@ void
free_child(pid)
int pid;
{
int mask = sigblock(sigmask(SIGCHLD));
sigset_t nset, oset;
struct child *cp = findchild(pid);
(void)sigemptyset(&nset);
(void)sigaddset(&nset, SIGCHLD);
(void)sigprocmask(SIG_BLOCK, &nset, &oset);
if (cp->done)
delchild(cp);
else
cp->free = 1;
(void)sigsetmask(mask);
(void)sigprocmask(SIG_SETMASK, &oset, NULL);
}

View File

@ -33,7 +33,7 @@
#ifndef lint
#if 0
static char sccsid[] = "@(#)quit.c 8.1 (Berkeley) 6/6/93";
static char sccsid[] = "@(#)quit.c 8.2 (Berkeley) 4/28/95";
#endif
static const char rcsid[] =
"$FreeBSD$";
@ -274,8 +274,8 @@ quit()
c = getc(ibuf);
}
(void)Fclose(ibuf);
(void)fflush(obuf);
}
(void)fflush(obuf);
trunc(obuf);
if (ferror(obuf)) {
warn("%s", mbox);

View File

@ -315,9 +315,12 @@ mail1(hp, printheaders)
if ((mtf = collect(hp, printheaders)) == NULL)
return;
if (value("interactive") != NULL) {
if (value("askcc") != NULL)
grabh(hp, GCC);
else {
if (value("askcc") != NULL || value("askbcc") != NULL) {
if (value("askcc") != NULL)
grabh(hp, GCC);
if (value("askbcc") != NULL)
grabh(hp, GBCC);
} else {
printf("EOT\n");
(void)fflush(stdout);
}
@ -380,9 +383,15 @@ mail1(hp, printheaders)
goto out;
}
if (pid == 0) {
prepare_child(sigmask(SIGHUP)|sigmask(SIGINT)|sigmask(SIGQUIT)|
sigmask(SIGTSTP)|sigmask(SIGTTIN)|sigmask(SIGTTOU),
fileno(mtf), -1);
sigset_t nset;
(void)sigemptyset(&nset);
(void)sigaddset(&nset, SIGHUP);
(void)sigaddset(&nset, SIGINT);
(void)sigaddset(&nset, SIGQUIT);
(void)sigaddset(&nset, SIGTSTP);
(void)sigaddset(&nset, SIGTTIN);
(void)sigaddset(&nset, SIGTTOU);
prepare_child(&nset, fileno(mtf), -1);
if ((cp = value("sendmail")) != NULL)
cp = expand(cp);
else
@ -414,6 +423,9 @@ fixhead(hp, tolist)
hp->h_cc = NULL;
hp->h_bcc = NULL;
for (np = tolist; np != NULL; np = np->n_flink)
/* Don't copy deleted addresses to the header */
if (np->n_type & GDEL)
continue;
if ((np->n_type & GMASK) == GTO)
hp->h_to =
cat(hp->h_to, nalloc(np->n_name, np->n_type));

View File

@ -33,7 +33,7 @@
#ifndef lint
#if 0
static char sccsid[] = "@(#)tty.c 8.1 (Berkeley) 6/6/93";
static char sccsid[] = "@(#)tty.c 8.2 (Berkeley) 6/6/93";
#endif
static const char rcsid[] =
"$FreeBSD$";
@ -48,8 +48,8 @@ static const char rcsid[] =
#include "rcv.h"
#include "extern.h"
static int c_erase; /* Current erase char */
static int c_kill; /* Current kill char */
static cc_t c_erase; /* Current erase char */
static cc_t c_kill; /* Current kill char */
static jmp_buf rewrite; /* Place to go when continued */
static jmp_buf intjmp; /* Place to go when interrupted */
#ifndef TIOCSTI
@ -65,15 +65,19 @@ grabh(hp, gflags)
struct header *hp;
int gflags;
{
struct termios tio;
struct termios ttybuf;
sig_t saveint;
#ifndef TIOCSTI
sig_t savequit;
#endif
sig_t savetstp;
sig_t savettou;
sig_t savettin;
int errs;
#ifndef TIOCSTI
sig_t savequit;
#else
# ifdef TIOCEXT
int extproc, flag;
# endif /* TIOCEXT */
#endif /* TIOCSTI */
savetstp = signal(SIGTSTP, SIG_DFL);
savettou = signal(SIGTTOU, SIG_DFL);
@ -82,20 +86,28 @@ grabh(hp, gflags)
#ifndef TIOCSTI
ttyset = 0;
#endif
if (tcgetattr(fileno(stdin), &tio) < 0) {
if (tcgetattr(fileno(stdin), &ttybuf) < 0) {
warn("tcgetattr(stdin)");
return (-1);
}
c_erase = tio.c_cc[VERASE];
c_kill = tio.c_cc[VKILL];
c_erase = ttybuf.c_cc[VERASE];
c_kill = ttybuf.c_cc[VKILL];
#ifndef TIOCSTI
tio.c_cc[VERASE] = 0;
tio.c_cc[VKILL] = 0;
ttybuf.c_cc[VERASE] = _POSIX_VDISABLE;
ttybuf.c_cc[VKILL] = _POSIX_VDISABLE;
if ((saveint = signal(SIGINT, SIG_IGN)) == SIG_DFL)
(void)signal(SIGINT, SIG_DFL);
if ((savequit = signal(SIGQUIT, SIG_IGN)) == SIG_DFL)
(void)signal(SIGQUIT, SIG_DFL);
#else
# ifdef TIOCEXT
extproc = ((ttybuf.c_lflag & EXTPROC) ? 1 : 0);
if (extproc) {
flag = 0;
if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0)
warn("TIOCEXT: off");
}
# endif /* TIOCEXT */
if (setjmp(intjmp))
goto out;
saveint = signal(SIGINT, ttyint);
@ -103,7 +115,7 @@ grabh(hp, gflags)
if (gflags & GTO) {
#ifndef TIOCSTI
if (!ttyset && hp->h_to != NULL)
ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &tio);
ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
#endif
hp->h_to =
extract(readtty("To: ", detract(hp->h_to, 0)), GTO);
@ -111,14 +123,14 @@ grabh(hp, gflags)
if (gflags & GSUBJECT) {
#ifndef TIOCSTI
if (!ttyset && hp->h_subject != NULL)
ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &tio);
ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
#endif
hp->h_subject = readtty("Subject: ", hp->h_subject);
}
if (gflags & GCC) {
#ifndef TIOCSTI
if (!ttyset && hp->h_cc != NULL)
ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &tio);
ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
#endif
hp->h_cc =
extract(readtty("Cc: ", detract(hp->h_cc, 0)), GCC);
@ -126,7 +138,7 @@ grabh(hp, gflags)
if (gflags & GBCC) {
#ifndef TIOCSTI
if (!ttyset && hp->h_bcc != NULL)
ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &tio);
ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
#endif
hp->h_bcc =
extract(readtty("Bcc: ", detract(hp->h_bcc, 0)), GBCC);
@ -136,11 +148,19 @@ grabh(hp, gflags)
(void)signal(SIGTTOU, savettou);
(void)signal(SIGTTIN, savettin);
#ifndef TIOCSTI
tio.c_cc[VERASE] = c_erase;
tio.c_cc[VKILL] = c_kill;
ttybuf.c_cc[VERASE] = c_erase;
ttybuf.c_cc[VKILL] = c_kill;
if (ttyset)
tcsetattr(fileno(stdin), TCSADRAIN, &tio);
tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
(void)signal(SIGQUIT, savequit);
#else
# ifdef TIOCEXT
if (extproc) {
flag = 1;
if (ioctl(fileno(stdin), TIOCEXT, &flag) < 0)
warn("TIOCEXT: on");
}
# endif /* TIOCEXT */
#endif
(void)signal(SIGINT, saveint);
return (errs);
@ -178,7 +198,8 @@ readtty(pr, src)
#else
cp = src == NULL ? "" : src;
while ((c = *cp++) != '\0') {
if (c == c_erase || c == c_kill) {
if ((c_erase != _POSIX_VDISABLE && c == c_erase) ||
(c_kill != _POSIX_VDISABLE && c == c_kill)) {
ch = '\\';
ioctl(0, TIOCSTI, &ch);
}
@ -222,7 +243,7 @@ readtty(pr, src)
return (strlen(canonb) > 0 ? savestr(canonb) : NULL);
while (*cp != '\0') {
c = *cp++;
if (c == c_erase) {
if (c_erase != _POSIX_VDISABLE && c == c_erase) {
if (cp2 == canonb)
continue;
if (cp2[-1] == '\\') {
@ -232,7 +253,7 @@ readtty(pr, src)
cp2--;
continue;
}
if (c == c_kill) {
if (c_kill != _POSIX_VDISABLE && c == c_kill) {
if (cp2 == canonb)
continue;
if (cp2[-1] == '\\') {
@ -259,10 +280,13 @@ ttystop(s)
int s;
{
sig_t old_action = signal(s, SIG_DFL);
sigset_t nset;
(void)sigsetmask(sigblock(0) & ~sigmask(s));
(void)kill(0, s);
(void)sigblock(sigmask(s));
(void)sigemptyset(&nset);
(void)sigaddset(&nset, s);
(void)sigprocmask(SIG_BLOCK, &nset, NULL);
kill(0, s);
(void)sigprocmask(SIG_UNBLOCK, &nset, NULL);
(void)signal(s, old_action);
longjmp(rewrite, 1);
}