Re: [nail-devel] Patch for setting sendmail opts
Brought to you by:
gritter
From: Dario N. <dn...@ti...> - 2012-07-11 21:02:20
|
Steffen Daode Nurpmeso <sd...@go...> wrote: > The problem i see with your patch is that it modifies the standard > POSIX standard (http://pubs.opengroup.org/onlinepubs/9699919799/) > command line: > > Send Mode > mailx [-s subject] address... > > Just in case of interest, i'll append a version which introduces > a new -O option which can be used to pass options to the MTA. > I think that is the more generic approach to the '-h hop' thing. Your patch is more robust and posixly correct than mine, and I think it should be preferred by all, except maybe some BSD guy who's still too irrationally attached to his old ways. Meanwhile, I've been working on another way to set options to be passed to the MTA. The included patch implements the "mtaopts" variable. Put space-separated options and arguments into it, just as you would on the MTA's command line. The new variable can be used in the start-up files, even in account{} blocks. I've been testing this patch for more than a week and it seems to work well. It can be applied to an unpatched mailx source, or it can coexist peacefully with any of the patches posted to this thread so far. Ciao, DN ===== BEGIN PATCH ===== diff -u -x '*main.c' -x '*Makefile' nail.orig/extern.h nail/extern.h --- nail.orig/extern.h 2008-10-02 09:57:19.000000000 +0200 +++ nail/extern.h 2012-07-03 12:10:46.000000000 +0200 @@ -391,6 +391,7 @@ struct name *nalloc(char *str, enum gfield ntype); struct name *extract(char *line, enum gfield ntype); struct name *sextract(char *line, enum gfield ntype); +struct name *catWords(struct name *optList, char *line, char *varName); char *detract(struct name *np, enum gfield ntype); struct name *outof(struct name *names, FILE *fo, struct header *hp); int is_fileaddr(char *name); diff -u -x '*main.c' -x '*Makefile' nail.orig/names.c nail/names.c --- nail.orig/names.c 2006-03-04 01:32:16.000000000 +0100 +++ nail/names.c 2012-07-03 14:25:40.000000000 +0200 @@ -541,6 +541,68 @@ return(n1); } +/* extract all words from a line and append them one by one to the passed-in + * name-struct optList. Space is a separator only if it is not + * backslash-escaped and it is not between single quotes. 'varName' is the name + * of the variable that holds 'line' as its value. 'varName' is used only to + * warn the user in case too many words (>256) have been put into it. */ +struct name * +catWords(struct name *optList, char *line, char *varName) +{ +#define NONE 0 +#define COPY 1 +#define WORDDONE 2 + char * lineCopy, * word[256]; + char prevCharWasEsc, betweenQuotes, action; + int i, j, w; + struct name * optName[256]; + + lineCopy = calloc(strlen(line)+1, sizeof(char)); + + /* copy line to lineCopy, a word at a time; when a word is done, copy + * it to word[w] and make a name-struct member to hold it. Link this + * struct member to optList. Rewind lineCopy & cp another word into it... */ + prevCharWasEsc = 0; betweenQuotes = 0; + for (i=0, j=0, w=0, action=NONE ; ; i++, action=NONE) { + if (line[i] == '\\' && !prevCharWasEsc) + { prevCharWasEsc = 1; continue; } + // else... + if (line[i] == '\'' && !prevCharWasEsc) + { betweenQuotes = 1-betweenQuotes; continue; } + // else... + if (line[i] == '\0') + action = WORDDONE; + else if (line[i] != ' ' && line[i] != '\t') // char's not whitespace + action = COPY; // copy it + else if (prevCharWasEsc || betweenQuotes) // char IS space, but escaped + action = COPY; // copy it + else + action = WORDDONE; // an unesc'd space NOT between quotes + // means we're done reading a word + if (action == COPY) { + lineCopy[j++] = line[i]; + prevCharWasEsc = 0; + } + else if (action == WORDDONE) { + lineCopy[j] = '\0'; + word[w] = calloc(strlen(lineCopy)+1, sizeof(char)); + strcpy(word[w], lineCopy); + optName[w] = nalloc(word[w], 0); + optList = cat(optList, optName[w]); + if (line[i] == '\0') break; // finished reading line + // else... + w++; j = 0; + if (w > 255) { + fprintf(stderr,"Warning: too many words in variable '%s'\n", varName); + fprintf(stderr," ignoring after the 256th word '%s'\n", word[255]); + break; + } + } + } + free(lineCopy); + return optList; +} + /* * Unpack the name list onto a vector of strings. * Return an error if the name list won't fit. diff -u -x '*main.c' -x '*Makefile' nail.orig/sendout.c nail/sendout.c --- nail.orig/sendout.c 2009-03-01 21:25:42.000000000 +0100 +++ nail/sendout.c 2012-07-03 12:10:46.000000000 +0200 @@ -971,6 +971,8 @@ if ((cp = value("autobcc")) != NULL && *cp) hp->h_bcc = cat(hp->h_bcc, checkaddrs(sextract(cp, GBCC|GFULL))); + if ((cp = value("mtaopts")) != NULL && *cp) // user set var "mtaopts" + hp->h_smopts = catWords(hp->h_smopts, cp, "mtaopts"); /* * Collect user's mail from standard input. * Get the result as mtf. Steffen Daode Nurpmeso <sd...@go...> wrote: > Ciao Dario, > > Dario Niedermann <dn...@ti...> wrote: > > |The attached patch enables mailx to read and set any sendmail options > |specified on mailx's own command line after all message recipients. > [.] > |- for (i = optind; argv[i]; i++) > |+ for (i = optind; argv[i] && argv[i][0] != '-'; i++) > | to = checkaddrs(cat(to, extract(argv[i], GTO|GFULL))); > |+ if (argv[i] && argv[i][0] == '-') /* it's a sendmail opt, coming after to-addr(s) */ > |+ for ( ; argv[i]; i++) > |+ smopts = cat(smopts, nalloc(argv[i], 0)); > > The problem i see with your patch is that it modifies the standard > POSIX standard (http://pubs.opengroup.org/onlinepubs/9699919799/) > command line: > > Send Mode > mailx [-s subject] address... > > Just in case of interest, i'll append a version which introduces > a new -O option which can be used to pass options to the MTA. > I think that is the more generic approach to the '-h hop' thing. > > |Cheers, > |DN > > --steffen > > Add -O option to pass options through to MTA.. > > Inspired by a mail from Dario Niedermann (dnied (AT) tiscali DOT it) > on the Heirloom mailx mailing list this changeset adds the > option -O which passes its arguments through to the chosen MTA, > but does not change the general POSIX usage syntax (remaining > arguments on the command line are solely interpreted as > recipient addresses). > Now it is possible to say > > $ nail -O-bm -O-C -O/etc/sendmail-alt.conf .. > > to get the following sendmail command line: > > -i -bm -C /etc/sendmail-alt.conf > --- > mailx.1 | 6 +++++- > main.c | 9 ++++++++- > 2 files changed, 13 insertions(+), 2 deletions(-) > > diff --git a/mailx.1 b/mailx.1 > index b90f76c..a12563a 100644 > --- a/mailx.1 > +++ b/mailx.1 > @@ -43,7 +43,7 @@ mailx \- send and receive Internet mail > .PD 0 > .HP > .ad l > -\fBmailx\fR [\fB\-BDdEFintv~\fR] > +\fBs-nail\fR [\fB\-BDdEFinOtv~\fR] > [\fB\-s\fI\ subject\fR] [\fB\-a\fI\ attachment\fR ] > [\fB\-c\fI\ cc-addr\fR] [\fB\-b\fI\ bcc-addr\fR] [\fB\-r\fI\ from-addr\fR] > [\fB\-h\fI\ hops\fR] > @@ -185,6 +185,10 @@ because the contents of that file may differ between them. > Inhibits the initial display of message headers when reading mail > or editing a mail folder. > .TP > +.BI \-O \ option > +Pass the given option through to sendmail. > +This option has no effect when SMTP is used for sending mail. > +.TP > .BI \-q \ file > Start the message with the contents of the specified file. > May be given in send mode only. > diff --git a/main.c b/main.c > index 6ff7aaf..4683f93 100644 > --- a/main.c > +++ b/main.c > @@ -87,7 +87,7 @@ static void setscreensize(int dummy); > int > main(int argc, char *argv[]) > { > - const char optstr[] = "A:BHEFINVT:RS:a:b:c:dDefh:inqr:s:tu:v~"; > + const char optstr[] = "A:BHEFINVT:RS:a:b:c:dDefh:inqr:s:tu:v~O:"; > int i, existonly = 0, headersonly = 0, sendflag = 0; > struct name *to, *cc, *bcc, *smopts; > struct attachment *attach; > @@ -337,6 +337,13 @@ main(int argc, char *argv[]) > smopts = cat(smopts, nalloc(optarg, 0)); > sendflag++; > break; > + case 'O': > + /* > + * Additional options to pass-through to MTA > + */ > + smopts = cat(smopts, nalloc(optarg, 0)); > + sendflag++; > + break; > case '~': > if (tildeflag == 0) > tildeflag = 1; Steffen Daode Nurpmeso <sd...@go...> wrote: > The problem i see with your patch is that it modifies the standard > POSIX standard (http://pubs.opengroup.org/onlinepubs/9699919799/) > command line: > > Send Mode > mailx [-s subject] address... > > Just in case of interest, i'll append a version which introduces > a new -O option which can be used to pass options to the MTA. > I think that is the more generic approach to the '-h hop' thing. Your patch is more robust and posixly correct than mine, and I think it should be preferred by all, except maybe some BSD guy who's still too irrationally attached to his old ways. Meanwhile, I've been working on another way to set options to be passed to the MTA. The included patch implements the "mtaopts" variable. The new variable can be used in the start-up files, even in account{} blocks. I've been testing this patch for a couple of weeks and it seems to work well. It can be applied to an unpatched mailx source, or it can coexist peacefully with any of the patches posted to this thread so far. Ciao, DN ===== BEGIN PATCH ===== diff -u -x '*main.c' -x '*Makefile' nail.orig/extern.h nail/extern.h --- nail.orig/extern.h 2008-10-02 09:57:19.000000000 +0200 +++ nail/extern.h 2012-07-03 12:10:46.000000000 +0200 @@ -391,6 +391,7 @@ struct name *nalloc(char *str, enum gfield ntype); struct name *extract(char *line, enum gfield ntype); struct name *sextract(char *line, enum gfield ntype); +struct name *catWords(struct name *optList, char *line, char *varName); char *detract(struct name *np, enum gfield ntype); struct name *outof(struct name *names, FILE *fo, struct header *hp); int is_fileaddr(char *name); diff -u -x '*main.c' -x '*Makefile' nail.orig/names.c nail/names.c --- nail.orig/names.c 2006-03-04 01:32:16.000000000 +0100 +++ nail/names.c 2012-07-03 14:25:40.000000000 +0200 @@ -541,6 +541,68 @@ return(n1); } +/* extract all words from a line and append them one by one to the passed-in + * name-struct optList. Space is a separator only if it is not + * backslash-escaped and it is not between single quotes. 'varName' is the name + * of the variable that holds 'line' as its value. 'varName' is used only to + * warn the user in case too many words (>256) have been put into it. */ +struct name * +catWords(struct name *optList, char *line, char *varName) +{ +#define NONE 0 +#define COPY 1 +#define WORDDONE 2 + char * lineCopy, * word[256]; + char prevCharWasEsc, betweenQuotes, action; + int i, j, w; + struct name * optName[256]; + + lineCopy = calloc(strlen(line)+1, sizeof(char)); + + /* copy line to lineCopy, a word at a time; when a word is done, copy + * it to word[w] and make a name-struct member to hold it. Link this + * struct member to optList. Rewind lineCopy & cp another word into it... */ + prevCharWasEsc = 0; betweenQuotes = 0; + for (i=0, j=0, w=0, action=NONE ; ; i++, action=NONE) { + if (line[i] == '\\' && !prevCharWasEsc) + { prevCharWasEsc = 1; continue; } + // else... + if (line[i] == '\'' && !prevCharWasEsc) + { betweenQuotes = 1-betweenQuotes; continue; } + // else... + if (line[i] == '\0') + action = WORDDONE; + else if (line[i] != ' ' && line[i] != '\t') // char's not whitespace + action = COPY; // copy it + else if (prevCharWasEsc || betweenQuotes) // char IS space, but escaped + action = COPY; // copy it + else + action = WORDDONE; // an unesc'd space NOT between quotes + // means we're done reading a word + if (action == COPY) { + lineCopy[j++] = line[i]; + prevCharWasEsc = 0; + } + else if (action == WORDDONE) { + lineCopy[j] = '\0'; + word[w] = calloc(strlen(lineCopy)+1, sizeof(char)); + strcpy(word[w], lineCopy); + optName[w] = nalloc(word[w], 0); + optList = cat(optList, optName[w]); + if (line[i] == '\0') break; // finished reading line + // else... + w++; j = 0; + if (w > 255) { + fprintf(stderr,"Warning: too many words in variable '%s'\n", varName); + fprintf(stderr," ignoring after the 256th word '%s'\n", word[255]); + break; + } + } + } + free(lineCopy); + return optList; +} + /* * Unpack the name list onto a vector of strings. * Return an error if the name list won't fit. diff -u -x '*main.c' -x '*Makefile' nail.orig/sendout.c nail/sendout.c --- nail.orig/sendout.c 2009-03-01 21:25:42.000000000 +0100 +++ nail/sendout.c 2012-07-03 12:10:46.000000000 +0200 @@ -971,6 +971,8 @@ if ((cp = value("autobcc")) != NULL && *cp) hp->h_bcc = cat(hp->h_bcc, checkaddrs(sextract(cp, GBCC|GFULL))); + if ((cp = value("mtaopts")) != NULL && *cp) // user set var "mtaopts" + hp->h_smopts = catWords(hp->h_smopts, cp, "mtaopts"); /* * Collect user's mail from standard input. * Get the result as mtf. |