standards/61934: [PATCH] FreeBSD's mailx not completely SUSv3-compliant

Mike Heffner mheffner at vt.edu
Sun Feb 8 22:00:28 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: Mon, 09 Feb 2004 00:59:59 -0500 (EST)

 I'm glad you picked up this stuff up, it is part of the few remaining
 things to implement for mailx standards compliance. :-D
 
 I've done a quick first pass, comments are inlined.
 
 | 
 |>Fix:
 |
 |       One little note: SUS is unclear on what does "login-name part of
 |       the address" means (in -F case). I've decided to use "the
 |       word before @,!,%", but this is, of course, arguable. For
 |       example, the only system I know of to support -F, AIX,
 |       uses the whole address as a filename.
 |
 
 This sounds like a good choice.
 
 |       
 | 
 | 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        Thu Jan 22 14:37:39 2004
 | @@ -51,6 +51,7 @@
 |  int  sourcing;                       /* Currently reading variant file
 */
 |  int  loading;                        /* Loading user definitions */
 |  int  cond;                           /* Current state of conditional
 exc. */
 | +int  record_recip;                   /* -F 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 Thu Jan 22 13:03:04 2004
 | @@ -156,6 +156,105 @@
 |  }
 |  
 |  /*
 | + * Check the mailbox for mail to read.
 | + * Return -1 in case of error, 0 if there's no mail, 1 if there is.
 | + * This function is almost identical to setfile above, but it has
 | + * meaningful return codes for checkmail task.
 | + */
 
 I would really rather not have the setfile() function duplicated here.
 Since the setfile()'s return code is only checked for error in two places,
 your modified setfile() should work in those cases as well. So, can you
 modify setfile to return a more descriptive error code like in your
 checkmail and use it instead for the -e option? Also, the fprintf that
 displays "No mail for ..." should not be printed when using the -e option.
 SuSv3 states that when using the -e option, nothing should be printed.
 
 
 | +int
 | +checkmail(name)
 | +     char *name;
 | +{
 
 <snip>
 
 | +}
 | +
 | +/*
 |   * Incorporate any new mail that has arrived since we first
 |   * started reading mail.
 |   */
 | 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        Mon Jan 26 14:43:16 2004
 | @@ -46,15 +46,22 @@
 |  .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 F
 |  .Fl f
 |  .Op Ar name
 |  .Nm
 |  .Op Fl EiInNv
 | +.Op Fl F
 |  .Op Fl u Ar user
 | +.Nm
 | +.Op Fl e
 | +.Nm
 | +.Op Fl H
 
 The -H option can be used in the receive modes and doesn't have to be
 separate. You can add it to the second and third usage lines.
 
 
 <snip>
 | @@ -123,6 +125,24 @@
 |               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++;
 
 A break is needed here.
 
 |               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 [-EiInNv] [-F] -f [name]\n\
 | +       %s [-EiInNv] [-F] [-u user]\n\
 | +       %s -e\n\
 | +       %s -H\n",__progname, strlen(__progname), "",
 | +                         __progname, __progname, __progname,
 __progname);
 |                       exit(1);
 
 Same thing for -H in the usage summary.
 
 |               }
 |       }
 | @@ -240,6 +262,38 @@
 |                */
 |               exit(senderr);
 |       }
 | +
 | +     if(check_mode) {
 | +             if (ef == NULL)
 | +                     ef = "%";
 | +             if (checkmail(ef) <= 0) {
 | +                     exit(1);        /* Either an error has occured, or
 no mail */
 | +             } else {
 | +                     exit(0);
 | +             }
 | +             /* Should exit anyway */
 | +             exit(1);
 
 Can you replace this exit with a /*NOTREACHED*/.
 
 
 | +     }
 | +
 | +     if (header_sum_mode) {
 | +             if (ef == NULL)
 | +                     ef = "%";
 | +             if (setfile(ef) < 0)
 | +                     exit(1);        /* error already reported */
 | +             if (setjmp(hdrjmp) == 0) {
 | +                     if ((prevint = signal(SIGINT, SIG_IGN)) != SIG_IGN)
 | +                             (void)signal(SIGINT, hdrstop);
 | +                     if (value("quiet") == NULL)
 | +                             printf("Mail version %s.  Type ? for
 help.\n",
 | +                                     version);
 | +                     announce();
 | +                     (void)fflush(stdout);
 | +                     (void)signal(SIGINT, prevint);
 | +             }
 | +             exit(0);
 | +     }
 | +
 | +
 
 Instead of duplicating this code from below, can you add something like:
 
         if (header_sum_mode)
                 exit(0);
 
 before the call to commands?
 
 
 |       /*
 |        * Ok, we are reading mail.
 |        * Decide whether we are editing a mailbox or reading
 | 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
 
 
 
 Cheers,
 
 Mike
 
 -- 
   Mike Heffner       <mheffner@[acm.]vt.edu>
                          <mikeh at FreeBSD.org>
 


More information about the freebsd-standards mailing list