From owner-freebsd-standards@FreeBSD.ORG Sat Feb 21 11:20:05 2004 Return-Path: Delivered-To: freebsd-standards@hub.freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id 387A816A4D2 for ; Sat, 21 Feb 2004 11:20:05 -0800 (PST) Received: from freefall.freebsd.org (freefall.freebsd.org [216.136.204.21]) by mx1.FreeBSD.org (Postfix) with ESMTP id 2DF6B43D1F for ; Sat, 21 Feb 2004 11:20:05 -0800 (PST) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) i1LJK5bv047401 for ; Sat, 21 Feb 2004 11:20:05 -0800 (PST) (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.12.10/8.12.10/Submit) id i1LJK4p7047399; Sat, 21 Feb 2004 11:20:04 -0800 (PST) (envelope-from gnats) Date: Sat, 21 Feb 2004 11:20:04 -0800 (PST) Message-Id: <200402211920.i1LJK4p7047399@freefall.freebsd.org> To: freebsd-standards@FreeBSD.org From: Mike Heffner Subject: Re: standards/61934: [PATCH] FreeBSD's mailx not completely SUSv3-compliant X-BeenThere: freebsd-standards@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list Reply-To: Mike Heffner List-Id: Standards compliance List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 21 Feb 2004 19:20:05 -0000 The following reply was made to PR standards/61934; it has been noted by GNATS. From: Mike Heffner To: Wartan Hachaturow Cc: FreeBSD-gnats-submit@FreeBSD.org Subject: Re: standards/61934: [PATCH] FreeBSD's mailx not completely SUSv3-compliant Date: Sat, 21 Feb 2004 14:16:21 -0500 (EST) This message is in MIME format --_=XFMail.1.5-DEVEL.FreeBSD:20040221141621:330=_ Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit On 18-Feb-2004 Wartan Hachaturow wrote: | On Wed, Feb 18, 2004 at 09:20:40AM -0500, Mike Heffner wrote: | |> Therefore, changing setfile to have a tri-state return value (< 0, 0, |> 1) |> will still work in these cases that are simply testing for a failure. | | Okay, here's the new patch that (hopefully :) fixes the issues you've | pointed. | Note also that -e works with -f, which is a SUS extension (SUS requires | only to check the system mailbox) -- quite handy. Solaris does the same. | I've made some changes so that this is consistent with the current style in mail(1). I plan to commit the attached patch unless you see/have any problems with it. Mike -- Mike Heffner --_=XFMail.1.5-DEVEL.FreeBSD:20040221141621:330=_ Content-Disposition: attachment; filename="mail-sus.diff" Content-Transfer-Encoding: 7bit Content-Description: mail-sus.diff Content-Type: text/plain; charset=us-ascii; name=mail-sus.diff; SizeOnDisk=8881 Index: extern.h =================================================================== RCS file: /cvs/ncvs/src/usr.bin/mail/extern.h,v retrieving revision 1.8 diff -u -r1.8 extern.h --- extern.h 25 Jun 2002 05:24:29 -0000 1.8 +++ extern.h 21 Feb 2004 19:51:45 -0000 @@ -73,6 +73,7 @@ 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 *); Index: lex.c =================================================================== RCS file: /cvs/ncvs/src/usr.bin/mail/lex.c,v retrieving revision 1.14 diff -u -r1.14 lex.c --- lex.c 30 Jun 2002 05:25:06 -0000 1.14 +++ lex.c 21 Feb 2004 19:51:45 -0000 @@ -60,13 +60,17 @@ * 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 @@ (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); } /* Index: mail.1 =================================================================== RCS file: /cvs/ncvs/src/usr.bin/mail/mail.1,v retrieving revision 1.42 diff -u -r1.42 mail.1 --- mail.1 9 Jan 2003 01:08:33 -0000 1.42 +++ mail.1 21 Feb 2004 19:51:45 -0000 @@ -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 @@ 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 @@ .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 Index: main.c =================================================================== RCS file: /cvs/ncvs/src/usr.bin/mail/main.c,v retrieving revision 1.13 diff -u -r1.13 main.c --- main.c 30 Jun 2002 05:25:06 -0000 1.13 +++ main.c 21 Feb 2004 19:51:45 -0000 @@ -93,7 +93,7 @@ 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 @@ 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 @@ 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 @@ */ 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 @@ (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); Index: names.c =================================================================== RCS file: /cvs/ncvs/src/usr.bin/mail/names.c,v retrieving revision 1.8 diff -u -r1.8 names.c --- names.c 30 Jun 2002 05:25:06 -0000 1.8 +++ names.c 21 Feb 2004 19:51:45 -0000 @@ -210,6 +210,79 @@ } /* + * 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. Index: send.c =================================================================== RCS file: /cvs/ncvs/src/usr.bin/mail/send.c,v retrieving revision 1.13 diff -u -r1.13 send.c --- send.c 30 Jun 2002 05:25:06 -0000 1.13 +++ send.c 21 Feb 2004 19:51:45 -0000 @@ -303,9 +303,10 @@ int printheaders; { char *cp; + char *nbuf; int pid; char **namelist; - struct name *to; + struct name *to, *nsto; FILE *mtf; /* @@ -354,6 +355,18 @@ 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,8 +382,21 @@ printf("\n"); goto out; } - if ((cp = value("record")) != NULL) - (void)savemail(expand(cp), mtf); + 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 * input for "mail", and exec with the user list we generated --_=XFMail.1.5-DEVEL.FreeBSD:20040221141621:330=_-- End of MIME message