aboutsummaryrefslogtreecommitdiffstats
path: root/mail_cmds
diff options
context:
space:
mode:
authorCameron Katri <me@cameronkatri.com>2021-05-09 14:20:58 -0400
committerCameron Katri <me@cameronkatri.com>2021-05-09 14:20:58 -0400
commit5fd83771641d15c418f747bd343ba6738d3875f7 (patch)
tree5abf0f78f680d9837dbd93d4d4c3933bb7509599 /mail_cmds
downloadapple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.tar.gz
apple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.tar.zst
apple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.zip
Import macOS userland
adv_cmds-176 basic_cmds-55 bootstrap_cmds-116.100.1 developer_cmds-66 diskdev_cmds-667.40.1 doc_cmds-53.60.1 file_cmds-321.40.3 mail_cmds-35 misc_cmds-34 network_cmds-606.40.1 patch_cmds-17 remote_cmds-63 shell_cmds-216.60.1 system_cmds-880.60.2 text_cmds-106
Diffstat (limited to 'mail_cmds')
-rw-r--r--mail_cmds/Makefile5
-rw-r--r--mail_cmds/biff/Makefile10
-rw-r--r--mail_cmds/biff/biff.1127
-rw-r--r--mail_cmds/biff/biff.c117
-rw-r--r--mail_cmds/comsat/Makefile11
-rw-r--r--mail_cmds/comsat/comsat.8115
-rw-r--r--mail_cmds/comsat/comsat.c314
-rw-r--r--mail_cmds/comsat/comsat.plist29
-rw-r--r--mail_cmds/from/Makefile10
-rw-r--r--mail_cmds/from/from.199
-rw-r--r--mail_cmds/from/from.c173
-rw-r--r--mail_cmds/mail/Makefile24
-rw-r--r--mail_cmds/mail/USD.doc/Makefile12
-rw-r--r--mail_cmds/mail/USD.doc/mail0.nr71
-rw-r--r--mail_cmds/mail/USD.doc/mail1.nr92
-rw-r--r--mail_cmds/mail/USD.doc/mail2.nr617
-rw-r--r--mail_cmds/mail/USD.doc/mail3.nr133
-rw-r--r--mail_cmds/mail/USD.doc/mail4.nr437
-rw-r--r--mail_cmds/mail/USD.doc/mail5.nr1042
-rw-r--r--mail_cmds/mail/USD.doc/mail6.nr125
-rw-r--r--mail_cmds/mail/USD.doc/mail7.nr107
-rw-r--r--mail_cmds/mail/USD.doc/mail8.nr75
-rw-r--r--mail_cmds/mail/USD.doc/mail9.nr203
-rw-r--r--mail_cmds/mail/USD.doc/maila.nr33
-rw-r--r--mail_cmds/mail/aux.c635
-rw-r--r--mail_cmds/mail/cmd1.c487
-rw-r--r--mail_cmds/mail/cmd2.c587
-rw-r--r--mail_cmds/mail/cmd3.c840
-rw-r--r--mail_cmds/mail/cmdtab.c133
-rw-r--r--mail_cmds/mail/collect.c998
-rw-r--r--mail_cmds/mail/def.h283
-rw-r--r--mail_cmds/mail/edit.c231
-rw-r--r--mail_cmds/mail/extern.h268
-rw-r--r--mail_cmds/mail/fio.c475
-rw-r--r--mail_cmds/mail/getname.c77
-rw-r--r--mail_cmds/mail/glob.h112
-rw-r--r--mail_cmds/mail/head.c291
-rw-r--r--mail_cmds/mail/lex.c736
-rw-r--r--mail_cmds/mail/list.c843
-rw-r--r--mail_cmds/mail/mail.11272
-rw-r--r--mail_cmds/mail/mailx.11
-rw-r--r--mail_cmds/mail/main.c395
-rw-r--r--mail_cmds/mail/misc/mail.help23
-rw-r--r--mail_cmds/mail/misc/mail.rc2
-rw-r--r--mail_cmds/mail/misc/mail.tildehelp36
-rw-r--r--mail_cmds/mail/names.c793
-rw-r--r--mail_cmds/mail/pathnames.h47
-rw-r--r--mail_cmds/mail/popen.c402
-rw-r--r--mail_cmds/mail/quit.c505
-rw-r--r--mail_cmds/mail/rcv.h52
-rw-r--r--mail_cmds/mail/send.c629
-rw-r--r--mail_cmds/mail/strings.c131
-rw-r--r--mail_cmds/mail/strlcpy.c74
-rw-r--r--mail_cmds/mail/temp.c94
-rw-r--r--mail_cmds/mail/tty.c306
-rw-r--r--mail_cmds/mail/v7.local.c101
-rw-r--r--mail_cmds/mail/vars.c196
-rw-r--r--mail_cmds/mail/version.c48
-rw-r--r--mail_cmds/msgs/Makefile11
-rw-r--r--mail_cmds/msgs/msgs.1236
-rw-r--r--mail_cmds/msgs/msgs.c923
-rw-r--r--mail_cmds/msgs/pathnames.h40
62 files changed, 17294 insertions, 0 deletions
diff --git a/mail_cmds/Makefile b/mail_cmds/Makefile
new file mode 100644
index 0000000..127d0a7
--- /dev/null
+++ b/mail_cmds/Makefile
@@ -0,0 +1,5 @@
+Project = mail_cmds
+
+SubProjects = biff comsat from mail msgs
+
+include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make
diff --git a/mail_cmds/biff/Makefile b/mail_cmds/biff/Makefile
new file mode 100644
index 0000000..2672505
--- /dev/null
+++ b/mail_cmds/biff/Makefile
@@ -0,0 +1,10 @@
+Project = biff
+Install_Dir = /usr/bin
+
+CFILES = biff.c
+MANPAGES = biff.1
+
+Extra_CC_Flags = -Wall -Werror -mdynamic-no-pic
+Extra_LD_Flags = -dead_strip
+
+include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make
diff --git a/mail_cmds/biff/biff.1 b/mail_cmds/biff/biff.1
new file mode 100644
index 0000000..05e8162
--- /dev/null
+++ b/mail_cmds/biff/biff.1
@@ -0,0 +1,127 @@
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)biff.1 8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/biff/biff.1,v 1.19 2002/08/16 03:08:25 johan Exp $
+.\"
+.Dd July 9, 2002
+.Dt BIFF 1
+.Os
+.Sh NAME
+.Nm biff
+.Nd "be notified if mail arrives and who it is from"
+.Sh SYNOPSIS
+.Nm
+.Op Cm n | y | b
+.Sh DESCRIPTION
+The
+.Nm
+utility informs the system whether you want to be notified on your terminal
+when mail arrives.
+.Pp
+Affected is the first terminal associated with the standard input,
+standard output or standard error file descriptor, in that order.
+Thus, it is possible to use the redirection facilities of a shell to
+toggle the notification for other terminals than the one
+.Nm
+runs on.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Cm n
+Disable notification.
+.It Cm y
+Enable header notification.
+.It Cm b
+Enable bell notification.
+.El
+.Pp
+When header notification is enabled, the header and first few lines of
+the message will be printed on your terminal whenever mail arrives.
+A
+.Dq Li biff y
+command is often included in the file
+.Pa \&.login
+or
+.Pa \&.profile
+to be executed at each login.
+.Pp
+When bell notification is enabled, only two bell characters
+.Tn ( ASCII
+\\007)
+will be printed on your terminal whenever mail arrives.
+.Pp
+If no arguments are given,
+.Nm
+displays the present notification status of the terminal to the
+standard output.
+.Pp
+The
+.Nm
+utility operates asynchronously.
+For synchronous notification use the
+.Ev MAIL
+variable of
+.Xr sh 1
+or the
+.Ev mail
+variable of
+.Xr csh 1 .
+.Sh DIAGNOSTICS
+The
+.Nm
+utility exits with one of the following values:
+.Bl -tag -width indent
+.It 0
+Notification is enabled.
+.It 1
+Notification is disabled.
+.It >1
+An error occurred.
+.El
+.Sh COMPATIBILITY
+Previous versions of the
+.Nm
+utility affected the terminal attached to standard error without first
+trying the standard input or output devices.
+.Sh SEE ALSO
+.Xr csh 1 ,
+.Xr mail 1 ,
+.Xr sh 1 ,
+.Xr comsat 8
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.0 .
+It was named after the dog of Heidi Stettner.
+He died
+in August 1993, at 15.
diff --git a/mail_cmds/biff/biff.c b/mail_cmds/biff/biff.c
new file mode 100644
index 0000000..444e2c7
--- /dev/null
+++ b/mail_cmds/biff/biff.c
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1980, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)biff.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif
+
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD: src/usr.bin/biff/biff.c,v 1.18 2002/07/24 18:54:59 robert Exp $");
+
+#include <sys/stat.h>
+
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ struct stat sb;
+ int ch;
+ char *name;
+
+
+ while ((ch = getopt(argc, argv, "")) != -1)
+ switch(ch) {
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if ((name = ttyname(STDIN_FILENO)) == NULL &&
+ (name = ttyname(STDOUT_FILENO)) == NULL &&
+ (name = ttyname(STDERR_FILENO)) == NULL)
+ err(2, "unknown tty");
+
+ if (stat(name, &sb))
+ err(2, "stat");
+
+ if (*argv == NULL) {
+ (void)printf("is %s\n",
+ sb.st_mode & S_IXUSR ? "y" :
+ sb.st_mode & S_IXGRP ? "b" : "n");
+ return (sb.st_mode & (S_IXUSR | S_IXGRP) ? 0 : 1);
+
+ }
+
+ switch (argv[0][0]) {
+ case 'n':
+ if (chmod(name, sb.st_mode & ~(S_IXUSR | S_IXGRP)) < 0)
+ err(2, "%s", name);
+ break;
+ case 'y':
+ if (chmod(name, (sb.st_mode & ~(S_IXUSR | S_IXGRP)) | S_IXUSR)
+ < 0)
+ err(2, "%s", name);
+ break;
+ case 'b':
+ if (chmod(name, (sb.st_mode & ~(S_IXUSR | S_IXGRP)) | S_IXGRP)
+ < 0)
+ err(2, "%s", name);
+ break;
+ default:
+ usage();
+ }
+ return (sb.st_mode & (S_IXUSR | S_IXGRP) ? 0 : 1);
+}
+
+static void
+usage()
+{
+ (void)fprintf(stderr, "usage: biff [n | y | b]\n");
+ exit(2);
+}
diff --git a/mail_cmds/comsat/Makefile b/mail_cmds/comsat/Makefile
new file mode 100644
index 0000000..fd52e66
--- /dev/null
+++ b/mail_cmds/comsat/Makefile
@@ -0,0 +1,11 @@
+Project = comsat
+Install_Dir = /usr/libexec
+
+CFILES = comsat.c
+MANPAGES = comsat.8
+LAUNCHD_PLISTS = comsat.plist
+
+Extra_CC_Flags = -Wall -Werror -mdynamic-no-pic
+Extra_LD_Flags = -dead_strip
+
+include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make
diff --git a/mail_cmds/comsat/comsat.8 b/mail_cmds/comsat/comsat.8
new file mode 100644
index 0000000..2f73c78
--- /dev/null
+++ b/mail_cmds/comsat/comsat.8
@@ -0,0 +1,115 @@
+.\" $NetBSD: comsat.8,v 1.6 1998/07/04 19:38:39 mrg Exp $
+.\"
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" from: @(#)comsat.8 8.1 (Berkeley) 6/4/93
+.\"
+.Dd June 4, 1993
+.Dt COMSAT 8
+.Os BSD 4.2
+.Sh NAME
+.Nm comsat
+.Nd biff server
+.Sh SYNOPSIS
+.Nm
+.Op Fl l
+.Sh DESCRIPTION
+.Nm
+is the server process which receives reports of incoming mail
+and notifies users if they have requested this service.
+.Nm
+receives messages on a datagram port associated with the
+.Dq biff
+service
+specification (see
+.Xr services 5
+and
+.Xr inetd 8 ) .
+The one line messages are of the form:
+.Pp
+.Dl user@mailbox-offset
+.Pp
+If the
+.Em user
+specified is logged in to the system and the associated terminal has
+the owner execute bit turned on (by a
+.Dq Li biff y ) ,
+the
+.Em offset
+is used as a seek offset into the appropriate mailbox file and
+the first 7 lines or 560 characters of the message are printed
+on the user's terminal. Lines which appear to be part of
+the message header other than the
+.Dq From ,
+.Dq \&To ,
+.Dq Date ,
+or
+.Dq Subject
+lines are not included in the displayed message.
+.Sh OPTIONS
+The
+.Nm
+program supports this option:
+.Bl -tag -width 12345
+.It Fl l
+The
+.Fl l
+option turns on
+.Xr syslogd 8
+log messages.
+.El
+.Sh FILES
+.Bl -tag -width /var/run/utmpx -compact
+.It Pa /var/run/utmpx
+to find out who's logged on and on what terminals
+.El
+.Sh SEE ALSO
+.Xr biff 1 ,
+.Xr inetd 8 ,
+.Xr syslogd 8 .
+.Sh BUGS
+The message header filtering is prone to error.
+The density of the information presented is near the theoretical minimum.
+.Pp
+Users should be notified of mail which arrives on other
+machines than the one to which they are currently logged in.
+.Pp
+The notification should appear in a separate window so it
+does not mess up the screen.
+.Pp
+.Nm
+runs as root so that it can open the users maildrop.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
diff --git a/mail_cmds/comsat/comsat.c b/mail_cmds/comsat/comsat.c
new file mode 100644
index 0000000..62ac5d5
--- /dev/null
+++ b/mail_cmds/comsat/comsat.c
@@ -0,0 +1,314 @@
+/* $NetBSD: comsat.c,v 1.14 1998/07/06 06:47:38 mrg Exp $ */
+
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1980, 1993\n\
+ The Regents of the University of California. All rights reserved.\n");
+#if 0
+static char sccsid[] = "from: @(#)comsat.c 8.1 (Berkeley) 6/4/93";
+#else
+__RCSID("$NetBSD: comsat.c,v 1.14 1998/07/06 06:47:38 mrg Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <sys/wait.h>
+
+#include <netinet/in.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <paths.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <syslog.h>
+#include <termios.h>
+#include <time.h>
+#include <vis.h>
+#include <unistd.h>
+#include <utmpx.h>
+
+int logging;
+int debug = 0;
+#define dsyslog if (debug) syslog
+
+#define MAXIDLE 120
+
+char hostname[MAXHOSTNAMELEN+1];
+struct utmpx *utmpx = NULL;
+time_t lastmsgtime;
+int nutmpx, uf;
+
+void jkfprintf __P((FILE *, char[], off_t));
+void mailfor __P((char *));
+void notify __P((struct utmpx *, off_t));
+void onalrm __P((int));
+void reapchildren __P((int));
+int main __P((int, char *[]));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ struct sockaddr_in from;
+ int cc, ch;
+ socklen_t fromlen;
+ char msgbuf[100];
+ sigset_t sigset;
+ extern char *__progname;
+
+ /* verify proper invocation */
+ fromlen = sizeof(from);
+ if (getsockname(0, (struct sockaddr *)&from, &fromlen) < 0) {
+ (void)fprintf(stderr,
+ "comsat: getsockname: %s.\n", strerror(errno));
+ exit(1);
+ }
+
+ openlog("comsat", LOG_PID, LOG_DAEMON);
+ while ((ch = getopt(argc, argv, "l")) != -1)
+ switch (ch) {
+ case 'l':
+ logging = 1;
+ break;
+ default:
+ syslog(LOG_ERR, "usage: %s [-l]", __progname);
+ exit(1);
+ }
+ if (chdir(_PATH_MAILDIR)) {
+ syslog(LOG_ERR, "chdir: %s: %m", _PATH_MAILDIR);
+ (void)recv(0, msgbuf, sizeof(msgbuf) - 1, 0);
+ exit(1);
+ }
+ if ((uf = open(_PATH_UTMPX, O_RDONLY, 0)) < 0) {
+ syslog(LOG_ERR, "open: %s: %m", _PATH_UTMPX);
+ (void)recv(0, msgbuf, sizeof(msgbuf) - 1, 0);
+ exit(1);
+ }
+ (void)time(&lastmsgtime);
+ (void)gethostname(hostname, sizeof(hostname));
+ hostname[sizeof(hostname) - 1] = '\0';
+ onalrm(0);
+ (void)signal(SIGALRM, onalrm);
+ (void)signal(SIGTTOU, SIG_IGN);
+ (void)signal(SIGCHLD, reapchildren);
+ for (;;) {
+ cc = recv(0, msgbuf, sizeof(msgbuf) - 1, 0);
+ if (cc <= 0) {
+ if (errno != EINTR)
+ sleep(1);
+ errno = 0;
+ continue;
+ }
+ if (!nutmpx) /* no one has logged in yet */
+ continue;
+ sigemptyset(&sigset);
+ sigaddset(&sigset, SIGALRM);
+ sigprocmask(SIG_SETMASK, &sigset, NULL);
+ msgbuf[cc] = '\0';
+ (void)time(&lastmsgtime);
+ mailfor(msgbuf);
+ sigemptyset(&sigset);
+ sigprocmask(SIG_SETMASK, &sigset, NULL);
+ }
+}
+
+void
+reapchildren(signo)
+ int signo;
+{
+
+ while (wait3(NULL, WNOHANG, NULL) > 0);
+}
+
+void
+onalrm(signo)
+ int signo;
+{
+ static u_int utmpxsize; /* last malloced size for utmpx */
+ static time_t utmpxmtime; /* last modification time for utmpx */
+ struct stat statbf;
+
+ if (time(NULL) - lastmsgtime >= MAXIDLE)
+ exit(0);
+ (void)alarm((u_int)15);
+ (void)fstat(uf, &statbf);
+ if (statbf.st_mtime > utmpxmtime) {
+ utmpxmtime = statbf.st_mtime;
+ if (statbf.st_size > utmpxsize) {
+ utmpxsize = statbf.st_size + 10 * sizeof(struct utmpx);
+ if ((utmpx = realloc(utmpx, utmpxsize)) == NULL) {
+ syslog(LOG_ERR, "%s", strerror(errno));
+ exit(1);
+ }
+ }
+ /* the first record is just a signature, so it is skipped */
+ (void)lseek(uf, (off_t)sizeof(struct utmpx), SEEK_SET);
+ nutmpx = read(uf, utmpx, statbf.st_size - sizeof(struct utmpx))/sizeof(struct utmpx);
+ }
+}
+
+void
+mailfor(name)
+ char *name;
+{
+ struct utmpx *utp = &utmpx[nutmpx];
+ char *cp;
+ off_t offset;
+
+ if (!(cp = strchr(name, '@')))
+ return;
+ *cp = '\0';
+ offset = atoi(cp + 1);
+ while (--utp >= utmpx)
+ if (utp->ut_type == USER_PROCESS && !strncmp(utp->ut_user, name, sizeof(utp->ut_user)))
+ notify(utp, offset);
+}
+
+static char *cr;
+
+void
+notify(utp, offset)
+ struct utmpx *utp;
+ off_t offset;
+{
+ FILE *tp;
+ struct passwd *p;
+ struct stat stb;
+ struct termios ttybuf;
+ char tty[40], name[sizeof(utp->ut_user) + 1];
+
+ (void)snprintf(tty, sizeof(tty), "%s%.*s",
+ _PATH_DEV, (int)sizeof(utp->ut_line), utp->ut_line);
+ if (strchr(tty + sizeof(_PATH_DEV) - 1, '/')) {
+ /* A slash is an attempt to break security... */
+ /*
+ * XXX but what about something like "/dev/pts/5"
+ * that we may one day "support". ?
+ */
+ syslog(LOG_AUTH | LOG_NOTICE, "'/' in \"%s\"", tty);
+ return;
+ }
+ if (stat(tty, &stb) || !(stb.st_mode & S_IEXEC)) {
+ dsyslog(LOG_DEBUG, "%s: wrong mode on %s", utp->ut_user, tty);
+ return;
+ }
+ dsyslog(LOG_DEBUG, "notify %s on %s\n", utp->ut_user, tty);
+ if (fork())
+ return;
+ (void)signal(SIGALRM, SIG_DFL);
+ (void)alarm((u_int)30);
+ if ((tp = fopen(tty, "w")) == NULL) {
+ dsyslog(LOG_ERR, "%s: %s", tty, strerror(errno));
+ _exit(-1);
+ }
+ (void)tcgetattr(fileno(tp), &ttybuf);
+ cr = (ttybuf.c_oflag & ONLCR) && (ttybuf.c_oflag & OPOST) ?
+ "\n" : "\n\r";
+ (void)strncpy(name, utp->ut_user, sizeof(utp->ut_user));
+ name[sizeof(name) - 1] = '\0';
+
+ /* Set uid/gid/groups to users in case mail drop is on nfs */
+ if ((p = getpwnam(name)) == NULL ||
+ initgroups(p->pw_name, p->pw_gid) < 0 ||
+ setgid(p->pw_gid) < 0 ||
+ setuid(p->pw_uid) < 0)
+ _exit(-1);
+
+ if (logging)
+ syslog(LOG_INFO, "biff message for %s", name);
+
+ (void)fprintf(tp, "%s\007New mail for %s@%.*s\007 has arrived:%s----%s",
+ cr, name, (int)sizeof(hostname), hostname, cr, cr);
+ jkfprintf(tp, name, offset);
+ (void)fclose(tp);
+ _exit(0);
+}
+
+void
+jkfprintf(tp, name, offset)
+ FILE *tp;
+ char name[];
+ off_t offset;
+{
+ FILE *fi;
+ int linecnt, charcnt, inheader;
+ char line[BUFSIZ], visline[BUFSIZ*4];
+
+ if ((fi = fopen(name, "r")) == NULL)
+ return;
+
+ (void)fseek(fi, offset, SEEK_SET);
+ /*
+ * Print the first 7 lines or 560 characters of the new mail
+ * (whichever comes first). Skip header crap other than
+ * From, Subject, To, and Date.
+ */
+ linecnt = 7;
+ charcnt = 560;
+ inheader = 1;
+ while (fgets(line, sizeof(line), fi) != NULL) {
+ if (inheader) {
+ if (line[0] == '\n') {
+ inheader = 0;
+ continue;
+ }
+ if (line[0] == ' ' || line[0] == '\t' ||
+ (strncasecmp(line, "From:", 5) &&
+ strncasecmp(line, "Subject:", 8)))
+ continue;
+ }
+ if (linecnt <= 0 || charcnt <= 0) {
+ (void)fprintf(tp, "...more...%s", cr);
+ (void)fclose(fi);
+ return;
+ }
+ /* strip weird stuff so can't trojan horse stupid terminals */
+ (void)strvis(visline, line, VIS_CSTYLE);
+ fputs(visline, tp);
+ --linecnt;
+ }
+ (void)fprintf(tp, "----%s\n", cr);
+ (void)fclose(fi);
+}
diff --git a/mail_cmds/comsat/comsat.plist b/mail_cmds/comsat/comsat.plist
new file mode 100644
index 0000000..48b772a
--- /dev/null
+++ b/mail_cmds/comsat/comsat.plist
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>Disabled</key>
+ <true/>
+ <key>Label</key>
+ <string>com.apple.comsat</string>
+ <key>ProgramArguments</key>
+ <array>
+ <string>/usr/libexec/comsat</string>
+ </array>
+ <key>inetdCompatibility</key>
+ <dict>
+ <key>Wait</key>
+ <true/>
+ </dict>
+ <key>Sockets</key>
+ <dict>
+ <key>Listeners</key>
+ <dict>
+ <key>SockServiceName</key>
+ <string>comsat</string>
+ <key>SockType</key>
+ <string>dgram</string>
+ </dict>
+ </dict>
+</dict>
+</plist>
diff --git a/mail_cmds/from/Makefile b/mail_cmds/from/Makefile
new file mode 100644
index 0000000..b0c5bd7
--- /dev/null
+++ b/mail_cmds/from/Makefile
@@ -0,0 +1,10 @@
+Project = from
+Install_Dir = /usr/bin
+
+CFILES = from.c
+MANPAGES = from.1
+
+Extra_CC_Flags = -Wall -Werror -mdynamic-no-pic
+Extra_LD_Flags = -dead_strip
+
+include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make
diff --git a/mail_cmds/from/from.1 b/mail_cmds/from/from.1
new file mode 100644
index 0000000..af26bfd
--- /dev/null
+++ b/mail_cmds/from/from.1
@@ -0,0 +1,99 @@
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)from.1 8.2 (Berkeley) 12/30/93
+.\" $FreeBSD: src/usr.bin/from/from.1,v 1.14 2002/07/15 06:15:38 keramida Exp $
+.\"
+.Dd December 30, 1993
+.Dt FROM 1
+.Os
+.Sh NAME
+.Nm from
+.Nd print names of those who have sent mail
+.Sh SYNOPSIS
+.Nm
+.Op Fl c
+.Op Fl s Ar sender
+.Op Fl f Ar file
+.Op Ar user
+.Sh DESCRIPTION
+The
+.Nm
+utility prints
+out the mail header lines from the invoker's mailbox.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl c
+Just print a count of messages and exit.
+.It Fl f Ar file
+The supplied file
+is examined instead of the invoker's mailbox.
+If the
+.Fl f
+option is used, the
+.Ar user
+argument should not be used.
+Read from standard input if file name
+.Ar -
+is given.
+.It Fl s Ar sender
+Only mail from addresses containing
+the
+supplied string are printed.
+.El
+.Pp
+If
+.Ar user
+is given, the
+.Ar user Ns 's
+mailbox is examined instead of the invoker's own mailbox.
+(Privileges are required.)
+.Sh ENVIRONMENT
+.Bl -tag -width Fl
+.It Ev MAIL
+If set, the location of the invoker's mailbox.
+Otherwise, the default in
+.Pa /var/mail
+is used.
+.El
+.Sh FILES
+.Bl -tag -width /var/mail/* -compact
+.It Pa /var/mail/*
+.El
+.Sh SEE ALSO
+.Xr biff 1 ,
+.Xr mail 1
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 3.0 .
diff --git a/mail_cmds/from/from.c b/mail_cmds/from/from.c
new file mode 100644
index 0000000..ac85c54
--- /dev/null
+++ b/mail_cmds/from/from.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 1980, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static const char copyright[] =
+"@(#) Copyright (c) 1980, 1988, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)from.c 8.1 (Berkeley) 6/6/93";
+#endif
+#endif /* not lint */
+#include <sys/cdefs.h>
+__RCSID("$FreeBSD: src/usr.bin/from/from.c,v 1.14 2002/09/04 23:29:00 dwmalone Exp $");
+
+#include <sys/types.h>
+#include <ctype.h>
+#include <err.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <paths.h>
+#include <string.h>
+#include <unistd.h>
+
+int match(const char *, const char *);
+static void usage(void);
+
+int
+main(int argc, char **argv)
+{
+ FILE *mbox;
+ struct passwd *pwd;
+ int ch, count, newline;
+ const char *file;
+ char *sender, *p;
+#if MAXPATHLEN > BUFSIZ
+ char buf[MAXPATHLEN];
+#else
+ char buf[BUFSIZ];
+#endif
+
+ file = sender = NULL;
+ count = -1;
+ while ((ch = getopt(argc, argv, "cf:s:")) != -1)
+ switch (ch) {
+ case 'c':
+ count = 0;
+ break;
+ case 'f':
+ file = optarg;
+ break;
+ case 's':
+ sender = optarg;
+ for (p = sender; *p; ++p)
+ if (isupper(*p))
+ *p = tolower(*p);
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (file == NULL) {
+ if (argc) {
+ (void)snprintf(buf, sizeof(buf), "%s/%s", _PATH_MAILDIR, *argv);
+ file = buf;
+ } else {
+ if (!(file = getenv("MAIL"))) {
+ if (!(pwd = getpwuid(getuid())))
+ errx(1, "no password file entry for you");
+ file = pwd->pw_name;
+ (void)snprintf(buf, sizeof(buf),
+ "%s/%s", _PATH_MAILDIR, file);
+ file = buf;
+ }
+ }
+ }
+
+ /* read from stdin */
+ if (strcmp(file, "-") == 0) {
+ mbox = stdin;
+ }
+ else if ((mbox = fopen(file, "r")) == NULL) {
+ errx(1, "can't read %s", file);
+ }
+ for (newline = 1; fgets(buf, sizeof(buf), mbox);) {
+ if (*buf == '\n') {
+ newline = 1;
+ continue;
+ }
+ if (newline && !strncmp(buf, "From ", 5) &&
+ (!sender || match(buf + 5, sender))) {
+ if (count != -1)
+ count++;
+ else
+ printf("%s", buf);
+ }
+ newline = 0;
+ }
+ if (count != -1)
+ printf("There %s %d message%s in your incoming mailbox.\n",
+ count == 1 ? "is" : "are", count, count == 1 ? "" : "s");
+ fclose(mbox);
+ exit(0);
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: from [-c] [-f file] [-s sender] [user]\n");
+ exit(1);
+}
+
+int
+match(const char *line, const char *sender)
+{
+ char ch, pch, first;
+ const char *p, *t;
+
+ for (first = *sender++;;) {
+ if (isspace(ch = *line))
+ return(0);
+ ++line;
+ if (isupper(ch))
+ ch = tolower(ch);
+ if (ch != first)
+ continue;
+ for (p = sender, t = line;;) {
+ if (!(pch = *p++))
+ return(1);
+ if (isupper(ch = *t++))
+ ch = tolower(ch);
+ if (ch != pch)
+ break;
+ }
+ }
+ /* NOTREACHED */
+}
diff --git a/mail_cmds/mail/Makefile b/mail_cmds/mail/Makefile
new file mode 100644
index 0000000..bd82ec4
--- /dev/null
+++ b/mail_cmds/mail/Makefile
@@ -0,0 +1,24 @@
+Project = mail
+Install_Dir = /usr/bin
+
+CFILES = aux.c cmd1.c cmd2.c cmd3.c cmdtab.c collect.c \
+ edit.c fio.c getname.c head.c lex.c list.c main.c names.c\
+ popen.c quit.c send.c strings.c temp.c tty.c v7.local.c\
+ vars.c version.c
+MANPAGES = mail.1 mailx.1
+
+Extra_CC_Flags = -Wall -Werror -mdynamic-no-pic
+Extra_LD_Flags = -dead_strip
+
+include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make
+
+ETCDIR=$(DSTROOT)/private/etc
+MISCDIR=$(DSTROOT)/usr/share/misc
+
+after_install:
+ $(INSTALL_DIRECTORY) $(MISCDIR)
+ $(INSTALL_FILE) -c misc/mail.help misc/mail.tildehelp $(MISCDIR)
+ $(INSTALL_DIRECTORY) $(ETCDIR)
+ $(INSTALL_FILE) -c -m 644 misc/mail.rc $(ETCDIR)/mail.rc
+ $(LN) -f $(DSTROOT)$(Install_Dir)/mail \
+ $(DSTROOT)$(Install_Dir)/mailx
diff --git a/mail_cmds/mail/USD.doc/Makefile b/mail_cmds/mail/USD.doc/Makefile
new file mode 100644
index 0000000..4c96c7e
--- /dev/null
+++ b/mail_cmds/mail/USD.doc/Makefile
@@ -0,0 +1,12 @@
+# $NetBSD: Makefile,v 1.3 1997/12/21 15:48:30 christos Exp $
+# from: @(#)Makefile 8.1 (Berkeley) 6/8/93
+
+DIR= usd/07.mail
+SRCS= mail0.nr mail1.nr mail2.nr mail3.nr mail4.nr mail5.nr mail6.nr \
+ mail7.nr mail8.nr mail9.nr maila.nr
+MACROS= -me
+
+paper.ps: ${SRCS}
+ ${SOELIM} -I${.CURDIR} ${.ALLSRC} | ${TBL} | ${ROFF} > ${.TARGET}
+
+.include <bsd.doc.mk>
diff --git a/mail_cmds/mail/USD.doc/mail0.nr b/mail_cmds/mail/USD.doc/mail0.nr
new file mode 100644
index 0000000..15955be
--- /dev/null
+++ b/mail_cmds/mail/USD.doc/mail0.nr
@@ -0,0 +1,71 @@
+.\" Copyright (c) 1980, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mail0.nr 8.1 (Berkeley) 6/8/93
+.\"
+.eh 'USD:7-%''Mail Reference Manual'
+.oh 'Mail Reference Manual''USD:7-%'
+.if n \
+.nr fs .5v
+.\".he 'Mail Reference Manual'\n(mo/\n(dy/\n(yr'%'
+.tp
+.sp 1.0i
+.sz 12
+.rb
+.(l C
+MAIL REFERENCE MANUAL
+.)l
+.sz 10
+.sp 2
+.i
+.(l C
+Kurt Shoens
+.)l
+.r
+.(l C
+Revised by
+.)l
+.(l C
+.i
+Craig Leres\ \c
+.r
+and\ \c
+.i
+Mark Andrews
+.)l
+.r
+.(l C
+Version 5.5
+
+
+\*(td
+.)l
+.pn 2
diff --git a/mail_cmds/mail/USD.doc/mail1.nr b/mail_cmds/mail/USD.doc/mail1.nr
new file mode 100644
index 0000000..50e7883
--- /dev/null
+++ b/mail_cmds/mail/USD.doc/mail1.nr
@@ -0,0 +1,92 @@
+.\" Copyright (c) 1980, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mail1.nr 8.1 (Berkeley) 6/8/93
+.\"
+.sh 1 Introduction
+.pp
+.i Mail
+provides a simple and friendly environment for sending and receiving mail.
+It divides incoming mail into
+its constituent messages and allows the user to deal with them
+in any order. In addition, it provides a set of
+.i ed -\c
+like commands for manipulating messages and sending mail.
+.i Mail
+offers the user simple editing capabilities to ease the composition
+of outgoing messages, as well as providing the ability to define and send
+to names which address groups of users. Finally,
+.i Mail
+is able to send and receive messages across such networks as the
+ARPANET, UUCP, and Berkeley network.
+.pp
+This document describes how to use the
+.i Mail
+program to send and receive messages. The reader is not assumed to
+be familiar with other message handling systems, but should be
+familiar with the \s-2UNIX\s0\**
+.(f
+\** \s-1UNIX\s0 is a trademark of Bell Laboratories.
+.)f
+shell, the text editor, and some of the common \s-2UNIX\s0 commands.
+.q "The \s-2UNIX\s0 Programmer's Manual,"
+.q "An Introduction to Csh,"
+and
+.q "Text Editing with Ex and Vi"
+can be consulted for more information on these topics.
+.pp
+Here is how messages are handled:
+the mail system accepts incoming
+.i messages
+for you from other people
+and collects them in a file, called your
+.i "system mailbox" .
+When you login, the system notifies you if there are any messages
+waiting in your system mailbox. If you are a
+.i csh
+user, you will be notified when new mail arrives if you inform
+the shell of the location of your mailbox. On version 7 systems,
+your system mailbox is located in the directory /var/mail
+in a file with your login name. If your login name is
+.q sam,
+then you can make
+.i csh
+notify you of new mail by including the following line in your .cshrc
+file:
+.(l
+set mail=/var/mail/sam
+.)l
+When you read your mail using
+.i Mail ,
+it reads your system mailbox and separates that file into the
+individual messages that have been sent to you. You can then
+read, reply to, delete, or save these messages.
+Each message is marked with its author and the date they sent it.
diff --git a/mail_cmds/mail/USD.doc/mail2.nr b/mail_cmds/mail/USD.doc/mail2.nr
new file mode 100644
index 0000000..0419859
--- /dev/null
+++ b/mail_cmds/mail/USD.doc/mail2.nr
@@ -0,0 +1,617 @@
+.\" Copyright (c) 1980, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mail2.nr 8.1 (Berkeley) 6/8/93
+.\"
+.bp
+.sh 1 "Common usage"
+.pp
+The
+.i Mail
+command has two distinct usages, according to whether one
+wants to send or receive mail. Sending mail is simple: to send a
+message to a user whose login name is, say,
+\*(lqroot,\*(rq
+use the shell
+command:
+.(l
+% Mail root
+.)l
+then type your message. When you reach the end of the message, type
+an EOT (control\-d) at the beginning of a line, which will cause
+.i Mail
+to echo \*(lqEOT\*(rq and return you to the Shell. When the user you sent mail
+to next logs in, he will receive the message:
+.(l
+You have mail.
+.)l
+to alert him to the existence of your message.
+.pp
+If, while you are composing the message
+you decide that you do not wish to send it after all, you can
+abort the letter with a \s-2RUBOUT\s0. Typing a single \s-2RUBOUT\s0
+causes
+.i Mail
+to print
+.(l
+(Interrupt -- one more to kill letter)
+.)l
+Typing a second
+\s-2RUBOUT\s0 causes
+.i Mail
+to save your partial letter on the file
+.q dead.letter
+in your home directory and abort the letter.
+Once you have
+sent mail to someone, there is no way to undo the act, so be
+careful.
+.pp
+The message your recipient reads will consist of the message you
+typed, preceded by a line telling who sent the message (your login name)
+and the date and time it
+was sent.
+.pp
+If you want to send the same message to several other people, you can list
+their login names on the command line.
+Thus,
+.(l
+% Mail sam bob john
+Tuition fees are due next Friday. Don't forget!!
+<Control\-d>
+EOT
+%
+.)l
+will send the reminder to sam, bob, and john.
+.pp
+If, when you log in, you see the message,
+.(l
+You have mail.
+.)l
+you can read the mail by typing simply:
+.(l
+% Mail
+.)l
+.i Mail
+will respond by typing its version number and date and then listing
+the messages you have waiting. Then it will type a prompt and await
+your command. The messages are assigned numbers starting with 1 \*- you
+refer to the messages with these numbers.
+.i Mail
+keeps track of which messages are
+.i new
+(have been sent since you last read your mail) and
+.i read
+(have been read by you). New messages have an
+.b N
+next to them in the header listing and old, but unread messages have
+a
+.b U
+next to them.
+.i Mail
+keeps track of new/old and read/unread messages by putting a
+header field called
+.q Status
+into your messages.
+.pp
+To look at a specific message, use the
+.b type
+command, which may be abbreviated to simply
+.b t .
+For example, if you had the following messages:
+.(l
+N 1 root Wed Sep 21 09:21 "Tuition fees"
+N 2 sam Tue Sep 20 22:55
+.)l
+you could examine the first message by giving the command:
+.(l
+type 1
+.)l
+which might cause
+.i Mail
+to respond with, for example:
+.(l
+Message 1:
+From root Wed Sep 21 09:21:45 1978
+Subject: Tuition fees
+Status: R
+
+Tuition fees are due next Wednesday. Don't forget!!
+
+.)l
+Many
+.i Mail
+commands that operate on messages take a message number as an
+argument like the
+.b type
+command. For these commands, there is a notion of a current
+message. When you enter the
+.i Mail
+program, the current message is initially the first one. Thus,
+you can often omit the message number and use, for example,
+.(l
+t
+.)l
+to type the current message. As a further shorthand, you can type a message
+by simply giving its message number. Hence,
+.(l
+1
+.)l
+would type the first message.
+.pp
+Frequently, it is useful to read the messages in your mailbox in order,
+one after another. You can read the next message in
+.i Mail
+by simply typing a newline. As a special case, you can type a newline
+as your first command to
+.i Mail
+to type the first message.
+.pp
+If, after typing a message, you wish to immediately send a reply,
+you can do so with the
+.b reply
+command.
+.b Reply ,
+like
+.b type ,
+takes a message number as an argument.
+.i Mail
+then begins a message addressed to the user who sent you the message.
+You may then type in your letter in reply, followed by a <control-d>
+at the beginning of a line, as before.
+.i Mail
+will type EOT, then type the ampersand prompt to indicate its readiness
+to accept another command. In our example, if, after typing the
+first message, you wished to reply to it, you might give the command:
+.(l
+reply
+.)l
+.i Mail
+responds by typing:
+.(l
+To: root
+Subject: Re: Tuition fees
+.)l
+and waiting for you to enter your letter.
+You are now in the message collection mode described at the beginning
+of this section and
+.i Mail
+will gather up your message up to a control\-d.
+Note that it copies the subject
+header from the original message. This is useful in that correspondence
+about a particular matter will tend to retain the same subject heading,
+making it easy to recognize. If there are other header fields in
+the message, the information found will also be used.
+For example, if the letter had a
+.q "To:"
+header listing several recipients,
+.i Mail
+would arrange to send your replay to the same people as well.
+Similarly, if the original message contained a
+.q "Cc:"
+(carbon copies to) field,
+.i Mail
+would send your reply to
+.i those
+users, too.
+.i Mail
+is careful, though, not too send the message to
+.i you ,
+even if you appear in the
+.q "To:"
+or
+.q "Cc:"
+field, unless you ask to be included explicitly. See section 4 for more
+details.
+.pp
+After typing in your letter, the dialog with
+.i Mail
+might look like the following:
+.(l
+reply
+To: root
+Subject: Tuition fees
+
+Thanks for the reminder
+EOT
+&
+.)l
+.pp
+The
+.b reply
+command is especially useful for sustaining extended conversations
+over the message system, with other
+.q listening
+users receiving copies of the conversation. The
+.b reply
+command can be abbreviated to
+.b r .
+.pp
+Sometimes you will receive a message that has been sent to
+several people and wish to reply
+.i only
+to the person who sent it.
+.b Reply
+with a capital
+.b R
+replies to a message, but sends a copy to the sender only.
+.pp
+If you wish, while reading your mail, to send a message to someone,
+but not as a reply to one of your messages, you can send the message
+directly with the
+.b mail
+command, which takes as arguments the names of the recipients you wish
+to send to. For example, to send a message to
+.q frank,
+you would do:
+.(l
+mail frank
+This is to confirm our meeting next Friday at 4.
+EOT
+&
+.)l
+The
+.b mail
+command can be abbreviated to
+.b m .
+.pp
+Normally, each message you receive is saved in the file
+.i mbox
+in your login directory at the time you leave
+.i Mail .
+Often,
+however, you will not want to save a particular message you
+have received because it is only of passing interest. To avoid
+saving a message in
+.i mbox
+you can delete it using the
+.b delete
+command. In our example,
+.(l
+delete 1
+.)l
+will prevent
+.i Mail
+from saving message 1 (from root) in
+.i mbox .
+In addition to not saving deleted messages,
+.i Mail
+will not let
+you type them, either. The effect is to make the message disappear
+altogether, along with its number. The
+.b delete
+command can be abbreviated to simply
+.b d .
+.pp
+Many features of
+.i Mail
+can be tailored to your liking with the
+.b set
+command. The
+.b set
+command has two forms, depending on whether you are setting
+a
+.i binary
+option or a
+.i valued
+option.
+Binary options are either on or off. For example, the
+.q ask
+option informs
+.i Mail
+that each time you send a message, you want it to prompt you for
+a subject header, to be included in the message.
+To set the
+.q ask
+option, you would type
+.(l
+set ask
+.)l
+.pp
+Another useful
+.i Mail
+option is
+.q hold.
+Unless told otherwise,
+.i Mail
+moves the messages from your system mailbox to the file
+.i mbox
+in your home directory when you leave
+.i Mail .
+If you want
+.i Mail
+to keep your letters in the system mailbox instead, you can set the
+.q hold
+option.
+.pp
+Valued options are values which
+.i Mail
+uses to adapt to your tastes. For example, the
+.q SHELL
+option tells
+.i Mail
+which shell you like to use, and is specified by
+.(l
+set SHELL=/bin/csh
+.)l
+for example. Note that no spaces are allowed in
+.q "SHELL=/bin/csh."
+A complete list of the
+.i Mail
+options appears in section 5.
+.pp
+Another important valued option is
+.q crt.
+If you use a fast video terminal, you will find that when you
+print long messages, they fly by too quickly for you to read them.
+With the
+.q crt
+option, you can make
+.i Mail
+print any message larger than a given number of lines by sending
+it through a paging program. This program is specified by the
+valued option \fBPAGER\fP.
+If \fBPAGER\fP is not set, a default paginator is used.
+For example, most CRT users with 24-line screens should do:
+.(l
+set crt=24
+.)l
+to paginate messages that will not fit on their screens.
+In the default state, \fImore\fP (default paginator) prints a screenful of
+information, then types --More--. Type a space to see the next screenful.
+.pp
+Another adaptation to user needs that
+.i Mail
+provides is that of
+.i aliases .
+An alias is simply a name which stands for one or more
+real user names.
+.i Mail
+sent to an alias is really sent to the list of real users
+associated with it. For example, an alias can be defined for the
+members of a project, so that you can send mail to the whole project
+by sending mail to just a single name. The
+.b alias
+command in
+.i Mail
+defines an alias. Suppose that the users in a project are
+named Sam, Sally, Steve, and Susan. To define an alias called
+.q project
+for them, you would use the
+.i Mail
+command:
+.(l
+alias project sam sally steve susan
+.)l
+The
+.b alias
+command can also be used to provide a convenient name for someone
+whose user name is inconvenient. For example, if a user named
+.q "Bob Anderson"
+had the login name
+.q anderson,"
+you might want to use:
+.(l
+alias bob anderson
+.)l
+so that you could send mail to the shorter name,
+.q bob.
+.pp
+While the
+.b alias
+and
+.b set
+commands allow you to customize
+.i Mail ,
+they have the drawback that they must be retyped each time you enter
+.i Mail .
+To make them more convenient to use,
+.i Mail
+always looks for two files when it is invoked. It first reads
+a system wide file
+.q /etc/mail.rc,
+then a user specific file,
+.q .mailrc,
+which is found in the user's home directory.
+The system wide file
+is maintained by the system administrator and
+contains
+.b set
+commands that are applicable to all users of the system.
+The
+.q .mailrc
+file is usually used by each user to set options the way he likes
+and define individual aliases.
+For example, my .mailrc file looks like this:
+.(l
+set ask nosave SHELL=/bin/csh
+.)l
+As you can see, it is possible to set many options in the
+same
+.b set
+command. The
+.q nosave
+option is described in section 5.
+.pp
+Mail aliasing is implemented
+at the system-wide level
+by the mail delivery
+system
+.i sendmail .
+These aliases are stored in the file /usr/lib/aliases and are
+accessible to all users of the system.
+The lines in /usr/lib/aliases are of
+the form:
+.(l
+alias: name\*<1\*>, name\*<2\*>, name\*<3\*>
+.)l
+where
+.i alias
+is the mailing list name and the
+.i name\*<i\*>
+are the members of the list. Long lists can be continued onto the next
+line by starting the next line with a space or tab. Remember that you
+must execute the shell command
+.i newaliases
+after editing /usr/lib/aliases since the delivery system
+uses an indexed file created by
+.i newaliases .
+.pp
+We have seen that
+.i Mail
+can be invoked with command line arguments which are people
+to send the message to, or with no arguments to read mail.
+Specifying the
+.rb \-f
+flag on the command line causes
+.i Mail
+to read messages from a file other than your system mailbox.
+For example, if you have a collection of messages in
+the file
+.q letters
+you can use
+.i Mail
+to read them with:
+.(l
+% Mail \-f letters
+.)l
+You can use all
+the
+.i Mail
+commands described in this document to examine, modify, or delete
+messages from your
+.q letters
+file, which will be rewritten when you leave
+.i Mail
+with the
+.b quit
+command described below.
+.pp
+Since mail that you read is saved in the file
+.i mbox
+in your home directory by default, you can read
+.i mbox
+in your home directory by using simply
+.(l
+% Mail \-f
+.)l
+.pp
+Normally, messages that you examine using the
+.b type
+command are saved in the file
+.q mbox
+in your home directory if you leave
+.i Mail
+with the
+.b quit
+command described below.
+If you wish to retain a message in your system mailbox
+you can use the
+.b preserve
+command to tell
+.i Mail
+to leave it there.
+The
+.b preserve
+command accepts a list of message numbers, just like
+.b type
+and may be abbreviated to
+.b pre .
+.pp
+Messages in your system mailbox that you do not examine are
+normally retained in your system mailbox automatically.
+If you wish to have such a message saved in
+.i mbox
+without reading it, you may use the
+.b mbox
+command to have them so saved. For example,
+.(l
+mbox 2
+.)l
+in our example would cause the second message (from sam)
+to be saved in
+.i mbox
+when the
+.b quit
+command is executed.
+.b Mbox
+is also the way to direct messages to your
+.i mbox
+file if you have set the
+.q hold
+option described above.
+.b Mbox
+can be abbreviated to
+.b mb .
+.pp
+When you have perused all the messages of interest, you can leave
+.i Mail
+with the
+.b quit
+command, which saves the messages you have typed but not
+deleted in the file
+.i mbox
+in your login directory. Deleted messages are discarded irretrievably,
+and messages left untouched are preserved in your system mailbox so
+that you will see them the next time you type:
+.(l
+% Mail
+.)l
+The
+.b quit
+command can be abbreviated to simply
+.b q .
+.pp
+If you wish for some reason to leave
+.i Mail
+quickly without altering either your system mailbox or
+.i mbox ,
+you can type the
+.b x
+command (short for
+.b exit ),
+which will immediately return you to the Shell without changing anything.
+.pp
+If, instead, you want to execute a Shell command without leaving
+.i Mail ,
+you
+can type the command preceded by an exclamation point, just as in the
+text editor. Thus, for instance:
+.(l
+!date
+.)l
+will print the current date without leaving
+.i Mail .
+.pp
+Finally, the
+.b help
+command is available to print out a brief summary of the
+.i Mail
+commands, using only the single character command abbreviations.
diff --git a/mail_cmds/mail/USD.doc/mail3.nr b/mail_cmds/mail/USD.doc/mail3.nr
new file mode 100644
index 0000000..8b133ef
--- /dev/null
+++ b/mail_cmds/mail/USD.doc/mail3.nr
@@ -0,0 +1,133 @@
+.\" Copyright (c) 1980, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mail3.nr 8.1 (Berkeley) 6/8/93
+.\"
+.sh 1 "Maintaining folders"
+.pp
+.i Mail
+includes a simple facility for maintaining groups of messages together
+in folders. This section describes this facility.
+.pp
+To use the folder facility, you must tell
+.i Mail
+where you wish to keep your folders. Each folder of messages will
+be a single file. For convenience, all of your folders are kept in
+a single directory of your choosing. To tell
+.i Mail
+where your folder directory is, put a line of the form
+.(l
+set folder=letters
+.)l
+in your
+.i .mailrc
+file. If, as in the example above, your folder directory does not
+begin with a `/,'
+.i Mail
+will assume that your folder directory is to be found starting from
+your home directory. Thus, if your home directory is
+.b /home/person
+the above example told
+.i Mail
+to find your folder directory in
+.b /home/person/letters .
+.pp
+Anywhere a file name is expected, you can use a folder name, preceded
+with `+.' For example, to put a message into a folder with the
+.b save
+command, you can use:
+.(l
+save +classwork
+.)l
+to save the current message in the
+.i classwork
+folder. If the
+.i classwork
+folder does not yet exist, it will be created. Note that messages
+which are saved with the
+.b save
+command are automatically removed from your system mailbox.
+.pp
+In order to make a copy of a message in a folder without causing
+that message to be removed from your system mailbox, use the
+.b copy
+command, which is identical in all other respects to the
+.b save
+command. For example,
+.(l
+copy +classwork
+.)l
+copies the current message into the
+.i classwork
+folder and leaves a copy in your system mailbox.
+.pp
+The
+.b folder
+command
+can be used to direct
+.i Mail
+to the contents of a different folder.
+For example,
+.(l
+folder +classwork
+.)l
+directs
+.i Mail
+to read the contents of the
+.i classwork
+folder. All of the commands that you can use on your system
+mailbox are also applicable to folders, including
+.b type ,
+.b delete ,
+and
+.b reply .
+To inquire which folder you are currently editing, use simply:
+.(l
+folder
+.)l
+.pp
+To list your current set of folders, use the
+.b folders
+command.
+.pp
+To start
+.i Mail
+reading one of your folders, you can use the
+.b \-f
+option described in section 2. For example:
+.(l
+% Mail \-f +classwork
+.)l
+will cause
+.i Mail
+to read your
+.i classwork
+folder without looking at your system mailbox.
diff --git a/mail_cmds/mail/USD.doc/mail4.nr b/mail_cmds/mail/USD.doc/mail4.nr
new file mode 100644
index 0000000..1a1e046
--- /dev/null
+++ b/mail_cmds/mail/USD.doc/mail4.nr
@@ -0,0 +1,437 @@
+.\" Copyright (c) 1980, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mail4.nr 8.1 (Berkeley) 6/8/93
+.\"
+.bp
+.sh 1 "More about sending mail"
+.sh 2 "Tilde escapes"
+.pp
+While typing in a message to be sent to others, it is often
+useful to be able to invoke the text editor on the partial message,
+print the message, execute a shell command, or do some other
+auxiliary function.
+.i Mail
+provides these capabilities through
+.i "tilde escapes" ,
+which consist of a tilde (~) at the beginning of a line, followed by
+a single character which indicates the function to be performed. For
+example, to print the text of the message so far, use:
+.(l
+~p
+.)l
+which will print a line of dashes, the recipients of your message, and
+the text of the message so far.
+Since
+.i Mail
+requires two consecutive \s-2RUBOUT\s0's to abort a letter, you
+can use a single \s-2RUBOUT\s0 to abort the output of ~p or any other
+~ escape without killing your letter.
+.pp
+If you are dissatisfied with the message as
+it stands, you can invoke the text editor on it using the escape
+.(l
+~e
+.)l
+which causes the message to be copied into a temporary file and an
+instance of the editor to be spawned. After modifying the message to
+your satisfaction, write it out and quit the editor.
+.i Mail
+will respond
+by typing
+.(l
+(continue)
+.)l
+after which you may continue typing text which will be appended to your
+message, or type <control-d> to end the message.
+A standard text editor is provided by
+.i Mail .
+You can override this default by setting the valued option
+.q EDITOR
+to something else. For example, you might prefer:
+.(l
+set EDITOR=/usr/bin/ex
+.)l
+.pp
+Many systems offer a screen editor as an alternative to the standard
+text editor, such as the
+.i vi
+editor from UC Berkeley.
+To use the screen, or
+.i visual
+editor, on your current message, you can use the escape,
+.(l
+~v
+.)l
+~v works like ~e, except that the screen editor is invoked instead.
+A default screen editor is defined by
+.i Mail .
+If it does not suit you, you can set the valued option
+.q VISUAL
+to the path name of a different editor.
+.pp
+It is often useful to be able to include the contents of some
+file in your message; the escape
+.(l
+~r filename
+.)l
+is provided for this purpose, and causes the named file to be appended
+to your current message.
+.i Mail
+complains if the file doesn't exist
+or can't be read. If the read is successful, the number of lines and
+characters appended to your message is printed, after which you may continue
+appending text. The filename may contain shell metacharacters like * and ?
+which are expanded according to the conventions of your shell.
+.pp
+As a special case of ~r, the escape
+.(l
+~d
+.)l
+reads in the file
+.q dead.letter
+in your home directory. This is often useful since
+.i Mail
+copies the text
+of your message there when you abort a message with \s-2RUBOUT\s0.
+.pp
+To save the current text of your message on a file you may use the
+.(l
+~w filename
+.)l
+escape.
+.i Mail
+will print out the number of lines and characters written
+to the file, after which you may continue appending text to your message.
+Shell metacharacters may be used in the filename, as in ~r and are expanded
+with the conventions of your shell.
+.pp
+If you are sending mail from within
+.i Mail's
+command mode
+you can read a message sent to you into the message
+you are constructing with the escape:
+.(l
+~m 4
+.)l
+which will read message 4 into the current message, shifted right by
+one tab stop. You can name any non-deleted message, or list of messages.
+Messages can also be forwarded without shifting by a tab stop with ~f.
+This is the usual way to forward a message.
+.pp
+If, in the process of composing a message, you decide to add additional
+people to the list of message recipients, you can do so with the escape
+.(l
+~t name1 name2 ...
+.)l
+You may name as few or many additional recipients as you wish. Note
+that the users originally on the recipient list will still receive
+the message; you cannot remove someone from the recipient
+list with ~t.
+.pp
+If you wish, you can associate a subject with your message by using the
+escape
+.(l
+~s Arbitrary string of text
+.)l
+which replaces any previous subject with
+.q "Arbitrary string of text."
+The subject, if given, is sent near the
+top of the message prefixed with
+.q "Subject:"
+You can see what the message will look like by using ~p.
+.pp
+For political reasons, one occasionally prefers to list certain
+people as recipients of carbon copies of a message rather than
+direct recipients. The escape
+.(l
+~c name1 name2 ...
+.)l
+adds the named people to the
+.q "Cc:"
+list, similar to ~t.
+Again, you can execute ~p to see what the message will look like.
+.pp
+The escape
+.(l
+~b name1 name2 ...
+.)l
+adds the named people to the
+.q "Cc:"
+list, but does not make the names visible in the
+.q "Cc:"
+line ("blind" carbon copy).
+.pp
+The recipients of the message together constitute the
+.q "To:"
+field, the subject the
+.q "Subject:"
+field, and the carbon copies the
+.q "Cc:"
+field. If you wish to edit these in ways impossible with the ~t, ~s, ~c
+and ~b escapes, you can use the escape
+.(l
+~h
+.)l
+which prints
+.q "To:"
+followed by the current list of recipients and leaves the cursor
+(or printhead) at the end of the line. If you type in ordinary
+characters, they are appended to the end of the current list of
+recipients. You can also use your erase character to erase back into
+the list of recipients, or your kill character to erase them altogether.
+Thus, for example, if your erase and kill characters are the standard
+(on printing terminals) # and @ symbols,
+.(l
+~h
+To: root kurt####bill
+.)l
+would change the initial recipients
+.q "root kurt"
+to
+.q "root bill."
+When you type a newline,
+.i Mail
+advances to the
+.q "Subject:"
+field, where the same rules apply. Another newline brings you to
+the
+.q "Cc:"
+field, which may be edited in the same fashion. Another newline
+brings you to the
+.q "Bcc:"
+("blind" carbon copy) field, which follows the same rules as the "Cc:"
+field. Another newline
+leaves you appending text to the end of your message. You can use
+~p to print the current text of the header fields and the body
+of the message.
+.pp
+To effect a temporary escape to the shell, the escape
+.(l
+~!command
+.)l
+is used, which executes
+.i command
+and returns you to mailing mode without altering the text of
+your message. If you wish, instead, to filter the body of your
+message through a shell command, then you can use
+.(l
+~|command
+.)l
+which pipes your message through the command and uses the output
+as the new text of your message. If the command produces no output,
+.i Mail
+assumes that something is amiss and retains the old version
+of your message. A frequently-used filter is the command
+.i fmt ,
+designed to format outgoing mail.
+.pp
+To effect a temporary escape to
+.i Mail
+command mode instead, you can use the
+.(l
+~:\fIMail command\fP
+.)l
+escape. This is especially useful for retyping the message you are
+replying to, using, for example:
+.(l
+~:t
+.)l
+It is also useful for setting options and modifying aliases.
+.pp
+If you wish abort the current message, you can use the escape
+.(l
+~q
+.)l
+This will terminate the current message and return you to the
+shell (or \fIMail\fP if you were using the \fBmail\fP command).
+If the \fBsave\fP option is set, the message will be copied
+to the file
+.q dead.letter
+in your home directory.
+.pp
+If you wish (for some reason) to send a message that contains
+a line beginning with a tilde, you must double it. Thus, for example,
+.(l
+~~This line begins with a tilde.
+.)l
+sends the line
+.(l
+~This line begins with a tilde.
+.)l
+.pp
+Finally, the escape
+.(l
+~?
+.)l
+prints out a brief summary of the available tilde escapes.
+.pp
+On some terminals (particularly ones with no lower case)
+tilde's are difficult to type.
+.i Mail
+allows you to change the escape character with the
+.q escape
+option. For example, I set
+.(l
+set escape=]
+.)l
+and use a right bracket instead of a tilde. If I ever need to
+send a line beginning with right bracket, I double it, just as for ~.
+Changing the escape character removes the special meaning of ~.
+.sh 2 "Network access"
+.pp
+This section describes how to send mail to people on other machines.
+Recall that sending to a plain login name sends mail to that person
+on your machine. If your machine is directly (or sometimes, even,
+indirectly) connected to the Arpanet, you can send messages to people
+on the Arpanet using a name of the form
+.(l
+name@host.domain
+.)l
+where
+.i name
+is the login name of the person you're trying to reach,
+.i host
+is the name of the machine on the Arpanet,
+and
+.i domain
+is the higher-level scope within which the hostname is known, e.g. EDU (for educational
+institutions), COM (for commercial entities), GOV (for governmental agencies),
+ARPA for many other things, BITNET or CSNET for those networks.
+.pp
+If your recipient logs in on a machine connected to yours by
+UUCP (the Bell Laboratories supplied network that communicates
+over telephone lines), sending mail can be a bit more complicated.
+You must know the list of machines through which your message must
+travel to arrive at his site. So, if his machine is directly connected
+to yours, you can send mail to him using the syntax:
+.(l
+host!name
+.)l
+where, again,
+.i host
+is the name of the machine and
+.i name
+is the login name.
+If your message must go through an intermediary machine first, you
+must use the syntax:
+.(l
+intermediary!host!name
+.)l
+and so on. It is actually a feature of UUCP that the map of all
+the systems in the network is not known anywhere (except where people
+decide to write it down for convenience). Talk to your system administrator
+about good ways to get places; the
+.i uuname
+command will tell you systems whose names are recognized, but not which
+ones are frequently called or well-connected.
+.pp
+When you use the
+.b reply
+command to respond to a letter, there is a problem of figuring out the
+names of the users in the
+.q "To:"
+and
+.q "Cc:"
+lists
+.i "relative to the current machine" .
+If the original letter was sent to you by someone on the local machine,
+then this problem does not exist, but if the message came from a remote
+machine, the problem must be dealt with.
+.i Mail
+uses a heuristic to build the correct name for each user relative
+to the local machine. So, when you
+.b reply
+to remote mail, the names in the
+.q "To:"
+and
+.q "Cc:"
+lists may change somewhat.
+.sh 2 "Special recipients"
+.pp
+As described previously, you can send mail to either user names or
+.b alias
+names. It is also possible to send messages directly to files or to
+programs, using special conventions. If a recipient name has a
+`/' in it or begins with a `+', it is assumed to be the
+path name of a file into which
+to send the message. If the file already exists, the message is
+appended to the end of the file. If you want to name a file in
+your current directory (ie, one for which a `/' would not usually
+be needed) you can precede the name with `./'
+So, to send mail to the file
+.q memo
+in the current directory, you can give the command:
+.(l
+% Mail ./memo
+.)l
+If the name begins with a `+,' it is expanded into the full path name
+of the folder name in your folder directory.
+This ability to send mail to files can be used for a variety of
+purposes, such as maintaining a journal and keeping a record of
+mail sent to a certain group of users. The second example can be
+done automatically by including the full pathname of the record
+file in the
+.b alias
+command for the group. Using our previous
+.b alias
+example, you might give the command:
+.(l
+alias project sam sally steve susan /usr/project/mail_record
+.)l
+Then, all mail sent to "project" would be saved on the file
+.q /usr/project/mail_record
+as well as being sent to the members of the project. This file
+can be examined using
+.i "Mail \-f" .
+.pp
+It is sometimes useful to send mail directly to a program, for
+example one might write a project billboard program and want to access
+it using
+.i Mail .
+To send messages to the billboard program, one can send mail
+to the special name `|billboard' for example.
+.i Mail
+treats recipient names that begin with a `|' as a program to send
+the mail to. An
+.b alias
+can be set up to reference a `|' prefaced name if desired.
+.i Caveats :
+the shell treats `|' specially, so it must be quoted on the command
+line. Also, the `| program' must be presented as a single argument to
+mail. The safest course is to surround the entire name with double
+quotes. This also applies to usage in the
+.b alias
+command. For example, if we wanted to alias `rmsgs' to `rmsgs \-s'
+we would need to say:
+.(l
+alias rmsgs "| rmsgs -s"
+.)l
diff --git a/mail_cmds/mail/USD.doc/mail5.nr b/mail_cmds/mail/USD.doc/mail5.nr
new file mode 100644
index 0000000..0116303
--- /dev/null
+++ b/mail_cmds/mail/USD.doc/mail5.nr
@@ -0,0 +1,1042 @@
+.\" Copyright (c) 1980, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mail5.nr 8.1 (Berkeley) 6/8/93
+.\" $FreeBSD: src/usr.bin/mail/USD.doc/mail5.nr,v 1.4 2000/11/29 10:56:59 ru Exp $
+.\"
+.bp
+.sh 1 "Additional features"
+.pp
+This section describes some additional commands useful for
+reading your mail, setting options, and handling lists of messages.
+.sh 2 "Message lists"
+.pp
+Several
+.i Mail
+commands accept a list of messages as an argument.
+Along with
+.b type
+and
+.b delete ,
+described in section 2,
+there is the
+.b from
+command, which prints the message headers associated with the
+message list passed to it.
+The
+.b from
+command is particularly useful in conjunction with some of the
+message list features described below.
+.pp
+A
+.i "message list"
+consists of a list of message numbers, ranges, and names,
+separated by spaces or tabs. Message numbers may be either
+decimal numbers, which directly specify messages, or one of the
+special characters
+.q \(ua
+.q "."
+or
+.q "$"
+to specify the first relevant, current, or last
+relevant message, respectively.
+.i Relevant
+here means, for most commands
+.q "not deleted"
+and
+.q "deleted"
+for the
+.b undelete
+command.
+.pp
+A range of messages consists of two message numbers (of the form
+described in the previous paragraph) separated by a dash.
+Thus, to print the first four messages, use
+.(l
+type 1\-4
+.)l
+and to print all the messages from the current message to the last
+message, use
+.(l
+type .\-$
+.)l
+.pp
+A
+.i name
+is a user name. The user names given in the message list are
+collected together and each message selected by other means
+is checked to make sure it was sent by one of the named users.
+If the message consists entirely of user names, then every
+message sent by one of those users that is
+.i relevant
+(in the sense described earlier)
+is selected. Thus, to print every message sent to you by
+.q root,
+do
+.(l
+type root
+.)l
+.pp
+As a shorthand notation, you can specify simply
+.q *
+to get every
+.i relevant
+(same sense)
+message. Thus,
+.(l
+type *
+.)l
+prints all undeleted messages,
+.(l
+delete *
+.)l
+deletes all undeleted messages, and
+.(l
+undelete *
+.)l
+undeletes all deleted messages.
+.pp
+You can search for the presence of a word in subject lines with
+.b / .
+For example, to print the headers of all messages that contain the
+word
+.q PASCAL,
+do:
+.(l
+from /pascal
+.)l
+Note that subject searching ignores upper/lower case differences.
+.sh 2 "List of commands"
+.pp
+This section describes all the
+.i Mail
+commands available when
+receiving mail.
+.ip "\fB\-\fP\ \ "
+The
+.rb \-
+command goes to the previous message and prints it. The
+.rb \-
+command may be given a decimal number
+.i n
+as an argument, in which case the
+.i n th
+previous message is gone to and printed.
+.ip "\fB?\fP\ \ "
+Prints a brief summary of commands.
+.ip "\fB!\fP\ \ "
+Used to preface a command to be executed by the shell.
+.ip "\fBPrint\fP\ \ "
+Like
+.b print ,
+but also print out ignored header fields. See also
+\fBprint\fP, \fBignore\fP and \fBretain\fP.
+\fBPrint\fP can be abbreviated to \fBP\fP.
+.ip "\fBReply\fP or \fBRespond\fP\ \ "
+Note the capital \fBR\fP in the name.
+Frame a reply to a one or more messages.
+The reply (or replies if you are using this on multiple messages)
+will be sent ONLY to the person who sent you the message
+(respectively, the set of people who sent the messages you are
+replying to).
+You can
+add people using the \fB~t\fP, \fB~c\fP and \fB~b\fP
+tilde escapes. The subject in your reply is formed by prefacing the
+subject in the original message with
+.q "Re:"
+unless it already began thus.
+If the original message included a
+.q "reply-to"
+header field, the reply will go
+.i only
+to the recipient named by
+.q "reply-to."
+You type in your message using the same conventions available to you
+through the
+.b mail
+command.
+The
+.b Reply
+command is especially useful for replying to messages that were sent
+to enormous distribution groups when you really just want to
+send a message to the originator. Use it often.
+\fBReply\fP (and \fBRespond\fP) can be abbreviated to \fBR\fP.
+.ip "\fBType\fP\ \ "
+Identical to the
+.b Print
+command.
+\fBType\fP can be abbreviated to \fBT\fP.
+.ip "\fBalias\fP\ \ "
+Define a name to stand for a set of other names.
+This is used when you want to send messages to a certain
+group of people and want to avoid retyping their names.
+For example
+.(l
+alias project john sue willie kathryn
+.)l
+creates an alias
+.i project
+which expands to the four people John, Sue, Willie, and Kathryn.
+If no arguments are given, all currently-defined aliases are printed.
+If one argument is given, that alias is printed (if it exists).
+\fBAlias\fP can be abbreviated to \fBa\fP.
+.ip "\fBalternates\fP\ \ "
+If you have accounts on several machines, you may find it convenient
+to use the /usr/lib/aliases on all the machines except one to direct
+your mail to a single account.
+The
+.b alternates
+command is used to inform
+.i Mail
+that each of these other addresses is really
+.i you .
+.i Alternates
+takes a list of user names and remembers that they are all actually you.
+When you
+.b reply
+to messages that were sent to one of these alternate names,
+.i Mail
+will not bother to send a copy of the message to this other address (which
+would simply be directed back to you by the alias mechanism).
+If
+.i alternates
+is given no argument, it lists the current set of alternate names.
+.b Alternates
+is usually used in the .mailrc file.
+\fBAlternates\fP can be abbreviated to \fBalt\fP.
+.ip "\fBchdir\fP\ \ "
+The
+.b chdir
+command allows you to change your current directory.
+.b Chdir
+takes a single argument, which is taken to be the pathname of
+the directory to change to. If no argument is given,
+.b chdir
+changes to your home directory.
+\fBChdir\fP can be abbreviated to \fBc\fP.
+.ip "\fBcopy\fP\ \ "
+The
+.b copy
+command does the same thing that
+.b save
+does, except that it does not mark the messages it is used on
+for deletion when you quit.
+\fBCopy\fP can be abbreviated to \fBco\fP.
+.ip "\fBdelete\fP\ \ "
+Deletes a list of messages. Deleted messages can be reclaimed
+with the
+.b undelete
+command.
+\fBDelete\fP can be abbreviated to \fBd\fP.
+.ip "\fBdp\fP or \fBdt\fP\ \ "
+These
+commands delete the current message and print the next message.
+They are useful for quickly reading and disposing of mail.
+If there is no next message, \fImail\fP says ``at EOF.''
+.ip "\fBedit\fP\ \ "
+To edit individual messages using the text editor, the
+.b edit
+command is provided. The
+.b edit
+command takes a list of messages as described under the
+.b type
+command and processes each by writing it into the file
+Message\c
+.i x
+where
+.i x
+is the message number being edited and executing the text editor on it.
+When you have edited the message to your satisfaction, write the message
+out and quit, upon which
+.i Mail
+will read the message back and remove the file.
+.b Edit
+can be abbreviated to
+.b e .
+.ip "\fBelse\fP\ \ "
+Marks the end of the then-part of an
+.b if
+statement and the beginning of the
+part to take effect if the condition of the
+.b if
+statement is false.
+.ip "\fBendif\fP\ \ "
+Marks the end of an
+.b if
+statement.
+.ip "\fBexit\fP or \fBxit\fP\ \ "
+Leave
+.i Mail
+without updating the system mailbox or the file your were reading.
+Thus, if you accidentally delete several messages, you can use
+.b exit
+to avoid scrambling your mailbox.
+\fBExit\fP can be abbreviated to \fBex\fP or \fBx\fP.
+.ip "\fBfile\fP\ \ "
+The same as
+.b folder .
+\fBFile\fP can be abbreviated to \fBfi\fP.
+.ip "\fBfolders\fP\ \ "
+List the names of the folders in your folder directory.
+.ip "\fBfolder\fP\ \ "
+The
+.b folder
+command switches to a new mail file or folder. With no arguments, it
+tells you which file you are currently reading. If you give
+it an argument, it will write out changes (such as deletions)
+you have made in the current file and read the new file.
+Some special conventions are recognized for the name:
+.(b
+.TS
+center;
+c c
+l a.
+Name Meaning
+_
+# Previous file read
+% Your system mailbox
+%name \fIName\fP's system mailbox
+& Your ~/mbox file
++folder A file in your folder directory
+.TE
+.)b
+\fBFolder\fP can be abbreviated to \fBfo\fP.
+.ip "\fBfrom\fP\ \ "
+The
+.b from
+command takes a list of messages and prints out the header lines for each one;
+hence
+.(l
+from joe
+.)l
+is the easy way to display all the message headers from \*(lqjoe.\*(rq
+\fBFrom\fP can be abbreviated to \fBf\fP.
+.ip "\fBheaders\fP\ \ "
+When you start up
+.i Mail
+to read your mail, it lists the message headers that you have.
+These headers tell you who each message is from, when they were
+received, how many lines and characters each message is, and the
+.q "Subject:"
+header field of each message, if present. In addition,
+.i Mail
+tags the message header of each message that has been the object
+of the
+.b preserve
+command with a
+.q P.
+Messages that have been
+.b saved
+or
+.b written
+are flagged with a
+.q *.
+Finally,
+.b deleted
+messages are not printed at all. If you wish to reprint the current
+list of message headers, you can do so with the
+.b headers
+command. The
+.b headers
+command (and thus the initial header listing)
+only lists the first so many message headers.
+The number of headers listed depends on the speed of your
+terminal.
+This can be overridden by specifying the number of headers you
+want with the
+.i window
+option.
+.i Mail
+maintains a notion of the current
+.q window
+into your messages for the purposes of printing headers.
+Use the
+.b z
+command to move forward and back a window.
+You can move
+.i Mail's
+notion of the current window directly to a particular message by
+using, for example,
+.(l
+headers 40
+.)l
+to move
+.i Mail's
+attention to the messages around message 40.
+If a ``+'' argument is given, then the next screenful of message headers is
+printed, and if a ``\-'' argument is given, the previous screenful of message
+headers is printed.
+\fBHeaders\fP can be abbreviated to \fBh\fP.
+.ip "\fBhelp\fP\ \ "
+Print a brief and usually out of date help message about the commands
+in
+.i Mail .
+The
+.i man
+page for
+.i mail
+is usually more up-to-date than either the help message or this manual.
+It is also a synonym for \fB?\fP.
+.ip "\fBhold\fP\ \ "
+Arrange to hold a list of messages in the system mailbox, instead
+of moving them to the file
+.i mbox
+in your home directory. If you set the binary option
+.i hold ,
+this will happen by default.
+It does not override the \fBdelete\fP command.
+\fBHold\fP can be abbreviated to \fBho\fP.
+.ip "\fBif\fP\ \ "
+Commands in your
+.q .mailrc
+file can be executed conditionally depending on whether you are
+sending or receiving mail with the
+.b if
+command. For example, you can do:
+.(l
+if receive
+ \fIcommands\fP...
+endif
+.)l
+An
+.b else
+form is also available:
+.(l
+if send
+ \fIcommands\fP...
+else
+ \fIcommands\fP...
+endif
+.)l
+Note that the only allowed conditions are
+.b receive
+and
+.b send .
+.ip "\fBignore\fP \ \ "
+.b N.B.:
+.i Ignore
+has been superseded by
+.i retain.
+.br
+Add the list of header fields named to the
+.i "ignore list" .
+Header fields in the ignore list are not printed on your
+terminal when you print a message. This allows you to suppress
+printing of certain machine-generated header fields, such as
+.i Via
+which are not usually of interest. The
+.b Type
+and
+.b Print
+commands can be used to print a message in its entirety, including
+ignored fields.
+If
+.b ignore
+is executed with no arguments, it lists the current set of ignored fields.
+.ip "\fBlist\fP\ \ "
+List the valid
+.i Mail
+commands.
+\fBList\fP can be abbreviated to \fBl\fP.
+.\".ip \fBlocal\fP
+.\"Define a list of local names for this host. This command is useful
+.\"when the host is known by more than one name. Names in the list
+.\"may be qualified be the domain of the host. The first name on the local
+.\"list is the
+.\".i distinguished
+.\"name of the host.
+.\"The names on the local list are used by
+.\".i Mail
+.\"to decide which addresses are local to the host.
+.\"For example:
+.\".(l
+.\"local ucbarpa.BERKELEY.ARPA arpa.BERKELEY.ARPA \\
+.\" arpavax.BERKELEY.ARPA r.BERKELEY.ARPA \\
+.\" ucb-arpa.ARPA
+.\".)l
+.\"From this list we see that
+.\".i "fred@ucbarpa.BERKELEY.ARPA",
+.\".i "harold@arpa.BERKELEY",
+.\"and
+.\".i "larry@r"
+.\"are all addresses of users on the local host.
+.\"The
+.\".b local
+.\"command is usually not used be general users since it is designed for
+.\"local configuration; it is usually found in the file /etc/mail.rc.
+.ip "\fBmail\fP\ \ "
+Send mail to one or more people. If you have the
+.i ask
+option set,
+.i Mail
+will prompt you for a subject to your message. Then you
+can type in your message, using tilde escapes as described in
+section 4 to edit, print, or modify your message. To signal your
+satisfaction with the message and send it, type control-d at the
+beginning of a line, or a . alone on a line if you set the option
+.i dot .
+To abort the message, type two interrupt characters (\s-2RUBOUT\s0
+by default) in a row or use the
+.b ~q
+escape.
+The \fBmail\fP command can be abbreviated to \fBm\fP.
+.ip "\fBmbox\fP\ \ "
+Indicate that a list of messages be sent to
+.i mbox
+in your home directory when you quit. This is the default
+action for messages if you do
+.i not
+have the
+.i hold
+option set.
+.ip "\fBnext\fP or \fB+\fP\ \ "
+The
+.b next
+command goes to the next message and types it. If given a message list,
+.b next
+goes to the first such message and types it. Thus,
+.(l
+next root
+.)l
+goes to the next message sent by
+.q root
+and types it. The
+.b next
+command can be abbreviated to simply a newline, which means that one
+can go to and type a message by simply giving its message number or
+one of the magic characters
+.q "^"
+.q "."
+or
+.q "$".
+Thus,
+.(l
+\&.
+.)l
+prints the current message and
+.(l
+4
+.)l
+prints message 4, as described previously.
+\fBNext\fP can be abbreviated to \fBn\fP.
+.ip "\fBpreserve\fP\ \ "
+Same as
+.b hold .
+Cause a list of messages to be held in your system mailbox when you quit.
+\fBPreserve\fP can be abbreviated to \fBpre\fP.
+.ip "\fBprint\fP\ \ "
+Print the specified messages. If the
+.b crt
+variable is set, messages longer than the number of lines it indicates
+are paged through the command specified by the \fBPAGER\fP variable.
+The \fBprint\fP command can be abbreviated to \fBp\fP.
+.ip "\fBquit\fP\ \ "
+Terminates the session, saving all undeleted, unsaved and unwritten messages
+in the user's \fImbox\fP file in their login directory
+(messages marked as having been read), preserving all
+messages marked with \fBhold\fP or \fBpreserve\fP or never referenced
+in their system mailbox.
+Any messages that were deleted, saved, written or saved to \fImbox\fP are
+removed from their system mailbox.
+If new mail has arrived during the session, the message
+``You have new mail'' is given. If given while editing a mailbox file
+with the \fB\-f\fP flag, then the edit file is rewritten.
+A return to the Shell is effected, unless the rewrite of edit file fails,
+in which case the user can escape with the \fBexit\fP command.
+\fBQuit\fP can be abbreviated to \fBq\fP.
+.ip "\fBreply\fP or \fBrespond\fP\ \ "
+Frame a reply to a single message.
+The reply will be sent to the
+person who sent you the message (to which you are replying), plus all
+the people who received the original message, except you. You can
+add people using the \fB~t\fP, \fB~c\fP and \fB~b\fP
+tilde escapes. The subject in your reply is formed by prefacing the
+subject in the original message with
+.q "Re:"
+unless it already began thus.
+If the original message included a
+.q "reply-to"
+header field, the reply will go
+.i only
+to the recipient named by
+.q "reply-to."
+You type in your message using the same conventions available to you
+through the
+.b mail
+command.
+The \fBreply\fP (and \fBrespond\fP) command can be abbreviated to \fBr\fP.
+.ip "\fBretain\fP\ \ "
+Add the list of header fields named to the \fIretained list\fP.
+Only the header fields in the retain list
+are shown on your terminal when you print a message.
+All other header fields are suppressed.
+The
+.b Type
+and
+.b Print
+commands can be used to print a message in its entirety.
+If
+.b retain
+is executed with no arguments, it lists the current set of
+retained fields.
+.ip "\fBsave\fP\ \ "
+It is often useful to be able to save messages on related topics
+in a file. The
+.b save
+command gives you the ability to do this. The
+.b save
+command takes as an argument a list of message numbers, followed by
+the name of the file in which to save the messages. The messages
+are appended to the named file, thus allowing one to keep several
+messages in the file, stored in the order they were put there.
+The filename in quotes, followed by the line
+count and character count is echoed on the user's terminal.
+An example of the
+.b save
+command relative to our running example is:
+.(l
+s 1 2 tuitionmail
+.)l
+.b Saved
+messages are not automatically saved in
+.i mbox
+at quit time, nor are they selected by the
+.b next
+command described above, unless explicitly specified.
+\fBSave\fP can be abbreviated to \fBs\fP.
+.ip "\fBset\fP\ \ "
+Set an option or give an option a value. Used to customize
+.i Mail .
+Section 5.3 contains a list of the options. Options can be
+.i binary ,
+in which case they are
+.i on
+or
+.i off ,
+or
+.i valued .
+To set a binary option
+.i option
+.i on ,
+do
+.(l
+set option
+.)l
+To give the valued option
+.i option
+the value
+.i value ,
+do
+.(l
+set option=value
+.)l
+There must be no space before or after the ``='' sign.
+If no arguments are given, all variable values are printed.
+Several options can be specified in a single
+.b set
+command.
+\fBSet\fP can be abbreviated to \fBse\fP.
+.ip "\fBshell\fP\ \ "
+The
+.b shell
+command allows you to
+escape to the shell.
+.b Shell
+invokes an interactive shell and allows you to type commands to it.
+When you leave the shell, you will return to
+.i Mail .
+The shell used is a default assumed by
+.i Mail ;
+you can override this default by setting the valued option
+.q SHELL,
+eg:
+.(l
+set SHELL=/bin/csh
+.)l
+\fBShell\fP can be abbreviated to \fBsh\fP.
+.ip "\fBsize\fP\ \ "
+Takes a message list and prints out the size in characters of each
+message.
+.ip "\fBsource\fP\ \ "
+The
+.b source
+command reads
+.i mail
+commands from a file. It is useful when you are trying to fix your
+.q .mailrc
+file and you need to re-read it.
+\fBSource\fP can be abbreviated to \fBso\fP.
+.ip "\fBtop\fP\ \ "
+The
+.b top
+command takes a message list and prints the first five lines
+of each addressed message.
+If you wish, you can change the number of lines that
+.b top
+prints out by setting the valued option
+.q "toplines."
+On a CRT terminal,
+.(l
+set toplines=10
+.)l
+might be preferred.
+\fBTop\fP can be abbreviated to \fBto\fP.
+.ip "\fBtype\fP\ \ "
+Same as \fBprint\fP.
+Takes a message list and types out each message on the terminal.
+The \fBtype\fP command can be abbreviated to \fBt\fP.
+.ip "\fBundelete\fP \ \"
+Takes a message list and marks each message as \fInot\fP
+being deleted.
+\fBUndelete\fP can be abbreviated to \fBu\fP.
+.ip "\fBunread\fP\ \ "
+Takes a message list and marks each message as
+.i not
+having been read.
+\fBUnread\fP can be abbreviated to \fBU\fP.
+.ip "\fBunset\fP\ \ "
+Takes a list of option names and discards their remembered values;
+the inverse of \fBset\fP .
+.ip "\fBvisual\fP\ \ "
+It is often useful to be able to invoke one of two editors,
+based on the type of terminal one is using. To invoke
+a display oriented editor, you can use the
+.b visual
+command. The operation of the
+.b visual
+command is otherwise identical to that of the
+.b edit
+command.
+.ne 2v+\n(psu
+.sp \n(psu
+Both the
+.b edit
+and
+.b visual
+commands assume some default text editors. These default editors
+can be overridden by the valued options
+.q EDITOR
+and
+.q VISUAL
+for the standard and screen editors. You might want to do:
+.(l
+set EDITOR=/usr/bin/ex VISUAL=/usr/bin/vi
+.)l
+\fBVisual\fP can be abbreviated to \fBv\fP.
+.ip "\fBwrite\fP\ \ "
+The
+.b save
+command always writes the entire message, including the headers,
+into the file. If you want to write just the message itself, you
+can use the
+.b write
+command. The
+.b write
+command has the same syntax as the
+.b save
+command, and can be abbreviated to simply
+.b w .
+Thus, we could write the second message by doing:
+.(l
+w 2 file.c
+.)l
+As suggested by this example, the
+.b write
+command is useful for such tasks as sending and receiving
+source program text over the message system.
+The filename in quotes, followed by the line
+count and character count is echoed on the user's terminal.
+.ip "\fBz\fP\ \ "
+.i Mail
+presents message headers in windowfuls as described under
+the
+.b headers
+command.
+You can move
+.i Mail's
+attention forward to the next window by giving the
+.(l
+z+
+.)l
+command. Analogously, you can move to the previous window with:
+.(l
+z\-
+.)l
+.sh 2 "Custom options"
+.pp
+Throughout this manual, we have seen examples of binary and valued options.
+This section describes each of the options in alphabetical order, including
+some that you have not seen yet.
+To avoid confusion, please note that the options are either
+all lower case letters or all upper case letters. When I start a sentence
+such as:
+.q "Ask"
+causes
+.i Mail
+to prompt you for a subject header,
+I am only capitalizing
+.q ask
+as a courtesy to English.
+.ip "\fBEDITOR\fP\ \ "
+The valued option
+.q EDITOR
+defines the pathname of the text editor to be used in the
+.b edit
+command and ~e. If not defined, a standard editor is used.
+.ip "\fBPAGER\fP\ \ "
+Pathname of the program to use for paginating output when
+it exceeds \fIcrt\fP lines.
+A default paginator is used if this option is not defined.
+.ip "\fBSHELL\fP\ \ "
+The valued option
+.q SHELL
+gives the path name of your shell. This shell is used for the
+.b !
+command and ~! escape. In addition, this shell expands
+file names with shell metacharacters like * and ? in them.
+.ip "\fBVISUAL\fP\ \ "
+The valued option
+.q VISUAL
+defines the pathname of the screen editor to be used in the
+.b visual
+command
+and ~v escape. A standard screen editor is used if you do not define one.
+.ip "\fBappend\fP\ \ "
+The
+.q append
+option is binary and
+causes messages saved in
+.i mbox
+to be appended to the end rather than prepended.
+Normally, \fIMail\fP will put messages in \fImbox\fP
+in the same order that the system puts messages in your system mailbox.
+By setting
+.q append,
+you are requesting that
+.i mbox
+be appended to regardless. It is in any event quicker to append.
+.ip "\fBask\fP\ \ "
+.q "Ask"
+is a binary option which
+causes
+.i Mail
+to prompt you for the subject of each message you send.
+If you respond with simply a newline, no subject field will be sent.
+.ip "\fBaskcc\fP\ \ "
+.q Askcc
+is a binary option which
+causes you to be prompted for additional carbon copy recipients at the
+end of each message. Responding with a newline shows your
+satisfaction with the current list.
+.ip "\fBautoprint\fP\ \ "
+.q Autoprint
+is a binary option which
+causes the
+.b delete
+command to behave like
+.b dp
+\*- thus, after deleting a message, the next one will be typed
+automatically. This is useful when quickly scanning and deleting
+messages in your mailbox.
+.ip "\fBcrt\fP \ \ "
+The valued option
+.q crt
+is used as a threshold to determine how long a message must
+be before
+.b PAGER
+is used to read it.
+.ip "\fBdebug\fP \ \ "
+The binary option
+.q debug
+causes debugging information to be displayed. Use of this
+option is the same as using the \fB\-d\fP command line flag.
+.ip "\fBdot\fP\ \ "
+.q Dot
+is a binary option which, if set, causes
+.i Mail
+to interpret a period alone on a line as the terminator
+of the message you are sending.
+.ip "\fBescape\fP\ \ "
+To allow you to change the escape character used when sending
+mail, you can set the valued option
+.q escape.
+Only the first character of the
+.q escape
+option is used, and it must be doubled if it is to appear as
+the first character of a line of your message. If you change your escape
+character, then ~ loses all its special meaning, and need no longer be doubled
+at the beginning of a line.
+.ip "\fBfolder\fP\ \ "
+The name of the directory to use for storing folders of messages.
+If this name begins with a `/'
+.i Mail
+considers it to be an absolute pathname; otherwise, the folder directory
+is found relative to your home directory.
+.ip "\fBhold\fP\ \ "
+The binary option
+.q hold
+causes messages that have been read but not manually dealt with
+to be held in the system mailbox. This prevents such messages from
+being automatically swept into your \fImbox\fP file.
+.ip "\fBignore\fP\ \ "
+The binary option
+.q ignore
+causes \s-2RUBOUT\s0 characters from your terminal to be ignored and echoed
+as @'s while you are sending mail. \s-2RUBOUT\s0 characters retain their
+original meaning in
+.i Mail
+command mode.
+Setting the
+.q ignore
+option is equivalent to supplying the
+.b \-i
+flag on the command line as described in section 6.
+.ip "\fBignoreeof\fP\ \ "
+An option related to
+.q dot
+is
+.q ignoreeof
+which makes
+.i Mail
+refuse to accept a control\-d as the end of a message.
+.q Ignoreeof
+also applies to
+.i Mail
+command mode.
+.ip "\fBkeep\fP\ \ "
+The
+.q keep
+option causes
+.i Mail
+to truncate your system mailbox instead of deleting it when it
+is empty. This is useful if you elect to protect your mailbox, which
+you would do with the shell command:
+.(l
+chmod 600 /var/mail/yourname
+.)l
+where
+.i yourname
+is your login name. If you do not do this, anyone can probably read
+your mail, although people usually don't.
+.ip "\fBkeepsave\fP\ \ "
+When you
+.b save
+a message,
+.i Mail
+usually discards it when you
+.b quit .
+To retain all saved messages, set the
+.q keepsave
+option.
+.ip "\fBmetoo\fP\ \ "
+When sending mail to an alias,
+.i Mail
+makes sure that if you are included in the alias, that mail will not
+be sent to you. This is useful if a single alias is being used by
+all members of the group. If however, you wish to receive a copy of
+all the messages you send to the alias, you can set the binary option
+.q metoo.
+.ip "\fBnoheader\fP\ \ "
+The binary option
+.q noheader
+suppresses the printing of the version and headers when
+.i Mail
+is first invoked. Setting this option is the same as using
+.b \-N
+on the command line.
+.ip "\fBnosave\fP\ \ "
+Normally,
+when you abort a message with two \s-2RUBOUTs\s0,
+.i Mail
+copies the partial letter to the file
+.q dead.letter
+in your home directory. Setting the binary option
+.q nosave
+prevents this.
+.ip "\fBReplyall\fP\ \ "
+Reverses the sense of
+.i reply
+and
+.i Reply
+commands.
+.ip "\fBquiet\fP\ \ "
+The binary option
+.q quiet
+suppresses the printing of the version when
+.i Mail
+is first invoked,
+as well as printing the for example
+.q "Message 4:"
+from the
+.b type
+command.
+.ip "\fBrecord\fP\ \ "
+If you love to keep records, then the
+valued option
+.q record
+can be set to the name of a file to save your outgoing mail.
+Each new message you send is appended to the end of the file.
+.ip "\fBscreen\fP\ \ "
+When
+.i Mail
+initially prints the message headers, it determines the number to
+print by looking at the speed of your terminal. The faster your
+terminal, the more it prints.
+The valued option
+.q screen
+overrides this calculation and
+specifies how many message headers you want printed.
+This number is also used for scrolling with the
+.b z
+command.
+.ip "\fBsendmail\fP\ \ "
+To use an alternate mail delivery system, set the
+.q sendmail
+option to the full pathname of the program to use. Note: this is not
+for everyone! Most people should use the default delivery system.
+.ip "\fBtoplines\fP\ \ "
+The valued option
+.q toplines
+defines the number of lines that the
+.q top
+command will print out instead of the default five lines.
+.ip "\fBverbose\fP\ \ "
+The binary option "verbose" causes
+.i Mail
+to invoke sendmail with the
+.b \-v
+flag, which causes it to go into verbose mode and announce expansion
+of aliases, etc. Setting the "verbose" option is equivalent to
+invoking
+.i Mail
+with the
+.b \-v
+flag as described in section 6.
diff --git a/mail_cmds/mail/USD.doc/mail6.nr b/mail_cmds/mail/USD.doc/mail6.nr
new file mode 100644
index 0000000..0465a94
--- /dev/null
+++ b/mail_cmds/mail/USD.doc/mail6.nr
@@ -0,0 +1,125 @@
+.\" Copyright (c) 1980, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mail6.nr 8.1 (Berkeley) 6/8/93
+.\"
+.bp
+.sh 1 "Command line options"
+.pp
+This section describes command line options for
+.i Mail
+and what they are used for.
+.ip \-N
+Suppress the initial printing of headers.
+.ip \-d
+Turn on debugging information. Not of general interest.
+.ip "\-f file\ \ "
+Show the messages in
+.i file
+instead of your system mailbox. If
+.i file
+is omitted,
+.i Mail
+reads
+.i mbox
+in your home directory.
+.ip \-i
+Ignore tty interrupt signals. Useful on noisy phone lines, which
+generate spurious RUBOUT or DELETE characters. It's usually
+more effective to change your interrupt character to control\-c,
+for which see the
+.i stty
+shell command.
+.ip \-n
+Inhibit reading of /etc/mail.rc. Not generally useful, since
+/etc/mail.rc is usually empty.
+.ip "\-s string"
+Used for sending mail.
+.i String
+is used as the subject of the message being composed. If
+.i string
+contains blanks, you must surround it with quote marks.
+.ip "\-u name"
+Read
+.i names's
+mail instead of your own. Unwitting others often neglect to protect
+their mailboxes, but discretion is advised. Essentially,
+.b "\-u user"
+is a shorthand way of doing
+.b "\-f /var/mail/user".
+.ip "\-v"
+Use the
+.b \-v
+flag when invoking sendmail. This feature may also be enabled
+by setting the the option "verbose".
+.pp
+The following command line flags are also recognized, but are
+intended for use by programs invoking
+.i Mail
+and not for people.
+.ip "\-T file"
+Arrange to print on
+.i file
+the contents of the
+.i article-id
+fields of all messages that were either read or deleted.
+.b \-T
+is for the
+.i readnews
+program and should NOT be used for reading your mail.
+.ip "\-h number"
+Pass on hop count information.
+.i Mail
+will take the number, increment it, and pass it with
+.b \-h
+to the mail delivery system.
+.b \-h
+only has effect when sending mail and is used for network mail
+forwarding.
+.ip "\-r name"
+Used for network mail forwarding: interpret
+.i name
+as the sender of the message. The
+.i name
+and
+.b \-r
+are simply sent along to the mail delivery system. Also,
+.i Mail
+will wait for the message to be sent and return the exit status.
+Also restricts formatting of message.
+.pp
+Note that
+.b \-h
+and
+.b \-r ,
+which are for network mail forwarding, are not used in practice
+since mail forwarding is now handled separately. They may
+disappear soon.
diff --git a/mail_cmds/mail/USD.doc/mail7.nr b/mail_cmds/mail/USD.doc/mail7.nr
new file mode 100644
index 0000000..0b2590b
--- /dev/null
+++ b/mail_cmds/mail/USD.doc/mail7.nr
@@ -0,0 +1,107 @@
+.\" Copyright (c) 1980, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mail7.nr 8.1 (Berkeley) 6/8/93
+.\"
+.sh 1 "Format of messages"
+.pp
+This section describes the format of messages.
+Messages begin with a
+.i from
+line, which consists of the word
+.q From
+followed by a user name, followed by anything, followed by
+a date in the format returned by the
+.i ctime
+library routine described in section 3 of the Unix Programmer's
+Manual. A possible
+.i ctime
+format date is:
+.(l
+Tue Dec 1 10:58:23 1981
+.)l
+The
+.i ctime
+date may be optionally followed by a single space and a
+time zone indication, which
+should be three capital letters, such as PDT.
+.pp
+Following the
+.i from
+line are zero or more
+.i "header field"
+lines.
+Each header field line is of the form:
+.(l
+name: information
+.)l
+.i Name
+can be anything, but only certain header fields are recognized as
+having any meaning. The recognized header fields are:
+.i article-id ,
+.i bcc ,
+.i cc ,
+.i from ,
+.i reply-to ,
+.i sender ,
+.i subject ,
+and
+.i to .
+Other header fields are also significant to other systems; see,
+for example, the current Arpanet message standard for much more
+information on this topic.
+A header field can be continued onto following lines by making the
+first character on the following line a space or tab character.
+.pp
+If any headers are present, they must be followed by a blank line.
+The part that follows is called the
+.i body
+of the message, and must be ASCII text, not containing null characters.
+Each line in the message body must be no longer than 512 characters and
+terminated with an ASCII newline character.
+If binary data must be passed through the mail system, it is suggested
+that this data be encoded in a system which encodes six bits into
+a printable character (i.e.: uuencode).
+For example, one could use the upper and lower case letters, the digits,
+and the characters comma and period to make up the 64 characters.
+Then, one can send a 16-bit binary number
+as three characters. These characters should be packed into lines,
+preferably lines about 70 characters long as long lines are transmitted
+more efficiently.
+.pp
+The message delivery system always adds a blank line to the end of
+each message. This blank line must not be deleted.
+.pp
+The UUCP message delivery system sometimes adds a blank line to
+the end of a message each time it is forwarded through a machine.
+.pp
+It should be noted that some network transport protocols enforce
+limits to the lengths of messages.
diff --git a/mail_cmds/mail/USD.doc/mail8.nr b/mail_cmds/mail/USD.doc/mail8.nr
new file mode 100644
index 0000000..b09afbd
--- /dev/null
+++ b/mail_cmds/mail/USD.doc/mail8.nr
@@ -0,0 +1,75 @@
+.\" Copyright (c) 1980, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mail8.nr 8.1 (Berkeley) 6/8/93
+.\"
+.bp
+.sh 1 "Glossary"
+.pp
+This section contains the definitions of a few phrases
+peculiar to
+.i Mail .
+.ip "\fIalias\fP"
+An alternative name for a person or list of people.
+.ip "\fIflag\fP"
+An option, given on the command line of
+.i Mail ,
+prefaced with a \-. For example,
+.b \-f
+is a flag.
+.ip "\fIheader field\fP"
+At the beginning of a message, a line which contains information
+that is part of the structure of the message. Popular header fields
+include
+.i to ,
+.i cc ,
+and
+.i subject .
+.ip "\fImail\ \ \fP"
+A collection of messages. Often used in the phrase,
+.q "Have you read your mail?"
+.ip "\fImailbox\fP"
+The place where your mail is stored, typically in the directory
+/var/mail.
+.ip "\fImessage\fP"
+A single letter from someone, initially stored in your
+.i mailbox .
+.ip "\fImessage list\fP"
+A string used in
+.i Mail
+command mode to describe a sequence of messages.
+.ip "\fIoption\fP"
+A piece of special purpose information used to tailor
+.i Mail
+to your taste.
+Options are specified with the
+.b set
+command.
diff --git a/mail_cmds/mail/USD.doc/mail9.nr b/mail_cmds/mail/USD.doc/mail9.nr
new file mode 100644
index 0000000..271548e
--- /dev/null
+++ b/mail_cmds/mail/USD.doc/mail9.nr
@@ -0,0 +1,203 @@
+.\" Copyright (c) 1980, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mail9.nr 8.1 (Berkeley) 6/8/93
+.\"
+.bp
+.sh 1 "Summary of commands, options, and escapes"
+.pp
+This section gives a quick summary of the
+.i Mail
+commands, binary and valued options, and tilde escapes.
+.pp
+The following table describes the commands:
+.TS
+center ;
+c ci
+lb l.
+Command Description
+_
++ Same as \fBnext\fP
+- Back up to previous message
+? Print brief summary of \fIMail\fP commands
+! Single command escape to shell
+Print Type message with ignored fields
+Reply Reply to author of message only
+Respond Same as \fBReply\fP
+Type Type message with ignored fields
+alias Define an alias as a set of user names
+alternates List other names you are known by
+chdir Change working directory, home by default
+copy Copy a message to a file or folder
+delete Delete a list of messages
+dp Same as \fBdt\fP
+dt Delete current message, type next message
+edit Edit a list of messages
+else Start of else part of conditional; see \fBif\fP
+endif End of conditional statement; see \fBif\fP
+exit Leave mail without changing anything
+file Interrogate/change current mail file
+folder Same as \fBfile\fP
+folders List the folders in your folder directory
+from List headers of a list of messages
+headers List current window of messages
+help Same as \fB?\fP
+hold Same as \fBpreserve\fP
+if Conditional execution of \fIMail\fP commands
+ignore Set/examine list of ignored header fields
+list List valid \fIMail\fP commands
+local List other names for the local host
+mail Send mail to specified names
+mbox Arrange to save a list of messages in \fImbox\fP
+next Go to next message and type it
+preserve Arrange to leave list of messages in system mailbox
+print Print messages
+quit Leave \fIMail\fP; update system mailbox, \fImbox\fP as appropriate
+reply Compose a reply to a message
+respond Same as \fBreply\fP
+retain Supersedes \fBignore\fP
+save Append messages, headers included, on a file
+set Set binary or valued options
+shell Invoke an interactive shell
+size Prints out size of message list
+source Read \fImail\fP commands from a file
+top Print first so many (5 by default) lines of list of messages
+type Same as \fBprint\fP
+undelete Undelete list of messages
+unread Marks list of messages as not been read
+unset Undo the operation of a \fBset\fP
+visual Invoke visual editor on a list of messages
+write Append messages to a file, don't include headers
+xit Same as \fBexit\fP
+z Scroll to next/previous screenful of headers
+.TE
+.bp
+.(b
+.pp
+The following table describes the options. Each option is
+shown as being either a binary or valued option.
+.TS
+center;
+c ci ci
+l ci l.
+Option Type Description
+_
+EDITOR valued Pathname of editor for ~e and \fBedit\fP
+PAGER valued Pathname of paginator for \fBPrint\fP, \fBprint\fP, \fBType\fP and \fBtype\fP
+SHELL valued Pathname of shell for \fBshell\fP, ~! and \fB!\fP
+VISUAL valued Pathname of screen editor for ~v, \fBvisual\fP
+append binary Always append messages to end of \fImbox\fP
+ask binary Prompt user for Subject: field when sending
+askcc binary Prompt user for additional Cc's at end of message
+autoprint binary Print next message after \fBdelete\fP
+crt valued Minimum number of lines before using \fBPAGER\fP
+debug binary Print out debugging information
+dot binary Accept . alone on line to terminate message input
+escape valued Escape character to be used instead of\ \ ~
+folder valued Directory to store folders in
+hold binary Hold messages in system mailbox by default
+ignore binary Ignore \s-2RUBOUT\s0 while sending mail
+ignoreeof binary Don't terminate letters/command input with \fB\(uaD\fP
+keep binary Don't unlink system mailbox when empty
+keepsave binary Don't delete \fBsave\fPd messages by default
+metoo binary Include sending user in aliases
+noheader binary Suppress initial printing of version and headers
+nosave binary Don't save partial letter in \fIdead.letter\fP
+quiet binary Suppress printing of \fIMail\fP version and message numbers
+record valued File to save all outgoing mail in
+screen valued Size of window of message headers for \fBz\fP, etc.
+sendmail valued Choose alternate mail delivery system
+toplines valued Number of lines to print in \fBtop\fP
+verbose binary Invoke sendmail with the \fB\-v\fP flag
+.TE
+.)b
+.(b
+.pp
+The following table summarizes the tilde escapes available
+while sending mail.
+.TS
+center;
+c ci ci
+l li l.
+Escape Arguments Description
+_
+~! command Execute shell command
+~b name ... Add names to "blind" Cc: list
+~c name ... Add names to Cc: field
+~d Read \fIdead.letter\fP into message
+~e Invoke text editor on partial message
+~f messages Read named messages
+~h Edit the header fields
+~m messages Read named messages, right shift by tab
+~p Print message entered so far
+~q Abort entry of letter; like \s-2RUBOUT\s0
+~r filename Read file into message
+~s string Set Subject: field to \fIstring\fP
+~t name ... Add names to To: field
+~v Invoke screen editor on message
+~w filename Write message on file
+~| command Pipe message through \fIcommand\fP
+~: Mail command Execute a \fIMail\fP command
+~~ string Quote a ~ in front of \fIstring\fP
+.TE
+.)b
+.(b
+.pp
+The following table shows the command line flags that
+.i Mail
+accepts:
+.TS
+center;
+c c
+l a.
+Flag Description
+_
+\-N Suppress the initial printing of headers
+\-T \fIfile\fP Article-id's of read/deleted messages to \fIfile\fP
+\-d Turn on debugging
+\-f \fIfile\fP Show messages in \fIfile\fP or \fI~/mbox\fP
+\-h \fInumber\fP Pass on hop count for mail forwarding
+\-i Ignore tty interrupt signals
+\-n Inhibit reading of /etc/mail.rc
+\-r \fIname\fP Pass on \fIname\fP for mail forwarding
+\-s \fIstring\fP Use \fIstring\fP as subject in outgoing mail
+\-u \fIname\fP Read \fIname's\fP mail instead of your own
+\-v Invoke sendmail with the \fB\-v\fP flag
+.TE
+.)b
+.lp
+Notes:
+.b \-T ,
+.b \-d ,
+.b \-h ,
+and
+.b \-r
+are not for human use.
diff --git a/mail_cmds/mail/USD.doc/maila.nr b/mail_cmds/mail/USD.doc/maila.nr
new file mode 100644
index 0000000..84b01fe
--- /dev/null
+++ b/mail_cmds/mail/USD.doc/maila.nr
@@ -0,0 +1,33 @@
+.\" Copyright (c) 1980, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)maila.nr 8.1 (Berkeley) 6/8/93
+.\"
diff --git a/mail_cmds/mail/aux.c b/mail_cmds/mail/aux.c
new file mode 100644
index 0000000..f1a621f
--- /dev/null
+++ b/mail_cmds/mail/aux.c
@@ -0,0 +1,635 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)aux.c 8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/aux.c,v 1.13 2002/08/25 13:22:47 charnier Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+#include <sys/time.h>
+
+#include "rcv.h"
+#include "extern.h"
+
+/*
+ * Mail -- a mail program
+ *
+ * Auxiliary functions.
+ */
+
+static char *save2str(char *, char *);
+
+/*
+ * Return a pointer to a dynamic copy of the argument.
+ */
+char *
+savestr(str)
+ char *str;
+{
+ char *new;
+ int size = strlen(str) + 1;
+
+ if ((new = salloc(size)) != NULL)
+ bcopy(str, new, size);
+ return (new);
+}
+
+/*
+ * Make a copy of new argument incorporating old one.
+ */
+char *
+save2str(str, old)
+ char *str, *old;
+{
+ char *new;
+ int newsize = strlen(str) + 1;
+ int oldsize = old ? strlen(old) + 1 : 0;
+
+ if ((new = salloc(newsize + oldsize)) != NULL) {
+ if (oldsize) {
+ bcopy(old, new, oldsize);
+ new[oldsize - 1] = ' ';
+ }
+ bcopy(str, new + oldsize, newsize);
+ }
+ return (new);
+}
+
+/*
+ * Touch the named message by setting its MTOUCH flag.
+ * Touched messages have the effect of not being sent
+ * back to the system mailbox on exit.
+ */
+void
+touch(mp)
+ struct message *mp;
+{
+
+ mp->m_flag |= MTOUCH;
+ if ((mp->m_flag & MREAD) == 0)
+ mp->m_flag |= MREAD|MSTATUS;
+}
+
+/*
+ * Test to see if the passed file name is a directory.
+ * Return true if it is.
+ */
+int
+isdir(name)
+ char name[];
+{
+ struct stat sbuf;
+
+ if (stat(name, &sbuf) < 0)
+ return (0);
+ return (S_ISDIR(sbuf.st_mode));
+}
+
+/*
+ * Count the number of arguments in the given string raw list.
+ */
+int
+argcount(argv)
+ char **argv;
+{
+ char **ap;
+
+ for (ap = argv; *ap++ != NULL;)
+ ;
+ return (ap - argv - 1);
+}
+
+/*
+ * Return the desired header line from the passed message
+ * pointer (or NULL if the desired header field is not available).
+ */
+char *
+hfield(field, mp)
+ const char *field;
+ struct message *mp;
+{
+ FILE *ibuf;
+ char linebuf[LINESIZE];
+ int lc;
+ char *hfield;
+ char *colon, *oldhfield = NULL;
+
+ ibuf = setinput(mp);
+ if ((lc = mp->m_lines - 1) < 0)
+ return (NULL);
+ if (readline(ibuf, linebuf, LINESIZE) < 0)
+ return (NULL);
+ while (lc > 0) {
+ if ((lc = gethfield(ibuf, linebuf, lc, &colon)) < 0)
+ return (oldhfield);
+ if ((hfield = ishfield(linebuf, colon, field)) != NULL)
+ oldhfield = save2str(hfield, oldhfield);
+ }
+ return (oldhfield);
+}
+
+/*
+ * Return the next header field found in the given message.
+ * Return >= 0 if something found, < 0 elsewise.
+ * "colon" is set to point to the colon in the header.
+ * Must deal with \ continuations & other such fraud.
+ */
+int
+gethfield(f, linebuf, rem, colon)
+ FILE *f;
+ char linebuf[];
+ int rem;
+ char **colon;
+{
+ char line2[LINESIZE];
+ char *cp, *cp2;
+ int c;
+
+ for (;;) {
+ if (--rem < 0)
+ return (-1);
+ if ((c = readline(f, linebuf, LINESIZE)) <= 0)
+ return (-1);
+ for (cp = linebuf; isprint((unsigned char)*cp) && *cp != ' ' && *cp != ':';
+ cp++)
+ ;
+ if (*cp != ':' || cp == linebuf)
+ continue;
+ /*
+ * I guess we got a headline.
+ * Handle wraparounding
+ */
+ *colon = cp;
+ cp = linebuf + c;
+ for (;;) {
+ while (--cp >= linebuf && (*cp == ' ' || *cp == '\t'))
+ ;
+ cp++;
+ if (rem <= 0)
+ break;
+ ungetc(c = getc(f), f);
+ if (c != ' ' && c != '\t')
+ break;
+ if ((c = readline(f, line2, LINESIZE)) < 0)
+ break;
+ rem--;
+ for (cp2 = line2; *cp2 == ' ' || *cp2 == '\t'; cp2++)
+ ;
+ c -= cp2 - line2;
+ if (cp + c >= linebuf + LINESIZE - 2)
+ break;
+ *cp++ = ' ';
+ bcopy(cp2, cp, c);
+ cp += c;
+ }
+ *cp = 0;
+ return (rem);
+ }
+ /* NOTREACHED */
+}
+
+/*
+ * Check whether the passed line is a header line of
+ * the desired breed. Return the field body, or 0.
+ */
+
+char*
+ishfield(linebuf, colon, field)
+ char linebuf[];
+ char *colon;
+ const char *field;
+{
+ char *cp = colon;
+
+ *cp = 0;
+ if (strcasecmp(linebuf, field) != 0) {
+ *cp = ':';
+ return (0);
+ }
+ *cp = ':';
+ for (cp++; *cp == ' ' || *cp == '\t'; cp++)
+ ;
+ return (cp);
+}
+
+/*
+ * Copy a string and lowercase the result.
+ * dsize: space left in buffer (including space for NULL)
+ */
+void
+istrncpy(dest, src, dsize)
+ char *dest;
+ const char *src;
+ size_t dsize;
+{
+
+ strlcpy(dest, src, dsize);
+ while (*dest) {
+ *dest = tolower((unsigned char)*dest);
+ dest++;
+ }
+}
+
+/*
+ * The following code deals with input stacking to do source
+ * commands. All but the current file pointer are saved on
+ * the stack.
+ */
+
+static int ssp; /* Top of file stack */
+struct sstack {
+ FILE *s_file; /* File we were in. */
+ int s_cond; /* Saved state of conditionals */
+ int s_loading; /* Loading .mailrc, etc. */
+};
+#define SSTACK_SIZE 64 /* XXX was NOFILE. */
+static struct sstack sstack[SSTACK_SIZE];
+
+/*
+ * Pushdown current input file and switch to a new one.
+ * Set the global flag "sourcing" so that others will realize
+ * that they are no longer reading from a tty (in all probability).
+ */
+int
+source(arglist)
+ char **arglist;
+{
+ FILE *fi;
+ char *cp;
+
+ if ((cp = expand(*arglist)) == NULL)
+ return (1);
+ if ((fi = Fopen(cp, "r")) == NULL) {
+ warn("%s", cp);
+ return (1);
+ }
+ if (ssp >= SSTACK_SIZE - 1) {
+ printf("Too much \"sourcing\" going on.\n");
+ (void)Fclose(fi);
+ return (1);
+ }
+ sstack[ssp].s_file = input;
+ sstack[ssp].s_cond = cond;
+ sstack[ssp].s_loading = loading;
+ ssp++;
+ loading = 0;
+ cond = CANY;
+ input = fi;
+ sourcing++;
+ return (0);
+}
+
+/*
+ * Pop the current input back to the previous level.
+ * Update the "sourcing" flag as appropriate.
+ */
+int
+unstack()
+{
+ if (ssp <= 0) {
+ printf("\"Source\" stack over-pop.\n");
+ sourcing = 0;
+ return (1);
+ }
+ (void)Fclose(input);
+ if (cond != CANY)
+ printf("Unmatched \"if\"\n");
+ ssp--;
+ cond = sstack[ssp].s_cond;
+ loading = sstack[ssp].s_loading;
+ input = sstack[ssp].s_file;
+ if (ssp == 0)
+ sourcing = loading;
+ return (0);
+}
+
+/*
+ * Touch the indicated file.
+ * This is nifty for the shell.
+ */
+void
+alter(name)
+ char *name;
+{
+ struct stat sb;
+ struct timeval tv[2];
+
+ if (stat(name, &sb))
+ return;
+ (void)gettimeofday(&tv[0], (struct timezone *)NULL);
+ tv[0].tv_sec++;
+ TIMESPEC_TO_TIMEVAL(&tv[1], &sb.st_mtimespec);
+ (void)utimes(name, tv);
+}
+
+/*
+ * Get sender's name from this message. If the message has
+ * a bunch of arpanet stuff in it, we may have to skin the name
+ * before returning it.
+ */
+char *
+nameof(mp, reptype)
+ struct message *mp;
+ int reptype;
+{
+ char *cp, *cp2;
+
+ cp = skin(name1(mp, reptype));
+ if (reptype != 0 || charcount(cp, '!') < 2)
+ return (cp);
+ cp2 = strrchr(cp, '!');
+ cp2--;
+ while (cp2 > cp && *cp2 != '!')
+ cp2--;
+ if (*cp2 == '!')
+ return (cp2 + 1);
+ return (cp);
+}
+
+/*
+ * Start of a "comment".
+ * Ignore it.
+ */
+char *
+skip_comment(cp)
+ char *cp;
+{
+ int nesting = 1;
+
+ for (; nesting > 0 && *cp; cp++) {
+ switch (*cp) {
+ case '\\':
+ if (cp[1])
+ cp++;
+ break;
+ case '(':
+ nesting++;
+ break;
+ case ')':
+ nesting--;
+ break;
+ }
+ }
+ return (cp);
+}
+
+/*
+ * Skin an arpa net address according to the RFC 822 interpretation
+ * of "host-phrase."
+ */
+char *
+skin(name)
+ char *name;
+{
+ char *nbuf, *bufend, *cp, *cp2;
+ int c, gotlt, lastsp;
+
+ if (name == NULL)
+ return (NULL);
+ if (strchr(name, '(') == NULL && strchr(name, '<') == NULL
+ && strchr(name, ' ') == NULL)
+ return (name);
+
+ /* We assume that length(input) <= length(output) */
+ if ((nbuf = malloc(strlen(name) + 1)) == NULL)
+ err(1, "Out of memory");
+ gotlt = 0;
+ lastsp = 0;
+ bufend = nbuf;
+ for (cp = name, cp2 = bufend; (c = *cp++) != '\0'; ) {
+ switch (c) {
+ case '(':
+ cp = skip_comment(cp);
+ lastsp = 0;
+ break;
+
+ case '"':
+ /*
+ * Start of a "quoted-string".
+ * Copy it in its entirety.
+ */
+ while ((c = *cp) != '\0') {
+ cp++;
+ if (c == '"')
+ break;
+ if (c != '\\')
+ *cp2++ = c;
+ else if ((c = *cp) != '\0') {
+ *cp2++ = c;
+ cp++;
+ }
+ }
+ lastsp = 0;
+ break;
+
+ case ' ':
+ if (cp[0] == 'a' && cp[1] == 't' && cp[2] == ' ')
+ cp += 3, *cp2++ = '@';
+ else
+ if (cp[0] == '@' && cp[1] == ' ')
+ cp += 2, *cp2++ = '@';
+ else
+ lastsp = 1;
+ break;
+
+ case '<':
+ cp2 = bufend;
+ gotlt++;
+ lastsp = 0;
+ break;
+
+ case '>':
+ if (gotlt) {
+ gotlt = 0;
+ while ((c = *cp) != '\0' && c != ',') {
+ cp++;
+ if (c == '(')
+ cp = skip_comment(cp);
+ else if (c == '"')
+ while ((c = *cp) != '\0') {
+ cp++;
+ if (c == '"')
+ break;
+ if (c == '\\' && *cp != '\0')
+ cp++;
+ }
+ }
+ lastsp = 0;
+ break;
+ }
+ /* FALLTHROUGH */
+
+ default:
+ if (lastsp) {
+ lastsp = 0;
+ *cp2++ = ' ';
+ }
+ *cp2++ = c;
+ if (c == ',' && *cp == ' ' && !gotlt) {
+ *cp2++ = ' ';
+ while (*++cp == ' ')
+ ;
+ lastsp = 0;
+ bufend = cp2;
+ }
+ }
+ }
+ *cp2 = '\0';
+
+ if ((cp = realloc(nbuf, strlen(nbuf) + 1)) != NULL)
+ nbuf = cp;
+ return (nbuf);
+}
+
+/*
+ * Fetch the sender's name from the passed message.
+ * Reptype can be
+ * 0 -- get sender's name for display purposes
+ * 1 -- get sender's name for reply
+ * 2 -- get sender's name for Reply
+ */
+char *
+name1(mp, reptype)
+ struct message *mp;
+ int reptype;
+{
+ char namebuf[LINESIZE];
+ char linebuf[LINESIZE];
+ char *cp, *cp2;
+ FILE *ibuf;
+ int first = 1;
+
+ if ((cp = hfield("from", mp)) != NULL)
+ return (cp);
+ if (reptype == 0 && (cp = hfield("sender", mp)) != NULL)
+ return (cp);
+ ibuf = setinput(mp);
+ namebuf[0] = '\0';
+ if (readline(ibuf, linebuf, LINESIZE) < 0)
+ return (savestr(namebuf));
+newname:
+ for (cp = linebuf; *cp != '\0' && *cp != ' '; cp++)
+ ;
+ for (; *cp == ' ' || *cp == '\t'; cp++)
+ ;
+ for (cp2 = &namebuf[strlen(namebuf)];
+ *cp != '\0' && *cp != ' ' && *cp != '\t' &&
+ cp2 < namebuf + LINESIZE - 1;)
+ *cp2++ = *cp++;
+ *cp2 = '\0';
+ if (readline(ibuf, linebuf, LINESIZE) < 0)
+ return (savestr(namebuf));
+ if ((cp = strchr(linebuf, 'F')) == NULL)
+ return (savestr(namebuf));
+ if (strncmp(cp, "From", 4) != 0)
+ return (savestr(namebuf));
+ while ((cp = strchr(cp, 'r')) != NULL) {
+ if (strncmp(cp, "remote", 6) == 0) {
+ if ((cp = strchr(cp, 'f')) == NULL)
+ break;
+ if (strncmp(cp, "from", 4) != 0)
+ break;
+ if ((cp = strchr(cp, ' ')) == NULL)
+ break;
+ cp++;
+ if (first) {
+ cp2 = namebuf;
+ first = 0;
+ } else
+ cp2 = strrchr(namebuf, '!') + 1;
+ strlcpy(cp2, cp, sizeof(namebuf) - (cp2 - namebuf) - 1);
+ strcat(namebuf, "!");
+ goto newname;
+ }
+ cp++;
+ }
+ return (savestr(namebuf));
+}
+
+/*
+ * Count the occurances of c in str
+ */
+int
+charcount(str, c)
+ char *str;
+ int c;
+{
+ char *cp;
+ int i;
+
+ for (i = 0, cp = str; *cp != '\0'; cp++)
+ if (*cp == c)
+ i++;
+ return (i);
+}
+
+/*
+ * See if the given header field is supposed to be ignored.
+ */
+int
+isign(field, ignore)
+ const char *field;
+ struct ignoretab ignore[2];
+{
+ char realfld[LINESIZE];
+
+ if (ignore == ignoreall)
+ return (1);
+ /*
+ * Lower-case the string, so that "Status" and "status"
+ * will hash to the same place.
+ */
+ istrncpy(realfld, field, sizeof(realfld));
+ if (ignore[1].i_count > 0)
+ return (!member(realfld, ignore + 1));
+ else
+ return (member(realfld, ignore));
+}
+
+int
+member(realfield, table)
+ char *realfield;
+ struct ignoretab *table;
+{
+ struct ignore *igp;
+
+ for (igp = table->i_head[hash(realfield)]; igp != NULL; igp = igp->i_link)
+ if (*igp->i_field == *realfield &&
+ equal(igp->i_field, realfield))
+ return (1);
+ return (0);
+}
diff --git a/mail_cmds/mail/cmd1.c b/mail_cmds/mail/cmd1.c
new file mode 100644
index 0000000..a1f9d61
--- /dev/null
+++ b/mail_cmds/mail/cmd1.c
@@ -0,0 +1,487 @@
+/*-
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)cmd1.c 8.2 (Berkeley) 4/20/95";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/cmd1.c,v 1.7 2002/06/30 05:25:05 obrien Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+#include "rcv.h"
+#include "extern.h"
+
+/*
+ * Mail -- a mail program
+ *
+ * User commands.
+ */
+
+extern const struct cmd cmdtab[];
+
+/*
+ * Print the current active headings.
+ * Don't change dot if invoker didn't give an argument.
+ */
+
+static int screen;
+
+int
+headers(msgvec)
+ int *msgvec;
+{
+ int n, mesg, flag, size;
+ struct message *mp;
+
+ size = screensize();
+ n = msgvec[0];
+ if (n != 0)
+ screen = (n-1)/size;
+ if (screen < 0)
+ screen = 0;
+ mp = &message[screen * size];
+ if (mp >= &message[msgCount])
+ mp = &message[msgCount - size];
+ if (mp < &message[0])
+ mp = &message[0];
+ flag = 0;
+ mesg = mp - &message[0];
+ if (dot != &message[n-1])
+ dot = mp;
+ for (; mp < &message[msgCount]; mp++) {
+ mesg++;
+ if (mp->m_flag & MDELETED)
+ continue;
+ if (flag++ >= size)
+ break;
+ printhead(mesg);
+ }
+ if (flag == 0) {
+ printf("No more mail.\n");
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Scroll to the next/previous screen
+ */
+int
+scroll(arg)
+ char arg[];
+{
+ int s, size;
+ int cur[1];
+
+ cur[0] = 0;
+ size = screensize();
+ s = screen;
+ switch (*arg) {
+ case 0:
+ case '+':
+ s++;
+ if (s * size >= msgCount) {
+ printf("On last screenful of messages\n");
+ return (0);
+ }
+ screen = s;
+ break;
+
+ case '-':
+ if (--s < 0) {
+ printf("On first screenful of messages\n");
+ return (0);
+ }
+ screen = s;
+ break;
+
+ default:
+ printf("Unrecognized scrolling command \"%s\"\n", arg);
+ return (1);
+ }
+ return (headers(cur));
+}
+
+/*
+ * Compute screen size.
+ */
+int
+screensize()
+{
+ int s;
+ char *cp;
+
+ if ((cp = value("screen")) != NULL && (s = atoi(cp)) > 0)
+ return (s);
+ return (screenheight - 4);
+}
+
+/*
+ * Print out the headlines for each message
+ * in the passed message list.
+ */
+int
+from(msgvec)
+ int *msgvec;
+{
+ int *ip;
+
+ for (ip = msgvec; *ip != 0; ip++)
+ printhead(*ip);
+ if (--ip >= msgvec)
+ dot = &message[*ip - 1];
+ return (0);
+}
+
+/*
+ * Print out the header of a specific message.
+ * This is a slight improvement to the standard one.
+ */
+void
+printhead(mesg)
+ int mesg;
+{
+ struct message *mp;
+ char headline[LINESIZE], wcount[LINESIZE], *subjline, dispc, curind;
+ char pbuf[BUFSIZ];
+ struct headline hl;
+ int subjlen;
+ char *name;
+
+ mp = &message[mesg-1];
+ (void)readline(setinput(mp), headline, LINESIZE);
+ if ((subjline = hfield("subject", mp)) == NULL)
+ subjline = hfield("subj", mp);
+ /*
+ * Bletch!
+ */
+ curind = dot == mp ? '>' : ' ';
+ dispc = ' ';
+ if (mp->m_flag & MSAVED)
+ dispc = '*';
+ if (mp->m_flag & MPRESERVE)
+ dispc = 'P';
+ if ((mp->m_flag & (MREAD|MNEW)) == MNEW)
+ dispc = 'N';
+ if ((mp->m_flag & (MREAD|MNEW)) == 0)
+ dispc = 'U';
+ if (mp->m_flag & MBOX)
+ dispc = 'M';
+ parse(headline, &hl, pbuf);
+ sprintf(wcount, "%3ld/%-5ld", mp->m_lines, mp->m_size);
+ subjlen = screenwidth - 50 - strlen(wcount);
+ name = value("show-rcpt") != NULL ?
+ skin(hfield("to", mp)) : nameof(mp, 0);
+ if (subjline == NULL || subjlen < 0) /* pretty pathetic */
+ printf("%c%c%3d %-20.20s %16.16s %s\n",
+ curind, dispc, mesg, name, hl.l_date, wcount);
+ else
+ printf("%c%c%3d %-20.20s %16.16s %s \"%.*s\"\n",
+ curind, dispc, mesg, name, hl.l_date, wcount,
+ subjlen, subjline);
+}
+
+/*
+ * Print out the value of dot.
+ */
+int
+pdot()
+{
+ printf("%ld\n", (uintptr_t)dot - (uintptr_t)&message[0] + 1);
+ return (0);
+}
+
+/*
+ * Print out all the possible commands.
+ */
+int
+pcmdlist()
+{
+ const struct cmd *cp;
+ int cc;
+
+ printf("Commands are:\n");
+ for (cc = 0, cp = cmdtab; cp->c_name != NULL; cp++) {
+ cc += strlen(cp->c_name) + 2;
+ if (cc > 72) {
+ printf("\n");
+ cc = strlen(cp->c_name) + 2;
+ }
+ if ((cp+1)->c_name != NULL)
+ printf("%s, ", cp->c_name);
+ else
+ printf("%s\n", cp->c_name);
+ }
+ return (0);
+}
+
+/*
+ * Paginate messages, honor ignored fields.
+ */
+int
+more(msgvec)
+ int *msgvec;
+{
+
+ return (type1(msgvec, 1, 1));
+}
+
+/*
+ * Paginate messages, even printing ignored fields.
+ */
+int
+More(msgvec)
+ int *msgvec;
+{
+
+ return (type1(msgvec, 0, 1));
+}
+
+/*
+ * Type out messages, honor ignored fields.
+ */
+int
+type(msgvec)
+ int *msgvec;
+{
+
+ return (type1(msgvec, 1, 0));
+}
+
+/*
+ * Type out messages, even printing ignored fields.
+ */
+int
+Type(msgvec)
+ int *msgvec;
+{
+
+ return (type1(msgvec, 0, 0));
+}
+
+/*
+ * Type out the messages requested.
+ */
+jmp_buf pipestop;
+int
+type1(msgvec, doign, page)
+ int *msgvec;
+ int doign, page;
+{
+ int nlines, *ip;
+ struct message *mp;
+ char *cp;
+ FILE *obuf;
+
+ obuf = stdout;
+ if (setjmp(pipestop))
+ goto close_pipe;
+ if (value("interactive") != NULL &&
+ (page || (cp = value("crt")) != NULL)) {
+ nlines = 0;
+ if (!page) {
+ for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++)
+ nlines += message[*ip - 1].m_lines;
+ }
+ if (page || nlines > (*cp ? atoi(cp) : realscreenheight)) {
+ cp = value("PAGER");
+ if (cp == NULL || *cp == '\0')
+ cp = _PATH_MORE;
+ obuf = Popen(cp, "w");
+ if (obuf == NULL) {
+ warnx("%s", cp);
+ obuf = stdout;
+ } else
+ (void)signal(SIGPIPE, brokpipe);
+ }
+ }
+
+ /*
+ * Send messages to the output.
+ *
+ */
+ for (ip = msgvec; *ip && ip - msgvec < msgCount; ip++) {
+ mp = &message[*ip - 1];
+ touch(mp);
+ dot = mp;
+ if (value("quiet") == NULL)
+ fprintf(obuf, "Message %d:\n", *ip);
+ (void)sendmessage(mp, obuf, doign ? ignore : 0, NULL);
+ }
+
+close_pipe:
+ if (obuf != stdout) {
+ /*
+ * Ignore SIGPIPE so it can't cause a duplicate close.
+ */
+ (void)signal(SIGPIPE, SIG_IGN);
+ (void)Pclose(obuf);
+ (void)signal(SIGPIPE, SIG_DFL);
+ }
+ return (0);
+}
+
+/*
+ * Respond to a broken pipe signal --
+ * probably caused by quitting more.
+ */
+/*ARGSUSED*/
+void
+brokpipe(signo)
+ int signo;
+{
+ longjmp(pipestop, 1);
+}
+
+/*
+ * Print the top so many lines of each desired message.
+ * The number of lines is taken from the variable "toplines"
+ * and defaults to 5.
+ */
+int
+top(msgvec)
+ int *msgvec;
+{
+ int *ip;
+ struct message *mp;
+ int c, topl, lines, lineb;
+ char *valtop, linebuf[LINESIZE];
+ FILE *ibuf;
+
+ topl = 5;
+ valtop = value("toplines");
+ if (valtop != NULL) {
+ topl = atoi(valtop);
+ if (topl < 0 || topl > 10000)
+ topl = 5;
+ }
+ lineb = 1;
+ for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
+ mp = &message[*ip - 1];
+ touch(mp);
+ dot = mp;
+ if (value("quiet") == NULL)
+ printf("Message %d:\n", *ip);
+ ibuf = setinput(mp);
+ c = mp->m_lines;
+ if (!lineb)
+ printf("\n");
+ for (lines = 0; lines < c && lines <= topl; lines++) {
+ if (readline(ibuf, linebuf, sizeof(linebuf)) < 0)
+ break;
+ puts(linebuf);
+ lineb = strspn(linebuf, " \t") == strlen(linebuf);
+ }
+ }
+ return (0);
+}
+
+/*
+ * Touch all the given messages so that they will
+ * get mboxed.
+ */
+int
+stouch(msgvec)
+ int msgvec[];
+{
+ int *ip;
+
+ for (ip = msgvec; *ip != 0; ip++) {
+ dot = &message[*ip-1];
+ dot->m_flag |= MTOUCH;
+ dot->m_flag &= ~MPRESERVE;
+ }
+ return (0);
+}
+
+/*
+ * Make sure all passed messages get mboxed.
+ */
+int
+mboxit(msgvec)
+ int msgvec[];
+{
+ int *ip;
+
+ for (ip = msgvec; *ip != 0; ip++) {
+ dot = &message[*ip-1];
+ dot->m_flag |= MTOUCH|MBOX;
+ dot->m_flag &= ~MPRESERVE;
+ }
+ return (0);
+}
+
+/*
+ * List the folders the user currently has.
+ */
+int
+folders()
+{
+ char dirname[PATHSIZE];
+ char *cmd;
+
+ if (getfold(dirname, sizeof(dirname)) < 0) {
+ printf("No value set for \"folder\"\n");
+ return (1);
+ }
+ if ((cmd = value("LISTER")) == NULL)
+ cmd = "ls";
+ (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);
+}
diff --git a/mail_cmds/mail/cmd2.c b/mail_cmds/mail/cmd2.c
new file mode 100644
index 0000000..7153b13
--- /dev/null
+++ b/mail_cmds/mail/cmd2.c
@@ -0,0 +1,587 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)cmd2.c 8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/cmd2.c,v 1.9 2002/06/30 05:25:06 obrien Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+#include "rcv.h"
+#include <sys/wait.h>
+#include "extern.h"
+
+/*
+ * Mail -- a mail program
+ *
+ * More user commands.
+ */
+
+extern int wait_status;
+
+/*
+ * If any arguments were given, go to the next applicable argument
+ * following dot, otherwise, go to the next applicable message.
+ * If given as first command with no arguments, print first message.
+ */
+int
+next(msgvec)
+ int *msgvec;
+{
+ struct message *mp;
+ int *ip, *ip2, list[2], mdot;
+
+ if (*msgvec != 0) {
+
+ /*
+ * If some messages were supplied, find the
+ * first applicable one following dot using
+ * wrap around.
+ */
+
+ mdot = dot - &message[0] + 1;
+
+ /*
+ * Find the first message in the supplied
+ * message list which follows dot.
+ */
+
+ for (ip = msgvec; *ip != 0; ip++) {
+ if (!sawcom) /* don't skip current message if first command */
+ break;
+ if (*ip > mdot)
+ break;
+ }
+ if (*ip == 0)
+ ip = msgvec;
+ ip2 = ip;
+ do {
+ mp = &message[*ip2 - 1];
+ if ((mp->m_flag & MDELETED) == 0) {
+ dot = mp;
+ goto hitit;
+ }
+ if (*ip2 != 0)
+ ip2++;
+ if (*ip2 == 0)
+ ip2 = msgvec;
+ } while (ip2 != ip);
+ printf("No messages applicable\n");
+ return (1);
+ }
+
+ /*
+ * If this is the first command, select message 1.
+ * Note that this must exist for us to get here at all.
+ */
+
+ if (!sawcom)
+ goto hitit;
+
+ /*
+ * Just find the next good message after dot, no
+ * wraparound.
+ */
+
+ for (mp = dot+1; mp < &message[msgCount]; mp++)
+ if ((mp->m_flag & (MDELETED|MSAVED)) == 0)
+ break;
+ if (mp >= &message[msgCount]) {
+ printf("At EOF\n");
+ return (0);
+ }
+ dot = mp;
+hitit:
+ /*
+ * Print dot.
+ */
+
+ list[0] = dot - &message[0] + 1;
+ list[1] = 0;
+ return (type(list));
+}
+
+/*
+ * Save a message in a file. Mark the message as saved
+ * so we can discard when the user quits.
+ */
+int
+save(str)
+ char str[];
+{
+
+ return (save1(str, 1, "save", saveignore));
+}
+
+/*
+ * Save a message list in a file named after author. Mark the message as saved
+ * so we can discard when the user quits.
+ */
+int
+Capsave(str)
+ char str[];
+{
+
+ return (save1(str, 1, "Save", saveignore));
+}
+
+/*
+ * Copy a message to a file without affected its saved-ness
+ */
+int
+copycmd(str)
+ char str[];
+{
+
+ return (save1(str, 0, "copy", saveignore));
+}
+
+/*
+ * Copy a message to a file named after author without affected its saved-ness
+ */
+int
+Capcopycmd(str)
+ char str[];
+{
+
+#if 1
+ printf("Copy command is not yet implemented\n");
+ return (1);
+#else
+ return (save1(str, 0, "Copy", saveignore));
+#endif
+}
+
+/*
+ * Save/copy the indicated messages at the end of the passed file name.
+ * If mark is true, mark the message "saved."
+ */
+int
+save1(str, mark, cmd, ignore)
+ char str[];
+ int mark;
+ const char *cmd;
+ struct ignoretab *ignore;
+{
+ struct message *mp;
+ char *file;
+ const char *disp;
+ int f, *msgvec, *ip;
+ FILE *obuf;
+ int doing_Save = !strcmp(cmd,"Save");
+
+ msgvec = (int *)salloc((msgCount + 2) * sizeof(*msgvec));
+ if ((file = snarf(str, &f, doing_Save)) == NULL)
+ return (1);
+ if (!f) {
+ *msgvec = first(0, MMNORM);
+ if (*msgvec == 0) {
+ printf("No messages to %s.\n", cmd);
+ return (1);
+ }
+ msgvec[1] = 0;
+ }
+ if (f && getmsglist(str, msgvec, 0) < 0)
+ return (1);
+ /* Save derives file name from author of first message: */
+ if (doing_Save) {
+ char *rcv;
+ mp = &message[msgvec[0] - 1];
+ touch(mp);
+ if ((rcv = skin(hfield("from", mp))) == NULL)
+ rcv = skin(nameof(mp, 1));
+ rcv = getauthor(rcv);
+ if (rcv == NULL) {
+ printf("Failed to find sender: Save not performed\n");
+ return(1);
+ }
+ file = rcv; /* use it as file name */
+ }
+ if ((file = expand(file)) == NULL)
+ return (1);
+ printf("\"%s\" ", file);
+ (void)fflush(stdout);
+ if (access(file, 0) >= 0)
+ disp = "[Appended]";
+ else
+ disp = "[New file]";
+ if ((obuf = Fopen(file, "a")) == NULL) {
+ warn((char *)NULL);
+ return (1);
+ }
+ for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
+ mp = &message[*ip - 1];
+ touch(mp);
+ if (sendmessage(mp, obuf, ignore, NULL) < 0) {
+ warnx("%s", file);
+ (void)Fclose(obuf);
+ return (1);
+ }
+ if (mark)
+ mp->m_flag |= MSAVED;
+ }
+ (void)fflush(obuf);
+ if (ferror(obuf))
+ warn("%s", file);
+ (void)Fclose(obuf);
+ printf("%s\n", disp);
+ return (0);
+}
+
+/*
+ * Write the indicated messages at the end of the passed
+ * file name, minus header and trailing blank line.
+ */
+int
+swrite(str)
+ char str[];
+{
+
+ return (save1(str, 1, "write", ignoreall));
+}
+
+/*
+ * Snarf the file from the end of the command line and
+ * return a pointer to it. If there is no file attached,
+ * just return NULL. Put a null in front of the file
+ * name so that the message list processing won't see it,
+ * unless the file name is the only thing on the line, in
+ * which case, return 0 in the reference flag variable.
+ */
+
+char *
+snarf(linebuf, flag, doing_Save)
+ char linebuf[];
+ int *flag;
+ int doing_Save;
+{
+ char *cp;
+
+ *flag = 1;
+ cp = strlen(linebuf) + linebuf - 1;
+
+ /*
+ * Strip away trailing blanks.
+ */
+
+ while (cp > linebuf && isspace((unsigned char)*cp))
+ cp--;
+ *++cp = '\0';
+
+ /*
+ * Now search for the beginning of the file name.
+ */
+
+ while (cp > linebuf && !isspace((unsigned char)*cp))
+ cp--;
+ if (*cp == '\0') {
+ if (!doing_Save)
+ printf("No file specified: using MBOX.\n");
+ *flag = 0; /* no message list found either */
+ return ("&");
+ }
+
+ if (isspace((unsigned char)*cp))
+ *cp++ = '\0';
+ else {
+ if (!doing_Save) *flag = 0;
+ }
+ return (cp);
+}
+
+/*
+ * Delete messages.
+ */
+int
+delete(msgvec)
+ int msgvec[];
+{
+
+ delm(msgvec);
+ return (0);
+}
+
+/*
+ * Delete messages, then type the new dot.
+ */
+int
+deltype(msgvec)
+ int msgvec[];
+{
+ int list[2];
+ int lastdot;
+
+ lastdot = dot - &message[0] + 1;
+ if (delm(msgvec) >= 0) {
+ list[0] = dot - &message[0] + 1;
+ if (list[0] > lastdot) {
+ touch(dot);
+ list[1] = 0;
+ return (type(list));
+ }
+ printf("At EOF\n");
+ } else
+ printf("No more messages\n");
+ return (0);
+}
+
+/*
+ * Delete the indicated messages.
+ * Set dot to some nice place afterwards.
+ * Internal interface.
+ */
+int
+delm(msgvec)
+ int *msgvec;
+{
+ struct message *mp;
+ int *ip, last;
+
+ last = 0;
+ for (ip = msgvec; *ip != 0; ip++) {
+ mp = &message[*ip - 1];
+ touch(mp);
+ mp->m_flag |= MDELETED|MTOUCH;
+ mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX);
+ last = *ip;
+ }
+ if (last != 0) {
+ dot = &message[last-1];
+ last = first(0, MDELETED);
+ if (last != 0) {
+ dot = &message[last-1];
+ return (0);
+ }
+ else {
+ dot = &message[0];
+ return (-1);
+ }
+ }
+
+ /*
+ * Following can't happen -- it keeps lint happy
+ */
+
+ return (-1);
+}
+
+/*
+ * Undelete the indicated messages.
+ */
+int
+undelete_messages(msgvec)
+ int *msgvec;
+{
+ struct message *mp;
+ int *ip;
+
+ for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
+ mp = &message[*ip - 1];
+ touch(mp);
+ dot = mp;
+ mp->m_flag &= ~MDELETED;
+ }
+ return (0);
+}
+
+/*
+ * Interactively dump core on "core"
+ */
+int
+core()
+{
+ int pid;
+
+ switch (pid = fork()) {
+ case -1:
+ warn("fork");
+ return (1);
+ case 0:
+ abort();
+ _exit(1);
+ }
+ printf("Okie dokie");
+ (void)fflush(stdout);
+ wait_child(pid);
+ if (WIFSIGNALED(wait_status) && WCOREDUMP(wait_status))
+ printf(" -- Core dumped.\n");
+ else
+ printf(" -- Can't dump core.\n");
+ return (0);
+}
+
+/*
+ * Clobber as many bytes of stack as the user requests.
+ */
+int
+clobber(argv)
+ char **argv;
+{
+ int times;
+
+ if (argv[0] == 0)
+ times = 1;
+ else
+ times = (atoi(argv[0]) + 511) / 512;
+ clob1(times);
+ return (0);
+}
+
+/*
+ * Clobber the stack.
+ */
+void
+clob1(n)
+ int n;
+{
+ char buf[512];
+ char *cp;
+
+ if (n <= 0)
+ return;
+ for (cp = buf; cp < &buf[512]; *cp++ = 0xFF)
+ ;
+ clob1(n - 1);
+}
+
+/*
+ * Add the given header fields to the retained list.
+ * If no arguments, print the current list of retained fields.
+ */
+int
+retfield(list)
+ char *list[];
+{
+
+ return (ignore1(list, ignore + 1, "retained"));
+}
+
+/*
+ * Add the given header fields to the ignored list.
+ * If no arguments, print the current list of ignored fields.
+ */
+int
+igfield(list)
+ char *list[];
+{
+
+ return (ignore1(list, ignore, "ignored"));
+}
+
+int
+saveretfield(list)
+ char *list[];
+{
+
+ return (ignore1(list, saveignore + 1, "retained"));
+}
+
+int
+saveigfield(list)
+ char *list[];
+{
+
+ return (ignore1(list, saveignore, "ignored"));
+}
+
+int
+ignore1(list, tab, which)
+ char *list[];
+ struct ignoretab *tab;
+ const char *which;
+{
+ char field[LINESIZE];
+ int h;
+ struct ignore *igp;
+ char **ap;
+
+ if (*list == NULL)
+ return (igshow(tab, which));
+ for (ap = list; *ap != 0; ap++) {
+ istrncpy(field, *ap, sizeof(field));
+ if (member(field, tab))
+ continue;
+ h = hash(field);
+ igp = calloc(1, sizeof(struct ignore));
+ igp->i_field = calloc((unsigned)strlen(field) + 1,
+ sizeof(char));
+ strcpy(igp->i_field, field);
+ igp->i_link = tab->i_head[h];
+ tab->i_head[h] = igp;
+ tab->i_count++;
+ }
+ return (0);
+}
+
+/*
+ * Print out all currently retained fields.
+ */
+int
+igshow(tab, which)
+ struct ignoretab *tab;
+ const char *which;
+{
+ int h;
+ struct ignore *igp;
+ char **ap, **ring;
+
+ if (tab->i_count == 0) {
+ printf("No fields currently being %s.\n", which);
+ return (0);
+ }
+ ring = (char **)salloc((tab->i_count + 1) * sizeof(char *));
+ ap = ring;
+ for (h = 0; h < HSHSIZE; h++)
+ for (igp = tab->i_head[h]; igp != NULL; igp = igp->i_link)
+ *ap++ = igp->i_field;
+ *ap = 0;
+ qsort(ring, tab->i_count, sizeof(char *), igcomp);
+ for (ap = ring; *ap != 0; ap++)
+ printf("%s\n", *ap);
+ return (0);
+}
+
+/*
+ * Compare two names for sorting ignored field list.
+ */
+int
+igcomp(l, r)
+ const void *l, *r;
+{
+
+ return (strcmp(*(const char **)l, *(const char **)r));
+}
diff --git a/mail_cmds/mail/cmd3.c b/mail_cmds/mail/cmd3.c
new file mode 100644
index 0000000..67bcd07
--- /dev/null
+++ b/mail_cmds/mail/cmd3.c
@@ -0,0 +1,840 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)cmd3.c 8.2 (Berkeley) 4/20/95";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/cmd3.c,v 1.10 2002/06/30 05:25:06 obrien Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+#include "rcv.h"
+#include "extern.h"
+
+/*
+ * Mail -- a mail program
+ *
+ * Still more user commands.
+ */
+
+/*
+ * Process a shell escape by saving signals, ignoring signals,
+ * and forking a sh -c
+ */
+int
+shell(str)
+ char *str;
+{
+ sig_t sigint = signal(SIGINT, SIG_IGN);
+ char *sh;
+ char cmd[BUFSIZ];
+
+ if (strlcpy(cmd, str, sizeof(cmd)) >= sizeof(cmd))
+ return (1);
+ if (bangexp(cmd, sizeof(cmd)) < 0)
+ return (1);
+ if ((sh = value("SHELL")) == NULL)
+ sh = _PATH_BSHELL;
+ (void)run_command(sh, 0, -1, -1, "-c", cmd, NULL);
+ (void)signal(SIGINT, sigint);
+ printf("!\n");
+ return (0);
+}
+
+/*
+ * Fork an interactive shell.
+ */
+/*ARGSUSED*/
+int
+dosh(str)
+ char *str;
+{
+ sig_t sigint = signal(SIGINT, SIG_IGN);
+ char *sh;
+
+ if ((sh = value("SHELL")) == NULL)
+ sh = _PATH_BSHELL;
+ (void)run_command(sh, 0, -1, -1, NULL, NULL, NULL);
+ (void)signal(SIGINT, sigint);
+ printf("\n");
+ return (0);
+}
+
+/*
+ * Expand the shell escape by expanding unescaped !'s into the
+ * last issued command where possible.
+ */
+int
+bangexp(str, strsize)
+ char *str;
+ size_t strsize;
+{
+ char bangbuf[BUFSIZ];
+ static char lastbang[BUFSIZ];
+ char *cp, *cp2;
+ int n, changed = 0;
+
+ if (value("bang") == NULL)
+ return (0);
+ cp = str;
+ cp2 = bangbuf;
+ n = sizeof(bangbuf);
+ while (*cp != '\0') {
+ if (*cp == '!') {
+ if (n < strlen(lastbang)) {
+overf:
+ printf("Command buffer overflow\n");
+ return (-1);
+ }
+ changed++;
+ if (strlcpy(cp2, lastbang, sizeof(bangbuf) - (cp2 - bangbuf))
+ >= sizeof(bangbuf) - (cp2 - bangbuf))
+ goto overf;
+ cp2 += strlen(lastbang);
+ n -= strlen(lastbang);
+ cp++;
+ continue;
+ }
+ if (*cp == '\\' && cp[1] == '!') {
+ if (--n <= 1)
+ goto overf;
+ *cp2++ = '!';
+ cp += 2;
+ changed++;
+ }
+ if (--n <= 1)
+ goto overf;
+ *cp2++ = *cp++;
+ }
+ *cp2 = 0;
+ if (changed) {
+ printf("!%s\n", bangbuf);
+ (void)fflush(stdout);
+ }
+ if (strlcpy(str, bangbuf, strsize) >= strsize)
+ goto overf;
+ if (strlcpy(lastbang, bangbuf, sizeof(lastbang)) >= sizeof(lastbang))
+ goto overf;
+ return (0);
+}
+
+/*
+ * Print out a nice help message from some file or another.
+ */
+
+int
+help()
+{
+ int c;
+ FILE *f;
+
+ if ((f = Fopen(_PATH_HELP, "r")) == NULL) {
+ warn("%s", _PATH_HELP);
+ return (1);
+ }
+ while ((c = getc(f)) != EOF)
+ putchar(c);
+ (void)Fclose(f);
+ return (0);
+}
+
+/*
+ * Change user's working directory.
+ */
+int
+schdir(arglist)
+ char **arglist;
+{
+ char *cp;
+
+ if (*arglist == NULL) {
+ if (homedir == NULL)
+ return (1);
+ cp = homedir;
+ } else
+ if ((cp = expand(*arglist)) == NULL)
+ return (1);
+ if (chdir(cp) < 0) {
+ warn("%s", cp);
+ return (1);
+ }
+ return (0);
+}
+
+char *
+getauthor(str)
+ char * str;
+{
+ char *atsign;
+ if (str == NULL) {
+ return(NULL);
+ }
+ atsign = strchr(str,'@');
+ if (atsign != NULL) {
+ str = savestr(str); /* copy to modify */
+ atsign = strchr(str,'@');
+ *atsign = '\0';
+ }
+/*
+printf("file name=%s\n", str);
+*/
+ return (str);
+}
+
+int
+followup(msgvec)
+ int *msgvec;
+{
+ int res;
+ int reset = 0;
+ if (value("recordrecip") == NULL) {
+ assign("recordrecip", "");
+ reset = 1;
+ }
+ res = respond(msgvec);
+ if (reset) {
+ char *alist[2];
+ alist[0] = "recordrecip";
+ alist[1] = NULL;
+ unset(alist);
+ }
+ return (res);
+}
+
+int
+Capfollowup(msgvec)
+ int *msgvec;
+{
+ int res;
+ int reset = 0;
+ if (value("recordrecip") == NULL) {
+ assign("recordrecip", "");
+ reset = 1;
+ }
+ res = Respond(msgvec);
+ if (reset) {
+ char *alist[2];
+ alist[0] = "recordrecip";
+ alist[1] = NULL;
+ unset(alist);
+ }
+ return (res);
+}
+
+int
+respond(msgvec)
+ int *msgvec;
+{
+ if (value("Replyall") == NULL && value("flipr") == NULL)
+ return (dorespond(msgvec));
+ else
+ return (doRespond(msgvec));
+}
+
+/*
+ * Reply to a list of messages. Extract each name from the
+ * message header and send them off to mail1()
+ */
+int
+dorespond(msgvec)
+ int *msgvec;
+{
+ struct message *mp;
+ char *cp, *rcv, *replyto;
+ char **ap;
+ struct name *np;
+ struct header head;
+
+ if (msgvec[1] != 0) {
+ printf("Sorry, can't reply to multiple messages at once\n");
+ return (1);
+ }
+ mp = &message[msgvec[0] - 1];
+ touch(mp);
+ dot = mp;
+ if ((rcv = skin(hfield("from", mp))) == NULL)
+ rcv = skin(nameof(mp, 1));
+ if ((replyto = skin(hfield("reply-to", mp))) != NULL)
+ np = extract(replyto, GTO);
+ else if ((cp = skin(hfield("to", mp))) != NULL)
+ np = extract(cp, GTO);
+ else
+ np = NULL;
+ np = elide(np);
+ /*
+ * Delete my name from the reply list,
+ * and with it, all my alternate names.
+ */
+ np = delname(np, myname);
+ if (altnames)
+ for (ap = altnames; *ap != NULL; ap++)
+ np = delname(np, *ap);
+ if (np != NULL && replyto == NULL)
+ np = cat(np, extract(rcv, GTO));
+ else if (np == NULL) {
+ if (replyto != NULL)
+ printf("Empty reply-to field -- replying to author\n");
+ np = extract(rcv, GTO);
+ }
+ head.h_to = np;
+ if ((head.h_subject = hfield("subject", mp)) == NULL)
+ head.h_subject = hfield("subj", mp);
+ head.h_subject = reedit(head.h_subject);
+ if (replyto == NULL && (cp = skin(hfield("cc", mp))) != NULL) {
+ np = elide(extract(cp, GCC));
+ np = delname(np, myname);
+ if (altnames != 0)
+ for (ap = altnames; *ap != NULL; ap++)
+ np = delname(np, *ap);
+ head.h_cc = np;
+ } else
+ head.h_cc = NULL;
+ head.h_bcc = NULL;
+ head.h_smopts = NULL;
+ head.h_replyto = value("REPLYTO");
+ head.h_inreplyto = skin(hfield("message-id", mp));
+ mail1(&head, 1);
+ return (0);
+}
+
+/*
+ * Modify the subject we are replying to to begin with Re: if
+ * it does not already.
+ */
+char *
+reedit(subj)
+ char *subj;
+{
+ char *newsubj;
+
+ if (subj == NULL)
+ return (NULL);
+ if ((subj[0] == 'r' || subj[0] == 'R') &&
+ (subj[1] == 'e' || subj[1] == 'E') &&
+ subj[2] == ':')
+ return (subj);
+ newsubj = salloc(strlen(subj) + 5);
+ sprintf(newsubj, "Re: %s", subj);
+ return (newsubj);
+}
+
+/*
+ * Preserve the named messages, so that they will be sent
+ * back to the system mailbox.
+ */
+int
+preserve(msgvec)
+ int *msgvec;
+{
+ int *ip, mesg;
+ struct message *mp;
+
+ if (edit) {
+ printf("Cannot \"preserve\" in edit mode\n");
+ return (1);
+ }
+ for (ip = msgvec; *ip != 0; ip++) {
+ mesg = *ip;
+ mp = &message[mesg-1];
+ mp->m_flag |= MPRESERVE;
+ mp->m_flag &= ~MBOX;
+ dot = mp;
+ }
+ return (0);
+}
+
+/*
+ * Mark all given messages as unread.
+ */
+int
+unread(msgvec)
+ int msgvec[];
+{
+ int *ip;
+
+ for (ip = msgvec; *ip != 0; ip++) {
+ dot = &message[*ip-1];
+ dot->m_flag &= ~(MREAD|MTOUCH);
+ dot->m_flag |= MSTATUS;
+ }
+ return (0);
+}
+
+/*
+ * Print the size of each message.
+ */
+int
+messize(msgvec)
+ int *msgvec;
+{
+ struct message *mp;
+ int *ip, mesg;
+
+ for (ip = msgvec; *ip != 0; ip++) {
+ mesg = *ip;
+ mp = &message[mesg-1];
+ printf("%d: %ld/%ld\n", mesg, mp->m_lines, mp->m_size);
+ }
+ return (0);
+}
+
+/*
+ * Quit quickly. If we are sourcing, just pop the input level
+ * by returning an error.
+ */
+int
+rexit(e)
+ int e;
+{
+ if (sourcing)
+ return (1);
+ exit(0);
+ /*NOTREACHED*/
+}
+
+/*
+ * Set or display a variable value. Syntax is similar to that
+ * of csh.
+ */
+int
+set(arglist)
+ char **arglist;
+{
+ struct var *vp;
+ char *cp, *cp2;
+ char varbuf[BUFSIZ], **ap, **p;
+ int errs, h, s;
+ int stringlength;
+
+ if (*arglist == NULL) {
+ char * printval;
+ for (h = 0, s = 1; h < HSHSIZE; h++)
+ for (vp = variables[h]; vp != NULL; vp = vp->v_link)
+ s++;
+ ap = (char **)salloc(s * sizeof(*ap));
+ for (h = 0, p = ap; h < HSHSIZE; h++)
+ for (vp = variables[h]; vp != NULL; vp = vp->v_link)
+ *p++ = vp->v_name;
+ *p = NULL;
+ sort(ap);
+ for (p = ap; *p != NULL; p++) {
+ printf("%s", *p);
+ printval = value(*p);
+ if (printval) {
+ if (printval[0]!='\0') printf("\t\"%s\"", printval);
+ }
+ printf("\n");
+ }
+ return (0);
+ }
+ errs = 0;
+ for (ap = arglist; *ap != NULL; ap++) {
+ cp = *ap;
+ stringlength = strlen(cp);
+ if (stringlength > 2 && cp[0]=='n' && cp[1]=='o') {
+ /* set no<var> means unset <var> */
+ char *alist[2];
+ alist[0] = cp+2;
+ alist[1] = NULL;
+ errs += unset(alist);
+ continue;
+ }
+ if (stringlength == 3 && cp[0]=='a' && cp[1]=='s' && cp[2]=='k') {
+ /* synonym: must convert into "asksub" */
+ cp = "asksub";
+ }
+ cp2 = varbuf;
+ while (cp2 < varbuf + sizeof(varbuf) - 1 && *cp != '=' && *cp != '\0')
+ *cp2++ = *cp++;
+ *cp2 = '\0';
+ if (*cp == '\0')
+ cp = "";
+ else
+ cp++;
+ if (equal(varbuf, "")) {
+ printf("Non-null variable name required\n");
+ errs++;
+ continue;
+ }
+ assign(varbuf, cp);
+ }
+ return (errs);
+}
+
+/*
+ * Unset a bunch of variable values.
+ */
+int
+unset(arglist)
+ char **arglist;
+{
+ struct var *vp, *vp2;
+ int errs, h;
+ char **ap;
+ int stringlength;
+
+ errs = 0;
+ for (ap = arglist; *ap != NULL; ap++) {
+ stringlength = strlen(*ap);
+ if (stringlength > 2 && (*ap)[0]=='n' && (*ap)[1]=='o') {
+ /* no<var> is not in db - only <var> can be in table */
+ printf("\"%s\": variable cannot be unset\n", *ap);
+ errs++;
+ continue;
+ }
+ if (stringlength == 3 && (*ap)[0]=='a' && (*ap)[1]=='s' && (*ap)[2]=='k') {
+ /* synonym: must convert into "asksub" */
+ *ap = "asksub";
+ }
+ if ((vp2 = lookup(*ap)) == NULL) {
+ if (getenv(*ap)) {
+ unsetenv(*ap);
+ if (debug)
+ fprintf(stderr,"WARNING: unsetting environment variable: %s\n", *ap);
+ } else if (!sourcing) {
+ printf("\"%s\": undefined variable\n", *ap);
+ errs++;
+ }
+ continue;
+ }
+ h = hash(*ap);
+ if (vp2 == variables[h]) {
+ variables[h] = variables[h]->v_link;
+ v_free(vp2->v_name);
+ v_free(vp2->v_value);
+ (void)free(vp2);
+ continue;
+ }
+ for (vp = variables[h]; vp->v_link != vp2; vp = vp->v_link)
+ ;
+ vp->v_link = vp2->v_link;
+ v_free(vp2->v_name);
+ v_free(vp2->v_value);
+ (void)free(vp2);
+ }
+ return (errs);
+}
+
+/*
+ * Put add users to a group.
+ */
+int
+group(argv)
+ char **argv;
+{
+ struct grouphead *gh;
+ struct group *gp;
+ char **ap, *gname, **p;
+ int h, s;
+
+ if (*argv == NULL) {
+ for (h = 0, s = 1; h < HSHSIZE; h++)
+ for (gh = groups[h]; gh != NULL; gh = gh->g_link)
+ s++;
+ ap = (char **)salloc(s * sizeof(*ap));
+ for (h = 0, p = ap; h < HSHSIZE; h++)
+ for (gh = groups[h]; gh != NULL; gh = gh->g_link)
+ *p++ = gh->g_name;
+ *p = NULL;
+ sort(ap);
+ for (p = ap; *p != NULL; p++)
+ printgroup(*p);
+ return (0);
+ }
+ if (argv[1] == NULL) {
+ printgroup(*argv);
+ return (0);
+ }
+ gname = *argv;
+ h = hash(gname);
+ if ((gh = findgroup(gname)) == NULL) {
+ gh = calloc(sizeof(*gh), 1);
+ gh->g_name = vcopy(gname);
+ gh->g_list = NULL;
+ gh->g_link = groups[h];
+ groups[h] = gh;
+ }
+
+ /*
+ * Insert names from the command list into the group.
+ * Who cares if there are duplicates? They get tossed
+ * later anyway.
+ */
+
+ for (ap = argv+1; *ap != NULL; ap++) {
+ gp = calloc(sizeof(*gp), 1);
+ gp->ge_name = vcopy(*ap);
+ gp->ge_link = gh->g_list;
+ gh->g_list = gp;
+ }
+ return (0);
+}
+
+/*
+ * Sort the passed string vecotor into ascending dictionary
+ * order.
+ */
+void
+sort(list)
+ char **list;
+{
+ char **ap;
+
+ for (ap = list; *ap != NULL; ap++)
+ ;
+ if (ap-list < 2)
+ return;
+ qsort(list, ap-list, sizeof(*list), diction);
+}
+
+/*
+ * Do a dictionary order comparison of the arguments from
+ * qsort.
+ */
+int
+diction(a, b)
+ const void *a, *b;
+{
+ return (strcmp(*(const char **)a, *(const char **)b));
+}
+
+/*
+ * The do nothing command for comments.
+ */
+
+/*ARGSUSED*/
+int
+null(e)
+ int e;
+{
+ return (0);
+}
+
+/*
+ * Change to another file. With no argument, print information about
+ * the current file.
+ */
+int
+file(argv)
+ char **argv;
+{
+
+ if (argv[0] == NULL) {
+ newfileinfo(0);
+ return (0);
+ }
+ if (setfile(*argv) < 0)
+ return (1);
+ announce();
+ return (0);
+}
+
+/*
+ * Expand file names like echo
+ */
+int
+echo(argv)
+ char **argv;
+{
+ char **ap, *cp;
+
+ for (ap = argv; *ap != NULL; ap++) {
+ cp = *ap;
+ if ((cp = expand(cp)) != NULL) {
+ if (ap != argv)
+ printf(" ");
+ printf("%s", cp);
+ }
+ }
+ printf("\n");
+ return (0);
+}
+
+int
+Respond(msgvec)
+ int *msgvec;
+{
+ if (value("Replyall") == NULL && value("flipr") == NULL)
+ return (doRespond(msgvec));
+ else
+ return (dorespond(msgvec));
+}
+
+/*
+ * Reply to a series of messages by simply mailing to the senders
+ * and not messing around with the To: and Cc: lists as in normal
+ * reply.
+ */
+int
+doRespond(msgvec)
+ int msgvec[];
+{
+ struct header head;
+ struct message *mp;
+ int *ap;
+ char *cp, *mid = NULL;
+
+ head.h_to = NULL;
+ for (ap = msgvec; *ap != 0; ap++) {
+ mp = &message[*ap - 1];
+ touch(mp);
+ dot = mp;
+ if ((cp = skin(hfield("from", mp))) == NULL)
+ cp = skin(nameof(mp, 2));
+ head.h_to = cat(head.h_to, extract(cp, GTO));
+ mid = skin(hfield("message-id", mp));
+ }
+ if (head.h_to == NULL)
+ return (0);
+ mp = &message[msgvec[0] - 1];
+ if ((head.h_subject = hfield("subject", mp)) == NULL)
+ head.h_subject = hfield("subj", mp);
+ head.h_subject = reedit(head.h_subject);
+ head.h_cc = NULL;
+ head.h_bcc = NULL;
+ head.h_smopts = NULL;
+ head.h_replyto = value("REPLYTO");
+ head.h_inreplyto = mid;
+ mail1(&head, 1);
+ return (0);
+}
+
+/*
+ * Conditional commands. These allow one to parameterize one's
+ * .mailrc and do some things if sending, others if receiving.
+ */
+int
+ifcmd(argv)
+ char **argv;
+{
+ char *cp;
+
+ if (cond != CANY) {
+ printf("Illegal nested \"if\"\n");
+ return (1);
+ }
+ cond = CANY;
+ cp = argv[0];
+ switch (*cp) {
+ case 'r': case 'R':
+ cond = CRCV;
+ break;
+
+ case 's': case 'S':
+ cond = CSEND;
+ break;
+
+ default:
+ printf("Unrecognized if-keyword: \"%s\"\n", cp);
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Implement 'else'. This is pretty simple -- we just
+ * flip over the conditional flag.
+ */
+int
+elsecmd()
+{
+
+ switch (cond) {
+ case CANY:
+ printf("\"Else\" without matching \"if\"\n");
+ return (1);
+
+ case CSEND:
+ cond = CRCV;
+ break;
+
+ case CRCV:
+ cond = CSEND;
+ break;
+
+ default:
+ printf("Mail's idea of conditions is screwed up\n");
+ cond = CANY;
+ break;
+ }
+ return (0);
+}
+
+/*
+ * End of if statement. Just set cond back to anything.
+ */
+int
+endifcmd()
+{
+
+ if (cond == CANY) {
+ printf("\"Endif\" without matching \"if\"\n");
+ return (1);
+ }
+ cond = CANY;
+ return (0);
+}
+
+/*
+ * Set the list of alternate names.
+ */
+int
+alternates(namelist)
+ char **namelist;
+{
+ int c;
+ char **ap, **ap2, *cp;
+
+ c = argcount(namelist) + 1;
+ if (c == 1) {
+ if (altnames == 0)
+ return (0);
+ for (ap = altnames; *ap != NULL; ap++)
+ printf("%s ", *ap);
+ printf("\n");
+ return (0);
+ }
+ if (altnames != 0)
+ (void)free(altnames);
+ altnames = calloc((unsigned)c, sizeof(char *));
+ for (ap = namelist, ap2 = altnames; *ap != NULL; ap++, ap2++) {
+ cp = calloc((unsigned)strlen(*ap) + 1, sizeof(char));
+ strcpy(cp, *ap);
+ *ap2 = cp;
+ }
+ *ap2 = 0;
+ return (0);
+}
diff --git a/mail_cmds/mail/cmdtab.c b/mail_cmds/mail/cmdtab.c
new file mode 100644
index 0000000..d001ac1
--- /dev/null
+++ b/mail_cmds/mail/cmdtab.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)cmdtab.c 8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/cmdtab.c,v 1.6 2002/06/30 05:25:06 obrien Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+#include "def.h"
+#include "extern.h"
+
+/*
+ * Mail -- a mail program
+ *
+ * Define all of the command names and bindings.
+ */
+
+const struct cmd cmdtab[] = {
+ /* msgmask msgflag */
+ /* command function argtype result & mask */
+ /* ------- -------- ------- ------ ------- */
+ { "next", next, NDMLIST, 0, MMNDEL },
+ { "alias", group, M|RAWLIST, 0, 1000 },
+ { "print", type, MSGLIST, 0, MMNDEL },
+ { "type", type, MSGLIST, 0, MMNDEL },
+ { "Type", Type, MSGLIST, 0, MMNDEL },
+ { "Print", Type, MSGLIST, 0, MMNDEL },
+ { "visual", visual, I|MSGLIST, 0, MMNORM },
+ { "top", top, MSGLIST, 0, MMNDEL },
+ { "touch", stouch, W|MSGLIST, 0, MMNDEL },
+ { "preserve", preserve, W|MSGLIST, 0, MMNDEL },
+ { "delete", delete, W|P|MSGLIST, 0, MMNDEL },
+ { "dp", deltype, W|MSGLIST, 0, MMNDEL },
+ { "dt", deltype, W|MSGLIST, 0, MMNDEL },
+ { "undelete", undelete_messages, P|MSGLIST, MDELETED,MMNDEL },
+ { "unset", unset, M|RAWLIST, 1, 1000 },
+ { "mail", sendmail, R|M|I|STRLIST, 0, 0 },
+ { "mbox", mboxit, W|MSGLIST, 0, 0 },
+ { "more", more, MSGLIST, 0, MMNDEL },
+ { "page", more, MSGLIST, 0, MMNDEL },
+ { "More", More, MSGLIST, 0, MMNDEL },
+ { "Page", More, MSGLIST, 0, MMNDEL },
+ { "unread", unread, MSGLIST, 0, MMNDEL },
+ { "!", shell, I|STRLIST, 0, 0 },
+ { "copy", copycmd, M|STRLIST, 0, 0 },
+ { "Copy", Capcopycmd, MSGLIST, 0, 0 },
+ { "chdir", schdir, M|RAWLIST, 0, 1 },
+ { "cd", schdir, M|RAWLIST, 0, 1 },
+ { "save", save, STRLIST, 0, 0 },
+ { "Save", Capsave, STRLIST, 0, 0 },
+ { "source", source, M|RAWLIST, 1, 1 },
+ { "set", set, M|RAWLIST, 0, 1000 },
+ { "shell", dosh, I|NOLIST, 0, 0 },
+ { "version", pversion, M|NOLIST, 0, 0 },
+ { "group", group, M|RAWLIST, 0, 1000 },
+ { "write", swrite, STRLIST, 0, 0 },
+ { "from", from, MSGLIST, 0, MMNORM },
+ { "file", file, T|M|RAWLIST, 0, 1 },
+ { "followup", followup, MSGLIST, 0, 0 },
+ { "folder", file, T|M|RAWLIST, 0, 1 },
+ { "folders", folders, T|M|NOLIST, 0, 0 },
+ { "Followup", Capfollowup, MSGLIST, 0, 0 },
+ { "|", mailpipe, STRLIST, 0, 0 },
+ { "pipe", mailpipe, STRLIST, 0, 0 },
+ { "?", help, M|NOLIST, 0, 0 },
+ { "z", scroll, M|STRLIST, 0, 0 },
+ { "headers", headers, MSGLIST, 0, MMNDEL },
+ { "help", help, M|NOLIST, 0, 0 },
+ { "=", pdot, NOLIST, 0, 0 },
+ { "Reply", Respond, R|I|MSGLIST, 0, MMNDEL },
+ { "Respond", Respond, R|I|MSGLIST, 0, MMNDEL },
+ { "reply", respond, R|I|MSGLIST, 0, MMNDEL },
+ { "respond", respond, R|I|MSGLIST, 0, MMNDEL },
+ { "edit", editor, I|MSGLIST, 0, MMNORM },
+ { "echo", echo, M|RAWLIST, 0, 1000 },
+ { "quit", quitcmd, NOLIST, 0, 0 },
+ { "list", pcmdlist, M|NOLIST, 0, 0 },
+ { "xit", rexit, M|NOLIST, 0, 0 },
+ { "exit", rexit, M|NOLIST, 0, 0 },
+ { "size", messize, MSGLIST, 0, MMNDEL },
+ { "hold", preserve, W|MSGLIST, 0, MMNDEL },
+ { "if", ifcmd, F|M|RAWLIST, 1, 1 },
+ { "else", elsecmd, F|M|RAWLIST, 0, 0 },
+ { "endif", endifcmd, F|M|RAWLIST, 0, 0 },
+ { "alternates", alternates, M|RAWLIST, 0, 1000 },
+ { "ignore", igfield, M|RAWLIST, 0, 1000 },
+ { "discard", igfield, M|RAWLIST, 0, 1000 },
+ { "retain", retfield, M|RAWLIST, 0, 1000 },
+ { "saveignore", saveigfield, M|RAWLIST, 0, 1000 },
+ { "savediscard",saveigfield, M|RAWLIST, 0, 1000 },
+ { "saveretain", saveretfield, M|RAWLIST, 0, 1000 },
+/* { "Header", Header, STRLIST, 0, 1000 }, */
+ { "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 }
+};
diff --git a/mail_cmds/mail/collect.c b/mail_cmds/mail/collect.c
new file mode 100644
index 0000000..703f953
--- /dev/null
+++ b/mail_cmds/mail/collect.c
@@ -0,0 +1,998 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)collect.c 8.2 (Berkeley) 4/19/94";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/collect.c,v 1.12 2002/06/30 05:25:06 obrien Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+/*
+ * Mail -- a mail program
+ *
+ * Collect input from standard input, handling
+ * ~ escapes.
+ */
+
+#include "rcv.h"
+#include <fcntl.h>
+#include "extern.h"
+
+/*
+ * Read a message from standard output and return a read file to it
+ * or NULL on error.
+ */
+
+/*
+ * The following hokiness with global variables is so that on
+ * receipt of an interrupt signal, the partial message can be salted
+ * away on dead.letter.
+ */
+
+static sig_t saveint; /* Previous SIGINT value */
+static sig_t savehup; /* Previous SIGHUP value */
+static sig_t savetstp; /* Previous SIGTSTP value */
+static sig_t savettou; /* Previous SIGTTOU value */
+static sig_t savettin; /* Previous SIGTTIN value */
+static FILE *collf; /* File for saving away */
+static int hadintr; /* Have seen one SIGINT so far */
+
+static jmp_buf colljmp; /* To get back to work */
+static int colljmp_p; /* whether to long jump */
+static jmp_buf collabort; /* To end collection with error */
+
+static jmp_buf pipejmp; /* To catch the loss of pipe connection */
+
+void
+brokthepipe(signo)
+ int signo;
+{
+ longjmp(pipejmp, 1);
+}
+
+FILE *
+collect(hp, printheaders)
+ struct header *hp;
+ int printheaders;
+{
+ FILE *fbuf;
+ int lc, cc, escape, eofcount, fd, c, t;
+ char linebuf[LINESIZE], tempname[PATHSIZE], *cp, getsub;
+ sigset_t nset;
+ int longline, lastlong, rc; /* So we don't make 2 or more lines
+ out of a long input line. */
+ int nlines, usepager;
+ char *envptr;
+
+ collf = NULL;
+ /*
+ * Start catching signals from here, but we're still die on interrupts
+ * until we're in the main loop.
+ */
+ (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)
+ (void)signal(SIGHUP, collhup);
+ savetstp = signal(SIGTSTP, collstop);
+ savettou = signal(SIGTTOU, collstop);
+ savettin = signal(SIGTTIN, collstop);
+ if (setjmp(collabort) || setjmp(colljmp)) {
+ (void)rm(tempname);
+ goto err;
+ }
+ (void)sigprocmask(SIG_UNBLOCK, &nset, NULL);
+
+ noreset++;
+ (void)snprintf(tempname, sizeof(tempname),
+ "%s/mail.RsXXXXXXXXXX", tmpdir);
+ if ((fd = mkstemp(tempname)) == -1 ||
+ (collf = Fdopen(fd, "w+")) == NULL) {
+ warn("%s", tempname);
+ goto err;
+ }
+ (void)rm(tempname);
+
+ /*
+ * If we are going to prompt for a subject,
+ * refrain from printing a newline after
+ * the headers (since some people mind).
+ */
+ t = GTO|GSUBJECT|GCC|GNL;
+ getsub = 0;
+ if (hp->h_subject == NULL && value("interactive") != NULL &&
+ (value("ask") != NULL || value("asksub") != NULL))
+ t &= ~GNL, getsub++;
+ if (printheaders) {
+ puthead(hp, stdout, t);
+ (void)fflush(stdout);
+ }
+ if ((cp = value("escape")) != NULL)
+ escape = *cp;
+ else
+ escape = ESCAPE;
+ eofcount = 0;
+ hadintr = 0;
+ lastlong = 0;
+ longline = 0;
+
+ if (!setjmp(colljmp)) {
+ if (getsub) {
+ if (grabh(hp, GSUBJECT)) {
+ /* grabh was interrupted: must count as first one */
+ /* makes Unix 2003 conformance tests mailx_01.ex{49,57} pass */
+ /* printf("Interrupt from Subject:\n"); */
+ hadintr++;
+ goto cont;
+ }
+ }
+ } else {
+ /*
+ * Come here for printing the after-signal message.
+ * Duplicate messages won't be printed because
+ * the write is aborted if we get a SIGTTOU.
+ */
+cont:
+ if (hadintr) {
+ (void)fflush(stdout);
+ fprintf(stderr,
+ "\n(Interrupt -- one more to kill letter)\n");
+ } else {
+ printf("(continue)\n");
+ (void)fflush(stdout);
+ }
+ }
+ for (;;) {
+ colljmp_p = 1;
+ c = readline(stdin, linebuf, LINESIZE);
+ colljmp_p = 0;
+ if (c < 0) {
+ if (value("interactive") != NULL &&
+ value("ignoreeof") != NULL && ++eofcount < 25) {
+ printf("Use \".\" to terminate letter\n");
+ continue;
+ }
+ break;
+ }
+ lastlong = longline;
+ longline = c == LINESIZE - 1;
+ eofcount = 0;
+ hadintr = 0;
+ if (linebuf[0] == '.' && linebuf[1] == '\0' &&
+ value("interactive") != NULL && !lastlong &&
+ (value("dot") != NULL || value("ignoreeof") != NULL))
+ break;
+ if (linebuf[0] != escape || value("interactive") == NULL ||
+ lastlong) {
+ if (putline(collf, linebuf, !longline) < 0)
+ goto err;
+ continue;
+ }
+ c = linebuf[1];
+ switch (c) {
+ default:
+ /*
+ * On double escape, just send the single one.
+ * Otherwise, it's an error.
+ */
+ if (c == escape) {
+ if (putline(collf, &linebuf[1], !longline) < 0)
+ goto err;
+ else
+ break;
+ }
+ printf("Unknown tilde escape.\n");
+ break;
+ case 'C':
+ /*
+ * Dump core.
+ */
+ core();
+ break;
+ case '!':
+ /*
+ * Shell escape, send the balance of the
+ * line to sh -c.
+ */
+ shell(&linebuf[2]);
+ break;
+ case ':':
+ case '_':
+ /*
+ * Escape to command mode, but be nice!
+ */
+ execute(&linebuf[2], 1);
+ goto cont;
+ case '.':
+ /*
+ * Simulate end of file on input.
+ */
+ goto out;
+ case 'q':
+ /*
+ * Force a quit of sending mail.
+ * Act like an interrupt happened.
+ */
+ hadintr++;
+ collint(SIGINT);
+ exit(1);
+ case 'x':
+ /*
+ * Exit, do not save in dead.letter.
+ */
+ goto err;
+ case 'h':
+ /*
+ * Grab a bunch of headers.
+ */
+ grabh(hp, GTO|GSUBJECT|GCC|GBCC);
+ goto cont;
+ case 't':
+ /*
+ * Add to the To list.
+ */
+ hp->h_to = cat(hp->h_to, extract(&linebuf[2], GTO));
+ break;
+ case 's':
+ /*
+ * Set the Subject line.
+ */
+ cp = &linebuf[2];
+ while (isspace((unsigned char)*cp))
+ cp++;
+ hp->h_subject = savestr(cp);
+ break;
+ case 'R':
+ /*
+ * Set the Reply-To line.
+ */
+ cp = &linebuf[2];
+ while (isspace((unsigned char)*cp))
+ cp++;
+ hp->h_replyto = savestr(cp);
+ break;
+ case 'c':
+ /*
+ * Add to the CC list.
+ */
+ hp->h_cc = cat(hp->h_cc, extract(&linebuf[2], GCC));
+ break;
+ case 'b':
+ /*
+ * Add to the BCC list.
+ */
+ hp->h_bcc = cat(hp->h_bcc, extract(&linebuf[2], GBCC));
+ break;
+ case 'i':
+ case 'A':
+ case 'a':
+ /*
+ * Insert named variable in message.
+ */
+ switch(c) {
+ case 'i':
+ cp = &linebuf[2];
+ while(isspace((unsigned char)*cp))
+ cp++;
+ break;
+ case 'a':
+ cp = "sign";
+ break;
+ case 'A':
+ cp = "Sign";
+ break;
+ default:
+ goto err;
+ }
+
+ if(*cp != '\0' && (cp = value(cp)) != NULL) {
+ if (*cp != '\0') {
+ printf("%s\n", cp);
+ if(putline(collf, cp, 1) < 0)
+ goto err;
+ }
+ }
+
+ break;
+ case 'd':
+ /*
+ * Read in the dead letter file.
+ */
+ if (strlcpy(linebuf + 2, getdeadletter(),
+ sizeof(linebuf) - 2)
+ >= sizeof(linebuf) - 2) {
+ printf("Line buffer overflow\n");
+ break;
+ }
+ /* FALLTHROUGH */
+ case 'r':
+ case '<':
+ /*
+ * Invoke a file:
+ * Search for the file name,
+ * then open it and copy the contents to collf.
+ */
+ cp = &linebuf[2];
+ while (isspace((unsigned char)*cp))
+ cp++;
+ if (*cp == '\0') {
+ printf("Interpolate what file?\n");
+ break;
+ }
+ cp = expand(cp);
+ if (cp == NULL)
+ break;
+ if (*cp == '!') {
+ /*
+ * Insert stdout of command.
+ */
+ char *sh;
+ int nullfd, tempfd, rc;
+ char tempname2[PATHSIZE];
+
+ if ((nullfd = open("/dev/null", O_RDONLY, 0))
+ == -1) {
+ warn("/dev/null");
+ break;
+ }
+
+ (void)snprintf(tempname2, sizeof(tempname2),
+ "%s/mail.ReXXXXXXXXXX", tmpdir);
+ if ((tempfd = mkstemp(tempname2)) == -1 ||
+ (fbuf = Fdopen(tempfd, "w+")) == NULL) {
+ warn("%s", tempname2);
+ break;
+ }
+ (void)unlink(tempname2);
+
+ if ((sh = value("SHELL")) == NULL)
+ sh = _PATH_BSHELL;
+
+ rc = run_command(sh, 0, nullfd, fileno(fbuf),
+ "-c", cp+1, NULL);
+
+ close(nullfd);
+
+ if (rc < 0) {
+ (void)Fclose(fbuf);
+ break;
+ }
+
+ if (fsize(fbuf) == 0) {
+ fprintf(stderr,
+ "No bytes from command \"%s\"\n",
+ cp+1);
+ (void)Fclose(fbuf);
+ break;
+ }
+
+ rewind(fbuf);
+ } else if (isdir(cp)) {
+ printf("%s: Directory\n", cp);
+ break;
+ } else if ((fbuf = Fopen(cp, "r")) == NULL) {
+ warn("%s", cp);
+ break;
+ }
+ printf("\"%s\" ", cp);
+ (void)fflush(stdout);
+ lc = 0;
+ cc = 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;
+ }
+ cc += t;
+ }
+ (void)Fclose(fbuf);
+ printf("%d/%d\n", lc, cc);
+ break;
+ case 'w':
+ /*
+ * Write the message on a file.
+ */
+ cp = &linebuf[2];
+ while (*cp == ' ' || *cp == '\t')
+ cp++;
+ if (*cp == '\0') {
+ fprintf(stderr, "Write what file!?\n");
+ break;
+ }
+ if ((cp = expand(cp)) == NULL)
+ break;
+ rewind(collf);
+ exwrite(cp, collf, 1);
+ break;
+ case 'm':
+ case 'M':
+ case 'f':
+ case 'F':
+ /*
+ * Interpolate the named messages, if we
+ * are in receiving mail mode. Does the
+ * standard list processing garbage.
+ * If ~f is given, we don't shift over.
+ */
+ if (forward(linebuf + 2, collf, tempname, c) < 0)
+ goto err;
+ goto cont;
+ case '?':
+ if ((fbuf = Fopen(_PATH_TILDE, "r")) == NULL) {
+ warn("%s", _PATH_TILDE);
+ break;
+ }
+ while ((t = getc(fbuf)) != EOF)
+ (void)putchar(t);
+ (void)Fclose(fbuf);
+ break;
+ case 'p':
+ /*
+ * Print out the current state of the
+ * message without altering anything.
+ */
+ rewind(collf);
+ printf("-------\nMessage contains:\n");
+ puthead(hp, stdout, GTO|GSUBJECT|GCC|GBCC|GNL);
+ if ((envptr = value("crt")) != NULL) {
+ nlines = atoi(envptr);
+ } else {
+ nlines = 0;
+ }
+ fbuf = stdout;
+ usepager = 0;
+ if (nlines>0) {
+ /* See if crt < num lines in file */
+ int countlines = 0;
+ while ((t = getc(collf)) != EOF) {
+ if (t=='\n') {
+ countlines++;
+ if (nlines < countlines) {
+ break;
+ }
+ }
+ }
+ rewind(collf);
+ if (nlines < countlines) {
+ /* Must use a paginator: default is "more" */
+ usepager = 1;
+ envptr = value("PAGER");
+ if (envptr == NULL || *envptr == '\0')
+ envptr = _PATH_MORE;
+ if (setjmp(pipejmp))
+ goto close_pipe;
+ fbuf = Popen(envptr, "w");
+ if (fbuf == NULL) {
+ warnx("%s", envptr);
+ fbuf = stdout;
+ } else
+ (void)signal(SIGPIPE, brokthepipe);
+ }
+ }
+ while ((t = getc(collf)) != EOF)
+ (void)putchar(t);
+ if (usepager) {
+ close_pipe:
+ if (fbuf != stdout) {
+ /*
+ * Ignore SIGPIPE so it can't cause a duplicate close.
+ */
+ (void)signal(SIGPIPE, SIG_IGN);
+ (void)Pclose(fbuf);
+ (void)signal(SIGPIPE, SIG_DFL);
+ }
+ }
+ goto cont;
+ case '|':
+ /*
+ * Pipe message through command.
+ * Collect output as new message.
+ */
+ rewind(collf);
+ mespipe(collf, &linebuf[2]);
+ goto cont;
+ case 'v':
+ case 'e':
+ /*
+ * Edit the current message.
+ * 'e' means to use EDITOR
+ * 'v' means to use VISUAL
+ */
+ rewind(collf);
+ mesedit(collf, c);
+ goto cont;
+ }
+ }
+ goto out;
+err:
+ senderr++; /* set return code */
+ if (collf != NULL) {
+ (void)Fclose(collf);
+ collf = NULL;
+ }
+out:
+ if (collf != NULL)
+ rewind(collf);
+ noreset--;
+ (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)sigprocmask(SIG_UNBLOCK, &nset, NULL);
+ return (collf);
+}
+
+/*
+ * Write a file, ex-like if f set.
+ */
+int
+exwrite(name, fp, f)
+ char name[];
+ FILE *fp;
+ int f;
+{
+ FILE *of;
+ int c, lc;
+ long cc;
+#if 0
+ struct stat junk;
+#endif
+
+ if (f) {
+ printf("\"%s\" ", name);
+ (void)fflush(stdout);
+ }
+#if 0
+ if (stat(name, &junk) >= 0 && S_ISREG(junk.st_mode)) {
+ if (!f)
+ fprintf(stderr, "%s: ", name);
+ fprintf(stderr, "File exists\n");
+ return (-1);
+ }
+#endif
+ if ((of = Fopen(name, "a")) == NULL) {
+ warn((char *)NULL);
+ return (-1);
+ }
+ lc = 0;
+ cc = 0;
+ while ((c = getc(fp)) != EOF) {
+ cc++;
+ if (c == '\n')
+ lc++;
+ (void)putc(c, of);
+ if (ferror(of)) {
+ warnx("%s", name);
+ (void)Fclose(of);
+ return (-1);
+ }
+ }
+ (void)Fclose(of);
+ printf("%d/%ld\n", lc, cc);
+ (void)fflush(stdout);
+ return (0);
+}
+
+/*
+ * Edit the message being collected on fp.
+ * On return, make the edit file the new temp file.
+ */
+void
+mesedit(fp, c)
+ FILE *fp;
+ int c;
+{
+ sig_t sigint = signal(SIGINT, SIG_IGN);
+ FILE *nf = run_editor(fp, (off_t)-1, c, 0);
+
+ if (nf != NULL) {
+ (void)fseeko(nf, (off_t)0, SEEK_END);
+ collf = nf;
+ (void)Fclose(fp);
+ }
+ (void)signal(SIGINT, sigint);
+}
+
+static char *
+parse_pipe_args(str, msglist)
+ char str[];
+ char **msglist;
+{
+ char *cp;
+ char quoted;
+
+ *msglist = NULL;
+ if (str==NULL) return NULL;
+ if (*str=='\0') return NULL;
+
+ cp = strlen(str) + str - 1;
+
+ /*
+ * Strip away trailing blanks.
+ */
+
+ while (cp > str && isspace((unsigned char)*cp))
+ cp--;
+ *++cp = '\0';
+
+ /*
+ * Now search for the beginning of the command.
+ */
+ quoted = 0;
+ if (cp > str) { /* check for quotes */
+ cp--;
+ if (*cp=='"' || *cp=='\'' ) {
+ quoted=*cp;
+ cp--;
+ }
+ }
+
+/*
+printf("before loop: str=%s,cp=%s\n", str,cp);
+*/
+
+ while (cp > str && (!isspace((unsigned char)*cp) || quoted)) {
+ if (quoted) {
+ if (*cp==quoted) {
+ cp--;
+ if (cp>str) {
+ if (!(*cp=='\\' || *cp==quoted)) {
+ quoted=0;
+ continue;
+ }
+ } else /* done */
+ break;
+ }
+ }
+ cp--;
+ }
+ if (cp == str) {
+ return (cp); /* no msglist */
+ }
+
+ *msglist = str;
+ if (isspace((unsigned char)*cp))
+ *cp++ = '\0';
+ else {
+ printf("malformed arguments:%s\n",str);
+ }
+ return (cp);
+}
+
+int
+mailpipe(str)
+ char str[];
+{
+ struct message *mp;
+ int *msgvec, *ip;
+ char *msglist = NULL;
+ char * cmd;
+ char * sh;
+ char cmdline[4096];
+ int do_pagefeed;
+ FILE *fbuf;
+
+ fbuf = stdout;
+
+ /* parse arguments: [[msglist] command] */
+ cmd = parse_pipe_args(str, &msglist);
+/*
+ printf (" pipe args: msglist=%s, cmd=%s\n", msglist, cmd);
+*/
+ /* get message list for reading */
+ msgvec = (int *)salloc((msgCount + 2) * sizeof(*msgvec));
+ if (msglist==NULL) {
+ *msgvec = first(0, MMNORM);
+ if (*msgvec == 0) {
+ printf("No messages to %s.\n", cmd);
+ return (1);
+ }
+ msgvec[1] = 0;
+ } else {
+ if (getmsglist(msglist, msgvec, 0) < 0)
+ return (1);
+ }
+ /* if cmd empty get from cmd= variable */
+ if (cmd==NULL) {
+ cmd = value("cmd");
+ if (cmd==NULL || *cmd == '\0') {
+ printf("No command to pipe.\n");
+ return(1);
+ }
+ }
+
+ if ((sh = value("SHELL")) == NULL)
+ sh = _PATH_BSHELL;
+
+ /* complete cmd, open a pipe to shell */
+ cmdline[0] = '\0';
+ strlcpy(cmdline, sh, sizeof(cmdline));
+ strlcat(cmdline, " -c ", sizeof(cmdline));
+ if (*cmd!='"' && *cmd!='\'') {
+ /* I know this doesn't handle all the cases, but
+ it is enough to make the conformance tests pass */
+ strlcat(cmdline, "\"", sizeof(cmdline));
+ strlcat(cmdline, cmd, sizeof(cmdline));
+ strlcat(cmdline, "\"", sizeof(cmdline));
+ } else {
+ strlcat(cmdline, cmd, sizeof(cmdline));
+ }
+
+/*
+ printf(" popen cmdline:%s\n", cmdline);
+*/
+ if (setjmp(pipejmp))
+ goto close_pipe;
+
+ fbuf = Popen(cmdline, "w");
+ if (fbuf == NULL) {
+ warnx("%s", cmdline);
+ return(1);
+ } else
+ (void)signal(SIGPIPE, brokthepipe);
+
+ /* paginate if page= set */
+ if (value("page") == NULL) {
+ do_pagefeed = 0;
+ } else {
+ do_pagefeed = 1;
+ }
+
+ /* write all messages to the pipe */
+ for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
+ mp = &message[*ip - 1];
+ touch(mp);
+ dot = mp;
+/* printf (" sending message %d\n", ip-msgvec); */
+ if (sendmessage(mp, fbuf, 0, NULL) < 0) {
+ warnx("%s", cmdline);
+ (void)Fclose(fbuf);
+ return (1);
+ }
+ if (do_pagefeed)
+ fprintf(fbuf,"\f"); /* form feed */
+ }
+ (void)fflush(fbuf);
+close_pipe:
+ if (fbuf != stdout) {
+ /*
+ * Ignore SIGPIPE so it can't cause a duplicate close.
+ */
+ (void)signal(SIGPIPE, SIG_IGN);
+ (void)Pclose(fbuf);
+ (void)signal(SIGPIPE, SIG_DFL);
+ }
+ return (0);
+}
+
+/*
+ * Pipe the message through the command.
+ * Old message is on stdin of command;
+ * New message collected from stdout.
+ * Sh -c must return 0 to accept the new message.
+ */
+void
+mespipe(fp, cmd)
+ FILE *fp;
+ char cmd[];
+{
+ FILE *nf;
+ int fd;
+ sig_t sigint = signal(SIGINT, SIG_IGN);
+ char *sh, tempname[PATHSIZE];
+
+ (void)snprintf(tempname, sizeof(tempname),
+ "%s/mail.ReXXXXXXXXXX", tmpdir);
+ if ((fd = mkstemp(tempname)) == -1 ||
+ (nf = Fdopen(fd, "w+")) == NULL) {
+ warn("%s", tempname);
+ goto out;
+ }
+ (void)rm(tempname);
+ /*
+ * stdin = current message.
+ * stdout = new message.
+ */
+ if ((sh = value("SHELL")) == NULL)
+ sh = _PATH_BSHELL;
+ if (run_command(sh,
+ 0, fileno(fp), fileno(nf), "-c", cmd, NULL) < 0) {
+ (void)Fclose(nf);
+ goto out;
+ }
+ if (fsize(nf) == 0) {
+ fprintf(stderr, "No bytes from \"%s\" !?\n", cmd);
+ (void)Fclose(nf);
+ goto out;
+ }
+ /*
+ * Take new files.
+ */
+ (void)fseeko(nf, (off_t)0, SEEK_END);
+ collf = nf;
+ (void)Fclose(fp);
+out:
+ (void)signal(SIGINT, sigint);
+}
+
+/*
+ * Interpolate the named messages into the current
+ * message, preceding each line with a tab.
+ * Return a count of the number of characters now in
+ * the message, or -1 if an error is encountered writing
+ * the message temporary. The flag argument is 'm' if we
+ * should shift over and 'f' if not.
+ */
+int
+forward(ms, fp, fn, f)
+ char ms[];
+ FILE *fp;
+ char *fn;
+ int f;
+{
+ int *msgvec;
+ struct ignoretab *ig;
+ char *tabst;
+
+ msgvec = (int *)salloc((msgCount+1) * sizeof(*msgvec));
+ if (msgvec == NULL)
+ return (0);
+ if (getmsglist(ms, msgvec, 0) < 0)
+ return (0);
+ if (*msgvec == 0) {
+ *msgvec = first(0, MMNORM);
+ if (*msgvec == 0) {
+ printf("No appropriate messages\n");
+ return (0);
+ }
+ msgvec[1] = 0;
+ }
+ if (f == 'f' || f == 'F')
+ tabst = NULL;
+ else if ((tabst = value("indentprefix")) == NULL)
+ tabst = "\t";
+ ig = isupper((unsigned char)f) ? NULL : ignore;
+ printf("Interpolating:");
+ for (; *msgvec != 0; msgvec++) {
+ struct message *mp = message + *msgvec - 1;
+
+ touch(mp);
+ printf(" %d", *msgvec);
+ if (sendmessage(mp, fp, ig, tabst) < 0) {
+ warnx("%s", fn);
+ return (-1);
+ }
+ }
+ printf("\n");
+ return (0);
+}
+
+/*
+ * Print (continue) when continued after ^Z.
+ */
+/*ARGSUSED*/
+void
+collstop(s)
+ int s;
+{
+ sig_t old_action = signal(s, SIG_DFL);
+ sigset_t nset;
+
+ (void)sigemptyset(&nset);
+ (void)sigaddset(&nset, s);
+ (void)sigprocmask(SIG_UNBLOCK, &nset, NULL);
+ (void)kill(0, s);
+ (void)sigprocmask(SIG_BLOCK, &nset, NULL);
+ (void)signal(s, old_action);
+ if (colljmp_p) {
+ colljmp_p = 0;
+ hadintr = 0;
+ longjmp(colljmp, 1);
+ }
+}
+
+/*
+ * On interrupt, come here to save the partial message in ~/dead.letter.
+ * Then jump out of the collection loop.
+ */
+/*ARGSUSED*/
+void
+collint(s)
+ int s;
+{
+ /*
+ * the control flow is subtle, because we can be called from ~q.
+ */
+ if (!hadintr) {
+ if (value("ignore") != NULL) {
+ printf("@");
+ (void)fflush(stdout);
+ clearerr(stdin);
+ return;
+ }
+ hadintr = 1;
+ longjmp(colljmp, 1);
+ }
+ rewind(collf);
+ if (value("save") != NULL)
+ savedeadletter(collf);
+ longjmp(collabort, 1);
+}
+
+/*ARGSUSED*/
+void
+collhup(s)
+ int s;
+{
+ rewind(collf);
+ savedeadletter(collf);
+ /*
+ * Let's pretend nobody else wants to clean up,
+ * a true statement at this time.
+ */
+ exit(1);
+}
+
+void
+savedeadletter(fp)
+ FILE *fp;
+{
+ FILE *dbuf;
+ int c;
+ char *cp;
+
+ if (fsize(fp) == 0)
+ return;
+ cp = getdeadletter();
+ c = umask(077);
+ dbuf = Fopen(cp, "w");
+ (void)umask(c);
+ if (dbuf == NULL)
+ return;
+ while ((c = getc(fp)) != EOF)
+ (void)putc(c, dbuf);
+ (void)Fclose(dbuf);
+ rewind(fp);
+}
diff --git a/mail_cmds/mail/def.h b/mail_cmds/mail/def.h
new file mode 100644
index 0000000..3817a5f
--- /dev/null
+++ b/mail_cmds/mail/def.h
@@ -0,0 +1,283 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)def.h 8.4 (Berkeley) 4/20/95
+ *
+ * $FreeBSD: src/usr.bin/mail/def.h,v 1.8 2001/12/18 20:52:09 mikeh Exp $
+ */
+
+/*
+ * Mail -- a mail program
+ *
+ * Author: Kurt Shoens (UCB) March 25, 1978
+ */
+
+#ifndef DEF_H
+#define DEF_H
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <paths.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "pathnames.h"
+
+#define APPEND /* New mail goes to end of mailbox */
+
+#define ESCAPE '~' /* Default escape for sending */
+#define NMLSIZE 1024 /* max names in a message list */
+#define PATHSIZE MAXPATHLEN /* Size of pathnames throughout */
+#define HSHSIZE 59 /* Hash size for aliases and vars */
+#define LINESIZE BUFSIZ /* max readable line width */
+#define STRINGSIZE ((unsigned)128) /* Dynamic allocation units */
+#define MAXARGC 1024 /* Maximum list of raw strings */
+#define MAXEXP 25 /* Maximum expansion of aliases */
+
+#define equal(a, b) (strcmp(a,b)==0)/* A nice function to string compare */
+
+struct message {
+ short m_flag; /* flags, see below */
+ short m_offset; /* offset in block of message */
+ long m_block; /* block number of this message */
+ long m_size; /* Bytes in the message */
+ long m_lines; /* Lines in the message */
+};
+
+/*
+ * flag bits.
+ */
+
+#define MUSED (1<<0) /* entry is used, but this bit isn't */
+#define MDELETED (1<<1) /* entry has been deleted */
+#define MSAVED (1<<2) /* entry has been saved */
+#define MTOUCH (1<<3) /* entry has been noticed */
+#define MPRESERVE (1<<4) /* keep entry in sys mailbox */
+#define MMARK (1<<5) /* message is marked! */
+#define MODIFY (1<<6) /* message has been modified */
+#define MNEW (1<<7) /* message has never been seen */
+#define MREAD (1<<8) /* message has been read sometime. */
+#define MSTATUS (1<<9) /* message status has changed */
+#define MBOX (1<<10) /* Send this to mbox, regardless */
+
+/*
+ * Given a file address, determine the block number it represents.
+ */
+#define blockof(off) ((int)((off) / 4096))
+#define boffsetof(off) ((int)((off) % 4096))
+#define positionof(block, offset) ((off_t)(block) * 4096 + (offset))
+
+/*
+ * Format of the command description table.
+ * The actual table is declared and initialized
+ * in lex.c
+ */
+struct cmd {
+ const char *c_name; /* Name of command */
+ int (*c_func)(); /* Implementor of the command */
+ short c_argtype; /* Type of arglist (see below) */
+ short c_msgflag; /* Required flags of messages */
+ short c_msgmask; /* Relevant flags of messages */
+};
+
+/* Yechh, can't initialize unions */
+
+#define c_minargs c_msgflag /* Minimum argcount for RAWLIST */
+#define c_maxargs c_msgmask /* Max argcount for RAWLIST */
+
+/*
+ * Argument types.
+ */
+
+#define MSGLIST 0 /* Message list type */
+#define STRLIST 1 /* A pure string */
+#define RAWLIST 2 /* Shell string list */
+#define NOLIST 3 /* Just plain 0 */
+#define NDMLIST 4 /* Message list, no defaults */
+
+#define P 040 /* Autoprint dot after command */
+#define I 0100 /* Interactive command bit */
+#define M 0200 /* Legal from send mode bit */
+#define W 0400 /* Illegal when read only bit */
+#define F 01000 /* Is a conditional command */
+#define T 02000 /* Is a transparent command */
+#define R 04000 /* Cannot be called from collect */
+
+/*
+ * Oft-used mask values
+ */
+
+#define MMNORM (MDELETED|MSAVED)/* Look at both save and delete bits */
+#define MMNDEL MDELETED /* Look only at deleted bit */
+
+/*
+ * Structure used to return a break down of a head
+ * line (hats off to Bill Joy!)
+ */
+
+struct headline {
+ char *l_from; /* The name of the sender */
+ char *l_tty; /* His tty string (if any) */
+ char *l_date; /* The entire date string */
+};
+
+#define GTO 1 /* Grab To: line */
+#define GSUBJECT 2 /* Likewise, Subject: line */
+#define GCC 4 /* And the Cc: line */
+#define GBCC 8 /* And also the Bcc: line */
+#define GREPLYTO 0x10 /* And the Reply-To: line */
+#define GINREPLYTO 0x20 /* The In-Reply-To: line */
+#define GMASK (GTO|GSUBJECT|GCC|GBCC|GREPLYTO|GINREPLYTO)
+ /* Mask of places from whence */
+
+#define GNL 0x40 /* Print blank line after */
+#define GDEL 0x80 /* Entity removed from list */
+#define GCOMMA 0x100 /* detract puts in commas */
+
+/*
+ * Structure used to pass about the current
+ * state of the user-typed message header.
+ */
+
+struct header {
+ struct name *h_bcc; /* Blind carbon copies */
+ struct name *h_cc; /* Carbon copies string */
+ struct name *h_smopts; /* Sendmail options */
+ struct name *h_to; /* Dynamic "To:" string */
+ char *h_inreplyto; /* Reference */
+ char *h_replyto; /* Reply address */
+ char *h_subject; /* Subject string */
+};
+
+/*
+ * Structure of namelist nodes used in processing
+ * the recipients of mail and aliases and all that
+ * kind of stuff.
+ */
+
+struct name {
+ struct name *n_flink; /* Forward link in list. */
+ struct name *n_blink; /* Backward list link */
+ short n_type; /* From which list it came */
+ char *n_name; /* This fella's name */
+};
+
+/*
+ * Structure of a variable node. All variables are
+ * kept on a singly-linked list of these, rooted by
+ * "variables"
+ */
+
+struct var {
+ struct var *v_link; /* Forward link to next variable */
+ char *v_name; /* The variable's name */
+ char *v_value; /* And it's current value */
+};
+
+struct group {
+ struct group *ge_link; /* Next person in this group */
+ char *ge_name; /* This person's user name */
+};
+
+struct grouphead {
+ struct grouphead *g_link; /* Next grouphead in list */
+ char *g_name; /* Name of this group */
+ struct group *g_list; /* Users in group. */
+};
+
+/*
+ * Structure of the hash table of ignored header fields
+ */
+struct ignoretab {
+ int i_count; /* Number of entries */
+ struct ignore {
+ struct ignore *i_link; /* Next ignored field in bucket */
+ char *i_field; /* This ignored field */
+ } *i_head[HSHSIZE];
+};
+
+/*
+ * Token values returned by the scanner used for argument lists.
+ * Also, sizes of scanner-related things.
+ */
+
+#define TEOL 0 /* End of the command line */
+#define TNUMBER 1 /* A message number */
+#define TDASH 2 /* A simple dash */
+#define TSTRING 3 /* A string (possibly containing -) */
+#define TDOT 4 /* A "." */
+#define TUP 5 /* An "^" */
+#define TDOLLAR 6 /* A "$" */
+#define TSTAR 7 /* A "*" */
+#define TOPEN 8 /* An '(' */
+#define TCLOSE 9 /* A ')' */
+#define TPLUS 10 /* A '+' */
+#define TERROR 11 /* A lexical error */
+
+#define REGDEP 2 /* Maximum regret depth. */
+#define STRINGLEN 1024 /* Maximum length of string token */
+
+/*
+ * Constants for conditional commands. These describe whether
+ * we should be executing stuff or not.
+ */
+
+#define CANY 0 /* Execute in send or receive mode */
+#define CRCV 1 /* Execute in receive mode only */
+#define CSEND 2 /* Execute in send mode only */
+
+/*
+ * Kludges to handle the change from setexit / reset to setjmp / longjmp
+ */
+
+#define setexit() setjmp(srbuf)
+#define reset(x) longjmp(srbuf, x)
+
+/*
+ * Truncate a file to the last character written. This is
+ * useful just before closing an old file that was opened
+ * for read/write.
+ */
+#define trunc(stream) { \
+ (void)fflush(stream); \
+ (void)ftruncate(fileno(stream), (off_t)ftell(stream)); \
+}
+
+#endif /* DEF_H */
diff --git a/mail_cmds/mail/edit.c b/mail_cmds/mail/edit.c
new file mode 100644
index 0000000..d49267a
--- /dev/null
+++ b/mail_cmds/mail/edit.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)edit.c 8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/edit.c,v 1.9 2002/06/30 05:25:06 obrien Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+#include "rcv.h"
+#include <fcntl.h>
+#include "extern.h"
+
+/*
+ * Mail -- a mail program
+ *
+ * Perform message editing functions.
+ */
+
+/*
+ * Edit a message list.
+ */
+int
+editor(msgvec)
+ int *msgvec;
+{
+
+ return (edit1(msgvec, 'e'));
+}
+
+/*
+ * Invoke the visual editor on a message list.
+ */
+int
+visual(msgvec)
+ int *msgvec;
+{
+
+ return (edit1(msgvec, 'v'));
+}
+
+/*
+ * Edit a message by writing the message into a funnily-named file
+ * (which should not exist) and forking an editor on it.
+ * We get the editor from the stuff above.
+ */
+int
+edit1(msgvec, type)
+ int *msgvec;
+ int type;
+{
+ int c, i;
+ FILE *fp;
+ struct message *mp;
+ off_t size;
+
+ /*
+ * Deal with each message to be edited . . .
+ */
+ for (i = 0; msgvec[i] && i < msgCount; i++) {
+ sig_t sigint;
+
+ if (i > 0) {
+ char buf[100];
+ char *p;
+
+ printf("Edit message %d [ynq]? ", msgvec[i]);
+ if (fgets(buf, sizeof(buf), stdin) == 0)
+ break;
+ for (p = buf; *p == ' ' || *p == '\t'; p++)
+ ;
+ if (*p == 'q')
+ break;
+ if (*p == 'n')
+ continue;
+ }
+ dot = mp = &message[msgvec[i] - 1];
+ touch(mp);
+ sigint = signal(SIGINT, SIG_IGN);
+ fp = run_editor(setinput(mp), mp->m_size, type, readonly);
+ if (fp != NULL) {
+ (void)fseeko(otf, (off_t)0, SEEK_END);
+ size = ftello(otf);
+ mp->m_block = blockof(size);
+ mp->m_offset = boffsetof(size);
+ mp->m_size = (long)fsize(fp);
+ mp->m_lines = 0;
+ mp->m_flag |= MODIFY;
+ rewind(fp);
+ while ((c = getc(fp)) != EOF) {
+ if (c == '\n')
+ mp->m_lines++;
+ if (putc(c, otf) == EOF)
+ break;
+ }
+ if (ferror(otf))
+ warnx("/tmp");
+ (void)Fclose(fp);
+ }
+ (void)signal(SIGINT, sigint);
+ }
+ return (0);
+}
+
+/*
+ * Run an editor on the file at "fpp" of "size" bytes,
+ * and return a new file pointer.
+ * Signals must be handled by the caller.
+ * "Type" is 'e' for _PATH_EX, 'v' for _PATH_VI.
+ */
+FILE *
+run_editor(fp, size, type, readonly)
+ FILE *fp;
+ off_t size;
+ int type, readonly;
+{
+ FILE *nf = NULL;
+ int t;
+ time_t modtime;
+ char *edit, tempname[PATHSIZE];
+ struct stat statb;
+
+ (void)snprintf(tempname, sizeof(tempname),
+ "%s/mail.ReXXXXXXXXXX", tmpdir);
+ if ((t = mkstemp(tempname)) == -1 ||
+ (nf = Fdopen(t, "w")) == NULL) {
+ warn("%s", tempname);
+ goto out;
+ }
+ if (readonly && fchmod(t, 0400) == -1) {
+ warn("%s", tempname);
+ (void)rm(tempname);
+ goto out;
+ }
+ if (size >= 0)
+ while (--size >= 0 && (t = getc(fp)) != EOF)
+ (void)putc(t, nf);
+ else
+ while ((t = getc(fp)) != EOF)
+ (void)putc(t, nf);
+ (void)fflush(nf);
+ if (fstat(fileno(nf), &statb) < 0)
+ modtime = 0;
+ else
+ modtime = statb.st_mtime;
+ if (ferror(nf)) {
+ (void)Fclose(nf);
+ warnx("%s", tempname);
+ (void)rm(tempname);
+ nf = NULL;
+ goto out;
+ }
+ if (Fclose(nf) < 0) {
+ warn("%s", tempname);
+ (void)rm(tempname);
+ nf = NULL;
+ goto out;
+ }
+ nf = NULL;
+ if ((edit = value(type == 'e' ? "EDITOR" : "VISUAL")) == NULL)
+ edit = type == 'e' ? _PATH_EX : _PATH_VI;
+ else {
+ if (*edit=='\0')
+ edit = type == 'e' ? _PATH_EX : _PATH_VI;
+ }
+ if (run_command(edit, 0, -1, -1, tempname, NULL, NULL) < 0) {
+ (void)rm(tempname);
+ goto out;
+ }
+ /*
+ * If in read only mode or file unchanged, just remove the editor
+ * temporary and return.
+ */
+ if (readonly) {
+ (void)rm(tempname);
+ goto out;
+ }
+ if (stat(tempname, &statb) < 0) {
+ warn("%s", tempname);
+ goto out;
+ }
+ if (modtime == statb.st_mtime) {
+ (void)rm(tempname);
+ goto out;
+ }
+ /*
+ * Now switch to new file.
+ */
+ if ((nf = Fopen(tempname, "a+")) == NULL) {
+ warn("%s", tempname);
+ (void)rm(tempname);
+ goto out;
+ }
+ (void)rm(tempname);
+out:
+ return (nf);
+}
diff --git a/mail_cmds/mail/extern.h b/mail_cmds/mail/extern.h
new file mode 100644
index 0000000..239a8cd
--- /dev/null
+++ b/mail_cmds/mail/extern.h
@@ -0,0 +1,268 @@
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)extern.h 8.2 (Berkeley) 4/20/95
+ *
+ * $FreeBSD: src/usr.bin/mail/extern.h,v 1.9 2004/02/29 20:44:44 mikeh Exp $
+ */
+
+#ifndef EXTERN_H
+#define EXTERN_H
+
+struct name *cat(struct name *, struct name *);
+struct name *delname(struct name *, char []);
+struct name *elide(struct name *);
+struct name *extract(char [], int);
+struct name *gexpand(struct name *, struct grouphead *, int, int);
+struct name *nalloc(char [], int);
+struct name *outof(struct name *, FILE *, struct header *);
+struct name *put(struct name *, struct name *);
+struct name *tailof(struct name *);
+struct name *usermap(struct name *);
+FILE *Fdopen(int, const char *);
+FILE *Fopen(const char *, const char *);
+FILE *Popen(char *, const char *);
+FILE *collect(struct header *, int);
+char *copyin(char *, char **);
+char *detract(struct name *, int);
+char *expand(char *);
+char *getauthor(char *);
+char *getdeadletter(void);
+char *getname(int);
+char *hfield(const char *, struct message *);
+FILE *infix(struct header *, FILE *);
+char *ishfield(char [], char *, const char *);
+char *name1(struct message *, int);
+char *nameof(struct message *, int);
+char *nextword(char *, char *);
+char *readtty(const char *, char []);
+char *reedit(char *);
+FILE *run_editor(FILE *, off_t, int, int);
+char *salloc(int);
+char *savestr(char *);
+FILE *setinput(struct message *);
+char *skin(char *);
+char *skip_comment(char *);
+char *snarf(char [], int *, int);
+char *username(void);
+char *value(const char *);
+char *vcopy(const char *);
+char *yankword(char *, char []);
+char *yanklogin(char *, char []);
+int Fclose(FILE *);
+int More(int *);
+int Pclose(FILE *);
+int Respond(int *);
+int Type(int *);
+int doRespond(int []);
+int dorespond(int *);
+void alter(char *);
+int alternates(char **);
+void announce(void);
+int append(struct message *, FILE *);
+int argcount(char **);
+void assign(const char *, const char *);
+int bangexp(char *, size_t);
+void brokpipe(int);
+int charcount(char *, int);
+int check(int, int);
+void clob1(int);
+int clobber(char **);
+void close_all_files(void);
+int cmatch(char *, char *);
+void collhup(int);
+void collint(int);
+void collstop(int);
+void commands(void);
+int copycmd(char []);
+int Capcopycmd(char []);
+int core(void);
+int count(struct name *);
+int delete(int []);
+int delm(int []);
+int deltype(int []);
+void demail(void);
+int diction(const void *, const void *);
+int dosh(char *);
+int echo(char **);
+int edit1(int *, int);
+int editor(int *);
+void edstop(void);
+int elsecmd(void);
+int endifcmd(void);
+int evalcol(int);
+int execute(char [], int);
+int exwrite(char [], FILE *, int);
+void fail(const char *, const char *);
+int file(char **);
+struct grouphead *
+ findgroup(char []);
+void findmail(char *, char *, int);
+int first(int, int);
+void fixhead(struct header *, struct name *);
+void fmt(const char *, struct name *, FILE *, int);
+int folders(void);
+int followup(int *);
+int Capfollowup(int *);
+int forward(char [], FILE *, char *, int);
+void free_child(int);
+int from(int *);
+off_t fsize(FILE *);
+int getfold(char *, int);
+int gethfield(FILE *, char [], int, char **);
+int getmsglist(char *, int *, int);
+int getrawlist(char [], char **, int);
+int getuserid(char []);
+int grabh(struct header *, int);
+int group(char **);
+void hangup(int);
+int hash(const char *);
+void hdrstop(int);
+int headers(int *);
+int help(void);
+void holdsigs(void);
+int ifcmd(char **);
+int igcomp(const void *, const void *);
+int igfield(char *[]);
+int ignore1(char *[], struct ignoretab *, const char *);
+int igshow(struct ignoretab *, const char *);
+int inc(void *);
+int incfile(void);
+void intr(int);
+int isdate(char []);
+int isdir(char []);
+int isfileaddr(char *);
+int ishead(char []);
+int isign(const char *, struct ignoretab []);
+int isprefix(const char *, const char *);
+void istrncpy(char *, const char *, size_t);
+__const struct cmd *
+ lex(char []);
+void load(char *);
+struct var *
+ lookup(const char *);
+int mail(struct name *,
+ struct name *, struct name *, struct name *, char *, char *);
+void mail1(struct header *, int);
+int mailpipe(char []);
+void makemessage(FILE *, int);
+void mark(int);
+int markall(char [], int);
+int matchsender(char *, int);
+int matchfield(char *, int);
+int mboxit(int []);
+int member(char *, struct ignoretab *);
+void mesedit(FILE *, int);
+void mespipe(FILE *, char []);
+int messize(int *);
+int metamess(int, int);
+int more(int *);
+int newfileinfo(int);
+int next(int *);
+int null(int);
+void parse(char [], struct headline *, char []);
+int pcmdlist(void);
+int pdot(void);
+void prepare_child(sigset_t *, int, int);
+int preserve(int *);
+void prettyprint(struct name *);
+void printgroup(char []);
+void printhead(int);
+int puthead(struct header *, FILE *, int);
+int putline(FILE *, char *, int);
+int pversion(int);
+void quit(void);
+int quitcmd(void);
+int readline(FILE *, char *, int);
+void register_file(FILE *, int, int);
+void regret(int);
+void relsesigs(void);
+int respond(int *);
+int retfield(char *[]);
+int rexit(int);
+int rm(char *);
+int run_command(char *, sigset_t *, int, int, char *, char *, char *);
+int save(char []);
+int Capsave(char []);
+int save1(char [], int, const char *, struct ignoretab *);
+void savedeadletter(FILE *);
+int saveigfield(char *[]);
+int savemail(char [], FILE *);
+int saveretfield(char *[]);
+int scan(char **);
+void scaninit(void);
+int schdir(char **);
+int screensize(void);
+int scroll(char []);
+int sendmessage(struct message *, FILE *, struct ignoretab *, char *);
+int sendmail(char *);
+int set(char **);
+int setfile(char *);
+void setmsize(int);
+void setptr(FILE *, off_t);
+void setscreensize(void);
+int shell(char *);
+void sigchild(int);
+void sort(char **);
+int source(char **);
+void spreserve(void);
+void sreset(void);
+int start_command(char *, sigset_t *, int, int, char *, char *, char *);
+void statusput(struct message *, FILE *, char *);
+void stop(int);
+int stouch(int []);
+int swrite(char []);
+void tinit(void);
+int top(int *);
+void touch(struct message *);
+void ttyint(int);
+void ttystop(int);
+int type(int *);
+int type1(int *, int, int);
+int undelete_messages(int *);
+void unmark(int);
+char **unpack(struct name *);
+int unread(int []);
+void unregister_file(FILE *);
+int unset(char **);
+int unstack(void);
+void v_free(char *);
+int visual(int *);
+int wait_child(int);
+int wait_command(int);
+int writeback(FILE *);
+
+extern char *__progname;
+extern char *tmpdir;
+
+#endif /* EXTERN_H */
+
diff --git a/mail_cmds/mail/fio.c b/mail_cmds/mail/fio.c
new file mode 100644
index 0000000..6f59372
--- /dev/null
+++ b/mail_cmds/mail/fio.c
@@ -0,0 +1,475 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)fio.c 8.2 (Berkeley) 4/20/95";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/fio.c,v 1.12 2002/06/30 05:25:06 obrien Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+#include "rcv.h"
+#include <sys/file.h>
+#include <sys/wait.h>
+
+#include <unistd.h>
+#include <paths.h>
+#include <errno.h>
+#include "extern.h"
+
+/*
+ * Mail -- a mail program
+ *
+ * File I/O.
+ */
+
+extern int wait_status;
+
+/*
+ * Set up the input pointers while copying the mail file into /tmp.
+ */
+void
+setptr(ibuf, offset)
+ FILE *ibuf;
+ off_t offset;
+{
+ int c, count;
+ char *cp, *cp2;
+ struct message this;
+ FILE *mestmp;
+ int maybe, inhead;
+ char linebuf[LINESIZE], pathbuf[PATHSIZE];
+ int omsgCount;
+
+ /* Get temporary file. */
+ (void)snprintf(pathbuf, sizeof(pathbuf), "%s/mail.XXXXXXXXXX", tmpdir);
+ if ((c = mkstemp(pathbuf)) == -1 || (mestmp = Fdopen(c, "r+")) == NULL)
+ err(1, "can't open %s", pathbuf);
+ (void)rm(pathbuf);
+
+ if (offset == 0) {
+ msgCount = 0;
+ } else {
+ /* Seek into the file to get to the new messages */
+ (void)fseeko(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)fseeko(otf, (off_t)0, SEEK_END);
+ offset = ftello(otf);
+ }
+ omsgCount = msgCount;
+ maybe = 1;
+ inhead = 0;
+ this.m_flag = MUSED|MNEW;
+ this.m_size = 0;
+ this.m_lines = 0;
+ this.m_block = 0;
+ this.m_offset = 0;
+ for (;;) {
+ if (fgets(linebuf, sizeof(linebuf), ibuf) == NULL) {
+ if (append(&this, mestmp))
+ errx(1, "temporary file");
+ makemessage(mestmp, omsgCount);
+ return;
+ }
+ count = strlen(linebuf);
+ /*
+ * Transforms lines ending in <CR><LF> to just <LF>.
+ * This allows mail to be able to read Eudora mailboxes.
+ */
+ if (count >= 2 && linebuf[count - 1] == '\n' &&
+ linebuf[count - 2] == '\r') {
+ count--;
+ linebuf[count - 1] = '\n';
+ }
+
+ (void)fwrite(linebuf, sizeof(*linebuf), count, otf);
+ if (ferror(otf))
+ errx(1, "/tmp");
+ if (count)
+ linebuf[count - 1] = '\0';
+ if (maybe && linebuf[0] == 'F' && ishead(linebuf)) {
+ msgCount++;
+ if (append(&this, mestmp))
+ errx(1, "temporary file");
+ this.m_flag = MUSED|MNEW;
+ this.m_size = 0;
+ this.m_lines = 0;
+ this.m_block = blockof(offset);
+ this.m_offset = boffsetof(offset);
+ inhead = 1;
+ } else if (linebuf[0] == 0) {
+ inhead = 0;
+ } else if (inhead) {
+ for (cp = linebuf, cp2 = "status";; cp++) {
+ if ((c = *cp2++) == '\0') {
+ while (isspace((unsigned char)*cp++))
+ ;
+ if (cp[-1] != ':')
+ break;
+ while ((c = *cp++) != '\0')
+ if (c == 'R')
+ this.m_flag |= MREAD;
+ else if (c == 'O')
+ this.m_flag &= ~MNEW;
+ inhead = 0;
+ break;
+ }
+ if (*cp != c && *cp != toupper((unsigned char)c))
+ break;
+ }
+ }
+ offset += count;
+ this.m_size += count;
+ this.m_lines++;
+ maybe = linebuf[0] == 0;
+ }
+}
+
+/*
+ * 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 if requested.
+ */
+int
+putline(obuf, linebuf, outlf)
+ FILE *obuf;
+ char *linebuf;
+ int outlf;
+{
+ int c;
+
+ c = strlen(linebuf);
+ (void)fwrite(linebuf, sizeof(*linebuf), c, obuf);
+ if (outlf) {
+ fprintf(obuf, "\n");
+ c++;
+ }
+ if (ferror(obuf))
+ return (-1);
+ return (c);
+}
+
+/*
+ * Read up a line from the specified input into the line
+ * buffer. Return the number of characters read. Do not
+ * include the newline (or carriage return) at the end.
+ */
+int
+readline(ibuf, linebuf, linesize)
+ FILE *ibuf;
+ char *linebuf;
+ int linesize;
+{
+ int n;
+
+ clearerr(ibuf);
+ if (fgets(linebuf, linesize, ibuf) == NULL)
+ return (-1);
+ n = strlen(linebuf);
+ if (n > 0 && linebuf[n - 1] == '\n')
+ linebuf[--n] = '\0';
+ if (n > 0 && linebuf[n - 1] == '\r')
+ linebuf[--n] = '\0';
+ return (n);
+}
+
+/*
+ * Return a file buffer all ready to read up the
+ * passed message pointer.
+ */
+FILE *
+setinput(mp)
+ struct message *mp;
+{
+
+ (void)fflush(otf);
+ if (fseeko(itf,
+ positionof(mp->m_block, mp->m_offset), SEEK_SET) < 0)
+ err(1, "fseeko");
+ return (itf);
+}
+
+/*
+ * Take the data out of the passed ghost file and toss it into
+ * a dynamically allocated message structure.
+ */
+void
+makemessage(f, omsgCount)
+ FILE *f;
+ int omsgCount;
+{
+ size_t size;
+ struct message *nmessage;
+
+ 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[omsgCount], size) != size)
+ errx(1, "Message temporary file corrupted");
+ message[msgCount].m_size = 0;
+ message[msgCount].m_lines = 0;
+ (void)Fclose(f);
+}
+
+/*
+ * Append the passed message descriptor onto the temp file.
+ * If the write fails, return 1, else 0
+ */
+int
+append(mp, f)
+ struct message *mp;
+ FILE *f;
+{
+ return (fwrite((char *)mp, sizeof(*mp), 1, f) != 1);
+}
+
+/*
+ * Delete a file, but only if the file is a plain file.
+ */
+int
+rm(name)
+ char *name;
+{
+ struct stat sb;
+
+ if (stat(name, &sb) < 0)
+ return (-1);
+ if (!S_ISREG(sb.st_mode)) {
+ errno = EISDIR;
+ return (-1);
+ }
+ return (unlink(name));
+}
+
+static int sigdepth; /* depth of holdsigs() */
+static sigset_t nset, oset;
+/*
+ * Hold signals SIGHUP, SIGINT, and SIGQUIT.
+ */
+void
+holdsigs()
+{
+
+ if (sigdepth++ == 0) {
+ (void)sigemptyset(&nset);
+ (void)sigaddset(&nset, SIGHUP);
+ (void)sigaddset(&nset, SIGINT);
+ (void)sigaddset(&nset, SIGQUIT);
+ (void)sigprocmask(SIG_BLOCK, &nset, &oset);
+ }
+}
+
+/*
+ * Release signals SIGHUP, SIGINT, and SIGQUIT.
+ */
+void
+relsesigs()
+{
+
+ if (--sigdepth == 0)
+ (void)sigprocmask(SIG_SETMASK, &oset, NULL);
+}
+
+/*
+ * Determine the size of the file possessed by
+ * the passed buffer.
+ */
+off_t
+fsize(iob)
+ FILE *iob;
+{
+ struct stat sbuf;
+
+ if (fstat(fileno(iob), &sbuf) < 0)
+ return (0);
+ return (sbuf.st_size);
+}
+
+/*
+ * Evaluate the string given as a new mailbox name.
+ * Supported meta characters:
+ * % for my system mail box
+ * %user for user's system mail box
+ * # for previous file
+ * & invoker's mbox file
+ * +file file in folder directory
+ * any shell meta character
+ * Return the file name as a dynamic string.
+ */
+char *
+expand(name)
+ char *name;
+{
+ char xname[PATHSIZE];
+ char cmdbuf[PATHSIZE]; /* also used for file names */
+ int pid, l;
+ char *cp, *sh;
+ int pivec[2];
+ struct stat sbuf;
+
+ /*
+ * The order of evaluation is "%" and "#" expand into constants.
+ * "&" can expand into "+". "+" can expand into shell meta characters.
+ * Shell meta characters expand into constants.
+ * This way, we make no recursive expansion.
+ */
+ switch (*name) {
+ case '%':
+ findmail(name[1] ? name + 1 : myname, xname, sizeof(xname));
+ return (savestr(xname));
+ case '#':
+ if (name[1] != 0)
+ break;
+ if (prevfile[0] == 0) {
+ printf("No previous file\n");
+ return (NULL);
+ }
+ return (savestr(prevfile));
+ case '&':
+ if (name[1] == 0 && (name = value("MBOX")) == NULL)
+ name = "~/mbox";
+ /* fall through */
+ }
+ if (name[0] == '+' && getfold(cmdbuf, sizeof(cmdbuf)) >= 0) {
+ (void)snprintf(xname, sizeof(xname), "%s/%s", cmdbuf, name + 1);
+ name = savestr(xname);
+ }
+ /* catch the most common shell meta character */
+ if (name[0] == '~' && homedir != NULL &&
+ (name[1] == '/' || name[1] == '\0')) {
+ (void)snprintf(xname, sizeof(xname), "%s%s", homedir, name + 1);
+ name = savestr(xname);
+ }
+ if (!strpbrk(name, "~{[*?$`'\"\\"))
+ return (name);
+ if (pipe(pivec) < 0) {
+ warn("pipe");
+ return (name);
+ }
+ (void)snprintf(cmdbuf, sizeof(cmdbuf), "echo %s", name);
+ if ((sh = value("SHELL")) == NULL)
+ sh = _PATH_BSHELL;
+ pid = start_command(sh, 0, -1, pivec[1], "-c", cmdbuf, NULL);
+ if (pid < 0) {
+ (void)close(pivec[0]);
+ (void)close(pivec[1]);
+ return (NULL);
+ }
+ (void)close(pivec[1]);
+ l = read(pivec[0], xname, BUFSIZ);
+ (void)close(pivec[0]);
+ if (wait_child(pid) < 0 && WIFSIGNALED(wait_status) &&
+ WTERMSIG(wait_status) != SIGPIPE) {
+ fprintf(stderr, "\"%s\": Expansion failed.\n", name);
+ return (NULL);
+ }
+ if (l < 0) {
+ warn("read");
+ return (NULL);
+ }
+ if (l == 0) {
+ fprintf(stderr, "\"%s\": No match.\n", name);
+ return (NULL);
+ }
+ if (l == BUFSIZ) {
+ fprintf(stderr, "\"%s\": Expansion buffer overflow.\n", name);
+ return (NULL);
+ }
+ xname[l] = '\0';
+ for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
+ ;
+ cp[1] = '\0';
+ if (strchr(xname, ' ') && stat(xname, &sbuf) < 0) {
+ fprintf(stderr, "\"%s\": Ambiguous.\n", name);
+ return (NULL);
+ }
+ return (savestr(xname));
+}
+
+/*
+ * Determine the current folder directory name.
+ */
+int
+getfold(name, namelen)
+ char *name;
+ int namelen;
+{
+ char *folder;
+ int copylen;
+
+ if ((folder = value("folder")) == NULL)
+ return (-1);
+ if (*folder == '/')
+ copylen = strlcpy(name, folder, namelen);
+ else
+ copylen = snprintf(name, namelen, "%s/%s",
+ homedir ? homedir : ".", folder);
+ return (copylen < 0 || copylen >= namelen ? (-1) : (0));
+}
+
+/*
+ * Return the name of the dead.letter file.
+ */
+char *
+getdeadletter()
+{
+ char *cp;
+
+ if ((cp = value("DEAD")) == NULL || (cp = expand(cp)) == NULL)
+ cp = expand("~/dead.letter");
+ else if (*cp != '/') {
+ char buf[PATHSIZE];
+
+ (void)snprintf(buf, sizeof(buf), "~/%s", cp);
+ cp = expand(buf);
+ }
+ return (cp);
+}
diff --git a/mail_cmds/mail/getname.c b/mail_cmds/mail/getname.c
new file mode 100644
index 0000000..f8e2231
--- /dev/null
+++ b/mail_cmds/mail/getname.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)getname.c 8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/getname.c,v 1.4 2002/06/30 05:25:06 obrien Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+#include "rcv.h"
+#include <pwd.h>
+#include "extern.h"
+
+/* Getname / getuserid for those with hashed passwd data base). */
+
+/*
+ * Search the passwd file for a uid. Return name on success, NULL on failure.
+ */
+char *
+getname(uid)
+ int uid;
+{
+ struct passwd *pw;
+
+ if ((pw = getpwuid(uid)) == NULL)
+ return (NULL);
+ return (pw->pw_name);
+}
+
+/*
+ * Convert the passed name to a user id and return it. Return -1
+ * on error.
+ */
+int
+getuserid(name)
+ char name[];
+{
+ struct passwd *pw;
+
+ if ((pw = getpwnam(name)) == NULL)
+ return (-1);
+ return (pw->pw_uid);
+}
diff --git a/mail_cmds/mail/glob.h b/mail_cmds/mail/glob.h
new file mode 100644
index 0000000..dfbc55f
--- /dev/null
+++ b/mail_cmds/mail/glob.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)glob.h 8.1 (Berkeley) 6/6/93
+ *
+ * $FreeBSD: src/usr.bin/mail/glob.h,v 1.2 2001/03/25 04:57:04 mikeh Exp $
+ */
+
+#ifndef GLOB_H
+#define GLOB_H
+
+#ifndef EXTERN
+#define EXTERN extern
+#endif
+
+/*
+ * A bunch of global variable declarations lie herein.
+ * def.h must be included first.
+ */
+
+EXTERN int msgCount; /* Count of messages read in */
+EXTERN int rcvmode; /* True if receiving mail */
+EXTERN int sawcom; /* Set after first command */
+EXTERN char *Tflag; /* -T temp file for netnews */
+EXTERN int senderr; /* An error while checking */
+EXTERN int edit; /* Indicates editing a file */
+EXTERN int readonly; /* Will be unable to rewrite file */
+EXTERN int noreset; /* String resets suspended */
+EXTERN int sourcing; /* Currently reading variant file */
+EXTERN int loading; /* Loading user definitions */
+EXTERN int cond; /* Current state of conditional exc. */
+EXTERN FILE *itf; /* Input temp file buffer */
+EXTERN FILE *otf; /* Output temp file buffer */
+EXTERN int image; /* File descriptor for image of msg */
+EXTERN FILE *input; /* Current command input file */
+EXTERN char mailname[PATHSIZE]; /* Name of current file */
+EXTERN char prevfile[PATHSIZE]; /* Name of previous file */
+EXTERN char *homedir; /* Path name of home directory */
+EXTERN char *myname; /* My login name */
+EXTERN off_t mailsize; /* Size of system mailbox */
+EXTERN int lexnumber; /* Number of TNUMBER from scan() */
+EXTERN char lexstring[STRINGLEN]; /* String from TSTRING, scan() */
+EXTERN int regretp; /* Pointer to TOS of regret tokens */
+EXTERN int regretstack[REGDEP]; /* Stack of regretted tokens */
+EXTERN char *string_stack[REGDEP]; /* Stack of regretted strings */
+EXTERN int numberstack[REGDEP]; /* Stack of regretted numbers */
+EXTERN struct message *dot; /* Pointer to current message */
+EXTERN struct message *message; /* The actual message structure */
+EXTERN struct var *variables[HSHSIZE]; /* Pointer to active var list */
+EXTERN struct grouphead *groups[HSHSIZE];/* Pointer to active groups */
+EXTERN struct ignoretab ignore[2]; /* ignored and retained fields
+ 0 is ignore, 1 is retain */
+EXTERN struct ignoretab saveignore[2]; /* ignored and retained fields
+ on save to folder */
+EXTERN struct ignoretab ignoreall[2]; /* special, ignore all headers */
+EXTERN char **altnames; /* List of alternate names for user */
+EXTERN int debug; /* Debug flag set */
+EXTERN int screenwidth; /* Screen width, or best guess */
+EXTERN int screenheight; /* Screen height, or best guess,
+ for "header" command */
+EXTERN int realscreenheight; /* the real screen height */
+
+#include <setjmp.h>
+
+EXTERN jmp_buf srbuf;
+
+
+/*
+ * The pointers for the string allocation routines,
+ * there are NSPACE independent areas.
+ * The first holds STRINGSIZE bytes, the next
+ * twice as much, and so on.
+ */
+
+#define NSPACE 25 /* Total number of string spaces */
+EXTERN struct strings {
+ char *s_topFree; /* Beginning of this area */
+ char *s_nextFree; /* Next alloctable place here */
+ unsigned s_nleft; /* Number of bytes left here */
+} stringdope[NSPACE];
+
+#endif /* GLOB_H */
+
diff --git a/mail_cmds/mail/head.c b/mail_cmds/mail/head.c
new file mode 100644
index 0000000..d747cb0
--- /dev/null
+++ b/mail_cmds/mail/head.c
@@ -0,0 +1,291 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)head.c 8.2 (Berkeley) 4/20/95";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/head.c,v 1.8 2003/01/09 05:08:37 mikeh Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+#include "rcv.h"
+#include "extern.h"
+
+/*
+ * Mail -- a mail program
+ *
+ * Routines for processing and detecting headlines.
+ */
+
+/*
+ * See if the passed line buffer is a mail header.
+ * Return true if yes. Note the extreme pains to
+ * accomodate all funny formats.
+ */
+int
+ishead(linebuf)
+ char linebuf[];
+{
+ struct headline hl;
+ char parbuf[BUFSIZ];
+
+ if (strncmp(linebuf, "From ", 5) != 0)
+ return (0);
+ parse(linebuf, &hl, parbuf);
+ if (hl.l_date == NULL) {
+ fail(linebuf, "No date field");
+ return (0);
+ }
+ if (!isdate(hl.l_date)) {
+ fail(linebuf, "Date field not legal date");
+ return (0);
+ }
+ /*
+ * I guess we got it!
+ */
+ return (1);
+}
+
+/*ARGSUSED*/
+void
+fail(linebuf, reason)
+ const char *linebuf, *reason;
+{
+
+ /*
+ if (value("debug") == NULL)
+ return;
+ fprintf(stderr, "\"%s\"\nnot a header because %s\n", linebuf, reason);
+ */
+}
+
+/*
+ * Split a headline into its useful components.
+ * Copy the line into dynamic string space, then set
+ * pointers into the copied line in the passed headline
+ * structure. Actually, it scans.
+ */
+void
+parse(line, hl, pbuf)
+ char line[], pbuf[];
+ struct headline *hl;
+{
+ char *cp, *sp;
+ char word[LINESIZE];
+
+ hl->l_from = NULL;
+ hl->l_tty = NULL;
+ hl->l_date = NULL;
+ cp = line;
+ sp = pbuf;
+ /*
+ * Skip over "From" first.
+ */
+ cp = nextword(cp, word);
+ /*
+ * Check for missing return-path.
+ */
+ if (isdate(cp)) {
+ hl->l_date = copyin(cp, &sp);
+ return;
+ }
+ cp = nextword(cp, word);
+ if (strlen(word) > 0)
+ hl->l_from = copyin(word, &sp);
+ if (cp != NULL && strncmp(cp, "tty", 3) == 0) {
+ cp = nextword(cp, word);
+ hl->l_tty = copyin(word, &sp);
+ }
+ if (cp != NULL)
+ hl->l_date = copyin(cp, &sp);
+}
+
+/*
+ * Copy the string on the left into the string on the right
+ * and bump the right (reference) string pointer by the length.
+ * Thus, dynamically allocate space in the right string, copying
+ * the left string into it.
+ */
+char *
+copyin(src, space)
+ char *src;
+ char **space;
+{
+ char *cp, *top;
+
+ top = cp = *space;
+ while ((*cp++ = *src++) != '\0')
+ ;
+ *space = cp;
+ return (top);
+}
+
+/*
+ * Test to see if the passed string is a ctime(3) generated
+ * date string as documented in the manual. The template
+ * below is used as the criterion of correctness.
+ * Also, we check for a possible trailing time zone using
+ * the tmztype template.
+ *
+ * If the mail file is created by Sys V (Solaris), there are
+ * no seconds in the time. If the mail is created by another
+ * program such as imapd, it might have timezone as
+ * <-|+>nnnn (-0800 for instance) at the end.
+ */
+
+/*
+ * 'A' An upper case char
+ * 'a' A lower case char
+ * ' ' A space
+ * '0' A digit
+ * 'O' A digit or space
+ * 'p' A punctuation char
+ * 'P' A punctuation char or space
+ * ':' A colon
+ * 'N' A new line
+ */
+
+static char *date_formats[] = {
+ "Aaa Aaa O0 00:00:00 0000", /* Mon Jan 01 23:59:59 2001 */
+ "Aaa Aaa O0 00:00:00 AAA 0000", /* Mon Jan 01 23:59:59 PST 2001 */
+ "Aaa Aaa O0 00:00:00 0000 p0000", /* Mon Jan 01 23:59:59 2001 -0800 */
+ "Aaa Aaa O0 00:00 0000", /* Mon Jan 01 23:59 2001 */
+ "Aaa Aaa O0 00:00 AAA 0000", /* Mon Jan 01 23:59 PST 2001 */
+ "Aaa Aaa O0 00:00 0000 p0000", /* Mon Jan 01 23:59 2001 -0800 */
+ NULL
+};
+
+int
+isdate(date)
+ char date[];
+{
+ int i;
+
+ for(i = 0; date_formats[i] != NULL; i++) {
+ if (cmatch(date, date_formats[i]))
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Match the given string (cp) against the given template (tp).
+ * Return 1 if they match, 0 if they don't
+ */
+int
+cmatch(cp, tp)
+ char *cp, *tp;
+{
+
+ while (*cp != '\0' && *tp != '\0')
+ switch (*tp++) {
+ case 'a':
+ if (!islower((unsigned char)*cp++))
+ return (0);
+ break;
+ case 'A':
+ if (!isupper((unsigned char)*cp++))
+ return (0);
+ break;
+ case ' ':
+ if (*cp++ != ' ')
+ return (0);
+ break;
+ case '0':
+ if (!isdigit((unsigned char)*cp++))
+ return (0);
+ break;
+ case 'O':
+ if (*cp != ' ' && !isdigit((unsigned char)*cp))
+ return (0);
+ cp++;
+ break;
+ case 'p':
+ if (!ispunct((unsigned char)*cp++))
+ return (0);
+ break;
+ case 'P':
+ if (*cp != ' ' && !ispunct((unsigned char)*cp))
+ return (0);
+ cp++;
+ break;
+ case ':':
+ if (*cp++ != ':')
+ return (0);
+ break;
+ case 'N':
+ if (*cp++ != '\n')
+ return (0);
+ break;
+ }
+ if (*cp != '\0' || *tp != '\0')
+ return (0);
+ return (1);
+}
+
+/*
+ * Collect a liberal (space, tab delimited) word into the word buffer
+ * passed. Also, return a pointer to the next word following that,
+ * or NULL if none follow.
+ */
+char *
+nextword(wp, wbuf)
+ char *wp, *wbuf;
+{
+ int c;
+
+ if (wp == NULL) {
+ *wbuf = '\0';
+ return (NULL);
+ }
+ while ((c = *wp++) != '\0' && c != ' ' && c != '\t') {
+ *wbuf++ = c;
+ if (c == '"') {
+ while ((c = *wp++) != '\0' && c != '"')
+ *wbuf++ = c;
+ if (c == '"')
+ *wbuf++ = c;
+ else
+ wp--;
+ }
+ }
+ *wbuf = '\0';
+ for (; c == ' ' || c == '\t'; c = *wp++)
+ ;
+ if (c == '\0')
+ return (NULL);
+ return (wp - 1);
+}
diff --git a/mail_cmds/mail/lex.c b/mail_cmds/mail/lex.c
new file mode 100644
index 0000000..9296b31
--- /dev/null
+++ b/mail_cmds/mail/lex.c
@@ -0,0 +1,736 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)lex.c 8.2 (Berkeley) 4/20/95";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/lex.c,v 1.16 2004/03/06 13:27:59 mikeh Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+#include "rcv.h"
+#include <errno.h>
+#include <fcntl.h>
+#include "extern.h"
+
+/*
+ * Mail -- a mail program
+ *
+ * Lexical processing of commands.
+ */
+
+const char *prompt = "? "; /* Unix standard prompt */
+
+extern const struct cmd cmdtab[];
+extern const char *version;
+
+/*
+ * Set up editing on the given file name.
+ * If the first character of name is %, we are considered to be
+ * editing the file, otherwise we are reading our mail which has
+ * signficance for mbox and so forth.
+ *
+ * If the -e option is being passed to mail, this function has a
+ * tri-state return code: -1 on error, 0 on no mail, 1 if there is
+ * mail.
+ */
+int
+setfile(name)
+ char *name;
+{
+ FILE *ibuf;
+ int checkmode, i, fd;
+ struct stat stb;
+ char isedit = *name != '%' || getuserid(myname) != getuid();
+ char *who = name[1] ? name + 1 : myname;
+ char tempname[PATHSIZE];
+ static int shudclob;
+
+ checkmode = value("checkmode") != NULL;
+ if ((name = expand(name)) == NULL)
+ return (-1);
+
+ if ((ibuf = Fopen(name, "r")) == NULL) {
+ if (!isedit && errno == ENOENT)
+ goto nomail;
+ warn("%s", name);
+ return (-1);
+ }
+
+ if (fstat(fileno(ibuf), &stb) < 0) {
+ warn("fstat");
+ (void)Fclose(ibuf);
+ return (-1);
+ }
+
+ if (S_ISDIR(stb.st_mode) || !S_ISREG(stb.st_mode)) {
+ (void)Fclose(ibuf);
+ errno = S_ISDIR(stb.st_mode) ? EISDIR : EINVAL;
+ warn("%s", name);
+ return (-1);
+ }
+
+ /*
+ * Looks like all will be well. We must now relinquish our
+ * hold on the current set of stuff. Must hold signals
+ * while we are reading the new file, else we will ruin
+ * the message[] data structure.
+ */
+
+ holdsigs();
+ if (shudclob)
+ quit();
+
+ /*
+ * Copy the messages into /tmp
+ * and set pointers.
+ */
+
+ readonly = 0;
+ if ((i = open(name, 1)) < 0)
+ readonly++;
+ else
+ (void)close(i);
+ if (shudclob) {
+ (void)fclose(itf);
+ (void)fclose(otf);
+ }
+ shudclob = 1;
+ edit = isedit;
+ strlcpy(prevfile, mailname, sizeof(prevfile));
+ if (name != mailname)
+ strlcpy(mailname, name, sizeof(mailname));
+ mailsize = fsize(ibuf);
+ (void)snprintf(tempname, sizeof(tempname),
+ "%s/mail.RxXXXXXXXXXX", tmpdir);
+ if ((fd = mkstemp(tempname)) == -1 || (otf = fdopen(fd, "w")) == NULL)
+ err(1, "%s", tempname);
+ (void)fcntl(fileno(otf), F_SETFD, 1);
+ if ((itf = fopen(tempname, "r")) == NULL)
+ err(1, "%s", tempname);
+ (void)fcntl(fileno(itf), F_SETFD, 1);
+ (void)rm(tempname);
+ 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 = ftello(ibuf);
+ (void)Fclose(ibuf);
+ relsesigs();
+ sawcom = 0;
+
+ if ((checkmode || !edit) && msgCount == 0) {
+nomail:
+ if (!checkmode) {
+ fprintf(stderr, "No mail for %s\n", who);
+ return (-1);
+ } else
+ return (0);
+ }
+ return (checkmode ? 1 : 0);
+}
+
+/*
+ * Incorporate any new mail that has arrived since we first
+ * started reading mail.
+ */
+int
+incfile()
+{
+ off_t 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 = ftello(ibuf);
+ (void)Fclose(ibuf);
+ relsesigs();
+ return (msgCount - omsgCount);
+}
+
+int *msgvec;
+int reset_on_stop; /* do a reset() if stopped */
+
+/*
+ * Interpret user commands one by one. If standard input is not a tty,
+ * print no prompt.
+ */
+void
+commands()
+{
+ int n, eofloop = 0;
+ char linebuf[PATHSIZE+LINESIZE]; /* make very large to handle maximum pathname in commands */
+
+ if (!sourcing) {
+ if (signal(SIGINT, SIG_IGN) != SIG_IGN)
+ (void)signal(SIGINT, intr);
+ if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
+ (void)signal(SIGHUP, hangup);
+ (void)signal(SIGTSTP, stop);
+ (void)signal(SIGTTOU, stop);
+ (void)signal(SIGTTIN, stop);
+ }
+ setexit();
+ for (;;) {
+ /*
+ * Print the prompt, if needed. Clear out
+ * string space, and flush the output.
+ */
+ if (!sourcing && value("interactive") != NULL) {
+ char * current_prompt;
+ if ((value("autoinc") != NULL) && (incfile() > 0))
+ printf("New mail has arrived.\n");
+ reset_on_stop = 1;
+ if ((current_prompt = value("prompt")) != NULL) {
+ printf("%s", current_prompt);
+ }
+ }
+ (void)fflush(stdout);
+ sreset();
+ /*
+ * Read a line of commands from the current input
+ * and handle end of file specially.
+ */
+ n = 0;
+ for (;;) {
+ if (readline(input, &linebuf[n], sizeof(linebuf) - n) < 0) {
+ if (n == 0)
+ n = -1;
+ break;
+ }
+ if ((n = strlen(linebuf)) == 0)
+ break;
+ n--;
+ if (linebuf[n] != '\\')
+ break;
+ linebuf[n++] = ' ';
+ }
+ reset_on_stop = 0;
+ if (n < 0) {
+ /* eof */
+ if (loading)
+ break;
+ if (sourcing) {
+ unstack();
+ continue;
+ }
+ if (value("interactive") != NULL &&
+ value("ignoreeof") != NULL &&
+ ++eofloop < 25) {
+ printf("Use \"quit\" to quit.\n");
+ continue;
+ }
+ break;
+ }
+ eofloop = 0;
+ if (execute(linebuf, 0))
+ break;
+ }
+}
+
+/*
+ * Execute a single command.
+ * Command functions return 0 for success, 1 for error, and -1
+ * for abort. A 1 or -1 aborts a load or source. A -1 aborts
+ * the interactive command loop.
+ * Contxt is non-zero if called while composing mail.
+ */
+int
+execute(linebuf, contxt)
+ char linebuf[];
+ int contxt;
+{
+ char word[LINESIZE];
+ char *arglist[MAXARGC];
+ const struct cmd *com;
+ char *cp, *cp2;
+ int c, muvec[2];
+ int e = 1;
+
+ /*
+ * Strip the white space away from the beginning
+ * of the command, then scan out a word, which
+ * consists of anything except digits and white space.
+ *
+ * Handle ! escapes differently to get the correct
+ * lexical conventions.
+ */
+
+ for (cp = linebuf; isspace((unsigned char)*cp); cp++)
+ ;
+ if (*cp == '!') {
+ if (sourcing) {
+ printf("Can't \"!\" while sourcing\n");
+ goto out;
+ }
+ shell(cp+1);
+ return (0);
+ }
+ cp2 = word;
+ while (*cp != '\0' && strchr(" \t0123456789$^.:/-+*'\"", *cp) == NULL)
+ *cp2++ = *cp++;
+ *cp2 = '\0';
+
+ /*
+ * Look up the command; if not found, bitch.
+ * Normally, a blank command would map to the
+ * first command in the table; while sourcing,
+ * however, we ignore blank lines to eliminate
+ * confusion.
+ */
+
+ if (sourcing && *word == '\0')
+ return (0);
+ com = lex(word);
+ if (com == NULL) {
+ printf("Unknown command: \"%s\"\n", word);
+ goto out;
+ }
+
+ if (debug != 1) {
+ if (value("debug") == NULL) {
+ debug = 0;
+ } else {
+ debug = 2;
+ }
+ } /* else ignore debug env var */
+ if (debug)
+ fprintf(stderr, "debug mode: cmd is %s\n", com->c_name);
+
+ /*
+ * See if we should execute the command -- if a conditional
+ * we always execute it, otherwise, check the state of cond.
+ */
+
+ if ((com->c_argtype & F) == 0)
+ if ((cond == CRCV && !rcvmode) || (cond == CSEND && rcvmode))
+ return (0);
+
+ /*
+ * Process the arguments to the command, depending
+ * on the type he expects. Default to an error.
+ * If we are sourcing an interactive command, it's
+ * an error.
+ */
+
+ if (!rcvmode && (com->c_argtype & M) == 0) {
+ printf("May not execute \"%s\" while sending\n",
+ com->c_name);
+ goto out;
+ }
+ if (sourcing && com->c_argtype & I) {
+ printf("May not execute \"%s\" while sourcing\n",
+ com->c_name);
+ goto out;
+ }
+ if (readonly && com->c_argtype & W) {
+ printf("May not execute \"%s\" -- message file is read only\n",
+ com->c_name);
+ goto out;
+ }
+ if (contxt && com->c_argtype & R) {
+ printf("Cannot recursively invoke \"%s\"\n", com->c_name);
+ goto out;
+ }
+ switch (com->c_argtype & ~(F|P|I|M|T|W|R)) {
+ case MSGLIST:
+ /*
+ * A message list defaulting to nearest forward
+ * legal message.
+ */
+ if (msgvec == 0) {
+ printf("Illegal use of \"message list\"\n");
+ break;
+ }
+ if ((c = getmsglist(cp, msgvec, com->c_msgflag)) < 0)
+ break;
+ if (c == 0) {
+ *msgvec = first(com->c_msgflag, com->c_msgmask);
+ msgvec[1] = 0;
+ }
+ if (*msgvec == 0) {
+ printf("No applicable messages\n");
+ break;
+ }
+ e = (*com->c_func)(msgvec);
+ break;
+
+ case NDMLIST:
+ /*
+ * A message list with no defaults, but no error
+ * if none exist.
+ */
+ if (msgvec == 0) {
+ printf("Illegal use of \"message list\"\n");
+ break;
+ }
+ if (getmsglist(cp, msgvec, com->c_msgflag) < 0)
+ break;
+ e = (*com->c_func)(msgvec);
+ break;
+
+ case STRLIST:
+ /*
+ * Just the straight string, with
+ * leading blanks removed.
+ */
+ while (isspace((unsigned char)*cp))
+ cp++;
+ e = (*com->c_func)(cp);
+ break;
+
+ case RAWLIST:
+ /*
+ * A vector of strings, in shell style.
+ */
+ if ((c = getrawlist(cp, arglist,
+ sizeof(arglist) / sizeof(*arglist))) < 0)
+ break;
+ if (c < com->c_minargs) {
+ printf("%s requires at least %d arg(s)\n",
+ com->c_name, com->c_minargs);
+ break;
+ }
+ if (c > com->c_maxargs) {
+ printf("%s takes no more than %d arg(s)\n",
+ com->c_name, com->c_maxargs);
+ break;
+ }
+ e = (*com->c_func)(arglist);
+ break;
+
+ case NOLIST:
+ /*
+ * Just the constant zero, for exiting,
+ * eg.
+ */
+ e = (*com->c_func)(0);
+ break;
+
+ default:
+ errx(1, "Unknown argtype");
+ }
+
+out:
+ /*
+ * Exit the current source file on
+ * error.
+ */
+ if (e) {
+ if (e < 0)
+ return (1);
+ if (loading)
+ return (1);
+ if (sourcing)
+ 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;
+ muvec[1] = 0;
+ type(muvec);
+ }
+ if (!sourcing && (com->c_argtype & T) == 0)
+ sawcom = 1;
+ return (0);
+}
+
+/*
+ * Set the size of the message vector used to construct argument
+ * lists to message list functions.
+ */
+void
+setmsize(sz)
+ int sz;
+{
+
+ if (msgvec != NULL)
+ (void)free(msgvec);
+ msgvec = calloc((unsigned)(sz + 1), sizeof(*msgvec));
+}
+
+/*
+ * Find the correct command in the command table corresponding
+ * to the passed command "word"
+ */
+
+__const struct cmd *
+lex(word)
+ char word[];
+{
+ const struct cmd *cp;
+
+ /*
+ * ignore trailing chars after `#'
+ *
+ * lines with beginning `#' are comments
+ * spaces before `#' are ignored in execute()
+ */
+
+ if (*word == '#')
+ *(word+1) = '\0';
+
+
+ for (cp = &cmdtab[0]; cp->c_name != NULL; cp++)
+ if (isprefix(word, cp->c_name))
+ return (cp);
+ return (NULL);
+}
+
+/*
+ * Determine if as1 is a valid prefix of as2.
+ * Return true if yep.
+ */
+int
+isprefix(as1, as2)
+ const char *as1, *as2;
+{
+ const char *s1, *s2;
+
+ s1 = as1;
+ s2 = as2;
+ while (*s1++ == *s2)
+ if (*s2++ == '\0')
+ return (1);
+ return (*--s1 == '\0');
+}
+
+/*
+ * The following gets called on receipt of an interrupt. This is
+ * to abort printout of a command, mainly.
+ * Dispatching here when command() is inactive crashes rcv.
+ * Close all open files except 0, 1, 2, and the temporary.
+ * Also, unstack all source files.
+ */
+
+int inithdr; /* am printing startup headers */
+
+/*ARGSUSED*/
+void
+intr(s)
+ int s;
+{
+
+ noreset = 0;
+ if (!inithdr)
+ sawcom++;
+ inithdr = 0;
+ while (sourcing)
+ unstack();
+
+ close_all_files();
+
+ if (image >= 0) {
+ (void)close(image);
+ image = -1;
+ }
+ fprintf(stderr, "Interrupt\n");
+ reset(0);
+}
+
+/*
+ * When we wake up after ^Z, reprint the prompt.
+ */
+void
+stop(s)
+ int s;
+{
+ sig_t old_action = signal(s, SIG_DFL);
+ sigset_t nset;
+
+ (void)sigemptyset(&nset);
+ (void)sigaddset(&nset, s);
+ (void)sigprocmask(SIG_UNBLOCK, &nset, NULL);
+ (void)kill(0, s);
+ (void)sigprocmask(SIG_BLOCK, &nset, NULL);
+ (void)signal(s, old_action);
+ if (reset_on_stop) {
+ reset_on_stop = 0;
+ reset(0);
+ }
+}
+
+/*
+ * Branch here on hangup signal and simulate "exit".
+ */
+/*ARGSUSED*/
+void
+hangup(s)
+ int s;
+{
+
+ /* nothing to do? */
+ exit(1);
+}
+
+/*
+ * Announce the presence of the current Mail version,
+ * give the message count, and print a header listing.
+ */
+void
+announce()
+{
+ int vec[2], mdot;
+
+ mdot = newfileinfo(0);
+ vec[0] = mdot;
+ vec[1] = 0;
+ dot = &message[mdot - 1];
+ if (msgCount > 0 && value("header") != NULL) {
+ inithdr++;
+ headers(vec);
+ inithdr = 0;
+ }
+}
+
+/*
+ * Announce information about the file we are editing.
+ * Return a likely place to set dot.
+ */
+int
+newfileinfo(omsgCount)
+ int omsgCount;
+{
+ struct message *mp;
+ int u, n, mdot, d, s;
+ char fname[PATHSIZE+1], zname[PATHSIZE+1], *ename;
+
+ for (mp = &message[omsgCount]; mp < &message[msgCount]; mp++)
+ if (mp->m_flag & MNEW)
+ break;
+ if (mp >= &message[msgCount])
+ 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 = omsgCount + 1;
+ if (value("header") == NULL) {
+ return (mdot);
+ }
+ s = d = 0;
+ for (mp = &message[0], n = 0, u = 0; mp < &message[msgCount]; mp++) {
+ if (mp->m_flag & MNEW)
+ n++;
+ if ((mp->m_flag & MREAD) == 0)
+ u++;
+ if (mp->m_flag & MDELETED)
+ d++;
+ if (mp->m_flag & MSAVED)
+ s++;
+ }
+ ename = mailname;
+ if (getfold(fname, sizeof(fname) - 1) >= 0) {
+ strcat(fname, "/");
+ if (strncmp(fname, mailname, strlen(fname)) == 0) {
+ (void)snprintf(zname, sizeof(zname), "+%s",
+ mailname + strlen(fname));
+ ename = zname;
+ }
+ }
+ printf("\"%s\": ", ename);
+ if (msgCount == 1)
+ printf("1 message");
+ else
+ printf("%d messages", msgCount);
+ if (n > 0)
+ printf(" %d new", n);
+ if (u-n > 0)
+ printf(" %d unread", u);
+ if (d > 0)
+ printf(" %d deleted", d);
+ if (s > 0)
+ printf(" %d saved", s);
+ if (readonly)
+ printf(" [Read only]");
+ printf("\n");
+ return (mdot);
+}
+
+/*
+ * Print the current version number.
+ */
+
+/*ARGSUSED*/
+int
+pversion(e)
+ int e;
+{
+
+ printf("Version %s\n", version);
+ return (0);
+}
+
+/*
+ * Load a file of user definitions.
+ */
+void
+load(name)
+ char *name;
+{
+ FILE *in, *oldin;
+
+ if ((in = Fopen(name, "r")) == NULL)
+ return;
+ oldin = input;
+ input = in;
+ loading = 1;
+ sourcing = 1;
+ commands();
+ loading = 0;
+ sourcing = 0;
+ input = oldin;
+ (void)Fclose(in);
+}
diff --git a/mail_cmds/mail/list.c b/mail_cmds/mail/list.c
new file mode 100644
index 0000000..1b0a962
--- /dev/null
+++ b/mail_cmds/mail/list.c
@@ -0,0 +1,843 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)list.c 8.4 (Berkeley) 5/1/95";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/list.c,v 1.9 2002/06/30 05:25:06 obrien Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+#include "rcv.h"
+#include <ctype.h>
+#include "extern.h"
+
+/*
+ * Mail -- a mail program
+ *
+ * Message list handling.
+ */
+
+/*
+ * Convert the user string of message numbers and
+ * store the numbers into vector.
+ *
+ * Returns the count of messages picked up or -1 on error.
+ */
+int
+getmsglist(buf, vector, flags)
+ char *buf;
+ int *vector, flags;
+{
+ int *ip;
+ struct message *mp;
+
+ if (msgCount == 0) {
+ *vector = 0;
+ return (0);
+ }
+ if (markall(buf, flags) < 0)
+ return (-1);
+ ip = vector;
+ for (mp = &message[0]; mp < &message[msgCount]; mp++)
+ if (mp->m_flag & MMARK)
+ *ip++ = mp - &message[0] + 1;
+ *ip = 0;
+ return (ip - vector);
+}
+
+/*
+ * Mark all messages that the user wanted from the command
+ * line in the message structure. Return 0 on success, -1
+ * on error.
+ */
+
+/*
+ * Bit values for colon modifiers.
+ */
+
+#define CMNEW 01 /* New messages */
+#define CMOLD 02 /* Old messages */
+#define CMUNREAD 04 /* Unread messages */
+#define CMDELETED 010 /* Deleted messages */
+#define CMREAD 020 /* Read messages */
+
+/*
+ * The following table describes the letters which can follow
+ * the colon and gives the corresponding modifier bit.
+ */
+
+struct coltab {
+ char co_char; /* What to find past : */
+ int co_bit; /* Associated modifier bit */
+ int co_mask; /* m_status bits to mask */
+ int co_equal; /* ... must equal this */
+} coltab[] = {
+ { 'n', CMNEW, MNEW, MNEW },
+ { 'o', CMOLD, MNEW, 0 },
+ { 'u', CMUNREAD, MREAD, 0 },
+ { 'd', CMDELETED, MDELETED, MDELETED},
+ { 'r', CMREAD, MREAD, MREAD },
+ { 0, 0, 0, 0 }
+};
+
+static int lastcolmod;
+
+int
+markall(buf, f)
+ char buf[];
+ int f;
+{
+ char **np;
+ int i;
+ struct message *mp;
+ char *namelist[NMLSIZE], *bufp;
+ int tok, beg, mc, star, other, valdot, colmod, colresult;
+
+ valdot = dot - &message[0] + 1;
+ colmod = 0;
+ for (i = 1; i <= msgCount; i++)
+ unmark(i);
+ bufp = buf;
+ mc = 0;
+ np = &namelist[0];
+ scaninit();
+ tok = scan(&bufp);
+ star = 0;
+ other = 0;
+ beg = 0;
+ while (tok != TEOL) {
+ switch (tok) {
+ case TNUMBER:
+number:
+ if (star) {
+ printf("No numbers mixed with *\n");
+ return (-1);
+ }
+ mc++;
+ other++;
+ if (beg != 0) {
+ if (check(lexnumber, f))
+ return (-1);
+ for (i = beg; i <= lexnumber; i++)
+ if (f == MDELETED || (message[i - 1].m_flag & MDELETED) == 0)
+ mark(i);
+ beg = 0;
+ break;
+ }
+ beg = lexnumber;
+ if (check(beg, f))
+ return (-1);
+ tok = scan(&bufp);
+ regret(tok);
+ if (tok != TDASH) {
+ mark(beg);
+ beg = 0;
+ }
+ break;
+
+ case TPLUS:
+ if (beg != 0) {
+ printf("Non-numeric second argument\n");
+ return (-1);
+ }
+ i = valdot;
+ do {
+ i++;
+ if (i > msgCount) {
+ printf("Referencing beyond EOF\n");
+ return (-1);
+ }
+ } while ((message[i - 1].m_flag & MDELETED) != f);
+ mark(i);
+ break;
+
+ case TDASH:
+ if (beg == 0) {
+ i = valdot;
+ do {
+ i--;
+ if (i <= 0) {
+ printf("Referencing before 1\n");
+ return (-1);
+ }
+ } while ((message[i - 1].m_flag & MDELETED) != f);
+ mark(i);
+ }
+ break;
+
+ case TSTRING:
+ if (beg != 0) {
+ printf("Non-numeric second argument\n");
+ return (-1);
+ }
+ other++;
+ if (lexstring[0] == ':') {
+ colresult = evalcol(lexstring[1]);
+ if (colresult == 0) {
+ printf("Unknown colon modifier \"%s\"\n",
+ lexstring);
+ return (-1);
+ }
+ colmod |= colresult;
+ }
+ else
+ *np++ = savestr(lexstring);
+ break;
+
+ case TDOLLAR:
+ case TUP:
+ case TDOT:
+ lexnumber = metamess(lexstring[0], f);
+ if (lexnumber == -1)
+ return (-1);
+ goto number;
+
+ case TSTAR:
+ if (other) {
+ printf("Can't mix \"*\" with anything\n");
+ return (-1);
+ }
+ star++;
+ break;
+
+ case TERROR:
+ return (-1);
+ }
+ tok = scan(&bufp);
+ }
+ lastcolmod = colmod;
+ *np = NULL;
+ mc = 0;
+ if (star) {
+ for (i = 0; i < msgCount; i++)
+ if ((message[i].m_flag & MDELETED) == f) {
+ mark(i+1);
+ mc++;
+ }
+ if (mc == 0) {
+ printf("No applicable messages.\n");
+ return (-1);
+ }
+ return (0);
+ }
+
+ /*
+ * If no numbers were given, mark all of the messages,
+ * so that we can unmark any whose sender was not selected
+ * if any user names were given.
+ */
+
+ if ((np > namelist || colmod != 0) && mc == 0)
+ for (i = 1; i <= msgCount; i++)
+ if ((message[i-1].m_flag & MDELETED) == f)
+ mark(i);
+
+ /*
+ * If any names were given, go through and eliminate any
+ * messages whose senders were not requested.
+ */
+
+ if (np > namelist) {
+ for (i = 1; i <= msgCount; i++) {
+ for (mc = 0, np = &namelist[0]; *np != NULL; np++)
+ if (**np == '/') {
+ if (matchfield(*np, i)) {
+ mc++;
+ break;
+ }
+ }
+ else {
+ if (matchsender(*np, i)) {
+ mc++;
+ break;
+ }
+ }
+ if (mc == 0)
+ unmark(i);
+ }
+
+ /*
+ * Make sure we got some decent messages.
+ */
+
+ mc = 0;
+ for (i = 1; i <= msgCount; i++)
+ if (message[i-1].m_flag & MMARK) {
+ mc++;
+ break;
+ }
+ if (mc == 0) {
+ printf("No applicable messages from {%s",
+ namelist[0]);
+ for (np = &namelist[1]; *np != NULL; np++)
+ printf(", %s", *np);
+ printf("}\n");
+ return (-1);
+ }
+ }
+
+ /*
+ * If any colon modifiers were given, go through and
+ * unmark any messages which do not satisfy the modifiers.
+ */
+
+ if (colmod != 0) {
+ for (i = 1; i <= msgCount; i++) {
+ struct coltab *colp;
+
+ mp = &message[i - 1];
+ for (colp = &coltab[0]; colp->co_char != '\0'; colp++)
+ if (colp->co_bit & colmod)
+ if ((mp->m_flag & colp->co_mask)
+ != colp->co_equal)
+ unmark(i);
+
+ }
+ for (mp = &message[0]; mp < &message[msgCount]; mp++)
+ if (mp->m_flag & MMARK)
+ break;
+ if (mp >= &message[msgCount]) {
+ struct coltab *colp;
+
+ printf("No messages satisfy");
+ for (colp = &coltab[0]; colp->co_char != '\0'; colp++)
+ if (colp->co_bit & colmod)
+ printf(" :%c", colp->co_char);
+ printf("\n");
+ return (-1);
+ }
+ }
+ return (0);
+}
+
+/*
+ * Turn the character after a colon modifier into a bit
+ * value.
+ */
+int
+evalcol(col)
+ int col;
+{
+ struct coltab *colp;
+
+ if (col == 0)
+ return (lastcolmod);
+ for (colp = &coltab[0]; colp->co_char != '\0'; colp++)
+ if (colp->co_char == col)
+ return (colp->co_bit);
+ return (0);
+}
+
+/*
+ * Check the passed message number for legality and proper flags.
+ * If f is MDELETED, then either kind will do. Otherwise, the message
+ * has to be undeleted.
+ */
+int
+check(mesg, f)
+ int mesg, f;
+{
+ struct message *mp;
+
+ if (mesg < 1 || mesg > msgCount) {
+ printf("%d: Invalid message number\n", mesg);
+ return (-1);
+ }
+ mp = &message[mesg-1];
+ if (f != MDELETED && (mp->m_flag & MDELETED) != 0) {
+ printf("%d: Inappropriate message\n", mesg);
+ return (-1);
+ }
+ return (0);
+}
+
+/*
+ * Scan out the list of string arguments, shell style
+ * for a RAWLIST.
+ */
+int
+getrawlist(line, argv, argc)
+ char line[];
+ char **argv;
+ int argc;
+{
+ char c, *cp, *cp2, quotec;
+ int argn;
+ char *linebuf;
+ size_t linebufsize = BUFSIZ;
+
+ if ((linebuf = malloc(linebufsize)) == NULL)
+ err(1, "Out of memory");
+
+ argn = 0;
+ cp = line;
+ for (;;) {
+ for (; *cp == ' ' || *cp == '\t'; cp++)
+ ;
+ if (*cp == '\0')
+ break;
+ if (argn >= argc - 1) {
+ printf(
+ "Too many elements in the list; excess discarded.\n");
+ break;
+ }
+ cp2 = linebuf;
+ quotec = '\0';
+ while ((c = *cp) != '\0') {
+ /* Allocate more space if necessary */
+ if (cp2 - linebuf == linebufsize - 1) {
+ linebufsize += BUFSIZ;
+ if ((linebuf = realloc(linebuf, linebufsize)) == NULL)
+ err(1, "Out of memory");
+ cp2 = linebuf + linebufsize - BUFSIZ - 1;
+ }
+ cp++;
+ if (quotec != '\0') {
+ if (c == quotec)
+ quotec = '\0';
+ else if (c == '\\')
+ switch (c = *cp++) {
+ case '\0':
+ *cp2++ = '\\';
+ cp--;
+ break;
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ c -= '0';
+ if (*cp >= '0' && *cp <= '7')
+ c = c * 8 + *cp++ - '0';
+ if (*cp >= '0' && *cp <= '7')
+ c = c * 8 + *cp++ - '0';
+ *cp2++ = c;
+ break;
+ case 'b':
+ *cp2++ = '\b';
+ break;
+ case 'f':
+ *cp2++ = '\f';
+ break;
+ case 'n':
+ *cp2++ = '\n';
+ break;
+ case 'r':
+ *cp2++ = '\r';
+ break;
+ case 't':
+ *cp2++ = '\t';
+ break;
+ case 'v':
+ *cp2++ = '\v';
+ break;
+ default:
+ *cp2++ = c;
+ }
+ else if (c == '^') {
+ c = *cp++;
+ if (c == '?')
+ *cp2++ = '\177';
+ /* null doesn't show up anyway */
+ else if ((c >= 'A' && c <= '_') ||
+ (c >= 'a' && c <= 'z'))
+ *cp2++ = c & 037;
+ else {
+ *cp2++ = '^';
+ cp--;
+ }
+ } else
+ *cp2++ = c;
+ } else if (c == '"' || c == '\'')
+ quotec = c;
+ else if (c == ' ' || c == '\t')
+ break;
+ else
+ *cp2++ = c;
+ }
+ *cp2 = '\0';
+ argv[argn++] = savestr(linebuf);
+ }
+ argv[argn] = NULL;
+ (void)free(linebuf);
+ return (argn);
+}
+
+/*
+ * scan out a single lexical item and return its token number,
+ * updating the string pointer passed **p. Also, store the value
+ * of the number or string scanned in lexnumber or lexstring as
+ * appropriate. In any event, store the scanned `thing' in lexstring.
+ */
+
+struct lex {
+ char l_char;
+ char l_token;
+} singles[] = {
+ { '$', TDOLLAR },
+ { '.', TDOT },
+ { '^', TUP },
+ { '*', TSTAR },
+ { '-', TDASH },
+ { '+', TPLUS },
+ { '(', TOPEN },
+ { ')', TCLOSE },
+ { 0, 0 }
+};
+
+int
+scan(sp)
+ char **sp;
+{
+ char *cp, *cp2;
+ int c;
+ struct lex *lp;
+ int quotec;
+
+ if (regretp >= 0) {
+ strcpy(lexstring, string_stack[regretp]);
+ lexnumber = numberstack[regretp];
+ return (regretstack[regretp--]);
+ }
+ cp = *sp;
+ cp2 = lexstring;
+ c = *cp++;
+
+ /*
+ * strip away leading white space.
+ */
+
+ while (c == ' ' || c == '\t')
+ c = *cp++;
+
+ /*
+ * If no characters remain, we are at end of line,
+ * so report that.
+ */
+
+ if (c == '\0') {
+ *sp = --cp;
+ return (TEOL);
+ }
+
+ /*
+ * If the leading character is a digit, scan
+ * the number and convert it on the fly.
+ * Return TNUMBER when done.
+ */
+
+ if (isdigit((unsigned char)c)) {
+ lexnumber = 0;
+ while (isdigit((unsigned char)c)) {
+ lexnumber = lexnumber*10 + c - '0';
+ *cp2++ = c;
+ c = *cp++;
+ }
+ *cp2 = '\0';
+ *sp = --cp;
+ return (TNUMBER);
+ }
+
+ /*
+ * Check for single character tokens; return such
+ * if found.
+ */
+
+ for (lp = &singles[0]; lp->l_char != '\0'; lp++)
+ if (c == lp->l_char) {
+ lexstring[0] = c;
+ lexstring[1] = '\0';
+ *sp = cp;
+ return (lp->l_token);
+ }
+
+ /*
+ * We've got a string! Copy all the characters
+ * of the string into lexstring, until we see
+ * a null, space, or tab.
+ * If the lead character is a " or ', save it
+ * and scan until you get another.
+ */
+
+ quotec = 0;
+ if (c == '\'' || c == '"') {
+ quotec = c;
+ c = *cp++;
+ }
+ while (c != '\0') {
+ if (c == quotec) {
+ cp++;
+ break;
+ }
+ if (quotec == 0 && (c == ' ' || c == '\t'))
+ break;
+ if (cp2 - lexstring < STRINGLEN-1)
+ *cp2++ = c;
+ c = *cp++;
+ }
+ if (quotec && c == '\0') {
+ fprintf(stderr, "Missing %c\n", quotec);
+ return (TERROR);
+ }
+ *sp = --cp;
+ *cp2 = '\0';
+ return (TSTRING);
+}
+
+/*
+ * Unscan the named token by pushing it onto the regret stack.
+ */
+void
+regret(token)
+ int token;
+{
+ if (++regretp >= REGDEP)
+ errx(1, "Too many regrets");
+ regretstack[regretp] = token;
+ lexstring[STRINGLEN-1] = '\0';
+ string_stack[regretp] = savestr(lexstring);
+ numberstack[regretp] = lexnumber;
+}
+
+/*
+ * Reset all the scanner global variables.
+ */
+void
+scaninit()
+{
+ regretp = -1;
+}
+
+/*
+ * Find the first message whose flags & m == f and return
+ * its message number.
+ */
+int
+first(f, m)
+ int f, m;
+{
+ struct message *mp;
+
+ if (msgCount == 0)
+ return (0);
+ f &= MDELETED;
+ m &= MDELETED;
+ for (mp = dot; mp < &message[msgCount]; mp++)
+ if ((mp->m_flag & m) == f)
+ return (mp - message + 1);
+ for (mp = dot-1; mp >= &message[0]; mp--)
+ if ((mp->m_flag & m) == f)
+ return (mp - message + 1);
+ return (0);
+}
+
+/*
+ * See if the passed name sent the passed message number. Return true
+ * if so.
+ */
+int
+matchsender(str, mesg)
+ char *str;
+ int mesg;
+{
+ char *cp;
+
+ /* null string matches nothing instead of everything */
+ if (*str == '\0')
+ return (0);
+
+ cp = nameof(&message[mesg - 1], 0);
+ return (strcasestr(cp, str) != NULL);
+}
+
+/*
+ * 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, **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 = hfield(*to, mp);
+ if (cp != NULL && strcasestr(cp, str) != NULL)
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * See if the given substring is contained within the specified field. If
+ * 'searchheaders' is set, then the form '/x:y' will be accepted and matches
+ * any message with the substring 'y' in field 'x'. If 'x' is omitted or
+ * 'searchheaders' is not set, then the search matches any messages
+ * with the substring 'y' in the 'Subject'. The search is case insensitive.
+ *
+ * The form '/to:y' is a special case, and will match all messages
+ * containing the substring 'y' in the 'To', 'Cc', or 'Bcc' header
+ * fields. The search for 'to' is case sensitive, so that '/To:y' can
+ * be used to limit the search to just the 'To' field.
+ */
+
+char lastscan[STRINGLEN];
+int
+matchfield(str, mesg)
+ char *str;
+ int mesg;
+{
+ struct message *mp;
+ char *cp, *cp2;
+
+ str++;
+ if (*str == '\0')
+ str = lastscan;
+ else
+ strlcpy(lastscan, str, sizeof(lastscan));
+ mp = &message[mesg-1];
+
+ /*
+ * Now look, ignoring case, for the word in the string.
+ */
+
+ if (value("searchheaders") && (cp = strchr(str, ':')) != NULL) {
+ /* Check for special case "/to:" */
+ if (strncmp(str, "to:", 3) == 0)
+ return (matchto(cp, mesg));
+ *cp++ = '\0';
+ cp2 = hfield(*str != '\0' ? str : "subject", mp);
+ cp[-1] = ':';
+ str = cp;
+ cp = cp2;
+ } else
+ cp = hfield("subject", mp);
+
+ if (cp == NULL)
+ return (0);
+
+ return (strcasestr(cp, str) != NULL);
+}
+
+/*
+ * Mark the named message by setting its mark bit.
+ */
+void
+mark(mesg)
+ int mesg;
+{
+ int i;
+
+ i = mesg;
+ if (i < 1 || i > msgCount)
+ errx(1, "Bad message number to mark");
+ message[i-1].m_flag |= MMARK;
+}
+
+/*
+ * Unmark the named message.
+ */
+void
+unmark(mesg)
+ int mesg;
+{
+ int i;
+
+ i = mesg;
+ if (i < 1 || i > msgCount)
+ errx(1, "Bad message number to unmark");
+ message[i-1].m_flag &= ~MMARK;
+}
+
+/*
+ * Return the message number corresponding to the passed meta character.
+ */
+int
+metamess(meta, f)
+ int meta, f;
+{
+ int c, m;
+ struct message *mp;
+
+ c = meta;
+ switch (c) {
+ case '^':
+ /*
+ * First 'good' message left.
+ */
+ for (mp = &message[0]; mp < &message[msgCount]; mp++)
+ if ((mp->m_flag & MDELETED) == f)
+ return (mp - &message[0] + 1);
+ printf("No applicable messages\n");
+ return (-1);
+
+ case '$':
+ /*
+ * Last 'good message left.
+ */
+ for (mp = &message[msgCount-1]; mp >= &message[0]; mp--)
+ if ((mp->m_flag & MDELETED) == f)
+ return (mp - &message[0] + 1);
+ printf("No applicable messages\n");
+ return (-1);
+
+ case '.':
+ /*
+ * Current message.
+ */
+ m = dot - &message[0] + 1;
+ if ((dot->m_flag & MDELETED) != f) {
+ printf("%d: Inappropriate message\n", m);
+ return (-1);
+ }
+ return (m);
+
+ default:
+ printf("Unknown metachar (%c)\n", c);
+ return (-1);
+ }
+}
diff --git a/mail_cmds/mail/mail.1 b/mail_cmds/mail/mail.1
new file mode 100644
index 0000000..18e617e
--- /dev/null
+++ b/mail_cmds/mail/mail.1
@@ -0,0 +1,1272 @@
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)mail.1 8.8 (Berkeley) 4/28/95
+.\" $FreeBSD: src/usr.bin/mail/mail.1,v 1.45 2004/05/19 09:51:31 ru Exp $
+.\"
+.Dd February 29, 2004
+.Dt MAIL 1
+.Os
+.Sh NAME
+.Nm mail ,
+.Nm mailx
+.Nd send and receive mail
+.Sh SYNOPSIS
+.Nm
+.Op Fl EiInv
+.Op Fl s Ar subject
+.Op Fl c Ar cc-addr
+.Op Fl b Ar bcc-addr
+.Op Fl F
+.Ar to-addr ...
+.Op Fl Ar sendmail-option ...
+.Nm
+.Op Fl EHiInNv
+.Op Fl F
+.Fl f
+.Op Ar name
+.Nm
+.Op Fl EHiInNv
+.Op Fl F
+.Op Fl u Ar user
+.Nm
+.Fl e
+.Op Fl f Ar name
+.Nm
+.Op Fl H
+.Sh INTRODUCTION
+The
+.Nm
+utility is an intelligent mail processing system, which has
+a command syntax reminiscent of
+.Xr ed 1
+with lines replaced by messages.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl v
+Verbose mode.
+The details of
+delivery are displayed on the user's terminal.
+.It Fl e
+Test for the presence of mail in the (by default, system)
+mailbox.
+An exit status of 0 is returned if
+it has mail; otherwise, an exit status
+of 1 is returned.
+.It Fl H
+Write a header summary only.
+.It Fl E
+Do not send messages with an empty body.
+This is useful for piping errors from
+.Xr cron 8
+scripts.
+.It Fl i
+Ignore tty interrupt signals.
+This is
+particularly useful when using
+.Nm
+on noisy phone lines.
+.It Fl I
+Force
+.Nm
+to run in interactive mode even when
+input is not a terminal.
+In particular, the
+.Ql ~
+special
+character when sending mail is only active in interactive mode.
+.It Fl n
+Inhibit reading the system-wide
+.Pa mail.rc
+files upon startup.
+.It Fl N
+Inhibit the initial display of message headers
+when reading mail or editing a mail folder.
+.It Fl s Ar subject
+Specify
+.Ar subject
+on command line.
+(Only the first argument after the
+.Fl s
+flag is used as a subject; be careful to quote subjects
+containing spaces.)
+.It Fl c Ar cc-addr
+Send carbon copies to
+.Ar cc-addr
+list of users.
+The
+.Ar cc-addr
+argument should be a comma-separated list of names.
+.It Fl b Ar bcc-addr
+Send blind carbon copies to
+.Ar bcc-addr
+list of users.
+The
+.Ar bcc-addr
+argument should be a comma-separated list of names.
+.It Fl f Op Ar mbox
+Read in the contents of your
+.Pa mbox
+(or the specified file)
+for processing; when you
+.Ic quit ,
+.Nm
+writes undeleted messages back to this file.
+.It Fl F
+Record the message in a file named after the first
+recipient.
+The name is the login-name portion of the
+address found first on the
+.Dq Li To:
+line in the mail header.
+Overrides the
+.Va record
+variable, if set.
+.It Fl u
+Is equivalent to:
+.Pp
+.Dl "mail -f /var/mail/user"
+.El
+.Ss "Startup Actions"
+At startup time
+.Nm
+will execute commands in the system command files
+.Pa /usr/share/misc/mail.rc ,
+.Pa /usr/local/etc/mail.rc
+and
+.Pa /etc/mail.rc
+in order, unless explicitly told not to by the use of the
+.Fl n
+option.
+Next, the commands in the user's personal command file
+.Pa ~/.mailrc
+are executed.
+The
+.Nm
+utility then examines its command line options to determine whether a
+new message is to be sent, or whether an existing mailbox is to
+be read.
+.Ss "Sending Mail"
+To send a message to one or more people,
+.Nm
+can be invoked with arguments which are the names of people to
+whom the mail will be sent.
+You are then expected to type in
+your message, followed
+by a
+.Aq Li control-D
+at the beginning of a line.
+The section below
+.Sx "Replying To or Originating Mail" ,
+describes some features of
+.Nm
+available to help you compose your letter.
+.Ss "Reading Mail"
+In normal usage
+.Nm
+is given no arguments and checks your mail out of the
+post office, then
+prints out a one line header of each message found.
+The current message is initially the first message (numbered 1)
+and can be printed using the
+.Ic print
+command (which can be abbreviated
+.Ic p ) .
+You can move among the messages much as you move between lines in
+.Xr ed 1 ,
+with the commands
+.Ic +
+and
+.Ic \-
+moving backwards and forwards, and
+simple numbers.
+.Ss "Disposing of Mail"
+After examining a message you can
+.Ic delete
+.Pq Ic d
+the message or
+.Ic reply
+.Pq Ic r
+to it.
+Deletion causes the
+.Nm
+program to forget about the message.
+This is not irreversible; the message can be
+.Ic undeleted
+.Pq Ic u
+by giving its number, or the
+.Nm
+session can be aborted by giving the
+.Ic exit
+.Pq Ic x
+command.
+Deleted messages will, however, usually disappear never to be seen again.
+.Ss "Specifying Messages"
+Commands such as
+.Ic print
+and
+.Ic delete
+can be given a list of message numbers as arguments to apply
+to a number of messages at once.
+Thus
+.Dq Li "delete 1 2"
+deletes messages 1 and 2, while
+.Dq Li "delete 1\-5"
+deletes messages 1 through 5.
+The special name
+.Ql *
+addresses all messages, and
+.Ql $
+addresses
+the last message; thus the command
+.Ic top
+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.
+.Ss "Replying To or Originating Mail"
+You can use the
+.Ic reply
+command to
+set up a response to a message, sending it back to the
+person who it was from.
+Text you then type in, up to an end-of-file,
+defines the contents of the message.
+While you are composing a message,
+.Nm
+treats lines beginning with the character
+.Ql ~
+specially.
+For instance, typing
+.Ic ~m
+(alone on a line) will place a copy
+of the current message into the response right shifting it by a tabstop
+(see
+.Va indentprefix
+variable, below).
+Other escapes will set up subject fields, add and delete recipients
+to the message and allow you to escape to an editor to revise the
+message or to a shell to run some commands.
+(These options
+are given in the summary below.)
+.Ss "Ending a Mail Processing Session"
+You can end a
+.Nm
+session with the
+.Ic quit
+.Pq Ic q
+command.
+Messages which have been examined go to your
+.Pa mbox
+file unless they have been deleted in which case they are discarded.
+Unexamined messages go back to the post office.
+(See the
+.Fl f
+option above).
+.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
+and have it go
+to a group of people.
+Such lists can be defined by placing a line like
+.Pp
+.Dl "alias cohorts bill ozalp jkf mark kridle@ucbcory"
+.Pp
+in the file
+.Pa .mailrc
+in your home directory.
+The current list of such aliases can be displayed with the
+.Ic alias
+command in
+.Nm .
+System wide distribution lists can be created by editing
+.Pa /etc/mail/aliases ,
+see
+.Xr aliases 5
+and
+.Xr sendmail 8 ;
+these are kept in a different syntax.
+In mail you send, personal aliases will be expanded in mail sent
+to others so that they will be able to
+.Ic reply
+to the recipients.
+System wide
+aliases
+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 8 .
+.Ss "Network Mail (ARPA, UUCP, Berknet)"
+See
+.Xr mailaddr 7
+for a description of network addresses.
+.Pp
+The
+.Nm
+utility has a number of options which can be set in the
+.Pa .mailrc
+file to alter its behavior; thus
+.Dq Li "set askcc"
+enables the
+.Va askcc
+feature.
+(These options are summarized below.)
+.Sh SUMMARY
+(Adapted from the
+.%T "Mail Reference Manual" . )
+.Pp
+Each command is typed on a line by itself, and may take arguments
+following the command word.
+The command need not be typed in its
+entirety \(em the first command which matches the typed prefix is used.
+For commands which take message lists as arguments, if no message
+list is given, then the next message forward which satisfies the
+command's requirements is used.
+If there are no messages forward of
+the current message, the search proceeds backwards, and if there are no
+good messages at all,
+.Nm
+types
+.Dq Li "No applicable messages"
+and
+aborts the command.
+.Bl -tag -width indent
+.It Ic \-
+Print out the preceding message.
+If given a numeric
+argument
+.Ar n ,
+goes to the
+.Ar n Ns 'th
+previous message and prints it.
+.It Ic #
+ignore the remainder of the line as a comment.
+.It Ic \&?
+Prints a brief summary of commands.
+.It Ic \&!
+Executes the shell
+(see
+.Xr sh 1
+and
+.Xr csh 1 )
+command which follows.
+.It Ic Print
+.Pq Ic P
+Like
+.Ic print
+but also prints out ignored header fields.
+See also
+.Ic print , ignore
+and
+.Ic retain .
+.It Ic Reply
+.Pq Ic R
+Reply to originator.
+Does not reply to other
+recipients of the original message.
+.It Ic Type
+.Pq Ic T
+Identical to the
+.Ic Print
+command.
+.It Ic alias
+.Pq Ic a
+With no arguments, prints out all currently-defined aliases.
+With one
+argument, prints out that alias.
+With more than one argument, creates
+a new alias or changes an old one.
+.It Ic alternates
+.Pq Ic alt
+The
+.Ic alternates
+command is useful if you have accounts on several machines.
+It can be used to inform
+.Nm
+that the listed addresses are really you.
+When you
+.Ic reply
+to messages,
+.Nm
+will not send a copy of the message to any of the addresses
+listed on the
+.Ic alternates
+list.
+If the
+.Ic alternates
+command is given with no argument, the current set of alternative
+names is displayed.
+.It Ic chdir
+.Pq Ic c
+Changes the user's working directory to that specified, if given.
+If
+no directory is given, then changes to the user's login directory.
+.It Ic copy
+.Pq Ic co
+The
+.Ic copy
+command does the same thing that
+.Ic save
+does, except that it does not mark the messages it
+is used on for deletion when you
+.Ic quit .
+.It Ic delete
+.Pq Ic d
+Takes a list of messages as argument and marks them all as deleted.
+Deleted messages will not be saved in
+.Pa mbox ,
+nor will they be available for most other commands.
+.It Ic dp
+(also
+.Ic dt )
+Deletes the current message and prints the next message.
+If there is no next message,
+.Nm
+says
+.Dq Li "at EOF" .
+.It Ic edit
+.Pq Ic e
+Takes a list of messages and points the text editor at each one in
+turn.
+On return from the editor, the message is read back in.
+.It Ic exit
+.Ic ( ex
+or
+.Ic x )
+Effects an immediate return to the shell without
+modifying the user's system mailbox, his
+.Pa mbox
+file, or his edit file in
+.Fl f .
+.It Ic file
+.Pq Ic fi
+The same as
+.Ic folder .
+.It Ic folders
+List the names of the folders in your folder directory.
+.It Ic folder
+.Pq Ic fo
+The
+.Ic folder
+command switches to a new mail file or folder.
+With no
+arguments, it tells you which file you are currently reading.
+If you give it an argument, it will write out changes (such
+as deletions) you have made in the current file and read in
+the new file.
+Some special conventions are recognized for
+the name.
+.Ql #
+means the previous file,
+.Ql %
+means your system mailbox,
+.Dq Li % Ns Ar user
+means user's system mailbox,
+.Ql &
+means your
+.Pa mbox
+file, and
+.Dq Li + Ns Ar folder
+means a file in your folder
+directory.
+.It Ic from
+.Pq Ic f
+Takes a list of messages and prints their message headers.
+.It Ic headers
+.Pq Ic h
+Lists the current range of headers, which is an 18-message group.
+If
+a
+.Ql +
+argument is given, then the next 18-message group is printed, and if
+a
+.Ql \-
+argument is given, the previous 18-message group is printed.
+.It Ic help
+A synonym for
+.Ic \&? .
+.It Ic hold
+.Ic ( ho ,
+also
+.Ic preserve )
+Takes a message list and marks each
+message therein to be saved in the
+user's system mailbox instead of in
+.Pa mbox .
+Does not override the
+.Ic delete
+command.
+.It Ic ignore
+Add the list of header fields named to the
+.Ar ignored list .
+Header fields in the ignore list are not printed
+on your terminal when you print a message.
+This
+command is very handy for suppression of certain machine-generated
+header fields.
+The
+.Ic Type
+and
+.Ic Print
+commands can be used to print a message in its entirety, including
+ignored fields.
+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 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 mbox
+Indicate that a list of messages be sent to
+.Pa mbox
+in your home directory when you quit.
+This is the default
+action for messages if you do
+.Em not
+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
+.Ic ( n ,
+like
+.Ic +
+or
+.Tn CR )
+Goes to the next message in sequence and types it.
+With an argument list, types the next matching message.
+.It Ic preserve
+.Pq Ic pre
+A synonym for
+.Ic hold .
+.It Ic print
+.Pq Ic p
+Takes a message list and types out each message on the user's terminal.
+.It Ic quit
+.Pq Ic q
+Terminates the session, saving all undeleted, unsaved messages in
+the user's
+.Pa mbox
+file in his login directory, preserving all messages marked with
+.Ic hold
+or
+.Ic preserve
+or never referenced
+in his system mailbox, and removing all other messages from his system
+mailbox.
+If new mail has arrived during the session, the message
+.Dq Li "You have new mail"
+is given.
+If given while editing a
+mailbox file with the
+.Fl f
+flag, then the edit file is rewritten.
+A return to the shell is
+effected, unless the rewrite of edit file fails, in which case the user
+can escape with the
+.Ic exit
+command.
+.It Ic reply
+.Pq Ic r
+Takes a message list and sends mail to the sender and all
+recipients of the specified message.
+The default message must not be deleted.
+.It Ic respond
+A synonym for
+.Ic reply .
+.It Ic retain
+Add the list of header fields named to the
+.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
+and
+.Ic print
+commands can be used to print a message in its entirety.
+If
+.Ic retain
+is executed with no arguments, it lists the current set of
+retained fields.
+.It Ic save
+.Pq Ic s
+Takes a message list and a filename and appends each message in
+turn to the end of the file.
+The filename in quotes, followed by the line
+count and character count is echoed on the user's terminal.
+.It Ic set
+.Pq Ic se
+With no arguments, prints all variable values.
+Otherwise, sets
+option.
+Arguments are of the form
+.Ar option Ns Li = Ns Ar value
+(no space before or after
+.Ql = )
+or
+.Ar option .
+Quotation marks may be placed around any part of the assignment statement to
+quote blanks or tabs, i.e.\&
+.Dq Li "set indentprefix=\*q->\*q"
+.It Ic saveignore
+.Ic Saveignore
+is to
+.Ic save
+what
+.Ic ignore
+is to
+.Ic print
+and
+.Ic type .
+Header fields thus marked are filtered out when
+saving a message by
+.Ic save
+or when automatically saving to
+.Pa mbox .
+.It Ic saveretain
+.Ic Saveretain
+is to
+.Ic save
+what
+.Ic retain
+is to
+.Ic print
+and
+.Ic type .
+Header fields thus marked are the only ones saved
+with a message when saving by
+.Ic save
+or when automatically saving to
+.Pa mbox .
+.Ic Saveretain
+overrides
+.Ic saveignore .
+.It Ic shell
+.Pq Ic sh
+Invokes an interactive version of the shell.
+.It Ic size
+Takes a message list and prints out the size in characters of each
+message.
+.It Ic source
+The
+.Ic source
+command reads
+commands from a file.
+.It Ic top
+Takes a message list and prints the top few lines of each.
+The number of
+lines printed is controlled by the variable
+.Va toplines
+and defaults to 5.
+.It Ic type
+.Pq Ic t
+A synonym for
+.Ic print .
+.It Ic unalias
+Takes a list of names defined by
+.Ic alias
+commands and discards the remembered groups of users.
+The group names
+no longer have any significance.
+.It Ic undelete
+.Pq Ic u
+Takes a message list and marks each message as
+.Em not
+being deleted.
+.It Ic unread
+.Pq Ic U
+Takes a message list and marks each message as
+.Em not
+having been read.
+.It Ic unset
+Takes a list of option names and discards their remembered values;
+the inverse of
+.Ic set .
+.It Ic visual
+.Pq Ic v
+Takes a message list and invokes the display editor on each message.
+.It Ic write
+.Pq Ic w
+Similar to
+.Ic save ,
+except that
+.Em only
+the message body
+.Em ( without
+the header) is saved.
+Extremely useful for such tasks as sending and receiving source
+program text over the message system.
+.It Ic xit
+.Pq Ic x
+A synonym for
+.Ic exit .
+.It Ic z
+The
+.Nm
+utility presents message headers in windowfuls as described under the
+.Ic headers
+command.
+You can move
+.Nm Ns 's
+attention forward to the next window with the
+.Ic z
+command.
+Also, you can move to the previous window by using
+.Ic z\- .
+.El
+.Ss Tilde/Escapes
+Here is a summary of the tilde escapes,
+which are used when composing messages to perform
+special functions.
+Tilde escapes are only recognized at the beginning
+of lines.
+The name
+.Dq "tilde escape"
+is somewhat of a misnomer since the actual escape character can be set
+by the option
+.Va escape .
+.Bl -tag -width indent
+.It Ic ~a
+Inserts the autograph string from the sign= option into the message.
+.It Ic ~A
+Inserts the autograph string from the Sign= option into the message.
+.It Ic ~b Ar name ...
+Add the given names to the list of carbon copy recipients but do not make
+the names visible in the Cc: line
+.Dq ( blind
+carbon copy).
+.It Ic ~c Ar name ...
+Add the given names to the list of carbon copy recipients.
+.It Ic ~d
+Read the file
+.Pa dead.letter
+from your home directory into the message.
+.It Ic ~e
+Invoke the text editor on the message collected so far.
+After the
+editing session is finished, you may continue appending text to the
+message.
+.It Ic ~f Ar messages
+Read the named messages into the message being sent.
+If no messages are specified, read in the current message.
+Message headers currently being ignored (by the
+.Ic ignore
+or
+.Ic retain
+command) are not included.
+.It Ic ~F Ar messages
+Identical to
+.Ic ~f ,
+except all message headers are included.
+.It Ic ~h
+Edit the message header fields by typing each one in turn and allowing
+the user to append text to the end or modify the field by using the
+current terminal erase and kill characters.
+.It Ic ~i Ar string
+Inserts the value of the named option into the text of the message.
+.It Ic ~m Ar messages
+Read the named messages into the message being sent, indented by a
+tab or by the value of
+.Va indentprefix .
+If no messages are specified,
+read the current message.
+Message headers currently being ignored (by the
+.Ic ignore
+or
+.Ic retain
+command) are not included.
+.It Ic ~M Ar messages
+Identical to
+.Ic ~m ,
+except all message headers are included.
+.It Ic ~p
+Print out the message collected so far, prefaced by the message header
+fields.
+.It Ic ~q
+Abort the message being sent, copying the message to
+.Pa dead.letter
+in your home directory if
+.Va save
+is set.
+.It Ic ~r Ar filename , Ic ~r Li \&! Ns Ar command
+.It Ic ~< Ar filename , Ic ~< Li \&! Ns Ar command
+Read the named file into the message.
+If the argument begins with a
+.Ql \&! ,
+the rest of the string is taken as an arbitrary system command and is
+executed, with the standard output inserted into the message.
+.It Ic ~R Ar string
+Use
+.Ar string
+as the Reply-To field.
+.It Ic ~s Ar string
+Cause the named string to become the current subject field.
+.It Ic ~t Ar name ...
+Add the given names to the direct recipient list.
+.It Ic ~v
+Invoke an alternative editor (defined by the
+.Ev VISUAL
+environment variable) on the
+message collected so far.
+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.
+.It Ic ~w Ar filename
+Write the message onto the named file.
+.It Ic ~x
+Exits as with
+.Ic ~q ,
+except the message is not saved in
+.Pa dead.letter .
+.It Ic ~! Ar command
+Execute the indicated shell command, then return to the message.
+.It Ic ~| Ar command , Ic ~^ Ar command
+Pipe the message through the command as a filter.
+If the command gives
+no output or terminates abnormally, retain the original text of the
+message.
+The command
+.Xr fmt 1
+is often used as
+.Ar command
+to rejustify the message.
+.It Ic ~: Ar mail-command , Ic ~_ Ar mail-command
+Execute the given
+.Nm
+command.
+Not all commands, however, are allowed.
+.It Ic ~.
+Simulate end-of-file on input.
+.It Ic ~?
+Print a summary of the available command escapes.
+.It Ic ~~ Ar string
+Insert the string of text in the message prefaced by a single
+.Ql ~ .
+If
+you have changed the escape character, then you should double
+that character in order to send it.
+.El
+.Ss "Mail Options"
+Options can be set with the
+.Ic set
+command
+and can be disabled with the
+.Ic unset
+or
+.Ic set Cm no Ns Ar name
+commands.
+Options may be either binary, in which case it is only
+significant to see whether they are set or not; or string, in which
+case the actual value is of interest.
+If an option is not set,
+.Nm
+will look for an environment variable of the same name.
+The available options include the following:
+.Bl -tag -width indent
+.It Va append
+Causes messages saved in
+.Pa mbox
+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).
+Default is
+.Va noappend .
+.It Va 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.
+Default is
+.Va asksub .
+.It Va 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.
+Default is
+.Va noaskbcc .
+.It Va 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.
+Default is
+.Va noaskcc .
+.It Va 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.
+Default is
+.Va noautoinc .
+.It Va autoprint
+Causes the
+.Ic delete
+command to behave like
+.Ic dp ;
+thus, after deleting a message, the next one will be typed
+automatically.
+Default is
+.Va noautoprint .
+.It Va crt
+The valued option
+.Va crt
+is used as a threshold to determine how long a message must
+be before
+.Ev PAGER
+is used to read it.
+If
+.Va crt
+is set without a value,
+then the height of the terminal screen stored in the system
+is used to compute the threshold (see
+.Xr stty 1 ) .
+Default is
+.Va nocrt .
+.It Va debug
+Setting the binary option
+.Va debug
+is the same as specifying
+.Fl d
+on the command line and causes
+.Nm
+to output all sorts of information useful for debugging
+.Nm .
+Default is
+.Va nodebug .
+.It Va dot
+The binary option
+.Va dot
+causes
+.Nm
+to interpret a period alone on a line as the terminator
+of a message you are sending.
+Default is
+.Va nodot .
+.It Va escape
+If defined, the first character of this option gives the character to
+use in place of
+.Ql ~
+to denote escapes.
+.It Va flipr
+Reverses the sense of
+.Ic reply
+and
+.Ic Reply
+commands.
+Default is
+.Va noflipr .
+.It Va folder
+The name of the directory to use for storing folders of
+messages.
+If this name begins with a
+.Ql / ,
+.Nm
+considers it to be an absolute pathname; otherwise, the
+folder directory is found relative to your home directory.
+.It Va header
+If defined, initially display message headers when reading mail or
+editing a mail folder.
+Default is
+.Va header .
+This option can be disabled by giving the
+.Fl N
+flag on the command line.
+.It Va hold
+This option is used to hold messages in the system mailbox
+by default.
+Default is
+.Va nohold .
+.It Va ignore
+Causes interrupt signals from your terminal to be ignored and echoed as
+.Li @ Ns 's.
+Default is
+.Va noignore .
+.It Va ignoreeof
+An option related to
+.Va dot
+is
+.Va ignoreeof
+which makes
+.Nm
+refuse to accept a
+.Aq Li control-D
+as the end of a message.
+.Ar Ignoreeof
+also applies to
+.Nm
+command mode.
+Default is
+.Va noignoreeof .
+.It Va indentprefix
+String used by the
+.Ic ~m
+tilde escape for indenting messages, in place of
+the normal tab character
+.Pq Li ^I .
+Be sure to quote the value if it contains
+spaces or tabs.
+.It Va metoo
+Usually, when a group is expanded that contains the sender, the sender
+is removed from the expansion.
+Setting this option causes the sender
+to be included in the group.
+Default is
+.Va nometoo .
+.It Va quiet
+Suppresses the printing of the version when first invoked.
+Default is
+.Va noquiet .
+.It Va record
+If defined, gives the pathname of the file used to record all outgoing
+mail.
+If not defined, outgoing mail is not saved.
+Default is
+.Va norecord .
+.It Va Replyall
+Reverses the sense of
+.Ic reply
+and
+.Ic Reply
+commands.
+Default is
+.Va noReplyall .
+.It Va save
+If this option is set, and you abort a message with two
+.Tn RUBOUT
+(erase or delete),
+.Nm
+will copy the partial letter to the file
+.Pa dead.letter
+in your home directory.
+Default is
+.Va save .
+.It Va searchheaders
+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
+.Ar y
+in the header field
+.Ar x .
+The string search is case insensitive.
+If
+.Ar x
+is omitted, 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
+.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
+.Ar y
+to just the
+.Dq Li To:
+field.
+Default is
+.Va nosearchheaders .
+.It Va toplines
+If defined, gives the number of lines of a message to be printed out
+with the
+.Ic top
+command; normally, the first five lines are printed.
+.It Va verbose
+Setting the option
+.Va verbose
+is the same as using the
+.Fl v
+flag on the command line.
+When
+.Nm
+runs in verbose mode,
+the actual delivery of messages is displayed on the user's
+terminal.
+Default is
+.Va noverbose .
+.El
+.Sh ENVIRONMENT
+.Bl -tag -width ".Ev REPLYTO"
+.It Ev DEAD
+Pathname of the file to save partial messages to in case of interrupts
+or delivery errors.
+Default is
+.Pa ~/dead.letter .
+.It Ev EDITOR
+Pathname of the text editor to use in the
+.Ic edit
+command and
+.Ic ~e
+escape.
+If not defined, then a default editor is used.
+.It Ev HOME
+Pathname of the user's home directory.
+.It Ev LISTER
+Pathname of the directory lister to use in the
+.Ic folders
+command.
+Default is
+.Pa /bin/ls .
+.It Ev MAIL
+Location of the user's mailbox.
+Default is
+.Pa /var/mail .
+.It Ev MAILRC
+Pathname of file containing initial
+.Nm
+commands.
+Default is
+.Pa ~/.mailrc .
+.It Ev MBOX
+The name of the mailbox file.
+It can be the name of a folder.
+The default is
+.Pa mbox
+in the user's home directory.
+.It Ev PAGER
+Pathname of the program to use in the
+.Ic more
+command or when
+.Va crt
+variable is set.
+The default paginator
+.Xr more 1
+is used if this option is not defined.
+.It Ev REPLYTO
+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 \&!
+command and the
+.Ic ~!
+escape.
+A default shell is used if this option is
+not defined.
+.It Ev VISUAL
+Pathname of the text editor to use in the
+.Ic visual
+command and
+.Ic ~v
+escape.
+.It Ev USER
+Login name of the user executing mail.
+.El
+.Sh FILES
+.Bl -tag -width ".Pa /usr/share/misc/mail.*help" -compact
+.It Pa /var/mail/*
+Post office.
+.It Pa ~/mbox
+User's old mail.
+.It Pa ~/.mailrc
+File giving initial
+.Nm
+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
+Help files.
+.Pp
+.It Pa /usr/share/misc/mail.rc
+.It Pa /usr/local/etc/mail.rc
+.It Pa /etc/mail.rc
+System-wide initialization files.
+Each file will be sourced, in order,
+if it exists.
+.El
+.Sh SEE ALSO
+.Xr fmt 1 ,
+.Xr newaliases 1 ,
+.Xr vacation 1 ,
+.Xr aliases 5 ,
+.Xr mailaddr 7 ,
+.Xr sendmail 8
+.Rs
+.%T "The Mail Reference Manual"
+.Re
+.Sh HISTORY
+A
+.Nm
+command
+appeared in
+.At v1 .
+This man page is derived from
+.%T "The Mail Reference Manual"
+originally written by
+.An Kurt Shoens .
+.Sh BUGS
+There are some flags that are not documented here.
+Most are
+not useful to the general user.
+.Pp
+Usually,
+.Nm
+is just a link to
+.Nm Mail
+and
+.Nm mailx ,
+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.
diff --git a/mail_cmds/mail/mailx.1 b/mail_cmds/mail/mailx.1
new file mode 100644
index 0000000..6c49b5b
--- /dev/null
+++ b/mail_cmds/mail/mailx.1
@@ -0,0 +1 @@
+.so man1/mail.1
diff --git a/mail_cmds/mail/main.c b/mail_cmds/mail/main.c
new file mode 100644
index 0000000..915a376
--- /dev/null
+++ b/mail_cmds/mail/main.c
@@ -0,0 +1,395 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__unused static char copyright[] =
+"@(#) Copyright (c) 1980, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)main.c 8.2 (Berkeley) 4/20/95";
+#endif
+__unused static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/main.c,v 1.14 2004/02/29 20:44:44 mikeh Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+#include <sys/ioctl.h>
+
+#define EXTERN
+#include "rcv.h"
+#include <fcntl.h>
+#include "extern.h"
+
+/*
+ * Mail -- a mail program
+ *
+ * Startup -- interface with user.
+ */
+
+jmp_buf hdrjmp;
+
+extern const char *version;
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int i;
+ struct name *to, *cc, *bcc, *smopts;
+ char *subject, *replyto;
+ char *ef, *rc;
+ char nosrc = 0;
+ sig_t prevint;
+
+ /*
+ * Set up a reasonable environment.
+ * Figure out whether we are being run interactively,
+ * start the SIGCHLD catcher, and so forth.
+ */
+ (void)signal(SIGCHLD, sigchild);
+ if (isatty(0))
+ assign("interactive", "");
+ image = -1;
+
+ /* Define defaults for internal variables, based on Unix 2003 standard */
+ /* noallnet allnet off */
+ /* noappend append off */
+ assign("asksub",""); /* asksub on */
+ /* noaskbcc askbcc off */
+ /* noaskcc askcc off */
+ /* noautoprint autoprint off */
+ /* nobang bang off */
+ /* nocmd cmd off */
+ /* nocrt crt off */
+ /* nodebug debug off */
+ /* nodot dot off */
+ /* noflipr flipr off */
+ /* nofolder folder off */
+ assign("header", ""); /* headers on */
+ /* nohold hold off */
+ /* noignore ignore off */
+ /* noignoreeof ignoreeof off */
+ /* nokeep keep off */
+ /* nokeepsave keepsave off */
+ /* nometoo metoo off */
+ /* noonehop onehop off */
+ /* nooutfolder outfolder off */
+ /* nopage page off */
+ assign("prompt", "? ");
+ /* noquiet quiet off */
+ /* norecord record off */
+ assign("save", ""); /* save on */
+ /* nosendwait sendwait off */
+ /* noshowto showto off */
+ /* nosign sign off */
+ /* noSign Sign off */
+
+ /*
+ * Now, determine how we are being used.
+ * We successively pick off - flags.
+ * If there is anything left, it is the base of the list
+ * of users to mail to. Argp will be set to point to the
+ * first of these users.
+ */
+ ef = NULL;
+ to = NULL;
+ cc = NULL;
+ bcc = NULL;
+ smopts = NULL;
+ subject = NULL;
+ while ((i = getopt(argc, argv, "FEHINT:b:c:edfins:u:v")) != -1) {
+ switch (i) {
+ case 'T':
+ /*
+ * Next argument is temp file to write which
+ * articles have been read/deleted for netnews.
+ */
+ Tflag = optarg;
+ if ((i = open(Tflag, O_CREAT | O_TRUNC | O_WRONLY,
+ 0600)) < 0)
+ err(1, "%s", Tflag);
+ (void)close(i);
+ break;
+ case 'u':
+ /*
+ * Next argument is person to pretend to be.
+ */
+ myname = optarg;
+ unsetenv("MAIL");
+ break;
+ case 'i':
+ /*
+ * User wants to ignore interrupts.
+ * Set the variable "ignore"
+ */
+ assign("ignore", "");
+ break;
+ case 'd':
+ debug = 1; /* 1 -> set from command line; disables env var [no]debug */
+ break;
+ case 'e':
+ /*
+ * User wants to check mail and exit.
+ */
+ assign("checkmode", "");
+ break;
+ case 'H':
+ /*
+ * User wants a header summary only.
+ */
+ assign("headersummary", "");
+ break;
+ case 'F':
+ /*
+ * User wants to record messages to files
+ * named after first recipient username.
+ */
+ assign("recordrecip", "");
+ break;
+ case 's':
+ /*
+ * Give a subject field for sending from
+ * non terminal
+ */
+ subject = optarg;
+ break;
+ case 'f':
+ /*
+ * User is specifying file to "edit" with Mail,
+ * as opposed to reading system mailbox.
+ * If no argument is given after -f, we read his
+ * mbox file.
+ *
+ * getopt() can't handle optional arguments, so here
+ * is an ugly hack to get around it.
+ */
+ if ((argv[optind] != NULL) && (argv[optind][0] != '-'))
+ ef = argv[optind++];
+ else
+ ef = "&";
+ break;
+ case 'n':
+ /*
+ * User doesn't want to source /usr/lib/Mail.rc
+ */
+ nosrc++;
+ break;
+ case 'N':
+ /*
+ * Avoid initial header printing.
+ */
+ assign("quiet", "");
+ break;
+ case 'v':
+ /*
+ * Send mailer verbose flag
+ */
+ assign("verbose", "");
+ break;
+ case 'I':
+ /*
+ * We're interactive
+ */
+ assign("interactive", "");
+ break;
+ case 'c':
+ /*
+ * Get Carbon Copy Recipient list
+ */
+ cc = cat(cc, nalloc(optarg, GCC));
+ break;
+ case 'b':
+ /*
+ * Get Blind Carbon Copy Recipient list
+ */
+ bcc = cat(bcc, nalloc(optarg, GBCC));
+ break;
+ case 'E':
+ /*
+ * Don't send empty files.
+ */
+ assign("dontsendempty", "");
+ break;
+ case '?':
+ fprintf(stderr, "\
+Usage: %s [-EiInv] [-s subject] [-c cc-addr] [-b bcc-addr] [-F] to-addr ...\n\
+ %*s [- sendmail-options ...]\n\
+ %s [-EHiInNv] [-F] -f [name]\n\
+ %s [-EHiInNv] [-F] [-u user]\n\
+ %s -e [-f name]\n\
+ %s -H\n",__progname, (int)strlen(__progname), "",
+ __progname, __progname, __progname, __progname);
+ exit(1);
+ }
+ }
+ for (i = optind; (argv[i] != NULL) && (*argv[i] != '-'); i++)
+ to = cat(to, nalloc(argv[i], GTO));
+ for (; argv[i] != NULL; i++)
+ smopts = cat(smopts, nalloc(argv[i], 0));
+ /*
+ * Check for inconsistent arguments.
+ */
+ if (to == NULL && (subject != NULL || cc != NULL || bcc != NULL))
+ errx(1, "You must specify direct recipients with -s, -c, or -b.");
+ if (ef != NULL && to != NULL)
+ errx(1, "Cannot give -f and people to send to.");
+ tinit();
+ setscreensize();
+ input = stdin;
+ rcvmode = !to;
+ spreserve();
+ if (!nosrc) {
+ char *s, *path_rc;
+
+ if ((path_rc = malloc(sizeof(_PATH_MASTER_RC))) == NULL)
+ err(1, "malloc(path_rc) failed");
+
+ strcpy(path_rc, _PATH_MASTER_RC);
+ while ((s = strsep(&path_rc, ":")) != NULL)
+ if (*s != '\0')
+ load(s);
+ }
+ /*
+ * Expand returns a savestr, but load only uses the file name
+ * for fopen, so it's safe to do this.
+ */
+ if ((rc = getenv("MAILRC")) == NULL)
+ rc = "~/.mailrc";
+ load(expand(rc));
+
+ replyto = value("REPLYTO");
+ if (!rcvmode) {
+ mail(to, cc, bcc, smopts, subject, replyto);
+ /*
+ * why wait?
+ */
+ exit(senderr);
+ }
+
+ if(value("checkmode") != NULL) {
+ if (ef == NULL)
+ ef = "%";
+ if (setfile(ef) <= 0)
+ /* Either an error has occured, or no mail */
+ exit(1);
+ else
+ exit(0);
+ /* NOTREACHED */
+ }
+
+ /*
+ * Ok, we are reading mail.
+ * Decide whether we are editing a mailbox or reading
+ * the system mailbox, and open up the right stuff.
+ */
+ if (ef == NULL)
+ ef = "%";
+ if (setfile(ef) < 0)
+ exit(1); /* error already reported */
+ if (setjmp(hdrjmp) == 0) {
+ if ((prevint = signal(SIGINT, SIG_IGN)) != SIG_IGN)
+ (void)signal(SIGINT, hdrstop);
+ if (value("quiet") == NULL) {
+ printf("Mail version %s. Type ? for help.\n",
+ version);
+ announce();
+ }
+ (void)fflush(stdout);
+ (void)signal(SIGINT, prevint);
+ }
+
+ /* If we were in header summary mode, it's time to exit. */
+ if (value("headersummary") != NULL)
+ exit(0);
+
+ commands();
+ (void)signal(SIGHUP, SIG_IGN);
+ (void)signal(SIGINT, SIG_IGN);
+ (void)signal(SIGQUIT, SIG_IGN);
+ quit();
+ exit(0);
+}
+
+/*
+ * Interrupt printing of the headers.
+ */
+/*ARGSUSED*/
+void
+hdrstop(signo)
+ int signo;
+{
+
+ (void)fflush(stdout);
+ fprintf(stderr, "\nInterrupt\n");
+ longjmp(hdrjmp, 1);
+}
+
+/*
+ * Compute what the screen size for printing headers should be.
+ * We use the following algorithm for the height:
+ * If baud rate < 1200, use 9
+ * If baud rate = 1200, use 14
+ * If baud rate > 1200, use 24 or ws_row
+ * Width is either 80 or ws_col;
+ */
+void
+setscreensize()
+{
+ struct termios tbuf;
+ struct winsize ws;
+ speed_t speed;
+
+ if (ioctl(1, TIOCGWINSZ, (char *)&ws) < 0)
+ ws.ws_col = ws.ws_row = 0;
+ if (tcgetattr(1, &tbuf) < 0)
+ speed = B9600;
+ else
+ speed = cfgetospeed(&tbuf);
+ if (speed < B1200)
+ screenheight = 9;
+ else if (speed == B1200)
+ screenheight = 14;
+ else if (ws.ws_row != 0)
+ screenheight = ws.ws_row;
+ else
+ screenheight = 24;
+ if ((realscreenheight = ws.ws_row) == 0)
+ realscreenheight = 24;
+ if ((screenwidth = ws.ws_col) == 0)
+ screenwidth = 80;
+}
diff --git a/mail_cmds/mail/misc/mail.help b/mail_cmds/mail/misc/mail.help
new file mode 100644
index 0000000..f5c5dd2
--- /dev/null
+++ b/mail_cmds/mail/misc/mail.help
@@ -0,0 +1,23 @@
+ Mail Commands
+t <message list> type messages
+n goto and type next message
+e <message list> edit messages
+f <message list> give head lines of messages
+d <message list> delete messages
+s <message list> file append messages to file
+u <message list> undelete messages
+R <message list> reply to message senders
+r <message list> reply to message senders and all recipients
+pre <message list> make messages go back to /var/mail
+m <user list> mail to specific users
+q quit, saving unresolved messages in mbox
+x quit, do not remove system mailbox
+h print out active message headers
+! shell escape
+cd [directory] chdir to directory or home if none given
+
+A <message list> consists of integers, ranges of same, or user names separated
+by spaces. If omitted, Mail uses the last message typed.
+
+A <user list> consists of user names or aliases separated by spaces.
+Aliases are defined in .mailrc in your home directory.
diff --git a/mail_cmds/mail/misc/mail.rc b/mail_cmds/mail/misc/mail.rc
new file mode 100644
index 0000000..2293b3c
--- /dev/null
+++ b/mail_cmds/mail/misc/mail.rc
@@ -0,0 +1,2 @@
+set append dot save ask crt
+ignore Received Message-Id Resent-Message-Id Status Mail-From Return-Path Via
diff --git a/mail_cmds/mail/misc/mail.tildehelp b/mail_cmds/mail/misc/mail.tildehelp
new file mode 100644
index 0000000..47201d3
--- /dev/null
+++ b/mail_cmds/mail/misc/mail.tildehelp
@@ -0,0 +1,36 @@
+-----------------------------------------------------------
+The following ~ escapes are defined:
+~? Print this message
+~~ Quote a single tilde
+~. Simulate end-of-file on input
+~A Equivalent to: ~i Sign
+~a Equivalent to: ~i sign
+~b users Add users to Bcc list
+~c users Add users to Cc list
+~C Dump core
+~d Read in dead.letter
+~e Edit the message buffer
+~f messages Read in messages
+~F messages Same as ~f, but keep all header lines
+~h Prompt for Subject and To, Cc, and Bcc lists
+~i name Insert the value of the named variable
+~m messages Read in messages, right shifted by a tab
+~M messages Same as ~m, but keep all header lines
+~p Print the message buffer
+~q Quit, save partial message in dead.letter
+~r file Read a file into the message buffer
+~r !command Insert the output of the command
+~< file Same as ~r
+~< !command Same as ~r
+~R address Set Reply-to to address
+~s subject Set Subject to subject
+~t users Add users to the To list
+~v Invoke display editor on message
+~w file Write message onto file
+~x Quit, do not save to dead.letter
+~! command Invoke the shell
+~| command Pipe the message through the command
+~^ command Same as ~|
+~_ mail-cmd Perform the command-level request
+~: mail-cmd Same as ~_
+-----------------------------------------------------------
diff --git a/mail_cmds/mail/names.c b/mail_cmds/mail/names.c
new file mode 100644
index 0000000..19aa411
--- /dev/null
+++ b/mail_cmds/mail/names.c
@@ -0,0 +1,793 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)names.c 8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/names.c,v 1.9 2004/02/29 20:44:44 mikeh Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+/*
+ * Mail -- a mail program
+ *
+ * Handle name lists.
+ */
+
+#include "rcv.h"
+#include <fcntl.h>
+#include "extern.h"
+
+/*
+ * Allocate a single element of a name list,
+ * initialize its name field to the passed
+ * name and return it.
+ */
+struct name *
+nalloc(str, ntype)
+ char str[];
+ int ntype;
+{
+ struct name *np;
+
+ np = (struct name *)salloc(sizeof(*np));
+ np->n_flink = NULL;
+ np->n_blink = NULL;
+ np->n_type = ntype;
+ np->n_name = savestr(str);
+ return (np);
+}
+
+/*
+ * Find the tail of a list and return it.
+ */
+struct name *
+tailof(name)
+ struct name *name;
+{
+ struct name *np;
+
+ np = name;
+ if (np == NULL)
+ return (NULL);
+ while (np->n_flink != NULL)
+ np = np->n_flink;
+ return (np);
+}
+
+/*
+ * Extract a list of names from a line,
+ * and make a list of names from it.
+ * Return the list or NULL if none found.
+ */
+struct name *
+extract(line, ntype)
+ char line[];
+ int ntype;
+{
+ char *cp, *nbuf;
+ struct name *top, *np, *t;
+
+ if (line == NULL || *line == '\0')
+ return (NULL);
+ if ((nbuf = malloc(strlen(line) + 1)) == NULL)
+ err(1, "Out of memory");
+ top = NULL;
+ np = NULL;
+ cp = line;
+ while ((cp = yankword(cp, nbuf)) != NULL) {
+ t = nalloc(nbuf, ntype);
+ if (top == NULL)
+ top = t;
+ else
+ np->n_flink = t;
+ t->n_blink = np;
+ np = t;
+ }
+ (void)free(nbuf);
+ return (top);
+}
+
+/*
+ * Turn a list of names into a string of the same names.
+ */
+char *
+detract(np, ntype)
+ struct name *np;
+ int ntype;
+{
+ int s, comma;
+ char *cp, *top;
+ struct name *p;
+
+ comma = ntype & GCOMMA;
+ if (np == NULL)
+ return (NULL);
+ ntype &= ~GCOMMA;
+ s = 0;
+ if (debug && comma)
+ fprintf(stderr, "detract asked to insert commas\n");
+ for (p = np; p != NULL; p = p->n_flink) {
+ if (ntype && (p->n_type & GMASK) != ntype)
+ continue;
+ s += strlen(p->n_name) + 1;
+ if (comma)
+ s++;
+ }
+ if (s == 0)
+ return (NULL);
+ s += 2;
+ top = salloc(s);
+ cp = top;
+ for (p = np; p != NULL; p = p->n_flink) {
+ if (ntype && (p->n_type & GMASK) != ntype)
+ continue;
+ cp += strlcpy(cp, p->n_name, strlen(p->n_name) + 1);
+ if (comma && p->n_flink != NULL)
+ *cp++ = ',';
+ *cp++ = ' ';
+ }
+ *--cp = '\0';
+ if (comma && *--cp == ',')
+ *cp = '\0';
+ return (top);
+}
+
+/*
+ * Grab a single word (liberal word)
+ * Throw away things between ()'s, and take anything between <>.
+ */
+char *
+yankword(ap, wbuf)
+ char *ap, wbuf[];
+{
+ char *cp, *cp2;
+
+ cp = ap;
+ for (;;) {
+ if (*cp == '\0')
+ return (NULL);
+ if (*cp == '(') {
+ int nesting = 0;
+
+ while (*cp != '\0') {
+ switch (*cp++) {
+ case '(':
+ nesting++;
+ break;
+ case ')':
+ --nesting;
+ break;
+ }
+ if (nesting <= 0)
+ break;
+ }
+ } else if (*cp == ' ' || *cp == '\t' || *cp == ',')
+ cp++;
+ else
+ break;
+ }
+ if (*cp == '<')
+ for (cp2 = wbuf; *cp && (*cp2++ = *cp++) != '>';)
+ ;
+ else
+ for (cp2 = wbuf; *cp != '\0' && strchr(" \t,(", *cp) == NULL;
+ *cp2++ = *cp++)
+ ;
+ *cp2 = '\0';
+ return (cp);
+}
+
+/*
+ * Grab a single login name (liberal word)
+ * Throw away things between ()'s, take anything between <>,
+ * and look for words before metacharacters %, @, !.
+ */
+char *
+yanklogin(ap, wbuf)
+ char *ap, wbuf[];
+{
+ char *cp, *cp2, *cp_temp;
+ int n;
+
+ cp = ap;
+ for (;;) {
+ if (*cp == '\0')
+ return (NULL);
+ if (*cp == '(') {
+ int nesting = 0;
+
+ while (*cp != '\0') {
+ switch (*cp++) {
+ case '(':
+ nesting++;
+ break;
+ case ')':
+ --nesting;
+ break;
+ }
+ if (nesting <= 0)
+ break;
+ }
+ } else if (*cp == ' ' || *cp == '\t' || *cp == ',')
+ cp++;
+ else
+ break;
+ }
+
+ /*
+ * Now, let's go forward till we meet the needed character,
+ * and step one word back.
+ */
+
+ /* First, remember current point. */
+ cp_temp = cp;
+ n = 0;
+
+ /*
+ * Note that we look ahead in a cycle. This is safe, since
+ * non-end of string is checked first.
+ */
+ while(*cp != '\0' && strchr("@%!", *(cp + 1)) == NULL)
+ cp++;
+
+ /*
+ * Now, start stepping back to the first non-word character,
+ * while counting the number of symbols in a word.
+ */
+ while(cp != cp_temp && strchr(" \t,<>", *(cp - 1)) == NULL) {
+ n++;
+ cp--;
+ }
+
+ /* Finally, grab the word forward. */
+ cp2 = wbuf;
+ while(n >= 0) {
+ *cp2++=*cp++;
+ n--;
+ }
+
+ *cp2 = '\0';
+ return (cp);
+}
+
+/*
+ * For each recipient in the passed name list with a /
+ * in the name, append the message to the end of the named file
+ * and remove him from the recipient list.
+ *
+ * Recipients whose name begins with | are piped through the given
+ * program and removed.
+ */
+struct name *
+outof(names, fo, hp)
+ struct name *names;
+ FILE *fo;
+ struct header *hp;
+{
+ int c, ispipe;
+ struct name *np, *top;
+ time_t now;
+ char *date, *fname;
+ FILE *fout, *fin;
+
+ top = names;
+ np = names;
+ (void)time(&now);
+ date = ctime(&now);
+ while (np != NULL) {
+ if (!isfileaddr(np->n_name) && np->n_name[0] != '|') {
+ np = np->n_flink;
+ continue;
+ }
+ ispipe = np->n_name[0] == '|';
+ if (ispipe)
+ fname = np->n_name+1;
+ else
+ fname = expand(np->n_name);
+
+ /*
+ * See if we have copied the complete message out yet.
+ * If not, do so.
+ */
+
+ if (image < 0) {
+ int fd;
+ char tempname[PATHSIZE];
+
+ (void)snprintf(tempname, sizeof(tempname),
+ "%s/mail.ReXXXXXXXXXX", tmpdir);
+ if ((fd = mkstemp(tempname)) == -1 ||
+ (fout = Fdopen(fd, "a")) == NULL) {
+ warn("%s", tempname);
+ senderr++;
+ goto cant;
+ }
+ image = open(tempname, O_RDWR);
+ (void)rm(tempname);
+ if (image < 0) {
+ warn("%s", tempname);
+ senderr++;
+ (void)Fclose(fout);
+ goto cant;
+ }
+ (void)fcntl(image, F_SETFD, 1);
+ fprintf(fout, "From %s %s", myname, date);
+ puthead(hp, fout,
+ GTO|GSUBJECT|GCC|GREPLYTO|GINREPLYTO|GNL);
+ while ((c = getc(fo)) != EOF)
+ (void)putc(c, fout);
+ rewind(fo);
+ fprintf(fout, "\n");
+ (void)fflush(fout);
+ if (ferror(fout)) {
+ warn("%s", tempname);
+ senderr++;
+ (void)Fclose(fout);
+ goto cant;
+ }
+ (void)Fclose(fout);
+ }
+
+ /*
+ * Now either copy "image" to the desired file
+ * or give it as the standard input to the desired
+ * program as appropriate.
+ */
+
+ if (ispipe) {
+ int pid;
+ char *sh;
+ sigset_t nset;
+
+ /*
+ * XXX
+ * We can't really reuse the same image file,
+ * because multiple piped recipients will
+ * share the same lseek location and trample
+ * on one another.
+ */
+ if ((sh = value("SHELL")) == NULL)
+ sh = _PATH_BSHELL;
+ (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;
+ }
+ free_child(pid);
+ } else {
+ int f;
+ if ((fout = Fopen(fname, "a")) == NULL) {
+ warn("%s", fname);
+ senderr++;
+ goto cant;
+ }
+ if ((f = dup(image)) < 0) {
+ warn("dup");
+ fin = NULL;
+ } else
+ fin = Fdopen(f, "r");
+ if (fin == NULL) {
+ fprintf(stderr, "Can't reopen image\n");
+ (void)Fclose(fout);
+ senderr++;
+ goto cant;
+ }
+ rewind(fin);
+ while ((c = getc(fin)) != EOF)
+ (void)putc(c, fout);
+ if (ferror(fout)) {
+ warnx("%s", fname);
+ senderr++;
+ (void)Fclose(fout);
+ (void)Fclose(fin);
+ goto cant;
+ }
+ (void)Fclose(fout);
+ (void)Fclose(fin);
+ }
+cant:
+ /*
+ * In days of old we removed the entry from the
+ * the list; now for sake of header expansion
+ * we leave it in and mark it as deleted.
+ */
+ np->n_type |= GDEL;
+ np = np->n_flink;
+ }
+ if (image >= 0) {
+ (void)close(image);
+ image = -1;
+ }
+ return (top);
+}
+
+/*
+ * Determine if the passed address is a local "send to file" address.
+ * If any of the network metacharacters precedes any slashes, it can't
+ * be a filename. We cheat with .'s to allow path names like ./...
+ */
+int
+isfileaddr(name)
+ char *name;
+{
+ char *cp;
+
+ if (*name == '+')
+ return (1);
+ for (cp = name; *cp != '\0'; cp++) {
+ if (*cp == '!' || *cp == '%' || *cp == '@')
+ return (0);
+ if (*cp == '/')
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Map all of the aliased users in the invoker's mailrc
+ * file and insert them into the list.
+ * Changed after all these months of service to recursively
+ * expand names (2/14/80).
+ */
+
+struct name *
+usermap(names)
+ struct name *names;
+{
+ struct name *new, *np, *cp;
+ struct grouphead *gh;
+ int metoo;
+
+ new = NULL;
+ np = names;
+ metoo = (value("metoo") != NULL);
+ while (np != NULL) {
+ if (np->n_name[0] == '\\') {
+ cp = np->n_flink;
+ new = put(new, np);
+ np = cp;
+ continue;
+ }
+ gh = findgroup(np->n_name);
+ cp = np->n_flink;
+ if (gh != NULL)
+ new = gexpand(new, gh, metoo, np->n_type);
+ else
+ new = put(new, np);
+ np = cp;
+ }
+ return (new);
+}
+
+/*
+ * Recursively expand a group name. We limit the expansion to some
+ * fixed level to keep things from going haywire.
+ * Direct recursion is not expanded for convenience.
+ */
+
+struct name *
+gexpand(nlist, gh, metoo, ntype)
+ struct name *nlist;
+ struct grouphead *gh;
+ int metoo, ntype;
+{
+ struct group *gp;
+ struct grouphead *ngh;
+ struct name *np;
+ static int depth;
+ char *cp;
+
+ if (depth > MAXEXP) {
+ printf("Expanding alias to depth larger than %d\n", MAXEXP);
+ return (nlist);
+ }
+ depth++;
+ for (gp = gh->g_list; gp != NULL; gp = gp->ge_link) {
+ cp = gp->ge_name;
+ if (*cp == '\\')
+ goto quote;
+ if (strcmp(cp, gh->g_name) == 0)
+ goto quote;
+ if ((ngh = findgroup(cp)) != NULL) {
+ nlist = gexpand(nlist, ngh, metoo, ntype);
+ continue;
+ }
+quote:
+ np = nalloc(cp, ntype);
+ /*
+ * At this point should allow to expand
+ * to self if only person in group
+ */
+ if (gp == gh->g_list && gp->ge_link == NULL)
+ goto skip;
+ if (!metoo && strcmp(cp, myname) == 0)
+ np->n_type |= GDEL;
+skip:
+ nlist = put(nlist, np);
+ }
+ depth--;
+ return (nlist);
+}
+
+/*
+ * Concatenate the two passed name lists, return the result.
+ */
+struct name *
+cat(n1, n2)
+ struct name *n1, *n2;
+{
+ struct name *tail;
+
+ if (n1 == NULL)
+ return (n2);
+ if (n2 == NULL)
+ return (n1);
+ tail = tailof(n1);
+ tail->n_flink = n2;
+ n2->n_blink = tail;
+ return (n1);
+}
+
+/*
+ * Unpack the name list onto a vector of strings.
+ * Return an error if the name list won't fit.
+ */
+char **
+unpack(np)
+ struct name *np;
+{
+ char **ap, **top;
+ struct name *n;
+ int t, extra, metoo, verbose;
+
+ n = np;
+ if ((t = count(n)) == 0)
+ errx(1, "No names to unpack");
+ /*
+ * Compute the number of extra arguments we will need.
+ * We need at least two extra -- one for "mail" and one for
+ * the terminating 0 pointer. Additional spots may be needed
+ * to pass along -f to the host mailer.
+ */
+ extra = 2;
+ extra++;
+ metoo = value("metoo") != NULL;
+ if (metoo)
+ extra++;
+ verbose = value("verbose") != NULL;
+ if (verbose)
+ extra++;
+ top = (char **)salloc((t + extra) * sizeof(*top));
+ ap = top;
+ *ap++ = "send-mail";
+ *ap++ = "-i";
+ if (metoo)
+ *ap++ = "-m";
+ if (verbose)
+ *ap++ = "-v";
+ for (; n != NULL; n = n->n_flink)
+ if ((n->n_type & GDEL) == 0)
+ *ap++ = n->n_name;
+ *ap = NULL;
+ return (top);
+}
+
+/*
+ * Remove all of the duplicates from the passed name list by
+ * insertion sorting them, then checking for dups.
+ * Return the head of the new list.
+ */
+struct name *
+elide(names)
+ struct name *names;
+{
+ struct name *np, *t, *new;
+ struct name *x;
+
+ if (names == NULL)
+ return (NULL);
+ new = names;
+ np = names;
+ np = np->n_flink;
+ if (np != NULL)
+ np->n_blink = NULL;
+ new->n_flink = NULL;
+ while (np != NULL) {
+ t = new;
+ while (strcasecmp(t->n_name, np->n_name) < 0) {
+ if (t->n_flink == NULL)
+ break;
+ t = t->n_flink;
+ }
+
+ /*
+ * If we ran out of t's, put the new entry after
+ * the current value of t.
+ */
+
+ if (strcasecmp(t->n_name, np->n_name) < 0) {
+ t->n_flink = np;
+ np->n_blink = t;
+ t = np;
+ np = np->n_flink;
+ t->n_flink = NULL;
+ continue;
+ }
+
+ /*
+ * Otherwise, put the new entry in front of the
+ * current t. If at the front of the list,
+ * the new guy becomes the new head of the list.
+ */
+
+ if (t == new) {
+ t = np;
+ np = np->n_flink;
+ t->n_flink = new;
+ new->n_blink = t;
+ t->n_blink = NULL;
+ new = t;
+ continue;
+ }
+
+ /*
+ * The normal case -- we are inserting into the
+ * middle of the list.
+ */
+
+ x = np;
+ np = np->n_flink;
+ x->n_flink = t;
+ x->n_blink = t->n_blink;
+ t->n_blink->n_flink = x;
+ t->n_blink = x;
+ }
+
+ /*
+ * Now the list headed up by new is sorted.
+ * Go through it and remove duplicates.
+ */
+
+ np = new;
+ while (np != NULL) {
+ t = np;
+ while (t->n_flink != NULL &&
+ strcasecmp(np->n_name, t->n_flink->n_name) == 0)
+ t = t->n_flink;
+ if (t == np || t == NULL) {
+ np = np->n_flink;
+ continue;
+ }
+
+ /*
+ * Now t points to the last entry with the same name
+ * as np. Make np point beyond t.
+ */
+
+ np->n_flink = t->n_flink;
+ if (t->n_flink != NULL)
+ t->n_flink->n_blink = np;
+ np = np->n_flink;
+ }
+ return (new);
+}
+
+/*
+ * Put another node onto a list of names and return
+ * the list.
+ */
+struct name *
+put(list, node)
+ struct name *list, *node;
+{
+ node->n_flink = list;
+ node->n_blink = NULL;
+ if (list != NULL)
+ list->n_blink = node;
+ return (node);
+}
+
+/*
+ * Determine the number of undeleted elements in
+ * a name list and return it.
+ */
+int
+count(np)
+ struct name *np;
+{
+ int c;
+
+ for (c = 0; np != NULL; np = np->n_flink)
+ if ((np->n_type & GDEL) == 0)
+ c++;
+ return (c);
+}
+
+/*
+ * Delete the given name from a namelist.
+ */
+struct name *
+delname(np, name)
+ struct name *np;
+ char name[];
+{
+ struct name *p;
+
+ for (p = np; p != NULL; p = p->n_flink)
+ if (strcasecmp(p->n_name, name) == 0) {
+ if (p->n_blink == NULL) {
+ if (p->n_flink != NULL)
+ p->n_flink->n_blink = NULL;
+ np = p->n_flink;
+ continue;
+ }
+ if (p->n_flink == NULL) {
+ if (p->n_blink != NULL)
+ p->n_blink->n_flink = NULL;
+ continue;
+ }
+ p->n_blink->n_flink = p->n_flink;
+ p->n_flink->n_blink = p->n_blink;
+ }
+ return (np);
+}
+
+/*
+ * Pretty print a name list
+ * Uncomment it if you need it.
+ */
+
+/*
+void
+prettyprint(name)
+ struct name *name;
+{
+ struct name *np;
+
+ np = name;
+ while (np != NULL) {
+ fprintf(stderr, "%s(%d) ", np->n_name, np->n_type);
+ np = np->n_flink;
+ }
+ fprintf(stderr, "\n");
+}
+*/
diff --git a/mail_cmds/mail/pathnames.h b/mail_cmds/mail/pathnames.h
new file mode 100644
index 0000000..ea67572
--- /dev/null
+++ b/mail_cmds/mail/pathnames.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pathnames.h 8.1 (Berkeley) 6/6/93
+ *
+ * $FreeBSD: src/usr.bin/mail/pathnames.h,v 1.4 2001/05/27 20:26:22 mikeh Exp $
+ */
+
+#ifndef PATHNAMES_H
+#define PATHNAMES_H
+
+#define _PATH_EX "/usr/bin/ex"
+#define _PATH_HELP "/usr/share/misc/mail.help"
+#define _PATH_TILDE "/usr/share/misc/mail.tildehelp"
+#define _PATH_MASTER_RC "/usr/share/misc/mail.rc:/usr/local/etc/mail.rc:/etc/mail.rc"
+#define _PATH_MORE "/usr/bin/more"
+
+#endif /* PATHNAMES_H */
diff --git a/mail_cmds/mail/popen.c b/mail_cmds/mail/popen.c
new file mode 100644
index 0000000..979a76f
--- /dev/null
+++ b/mail_cmds/mail/popen.c
@@ -0,0 +1,402 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)popen.c 8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/popen.c,v 1.7 2002/06/30 05:25:06 obrien Exp $";
+#endif /* not lint */
+#include <sys/cdefs.h>
+
+
+#include "rcv.h"
+#include <sys/wait.h>
+#include <fcntl.h>
+#include "extern.h"
+
+#define READ 0
+#define WRITE 1
+
+struct fp {
+ FILE *fp;
+ int pipe;
+ int pid;
+ struct fp *link;
+};
+static struct fp *fp_head;
+
+struct child {
+ int pid;
+ char done;
+ char free;
+ int status;
+ struct child *link;
+};
+static struct child *child;
+static struct child *findchild(int);
+static void delchild(struct child *);
+static int file_pid(FILE *);
+
+FILE *
+Fopen(path, mode)
+ const char *path, *mode;
+{
+ FILE *fp;
+
+ if ((fp = fopen(path, mode)) != NULL) {
+ register_file(fp, 0, 0);
+ (void)fcntl(fileno(fp), F_SETFD, 1);
+ }
+ return (fp);
+}
+
+FILE *
+Fdopen(fd, mode)
+ int fd;
+ const char *mode;
+{
+ FILE *fp;
+
+ if ((fp = fdopen(fd, mode)) != NULL) {
+ register_file(fp, 0, 0);
+ (void)fcntl(fileno(fp), F_SETFD, 1);
+ }
+ return (fp);
+}
+
+int
+Fclose(fp)
+ FILE *fp;
+{
+ unregister_file(fp);
+ return (fclose(fp));
+}
+
+FILE *
+Popen(cmd, mode)
+ char *cmd;
+ const char *mode;
+{
+ int p[2];
+ int myside, hisside, fd0, fd1;
+ int pid;
+ sigset_t nset;
+ FILE *fp;
+
+ if (pipe(p) < 0)
+ return (NULL);
+ (void)fcntl(p[READ], F_SETFD, 1);
+ (void)fcntl(p[WRITE], F_SETFD, 1);
+ if (*mode == 'r') {
+ myside = p[READ];
+ fd0 = -1;
+ hisside = fd1 = p[WRITE];
+ } else {
+ myside = p[WRITE];
+ hisside = fd0 = p[READ];
+ fd1 = -1;
+ }
+ (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);
+ }
+ (void)close(hisside);
+ if ((fp = fdopen(myside, mode)) != NULL)
+ register_file(fp, 1, pid);
+ return (fp);
+}
+
+int
+Pclose(ptr)
+ FILE *ptr;
+{
+ int i;
+ sigset_t nset, oset;
+
+ i = file_pid(ptr);
+ unregister_file(ptr);
+ (void)fclose(ptr);
+ (void)sigemptyset(&nset);
+ (void)sigaddset(&nset, SIGINT);
+ (void)sigaddset(&nset, SIGHUP);
+ (void)sigprocmask(SIG_BLOCK, &nset, &oset);
+ i = wait_child(i);
+ (void)sigprocmask(SIG_SETMASK, &oset, NULL);
+ return (i);
+}
+
+void
+close_all_files()
+{
+
+ while (fp_head != NULL)
+ if (fp_head->pipe)
+ (void)Pclose(fp_head->fp);
+ else
+ (void)Fclose(fp_head->fp);
+}
+
+void
+register_file(fp, pipe, pid)
+ FILE *fp;
+ int pipe, pid;
+{
+ struct fp *fpp;
+
+ if ((fpp = malloc(sizeof(*fpp))) == NULL)
+ err(1, "Out of memory");
+ fpp->fp = fp;
+ fpp->pipe = pipe;
+ fpp->pid = pid;
+ fpp->link = fp_head;
+ fp_head = fpp;
+}
+
+void
+unregister_file(fp)
+ FILE *fp;
+{
+ struct fp **pp, *p;
+
+ for (pp = &fp_head; (p = *pp) != NULL; pp = &p->link)
+ if (p->fp == fp) {
+ *pp = p->link;
+ (void)free(p);
+ return;
+ }
+ errx(1, "Invalid file pointer");
+ /*NOTREACHED*/
+}
+
+int
+file_pid(fp)
+ FILE *fp;
+{
+ struct fp *p;
+
+ for (p = fp_head; p != NULL; p = p->link)
+ if (p->fp == fp)
+ return (p->pid);
+ errx(1, "Invalid file pointer");
+ /*NOTREACHED*/
+}
+
+/*
+ * Run a command without a shell, with optional arguments and splicing
+ * of stdin and stdout. The command name can be a sequence of words.
+ * Signals must be handled by the caller.
+ * "Mask" contains the signals to ignore in the new process.
+ * SIGINT is enabled unless it's in the mask.
+ */
+/*VARARGS4*/
+int
+run_command(cmd, mask, infd, outfd, a0, a1, a2)
+ char *cmd;
+ sigset_t *mask;
+ int infd, outfd;
+ char *a0, *a1, *a2;
+{
+ int pid;
+
+ if ((pid = start_command(cmd, mask, infd, outfd, a0, a1, a2)) < 0)
+ return (-1);
+ return (wait_command(pid));
+}
+
+/*VARARGS4*/
+int
+start_command(cmd, mask, infd, outfd, a0, a1, a2)
+ char *cmd;
+ sigset_t *mask;
+ int infd, outfd;
+ char *a0, *a1, *a2;
+{
+ int pid;
+
+ if ((pid = fork()) < 0) {
+ warn("fork");
+ return (-1);
+ }
+ if (pid == 0) {
+ char *argv[100];
+ int i = getrawlist(cmd, argv, sizeof(argv) / sizeof(*argv));
+
+ if ((argv[i++] = a0) != NULL &&
+ (argv[i++] = a1) != NULL &&
+ (argv[i++] = a2) != NULL)
+ argv[i] = NULL;
+ prepare_child(mask, infd, outfd);
+ execvp(argv[0], argv);
+ warn("%s", argv[0]);
+ _exit(1);
+ }
+ return (pid);
+}
+
+void
+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
+ * close-on-exec.
+ */
+ if (infd >= 0)
+ dup2(infd, 0);
+ if (outfd >= 0)
+ dup2(outfd, 1);
+ for (i = 1; i < NSIG; i++)
+ if (nset != NULL && sigismember(nset, i))
+ (void)signal(i, SIG_IGN);
+ if (nset == NULL || !sigismember(nset, SIGINT))
+ (void)signal(SIGINT, SIG_DFL);
+ (void)sigemptyset(&eset);
+ (void)sigprocmask(SIG_SETMASK, &eset, NULL);
+}
+
+int
+wait_command(pid)
+ int pid;
+{
+
+ if (wait_child(pid) < 0) {
+ printf("Fatal error in process.\n");
+ return (-1);
+ }
+ return (0);
+}
+
+static struct child *
+findchild(pid)
+ int pid;
+{
+ struct child **cpp;
+
+ for (cpp = &child; *cpp != NULL && (*cpp)->pid != pid;
+ cpp = &(*cpp)->link)
+ ;
+ if (*cpp == NULL) {
+ *cpp = malloc(sizeof(struct child));
+ if (*cpp == NULL)
+ err(1, "Out of memory");
+ (*cpp)->pid = pid;
+ (*cpp)->done = (*cpp)->free = 0;
+ (*cpp)->link = NULL;
+ }
+ return (*cpp);
+}
+
+static void
+delchild(cp)
+ struct child *cp;
+{
+ struct child **cpp;
+
+ for (cpp = &child; *cpp != cp; cpp = &(*cpp)->link)
+ ;
+ *cpp = cp->link;
+ (void)free(cp);
+}
+
+/*ARGSUSED*/
+void
+sigchild(signo)
+ int signo;
+{
+ int pid;
+ int status;
+ struct child *cp;
+
+ while ((pid = waitpid((pid_t)-1, &status, WNOHANG)) > 0) {
+ cp = findchild(pid);
+ if (cp->free)
+ delchild(cp);
+ else {
+ cp->done = 1;
+ cp->status = status;
+ }
+ }
+}
+
+int wait_status;
+
+/*
+ * Wait for a specific child to die.
+ */
+int
+wait_child(pid)
+ int pid;
+{
+ 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)
+ (void)sigsuspend(&oset);
+ wait_status = cp->status;
+ delchild(cp);
+ (void)sigprocmask(SIG_SETMASK, &oset, NULL);
+ return ((WIFEXITED(wait_status) && WEXITSTATUS(wait_status)) ? -1 : 0);
+}
+
+/*
+ * Mark a child as don't care.
+ */
+void
+free_child(pid)
+ int pid;
+{
+ 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)sigprocmask(SIG_SETMASK, &oset, NULL);
+}
diff --git a/mail_cmds/mail/quit.c b/mail_cmds/mail/quit.c
new file mode 100644
index 0000000..69d7db1
--- /dev/null
+++ b/mail_cmds/mail/quit.c
@@ -0,0 +1,505 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)quit.c 8.2 (Berkeley) 4/28/95";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/quit.c,v 1.7 2002/06/30 05:25:06 obrien Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+#include "rcv.h"
+#include <fcntl.h>
+#include "extern.h"
+
+/*
+ * Rcv -- receive mail rationally.
+ *
+ * Termination processing.
+ */
+
+/*
+ * The "quit" command.
+ */
+int
+quitcmd()
+{
+ /*
+ * If we are sourcing, then return 1 so execute() can handle it.
+ * Otherwise, return -1 to abort command loop.
+ */
+ if (sourcing)
+ return (1);
+ return (-1);
+}
+
+/*
+ * Save all of the undetermined messages at the top of "mbox"
+ * Save all untouched messages back in the system mailbox.
+ * Remove the system mailbox, if none saved there.
+ */
+void
+quit()
+{
+ int mcount, p, modify, autohold, anystat, holdbit, nohold;
+ FILE *ibuf = NULL, *obuf = NULL, *fbuf, *rbuf, *readstat = NULL, *abuf;
+ struct message *mp;
+ int c, fd;
+ struct stat minfo;
+ char *mbox, tempname[PATHSIZE];
+
+ /*
+ * If we are read only, we can't do anything,
+ * so just return quickly.
+ */
+ if (readonly)
+ return;
+ /*
+ * If editing (not reading system mail box), then do the work
+ * in edstop()
+ */
+ if (edit) {
+ edstop();
+ return;
+ }
+
+ /*
+ * See if there any messages to save in mbox. If no, we
+ * can save copying mbox to /tmp and back.
+ *
+ * Check also to see if any files need to be preserved.
+ * Delete all untouched messages to keep them out of mbox.
+ * If all the messages are to be preserved, just exit with
+ * a message.
+ */
+
+ fbuf = Fopen(mailname, "r");
+ if (fbuf == NULL)
+ goto newmail;
+ (void)flock(fileno(fbuf), LOCK_EX);
+ rbuf = NULL;
+ if (fstat(fileno(fbuf), &minfo) >= 0 && minfo.st_size > mailsize) {
+ printf("New mail has arrived.\n");
+ (void)snprintf(tempname, sizeof(tempname),
+ "%s/mail.RqXXXXXXXXXX", tmpdir);
+ if ((fd = mkstemp(tempname)) == -1 ||
+ (rbuf = Fdopen(fd, "w")) == NULL)
+ goto newmail;
+#ifdef APPEND
+ (void)fseeko(fbuf, mailsize, SEEK_SET);
+ while ((c = getc(fbuf)) != EOF)
+ (void)putc(c, rbuf);
+#else
+ p = minfo.st_size - mailsize;
+ while (p-- > 0) {
+ c = getc(fbuf);
+ if (c == EOF)
+ goto newmail;
+ (void)putc(c, rbuf);
+ }
+#endif
+ (void)Fclose(rbuf);
+ if ((rbuf = Fopen(tempname, "r")) == NULL)
+ goto newmail;
+ (void)rm(tempname);
+ }
+
+ /*
+ * Adjust the message flags in each message.
+ */
+
+ anystat = 0;
+ autohold = value("hold") != NULL;
+ holdbit = autohold ? MPRESERVE : MBOX;
+ nohold = MBOX|MSAVED|MDELETED|MPRESERVE;
+ if (value("keepsave") != NULL)
+ nohold &= ~MSAVED;
+ for (mp = &message[0]; mp < &message[msgCount]; mp++) {
+ if (mp->m_flag & MNEW) {
+ mp->m_flag &= ~MNEW;
+ mp->m_flag |= MSTATUS;
+ }
+ if (mp->m_flag & MSTATUS)
+ anystat++;
+ if ((mp->m_flag & MTOUCH) == 0)
+ mp->m_flag |= MPRESERVE;
+ if ((mp->m_flag & nohold) == 0)
+ mp->m_flag |= holdbit;
+ }
+ modify = 0;
+ if (Tflag != NULL) {
+ if ((readstat = Fopen(Tflag, "w")) == NULL)
+ Tflag = NULL;
+ }
+ for (c = 0, p = 0, mp = &message[0]; mp < &message[msgCount]; mp++) {
+ if (mp->m_flag & MBOX)
+ c++;
+ if (mp->m_flag & MPRESERVE)
+ p++;
+ if (mp->m_flag & MODIFY)
+ modify++;
+ if (Tflag != NULL && (mp->m_flag & (MREAD|MDELETED)) != 0) {
+ char *id;
+
+ if ((id = hfield("article-id", mp)) != NULL)
+ fprintf(readstat, "%s\n", id);
+ }
+ }
+ if (Tflag != NULL)
+ (void)Fclose(readstat);
+ if (p == msgCount && !modify && !anystat) {
+ printf("Held %d message%s in %s\n",
+ p, p == 1 ? "" : "s", mailname);
+ (void)Fclose(fbuf);
+ return;
+ }
+ if (c == 0) {
+ if (p != 0) {
+ writeback(rbuf);
+ (void)Fclose(fbuf);
+ return;
+ }
+ goto cream;
+ }
+
+ /*
+ * Create another temporary file and copy user's mbox file
+ * darin. If there is no mbox, copy nothing.
+ * If he has specified "append" don't copy his mailbox,
+ * just copy saveable entries at the end.
+ */
+
+ mbox = expand("&");
+ mcount = c;
+ if (value("append") == NULL) {
+ (void)snprintf(tempname, sizeof(tempname),
+ "%s/mail.RmXXXXXXXXXX", tmpdir);
+ if ((fd = mkstemp(tempname)) == -1 ||
+ (obuf = Fdopen(fd, "w")) == NULL) {
+ warn("%s", tempname);
+ (void)Fclose(fbuf);
+ return;
+ }
+ if ((ibuf = Fopen(tempname, "r")) == NULL) {
+ warn("%s", tempname);
+ (void)rm(tempname);
+ (void)Fclose(obuf);
+ (void)Fclose(fbuf);
+ return;
+ }
+ (void)rm(tempname);
+ if ((abuf = Fopen(mbox, "r")) != NULL) {
+ while ((c = getc(abuf)) != EOF)
+ (void)putc(c, obuf);
+ (void)Fclose(abuf);
+ }
+ if (ferror(obuf)) {
+ warnx("%s", tempname);
+ (void)Fclose(ibuf);
+ (void)Fclose(obuf);
+ (void)Fclose(fbuf);
+ return;
+ }
+ (void)Fclose(obuf);
+ (void)close(open(mbox, O_CREAT | O_TRUNC | O_WRONLY, 0600));
+ if ((obuf = Fopen(mbox, "r+")) == NULL) {
+ warn("%s", mbox);
+ (void)Fclose(ibuf);
+ (void)Fclose(fbuf);
+ return;
+ }
+ }
+ if (value("append") != NULL) {
+ if ((obuf = Fopen(mbox, "a")) == NULL) {
+ warn("%s", mbox);
+ (void)Fclose(fbuf);
+ return;
+ }
+ (void)fchmod(fileno(obuf), 0600);
+ }
+ for (mp = &message[0]; mp < &message[msgCount]; mp++)
+ if (mp->m_flag & MBOX)
+ if (sendmessage(mp, obuf, saveignore, NULL) < 0) {
+ warnx("%s", mbox);
+ (void)Fclose(ibuf);
+ (void)Fclose(obuf);
+ (void)Fclose(fbuf);
+ return;
+ }
+
+ /*
+ * Copy the user's old mbox contents back
+ * to the end of the stuff we just saved.
+ * If we are appending, this is unnecessary.
+ */
+
+ if (value("append") == NULL) {
+ rewind(ibuf);
+ c = getc(ibuf);
+ while (c != EOF) {
+ (void)putc(c, obuf);
+ if (ferror(obuf))
+ break;
+ c = getc(ibuf);
+ }
+ (void)Fclose(ibuf);
+ }
+ (void)fflush(obuf);
+ trunc(obuf);
+ if (ferror(obuf)) {
+ warn("%s", mbox);
+ (void)Fclose(obuf);
+ (void)Fclose(fbuf);
+ return;
+ }
+ (void)Fclose(obuf);
+ if (mcount == 1)
+ printf("Saved 1 message in mbox\n");
+ else
+ printf("Saved %d messages in mbox\n", mcount);
+
+ /*
+ * Now we are ready to copy back preserved files to
+ * the system mailbox, if any were requested.
+ */
+
+ if (p != 0) {
+ writeback(rbuf);
+ (void)Fclose(fbuf);
+ return;
+ }
+
+ /*
+ * Finally, remove his /var/mail file.
+ * If new mail has arrived, copy it back.
+ */
+
+cream:
+ if (rbuf != NULL) {
+ abuf = Fopen(mailname, "r+");
+ if (abuf == NULL)
+ goto newmail;
+ while ((c = getc(rbuf)) != EOF)
+ (void)putc(c, abuf);
+ (void)Fclose(rbuf);
+ trunc(abuf);
+ (void)Fclose(abuf);
+ alter(mailname);
+ (void)Fclose(fbuf);
+ return;
+ }
+ demail();
+ (void)Fclose(fbuf);
+ return;
+
+newmail:
+ printf("Thou hast new mail.\n");
+ if (fbuf != NULL)
+ (void)Fclose(fbuf);
+}
+
+/*
+ * Preserve all the appropriate messages back in the system
+ * mailbox, and print a nice message indicated how many were
+ * saved. On any error, just return -1. Else return 0.
+ * Incorporate the any new mail that we found.
+ */
+int
+writeback(res)
+ FILE *res;
+{
+ struct message *mp;
+ int p, c;
+ FILE *obuf;
+
+ p = 0;
+ if ((obuf = Fopen(mailname, "r+")) == NULL) {
+ warn("%s", mailname);
+ return (-1);
+ }
+#ifndef APPEND
+ if (res != NULL)
+ while ((c = getc(res)) != EOF)
+ (void)putc(c, obuf);
+#endif
+ for (mp = &message[0]; mp < &message[msgCount]; mp++)
+ if ((mp->m_flag&MPRESERVE)||(mp->m_flag&MTOUCH)==0) {
+ p++;
+ if (sendmessage(mp, obuf, NULL, NULL) < 0) {
+ warnx("%s", mailname);
+ (void)Fclose(obuf);
+ return (-1);
+ }
+ }
+#ifdef APPEND
+ if (res != NULL)
+ while ((c = getc(res)) != EOF)
+ (void)putc(c, obuf);
+#endif
+ (void)fflush(obuf);
+ trunc(obuf);
+ if (ferror(obuf)) {
+ warn("%s", mailname);
+ (void)Fclose(obuf);
+ return (-1);
+ }
+ if (res != NULL)
+ (void)Fclose(res);
+ (void)Fclose(obuf);
+ alter(mailname);
+ if (p == 1)
+ printf("Held 1 message in %s\n", mailname);
+ else
+ printf("Held %d messages in %s\n", p, mailname);
+ return (0);
+}
+
+/*
+ * Terminate an editing session by attempting to write out the user's
+ * file from the temporary. Save any new stuff appended to the file.
+ */
+void
+edstop()
+{
+ int gotcha, c;
+ struct message *mp;
+ FILE *obuf, *ibuf, *readstat = NULL;
+ struct stat statb;
+ char tempname[PATHSIZE];
+
+ if (readonly)
+ return;
+ holdsigs();
+ if (Tflag != NULL) {
+ if ((readstat = Fopen(Tflag, "w")) == NULL)
+ Tflag = NULL;
+ }
+ for (mp = &message[0], gotcha = 0; mp < &message[msgCount]; mp++) {
+ if (mp->m_flag & MNEW) {
+ mp->m_flag &= ~MNEW;
+ mp->m_flag |= MSTATUS;
+ }
+ if (mp->m_flag & (MODIFY|MDELETED|MSTATUS))
+ gotcha++;
+ if (Tflag != NULL && (mp->m_flag & (MREAD|MDELETED)) != 0) {
+ char *id;
+
+ if ((id = hfield("article-id", mp)) != NULL)
+ fprintf(readstat, "%s\n", id);
+ }
+ }
+ if (Tflag != NULL)
+ (void)Fclose(readstat);
+ if (!gotcha || Tflag != NULL)
+ goto done;
+ ibuf = NULL;
+ if (stat(mailname, &statb) >= 0 && statb.st_size > mailsize) {
+ int fd;
+
+ (void)snprintf(tempname, sizeof(tempname),
+ "%s/mbox.XXXXXXXXXX", tmpdir);
+ if ((fd = mkstemp(tempname)) == -1 ||
+ (obuf = Fdopen(fd, "w")) == NULL) {
+ warn("%s", tempname);
+ relsesigs();
+ reset(0);
+ }
+ if ((ibuf = Fopen(mailname, "r")) == NULL) {
+ warn("%s", mailname);
+ (void)Fclose(obuf);
+ (void)rm(tempname);
+ relsesigs();
+ reset(0);
+ }
+ (void)fseeko(ibuf, mailsize, SEEK_SET);
+ while ((c = getc(ibuf)) != EOF)
+ (void)putc(c, obuf);
+ (void)Fclose(ibuf);
+ (void)Fclose(obuf);
+ if ((ibuf = Fopen(tempname, "r")) == NULL) {
+ warn("%s", tempname);
+ (void)rm(tempname);
+ relsesigs();
+ reset(0);
+ }
+ (void)rm(tempname);
+ }
+ printf("\"%s\" ", mailname);
+ (void)fflush(stdout);
+ if ((obuf = Fopen(mailname, "r+")) == NULL) {
+ warn("%s", mailname);
+ relsesigs();
+ reset(0);
+ }
+ trunc(obuf);
+ c = 0;
+ for (mp = &message[0]; mp < &message[msgCount]; mp++) {
+ if ((mp->m_flag & MDELETED) != 0)
+ continue;
+ c++;
+ if (sendmessage(mp, obuf, NULL, NULL) < 0) {
+ warnx("%s", mailname);
+ relsesigs();
+ reset(0);
+ }
+ }
+ gotcha = (c == 0 && ibuf == NULL);
+ if (ibuf != NULL) {
+ while ((c = getc(ibuf)) != EOF)
+ (void)putc(c, obuf);
+ (void)Fclose(ibuf);
+ }
+ (void)fflush(obuf);
+ if (ferror(obuf)) {
+ warn("%s", mailname);
+ relsesigs();
+ reset(0);
+ }
+ (void)Fclose(obuf);
+ if (gotcha) {
+ if (value("keep") == NULL) {
+ (void)rm(mailname);
+ printf("removed\n");
+ } else { /* leave truncated file there */
+ printf("is empty\n");
+ }
+ } else
+ printf("complete\n");
+ (void)fflush(stdout);
+
+done:
+ relsesigs();
+}
diff --git a/mail_cmds/mail/rcv.h b/mail_cmds/mail/rcv.h
new file mode 100644
index 0000000..b8269b8
--- /dev/null
+++ b/mail_cmds/mail/rcv.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)rcv.h 8.1 (Berkeley) 6/6/93
+ *
+ * $FreeBSD: src/usr.bin/mail/rcv.h,v 1.2 2001/03/25 04:57:04 mikeh Exp $
+ */
+
+#ifndef RCV_H
+#define RCV_H
+
+/*
+ * Mail -- a mail program
+ *
+ * This file is included by normal files which want both
+ * globals and declarations.
+ */
+
+#include "def.h"
+#include "glob.h"
+
+#endif /* RCV_H */
+
diff --git a/mail_cmds/mail/send.c b/mail_cmds/mail/send.c
new file mode 100644
index 0000000..466bd65
--- /dev/null
+++ b/mail_cmds/mail/send.c
@@ -0,0 +1,629 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)send.c 8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/send.c,v 1.14 2004/02/29 20:44:44 mikeh Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+#include "rcv.h"
+#include "extern.h"
+
+/*
+ * Mail -- a mail program
+ *
+ * Mail to others.
+ */
+
+/*
+ * Send message described by the passed pointer to the
+ * passed output buffer. Return -1 on error.
+ * Adjust the status: field if need be.
+ * If doign is given, suppress ignored header fields.
+ * prefix is a string to prepend to each output line.
+ */
+int
+sendmessage(mp, obuf, doign, prefix)
+ struct message *mp;
+ FILE *obuf;
+ struct ignoretab *doign;
+ char *prefix;
+{
+ long count;
+ FILE *ibuf;
+ char *cp, *cp2, line[LINESIZE];
+ int ishead, infld, ignoring = 0, dostat, firstline;
+ int c = 0, length, prefixlen = 0;
+
+ /*
+ * Compute the prefix string, without trailing whitespace
+ */
+ if (prefix != NULL) {
+ cp2 = 0;
+ for (cp = prefix; *cp != '\0'; cp++)
+ if (*cp != ' ' && *cp != '\t')
+ cp2 = cp;
+ prefixlen = cp2 == NULL ? 0 : cp2 - prefix + 1;
+ }
+ ibuf = setinput(mp);
+ count = mp->m_size;
+ ishead = 1;
+ dostat = doign == 0 || !isign("status", doign);
+ infld = 0;
+ firstline = 1;
+ /*
+ * Process headers first
+ */
+ while (count > 0 && ishead) {
+ if (fgets(line, sizeof(line), ibuf) == NULL)
+ break;
+ count -= length = strlen(line);
+ if (firstline) {
+ /*
+ * First line is the From line, so no headers
+ * there to worry about
+ */
+ firstline = 0;
+ ignoring = doign == ignoreall;
+ } else if (line[0] == '\n') {
+ /*
+ * If line is blank, we've reached end of
+ * headers, so force out status: field
+ * and note that we are no longer in header
+ * fields
+ */
+ if (dostat) {
+ statusput(mp, obuf, prefix);
+ dostat = 0;
+ }
+ ishead = 0;
+ ignoring = doign == ignoreall;
+ } else if (infld && (line[0] == ' ' || line[0] == '\t')) {
+ /*
+ * If this line is a continuation (via space or tab)
+ * of a previous header field, just echo it
+ * (unless the field should be ignored).
+ * In other words, nothing to do.
+ */
+ } else {
+ /*
+ * Pick up the header field if we have one.
+ */
+ for (cp = line; (c = *cp++) != '\0' && c != ':' &&
+ !isspace((unsigned char)c);)
+ ;
+ cp2 = --cp;
+ while (isspace((unsigned char)*cp++))
+ ;
+ if (cp[-1] != ':') {
+ /*
+ * Not a header line, force out status:
+ * This happens in uucp style mail where
+ * there are no headers at all.
+ */
+ if (dostat) {
+ statusput(mp, obuf, prefix);
+ dostat = 0;
+ }
+ if (doign != ignoreall)
+ /* add blank line */
+ (void)putc('\n', obuf);
+ ishead = 0;
+ ignoring = 0;
+ } else {
+ /*
+ * If it is an ignored field and
+ * we care about such things, skip it.
+ */
+ *cp2 = '\0'; /* temporarily null terminate */
+ if (doign && isign(line, doign))
+ ignoring = 1;
+ else if ((line[0] == 's' || line[0] == 'S') &&
+ strcasecmp(line, "status") == 0) {
+ /*
+ * If the field is "status," go compute
+ * and print the real Status: field
+ */
+ if (dostat) {
+ statusput(mp, obuf, prefix);
+ dostat = 0;
+ }
+ ignoring = 1;
+ } else {
+ ignoring = 0;
+ *cp2 = c; /* restore */
+ }
+ infld = 1;
+ }
+ }
+ if (!ignoring) {
+ /*
+ * Strip trailing whitespace from prefix
+ * if line is blank.
+ */
+ if (prefix != NULL) {
+ if (length > 1)
+ fputs(prefix, obuf);
+ else
+ (void)fwrite(prefix, sizeof(*prefix),
+ prefixlen, obuf);
+ }
+ (void)fwrite(line, sizeof(*line), length, obuf);
+ if (ferror(obuf))
+ return (-1);
+ }
+ }
+ /*
+ * Copy out message body
+ */
+ if (doign == ignoreall)
+ count--; /* skip final blank line */
+ if (prefix != NULL)
+ while (count > 0) {
+ if (fgets(line, sizeof(line), ibuf) == NULL) {
+ c = 0;
+ break;
+ }
+ count -= c = strlen(line);
+ /*
+ * Strip trailing whitespace from prefix
+ * if line is blank.
+ */
+ if (c > 1)
+ fputs(prefix, obuf);
+ else
+ (void)fwrite(prefix, sizeof(*prefix),
+ prefixlen, obuf);
+ (void)fwrite(line, sizeof(*line), c, obuf);
+ if (ferror(obuf))
+ return (-1);
+ }
+ else
+ while (count > 0) {
+ c = count < LINESIZE ? count : LINESIZE;
+ if ((c = fread(line, sizeof(*line), c, ibuf)) <= 0)
+ break;
+ count -= c;
+ if (fwrite(line, sizeof(*line), c, obuf) != c)
+ return (-1);
+ }
+ if (doign == ignoreall && c > 0 && line[c - 1] != '\n')
+ /* no final blank line */
+ if ((c = getc(ibuf)) != EOF && putc(c, obuf) == EOF)
+ return (-1);
+ return (0);
+}
+
+/*
+ * Output a reasonable looking status field.
+ */
+void
+statusput(mp, obuf, prefix)
+ struct message *mp;
+ FILE *obuf;
+ char *prefix;
+{
+ char statout[3];
+ char *cp = statout;
+
+ if (mp->m_flag & MREAD)
+ *cp++ = 'R';
+ if ((mp->m_flag & MNEW) == 0)
+ *cp++ = 'O';
+ *cp = '\0';
+ if (statout[0] != '\0')
+ fprintf(obuf, "%sStatus: %s\n",
+ prefix == NULL ? "" : prefix, statout);
+}
+
+/*
+ * Interface between the argument list and the mail1 routine
+ * which does all the dirty work.
+ */
+int
+mail(to, cc, bcc, smopts, subject, replyto)
+ struct name *to, *cc, *bcc, *smopts;
+ char *subject, *replyto;
+{
+ struct header head;
+
+ head.h_to = to;
+ head.h_subject = subject;
+ head.h_cc = cc;
+ head.h_bcc = bcc;
+ head.h_smopts = smopts;
+ head.h_replyto = replyto;
+ head.h_inreplyto = NULL;
+ mail1(&head, 0);
+ return (0);
+}
+
+
+/*
+ * Send mail to a bunch of user names. The interface is through
+ * the mail routine below.
+ */
+int
+sendmail(str)
+ char *str;
+{
+ struct header head;
+
+ head.h_to = extract(str, GTO);
+ head.h_subject = NULL;
+ head.h_cc = NULL;
+ head.h_bcc = NULL;
+ head.h_smopts = NULL;
+ head.h_replyto = value("REPLYTO");
+ head.h_inreplyto = NULL;
+ mail1(&head, 0);
+ return (0);
+}
+
+/*
+ * Mail a message on standard input to the people indicated
+ * in the passed header. (Internal interface).
+ */
+void
+mail1(hp, printheaders)
+ struct header *hp;
+ int printheaders;
+{
+ char *cp;
+ char *nbuf;
+ int pid;
+ char **namelist;
+ struct name *to, *nsto = NULL;
+ FILE *mtf;
+
+ /*
+ * Collect user's mail from standard input.
+ * Get the result as mtf.
+ */
+ if ((mtf = collect(hp, printheaders)) == NULL)
+ return;
+ if (value("interactive") != NULL) {
+ 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);
+ }
+ }
+ if (fsize(mtf) == 0) {
+ if (value("dontsendempty") != NULL)
+ goto out;
+ if (hp->h_subject == NULL)
+ printf("No message, no subject; hope that's ok\n");
+ else
+ printf("Null message body; hope that's ok\n");
+ }
+ /*
+ * Now, take the user names from the combined
+ * to and cc lists and do all the alias
+ * processing.
+ */
+ senderr = 0;
+ to = usermap(cat(hp->h_bcc, cat(hp->h_to, hp->h_cc)));
+ if (to == NULL) {
+ printf("No recipients specified\n");
+ senderr++;
+ }
+ /*
+ * Look through the recipient list for names with /'s
+ * in them which we write to as files directly.
+ */
+ to = outof(to, mtf, hp);
+ if (senderr)
+ savedeadletter(mtf);
+ to = elide(to);
+ if (count(to) == 0)
+ goto out;
+ if (value("recordrecip") != NULL) {
+ /*
+ * Before fixing the header, save old To:.
+ * We do this because elide above has sorted To: list, and
+ * we would like to save message in a file named by the first
+ * recipient the user has entered, not the one being the first
+ * after sorting happened.
+ */
+ if ((nsto = malloc(sizeof(struct name))) == NULL)
+ err(1, "Out of memory");
+ bcopy(hp->h_to, nsto, sizeof(struct name));
+ }
+ fixhead(hp, to);
+ if ((mtf = infix(hp, mtf)) == NULL) {
+ fprintf(stderr, ". . . message lost, sorry.\n");
+ return;
+ }
+ namelist = unpack(cat(hp->h_smopts, to));
+ if (debug) {
+ char **t;
+
+ printf("Sendmail arguments:");
+ for (t = namelist; *t != NULL; t++)
+ printf(" \"%s\"", *t);
+ printf("\n");
+ goto out;
+ }
+ if (value("recordrecip") != NULL) {
+ /*
+ * Extract first recipient username from saved To: and use it
+ * as a filename.
+ */
+ if ((nbuf = malloc(strlen(detract(nsto, 0)) + 1)) == NULL)
+ err(1, "Out of memory");
+ if ((cp = yanklogin(detract(nsto, 0), nbuf)) != NULL)
+ (void)savemail(expand(nbuf), mtf);
+ free(nbuf);
+ free(nsto);
+ } else if ((cp = value("record")) != NULL) {
+ char * expanded_record_name = expand(cp);
+ char * outfolder = value("outfolder");
+ if ((outfolder != NULL) && (*expanded_record_name != '/')) {
+ char xname[PATHSIZE];
+ if (getfold(xname, sizeof(xname)) >= 0) {
+ if (xname[strlen(xname)-1] != '/')
+ strlcat(xname, "/", sizeof(xname)); /* only when needed */
+ strlcat(xname, expanded_record_name, sizeof(xname));
+ (void)savemail(xname, mtf);
+ } else { /* folder problem? - just save using "record" */
+ (void)savemail(expanded_record_name, mtf);
+ }
+ } else {
+ (void)savemail(expanded_record_name, mtf);
+ }
+ }
+ /*
+ * Fork, set up the temporary mail file as standard
+ * input for "mail", and exec with the user list we generated
+ * far above.
+ */
+ pid = fork();
+ if (pid == -1) {
+ warn("fork");
+ savedeadletter(mtf);
+ goto out;
+ }
+ if (pid == 0) {
+ 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
+ cp = _PATH_SENDMAIL;
+ execv(cp, namelist);
+ warn("%s", cp);
+ _exit(1);
+ }
+ if (value("verbose") != NULL)
+ (void)wait_child(pid);
+ else
+ free_child(pid);
+out:
+ (void)Fclose(mtf);
+}
+
+/*
+ * Fix the header by glopping all of the expanded names from
+ * the distribution list into the appropriate fields.
+ */
+void
+fixhead(hp, tolist)
+ struct header *hp;
+ struct name *tolist;
+{
+ struct name *np;
+
+ hp->h_to = NULL;
+ 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));
+ else if ((np->n_type & GMASK) == GCC)
+ hp->h_cc =
+ cat(hp->h_cc, nalloc(np->n_name, np->n_type));
+ else if ((np->n_type & GMASK) == GBCC)
+ hp->h_bcc =
+ cat(hp->h_bcc, nalloc(np->n_name, np->n_type));
+ }
+}
+
+/*
+ * Prepend a header in front of the collected stuff
+ * and return the new file.
+ */
+FILE *
+infix(hp, fi)
+ struct header *hp;
+ FILE *fi;
+{
+ FILE *nfo, *nfi;
+ int c, fd;
+ char tempname[PATHSIZE];
+
+ (void)snprintf(tempname, sizeof(tempname),
+ "%s/mail.RsXXXXXXXXXX", tmpdir);
+ if ((fd = mkstemp(tempname)) == -1 ||
+ (nfo = Fdopen(fd, "w")) == NULL) {
+ warn("%s", tempname);
+ return (fi);
+ }
+ if ((nfi = Fopen(tempname, "r")) == NULL) {
+ warn("%s", tempname);
+ (void)Fclose(nfo);
+ (void)rm(tempname);
+ return (fi);
+ }
+ (void)rm(tempname);
+ (void)puthead(hp, nfo,
+ GTO|GSUBJECT|GCC|GBCC|GREPLYTO|GINREPLYTO|GNL|GCOMMA);
+ c = getc(fi);
+ while (c != EOF) {
+ (void)putc(c, nfo);
+ c = getc(fi);
+ }
+ if (ferror(fi)) {
+ warnx("read");
+ rewind(fi);
+ return (fi);
+ }
+ (void)fflush(nfo);
+ if (ferror(nfo)) {
+ warn("%s", tempname);
+ (void)Fclose(nfo);
+ (void)Fclose(nfi);
+ rewind(fi);
+ return (fi);
+ }
+ (void)Fclose(nfo);
+ (void)Fclose(fi);
+ rewind(nfi);
+ return (nfi);
+}
+
+/*
+ * Dump the to, subject, cc header on the
+ * passed file buffer.
+ */
+int
+puthead(hp, fo, w)
+ struct header *hp;
+ FILE *fo;
+ int w;
+{
+ int gotcha;
+
+ gotcha = 0;
+ if (hp->h_to != NULL && w & GTO)
+ fmt("To:", hp->h_to, fo, w&GCOMMA), gotcha++;
+ if (hp->h_subject != NULL && w & GSUBJECT)
+ fprintf(fo, "Subject: %s\n", hp->h_subject), gotcha++;
+ if (hp->h_cc != NULL && w & GCC)
+ fmt("Cc:", hp->h_cc, fo, w&GCOMMA), gotcha++;
+ if (hp->h_bcc != NULL && w & GBCC)
+ fmt("Bcc:", hp->h_bcc, fo, w&GCOMMA), gotcha++;
+ if (hp->h_replyto != NULL && w & GREPLYTO)
+ fprintf(fo, "Reply-To: %s\n", hp->h_replyto), gotcha++;
+ if (hp->h_inreplyto != NULL && w & GINREPLYTO)
+ fprintf(fo, "In-Reply-To: <%s>\n", hp->h_inreplyto), gotcha++;
+ if (gotcha && w & GNL)
+ (void)putc('\n', fo);
+ return (0);
+}
+
+/*
+ * Format the given header line to not exceed 72 characters.
+ */
+void
+fmt(str, np, fo, comma)
+ const char *str;
+ struct name *np;
+ FILE *fo;
+ int comma;
+{
+ int col, len;
+
+ comma = comma ? 1 : 0;
+ col = strlen(str);
+ if (col)
+ fputs(str, fo);
+ for (; np != NULL; np = np->n_flink) {
+ if (np->n_flink == NULL)
+ comma = 0;
+ len = strlen(np->n_name);
+ col++; /* for the space */
+ if (col + len + comma > 72 && col > 4) {
+ fprintf(fo, "\n ");
+ col = 4;
+ } else
+ fprintf(fo, " ");
+ fputs(np->n_name, fo);
+ if (comma)
+ fprintf(fo, ",");
+ col += len + comma;
+ }
+ fprintf(fo, "\n");
+}
+
+/*
+ * Save the outgoing mail on the passed file.
+ */
+
+/*ARGSUSED*/
+int
+savemail(name, fi)
+ char name[];
+ FILE *fi;
+{
+ FILE *fo;
+ char buf[BUFSIZ];
+ int i;
+ time_t now;
+
+ if ((fo = Fopen(name, "a")) == NULL) {
+ warn("%s", name);
+ return (-1);
+ }
+ (void)time(&now);
+ fprintf(fo, "From %s %s", myname, ctime(&now));
+ while ((i = fread(buf, 1, sizeof(buf), fi)) > 0)
+ (void)fwrite(buf, 1, i, fo);
+ fprintf(fo, "\n");
+ (void)fflush(fo);
+ if (ferror(fo))
+ warn("%s", name);
+ (void)Fclose(fo);
+ rewind(fi);
+ return (0);
+}
diff --git a/mail_cmds/mail/strings.c b/mail_cmds/mail/strings.c
new file mode 100644
index 0000000..6b4fc6b
--- /dev/null
+++ b/mail_cmds/mail/strings.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)strings.c 8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/strings.c,v 1.5 2002/06/30 05:25:06 obrien Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+/*
+ * Mail -- a mail program
+ *
+ * String allocation routines.
+ * Strings handed out here are reclaimed at the top of the command
+ * loop each time, so they need not be freed.
+ */
+
+#include "rcv.h"
+#include "extern.h"
+
+/*
+ * Allocate size more bytes of space and return the address of the
+ * first byte to the caller. An even number of bytes are always
+ * allocated so that the space will always be on a word boundary.
+ * The string spaces are of exponentially increasing size, to satisfy
+ * the occasional user with enormous string size requests.
+ */
+
+char *
+salloc(size)
+ int size;
+{
+ char *t;
+ int s, index;
+ struct strings *sp;
+
+ s = size;
+ s += (sizeof(char *) - 1);
+ s &= ~(sizeof(char *) - 1);
+ index = 0;
+ for (sp = &stringdope[0]; sp < &stringdope[NSPACE]; sp++) {
+ if (sp->s_topFree == NULL && (STRINGSIZE << index) >= s)
+ break;
+ if (sp->s_nleft >= s)
+ break;
+ index++;
+ }
+ if (sp >= &stringdope[NSPACE])
+ errx(1, "String too large");
+ if (sp->s_topFree == NULL) {
+ index = sp - &stringdope[0];
+ if ((sp->s_topFree = malloc(STRINGSIZE << index)) == NULL)
+ err(1, "No room for space %d", index);
+ sp->s_nextFree = sp->s_topFree;
+ sp->s_nleft = STRINGSIZE << index;
+ }
+ sp->s_nleft -= s;
+ t = sp->s_nextFree;
+ sp->s_nextFree += s;
+ return (t);
+}
+
+/*
+ * Reset the string area to be empty.
+ * Called to free all strings allocated
+ * since last reset.
+ */
+void
+sreset()
+{
+ struct strings *sp;
+ int index;
+
+ if (noreset)
+ return;
+ index = 0;
+ for (sp = &stringdope[0]; sp < &stringdope[NSPACE]; sp++) {
+ if (sp->s_topFree == NULL)
+ continue;
+ sp->s_nextFree = sp->s_topFree;
+ sp->s_nleft = STRINGSIZE << index;
+ index++;
+ }
+}
+
+/*
+ * Make the string area permanent.
+ * Meant to be called in main, after initialization.
+ */
+void
+spreserve()
+{
+ struct strings *sp;
+
+ for (sp = &stringdope[0]; sp < &stringdope[NSPACE]; sp++)
+ sp->s_topFree = NULL;
+}
diff --git a/mail_cmds/mail/strlcpy.c b/mail_cmds/mail/strlcpy.c
new file mode 100644
index 0000000..9de9d32
--- /dev/null
+++ b/mail_cmds/mail/strlcpy.c
@@ -0,0 +1,74 @@
+/* $OpenBSD: strlcpy.c,v 1.4 1999/05/01 18:56:41 millert Exp $ */
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+#if 0
+static char *rcsid = "$OpenBSD: strlcpy.c,v 1.4 1999/05/01 18:56:41 millert Exp $";
+#endif
+#endif /* LIBC_SCCS and not lint */
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD: src/lib/libc/string/strlcpy.c,v 1.2.4.1 2001/07/09 23:30:06 obrien Exp $";
+#endif
+
+#include <sys/types.h>
+#include <string.h>
+
+/*
+ * Copy src to string dst of size siz. At most siz-1 characters
+ * will be copied. Always NUL terminates (unless siz == 0).
+ * Returns strlen(src); if retval >= siz, truncation occurred.
+ */
+size_t strlcpy(dst, src, siz)
+ char *dst;
+ const char *src;
+ size_t siz;
+{
+ register char *d = dst;
+ register const char *s = src;
+ register size_t n = siz;
+
+ /* Copy as many bytes as will fit */
+ if (n != 0 && --n != 0) {
+ do {
+ if ((*d++ = *s++) == 0)
+ break;
+ } while (--n != 0);
+ }
+
+ /* Not enough room in dst, add NUL and traverse rest of src */
+ if (n == 0) {
+ if (siz != 0)
+ *d = '\0'; /* NUL-terminate dst */
+ while (*s++)
+ ;
+ }
+
+ return(s - src - 1); /* count does not include NUL */
+}
diff --git a/mail_cmds/mail/temp.c b/mail_cmds/mail/temp.c
new file mode 100644
index 0000000..8b2195d
--- /dev/null
+++ b/mail_cmds/mail/temp.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)temp.c 8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/temp.c,v 1.9 2002/06/30 05:25:06 obrien Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+#include "rcv.h"
+#include "extern.h"
+
+/*
+ * Mail -- a mail program
+ *
+ * Give names to all the temporary files that we will need.
+ */
+
+char *tmpdir;
+
+void
+tinit()
+{
+ char *cp;
+
+ if ((tmpdir = getenv("TMPDIR")) == NULL || *tmpdir == '\0')
+ tmpdir = _PATH_TMP;
+ if ((tmpdir = strdup(tmpdir)) == NULL)
+ errx(1, "Out of memory");
+ /* Strip trailing '/' if necessary */
+ cp = tmpdir + strlen(tmpdir) - 1;
+ while (cp > tmpdir && *cp == '/') {
+ *cp = '\0';
+ cp--;
+ }
+
+ /*
+ * It's okay to call savestr in here because main will
+ * do a spreserve() after us.
+ */
+ if (myname != NULL) {
+ if (getuserid(myname) < 0)
+ errx(1, "\"%s\" is not a user of this system", myname);
+ } else {
+ if ((cp = username()) == NULL) {
+ myname = "ubluit";
+ if (rcvmode)
+ errx(1, "Who are you!?");
+ } else
+ myname = savestr(cp);
+ }
+ if ((cp = getenv("HOME")) == NULL || *cp == '\0' ||
+ strlen(cp) >= PATHSIZE)
+ homedir = NULL;
+ else
+ homedir = savestr(cp);
+ if (debug)
+ fprintf(stderr, "user = %s, homedir = %s\n", myname,
+ homedir ? homedir : "NONE");
+}
diff --git a/mail_cmds/mail/tty.c b/mail_cmds/mail/tty.c
new file mode 100644
index 0000000..77e9e0d
--- /dev/null
+++ b/mail_cmds/mail/tty.c
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)tty.c 8.2 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/tty.c,v 1.6 2002/06/30 05:25:06 obrien Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+#include <sys/ioctl.h>
+
+/*
+ * Mail -- a mail program
+ *
+ * Generally useful tty stuff.
+ */
+
+#include "rcv.h"
+#include "extern.h"
+
+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
+static int ttyset; /* We must now do erase/kill */
+#endif
+
+/*
+ * Read all relevant header fields.
+ */
+
+int
+grabh(hp, gflags)
+ struct header *hp;
+ int gflags;
+{
+ struct termios ttybuf;
+ sig_t saveint;
+ 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);
+ savettin = signal(SIGTTIN, SIG_DFL);
+ errs = 0;
+#ifndef TIOCSTI
+ ttyset = 0;
+#endif
+ if (tcgetattr(fileno(stdin), &ttybuf) < 0) {
+ warn("tcgetattr(stdin)");
+ return (-1);
+ }
+ c_erase = ttybuf.c_cc[VERASE];
+ c_kill = ttybuf.c_cc[VKILL];
+#ifndef TIOCSTI
+ 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 */
+ saveint = signal(SIGINT, ttyint);
+ if (setjmp(intjmp)) {
+ /* Interrupt from headers needs to be told to caller */
+ errs++;
+ goto out;
+ }
+#endif
+ if (gflags & GTO) {
+#ifndef TIOCSTI
+ if (!ttyset && hp->h_to != NULL)
+ ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
+#endif
+ hp->h_to =
+ extract(readtty("To: ", detract(hp->h_to, 0)), GTO);
+ }
+ if (gflags & GSUBJECT) {
+#ifndef TIOCSTI
+ if (!ttyset && hp->h_subject != NULL)
+ 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, &ttybuf);
+#endif
+ hp->h_cc =
+ extract(readtty("Cc: ", detract(hp->h_cc, 0)), GCC);
+ }
+ if (gflags & GBCC) {
+#ifndef TIOCSTI
+ if (!ttyset && hp->h_bcc != NULL)
+ ttyset++, tcsetattr(fileno(stdin), TCSADRAIN, &ttybuf);
+#endif
+ hp->h_bcc =
+ extract(readtty("Bcc: ", detract(hp->h_bcc, 0)), GBCC);
+ }
+out:
+ (void)signal(SIGTSTP, savetstp);
+ (void)signal(SIGTTOU, savettou);
+ (void)signal(SIGTTIN, savettin);
+#ifndef TIOCSTI
+ ttybuf.c_cc[VERASE] = c_erase;
+ ttybuf.c_cc[VKILL] = c_kill;
+ if (ttyset)
+ 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);
+}
+
+/*
+ * Read up a header from standard input.
+ * The source string has the preliminary contents to
+ * be read.
+ *
+ */
+
+char *
+readtty(pr, src)
+ const char *pr;
+ char src[];
+{
+ char ch, canonb[BUFSIZ];
+ int c;
+ char *cp, *cp2;
+
+ fputs(pr, stdout);
+ (void)fflush(stdout);
+ if (src != NULL && strlen(src) > BUFSIZ - 2) {
+ printf("too long to edit\n");
+ return (src);
+ }
+#ifndef TIOCSTI
+ if (src != NULL)
+ strlcpy(canonb, src, sizeof(canonb));
+ else
+ *canonb = '\0';
+ fputs(canonb, stdout);
+ (void)fflush(stdout);
+#else
+ cp = src == NULL ? "" : src;
+ while ((c = *cp++) != '\0') {
+ if ((c_erase != _POSIX_VDISABLE && c == c_erase) ||
+ (c_kill != _POSIX_VDISABLE && c == c_kill)) {
+ ch = '\\';
+ ioctl(0, TIOCSTI, &ch);
+ }
+ ch = c;
+ ioctl(0, TIOCSTI, &ch);
+ }
+ cp = canonb;
+ *cp = '\0';
+#endif
+ cp2 = cp;
+ while (cp2 < canonb + BUFSIZ)
+ *cp2++ = '\0';
+ cp2 = cp;
+ if (setjmp(rewrite))
+ goto redo;
+ (void)signal(SIGTSTP, ttystop);
+ (void)signal(SIGTTOU, ttystop);
+ (void)signal(SIGTTIN, ttystop);
+ clearerr(stdin);
+ while (cp2 < canonb + BUFSIZ) {
+ c = getc(stdin);
+ if (c == EOF || c == '\n')
+ break;
+ *cp2++ = c;
+ }
+ *cp2 = '\0';
+ (void)signal(SIGTSTP, SIG_DFL);
+ (void)signal(SIGTTOU, SIG_DFL);
+ (void)signal(SIGTTIN, SIG_DFL);
+ if (c == EOF && ferror(stdin)) {
+redo:
+ cp = strlen(canonb) > 0 ? canonb : NULL;
+ clearerr(stdin);
+ return (readtty(pr, cp));
+ }
+#ifndef TIOCSTI
+ if (cp == NULL || *cp == '\0')
+ return (src);
+ cp2 = cp;
+ if (!ttyset)
+ return (strlen(canonb) > 0 ? savestr(canonb) : NULL);
+ while (*cp != '\0') {
+ c = *cp++;
+ if (c_erase != _POSIX_VDISABLE && c == c_erase) {
+ if (cp2 == canonb)
+ continue;
+ if (cp2[-1] == '\\') {
+ cp2[-1] = c;
+ continue;
+ }
+ cp2--;
+ continue;
+ }
+ if (c_kill != _POSIX_VDISABLE && c == c_kill) {
+ if (cp2 == canonb)
+ continue;
+ if (cp2[-1] == '\\') {
+ cp2[-1] = c;
+ continue;
+ }
+ cp2 = canonb;
+ continue;
+ }
+ *cp2++ = c;
+ }
+ *cp2 = '\0';
+#endif
+ if (equal("", canonb))
+ return (NULL);
+ return (savestr(canonb));
+}
+
+/*
+ * Receipt continuation.
+ */
+void
+ttystop(s)
+ int s;
+{
+ sig_t old_action = signal(s, SIG_DFL);
+ sigset_t nset;
+
+ (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);
+}
+
+/*ARGSUSED*/
+void
+ttyint(s)
+ int s;
+{
+ longjmp(intjmp, 1);
+}
diff --git a/mail_cmds/mail/v7.local.c b/mail_cmds/mail/v7.local.c
new file mode 100644
index 0000000..3e43ff2
--- /dev/null
+++ b/mail_cmds/mail/v7.local.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)v7.local.c 8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/v7.local.c,v 1.5 2002/06/30 05:25:06 obrien Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+/*
+ * Mail -- a mail program
+ *
+ * Version 7
+ *
+ * Local routines that are installation dependent.
+ */
+
+#include "rcv.h"
+#include <fcntl.h>
+#include "extern.h"
+
+/*
+ * Locate the user's mailbox file (ie, the place where new, unread
+ * mail is queued).
+ */
+void
+findmail(user, buf, buflen)
+ char *user, *buf;
+ int buflen;
+{
+ char *tmp = getenv("MAIL");
+
+ if (tmp == NULL)
+ (void)snprintf(buf, buflen, "%s/%s", _PATH_MAILDIR, user);
+ else
+ (void)strlcpy(buf, tmp, buflen);
+}
+
+/*
+ * Get rid of the queued mail.
+ */
+void
+demail()
+{
+
+ if (value("keep") != NULL || rm(mailname) < 0)
+ (void)close(open(mailname, O_CREAT | O_TRUNC | O_WRONLY, 0600));
+}
+
+/*
+ * Discover user login name.
+ */
+char *
+username()
+{
+ char *np;
+ uid_t uid;
+
+ if ((np = getenv("USER")) != NULL)
+ return (np);
+ if ((np = getenv("LOGNAME")) != NULL)
+ return (np);
+ if ((np = getname(uid = getuid())) != NULL)
+ return (np);
+ printf("Cannot associate a name with uid %u\n", (unsigned)uid);
+ return (NULL);
+}
diff --git a/mail_cmds/mail/vars.c b/mail_cmds/mail/vars.c
new file mode 100644
index 0000000..419952d
--- /dev/null
+++ b/mail_cmds/mail/vars.c
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)vars.c 8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/vars.c,v 1.4 2002/06/30 05:25:06 obrien Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+#include "rcv.h"
+#include "extern.h"
+
+/*
+ * Mail -- a mail program
+ *
+ * Variable handling stuff.
+ */
+
+/*
+ * Assign a value to a variable.
+ */
+void
+assign(name, value)
+ const char *name, *value;
+{
+ struct var *vp;
+ int h;
+
+ h = hash(name);
+ vp = lookup(name);
+ if (vp == NULL) {
+ vp = calloc(sizeof(*vp), 1);
+ vp->v_name = vcopy(name);
+ vp->v_link = variables[h];
+ variables[h] = vp;
+ }
+ else
+ v_free(vp->v_value);
+ vp->v_value = vcopy(value);
+}
+
+/*
+ * Free up a variable string. We do not bother to allocate
+ * strings whose value is "" since they are expected to be frequent.
+ * Thus, we cannot free same!
+ */
+void
+v_free(cp)
+ char *cp;
+{
+ if (*cp != '\0')
+ (void)free(cp);
+}
+
+/*
+ * Copy a variable value into permanent (ie, not collected after each
+ * command) space. Do not bother to alloc space for ""
+ */
+
+char *
+vcopy(str)
+ const char *str;
+{
+ char *new;
+ unsigned len;
+
+ if (*str == '\0')
+ return ("");
+ len = strlen(str) + 1;
+ if ((new = malloc(len)) == NULL)
+ err(1, "Out of memory");
+ bcopy(str, new, (int)len);
+ return (new);
+}
+
+/*
+ * Get the value of a variable and return it.
+ * Look in the environment if its not available locally.
+ */
+
+char *
+value(name)
+ const char *name;
+{
+ struct var *vp;
+
+ if ((vp = lookup(name)) == NULL)
+ return (getenv(name));
+ return (vp->v_value);
+}
+
+/*
+ * Locate a variable and return its variable
+ * node.
+ */
+
+struct var *
+lookup(name)
+ const char *name;
+{
+ struct var *vp;
+
+ for (vp = variables[hash(name)]; vp != NULL; vp = vp->v_link)
+ if (*vp->v_name == *name && equal(vp->v_name, name))
+ return (vp);
+ return (NULL);
+}
+
+/*
+ * Locate a group name and return it.
+ */
+
+struct grouphead *
+findgroup(name)
+ char name[];
+{
+ struct grouphead *gh;
+
+ for (gh = groups[hash(name)]; gh != NULL; gh = gh->g_link)
+ if (*gh->g_name == *name && equal(gh->g_name, name))
+ return (gh);
+ return (NULL);
+}
+
+/*
+ * Print a group out on stdout
+ */
+void
+printgroup(name)
+ char name[];
+{
+ struct grouphead *gh;
+ struct group *gp;
+
+ if ((gh = findgroup(name)) == NULL) {
+ printf("\"%s\": not a group\n", name);
+ return;
+ }
+ printf("%s\t", gh->g_name);
+ for (gp = gh->g_list; gp != NULL; gp = gp->ge_link)
+ printf(" %s", gp->ge_name);
+ printf("\n");
+}
+
+/*
+ * Hash the passed string and return an index into
+ * the variable or group hash table.
+ */
+int
+hash(name)
+ const char *name;
+{
+ int h = 0;
+
+ while (*name != '\0') {
+ h <<= 2;
+ h += *name++;
+ }
+ if (h < 0 && (h = -h) < 0)
+ h = 0;
+ return (h % HSHSIZE);
+}
diff --git a/mail_cmds/mail/version.c b/mail_cmds/mail/version.c
new file mode 100644
index 0000000..5178acb
--- /dev/null
+++ b/mail_cmds/mail/version.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)version.c 8.1 (Berkeley) 6/6/93";
+#endif
+static const char rcsid[] =
+ "$FreeBSD: src/usr.bin/mail/version.c,v 1.4 2002/06/30 05:25:06 obrien Exp $";
+#endif /* not lint */
+
+#include <sys/cdefs.h>
+
+/*
+ * Just keep track of the date/sid of this version of Mail.
+ * Load this file first to get a "total" Mail version.
+ */
+const char *version = "8.1 6/6/93";
diff --git a/mail_cmds/msgs/Makefile b/mail_cmds/msgs/Makefile
new file mode 100644
index 0000000..3319b01
--- /dev/null
+++ b/mail_cmds/msgs/Makefile
@@ -0,0 +1,11 @@
+Project = msgs
+Install_Dir = /usr/bin
+
+CFILES = msgs.c
+MANPAGES = msgs.1
+
+Extra_CC_Flags = -Wall -Werror -mdynamic-no-pic
+Extra_LD_Flags = -dead_strip \
+ -lcurses
+
+include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make
diff --git a/mail_cmds/msgs/msgs.1 b/mail_cmds/msgs/msgs.1
new file mode 100644
index 0000000..3897861
--- /dev/null
+++ b/mail_cmds/msgs/msgs.1
@@ -0,0 +1,236 @@
+.\" Copyright (c) 1980, 1990, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)msgs.1 8.2 (Berkeley) 4/28/95
+.\" $FreeBSD: src/usr.bin/msgs/msgs.1,v 1.18 2002/07/15 07:16:54 keramida Exp $
+.\"
+.Dd April 28, 1995
+.Dt MSGS 1
+.Os
+.Sh NAME
+.Nm msgs
+.Nd system messages and junk mail program
+.Sh SYNOPSIS
+.Nm
+.Op Fl fhlpq
+.Op Ar number
+.Op Ar \-number
+.Nm
+.Op Fl s
+.Nm
+.Op Fl c
+.Op \-days
+.Sh DESCRIPTION
+The
+.Nm
+utility is used to read system messages.
+These messages are
+sent by mailing to the login `msgs' and should be short
+pieces of information which are suitable to be read once by most users
+of the system.
+.Pp
+The
+.Nm
+utility is normally invoked each time you login, by placing it in the file
+.Pa .login
+(or
+.Pa .profile
+if you use
+.Xr sh 1 ) .
+It will then prompt you with the source and subject of each new message.
+If there is no subject line, the first few non-blank lines of the
+message will be displayed.
+If there is more to the message, you will be told how
+long it is and asked whether you wish to see the rest of the message.
+The possible responses are:
+.Bl -tag -width Fl
+.It Fl y
+Type the rest of the message.
+.It Ic RETURN
+Synonym for y.
+.It Fl n
+Skip this message
+and go on to the next message.
+.It Fl
+Redisplay the last message.
+.It Fl q
+Drop out of
+.Nm ;
+the next time
+.Nm
+will pick up where it last left off.
+.It Fl s
+Append the current message to the file ``Messages'' in the current directory;
+`s\-' will save the previously displayed message.
+A `s' or `s\-' may
+be followed by a space and a file name to receive the message replacing
+the default ``Messages''.
+.It Fl m
+A copy of the specified message is placed in a temporary
+mailbox and
+.Xr mail 1
+is invoked on that mailbox.
+Both `m' and `s' accept a numeric argument in place of the `\-'.
+.El
+.Pp
+The
+.Nm
+utility keeps track of the next message you will see by a number in the file
+.Pa \&.msgsrc
+in your home directory.
+In the directory
+.Pa /var/msgs
+it keeps a set of files whose names are the (sequential) numbers
+of the messages they represent.
+The file
+.Pa /var/msgs/bounds
+shows the low and high number of the messages in the directory
+so that
+.Nm
+can quickly determine if there are no messages for you.
+If the contents of
+.Pa bounds
+is incorrect it can be fixed by removing it;
+.Nm
+will make a new
+.Pa bounds
+file the next time it is run with the
+.Fl s
+option.
+If
+.Nm
+is run with any option other than
+.Fl s ,
+an error will be displayed if
+.Pa /var/msgs/bounds
+does not exist.
+.Pp
+The
+.Fl s
+option is used for setting up the posting of messages.
+The line
+.Pp
+.Dl msgs: \&"\&| /usr/bin/msgs \-s\&"
+.Pp
+should be included in
+.Pa /etc/mail/aliases
+(see
+.Xr newaliases 1 )
+to enable posting of messages.
+.Pp
+The
+.Fl c
+option is used for performing cleanup on
+.Pa /var/msgs .
+A shell script entry to run
+.Nm
+with the
+.Fl c
+option should be placed in
+.Pa /etc/periodic/daily
+(see
+.Xr periodic 8 )
+to run every night.
+This will remove all messages over 21 days old.
+A different expiration may be specified on the command line to override
+the default.
+You must be the superuser to use this option.
+.Pp
+Options when reading messages include:
+.Bl -tag -width Fl
+.It Fl f
+Do not say ``No new messages.''.
+This is useful in a
+.Pa .login
+file since this is often the case here.
+.It Fl q
+Queries whether there are messages, printing
+``There are new messages.'' if there are.
+The command ``msgs \-q'' is often used in login scripts.
+.It Fl h
+Print the first part of messages only.
+.It Fl l
+Cause only locally originated messages to be reported.
+.It Ar num
+A message number can be given
+on the command line, causing
+.Nm
+to start at the specified message rather than at the next message
+indicated by your
+.Pa \&.msgsrc
+file.
+Thus
+.Pp
+.Dl msgs \-h 1
+.Pp
+prints the first part of all messages.
+.It Ar \-number
+Start
+.Ar number
+messages back from the one indicated in the
+.Pa \&.msgsrc
+file, useful for reviews of recent messages.
+.It Fl p
+Pipe long messages through
+.Xr more 1 .
+.El
+.Pp
+Within
+.Nm
+you can also go to any specific message by typing its number when
+.Nm
+requests input as to what to do.
+.Sh ENVIRONMENT
+The
+.Nm
+utility uses the
+.Ev HOME
+and
+.Ev TERM
+environment variables for the default home directory and
+terminal type.
+.Sh FILES
+.Bl -tag -width /var/msgs/* -compact
+.It Pa /var/msgs/*
+database
+.It Pa ~/.msgsrc
+number of next message to be presented
+.El
+.Sh SEE ALSO
+.Xr mail 1 ,
+.Xr more 1 ,
+.Xr aliases 5 ,
+.Xr periodic 8
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 3.0 .
diff --git a/mail_cmds/msgs/msgs.c b/mail_cmds/msgs/msgs.c
new file mode 100644
index 0000000..a452994
--- /dev/null
+++ b/mail_cmds/msgs/msgs.c
@@ -0,0 +1,923 @@
+/*-
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__unused static const char copyright[] =
+"@(#) Copyright (c) 1980, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#if 0
+#ifndef lint
+static char sccsid[] = "@(#)msgs.c 8.2 (Berkeley) 4/28/95";
+#endif /* not lint */
+#endif
+
+__RCSID("$FreeBSD: src/usr.bin/msgs/msgs.c,v 1.24 2002/09/04 23:29:04 dwmalone Exp $");
+
+/*
+ * msgs - a user bulletin board program
+ *
+ * usage:
+ * msgs [fhlopqr] [[-]number] to read messages
+ * msgs -s to place messages
+ * msgs -c [-days] to clean up the bulletin board
+ *
+ * prompt commands are:
+ * y print message
+ * n flush message, go to next message
+ * q flush message, quit
+ * p print message, turn on 'pipe thru more' mode
+ * P print message, turn off 'pipe thru more' mode
+ * - reprint last message
+ * s[-][<num>] [<filename>] save message
+ * m[-][<num>] mail with message in temp mbox
+ * x exit without flushing this message
+ * <num> print message number <num>
+ */
+
+#define V7 /* will look for TERM in the environment */
+#define OBJECT /* will object to messages without Subjects */
+#define REJECT /* will reject messages without Subjects
+ (OBJECT must be defined also) */
+/* #define UNBUFFERED *//* use unbuffered output */
+
+#ifdef __APPLE__
+#include <sys/ioctl.h>
+#endif /* __APPLE__ */
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <locale.h>
+#include <pwd.h>
+#include <setjmp.h>
+#include <termcap.h>
+#include <termios.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+#include "pathnames.h"
+
+#define CMODE 0644 /* bounds file creation mode */
+#define NO 0
+#define YES 1
+#define SUPERUSER 0 /* superuser uid */
+#define DAEMON 1 /* daemon uid */
+#define NLINES 24 /* default number of lines/crt screen */
+#define NDAYS 21 /* default keep time for messages */
+#define DAYS *24*60*60 /* seconds/day */
+#define MSGSRC ".msgsrc" /* user's rc file */
+#define BOUNDS "bounds" /* message bounds file */
+#define NEXT "Next message? [yq]"
+#define MORE "More? [ynq]"
+#define NOMORE "(No more) [q] ?"
+
+typedef char bool;
+
+FILE *msgsrc;
+FILE *newmsg;
+const char *sep = "-";
+char inbuf[BUFSIZ];
+char fname[MAXPATHLEN];
+char cmdbuf[MAXPATHLEN + MAXPATHLEN];
+char subj[128];
+char from[128];
+char date[128];
+char *ptr;
+char *in;
+bool local;
+bool ruptible;
+bool totty;
+bool seenfrom;
+bool seensubj;
+bool blankline;
+bool printing = NO;
+bool mailing = NO;
+bool quitit = NO;
+bool sending = NO;
+bool intrpflg = NO;
+bool restricted = NO;
+uid_t uid;
+int msg;
+int prevmsg;
+int lct;
+int nlines;
+int Lpp = 0;
+time_t t;
+time_t keep;
+
+/* option initialization */
+bool hdrs = NO;
+bool qopt = NO;
+bool hush = NO;
+bool send_msg = NO;
+bool locomode = NO;
+bool use_pager = NO;
+bool clean = NO;
+bool lastcmd = NO;
+jmp_buf tstpbuf;
+
+void ask(const char *);
+void gfrsub(FILE *);
+int linecnt(FILE *);
+int next(char *);
+char *nxtfld(unsigned char *);
+void onsusp(int);
+void onintr(int);
+void prmesg(int);
+static void usage(void);
+
+int
+main(int argc, char *argv[])
+{
+ bool newrc, already;
+ int rcfirst = 0; /* first message to print (from .rc) */
+ int rcback = 0; /* amount to back off of rcfirst */
+ int firstmsg = 0, nextmsg = 0, lastmsg = 0;
+ int blast = 0;
+ struct stat buf; /* stat to check access of bounds */
+ FILE *bounds;
+
+#ifdef UNBUFFERED
+ setbuf(stdout, NULL);
+#endif
+ setlocale(LC_ALL, "");
+
+ time(&t);
+ setuid(uid = getuid());
+ ruptible = (signal(SIGINT, SIG_IGN) == SIG_DFL);
+ if (ruptible)
+ signal(SIGINT, SIG_DFL);
+
+ argc--, argv++;
+ while (argc > 0) {
+ if (isdigit(argv[0][0])) { /* starting message # */
+ rcfirst = atoi(argv[0]);
+ }
+ else if (isdigit(argv[0][1])) { /* backward offset */
+ rcback = atoi( &( argv[0][1] ) );
+ }
+ else {
+ ptr = *argv;
+ while (*ptr) switch (*ptr++) {
+
+ case '-':
+ break;
+
+ case 'c':
+ if (uid != SUPERUSER && uid != DAEMON)
+ errx(1,
+ "only the super-user can use the c flag");
+ clean = YES;
+ break;
+
+ case 'f': /* silently */
+ hush = YES;
+ break;
+
+ case 'h': /* headers only */
+ hdrs = YES;
+ break;
+
+ case 'l': /* local msgs only */
+ locomode = YES;
+ break;
+
+ case 'o': /* option to save last message */
+ lastcmd = YES;
+ break;
+
+ case 'p': /* pipe thru 'more' during long msgs */
+ use_pager = YES;
+ break;
+
+ case 'q': /* query only */
+ qopt = YES;
+ break;
+
+#ifdef __APPLE__
+ case 'r': /* restricted */
+ restricted = YES;
+ break;
+#endif /* __APPLE__ */
+
+
+ case 's': /* sending TO msgs */
+ send_msg = YES;
+ break;
+
+ default:
+ usage();
+ }
+ }
+ argc--, argv++;
+ }
+
+ /*
+ * determine current message bounds
+ */
+ snprintf(fname, sizeof(fname), "%s/%s", _PATH_MSGS, BOUNDS);
+
+ /*
+ * Test access rights to the bounds file
+ * This can be a little tricky. if(send_msg), then
+ * we will create it. We assume that if(send_msg),
+ * then you have write permission there.
+ * Else, it better be there, or we bail.
+ */
+ if (send_msg != YES) {
+ if (stat(fname, &buf) < 0) {
+ if (hush != YES) {
+ err(errno, "%s", fname);
+ } else {
+ exit(1);
+ }
+ }
+ }
+ bounds = fopen(fname, "r");
+
+ if (bounds != NULL) {
+ fscanf(bounds, "%d %d\n", &firstmsg, &lastmsg);
+ fclose(bounds);
+ blast = lastmsg; /* save upper bound */
+ }
+
+ if (clean)
+ keep = t - (rcback? rcback : NDAYS) DAYS;
+
+ if (clean || bounds == NULL) { /* relocate message bounds */
+ struct dirent *dp;
+ struct stat stbuf;
+ bool seenany = NO;
+ DIR *dirp;
+
+ dirp = opendir(_PATH_MSGS);
+ if (dirp == NULL)
+ err(errno, "%s", _PATH_MSGS);
+
+ firstmsg = 32767;
+ lastmsg = 0;
+
+ for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)){
+ char *cp = dp->d_name;
+ int i = 0;
+
+ if (dp->d_ino == 0)
+ continue;
+ if (dp->d_namlen == 0)
+ continue;
+
+ if (clean)
+ snprintf(inbuf, sizeof(inbuf), "%s/%s", _PATH_MSGS, cp);
+
+ while (isdigit(*cp))
+ i = i * 10 + *cp++ - '0';
+ if (*cp)
+ continue; /* not a message! */
+
+ if (clean) {
+ if (stat(inbuf, &stbuf) != 0)
+ continue;
+ if (stbuf.st_mtime < keep
+ && stbuf.st_mode&S_IWRITE) {
+ unlink(inbuf);
+ continue;
+ }
+ }
+
+ if (i > lastmsg)
+ lastmsg = i;
+ if (i < firstmsg)
+ firstmsg = i;
+ seenany = YES;
+ }
+ closedir(dirp);
+
+ if (!seenany) {
+ if (blast != 0) /* never lower the upper bound! */
+ lastmsg = blast;
+ firstmsg = lastmsg + 1;
+ }
+ else if (blast > lastmsg)
+ lastmsg = blast;
+
+ if (!send_msg) {
+ bounds = fopen(fname, "w");
+ if (bounds == NULL)
+ err(errno, "%s", fname);
+ chmod(fname, CMODE);
+ fprintf(bounds, "%d %d\n", firstmsg, lastmsg);
+ fclose(bounds);
+ }
+ }
+
+ if (send_msg) {
+ /*
+ * Send mode - place msgs in _PATH_MSGS
+ */
+ bounds = fopen(fname, "w");
+ if (bounds == NULL)
+ err(errno, "%s", fname);
+
+ nextmsg = lastmsg + 1;
+ snprintf(fname, sizeof(fname), "%s/%d", _PATH_MSGS, nextmsg);
+ newmsg = fopen(fname, "w");
+ if (newmsg == NULL)
+ err(errno, "%s", fname);
+ chmod(fname, CMODE);
+
+ fprintf(bounds, "%d %d\n", firstmsg, nextmsg);
+ fclose(bounds);
+
+ sending = YES;
+ if (ruptible)
+ signal(SIGINT, onintr);
+
+ if (isatty(fileno(stdin))) {
+ ptr = getpwuid(uid)->pw_name;
+ printf("Message %d:\nFrom %s %sSubject: ",
+ nextmsg, ptr, ctime(&t));
+ fflush(stdout);
+ fgets(inbuf, sizeof inbuf, stdin);
+ putchar('\n');
+ fflush(stdout);
+ fprintf(newmsg, "From %s %sSubject: %s\n",
+ ptr, ctime(&t), inbuf);
+ blankline = seensubj = YES;
+ }
+ else
+ blankline = seensubj = NO;
+ for (;;) {
+ fgets(inbuf, sizeof inbuf, stdin);
+ if (feof(stdin) || ferror(stdin))
+ break;
+ blankline = (blankline || (inbuf[0] == '\n'));
+ seensubj = (seensubj || (!blankline && (strncmp(inbuf, "Subj", 4) == 0)));
+ fputs(inbuf, newmsg);
+ }
+#ifdef OBJECT
+ if (!seensubj) {
+ printf("NOTICE: Messages should have a Subject field!\n");
+#ifdef REJECT
+ unlink(fname);
+#endif
+ exit(1);
+ }
+#endif
+ exit(ferror(stdin));
+ }
+ if (clean)
+ exit(0);
+
+ /*
+ * prepare to display messages
+ */
+ totty = (isatty(fileno(stdout)) != 0);
+ use_pager = use_pager && totty;
+
+ snprintf(fname, sizeof(fname), "%s/%s", getenv("HOME"), MSGSRC);
+ msgsrc = fopen(fname, "r");
+ if (msgsrc) {
+ newrc = NO;
+ fscanf(msgsrc, "%d\n", &nextmsg);
+ fclose(msgsrc);
+ if (nextmsg > lastmsg+1) {
+ printf("Warning: bounds have been reset (%d, %d)\n",
+ firstmsg, lastmsg);
+ truncate(fname, (off_t)0);
+ newrc = YES;
+ }
+ else if (!rcfirst)
+ rcfirst = nextmsg - rcback;
+ }
+ else
+ newrc = YES;
+ msgsrc = fopen(fname, "r+");
+ if (msgsrc == NULL)
+ msgsrc = fopen(fname, "w");
+ if (msgsrc == NULL)
+ err(errno, "%s", fname);
+ if (rcfirst) {
+ if (rcfirst > lastmsg+1) {
+ printf("Warning: the last message is number %d.\n",
+ lastmsg);
+ rcfirst = nextmsg;
+ }
+ if (rcfirst > firstmsg)
+ firstmsg = rcfirst; /* don't set below first msg */
+ }
+ if (newrc) {
+ nextmsg = firstmsg;
+ rewind(msgsrc);
+ fprintf(msgsrc, "%d\n", nextmsg);
+ fflush(msgsrc);
+ }
+
+#ifdef V7
+ if (totty) {
+ struct winsize win;
+ if (ioctl(fileno(stdout), TIOCGWINSZ, &win) != -1)
+ Lpp = win.ws_row;
+ if (Lpp <= 0) {
+ if (tgetent(inbuf, getenv("TERM")) <= 0
+ || (Lpp = tgetnum("li")) <= 0) {
+ Lpp = NLINES;
+ }
+ }
+ }
+#endif
+ Lpp -= 6; /* for headers, etc. */
+
+ already = NO;
+ prevmsg = firstmsg;
+ printing = YES;
+ if (ruptible)
+ signal(SIGINT, onintr);
+
+ /*
+ * Main program loop
+ */
+ for (msg = firstmsg; msg <= lastmsg; msg++) {
+
+ snprintf(fname, sizeof(fname), "%s/%d", _PATH_MSGS, msg);
+ newmsg = fopen(fname, "r");
+ if (newmsg == NULL)
+ continue;
+
+ gfrsub(newmsg); /* get From and Subject fields */
+ if (locomode && !local) {
+ fclose(newmsg);
+ continue;
+ }
+
+ if (qopt) { /* This has to be located here */
+ printf("There are new messages.\n");
+ exit(0);
+ }
+
+ if (already && !hdrs)
+ putchar('\n');
+
+ /*
+ * Print header
+ */
+ if (totty)
+ signal(SIGTSTP, onsusp);
+ (void) setjmp(tstpbuf);
+ already = YES;
+ nlines = 2;
+ if (seenfrom) {
+ printf("Message %d:\nFrom %s %s", msg, from, date);
+ nlines++;
+ }
+ if (seensubj) {
+ printf("Subject: %s", subj);
+ nlines++;
+ }
+ else {
+ if (seenfrom) {
+ putchar('\n');
+ nlines++;
+ }
+ while (nlines < 6
+ && fgets(inbuf, sizeof inbuf, newmsg)
+ && inbuf[0] != '\n') {
+ fputs(inbuf, stdout);
+ nlines++;
+ }
+ }
+
+ lct = linecnt(newmsg);
+ if (lct)
+ printf("(%d%slines) ", lct, seensubj? " " : " more ");
+
+ if (hdrs) {
+ printf("\n-----\n");
+ fclose(newmsg);
+ continue;
+ }
+
+ /*
+ * Ask user for command
+ */
+ if (totty)
+ ask(lct? MORE : (msg==lastmsg? NOMORE : NEXT));
+ else
+ inbuf[0] = 'y';
+ if (totty)
+ signal(SIGTSTP, SIG_DFL);
+cmnd:
+ in = inbuf;
+ switch (*in) {
+ case 'x':
+ /* FALLTHROUGH */
+ case 'X':
+ exit(0);
+ /* NOTREACHED */
+
+ case 'q':
+ /* FALLTHROUGH */
+ case 'Q':
+ quitit = YES;
+ printf("--Postponed--\n");
+ exit(0);
+ /* NOTREACHED */
+
+ case 'n':
+ /* FALLTHROUGH */
+ case 'N':
+ if (msg >= nextmsg) sep = "Flushed";
+ prevmsg = msg;
+ break;
+
+ case 'p':
+ /* FALLTHROUGH */
+ case 'P':
+ use_pager = (*in++ == 'p');
+ /* FALLTHROUGH */
+ case '\n':
+ /* FALLTHROUGH */
+ case 'y':
+ default:
+ if (*in == '-') {
+ msg = prevmsg-1;
+ sep = "replay";
+ break;
+ }
+ if (isdigit(*in)) {
+ msg = next(in);
+ sep = in;
+ break;
+ }
+
+ prmesg(nlines + lct + (seensubj? 1 : 0));
+ prevmsg = msg;
+
+ }
+
+ printf("--%s--\n", sep);
+ sep = "-";
+ if (msg >= nextmsg) {
+ nextmsg = msg + 1;
+ rewind(msgsrc);
+ fprintf(msgsrc, "%d\n", nextmsg);
+ fflush(msgsrc);
+ }
+ if (newmsg)
+ fclose(newmsg);
+ if (quitit)
+ break;
+ }
+
+ /*
+ * Make sure .rc file gets updated
+ */
+ if (--msg >= nextmsg) {
+ nextmsg = msg + 1;
+ rewind(msgsrc);
+ fprintf(msgsrc, "%d\n", nextmsg);
+ fflush(msgsrc);
+ }
+ if (already && !quitit && lastcmd && totty) {
+ /*
+ * save or reply to last message?
+ */
+ msg = prevmsg;
+ ask(NOMORE);
+ if (inbuf[0] == '-' || isdigit(inbuf[0]))
+ goto cmnd;
+ }
+ if (!(already || hush || qopt))
+ printf("No new messages.\n");
+ exit(0);
+ /* NOTREACHED */
+}
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: msgs [fhlopqr] [[-]number]\n");
+ exit(1);
+}
+
+void
+prmesg(int length)
+{
+ FILE *outf;
+ char *env_pager;
+
+ if (use_pager && length > Lpp) {
+ signal(SIGPIPE, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ if ((env_pager = getenv("PAGER")) == NULL) {
+ snprintf(cmdbuf, sizeof(cmdbuf), _PATH_PAGER, Lpp);
+ } else {
+ snprintf(cmdbuf, sizeof(cmdbuf), "%s", env_pager);
+ }
+ outf = popen(cmdbuf, "w");
+ if (!outf)
+ outf = stdout;
+ else
+ setbuf(outf, (char *)NULL);
+ }
+ else
+ outf = stdout;
+
+ if (seensubj)
+ putc('\n', outf);
+
+ while (fgets(inbuf, sizeof inbuf, newmsg)) {
+ fputs(inbuf, outf);
+ if (ferror(outf)) {
+ clearerr(outf);
+ break;
+ }
+ }
+
+ if (outf != stdout) {
+ pclose(outf);
+ signal(SIGPIPE, SIG_DFL);
+ signal(SIGQUIT, SIG_DFL);
+ }
+ else {
+ fflush(stdout);
+ }
+
+ /* force wait on output */
+ tcdrain(fileno(stdout));
+}
+
+void
+onintr(int unused)
+{
+ signal(SIGINT, onintr);
+ if (mailing)
+ unlink(fname);
+ if (sending) {
+ unlink(fname);
+ puts("--Killed--");
+ exit(1);
+ }
+ if (printing) {
+ putchar('\n');
+ if (hdrs)
+ exit(0);
+ sep = "Interrupt";
+ if (newmsg)
+ fseeko(newmsg, (off_t)0, SEEK_END);
+ intrpflg = YES;
+ }
+}
+
+/*
+ * We have just gotten a susp. Suspend and prepare to resume.
+ */
+void
+onsusp(int unused)
+{
+ signal(SIGTSTP, SIG_DFL);
+ sigsetmask(0);
+ kill(0, SIGTSTP);
+ signal(SIGTSTP, onsusp);
+ if (!mailing)
+ longjmp(tstpbuf, 0);
+}
+
+int
+linecnt(FILE *f)
+{
+ off_t oldpos = ftello(f);
+ int l = 0;
+ char lbuf[BUFSIZ];
+
+ while (fgets(lbuf, sizeof lbuf, f))
+ l++;
+ clearerr(f);
+ fseeko(f, oldpos, SEEK_SET);
+ return (l);
+}
+
+int
+next(char *buf)
+{
+ int i;
+ sscanf(buf, "%d", &i);
+ sprintf(buf, "Goto %d", i);
+ return(--i);
+}
+
+void
+ask(const char *prompt)
+{
+ char inch;
+ int n, cmsg, fd;
+ off_t oldpos;
+ FILE *cpfrom, *cpto;
+
+ printf("%s ", prompt);
+ fflush(stdout);
+ intrpflg = NO;
+ (void) fgets(inbuf, sizeof inbuf, stdin);
+ if ((n = strlen(inbuf)) > 0 && inbuf[n - 1] == '\n')
+ inbuf[n - 1] = '\0';
+ if (intrpflg)
+ inbuf[0] = 'x';
+
+ /*
+ * Handle 'mail' and 'save' here.
+ */
+#ifdef __APPLE__
+ if (((inch = inbuf[0]) == 's' || inch == 'm') && !restricted) {
+#else
+ if ((inch = inbuf[0]) == 's' || inch == 'm') {
+#endif /* __APPLE__ */
+ if (inbuf[1] == '-')
+ cmsg = prevmsg;
+ else if (isdigit(inbuf[1]))
+ cmsg = atoi(&inbuf[1]);
+ else
+ cmsg = msg;
+ snprintf(fname, sizeof(fname), "%s/%d", _PATH_MSGS, cmsg);
+
+ oldpos = ftello(newmsg);
+
+ cpfrom = fopen(fname, "r");
+ if (!cpfrom) {
+ printf("Message %d not found\n", cmsg);
+ ask (prompt);
+ return;
+ }
+
+ if (inch == 's') {
+ in = nxtfld((unsigned char *)inbuf);
+ if (*in) {
+ for (n=0; in[n] > ' '; n++) { /* sizeof fname? */
+ fname[n] = in[n];
+ }
+ fname[n] = 0;
+ }
+ else
+ strcpy(fname, "Messages");
+ fd = open(fname, O_RDWR|O_EXCL|O_CREAT|O_APPEND);
+ }
+ else {
+ strcpy(fname, _PATH_TMP);
+ fd = mkstemp(fname);
+ if (fd != -1) {
+ snprintf(cmdbuf, sizeof(cmdbuf), _PATH_MAIL,
+ fname);
+ mailing = YES;
+ }
+ }
+ if (fd == -1 || (cpto = fdopen(fd, "a")) == NULL) {
+ if (fd != -1)
+ close(fd);
+ warn("%s", fname);
+ mailing = NO;
+ fseeko(newmsg, oldpos, SEEK_SET);
+ ask(prompt);
+ return;
+ }
+
+ while ((n = fread(inbuf, 1, sizeof inbuf, cpfrom)))
+ fwrite(inbuf, 1, n, cpto);
+
+ fclose(cpfrom);
+ fclose(cpto);
+ fseeko(newmsg, oldpos, SEEK_SET);/* reposition current message */
+ if (inch == 's')
+ printf("Message %d saved in \"%s\"\n", cmsg, fname);
+ else {
+ system(cmdbuf);
+ unlink(fname);
+ mailing = NO;
+ }
+ ask(prompt);
+ }
+}
+
+void
+gfrsub(FILE *infile)
+{
+ off_t frompos;
+ int count;
+
+ seensubj = seenfrom = NO;
+ local = YES;
+ subj[0] = from[0] = date[0] = 0;
+
+ /*
+ * Is this a normal message?
+ */
+ if (fgets(inbuf, sizeof inbuf, infile)) {
+ if (strncmp(inbuf, "From", 4)==0) {
+ /*
+ * expected form starts with From
+ */
+ seenfrom = YES;
+ frompos = ftello(infile);
+ ptr = from;
+ in = nxtfld((unsigned char *)inbuf);
+ if (*in) {
+ count = sizeof(from) - 1;
+ while (*in && *in > ' ' && count-- > 0) {
+ if (*in == ':' || *in == '@' ||
+ *in == '!')
+ local = NO;
+ *ptr++ = *in++;
+ }
+ }
+ *ptr = 0;
+ if (*(in = nxtfld((unsigned char *)in)))
+ strncpy(date, in, sizeof date);
+ else {
+ date[0] = '\n';
+ date[1] = 0;
+ }
+ }
+ else {
+ /*
+ * not the expected form
+ */
+ rewind(infile);
+ return;
+ }
+ }
+ else
+ /*
+ * empty file ?
+ */
+ return;
+
+ /*
+ * look for Subject line until EOF or a blank line
+ */
+ while (fgets(inbuf, sizeof inbuf, infile)
+ && !(blankline = (inbuf[0] == '\n'))) {
+ /*
+ * extract Subject line
+ */
+ if (!seensubj && strncmp(inbuf, "Subj", 4)==0) {
+ seensubj = YES;
+ frompos = ftello(infile);
+ strncpy(subj, nxtfld((unsigned char *)inbuf), sizeof subj);
+ }
+ }
+ if (!blankline)
+ /*
+ * ran into EOF
+ */
+ fseeko(infile, frompos, SEEK_SET);
+
+ if (!seensubj)
+ /*
+ * for possible use with Mail
+ */
+ strncpy(subj, "(No Subject)\n", sizeof subj);
+}
+
+char *
+nxtfld(unsigned char *s)
+{
+ if (*s) while (*s && !isspace(*s)) s++; /* skip over this field */
+ if (*s) while (*s && isspace(*s)) s++; /* find start of next field */
+ return ((char *)s);
+}
diff --git a/mail_cmds/msgs/pathnames.h b/mail_cmds/msgs/pathnames.h
new file mode 100644
index 0000000..90f23f4
--- /dev/null
+++ b/mail_cmds/msgs/pathnames.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pathnames.h 8.1 (Berkeley) 6/6/93
+ */
+
+#define _PATH_MSGS "/var/msgs"
+#define _PATH_MAIL "/usr/bin/Mail -f %s"
+#define _PATH_PAGER "/usr/bin/more -%d"
+#undef _PATH_TMP
+#define _PATH_TMP "/tmp/msgXXXXXX"