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
This commit is contained in:
Mike Heffner 2004-02-29 20:44:44 +00:00
parent 16c36bbe5d
commit c92dfc231b
6 changed files with 183 additions and 14 deletions

View File

@ -73,6 +73,7 @@ char *username(void);
char *value(const char *); char *value(const char *);
char *vcopy(const char *); char *vcopy(const char *);
char *yankword(char *, char []); char *yankword(char *, char []);
char *yanklogin(char *, char []);
int Fclose(FILE *); int Fclose(FILE *);
int More(int *); int More(int *);
int Pclose(FILE *); int Pclose(FILE *);

View File

@ -60,13 +60,17 @@ extern const char *version;
* If the first character of name is %, we are considered to be * If the first character of name is %, we are considered to be
* editing the file, otherwise we are reading our mail which has * editing the file, otherwise we are reading our mail which has
* signficance for mbox and so forth. * 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 int
setfile(name) setfile(name)
char *name; char *name;
{ {
FILE *ibuf; FILE *ibuf;
int i, fd; int checkmode, i, fd;
struct stat stb; struct stat stb;
char isedit = *name != '%' || getuserid(myname) != getuid(); char isedit = *name != '%' || getuserid(myname) != getuid();
char *who = name[1] ? name + 1 : myname; char *who = name[1] ? name + 1 : myname;
@ -147,12 +151,17 @@ setfile(name)
(void)Fclose(ibuf); (void)Fclose(ibuf);
relsesigs(); relsesigs();
sawcom = 0; sawcom = 0;
if (!edit && msgCount == 0) { checkmode = value("checkmode") != NULL;
if ((checkmode || !edit) && msgCount == 0) {
nomail: nomail:
fprintf(stderr, "No mail for %s\n", who); if (!checkmode) {
return (-1); fprintf(stderr, "No mail for %s\n", who);
return (-1);
} else
return (0);
} }
return (0); return (checkmode ? 1 : 0);
} }
/* /*

View File

@ -46,15 +46,23 @@
.Op Fl s Ar subject .Op Fl s Ar subject
.Op Fl c Ar cc-addr .Op Fl c Ar cc-addr
.Op Fl b Ar bcc-addr .Op Fl b Ar bcc-addr
.Op Fl F
.Ar to-addr ... .Ar to-addr ...
.Op Fl Ar sendmail-option ... .Op Fl Ar sendmail-option ...
.Nm .Nm
.Op Fl EiInNv .Op Fl EHiInNv
.Op Fl F
.Fl f .Fl f
.Op Ar name .Op Ar name
.Nm .Nm
.Op Fl EiInNv .Op Fl EHiInNv
.Op Fl F
.Op Fl u Ar user .Op Fl u Ar user
.Nm
.Fl e
.Op Fl f Ar name
.Nm
.Op Fl H
.Sh INTRODUCTION .Sh INTRODUCTION
The The
.Nm .Nm
@ -69,6 +77,13 @@ The following options are available:
Verbose mode. Verbose mode.
The details of The details of
delivery are displayed on the user's terminal. 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 .It Fl E
Do not send messages with an empty body. Do not send messages with an empty body.
This is useful for piping errors from This is useful for piping errors from
@ -126,6 +141,15 @@ for processing; when you
.Ic quit , .Ic quit ,
.Nm .Nm
writes undeleted messages back to this file. 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 .It Fl u
Is equivalent to: Is equivalent to:
.Pp .Pp

View File

@ -93,7 +93,7 @@ main(argc, argv)
bcc = NULL; bcc = NULL;
smopts = NULL; smopts = NULL;
subject = 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) { switch (i) {
case 'T': case 'T':
/* /*
@ -123,6 +123,25 @@ main(argc, argv)
case 'd': case 'd':
debug++; debug++;
break; 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': case 's':
/* /*
* Give a subject field for sending from * Give a subject field for sending from
@ -189,11 +208,13 @@ main(argc, argv)
break; break;
case '?': case '?':
fprintf(stderr, "\ 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 [- sendmail-options ...]\n\
%s [-EiInNv] -f [name]\n\ %s [-EHiInNv] [-F] -f [name]\n\
%s [-EiInNv] [-u user]\n",__progname, strlen(__progname), "", %s [-EHiInNv] [-F] [-u user]\n\
__progname, __progname); %s -e [-f name]\n\
%s -H\n",__progname, strlen(__progname), "",
__progname, __progname, __progname, __progname);
exit(1); exit(1);
} }
} }
@ -240,6 +261,18 @@ Usage: %s [-EiInv] [-s subject] [-c cc-addr] [-b bcc-addr] to-addr ...\n\
*/ */
exit(senderr); 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. * Ok, we are reading mail.
* Decide whether we are editing a mailbox or reading * 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)fflush(stdout);
(void)signal(SIGINT, prevint); (void)signal(SIGINT, prevint);
} }
/* If we were in header summary mode, it's time to exit. */
if (value("headersummary") != NULL)
exit(0);
commands(); commands();
(void)signal(SIGHUP, SIG_IGN); (void)signal(SIGHUP, SIG_IGN);
(void)signal(SIGINT, SIG_IGN); (void)signal(SIGINT, SIG_IGN);

View File

@ -209,6 +209,79 @@ yankword(ap, wbuf)
return (cp); return (cp);
} }
/*
* 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 / * For each recipient in the passed name list with a /
* in the name, append the message to the end of the named file * in the name, append the message to the end of the named file

View File

@ -303,9 +303,10 @@ mail1(hp, printheaders)
int printheaders; int printheaders;
{ {
char *cp; char *cp;
char *nbuf;
int pid; int pid;
char **namelist; char **namelist;
struct name *to; struct name *to, *nsto;
FILE *mtf; FILE *mtf;
/* /*
@ -354,6 +355,18 @@ mail1(hp, printheaders)
to = elide(to); to = elide(to);
if (count(to) == 0) if (count(to) == 0)
goto out; 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); fixhead(hp, to);
if ((mtf = infix(hp, mtf)) == NULL) { if ((mtf = infix(hp, mtf)) == NULL) {
fprintf(stderr, ". . . message lost, sorry.\n"); fprintf(stderr, ". . . message lost, sorry.\n");
@ -369,7 +382,18 @@ mail1(hp, printheaders)
printf("\n"); printf("\n");
goto out; 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); (void)savemail(expand(cp), mtf);
/* /*
* Fork, set up the temporary mail file as standard * Fork, set up the temporary mail file as standard