standards/61934: [PATCH] FreeBSD's mailx not completely
SUSv3-compliant
Mike Heffner
mheffner at vt.edu
Sat Feb 21 11:20:05 PST 2004
The following reply was made to PR standards/61934; it has been noted by GNATS.
From: Mike Heffner <mheffner at vt.edu>
To: Wartan Hachaturow <wart at tepkom.ru>
Cc: FreeBSD-gnats-submit at 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 <mheffner@[acm.]vt.edu>
<mikeh at FreeBSD.org>
--_=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
More information about the freebsd-standards
mailing list