html/Makefile.in, man/Makefile.in, proto/DATABASE_README.html,
postconf/postconf.c, proto/socketmap_table, proto/lmdb_table.
-20121122
+20131122
Documentation: missing database hyperlinks, refined text
about partial lookup keys. Files: mantools/postlink,
proto/DATABASE_README.html, proto/lmdb_table,
proto/socketmap_table.
+20131123
+
+ Feature: support for NOTIFY parameter in the Milter
+ SMFIR_ADDRCPT_PAR request. Contributed by by Andrew Ayer.
+ Wietse added support for ORCPT. Files: cleanup/cleanup.h,
+ cleanup/cleanup_milter.c, cleanup/cleanup_state.c,
+ global/xtext.c, global/xtext.h, milter/test-milter.c.
+
+20131124
+
+ Cleanup: remove extra blank line from ccformat output,
+ making it compatible with the script that Wietse actually
+ uses (this line was part of a test to detect file truncation,
+ but it is now obsolete). File: mantools/ccformat.
{ # some versions of indent return garbage exit status -- gack!
(indent $FLAGS <$i 2>.ind.$$ >$TMPF || test ! -s .ind.$$) >$TMPF &&
# try a device full check
- echo >>$TMPF && (
+ # echo >>$TMPF &&
+ (
# ignore interrupts while we overwrite the original file
trap '' 1 2 3 15; cp $TMPF $i
) && echo replaced; } || { echo replacement FAILED; exit 1; }
cleanup_milter.o: ../../include/vbuf.h
cleanup_milter.o: ../../include/vstream.h
cleanup_milter.o: ../../include/vstring.h
+cleanup_milter.o: ../../include/xtext.h
cleanup_milter.o: cleanup.h
cleanup_milter.o: cleanup_milter.c
cleanup_out.o: ../../include/argv.h
VSTRING *milter_err_text; /* milter call-back reply */
HBC_CHECKS *milter_hbc_checks; /* Milter header checks */
VSTRING *milter_hbc_reply; /* Milter header checks reply */
+ VSTRING *milter_orcpt_buf; /* add_rcpt_par() orcpt */
/*
* Support for Milter body replacement requests.
#include <is_header.h>
#include <quote_821_local.h>
#include <dsn_util.h>
+#include <xtext.h>
/* Application-specific. */
return (CLEANUP_OUT_OK(state) ? 0 : cleanup_milter_error(state, 0));
}
-/* cleanup_add_rcpt - append recipient address */
+/* cleanup_add_rcpt_par - append recipient address, with ESMTP arguments */
-static const char *cleanup_add_rcpt(void *context, const char *ext_rcpt)
+static const char *cleanup_add_rcpt_par(void *context, const char *ext_rcpt,
+ const char *esmtp_args)
{
const char *myname = "cleanup_add_rcpt";
CLEANUP_STATE *state = (CLEANUP_STATE *) context;
TOK822 *tree;
TOK822 *tp;
VSTRING *int_rcpt_buf;
-
+ ARGV *esmtp_argv;
+ int dsn_notify = 0;
+ const char *dsn_orcpt_info = 0;
+ size_t type_len;
+ int i;
+ const char *arg;
+ const char *arg_val;
+
+ if (esmtp_args[0]) {
+ esmtp_argv = argv_split(esmtp_args, " ");
+ for (i = 0; i < esmtp_argv->argc; ++i) {
+ arg = esmtp_argv->argv[i];
+ if (strncasecmp(arg, "NOTIFY=", 7) == 0) { /* RFC 3461 */
+ if (dsn_notify || (dsn_notify = dsn_notify_mask(arg + 7)) == 0)
+ msg_warn("%s: Bad NOTIFY parameter from MILTER: \"%.100s\"",
+ state->queue_id, arg);
+ } else if (strncasecmp(arg, "ORCPT=", 6) == 0) { /* RFC 3461 */
+ if (state->milter_orcpt_buf == 0)
+ state->milter_orcpt_buf = vstring_alloc(100);
+ if (dsn_orcpt_info
+ || (type_len = strcspn(arg_val = arg + 6, ";")) == 0
+ || (arg_val)[type_len] != ';'
+ || xtext_unquote_append(
+ vstring_sprintf(state->milter_orcpt_buf,
+ "%.*s;", (int) type_len,
+ arg_val),
+ arg_val + type_len + 1) == 0) {
+ msg_warn("%s: Bad ORCPT parameter from MILTER: \"%.100s\"",
+ state->queue_id, arg);
+ } else {
+ dsn_orcpt_info = STR(state->milter_orcpt_buf);
+ }
+ } else {
+ msg_warn("%s: ignoring ESMTP argument from MILTER: \"%.100s\"",
+ state->queue_id, arg);
+ }
+ }
+ argv_free(esmtp_argv);
+ }
if (msg_verbose)
msg_info("%s: \"%s\"", myname, ext_rcpt);
* overwrite the old "recipient append" pointer with the forward pointer
* to the new recipient.
*/
-#define NO_DSN_ORCPT ((char *) 0)
-
if ((new_rcpt_offset = vstream_fseek(state->dst, (off_t) 0, SEEK_END)) < 0) {
msg_warn("%s: seek file %s: %m", myname, cleanup_path);
return (cleanup_milter_error(state, errno));
}
}
tok822_free_tree(tree);
- cleanup_addr_bcc_dsn(state, STR(int_rcpt_buf), NO_DSN_ORCPT, DEF_DSN_NOTIFY);
+ cleanup_addr_bcc_dsn(state, STR(int_rcpt_buf), dsn_orcpt_info,
+ dsn_notify ? dsn_notify : DEF_DSN_NOTIFY);
vstring_free(int_rcpt_buf);
if (addr_count == 0) {
msg_warn("%s: ignoring attempt from Milter to add null recipient",
return (CLEANUP_OUT_OK(state) ? 0 : cleanup_milter_error(state, 0));
}
-/* cleanup_add_rcpt_par - append recipient address, ignore ESMTP arguments */
+/* cleanup_add_rcpt - append recipient address */
-static const char *cleanup_add_rcpt_par(void *context, const char *ext_rcpt,
- const char *esmtp_args)
+static const char *cleanup_add_rcpt(void *context, const char *ext_rcpt)
{
- const char *myname = "cleanup_add_rcpt";
- CLEANUP_STATE *state = (CLEANUP_STATE *) context;
-
- if (esmtp_args[0])
- msg_warn("%s: %s: ignoring ESMTP arguments \"%.100s\"",
- state->queue_id, myname, esmtp_args);
- return (cleanup_add_rcpt(context, ext_rcpt));
+ return (cleanup_add_rcpt_par(context, ext_rcpt, ""));
}
/* cleanup_del_rcpt - remove recipient and all its expansions */
state->append_meta_pt_target = -1;
state->milter_hbc_checks = 0;
state->milter_hbc_reply = 0;
+ state->milter_orcpt_buf = 0;
state->rcpt_count = 0;
state->reason = 0;
state->smtp_reply = 0;
myfree(state->reason);
if (state->smtp_reply)
myfree(state->smtp_reply);
+ if (state->milter_orcpt_buf)
+ vstring_free(state->milter_orcpt_buf);
nvtable_free(state->attr);
if (state->mime_state)
mime_state_free(state->mime_state);
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20131122"
+#define MAIL_RELEASE_DATE "20131126"
#define MAIL_VERSION_NUMBER "2.11"
#ifdef SNAPSHOT
/* VSTRING *xtext_unquote(unquoted, quoted)
/* VSTRING *unquoted;
/* const char *quoted;
+/*
+/* VSTRING *xtext_unquote_append(unquoted, quoted)
+/* VSTRING *unquoted;
+/* const char *quoted;
/* DESCRIPTION
/* xtext_quote() takes a null-terminated string and replaces characters
/* +, <33(10) and >126(10), as well as characters specified with "special"
/* understands lowercase, uppercase, and mixed case +XX sequences. The
/* result value is the unquoted argument in case of success, a null pointer
/* otherwise.
+/*
+/* xtext_unquote_append() is like xtext_unquote(), but appends
+/* the conversion result to the result buffer.
/* BUGS
/* This module cannot process null characters in data.
/* LICENSE
return (quoted);
}
-/* xtext_unquote - quoted data to unquoted */
+/* xtext_unquote_append - quoted data to unquoted */
-VSTRING *xtext_unquote(VSTRING *unquoted, const char *quoted)
+VSTRING *xtext_unquote_append(VSTRING *unquoted, const char *quoted)
{
const char *cp;
int ch;
- VSTRING_RESET(unquoted);
for (cp = quoted; (ch = *cp) != 0; cp++) {
if (ch == '+') {
if (ISDIGIT(cp[1]))
VSTRING_TERMINATE(unquoted);
return (unquoted);
}
+/* xtext_unquote - quoted data to unquoted */
+
+VSTRING *xtext_unquote(VSTRING *unquoted, const char *quoted)
+{
+ VSTRING_RESET(unquoted);
+ xtext_unquote_append(unquoted, quoted);
+ return (unquoted);
+}
#ifdef TEST
extern VSTRING *xtext_quote(VSTRING *, const char *, const char *);
extern VSTRING *xtext_quote_append(VSTRING *, const char *, const char *);
extern VSTRING *xtext_unquote(VSTRING *, const char *);
+extern VSTRING *xtext_unquote_append(VSTRING *, const char *);
/* LICENSE
/* .ad
/* Specifies a non-default reply for the MTA command specified
/* with \fB-c\fR. The default is \fBtempfail\fR.
/* .IP "\fB-A address\fR"
-/* Add the specified recipient address. Multiple -A options
-/* are supported.
+/* Add the specified recipient address (specify ESMTP parameters
+/* separated by space). Multiple -A options are supported.
/* .IP "\fB-b pathname
/* Replace the message body by the content of the specified file.
/* .IP "\fB-c connect|helo|mail|rcpt|data|header|eoh|body|eom|unknown|close|abort\fR"
#endif
{
int count;
-
- for (count = 0; count < add_rcpt_count; count++)
- if (smfi_addrcpt(ctx, add_rcpt[count]) == MI_FAILURE)
- fprintf(stderr, "smfi_addrcpt `%s' failed\n", add_rcpt[count]);
+ char *args;
+
+ for (count = 0; count < add_rcpt_count; count++) {
+ if ((args = strchr(add_rcpt[count], ' ')) != 0) {
+ *args++ = 0;
+ if (smfi_addrcpt_par(ctx, add_rcpt[count], args) == MI_FAILURE)
+ fprintf(stderr, "smfi_addrcpt_par `%s' `%s' failed\n",
+ add_rcpt[count], args);
+ } else {
+ if (smfi_addrcpt(ctx, add_rcpt[count]) == MI_FAILURE)
+ fprintf(stderr, "smfi_addrcpt `%s' failed\n",
+ add_rcpt[count]);
+ }
+ }
for (count = 0; count < del_rcpt_count; count++)
if (smfi_delrcpt(ctx, del_rcpt[count]) == MI_FAILURE)