diff options
author | Cameron Katri <me@cameronkatri.com> | 2021-05-09 14:20:58 -0400 |
---|---|---|
committer | Cameron Katri <me@cameronkatri.com> | 2021-05-09 14:20:58 -0400 |
commit | 5fd83771641d15c418f747bd343ba6738d3875f7 (patch) | |
tree | 5abf0f78f680d9837dbd93d4d4c3933bb7509599 /mail_cmds | |
download | apple_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')
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" |