From 5ae330e220636de2b9caa5a69c059adc48b46444 Mon Sep 17 00:00:00 2001 From: David van Moolenbroek Date: Mon, 20 Feb 2017 15:56:15 +0000 Subject: [PATCH] Import NetBSD fmt(1) This requires importing a few files from mail(1) already. Importing the rest of mail(1) is left to future work. Change-Id: If96513a306245cd7fb64660758d0dbd29a36e87c --- distrib/sets/lists/minix-base/mi | 1 + distrib/sets/lists/minix-debug/mi | 1 + distrib/sets/lists/minix-man/mi | 1 + usr.bin/Makefile | 2 +- usr.bin/fmt/Makefile | 12 + usr.bin/fmt/buffer.h | 99 ++++++ usr.bin/fmt/fmt.1 | 113 ++++++ usr.bin/fmt/fmt.c | 555 ++++++++++++++++++++++++++++++ usr.bin/mail/def.h | 468 +++++++++++++++++++++++++ usr.bin/mail/extern.h | 365 ++++++++++++++++++++ usr.bin/mail/head.c | 289 ++++++++++++++++ usr.bin/mail/pathnames.h | 49 +++ usr.bin/mail/rcv.h | 48 +++ 13 files changed, 2002 insertions(+), 1 deletion(-) create mode 100644 usr.bin/fmt/Makefile create mode 100644 usr.bin/fmt/buffer.h create mode 100644 usr.bin/fmt/fmt.1 create mode 100644 usr.bin/fmt/fmt.c create mode 100644 usr.bin/mail/def.h create mode 100644 usr.bin/mail/extern.h create mode 100644 usr.bin/mail/head.c create mode 100644 usr.bin/mail/pathnames.h create mode 100644 usr.bin/mail/rcv.h diff --git a/distrib/sets/lists/minix-base/mi b/distrib/sets/lists/minix-base/mi index 116256723..67ae9e428 100644 --- a/distrib/sets/lists/minix-base/mi +++ b/distrib/sets/lists/minix-base/mi @@ -328,6 +328,7 @@ ./usr/bin/flex++ minix-base ./usr/bin/flex minix-base ./usr/bin/flock minix-base +./usr/bin/fmt minix-base ./usr/bin/fold minix-base ./usr/bin/format minix-base ./usr/bin/fpr minix-base diff --git a/distrib/sets/lists/minix-debug/mi b/distrib/sets/lists/minix-debug/mi index be5e6ee07..99dd9fb3a 100644 --- a/distrib/sets/lists/minix-debug/mi +++ b/distrib/sets/lists/minix-debug/mi @@ -269,6 +269,7 @@ ./usr/libdata/debug/usr/bin/finger.debug minix-debug debug ./usr/libdata/debug/usr/bin/fix.debug minix-debug debug ./usr/libdata/debug/usr/bin/flock.debug minix-debug debug +./usr/libdata/debug/usr/bin/fmt.debug minix-debug debug ./usr/libdata/debug/usr/bin/fold.debug minix-debug debug ./usr/libdata/debug/usr/bin/format.debug minix-debug debug ./usr/libdata/debug/usr/bin/fpr.debug minix-debug debug diff --git a/distrib/sets/lists/minix-man/mi b/distrib/sets/lists/minix-man/mi index 17122db78..3c349835b 100644 --- a/distrib/sets/lists/minix-man/mi +++ b/distrib/sets/lists/minix-man/mi @@ -112,6 +112,7 @@ ./usr/man/man1/flex.1 minix-man ./usr/man/man1/flexdoc.1 minix-man obsolete ./usr/man/man1/flock.1 minix-man +./usr/man/man1/fmt.1 minix-man ./usr/man/man1/fold.1 minix-man ./usr/man/man1/for.1 minix-man obsolete ./usr/man/man1/foreach.1 minix-man diff --git a/usr.bin/Makefile b/usr.bin/Makefile index c397185d2..e9528ee53 100644 --- a/usr.bin/Makefile +++ b/usr.bin/Makefile @@ -10,7 +10,7 @@ SUBDIR= asa \ column comm csplit ctags cut \ deroff dirname du \ env expand \ - false find finger flock fold fpr from \ + false find finger flock fold fmt fpr from \ fsplit ftp genassym gencat \ getopt \ head hexdump id indent infocmp ipcrm ipcs join jot \ diff --git a/usr.bin/fmt/Makefile b/usr.bin/fmt/Makefile new file mode 100644 index 000000000..a794cb17b --- /dev/null +++ b/usr.bin/fmt/Makefile @@ -0,0 +1,12 @@ +# @(#)Makefile 8.1 (Berkeley) 6/6/93 +# $NetBSD: Makefile,v 1.10 2009/04/14 22:15:20 lukem Exp $ + +.include + +PROG= fmt +SRCS= fmt.c head.c +CPPFLAGS+= -DFMT_PROG + +.PATH: ${NETBSDSRCDIR}/usr.bin/mail + +.include diff --git a/usr.bin/fmt/buffer.h b/usr.bin/fmt/buffer.h new file mode 100644 index 000000000..41016e4ea --- /dev/null +++ b/usr.bin/fmt/buffer.h @@ -0,0 +1,99 @@ +/* $NetBSD: buffer.h,v 1.4 2008/04/28 20:24:12 martin Exp $ */ + +/*- + * Copyright (c) 2005 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Christos Zoulas. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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 +#include +#include +#include + +#define BUF_SIZE BUFSIZ +struct buffer { + char *ptr; + char *bptr; + char *eptr; +}; + +static void +buf_init(struct buffer *buf) +{ + buf->ptr = buf->bptr = malloc(BUF_SIZE); + if (buf->ptr == NULL) + err(1, "Cannot allocate buffer"); + buf->eptr = buf->ptr + BUF_SIZE; +} + +static void +buf_end(struct buffer *buf) +{ + free(buf->bptr); +} + +static void +buf_grow(struct buffer *buf, size_t minsize) +{ + ptrdiff_t diff; + size_t len = (buf->eptr - buf->bptr) + + (minsize > BUF_SIZE ? minsize : BUF_SIZE); + char *nptr = realloc(buf->bptr, len); + + if (nptr == NULL) + err(1, "Cannot grow buffer"); + + if (nptr == buf->bptr) { + buf->eptr = buf->bptr + len; + return; + } + + diff = nptr - buf->bptr; + buf->bptr += diff; + buf->eptr = buf->bptr + len; + buf->ptr += diff; +} + +static inline void +buf_putc(struct buffer *buf, char c) +{ + if (buf->ptr >= buf->eptr) + buf_grow(buf, 1); + *buf->ptr++ = c; +} + +static inline void +buf_reset(struct buffer *buf) +{ + buf->ptr = buf->bptr; +} + +static inline char +buf_unputc(struct buffer *buf) +{ + return buf->ptr > buf->bptr ? *--buf->ptr : '\0'; +} diff --git a/usr.bin/fmt/fmt.1 b/usr.bin/fmt/fmt.1 new file mode 100644 index 000000000..623b12431 --- /dev/null +++ b/usr.bin/fmt/fmt.1 @@ -0,0 +1,113 @@ +.\" $NetBSD: fmt.1,v 1.13 2012/06/30 21:31:15 christos Exp $ +.\" +.\" 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. 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. +.\" +.\" @(#)fmt.1 8.1 (Berkeley) 6/6/93 +.\" +.Dd June 31, 2012 +.Dt FMT 1 +.Os +.Sh NAME +.Nm fmt +.Nd simple text formatter +.Sh SYNOPSIS +.Nm +.Op Fl Cr +.Oo +.Ar goal +.Op Ar maximum +.Oc +.Op name ... +.Nm +.Op Fl Cr +.Op Fl g Ar goal +.Op Fl m Ar maximum +.Op Fl w Ar maximum +.Op name ... +.Sh DESCRIPTION +.Nm +is a simple text formatter which reads the concatenation of input +files (or standard input if none are given) and produces on standard +output a version of its input with lines as close to the +.Ar goal +length as possible without exceeding the +.Ar maximum . +The +.Ar goal +length defaults to 65 and the +.Ar maximum +to 75. +The spacing at the beginning of the input lines is preserved in +the output, as are blank lines and interword spacing. +In non raw mode, lines that look like mail headers or begin with +a period are not formatted. +.Pp +.Bl -tag -width ".Fl m Ar maximum" +.It Fl C +instructs +.Nm +to center the text. +.It Fl g Ar goal +New way to set the goal length. +.It Fl m Ar maximum +New way to set the maximum length. +.It Fl w Ar maximum +New way to set the maximum length. +.It Fl r +Raw mode; formats all lines and does not make exceptions for lines +that start with a period or look like mail headers. +.El +.Pp +.Nm +is meant to format mail messages prior to sending, but may also be useful +for other simple tasks. +For instance, within visual mode of the +.Xr ex 1 +editor (e.g., +.Xr vi 1 ) +the command +.Pp +.Dl \&!}fmt +.Pp +will reformat a paragraph, evening the lines. +.Sh SEE ALSO +.Xr mail 1 , +.Xr nroff 1 +.Sh HISTORY +The +.Nm +command appeared in +.Bx 3 . +.\" .Sh AUTHORS +.\" Kurt Shoens +.\" .Pp +.\" Liz Allen (added goal length concept) +.Sh BUGS +The program was designed to be simple and fast \- for more complex +operations, the standard text processors are likely to be more +appropriate. diff --git a/usr.bin/fmt/fmt.c b/usr.bin/fmt/fmt.c new file mode 100644 index 000000000..c420b2659 --- /dev/null +++ b/usr.bin/fmt/fmt.c @@ -0,0 +1,555 @@ +/* $NetBSD: fmt.c,v 1.32 2012/06/30 21:31:15 christos 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. 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 +#ifndef lint +__COPYRIGHT("@(#) Copyright (c) 1980, 1993\ + The Regents of the University of California. All rights reserved."); +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)fmt.c 8.1 (Berkeley) 7/20/93"; +#endif +__RCSID("$NetBSD: fmt.c,v 1.32 2012/06/30 21:31:15 christos Exp $"); +#endif /* not lint */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "buffer.h" + +/* + * fmt -- format the concatenation of input files or standard input + * onto standard output. Designed for use with Mail ~| + * + * Syntax : fmt [ goal [ max ] ] [ name ... ] + * Authors: Kurt Shoens (UCB) 12/7/78; + * Liz Allen (UMCP) 2/24/83 [Addition of goal length concept]. + */ + +/* LIZ@UOM 6/18/85 --New variables goal_length and max_length */ +#define GOAL_LENGTH 65 +#define MAX_LENGTH 75 +static size_t goal_length; /* Target or goal line length in output */ +static size_t max_length; /* Max line length in output */ +static size_t pfx; /* Current leading blank count */ +static int raw; /* Don't treat mail specially */ +static int lineno; /* Current input line */ +static int mark; /* Last place we saw a head line */ +static int center; +static struct buffer outbuf; + +static const char *headnames[] = {"To", "Subject", "Cc", 0}; + +static void usage(void) __dead; +static int getnum(const char *, const char *, size_t *, int); +static void fmt(FILE *); +static int ispref(const char *, const char *); +static void leadin(void); +static void oflush(void); +static void pack(const char *, size_t); +static void prefix(const struct buffer *, int); +static void split(const char *, int); +static void tabulate(struct buffer *); + + +int ishead(const char *); + +/* + * Drive the whole formatter by managing input files. Also, + * cause initialization of the output stuff and flush it out + * at the end. + */ + +int +main(int argc, char **argv) +{ + FILE *fi; + int errs = 0; + int compat = 1; + int c; + + goal_length = GOAL_LENGTH; + max_length = MAX_LENGTH; + buf_init(&outbuf); + lineno = 1; + mark = -10; + + setprogname(*argv); + (void)setlocale(LC_ALL, ""); + + while ((c = getopt(argc, argv, "Cg:m:rw:")) != -1) + switch (c) { + case 'C': + center++; + break; + case 'g': + (void)getnum(optarg, "goal", &goal_length, 1); + compat = 0; + break; + case 'm': + case 'w': + (void)getnum(optarg, "max", &max_length, 1); + compat = 0; + break; + case 'r': + raw++; + break; + default: + usage(); + } + + argc -= optind; + argv += optind; + + /* + * compatibility with old usage. + */ + if (compat && argc > 0 && getnum(*argv, "goal", &goal_length, 0)) { + argv++; + argc--; + if (argc > 0 && getnum(*argv, "max", &max_length, 0)) { + argv++; + argc--; + } + } + + if (max_length <= goal_length) { + errx(1, "Max length (%zu) must be greater than goal " + "length (%zu)", max_length, goal_length); + } + if (argc == 0) { + fmt(stdin); + oflush(); + return 0; + } + for (;argc; argc--, argv++) { + if ((fi = fopen(*argv, "r")) == NULL) { + warn("Cannot open `%s'", *argv); + errs++; + continue; + } + fmt(fi); + (void)fclose(fi); + } + oflush(); + buf_end(&outbuf); + return errs; +} + +static void +usage(void) +{ + (void)fprintf(stderr, + "Usage: %s [-Cr] [-g ] [-m|w ] [..]\n" + "\t %s [-Cr] [] [] []\n", + getprogname(), getprogname()); + exit(1); +} + +static int +getnum(const char *str, const char *what, size_t *res, int badnum) +{ + unsigned long ul; + char *ep; + + errno = 0; + ul = strtoul(str, &ep, 0); + if (*str != '\0' && *ep == '\0') { + if ((errno == ERANGE && ul == ULONG_MAX) || ul > SIZE_T_MAX) + errx(1, "%s number `%s' too big", what, str); + *res = (size_t)ul; + return 1; + } else if (badnum) + errx(1, "Bad %s number `%s'", what, str); + + return 0; +} + +/* + * Read up characters from the passed input file, forming lines, + * doing ^H processing, expanding tabs, stripping trailing blanks, + * and sending each line down for analysis. + */ +static void +fmt(FILE *fi) +{ + struct buffer lbuf, cbuf; + char *cp, *cp2; + int c, add_space; + size_t len, col, i; + + if (center) { + for (;;) { + cp = fgetln(fi, &len); + if (!cp) + return; + + /* skip over leading space */ + while (len > 0) { + if (!isspace((unsigned char)*cp)) + break; + cp++; + len--; + } + + /* clear trailing space */ + while (len > 0) { + if (!isspace((unsigned char)cp[len-1])) + break; + len--; + } + + if (len == 0) { + /* blank line */ + (void)putchar('\n'); + continue; + } + + if (goal_length > len) { + for (i = 0; i < (goal_length - len) / 2; i++) { + (void)putchar(' '); + } + } + for (i = 0; i < len; i++) { + (void)putchar(cp[i]); + } + (void)putchar('\n'); + } + } + + buf_init(&lbuf); + buf_init(&cbuf); + c = getc(fi); + + while (c != EOF) { + /* + * Collect a line, doing ^H processing. + * Leave tabs for now. + */ + buf_reset(&lbuf); + while (c != '\n' && c != EOF) { + if (c == '\b') { + (void)buf_unputc(&lbuf); + c = getc(fi); + continue; + } + if(!(isprint(c) || c == '\t' || c >= 160)) { + c = getc(fi); + continue; + } + buf_putc(&lbuf, c); + c = getc(fi); + } + buf_putc(&lbuf, '\0'); + (void)buf_unputc(&lbuf); + add_space = c != EOF; + + /* + * Expand tabs on the way. + */ + col = 0; + cp = lbuf.bptr; + buf_reset(&cbuf); + while ((c = *cp++) != '\0') { + if (c != '\t') { + col++; + buf_putc(&cbuf, c); + continue; + } + do { + buf_putc(&cbuf, ' '); + col++; + } while ((col & 07) != 0); + } + + /* + * Swipe trailing blanks from the line. + */ + for (cp2 = cbuf.ptr - 1; cp2 >= cbuf.bptr && *cp2 == ' '; cp2--) + continue; + cbuf.ptr = cp2 + 1; + buf_putc(&cbuf, '\0'); + (void)buf_unputc(&cbuf); + prefix(&cbuf, add_space); + if (c != EOF) + c = getc(fi); + } + buf_end(&cbuf); + buf_end(&lbuf); +} + +/* + * Take a line devoid of tabs and other garbage and determine its + * blank prefix. If the indent changes, call for a linebreak. + * If the input line is blank, echo the blank line on the output. + * Finally, if the line minus the prefix is a mail header, try to keep + * it on a line by itself. + */ +static void +prefix(const struct buffer *buf, int add_space) +{ + const char *cp; + const char **hp; + size_t np; + int h; + + if (buf->ptr == buf->bptr) { + oflush(); + (void)putchar('\n'); + return; + } + for (cp = buf->bptr; *cp == ' '; cp++) + continue; + np = cp - buf->bptr; + + /* + * The following horrible expression attempts to avoid linebreaks + * when the indent changes due to a paragraph. + */ + if (np != pfx && (np > pfx || abs((int)(pfx - np)) > 8)) + oflush(); + if (!raw) { + if ((h = ishead(cp)) != 0) { + oflush(); + mark = lineno; + } + if (lineno - mark < 3 && lineno - mark > 0) + for (hp = &headnames[0]; *hp != NULL; hp++) + if (ispref(*hp, cp)) { + h = 1; + oflush(); + break; + } + if (!h && (h = (*cp == '.'))) + oflush(); + } else + h = 0; + pfx = np; + if (h) { + pack(cp, (size_t)(buf->ptr - cp)); + oflush(); + } else + split(cp, add_space); + lineno++; +} + +/* + * Split up the passed line into output "words" which are + * maximal strings of non-blanks with the blank separation + * attached at the end. Pass these words along to the output + * line packer. + */ +static void +split(const char line[], int add_space) +{ + const char *cp; + struct buffer word; + size_t wlen; + + buf_init(&word); + cp = line; + while (*cp) { + buf_reset(&word); + wlen = 0; + + /* + * Collect a 'word,' allowing it to contain escaped white + * space. + */ + while (*cp && *cp != ' ') { + if (*cp == '\\' && isspace((unsigned char)cp[1])) + buf_putc(&word, *cp++); + buf_putc(&word, *cp++); + wlen++; + } + + /* + * Guarantee a space at end of line. Two spaces after end of + * sentence punctuation. + */ + if (*cp == '\0' && add_space) { + buf_putc(&word, ' '); + if (strchr(".:!", cp[-1])) + buf_putc(&word, ' '); + } + while (*cp == ' ') + buf_putc(&word, *cp++); + + buf_putc(&word, '\0'); + (void)buf_unputc(&word); + + pack(word.bptr, wlen); + } + buf_end(&word); +} + +/* + * Output section. + * Build up line images from the words passed in. Prefix + * each line with correct number of blanks. + * + * At the bottom of this whole mess, leading tabs are reinserted. + */ + +/* + * Pack a word onto the output line. If this is the beginning of + * the line, push on the appropriately-sized string of blanks first. + * If the word won't fit on the current line, flush and begin a new + * line. If the word is too long to fit all by itself on a line, + * just give it its own and hope for the best. + * + * LIZ@UOM 6/18/85 -- If the new word will fit in at less than the + * goal length, take it. If not, then check to see if the line + * will be over the max length; if so put the word on the next + * line. If not, check to see if the line will be closer to the + * goal length with or without the word and take it or put it on + * the next line accordingly. + */ + +static void +pack(const char *word, size_t wlen) +{ + const char *cp; + size_t s, t; + + if (outbuf.bptr == outbuf.ptr) + leadin(); + /* + * LIZ@UOM 6/18/85 -- change condition to check goal_length; s is the + * length of the line before the word is added; t is now the length + * of the line after the word is added + */ + s = outbuf.ptr - outbuf.bptr; + t = wlen + s; + if ((t <= goal_length) || ((t <= max_length) && + (s <= goal_length) && (t - goal_length <= goal_length - s))) { + /* + * In like flint! + */ + for (cp = word; *cp;) + buf_putc(&outbuf, *cp++); + return; + } + if (s > pfx) { + oflush(); + leadin(); + } + for (cp = word; *cp;) + buf_putc(&outbuf, *cp++); +} + +/* + * If there is anything on the current output line, send it on + * its way. Reset outbuf. + */ +static void +oflush(void) +{ + if (outbuf.bptr == outbuf.ptr) + return; + buf_putc(&outbuf, '\0'); + (void)buf_unputc(&outbuf); + tabulate(&outbuf); + buf_reset(&outbuf); +} + +/* + * Take the passed line buffer, insert leading tabs where possible, and + * output on standard output (finally). + */ +static void +tabulate(struct buffer *buf) +{ + char *cp; + size_t b, t; + + /* + * Toss trailing blanks in the output line. + */ + for (cp = buf->ptr - 1; cp >= buf->bptr && *cp == ' '; cp--) + continue; + *++cp = '\0'; + + /* + * Count the leading blank space and tabulate. + */ + for (cp = buf->bptr; *cp == ' '; cp++) + continue; + b = cp - buf->bptr; + t = b / 8; + b = b % 8; + if (t > 0) + do + (void)putchar('\t'); + while (--t); + if (b > 0) + do + (void)putchar(' '); + while (--b); + while (*cp) + (void)putchar(*cp++); + (void)putchar('\n'); +} + +/* + * Initialize the output line with the appropriate number of + * leading blanks. + */ +static void +leadin(void) +{ + size_t b; + + buf_reset(&outbuf); + + for (b = 0; b < pfx; b++) + buf_putc(&outbuf, ' '); +} + +/* + * Is s1 a prefix of s2?? + */ +static int +ispref(const char *s1, const char *s2) +{ + + while (*s1++ == *s2) + continue; + return *s1 == '\0'; +} diff --git a/usr.bin/mail/def.h b/usr.bin/mail/def.h new file mode 100644 index 000000000..f43e2059e --- /dev/null +++ b/usr.bin/mail/def.h @@ -0,0 +1,468 @@ +/* $NetBSD: def.h,v 1.28 2014/10/18 08:33:30 snj 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. 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 + * $NetBSD: def.h,v 1.28 2014/10/18 08:33:30 snj Exp $ + */ + +/* + * Mail -- a mail program + * + * Author: Kurt Shoens (UCB) March 25, 1978 + */ + +#ifndef __DEF_H__ +#define __DEF_H__ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pathnames.h" + +#define APPEND /* New mail goes to end of mailbox */ + +#define COMMENT_CHAR '#' /* Comment character when sourcing */ +#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 MAXARGC 1024 /* Maximum list of raw strings */ +#define MAXEXP 25 /* Maximum expansion of aliases */ + +#define PUBLIC /* make it easy to find the entry points */ + +/* + * User environment variable names. + * See complete.h, mime.h, and thread.h for names specific to those modules. + */ +#define ENAME_INDENT_POSTSCRIPT "indentpostscript" +#define ENAME_INDENT_PREAMBLE "indentpreamble" +#define ENAME_APPEND "append" +#define ENAME_ASK "ask" +#define ENAME_ASKBCC "askbcc" +#define ENAME_ASKCC "askcc" +#define ENAME_ASKSUB "asksub" +#define ENAME_AUTOINC "autoinc" +#define ENAME_AUTOPRINT "autoprint" +#define ENAME_CRT "crt" +#define ENAME_DEAD "DEAD" +#define ENAME_DEBUG "debug" +#define ENAME_DONTSENDEMPTY "dontsendempty" +#define ENAME_DOT "dot" +#define ENAME_EDITOR "EDITOR" +#define ENAME_ENABLE_PIPES "enable-pipes" +#define ENAME_ESCAPE "escape" +#define ENAME_FOLDER "folder" +#define ENAME_HEADER_FORMAT "header-format" +#define ENAME_HOLD "hold" +#define ENAME_IGNORE "ignore" +#define ENAME_IGNOREEOF "ignoreeof" +#define ENAME_INDENTPREFIX "indentprefix" +#define ENAME_INTERACTIVE "interactive" +#define ENAME_KEEP "keep" +#define ENAME_KEEPSAVE "keepsave" +#define ENAME_LISTER "LISTER" +#define ENAME_MBOX "MBOX" +#define ENAME_METOO "metoo" +#define ENAME_NOHEADER "noheader" +#define ENAME_NOSAVE "nosave" +#define ENAME_PAGE_ALSO "page-also" +#define ENAME_PAGER "PAGER" +#define ENAME_PAGER_OFF "pager-off" +#define ENAME_PROMPT "prompt" +#define ENAME_QUIET "quiet" +#define ENAME_RECORD "record" +#define ENAME_REGEX_SEARCH "regex-search" +#define ENAME_REPLYALL "Replyall" +#define ENAME_REPLYASRECIPIENT "ReplyAsRecipient" +#define ENAME_SCREEN "screen" +#define ENAME_SCREENHEIGHT "screenheight" +#define ENAME_SCREENWIDTH "screenwidth" +#define ENAME_SEARCHHEADERS "searchheaders" +#define ENAME_SENDMAIL "sendmail" +#define ENAME_SHELL "SHELL" +#define ENAME_SHOW_RCPT "show-rcpt" +#define ENAME_SMOPTS_VERIFY "smopts-verify" +#define ENAME_TOPLINES "toplines" +#define ENAME_VERBOSE "verbose" +#define ENAME_VISUAL "VISUAL" + +#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_lines; /* Lines in the message */ + off_t m_size; /* Bytes in the message */ + long m_blines; /* Body (non-header) lines */ + + /* + * threading fields + */ + int m_index; /* message index in this thread */ + int m_depth; /* depth in thread */ + struct message *m_flink; /* link to next message */ + struct message *m_blink; /* link to previous message */ + struct message *m_clink; /* link to child of this message */ + struct message *m_plink; /* link to parent of thread */ +}; +typedef struct mime_info mime_info_t; /* phantom structure only to attach.c */ + +/* + * 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 MMODIFY (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 */ +#define MTAGGED (1<<11) /* message has been tagged */ + +/* + * Given a file address, determine the block number it represents. + */ +#define blockof(off) ((int) ((off) / 4096)) +#define blkoffsetof(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)(void *); /* Implementor of the command */ + int c_pipe; /* Pipe output through the pager */ +# define C_PIPE_PAGER 1 /* enable use of pager */ +# define C_PIPE_CRT 2 /* use the pager if CRT is defined */ +# define C_PIPE_SHELL 4 /* enable shell pipes */ +#ifdef USE_EDITLINE + const char *c_complete; /* String describing completion */ +#endif + 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 0x010 /* Autoprint dot after command */ +#define I 0x020 /* Interactive command bit */ +#define M 0x040 /* Legal from send mode bit */ +#define W 0x080 /* Illegal when read only bit */ +#define F 0x100 /* Is a conditional command */ +#define T 0x200 /* Is a transparent command */ +#define R 0x400 /* Cannot be called from collect */ +#define ARGTYPE_MASK ~(P|I|M|W|F|T|R) + +/* + * 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 0x001 /* Grab To: line */ +#define GSUBJECT 0x002 /* Likewise, Subject: line */ +#define GCC 0x004 /* And the Cc: line */ +#define GBCC 0x008 /* And also the Bcc: line */ +#define GSMOPTS 0x010 /* Grab the sendmail options */ +#define GMISC 0x020 /* miscellaneous extra fields for sending */ +#ifdef MIME_SUPPORT +#define GMIME 0x040 /* mime flag */ +#endif +#define GMASK (GTO | GSUBJECT | GCC | GBCC | GSMOPTS) + /* Mask of places from whence */ + +#define GNL 0x100 /* Print blank line after */ +#define GDEL 0x200 /* Entity removed from list */ +#define GCOMMA 0x400 /* detract puts in commas */ + +#ifdef MIME_SUPPORT +/* + * Structure of MIME content. + */ +struct Content { + const char *C_type; /* content type */ + const char *C_encoding; /* content transfer encoding */ + const char *C_disposition; /* content disposition */ + const char *C_description; /* content description */ + const char *C_id; /* content id */ +}; +/* Header strings corresponding to the above Content fields. */ +#define MIME_HDR_TYPE "Content-Type" +#define MIME_HDR_ENCODING "Content-Transfer-Encoding" +#define MIME_HDR_DISPOSITION "Content-Disposition" +#define MIME_HDR_ID "Content-ID" +#define MIME_HDR_DESCRIPTION "Content-Description" +#define MIME_HDR_VERSION "MIME-Version" +/* the value of the MIME-Version field */ +#define MIME_VERSION "1.0" + +typedef enum { + ATTACH_INVALID = 0, /* do not use! */ + ATTACH_FNAME = 1, + ATTACH_MSG = 2, + ATTACH_FILENO = 3 +} attach_t; + +/* + * Structure of a MIME attachment. + */ +struct attachment { + struct attachment *a_flink; /* Forward link in list. */ + struct attachment *a_blink; /* Backward list link */ + + attach_t a_type; /* attachment type */ +#if 1 + union { + char *u_name; /* file name */ + struct message *u_msg; /* message */ + int u_fileno; /* file number */ + } a_u; + + #define a_name a_u.u_name + #define a_msg a_u.u_msg + #define a_fileno a_u.u_fileno +#else + char *a_name; /* file name */ + struct message *a_msg; /* message */ + int a_fileno; /* file number */ +#endif + + struct Content a_Content; /* MIME content strings */ +}; +#endif /* MIME_SUPPORT */ + +/* + * Structure used to pass about the current + * state of the user-typed message header. + */ + +struct header { + struct name *h_to; /* Dynamic "To:" string */ + char *h_subject; /* Subject string */ + struct name *h_cc; /* Carbon copies string */ + struct name *h_bcc; /* Blind carbon copies */ + struct name *h_smopts; /* Sendmail options */ + char *h_in_reply_to; /* In-Reply-To: field */ + struct name *h_references; /* References: field */ + struct name *h_extra; /* extra header fields */ +#ifdef MIME_SUPPORT + char *h_mime_boundary; /* MIME multipart boundary string */ + struct Content h_Content; /* MIME content for message */ + struct attachment *h_attach; /* MIME attachments */ +#endif +}; + +/* + * 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 its 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. */ +}; + +struct smopts_s { + struct smopts_s *s_link; /* Link to next smopts_s in list */ + char *s_name; /* Name of this smopts_s */ + struct name *s_smopts; /* sendmail options name list */ +}; + +/* + * Structure of the hash table of ignored header fields + */ +struct ignoretab { + size_t 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]; +}; + +/* + * Constants for conditional commands. These control whether we + * should be executing commands or not. + */ +struct cond_stack_s { + struct cond_stack_s *c_next; + int c_cond; +}; +#define CNONE 0x00 /* Execute everything */ +#define CSKIP 0x01 /* Do not execute commands */ +#define CIF 0x02 /* Inside if/endif block */ +#define CELSE 0x04 /* The last conditional was else */ +#define CIGN 0x08 /* Conditional in a skipped block */ + +enum mailmode_e { + mm_receiving, /* receiving mail mode */ + mm_sending, /* sending mail mode */ + mm_hdrsonly /* headers only mode */ +}; + +/* + * 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)); \ +} + +/* + * White Space (WSP) as specified in see RFC 2822. + * + * NOTE: Use this in place of isblank() so it is inline. Also, unlike + * the table implemented ctype(3) routines, this does not have input + * range issues caused by sign extensions. + * + * See mime_header.h for the related is_FWS(). + */ +static inline int +is_WSP(int c) +{ + return c == ' ' || c == '\t'; +} + +static inline char * +skip_WSP(const char *cp) +{ + while (is_WSP(*cp)) + cp++; + return __UNCONST(cp); +} + +static inline char * +skip_space(char *p) +{ + while (isspace((unsigned char)*p)) + p++; + return p; +} + +/* + * strip trailing white space + */ +static inline char * +strip_WSP(char *line) +{ + char *cp; + + cp = line + strlen(line) - 1; + while (cp >= line && is_WSP(*cp)) + cp--; + *++cp = '\0'; + return cp; +} + +#endif /* __DEF_H__ */ diff --git a/usr.bin/mail/extern.h b/usr.bin/mail/extern.h new file mode 100644 index 000000000..95dee1533 --- /dev/null +++ b/usr.bin/mail/extern.h @@ -0,0 +1,365 @@ +/* $NetBSD: extern.h,v 1.33 2014/12/16 19:30:24 christos Exp $ */ + +/*- + * 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. 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 + * $NetBSD: extern.h,v 1.33 2014/12/16 19:30:24 christos Exp $ + */ + +#ifndef __EXTERN_H__ +#define __EXTERN_H__ + +/* + * from cmd1.c + */ +int More(void *); +int Type(void *); +int folders(void *); +int from(void *); +int headers(void *); +int inc(void *); +int mboxit(void *); +int more(void *); +int pcmdlist(void *); +int pdot(void *); +int pipecmd(void *); +int scroll(void *); +int stouch(void *); +int top(void *); +int type(void *); +#ifdef MIME_SUPPORT +int page(void *); +int Page(void *); +int print(void *); +int Print(void *); +int view(void *); +int View(void *); +#endif +/* XXX - should these be elsewhere? */ +void printhead(int); +char * sget_msgnum(struct message *, struct message *); +void show_msgnum(FILE *, struct message *, struct message *); + +/* + * from cmd2.c + */ +int Detach(void *); +int Save(void *); +int clobber(void *); +int copycmd(void *); +int core(void *); +int delete(void *); +int deltype(void *); +int detach(void *); +int igfield(void *); +int next(void *); +int retfield(void *); +int save(void *); +int saveigfield(void *); +int saveretfield(void *); +int swrite(void *); +int undeletecmd(void *); + +/* + * from cmd3.c + */ +int Respond(void *); +int alternates(void *); +int bounce(void *); +int dosh(void *); +int echo(void *); +int elsecmd(void *); +int endifcmd(void *); +int file(void *); +int bounce(void *); +int forward(void *); +int group(void *); +int help(void *); +int ifcmd(void *); +int ifdefcmd(void *v); +int ifndefcmd(void *v); +int markread(void *); +int messize(void *); +int null(void *); +int preserve(void *); +int respond(void *); +int rexit(void *); +int schdir(void *); +int set(void *); +int shell(void *); +int show(void *); +int unalias(void *); +int unread(void *); +int unset(void *); +/* XXX - Should this be elsewhere? */ +void sort(const char **); + +/* + * from cmd4.c + */ +struct smopts_s *findsmopts(const char *, int); +int smoptscmd(void *); +int unsmoptscmd(void *); +int Header(void *); + +/* + * from cmdtab.c + */ +extern const struct cmd cmdtab[]; + +/* + * from collect.c + */ +FILE * collect(struct header *, int); +void savedeadletter(FILE *); + +/* + * from dotlock.c + */ +int dot_lock(const char *, int, FILE *, const char *); +void dot_unlock(const char *); + +/* + * from edit.c + */ +int editor(void *); +int visual(void *); +FILE * run_editor(FILE *, off_t, int, int); + +/* + * from fio.c + */ +const char *expand(const char *); +off_t fsize(FILE *); +const char *getdeadletter(void); +int getfold(char *, size_t); +#ifdef USE_EDITLINE +#define readline xreadline /* readline() is defined in libedit */ +#endif +int readline(FILE *, char *, int, int); +int putline(FILE *, const char *, int); +int rm(char *); +FILE * setinput(const struct message *); +void setptr(FILE *, off_t); + +/* + * from getname.c + */ +const char *getname(uid_t); +int getuserid(char []); + +/* + * from head.c + */ +int ishead(const char []); +void parse(const char [], struct headline *, char []); + +/* + * from lex.c + */ +void announce(void); +void commands(void); +enum execute_contxt_e { ec_normal, ec_composing, ec_autoprint }; +int execute(char [], enum execute_contxt_e); +int incfile(void); +const struct cmd *lex(char []); +void load(const char *); +int newfileinfo(int); +int pversion(void *); +int setfile(const char *); +char * shellpr(char *); +char * get_cmdname(char *); + +/* + * from list.c + */ +int first(int, int); +int get_Hflag(char **); +int getmsglist(char *, int *, int); +int getrawlist(const char [], char **, int); +int show_headers_and_exit(int) __dead; + +/* + * from main.c + */ +struct name *lexpand(char *, int); +void setscreensize(void); +int main(int, char **); + +/* + * from names.c + */ +struct name *cat(struct name *, struct name *); +int count(struct name *); +struct name *delname(struct name *, char []); +char * detract(struct name *, int); +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 *); +const char ** unpack(struct name *, struct name *); +struct name * usermap(struct name *); +#if 0 +void prettyprint(struct name *); /* commented out? */ +#endif + +/* + * from popen.c + */ +int Fclose(FILE *); +FILE * Fdopen(int, const char *); +FILE * Fopen(const char *, const char *); +int Pclose(FILE *); +FILE * Popen(const char *, const char *); +void close_all_files(void); +void close_top_files(FILE *); +void free_child(int); +void prepare_child(sigset_t *, int, int); +FILE * last_registered_file(int); +void register_file(FILE *, int, int); +int run_command(const char *, sigset_t *, int, int, ...); +void sigchild(int); +int start_command(const char *, sigset_t *, int, int, ...); +int wait_child(int); +#ifdef MIME_SUPPORT +void flush_files(FILE *, int); +#endif + +/* + * from quit.c + */ +void quit(jmp_buf); +int quitcmd(void *); + +/* + * from send.c + */ +#ifndef MIME_SUPPORT +# define sendmessage(a,b,c,d,e) legacy_sendmessage(a,b,c,d) +# define mail(a,b,c,d,e,f) legacy_mail(a,b,c,d,e) +#endif +int sendmessage(struct message *, FILE *, struct ignoretab *, const char *, struct mime_info *); +int mail(struct name *, struct name *, struct name *, struct name *, char *, struct attachment *); +void mail1(struct header *, int); +void mail2(FILE *, const char **); +int puthead(struct header *, FILE *, int); +int sendmail(void *); + +/* + * from strings.c + */ +void * csalloc(size_t, size_t); +void * salloc(size_t); +void sreset(void); +void spreserve(void); + +/* + * from support.c + */ +void add_ignore(const char *, struct ignoretab *); +void alter(char *); +int argcount(char **); +int blankline(char []); +char * copy(char *, char *); +char * hfield(const char [], const struct message *); +int isdir(const char []); +int isign(const char *, struct ignoretab []); +void istrcpy(char *, const char *); +int member(char *, struct ignoretab *); +char * nameof(struct message *, int); +int sasprintf(char **ret, const char *format, ...) __printflike(2, 3); +char * savestr(const char *); +struct message *set_m_flag(int, int, int); +char * skin(char *); +int source(void *); +void touch(struct message *); +int unstack(void); +int upcase(int); +void cathelp(const char *); + +/* + * from temp.c + */ +void tinit(void); + +/* + * from tty.c + */ +int grabh(struct header *, int); + +/* + * from vars.c + */ +void assign(const char [], const char []); +struct grouphead * findgroup(const char []); +int hash(const char *); +struct var * lookup(const char []); +void printgroup(const char []); +void v_free(char *); +char * value(const char []); +char * vcopy(const char []); + +/* + * from v7.local.c + */ +void demail(void); +void findmail(const char *, char *, size_t); +const char *username(void); + +/* + * from version.c + */ +extern const char *version; + + +#ifndef THREAD_SUPPORT +/* + * Specials from fio.c (if THREAD_SUPPORT is not defined). + * With THREAD_SUPPORT, they live in thread.c. + */ +struct message *next_message(struct message *); +struct message *prev_message(struct message *); +struct message *get_message(int); +int get_msgnum(struct message *); +int get_msgCount(void); + +/* we remap these commands */ +# define get_abs_msgCount get_msgCount +# define get_abs_message(a) get_message(a) +# define next_abs_message(a) next_message(a) + +/* we trash these commands */ +# define do_recursion() 0 +# define thread_recursion(mp,fn,args) fn(mp,args) +# define thread_fix_old_links(nmessage,message,omsgCount) +# define thread_fix_new_links(message,omsgCount,msgCount) +#endif /* THREAD_SUPPORT */ + +#endif /* __EXTERN_H__ */ diff --git a/usr.bin/mail/head.c b/usr.bin/mail/head.c new file mode 100644 index 000000000..bdb59624c --- /dev/null +++ b/usr.bin/mail/head.c @@ -0,0 +1,289 @@ +/* $NetBSD: head.c,v 1.24 2013/01/16 15:21:42 christos 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. 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 +#ifndef lint +#if 0 +static char sccsid[] = "@(#)head.c 8.2 (Berkeley) 4/20/95"; +#else +__RCSID("$NetBSD: head.c,v 1.24 2013/01/16 15:21:42 christos Exp $"); +#endif +#endif /* not lint */ + +#include "rcv.h" +#include "extern.h" + +/* + * Mail -- a mail program + * + * Routines for processing and detecting headlines. + */ + +/* + * Match the given string (cp) against the given template (tp). + * Return 1 if they match, 0 if they don't + */ +static int +cmatch(const char *cp, const char *tp) +{ + + while (*cp && *tp) + 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 ':': + if (*cp++ != ':') + return 0; + break; + case 'N': + if (*cp++ != '\n') + return 0; + break; + case '+': + if (*cp != '+' && *cp != '-') + return 0; + cp++; + break; + } + if (*cp || *tp) + return 0; + return 1; +} + +/* + * 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. + */ + +/* + * 'A' An upper case char + * 'a' A lower case char + * ' ' A space + * '0' A digit + * 'O' An optional digit or space + * ':' A colon + * 'N' A new line + * '+' A plus or minus sign + */ +static struct cmatch_data { + size_t tlen; + char const *tdata; +} const cmatch_data[] = { +#define TSZ(a) (sizeof(a) - 1), a + { TSZ("Aaa Aaa O0 00:00:00 0000") }, /* BSD ctype */ + { TSZ("Aaa Aaa O0 00:00 0000") }, /* SysV ctype */ + { TSZ("Aaa Aaa O0 00:00:00 AAA 0000") }, /* BSD tmztype */ + { TSZ("Aaa Aaa O0 00:00 AAA 0000") }, /* SysV tmztype */ + /* + * RFC 822-alike From_ lines do not conform to RFC 4155, but seem to + * be used in the wild by UW-imap (MBX format plus) + */ + { TSZ("Aaa Aaa O0 00:00:00 0000 +0000") }, /* RFC822, UT offset */ + /* + * RFC 822 with zone spec: + * 1. military, + * 2. UT, + * 3. north america time zone strings + * note that 1. is strictly speaking not correct as some letters are + * not used + */ + { TSZ("Aaa Aaa O0 00:00:00 0000 A") }, + { TSZ("Aaa Aaa O0 00:00:00 0000 AA") }, + { TSZ("Aaa Aaa O0 00:00:00 0000 AAA") }, + { 0, NULL }, +}; + +static int +isdate(const char date[]) +{ + static size_t cmatch_minlen = 0; + struct cmatch_data const *cmdp; + size_t dl = strlen(date); + + if (cmatch_minlen == 0) + for (cmdp = cmatch_data; cmdp->tdata != NULL; ++cmdp) + cmatch_minlen = MIN(cmatch_minlen, cmdp->tlen); + + if (dl < cmatch_minlen) + return 0; + + for (cmdp = cmatch_data; cmdp->tdata != NULL; ++cmdp) + if (dl == cmdp->tlen && cmatch(date, cmdp->tdata)) + return 1; + + return 0; +} + +static void +fail(const char linebuf[], const char reason[]) +{ +#ifndef FMT_PROG + if (debug) + (void)fprintf(stderr, "\"%s\"\nnot a header because %s\n", + linebuf, reason); +#endif +} + +/* + * 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. + */ +static const char * +nextword(const char *wp, char *wbuf) +{ + if (wp == NULL) { + *wbuf = 0; + return NULL; + } + while (*wp && !is_WSP(*wp)) { + *wbuf++ = *wp; + if (*wp++ == '"') { + while (*wp && *wp != '"') + *wbuf++ = *wp++; + if (*wp == '"') + *wbuf++ = *wp++; + } + } + *wbuf = '\0'; + wp = skip_WSP(wp); + if (*wp == '\0') + return NULL; + return wp; +} + +/* + * 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. + */ +static char * +copyin(const char *src, char **space) +{ + char *cp; + char *begin; + + begin = cp = *space; + while ((*cp++ = *src++) != '\0') + continue; + *space = cp; + return begin; +} + +/* + * 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. + * + * XXX - line[], pbuf[], and word[] must be LINESIZE in length or + * overflow can occur in nextword() or copyin(). + */ +PUBLIC void +parse(const char line[], struct headline *hl, char pbuf[]) +{ + const char *cp; + char *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); + cp = nextword(cp, word); + if (*word) + hl->l_from = copyin(word, &sp); + if (cp != NULL && cp[0] == 't' && cp[1] == 't' && cp[2] == 'y') { + cp = nextword(cp, word); + hl->l_tty = copyin(word, &sp); + } + if (cp != NULL) + hl->l_date = copyin(cp, &sp); +} + +/* + * See if the passed line buffer is a mail header. + * Return true if yes. Note the extreme pains to + * accommodate all funny formats. + */ +PUBLIC int +ishead(const char linebuf[]) +{ + const char *cp; + struct headline hl; + char parbuf[LINESIZE]; + + cp = linebuf; + if (*cp++ != 'F' || *cp++ != 'r' || *cp++ != 'o' || *cp++ != 'm' || + *cp++ != ' ') + return 0; + parse(linebuf, &hl, parbuf); + if (hl.l_from == NULL || hl.l_date == NULL) { + fail(linebuf, "No from or 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; +} diff --git a/usr.bin/mail/pathnames.h b/usr.bin/mail/pathnames.h new file mode 100644 index 000000000..6866f6d83 --- /dev/null +++ b/usr.bin/mail/pathnames.h @@ -0,0 +1,49 @@ +/* $NetBSD: pathnames.h,v 1.8 2006/11/28 18:45:32 christos Exp $ */ + +/* + * 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. 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 + * $NetBSD: pathnames.h,v 1.8 2006/11/28 18:45:32 christos Exp $ + */ + +#ifndef __PATHNAMES_H__ +#define __PATHNAMES_H__ + +#include + +#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 "/etc/mail.rc" +#define _PATH_MORE "/usr/bin/more" +#ifdef MIME_SUPPORT +#define _PATH_FILE "/usr/bin/file" /* Used to get mime type/subtype */ +#endif + +#endif /* __PATHNAMES_H__ */ diff --git a/usr.bin/mail/rcv.h b/usr.bin/mail/rcv.h new file mode 100644 index 000000000..e49dbed72 --- /dev/null +++ b/usr.bin/mail/rcv.h @@ -0,0 +1,48 @@ +/* $NetBSD: rcv.h,v 1.7 2006/11/28 18:45:32 christos 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. 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 + * $NetBSD: rcv.h,v 1.7 2006/11/28 18:45:32 christos Exp $ + */ + +/* + * Mail -- a mail program + * + * This file is included by normal files which want both + * globals and declarations. + */ + +#ifndef __RCV_H__ +#define __RCV_H__ + +#include "def.h" +#include "glob.h" + +#endif /* __RCV_H__ */ -- 2.44.0