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:
parent
16c36bbe5d
commit
c92dfc231b
@ -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 *);
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user