Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 18 Feb 2004 12:00:49 -0800 (PST)
From:      Wartan Hachaturow <wart@tepkom.ru>
To:        freebsd-standards@FreeBSD.org
Subject:   Re: standards/61934: [PATCH] FreeBSD's mailx not completely SUSv3-compliant
Message-ID:  <200402182000.i1IK0nX8008318@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help
The following reply was made to PR standards/61934; it has been noted by GNATS.

From: Wartan Hachaturow <wart@tepkom.ru>
To: Mike Heffner <mheffner@vt.edu>
Cc: FreeBSD-gnats-submit@FreeBSD.org
Subject: Re: standards/61934: [PATCH] FreeBSD's mailx not completely SUSv3-compliant
Date: Wed, 18 Feb 2004 22:55:37 +0300

 --Q68bSM7Ycu6FN28Q
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: inline
 
 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.
 
 -- 
 Regards, Wartan.
 "Be different: conform."
 
 --Q68bSM7Ycu6FN28Q
 Content-Type: text/plain; charset=us-ascii
 Content-Disposition: attachment; filename="mailx.patch.2"
 
 diff -ur ./mail_HEAD.orig/extern.h ./mail_HEAD.patched/extern.h
 --- ./mail_HEAD.orig/extern.h	Tue Jun 25 09:24:29 2002
 +++ ./mail_HEAD.patched/extern.h	Fri Jan 23 12:57:04 2004
 @@ -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 *);
 diff -ur ./mail_HEAD.orig/glob.h ./mail_HEAD.patched/glob.h
 --- ./mail_HEAD.orig/glob.h	Sun Mar 25 08:57:04 2001
 +++ ./mail_HEAD.patched/glob.h	Wed Feb 18 17:23:46 2004
 @@ -51,6 +51,8 @@
  int	sourcing;			/* Currently reading variant file */
  int	loading;			/* Loading user definitions */
  int	cond;				/* Current state of conditional exc. */
 +int	record_recip;			/* -F flag set */
 +int	check_mode;			/* -e flag set */
  FILE	*itf;				/* Input temp file buffer */
  FILE	*otf;				/* Output temp file buffer */
  int	image;				/* File descriptor for image of msg */
 diff -ur ./mail_HEAD.orig/lex.c ./mail_HEAD.patched/lex.c
 --- ./mail_HEAD.orig/lex.c	Sun Jun 30 09:25:06 2002
 +++ ./mail_HEAD.patched/lex.c	Wed Feb 18 22:30:52 2004
 @@ -60,6 +60,9 @@
   * 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.
 + * This function is also used for -e option implementation, so
 + * exit codes are designed to serve that need:
 + * Return -1 in case of error, 0 if there's no mail, 1 if there is.
   */
  int
  setfile(name)
 @@ -147,9 +150,17 @@
  	(void)Fclose(ibuf);
  	relsesigs();
  	sawcom = 0;
 +	if (check_mode) {
 +		if (msgCount >= 1)
 +			return (1);
 +		else
 +			return (0);
 +	}
 +
  	if (!edit && msgCount == 0) {
  nomail:
 -		fprintf(stderr, "No mail for %s\n", who);
 +		if (!check_mode)
 +			fprintf(stderr, "No mail for %s\n", who);
  		return (-1);
  	}
  	return (0);
 diff -ur ./mail_HEAD.orig/mail.1 ./mail_HEAD.patched/mail.1
 --- ./mail_HEAD.orig/mail.1	Thu Jan  9 04:08:33 2003
 +++ ./mail_HEAD.patched/mail.1	Wed Feb 18 22:53:45 2004
 @@ -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
 diff -ur ./mail_HEAD.orig/main.c ./mail_HEAD.patched/main.c
 --- ./mail_HEAD.orig/main.c	Sun Jun 30 09:25:06 2002
 +++ ./mail_HEAD.patched/main.c	Wed Feb 18 22:53:34 2004
 @@ -65,6 +65,7 @@
  	char *argv[];
  {
  	int i;
 +	int header_sum_mode = 0;
  	struct name *to, *cc, *bcc, *smopts;
  	char *subject, *replyto;
  	char *ef, *rc;
 @@ -93,7 +94,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 +124,25 @@
  		case 'd':
  			debug++;
  			break;
 +		case 'e':
 +			/*
 +			 * User wants to check mail and exit.
 +			 */
 +			 check_mode++;
 +			 break;
 +		case 'H':
 +			/*
 +			 * User wants a header summary only.
 +			 */
 +			 header_sum_mode++;
 +			 break;
 +		case 'F':
 +			/*
 +			 * User wants to record messages to files
 +			 * named after first recipient username.
 +			 */
 +			 record_recip++;
 +			 break;
  		case 's':
  			/*
  			 * Give a subject field for sending from
 @@ -189,11 +209,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 +262,19 @@
  		 */
  		exit(senderr);
  	}
 +
 +	if(check_mode) {
 +		if (ef == NULL)
 +			ef = "%";
 +		if (setfile(ef) <= 0) {
 +			exit(1);	/* Either an error has occured, or no mail */
 +		} else {
 +			exit(0);
 +		}
 +		/* NOTREACHED */
 +		exit(1);
 +	}
 +
  	/*
  	 * Ok, we are reading mail.
  	 * Decide whether we are editing a mailbox or reading
 @@ -259,6 +294,11 @@
  		(void)fflush(stdout);
  		(void)signal(SIGINT, prevint);
  	}
 +
 +	/* If we were in header summary mode, it's time to exit. */
 +	if (header_sum_mode)
 +		exit(0);
 +
  	commands();
  	(void)signal(SIGHUP, SIG_IGN);
  	(void)signal(SIGINT, SIG_IGN);
 diff -ur ./mail_HEAD.orig/names.c ./mail_HEAD.patched/names.c
 --- ./mail_HEAD.orig/names.c	Sun Jun 30 09:25:06 2002
 +++ ./mail_HEAD.patched/names.c	Mon Jan 26 13:51:04 2004
 @@ -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.
 diff -ur ./mail_HEAD.orig/send.c ./mail_HEAD.patched/send.c
 --- ./mail_HEAD.orig/send.c	Sun Jun 30 09:25:06 2002
 +++ ./mail_HEAD.patched/send.c	Fri Jan 23 12:56:28 2004
 @@ -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 (record_recip) {
 +		/*
 +		 * 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 (record_recip) {
 +		/*
 +		 * 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
 
 --Q68bSM7Ycu6FN28Q--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200402182000.i1IK0nX8008318>