diff options
author | mikeh <mikeh@FreeBSD.org> | 2004-02-29 20:44:44 +0000 |
---|---|---|
committer | mikeh <mikeh@FreeBSD.org> | 2004-02-29 20:44:44 +0000 |
commit | 9d29f488fff50b2f5e4eb49f972fb3d0e3522029 (patch) | |
tree | 504aca9a1fd911180e61a965ba10728d59f52cbd | |
parent | 1631601f6d0b62bdd426c167f3a29cb48a797bbf (diff) | |
download | FreeBSD-src-9d29f488fff50b2f5e4eb49f972fb3d0e3522029.zip FreeBSD-src-9d29f488fff50b2f5e4eb49f972fb3d0e3522029.tar.gz |
Add the -e (mail presence test), -H (header summary mode), and -F
(message save as first recipient) options for standards
conformance.
Submitted by: Wartan Hachaturow <wart@tepkom.ru> (with some changes)
PR: standards/61934
-rw-r--r-- | usr.bin/mail/extern.h | 1 | ||||
-rw-r--r-- | usr.bin/mail/lex.c | 19 | ||||
-rw-r--r-- | usr.bin/mail/mail.1 | 28 | ||||
-rw-r--r-- | usr.bin/mail/main.c | 48 | ||||
-rw-r--r-- | usr.bin/mail/names.c | 73 | ||||
-rw-r--r-- | usr.bin/mail/send.c | 28 |
6 files changed, 183 insertions, 14 deletions
diff --git a/usr.bin/mail/extern.h b/usr.bin/mail/extern.h index 9c3c7ad..7f02a88 100644 --- a/usr.bin/mail/extern.h +++ b/usr.bin/mail/extern.h @@ -73,6 +73,7 @@ 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 *); diff --git a/usr.bin/mail/lex.c b/usr.bin/mail/lex.c index 518c25b..973eee5 100644 --- a/usr.bin/mail/lex.c +++ b/usr.bin/mail/lex.c @@ -60,13 +60,17 @@ extern const char *version; * 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 i, fd; + int checkmode, i, fd; struct stat stb; char isedit = *name != '%' || getuserid(myname) != getuid(); char *who = name[1] ? name + 1 : myname; @@ -147,12 +151,17 @@ setfile(name) (void)Fclose(ibuf); relsesigs(); sawcom = 0; - if (!edit && msgCount == 0) { + checkmode = value("checkmode") != NULL; + + if ((checkmode || !edit) && msgCount == 0) { nomail: - fprintf(stderr, "No mail for %s\n", who); - return (-1); + if (!checkmode) { + fprintf(stderr, "No mail for %s\n", who); + return (-1); + } else + return (0); } - return (0); + return (checkmode ? 1 : 0); } /* diff --git a/usr.bin/mail/mail.1 b/usr.bin/mail/mail.1 index 9d3a7c6..2cfb078 100644 --- a/usr.bin/mail/mail.1 +++ b/usr.bin/mail/mail.1 @@ -46,15 +46,23 @@ .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 EiInNv +.Op Fl EHiInNv +.Op Fl F .Fl f .Op Ar name .Nm -.Op Fl EiInNv +.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 @@ -69,6 +77,13 @@ The following options are available: 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 @@ -126,6 +141,15 @@ 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 diff --git a/usr.bin/mail/main.c b/usr.bin/mail/main.c index c4d0704..4a00177 100644 --- a/usr.bin/mail/main.c +++ b/usr.bin/mail/main.c @@ -93,7 +93,7 @@ main(argc, argv) bcc = NULL; smopts = NULL; subject = NULL; - while ((i = getopt(argc, argv, "EINT:b:c:dfins:u:v")) != -1) { + while ((i = getopt(argc, argv, "FEHINT:b:c:edfins:u:v")) != -1) { switch (i) { case 'T': /* @@ -123,6 +123,25 @@ main(argc, argv) case 'd': 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 @@ -189,11 +208,13 @@ main(argc, argv) break; case '?': fprintf(stderr, "\ -Usage: %s [-EiInv] [-s subject] [-c cc-addr] [-b bcc-addr] to-addr ...\n\ +Usage: %s [-EiInv] [-s subject] [-c cc-addr] [-b bcc-addr] [-F] to-addr ...\n\ %*s [- sendmail-options ...]\n\ - %s [-EiInNv] -f [name]\n\ - %s [-EiInNv] [-u user]\n",__progname, strlen(__progname), "", - __progname, __progname); + %s [-EHiInNv] [-F] -f [name]\n\ + %s [-EHiInNv] [-F] [-u user]\n\ + %s -e [-f name]\n\ + %s -H\n",__progname, strlen(__progname), "", + __progname, __progname, __progname, __progname); exit(1); } } @@ -240,6 +261,18 @@ Usage: %s [-EiInv] [-s subject] [-c cc-addr] [-b bcc-addr] to-addr ...\n\ */ 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 @@ -259,6 +292,11 @@ Usage: %s [-EiInv] [-s subject] [-c cc-addr] [-b bcc-addr] to-addr ...\n\ (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); diff --git a/usr.bin/mail/names.c b/usr.bin/mail/names.c index a4d64c6..fc0acdc 100644 --- a/usr.bin/mail/names.c +++ b/usr.bin/mail/names.c @@ -210,6 +210,79 @@ yankword(ap, wbuf) } /* + * 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. diff --git a/usr.bin/mail/send.c b/usr.bin/mail/send.c index 1addf07..35b4c72 100644 --- a/usr.bin/mail/send.c +++ b/usr.bin/mail/send.c @@ -303,9 +303,10 @@ mail1(hp, printheaders) int printheaders; { char *cp; + char *nbuf; int pid; char **namelist; - struct name *to; + struct name *to, *nsto; FILE *mtf; /* @@ -354,6 +355,18 @@ mail1(hp, printheaders) 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"); @@ -369,7 +382,18 @@ mail1(hp, printheaders) printf("\n"); goto out; } - if ((cp = value("record")) != NULL) + 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) (void)savemail(expand(cp), mtf); /* * Fork, set up the temporary mail file as standard |