Merge branch 'master' into 4.next
authorJeremy Harris <jgh@wizmail.org>
Sun, 1 Oct 2017 14:36:32 +0000 (15:36 +0100)
committerJeremy Harris <jgh@wizmail.org>
Sun, 1 Oct 2017 14:36:32 +0000 (15:36 +0100)
544 files changed:
Readme.pod
doc/doc-docbook/Makefile
doc/doc-docbook/Markup.txt
doc/doc-docbook/spec.xfpt
doc/doc-src/FAQ.src
doc/doc-txt/ChangeLog
doc/doc-txt/NewStuff
doc/doc-txt/OptionLists.txt
doc/doc-txt/experimental-spec.txt
src/Makefile
src/OS/Makefile-AIX [deleted file]
src/OS/Makefile-BSDI [deleted file]
src/OS/Makefile-Base
src/OS/Makefile-CYGWIN [deleted file]
src/OS/Makefile-DGUX [deleted file]
src/OS/Makefile-Darwin [deleted file]
src/OS/Makefile-DragonFly [deleted file]
src/OS/Makefile-GNU [deleted file]
src/OS/Makefile-GNUkFreeBSD [deleted file]
src/OS/Makefile-GNUkNetBSD [deleted file]
src/OS/Makefile-HI-OSF [deleted file]
src/OS/Makefile-HI-UX [deleted file]
src/OS/Makefile-HP-UX [deleted file]
src/OS/Makefile-HP-UX-9 [deleted file]
src/OS/Makefile-IRIX [deleted file]
src/OS/Makefile-IRIX6 [deleted file]
src/OS/Makefile-IRIX632 [deleted file]
src/OS/Makefile-IRIX65 [deleted file]
src/OS/Makefile-NetBSD [deleted file]
src/OS/Makefile-NetBSD-a.out [deleted file]
src/OS/Makefile-OSF1 [deleted file]
src/OS/Makefile-OpenUNIX [deleted file]
src/OS/Makefile-QNX [deleted file]
src/OS/Makefile-SCO [deleted file]
src/OS/Makefile-SCO_SV [deleted file]
src/OS/Makefile-SunOS4 [deleted file]
src/OS/Makefile-SunOS5-hal [deleted file]
src/OS/Makefile-ULTRIX [deleted file]
src/OS/Makefile-UNIX_SV [deleted file]
src/OS/Makefile-USG [deleted file]
src/OS/Makefile-Unixware7 [deleted file]
src/OS/Makefile-mips [deleted file]
src/OS/os.c-BSDI [deleted file]
src/OS/os.c-FreeBSD [new file with mode: 0644]
src/OS/os.c-GNU [deleted file]
src/OS/os.c-HI-OSF [deleted file]
src/OS/os.c-HP-UX [deleted file]
src/OS/os.c-IRIX [deleted file]
src/OS/os.c-IRIX6 [deleted file]
src/OS/os.c-IRIX632 [deleted file]
src/OS/os.c-IRIX65 [deleted file]
src/OS/os.c-Linux
src/OS/os.c-OSF1 [deleted file]
src/OS/os.c-cygwin [deleted file]
src/OS/os.h-AIX [deleted file]
src/OS/os.h-BSDI [deleted file]
src/OS/os.h-DGUX [deleted file]
src/OS/os.h-Darwin [deleted file]
src/OS/os.h-DragonFly [deleted file]
src/OS/os.h-FreeBSD
src/OS/os.h-GNU [deleted file]
src/OS/os.h-GNUkFreeBSD [deleted file]
src/OS/os.h-GNUkNetBSD [deleted file]
src/OS/os.h-HI-OSF [deleted file]
src/OS/os.h-HI-UX [deleted file]
src/OS/os.h-HP-UX [deleted file]
src/OS/os.h-HP-UX-9 [deleted file]
src/OS/os.h-IRIX [deleted file]
src/OS/os.h-IRIX6 [deleted file]
src/OS/os.h-IRIX632 [deleted file]
src/OS/os.h-IRIX65 [deleted file]
src/OS/os.h-Linux
src/OS/os.h-NetBSD [deleted file]
src/OS/os.h-NetBSD-a.out [deleted file]
src/OS/os.h-OSF1 [deleted file]
src/OS/os.h-OpenUNIX [deleted file]
src/OS/os.h-QNX [deleted file]
src/OS/os.h-SCO [deleted file]
src/OS/os.h-SCO_SV [deleted file]
src/OS/os.h-SunOS4 [deleted file]
src/OS/os.h-SunOS5-hal [deleted file]
src/OS/os.h-ULTRIX [deleted file]
src/OS/os.h-UNIX_SV [deleted file]
src/OS/os.h-USG [deleted file]
src/OS/os.h-Unixware7 [deleted file]
src/OS/os.h-cygwin [deleted file]
src/OS/os.h-mips [deleted file]
src/OS/unsupported/Makefile-AIX [new file with mode: 0644]
src/OS/unsupported/Makefile-BSDI [new file with mode: 0644]
src/OS/unsupported/Makefile-CYGWIN [new file with mode: 0644]
src/OS/unsupported/Makefile-DGUX [new file with mode: 0644]
src/OS/unsupported/Makefile-Darwin [new file with mode: 0644]
src/OS/unsupported/Makefile-DragonFly [new file with mode: 0644]
src/OS/unsupported/Makefile-GNU [new file with mode: 0644]
src/OS/unsupported/Makefile-GNUkFreeBSD [new file with mode: 0644]
src/OS/unsupported/Makefile-GNUkNetBSD [new file with mode: 0644]
src/OS/unsupported/Makefile-HI-OSF [new file with mode: 0644]
src/OS/unsupported/Makefile-HI-UX [new file with mode: 0644]
src/OS/unsupported/Makefile-HP-UX [new file with mode: 0644]
src/OS/unsupported/Makefile-HP-UX-9 [new file with mode: 0644]
src/OS/unsupported/Makefile-IRIX [new file with mode: 0644]
src/OS/unsupported/Makefile-IRIX6 [new file with mode: 0644]
src/OS/unsupported/Makefile-IRIX632 [new file with mode: 0644]
src/OS/unsupported/Makefile-IRIX65 [new file with mode: 0644]
src/OS/unsupported/Makefile-NetBSD [new file with mode: 0644]
src/OS/unsupported/Makefile-NetBSD-a.out [new file with mode: 0644]
src/OS/unsupported/Makefile-OSF1 [new file with mode: 0644]
src/OS/unsupported/Makefile-OpenUNIX [new file with mode: 0644]
src/OS/unsupported/Makefile-QNX [new file with mode: 0644]
src/OS/unsupported/Makefile-SCO [new file with mode: 0644]
src/OS/unsupported/Makefile-SCO_SV [new file with mode: 0644]
src/OS/unsupported/Makefile-SunOS4 [new file with mode: 0644]
src/OS/unsupported/Makefile-SunOS5-hal [new file with mode: 0644]
src/OS/unsupported/Makefile-ULTRIX [new file with mode: 0644]
src/OS/unsupported/Makefile-UNIX_SV [new file with mode: 0644]
src/OS/unsupported/Makefile-USG [new file with mode: 0644]
src/OS/unsupported/Makefile-Unixware7 [new file with mode: 0644]
src/OS/unsupported/Makefile-mips [new file with mode: 0644]
src/OS/unsupported/README [new file with mode: 0644]
src/OS/unsupported/os.c-BSDI [new file with mode: 0644]
src/OS/unsupported/os.c-GNU [new file with mode: 0644]
src/OS/unsupported/os.c-HI-OSF [new file with mode: 0644]
src/OS/unsupported/os.c-HP-UX [new file with mode: 0644]
src/OS/unsupported/os.c-IRIX [new file with mode: 0644]
src/OS/unsupported/os.c-IRIX6 [new file with mode: 0644]
src/OS/unsupported/os.c-IRIX632 [new file with mode: 0644]
src/OS/unsupported/os.c-IRIX65 [new file with mode: 0644]
src/OS/unsupported/os.c-OSF1 [new file with mode: 0644]
src/OS/unsupported/os.c-cygwin [new file with mode: 0644]
src/OS/unsupported/os.h-AIX [new file with mode: 0644]
src/OS/unsupported/os.h-BSDI [new file with mode: 0644]
src/OS/unsupported/os.h-DGUX [new file with mode: 0644]
src/OS/unsupported/os.h-Darwin [new file with mode: 0644]
src/OS/unsupported/os.h-DragonFly [new file with mode: 0644]
src/OS/unsupported/os.h-GNU [new file with mode: 0644]
src/OS/unsupported/os.h-GNUkFreeBSD [new file with mode: 0644]
src/OS/unsupported/os.h-GNUkNetBSD [new file with mode: 0644]
src/OS/unsupported/os.h-HI-OSF [new file with mode: 0644]
src/OS/unsupported/os.h-HI-UX [new file with mode: 0644]
src/OS/unsupported/os.h-HP-UX [new file with mode: 0644]
src/OS/unsupported/os.h-HP-UX-9 [new file with mode: 0644]
src/OS/unsupported/os.h-IRIX [new file with mode: 0644]
src/OS/unsupported/os.h-IRIX6 [new file with mode: 0644]
src/OS/unsupported/os.h-IRIX632 [new file with mode: 0644]
src/OS/unsupported/os.h-IRIX65 [new file with mode: 0644]
src/OS/unsupported/os.h-NetBSD [new file with mode: 0644]
src/OS/unsupported/os.h-NetBSD-a.out [new file with mode: 0644]
src/OS/unsupported/os.h-OSF1 [new file with mode: 0644]
src/OS/unsupported/os.h-OpenUNIX [new file with mode: 0644]
src/OS/unsupported/os.h-QNX [new file with mode: 0644]
src/OS/unsupported/os.h-SCO [new file with mode: 0644]
src/OS/unsupported/os.h-SCO_SV [new file with mode: 0644]
src/OS/unsupported/os.h-SunOS4 [new file with mode: 0644]
src/OS/unsupported/os.h-SunOS5-hal [new file with mode: 0644]
src/OS/unsupported/os.h-ULTRIX [new file with mode: 0644]
src/OS/unsupported/os.h-UNIX_SV [new file with mode: 0644]
src/OS/unsupported/os.h-USG [new file with mode: 0644]
src/OS/unsupported/os.h-Unixware7 [new file with mode: 0644]
src/OS/unsupported/os.h-cygwin [new file with mode: 0644]
src/OS/unsupported/os.h-mips [new file with mode: 0644]
src/exim_monitor/em_globals.c
src/exim_monitor/em_hdr.h
src/exim_monitor/em_log.c
src/exim_monitor/em_main.c
src/exim_monitor/em_menu.c
src/exim_monitor/em_queue.c
src/exim_monitor/em_version.c
src/scripts/Configure-Makefile
src/scripts/MakeLinks
src/scripts/reversion
src/src/EDITME
src/src/acl.c
src/src/auths/auth-spa.c
src/src/auths/call_pam.c
src/src/auths/cram_md5.c
src/src/auths/cyrus_sasl.c
src/src/auths/dovecot.c
src/src/auths/get_data.c
src/src/auths/get_no64_data.c
src/src/auths/gsasl_exim.c
src/src/auths/heimdal_gssapi.c
src/src/auths/md5.c
src/src/auths/plaintext.c
src/src/auths/pwcheck.c
src/src/auths/spa.c
src/src/auths/tls.c
src/src/auths/xtextencode.c
src/src/base64.c
src/src/bmi_spam.c
src/src/config.h.defaults
src/src/daemon.c
src/src/dane-openssl.c
src/src/dbfn.c
src/src/dbstuff.h
src/src/dcc.c
src/src/debug.c
src/src/deliver.c
src/src/dkim.c
src/src/dkim.h
src/src/dkim_transport.c [new file with mode: 0644]
src/src/dmarc.c
src/src/dns.c
src/src/drtables.c
src/src/exigrep.src
src/src/exim.c
src/src/exim.h
src/src/exim_dbmbuild.c
src/src/exim_dbutil.c
src/src/eximstats.src
src/src/exipick.src
src/src/expand.c
src/src/filter.c
src/src/functions.h
src/src/globals.c
src/src/globals.h
src/src/hash.c
src/src/hash.h
src/src/host.c
src/src/ip.c
src/src/local_scan.h
src/src/log.c
src/src/lookups/cdb.c
src/src/lookups/dbmdb.c
src/src/lookups/dnsdb.c
src/src/lookups/ibase.c
src/src/lookups/lmdb.c
src/src/lookups/mysql.c
src/src/lookups/sqlite.c
src/src/macro_predef.c [new file with mode: 0644]
src/src/macro_predef.h [new file with mode: 0644]
src/src/macros.h
src/src/malware.c
src/src/match.c
src/src/mime.c
src/src/mytypes.h
src/src/os.c
src/src/parse.c
src/src/pdkim/Makefile
src/src/pdkim/crypt_ver.h
src/src/pdkim/pdkim.c
src/src/pdkim/pdkim.h
src/src/pdkim/pdkim_hash.h
src/src/pdkim/rsa.c [deleted file]
src/src/pdkim/rsa.h [deleted file]
src/src/pdkim/signing.c [new file with mode: 0644]
src/src/pdkim/signing.h [new file with mode: 0644]
src/src/perl.c
src/src/queue.c
src/src/rda.c
src/src/readconf.c
src/src/receive.c
src/src/regex.c
src/src/retry.c
src/src/rfc2047.c
src/src/route.c
src/src/routers/accept.c
src/src/routers/dnslookup.c
src/src/routers/ipliteral.c
src/src/routers/iplookup.c
src/src/routers/manualroute.c
src/src/routers/queryprogram.c
src/src/routers/redirect.c
src/src/routers/rf_get_errors_address.c
src/src/routers/rf_get_munge_headers.c
src/src/routers/rf_queue_add.c
src/src/sieve.c
src/src/smtp_in.c
src/src/smtp_out.c
src/src/spam.c
src/src/spf.c
src/src/spool_in.c
src/src/spool_mbox.c
src/src/spool_out.c
src/src/std-crypto.c
src/src/store.c
src/src/string.c
src/src/structs.h
src/src/tls-gnu.c
src/src/tls-openssl.c
src/src/tls.c
src/src/tlscert-gnu.c
src/src/tlscert-openssl.c
src/src/tod.c
src/src/transport.c
src/src/transports/appendfile.c
src/src/transports/appendfile.h
src/src/transports/autoreply.c
src/src/transports/lmtp.c
src/src/transports/pipe.c
src/src/transports/queuefile.c
src/src/transports/smtp.c
src/src/transports/smtp.h
src/src/transports/smtp_socks.c
src/src/transports/tf_maildir.c
src/src/utf8.c
src/src/verify.c
src/src/version.c
test/confs/0021
test/confs/0211
test/confs/0227
test/confs/0547
test/confs/0580 [new file with mode: 0644]
test/confs/0581 [new symlink]
test/confs/0582 [new symlink]
test/confs/0906 [new file with mode: 0644]
test/confs/0907 [new file with mode: 0644]
test/confs/0908 [new file with mode: 0644]
test/confs/1990 [new file with mode: 0644]
test/confs/2007
test/confs/2013
test/confs/2035 [new file with mode: 0644]
test/confs/2036 [new symlink]
test/confs/2037 [new symlink]
test/confs/2038 [new file with mode: 0644]
test/confs/2052 [deleted file]
test/confs/2107
test/confs/2113
test/confs/2135 [new file with mode: 0644]
test/confs/2136 [new symlink]
test/confs/2137 [new symlink]
test/confs/2138 [new file with mode: 0644]
test/confs/2152 [deleted file]
test/confs/4012 [new file with mode: 0644]
test/confs/4020
test/confs/4027 [new symlink]
test/confs/4503 [new symlink]
test/confs/4520
test/confs/4523 [new symlink]
test/confs/4524 [new symlink]
test/confs/4530 [new symlink]
test/confs/5010 [new file with mode: 0644]
test/confs/5011 [new file with mode: 0644]
test/confs/5012 [new file with mode: 0644]
test/confs/5601
test/confs/5740
test/confs/5840
test/dnszones-src/db.test.ex
test/lib/Exim/Runtest.pm
test/log/0211
test/log/0227
test/log/0376
test/log/0429
test/log/0506
test/log/0547
test/log/0551
test/log/0578
test/log/0580 [new file with mode: 0644]
test/log/0581 [new file with mode: 0644]
test/log/0582 [new file with mode: 0644]
test/log/0609
test/log/0901
test/log/0906 [new file with mode: 0644]
test/log/1990 [new file with mode: 0644]
test/log/2013
test/log/2035 [new file with mode: 0644]
test/log/2036 [new file with mode: 0644]
test/log/2037 [new file with mode: 0644]
test/log/2038 [new file with mode: 0644]
test/log/2052 [deleted file]
test/log/2091
test/log/2113
test/log/2135 [new file with mode: 0644]
test/log/2136 [new file with mode: 0644]
test/log/2137 [new file with mode: 0644]
test/log/2138 [new file with mode: 0644]
test/log/2152 [deleted file]
test/log/2191
test/log/3454
test/log/3464
test/log/4027 [new file with mode: 0644]
test/log/4203
test/log/4213
test/log/4223
test/log/4500
test/log/4503 [new file with mode: 0644]
test/log/4506
test/log/4520
test/log/4521
test/log/4523 [new file with mode: 0644]
test/log/4524 [new file with mode: 0644]
test/log/4530 [new file with mode: 0644]
test/log/4700
test/log/5002
test/log/5010 [new file with mode: 0644]
test/log/5011 [new file with mode: 0644]
test/log/5012 [new file with mode: 0644]
test/log/5601
test/log/5740
test/log/5840
test/mail/0906.a [new file with mode: 0644]
test/mail/2013.usera [new file with mode: 0644]
test/mail/2013.userb [new file with mode: 0644]
test/mail/2013.userc [new file with mode: 0644]
test/mail/2038.userx0 [new file with mode: 0644]
test/mail/2038.userx1 [new file with mode: 0644]
test/mail/2038.usery0 [new file with mode: 0644]
test/mail/2038.usery1 [new file with mode: 0644]
test/mail/2038.userz0 [new file with mode: 0644]
test/mail/2038.userz1 [new file with mode: 0644]
test/mail/2113.usera [new file with mode: 0644]
test/mail/2113.userb [new file with mode: 0644]
test/mail/2113.userc [new file with mode: 0644]
test/mail/2138.userx0 [new file with mode: 0644]
test/mail/2138.userx1 [new file with mode: 0644]
test/mail/2138.usery0 [new file with mode: 0644]
test/mail/2138.usery1 [new file with mode: 0644]
test/mail/2138.userz0 [new file with mode: 0644]
test/mail/2138.userz1 [new file with mode: 0644]
test/mail/4530.y [new file with mode: 0644]
test/mail/4530.z [new file with mode: 0644]
test/mail/5010.maildirsize [new file with mode: 0644]
test/mail/5010.new/1.myhost.test.ex [new file with mode: 0644]
test/mail/5011.maildirsize [new file with mode: 0644]
test/mail/5012.maildirsize [new file with mode: 0644]
test/mail/5012.new/1.myhost.test.ex [new file with mode: 0644]
test/mail/5012.new/2.myhost.test.ex [new file with mode: 0644]
test/paniclog/0021
test/rejectlog/0227
test/rejectlog/0376
test/rejectlog/0578
test/rejectlog/0582 [new file with mode: 0644]
test/rejectlog/0901
test/rejectlog/2037 [new file with mode: 0644]
test/rejectlog/2137 [new file with mode: 0644]
test/runtest
test/scripts/0000-Basic/0002
test/scripts/0000-Basic/0211
test/scripts/0000-Basic/0227
test/scripts/0000-Basic/0547
test/scripts/0000-Basic/0551
test/scripts/0000-Basic/0580 [new file with mode: 0644]
test/scripts/0000-Basic/0581 [new file with mode: 0644]
test/scripts/0000-Basic/0582 [new file with mode: 0644]
test/scripts/0000-Basic/0901
test/scripts/0000-Basic/0906 [new file with mode: 0644]
test/scripts/0000-Basic/0907 [new file with mode: 0644]
test/scripts/0000-Basic/0908 [new symlink]
test/scripts/1990-TCP-Fast-Open/1990 [new file with mode: 0644]
test/scripts/1990-TCP-Fast-Open/REQUIRES [new file with mode: 0644]
test/scripts/2000-GnuTLS/2013
test/scripts/2000-GnuTLS/2031
test/scripts/2000-GnuTLS/2035 [new file with mode: 0644]
test/scripts/2000-GnuTLS/2036 [new file with mode: 0644]
test/scripts/2000-GnuTLS/2037 [new file with mode: 0644]
test/scripts/2000-GnuTLS/2038 [new file with mode: 0644]
test/scripts/2000-GnuTLS/2052 [deleted file]
test/scripts/2000-GnuTLS/2090
test/scripts/2100-OpenSSL/2113
test/scripts/2100-OpenSSL/2135 [new file with mode: 0644]
test/scripts/2100-OpenSSL/2136 [new file with mode: 0644]
test/scripts/2100-OpenSSL/2137 [new file with mode: 0644]
test/scripts/2100-OpenSSL/2138 [new file with mode: 0644]
test/scripts/2100-OpenSSL/2152 [deleted file]
test/scripts/2100-OpenSSL/2190
test/scripts/4000-scanning/4012 [new file with mode: 0644]
test/scripts/4020-socks/4020
test/scripts/4027-TFO-socks/4027 [new file with mode: 0644]
test/scripts/4027-TFO-socks/REQUIRES [new file with mode: 0644]
test/scripts/4500-DKIM/4500
test/scripts/4500-DKIM/4503 [new file with mode: 0644]
test/scripts/4500-DKIM/4506
test/scripts/4500-DKIM/4520
test/scripts/4500-DKIM/4523 [new file with mode: 0644]
test/scripts/4500-DKIM/4524 [new file with mode: 0644]
test/scripts/4500-DKIM/4530 [new file with mode: 0644]
test/scripts/4700-dsn-info/4700
test/scripts/5000-maildir/5010 [new file with mode: 0644]
test/scripts/5000-maildir/5011 [new symlink]
test/scripts/5000-maildir/5012 [new symlink]
test/scripts/5600-OCSP-OpenSSL/5601
test/scripts/5730-OCSP-GnuTLS-events/5730
test/scripts/5740-OCSP-OpenSSL-events/5740
test/scripts/5840-DANE-OpenSSL/5840
test/src/fakens.c
test/src/server.c
test/stderr/0004
test/stderr/0021
test/stderr/0143
test/stderr/0169
test/stderr/0227
test/stderr/0275
test/stderr/0278
test/stderr/0361
test/stderr/0376
test/stderr/0386
test/stderr/0388
test/stderr/0393
test/stderr/0398
test/stderr/0402
test/stderr/0403
test/stderr/0404
test/stderr/0408
test/stderr/0432
test/stderr/0476
test/stderr/0487
test/stderr/0512
test/stderr/0547
test/stderr/0551 [new file with mode: 0644]
test/stderr/0578
test/stderr/0609
test/stderr/0907 [new file with mode: 0644]
test/stderr/0908 [new file with mode: 0644]
test/stderr/2013
test/stderr/2035 [new file with mode: 0644]
test/stderr/2113
test/stderr/2135 [new file with mode: 0644]
test/stderr/2600
test/stderr/3400
test/stderr/4520
test/stderr/5004
test/stderr/5005
test/stderr/5006
test/stderr/5008
test/stderr/5410
test/stderr/5420
test/stderr/5840
test/stdout/0002
test/stdout/0035
test/stdout/0211
test/stdout/0227
test/stdout/0245
test/stdout/0250
test/stdout/0254
test/stdout/0311
test/stdout/0338
test/stdout/0376
test/stdout/0377
test/stdout/0378
test/stdout/0379
test/stdout/0389
test/stdout/0488
test/stdout/0490
test/stdout/0514
test/stdout/0551
test/stdout/0578
test/stdout/0901
test/stdout/0906 [new file with mode: 0644]
test/stdout/2090
test/stdout/2190
test/stdout/3415
test/stdout/4027 [new file with mode: 0644]
test/stdout/4530 [new file with mode: 0644]
test/stdout/5840
test/t/00-basic.t

index b82161e9373e55493554e682a406f029abb1d736..df75f8958e872855056f5abd124bab2446c1b725 100644 (file)
@@ -19,26 +19,25 @@ wiki document.
 
 =head2 Development Repositories
 
-Exim development is kept within a  git (L<http://git-scm.com/>)
+Exim development is kept within a  git (L<https://git-scm.com/>)
 repository. The master repository is at L<git://git.exim.org/exim.git>
 with a web interface giving change and source visibility at
-L<http://git.exim.org/exim.git>
+L<https://git.exim.org/exim.git>
 
 There is a secondary repository on github at
 L<https://github.com/Exim/exim> managed by the Exim Organisation
-L<https://github.com/Exim> - however this may currently fall out of
-synchronisation with the main one. We intend to manage this better in
-the future, but it is currently early days for our github repo.
+- however this may currently fall out of synchronisation with the
+main one.
 
 =head2 Bug Tracking
 
-Currently this is all done using Bugzilla at L<http://bugs.exim.org/>
+Currently this is all done using Bugzilla at L<https://bugs.exim.org/>
 - please do not use github issue tracking.
 
 =head2 Mailing List
 
 Development issues are normally discussed on the exim-dev mailing list
-- see L<http://www.exim.org/maillist.html>
+- see L<https://www.exim.org/maillist.html>
 
 =head2 Exim Release Process
 
@@ -48,19 +47,19 @@ L<http://wiki.exim.org/EximRelease>.
 =head2 General Exim Information
 
 The best place to get general information is on the website at
-L<http://www.exim.org/>.
+L<https://www.exim.org/>.
 
-You can find Download locations L<http://www.exim.org/mirrors.html>,
-Mailing list info L<http://www.exim.org/maillist.html> and Full
-Documentation L<http://www.exim.org/docs.html> on that website.
+You can find Download locations L<https://www.exim.org/mirrors.html>,
+Mailing list info L<https://www.exim.org/maillist.html> and Full
+Documentation L<https://www.exim.org/docs.html> on that website.
 
 If you are using a Linux or other freely available Unix like operating
 system it is very likely that your system will have Exim packaged for
 it already. In this case it is probably prudent to use these packages
 unless you have specialised requirements.
 
-In any case you can always ask on the 
-Exim Users mailing list L<https://lists.exim.org/mailman/listinfo/exim-users> 
+In any case you can always ask on the
+Exim Users mailing list L<https://lists.exim.org/mailman/listinfo/exim-users>
 for further information.
 
 [End]
index d835db9edfa961036999ed9a6b80148c61ff96e3..ee97257b64d98915a0ceef7a9bbe7ae86a4ddb89 100644 (file)
@@ -96,6 +96,7 @@ filter.txt:   filter-txt.xml Tidytxt MyStyle-txt-html.xsl MyStyle-html.xsl \
                 MyStyle.xsl
              /bin/rm -rf filter-txt.html
              xmlto -x MyStyle-txt-html.xsl html-nochunks filter-txt.xml
+             command -v w3m >/dev/null
              LC_ALL=C w3m -dump filter-txt.html | ./Tidytxt >filter.txt
              ./SanityTestText filter.txt
 
@@ -181,9 +182,11 @@ spec.utf8: spec-txt.html Tidytxt
                @grep -iq 'LC_CTYPE=.*utf-\?8' local_params || { \
                        echo 'your current locale does not support UTF-8' >&2; \
                        false; }
+               command -v w3m >/dev/null
                w3m -dump $< | ./Tidytxt -utf8 >$@
 
 spec.txt: spec-txt.html Tidytxt
+             command -v w3m >/dev/null
              LC_ALL=C w3m -dump $< | ./Tidytxt >$@
              ./SanityTestText spec.txt
 
@@ -270,6 +273,7 @@ test.txt:     test-txt.xml Tidytxt MyStyle-txt-html.xsl MyStyle-html.xsl \
                 MyStyle.xsl
              /bin/rm -rf test-txt.html
              xmlto -x MyStyle-txt-html.xsl html-nochunks test-txt.xml
+             command -v w3m >/dev/null
              w3m -dump test-txt.html | Tidytxt >test.txt
 
 # I have not found a way of making docbook2texi write its output anywhere
index 9f591955feea5ebd97daf3fe2ae27bc6e11d194b..58116a792f82ab82ffa9bfaaffdac9c08bb64373 100644 (file)
@@ -139,9 +139,9 @@ To refer to a URL, use &url, followed by parentheses that can enclose one or
 two arguments, comma separated. The second, if present, is used as the
 displayed text. If there is only one argument, it is used both as the displayed
 text and as the URL. For example, here is a reference to
-&url(http://www.exim.org/,the exim home page). In HTML output, all you see is
+&url(https://www.exim.org/,the exim home page). In HTML output, all you see is
 the display text; in printed output you see something like "the exim home page
-[http://www.exim.org/]". The URL is printed in a bold font.
+[https://www.exim.org/]". The URL is printed in a bold font.
 
 
 CHAPTERS AND SECTIONS
index be93cf67075ebd93f4493b621ecd1c49f2a216a2..4a8e1d06e39b4f5945d6e23bd634c13984fd729f 100644 (file)
@@ -464,7 +464,7 @@ which contains what used to be a separate FAQ, as well as various other
 examples, tips, and know-how that have been contributed by Exim users.
 
 .cindex Bugzilla
-An Exim Bugzilla exists at &url(http://bugs.exim.org). You can use
+An Exim Bugzilla exists at &url(https://bugs.exim.org). You can use
 this to report bugs, and also to add items to the wish list. Please search
 first to check that you are not duplicating a previous entry.
 
@@ -493,18 +493,11 @@ via this web page:
 Please ask Debian-specific questions on this list and not on the general Exim
 lists.
 
-.section "Exim training" "SECID4"
-.cindex "training courses"
-Training courses in Cambridge (UK) used to be run annually by the author of
-Exim, before he retired. At the time of writing, there are no plans to run
-further Exim courses in Cambridge. However, if that changes, relevant
-information will be posted at &url(http://www-tus.csx.cam.ac.uk/courses/exim/).
-
 .section "Bug reports" "SECID5"
 .cindex "bug reports"
 .cindex "reporting bugs"
 Reports of obvious bugs can be emailed to &'bugs@exim.org'& or reported
-via the Bugzilla (&url(http://bugs.exim.org)). However, if you are unsure
+via the Bugzilla (&url(https://bugs.exim.org)). However, if you are unsure
 whether some behaviour is a bug or not, the best thing to do is to post a
 message to the &'exim-dev'& mailing list and have it discussed.
 
@@ -515,10 +508,6 @@ message to the &'exim-dev'& mailing list and have it discussed.
 .cindex "distribution" "ftp site"
 The master ftp site for the Exim distribution is
 .display
-&*ftp://ftp.csx.cam.ac.uk/pub/software/email/exim*&
-.endd
-This is mirrored by
-.display
 &*ftp://ftp.exim.org/pub/exim*&
 .endd
 The file references that follow are relative to the &_exim_& directories at
@@ -1678,6 +1667,9 @@ Symbolic links to the sources are installed in this directory, which is where
 the actual building takes place. In most cases, Exim can discover the machine
 architecture and operating system for itself, but the defaults can be
 overridden if necessary.
+.cindex compiler requirements
+.cindex compiler version
+A C99-capable compiler will be required for the build.
 
 
 .section "PCRE library" "SECTpcre"
@@ -3869,12 +3861,12 @@ by Exim in conjunction with the &%-MC%& option, and passes on the fact that the
 host to which Exim is connected supports TLS encryption.
 
 .new
-.vitem &%-MCt%&&~<&'IP&~address'&>&~<&'port'&>
+.vitem &%-MCt%&&~<&'IP&~address'&>&~<&'port'&>&~<&'cipher'&>
 .oindex "&%-MCt%&"
 This option is not intended for use by external callers. It is used internally
 by Exim in conjunction with the &%-MC%& option, and passes on the fact that the
 connection is being proxied by a parent process for handling TLS encryption.
-The pair of arguments give the local address and port being proxied.
+The arguments give the local address and port being proxied, and the TLS cipher.
 .wen
 
 .vitem &%-Mc%&&~<&'message&~id'&>&~<&'message&~id'&>&~...
@@ -4285,7 +4277,7 @@ or &%-bs%& is used. For &%-bh%&, the protocol is forced to one of the standard
 SMTP protocol names (see the description of &$received_protocol$& in section
 &<<SECTexpvar>>&). For &%-bs%&, the protocol is always &"local-"& followed by
 one of those same names. For &%-bS%& (batched SMTP) however, the protocol can
-be set by &%-oMr%&.
+be set by &%-oMr%&. Repeated use of this option is not supported.
 
 .vitem &%-oMs%&&~<&'host&~name'&>
 .oindex "&%-oMs%&"
@@ -4385,6 +4377,7 @@ host name and its colon can be omitted when only the protocol is to be set.
 Note the Exim already has two private options, &%-pd%& and &%-ps%&, that refer
 to embedded Perl. It is therefore impossible to set a protocol value of &`d`&
 or &`s`& using this option (but that does not seem a real limitation).
+Repeated use of this option is not supported.
 
 .vitem &%-q%&
 .oindex "&%-q%&"
@@ -11042,9 +11035,14 @@ colon-separated components are permitted, each containing from one to four
 hexadecimal digits. There may be fewer than eight components if an empty
 component (adjacent colons) is present. Only one empty component is permitted.
 
-&*Note*&: The checks are just on the form of the address; actual numerical
-values are not considered. Thus, for example, 999.999.999.999 passes the IPv4
-check. The main use of these tests is to distinguish between IP addresses and
+.new
+&*Note*&: The checks used to be just on the form of the address; actual numerical
+values were not considered. Thus, for example, 999.999.999.999 passed the IPv4
+check.
+This is no longer the case.
+.wen
+
+The main use of these tests is to distinguish between IP addresses and
 host names, or between IPv4 and IPv6 addresses. For example, you could use
 .code
 ${if isip4{$sender_host_address}...
@@ -11201,8 +11199,8 @@ example is:
 ${if match_domain{a.b.c}{x.y.z:a.b.c:p.q.r}{yes}{no}}
 .endd
 In each case, the second argument may contain any of the allowable items for a
-list of the appropriate type. Also, because the second argument (after
-expansion) is a standard form of list, it is possible to refer to a named list.
+list of the appropriate type. Also, because the second argument
+is a standard form of list, it is possible to refer to a named list.
 Thus, you can use conditions like this:
 .code
 ${if match_domain{$domain}{+local_domains}{...
@@ -12073,6 +12071,9 @@ when the ACL &%malware%& condition is true (see section &<<SECTscanvirus>>&).
 This variable contains the number of bytes in the longest line that was
 received as part of the message, not counting the line termination
 character(s).
+.new
+It is not valid if the &%spool_files_wireformat%& option is used.
+.wen
 
 .vitem &$message_age$&
 .cindex "message" "age of"
@@ -12115,6 +12116,12 @@ in bytes. The count starts from the character after the blank line that
 separates the body from the header. Newlines are included in the count. See
 also &$message_size$&, &$body_linecount$&, and &$body_zerocount$&.
 
+.new
+If the spool file is wireformat
+(see the &%spool_files_wireformat%& main option)
+the CRLF line-terminators are included in the count.
+.wen
+
 .vitem &$message_exim_id$&
 .vindex "&$message_exim_id$&"
 When a message is being received or delivered, this variable contains the
@@ -12165,6 +12172,10 @@ deny message   = Too many lines in message header
 In the MAIL and RCPT ACLs, the value is zero because at that stage the
 message has not yet been received.
 
+.new
+This variable is not valid if the &%spool_files_wireformat%& option is used.
+.wen
+
 .vitem &$message_size$&
 .cindex "size" "of message"
 .cindex "message" "size"
@@ -12785,6 +12796,15 @@ argument, that is, the text that follows the command name, with leading white
 space removed. Following the introduction of &$smtp_command$&, this variable is
 somewhat redundant, but is retained for backwards compatibility.
 
+.new
+.vitem &$smtp_command_history$&
+.cindex SMTP "command history"
+.vindex "&$smtp_command_history$&"
+A comma-separated list (with no whitespace) of the most-recent SMTP commands
+received, in time-order left to right.  Only a limited number of commands
+are remembered.
+.wen
+
 .vitem &$smtp_count_at_connection_start$&
 .vindex "&$smtp_count_at_connection_start$&"
 This variable is set greater than zero only in processes spawned by the Exim
@@ -13572,6 +13592,7 @@ listed in more than one group.
 .row &%message_body_visible%&        "how much to show in &$message_body$&"
 .row &%mua_wrapper%&                 "run in &""MUA wrapper""& mode"
 .row &%print_topbitchars%&           "top-bit characters are printing"
+.row &%spool_wireformat%&            "use wire-format spool data files when possible"
 .row &%timezone%&                    "force time zone"
 .endtable
 
@@ -13591,6 +13612,7 @@ listed in more than one group.
 .section "Privilege controls" "SECID98"
 .table2
 .row &%admin_groups%&                "groups that are Exim admin users"
+.row &%commandline_checks_require_admin%& "require admin for various checks"
 .row &%deliver_drop_privilege%&      "drop root for delivery processes"
 .row &%local_from_check%&            "insert &'Sender:'& if necessary"
 .row &%local_from_prefix%&           "for testing &'From:'& for local sender"
@@ -14453,6 +14475,14 @@ The CHUNKING extension (RFC3030) will be advertised in the EHLO message to
 these hosts.
 Hosts may use the BDAT command as an alternate to DATA.
 
+.new
+.option commandline_checks_require_admin main boolean &`false`&
+.cindex "restricting access to features"
+This option restricts various basic checking features to require an
+administrative user.
+This affects most of the &%-b*%& options, such as &%-be%&.
+.wen
+
 .option debug_store main boolean &`false`&
 .cindex debugging "memory corruption"
 .cindex memory debugging
@@ -15685,7 +15715,7 @@ harm. This option overrides the &%pipe_as_creator%& option of the &(pipe)&
 transport driver.
 
 
-.option openssl_options main "string list" "+no_sslv2 +single_dh_use"
+.option openssl_options main "string list" "+no_sslv2 +single_dh_use +no_ticket"
 .cindex "OpenSSL "compatibility options"
 This option allows an administrator to adjust the SSL options applied
 by OpenSSL to connections.  It is given as a space-separated list of items,
@@ -15934,12 +15964,13 @@ different spool directories.
 
 
 .option prod_requires_admin main boolean true
+.cindex "restricting access to features"
 .oindex "&%-M%&"
 .oindex "&%-R%&"
 .oindex "&%-q%&"
 The &%-M%&, &%-R%&, and &%-q%& command-line options require the caller to be an
 admin user unless &%prod_requires_admin%& is set false. See also
-&%queue_list_requires_admin%&.
+&%queue_list_requires_admin%& and &%commandline_checks_require_admin%&.
 
 
 .option qualify_domain main string "see below"
@@ -15978,10 +16009,12 @@ next queue run. See also &%hold_domains%& and &%queue_smtp_domains%&.
 
 
 .option queue_list_requires_admin main boolean true
+.cindex "restricting access to features"
 .oindex "&%-bp%&"
 The &%-bp%& command-line option, which lists the messages that are on the
 queue, requires the caller to be an admin user unless
-&%queue_list_requires_admin%& is set false. See also &%prod_requires_admin%&.
+&%queue_list_requires_admin%& is set false.
+See also &%prod_requires_admin%& and &%commandline_checks_require_admin%&.
 
 
 .option queue_only main boolean false
@@ -16827,6 +16860,32 @@ as failures in the configuration file.
 By using this option to override the compiled-in path, it is possible to run
 tests of Exim without using the standard spool.
 
+.new
+.option spool_wireformat main boolean false
+.cindex "spool directory" "file formats"
+If this option is set, Exim may for some messages use an alternate format
+for data-files in the spool which matches the wire format.
+Doing this permits more efficient message reception and transmission.
+Currently it is only done for messages received using the EMSTP CHUNKING
+option.
+
+The following variables will not have useful values:
+.code
+$max_received_linelength
+$body_linecount
+$body_zerocount
+.endd
+
+Users of the local_scan() API (see &<<CHAPlocalscan>>&),
+and any external programs which are passed a reference to a message data file
+(except via the &"regex"&, &"malware"& or &"spam"&) ACL conditions)
+will need to be aware of the potential different format.
+
+Using any of the ACL conditions noted will negate the reception benefit
+(as a Unix-mbox-format file is contructed for them).
+The transimssion benefit is maintained.
+.wen
+
 .option sqlite_lock_timeout main time 5s
 .cindex "sqlite lookup type" "lock timeout"
 This option controls the timeout that the &(sqlite)& lookup uses when trying to
@@ -19422,6 +19481,10 @@ instead of TRY_AGAIN. That is why the default action is to try a DNS
 lookup first. Only if that gives a definite &"no such host"& is the local
 function called.
 
+&*Compatibility*&: From Exim 4.85 until fixed for 4.90, there was an
+inadvertent constraint that a transport name as an option had to be the last
+option specified.
+
 
 
 If no IP address for a host can be found, what happens is controlled by the
@@ -20299,11 +20362,15 @@ relative path is then passed to the transport unmodified.
 
 
 .option forbid_blackhole redirect boolean false
+.cindex "restricting access to features"
+.cindex "filter" "locking out certain features"
 If this option is true, the &':blackhole:'& item may not appear in a
 redirection list.
 
 
 .option forbid_exim_filter redirect boolean false
+.cindex "restricting access to features"
+.cindex "filter" "locking out certain features"
 If this option is set true, only Sieve filters are permitted when
 &%allow_filter%& is true.
 
@@ -20311,7 +20378,9 @@ If this option is set true, only Sieve filters are permitted when
 
 
 .option forbid_file redirect boolean false
+.cindex "restricting access to features"
 .cindex "delivery" "to file; forbidding"
+.cindex "filter" "locking out certain features"
 .cindex "Sieve filter" "forbidding delivery to a file"
 .cindex "Sieve filter" "&""keep""& facility; disabling"
 If this option is true, this router may not generate a new address that
@@ -20322,17 +20391,22 @@ locks out the Sieve's &"keep"& facility.
 
 
 .option forbid_filter_dlfunc redirect boolean false
+.cindex "restricting access to features"
 .cindex "filter" "locking out certain features"
 If this option is true, string expansions in Exim filters are not allowed to
 make use of the &%dlfunc%& expansion facility to run dynamically loaded
 functions.
 
 .option forbid_filter_existstest redirect boolean false
+.cindex "restricting access to features"
+.cindex "filter" "locking out certain features"
 .cindex "expansion" "statting a file"
 If this option is true, string expansions in Exim filters are not allowed to
 make use of the &%exists%& condition or the &%stat%& expansion item.
 
 .option forbid_filter_logwrite redirect boolean false
+.cindex "restricting access to features"
+.cindex "filter" "locking out certain features"
 If this option is true, use of the logging facility in Exim filters is not
 permitted. Logging is in any case available only if the filter is being run
 under some unprivileged uid (which is normally the case for ordinary users'
@@ -20340,27 +20414,37 @@ under some unprivileged uid (which is normally the case for ordinary users'
 
 
 .option forbid_filter_lookup redirect boolean false
+.cindex "restricting access to features"
+.cindex "filter" "locking out certain features"
 If this option is true, string expansions in Exim filter files are not allowed
 to make use of &%lookup%& items.
 
 
 .option forbid_filter_perl redirect boolean false
+.cindex "restricting access to features"
+.cindex "filter" "locking out certain features"
 This option has an effect only if Exim is built with embedded Perl support. If
 it is true, string expansions in Exim filter files are not allowed to make use
 of the embedded Perl support.
 
 
 .option forbid_filter_readfile redirect boolean false
+.cindex "restricting access to features"
+.cindex "filter" "locking out certain features"
 If this option is true, string expansions in Exim filter files are not allowed
 to make use of &%readfile%& items.
 
 
 .option forbid_filter_readsocket redirect boolean false
+.cindex "restricting access to features"
+.cindex "filter" "locking out certain features"
 If this option is true, string expansions in Exim filter files are not allowed
 to make use of &%readsocket%& items.
 
 
 .option forbid_filter_reply redirect boolean false
+.cindex "restricting access to features"
+.cindex "filter" "locking out certain features"
 If this option is true, this router may not generate an automatic reply
 message. Automatic replies can be generated only from Exim or Sieve filter
 files, not from traditional forward files. This option is forced to be true if
@@ -20368,11 +20452,15 @@ files, not from traditional forward files. This option is forced to be true if
 
 
 .option forbid_filter_run redirect boolean false
+.cindex "restricting access to features"
+.cindex "filter" "locking out certain features"
 If this option is true, string expansions in Exim filter files are not allowed
 to make use of &%run%& items.
 
 
 .option forbid_include redirect boolean false
+.cindex "restricting access to features"
+.cindex "filter" "locking out certain features"
 If this option is true, items of the form
 .code
 :include:<path name>
@@ -20381,6 +20469,8 @@ are not permitted in non-filter redirection lists.
 
 
 .option forbid_pipe redirect boolean false
+.cindex "restricting access to features"
+.cindex "filter" "locking out certain features"
 .cindex "delivery" "to pipe; forbidding"
 If this option is true, this router may not generate a new address which
 specifies delivery to a pipe, either from an Exim filter or from a conventional
@@ -20388,6 +20478,8 @@ forward file. This option is forced to be true if &%one_time%& is set.
 
 
 .option forbid_sieve_filter redirect boolean false
+.cindex "restricting access to features"
+.cindex "filter" "locking out certain features"
 If this option is set true, only Exim filters are permitted when
 &%allow_filter%& is true.
 
@@ -22052,10 +22144,14 @@ the obvious value which users understand most easily.
 
 The value of the option is expanded, and must then be a numerical value
 (decimal point allowed), optionally followed by one of the letters K, M, or G,
-for kilobytes, megabytes, or gigabytes. If Exim is running on a system with
+for kilobytes, megabytes, or gigabytes, optionally followed by a slash
+and further option modifiers. If Exim is running on a system with
 large file support (Linux and FreeBSD have this), mailboxes larger than 2G can
 be handled.
 
+The option modifier &%no_check%& can be used to force delivery even if the over
+quota condition is met. The quota gets updated as usual.
+
 &*Note*&: A value of zero is interpreted as &"no quota"&.
 
 The expansion happens while Exim is running as root, before it changes uid for
@@ -22090,6 +22186,8 @@ can only be used if &%quota%& is also set. The value is expanded; an expansion
 failure causes delivery to be deferred. A value of zero is interpreted as
 &"no quota"&.
 
+The option modifier &%no_check%& can be used to force delivery even if the over
+quota condition is met. The quota gets updated as usual.
 
 .option quota_is_inclusive appendfile boolean true
 See &%quota%& above.
@@ -23695,12 +23793,14 @@ the message. As a result, the overall timeout for a message depends on the size
 of the message. Its value must not be zero. See also &%final_timeout%&.
 
 
-.option dkim_domain smtp string&!! unset
+.option dkim_domain smtp string list&!! unset
 .option dkim_selector smtp string&!! unset
 .option dkim_private_key smtp string&!! unset
 .option dkim_canon smtp string&!! unset
 .option dkim_strict smtp string&!! unset
 .option dkim_sign_headers smtp string&!! unset
+.option dkim_hash smtp string&!! sha256
+.option dkim_identity smtp string&!! unset
 DKIM signing options.  For details see section &<<SECDKIMSIGN>>&.
 
 
@@ -27637,13 +27737,22 @@ built, then you have SNI support).
          "SECTmulmessam"
 .cindex "multiple SMTP deliveries with TLS"
 .cindex "TLS" "multiple message deliveries"
+.new
 Exim sends multiple messages down the same TCP/IP connection by starting up
 an entirely new delivery process for each message, passing the socket from
 one process to the next. This implementation does not fit well with the use
 of TLS, because there is quite a lot of state information associated with a TLS
 connection, not just a socket identification. Passing all the state information
-to a new process is not feasible. Consequently, Exim shuts down an existing TLS
-session before passing the socket to a new process. The new process may then
+to a new process is not feasible. Consequently, for sending using TLS Exim
+starts an additional proxy process for handling the encryption, piping the
+unencrypted data stream from and to the delivery processes.
+
+An older mode of operation can be enabled on a per-host basis by the
+&%hosts_noproxy_tls%& option on the &(smtp)& transport.  If the host matches
+this list the proxy process descibed above is not used; instead Exim
+.wen
+shuts down an existing TLS session being run by the delivery process
+before passing the socket to a new process. The new process may then
 try to start a new TLS session, and if successful, may try to re-authenticate
 if AUTH is in use, before sending the next message.
 
@@ -28971,6 +29080,11 @@ and cannot depend on content of received headers.
 Note also that headers cannot be
 modified by any of the post-data ACLs (DATA, MIME and DKIM).
 Headers may be modified by routers (subject to the above) and transports.
+.new
+The Received-By: header is generated as soon as the body reception starts,
+rather than the traditional time after the full message is received;
+this will affect the timestamp.
+.wen
 
 All the usual ACLs are called; if one results in the message being
 rejected, all effort spent in delivery (including the costs on
@@ -29008,12 +29122,14 @@ sender when the destination system is doing content-scan based rejection.
 .cindex "&ACL;" "enabling debug logging"
 .cindex "debugging" "enabling from an ACL"
 This control turns on debug logging, almost as though Exim had been invoked
-with &`-d`&, with the output going to a new logfile, by default called
-&'debuglog'&.  The filename can be adjusted with the &'tag'& option, which
+with &`-d`&, with the output going to a new logfile in the usual logs directory,
+by default called &'debuglog'&.
+The filename can be adjusted with the &'tag'& option, which
 may access any variables already defined.  The logging may be adjusted with
 the &'opts'& option, which takes the same values as the &`-d`& command-line
 option.
-Logging may be stopped, and the file removed, with the &'kill'& option.
+Logging started this way may be stopped, and the file removed,
+with the &'kill'& option.
 Some examples (which depend on variables that don't exist in all
 contexts):
 .code
@@ -30903,6 +31019,23 @@ command when performing the callout, instead of an empty address. There is no
 need to use this option unless you know that the called hosts make use of the
 sender when checking recipients. If used indiscriminately, it reduces the
 usefulness of callout caching.
+
+.new
+.vitem &*hold*&
+This option applies to recipient callouts only. For example:
+.code
+require  verify = recipient/callout=use_sender,hold
+.endd
+It causes the connection to be helod open and used for any further recipients
+and for eventual delivery (should that be done quickly).
+Doing this saves on TCP and SMTP startup costs, and TLS costs also
+when that is used for the connections.
+The advantage is only gained if there are no callout cache hits
+(which could be enforced by the no_cache option),
+if the use_sender option is used,
+if neither the random nor the use_postmaster option is used,
+and if no other callouts intervene.
+.wen
 .endlist
 
 If you use any of the parameters that set a non-empty sender for the MAIL
@@ -31594,14 +31727,18 @@ an address (which may be an IP address and port, or the path of a Unix socket),
 a commandline to send (may include a single %s which will be replaced with
 the path to the mail file to be scanned),
 an RE to trigger on from the returned data,
-an RE to extract malware_name from the returned data.
+and an RE to extract malware_name from the returned data.
 For example:
 .code
-av_scanner = sock:127.0.0.1 6001:%s:(SPAM|VIRUS):(.*)\$
+av_scanner = sock:127.0.0.1 6001:%s:(SPAM|VIRUS):(.*)$
 .endd
-Default for the socket specifier is &_/tmp/malware.sock_&.
-Default for the commandline is &_%s\n_&.
-Both regular-expressions are required.
+.new
+Note that surrounding whitespace is stripped from each option, meaning
+there is no way to specify a trailing newline.
+The socket specifier and both regular-expressions are required.
+Default for the commandline is &_%s\n_& (note this does have a trailing newline);
+specify an empty element to get this.
+.wen
 
 .vitem &%sophie%&
 .cindex "virus scanners" "Sophos and Sophie"
@@ -32441,9 +32578,15 @@ C variables are as follows:
 .vlist
 .vitem &*int&~body_linecount*&
 This variable contains the number of lines in the message's body.
+.new
+It is not valid if the &%spool_files_wireformat%& option is used.
+.wen
 
 .vitem &*int&~body_zerocount*&
 This variable contains the number of binary zero bytes in the message's body.
+.new
+It is not valid if the &%spool_files_wireformat%& option is used.
+.wen
 
 .vitem &*unsigned&~int&~debug_selector*&
 This variable is set to zero when no debugging is taking place. Otherwise, it
@@ -35769,9 +35912,9 @@ down a single SMTP connection, an asterisk follows the IP address in the log
 lines for the second and subsequent messages.
 .new
 When two or more messages are delivered down a single TLS connection, the
-TLS-related information logged for the first message delivered
-(which may not be the earliest line in the log)
+DNS and some TLS-related information logged for the first message delivered
 will not be present in the log lines for the second and subsequent messages.
+TLS cipher information is still available.
 .wen
 
 .cindex "delivery" "cutthrough; logging"
@@ -35885,6 +36028,7 @@ the following table:
 &`I   `&        local interface used
 &`K   `&        CHUNKING extension used
 &`id  `&        message id for incoming message
+&`M8S `&        8BITMIME status for incoming message
 &`P   `&        on &`<=`& lines: protocol used
 &`    `&        on &`=>`& and &`**`& lines: return path
 &`PRDR`&        PRDR extension used
@@ -35898,6 +36042,7 @@ the following table:
 &`SNI `&        server name indication from TLS client hello
 &`ST  `&        shadow transport name
 &`T   `&        on &`<=`& lines: message subject (topic)
+&`TFO `&        connection took advantage of TCP Fast Open
 &`    `&        on &`=>`& &`**`& and &`==`& lines: transport name
 &`U   `&        local user or RFC 1413 identity
 &`X   `&        TLS cipher suite
@@ -35979,6 +36124,7 @@ selection marked by asterisks:
 &` incoming_interface         `&  local interface on <= and => lines
 &` incoming_port              `&  remote port on <= lines
 &`*lost_incoming_connection   `&  as it says (includes timeouts)
+&` millisec                   `&  millisecond timestamps and QT,DT,D times
 &` outgoing_interface         `&  local interface on => lines
 &` outgoing_port              `&  add remote port to => lines
 &`*queue_run                  `&  start and end queue runs
@@ -36068,6 +36214,8 @@ process is started because &%queue_only%& is set or &%-odq%& was used.
 .cindex "log" "delivery duration"
 &%deliver_time%&: For each delivery, the amount of real time it has taken to
 perform the actual delivery is logged as DT=<&'time'&>, for example, &`DT=1s`&.
+If millisecond logging is enabled, short times will be shown with greater
+precision, eg. &`DT=0.304`&.
 .next
 .cindex "log" "message size on delivery"
 .cindex "size" "of message"
@@ -36143,6 +36291,14 @@ important with the widening use of NAT (see RFC 2505).
 &%lost_incoming_connection%&: A log line is written when an incoming SMTP
 connection is unexpectedly dropped.
 .next
+.new
+.cindex "log" "millisecond timestamps"
+.cindex millisecond logging
+.cindex timstamps "millisecond, in logs"
+&%millisec%&: Timestamps have a period and three decimal places of finer granularity
+appended to the seconds value.
+.wen
+.next
 .cindex "log" "outgoing interface"
 .cindex "log" "local interface"
 .cindex "log" "local address and port"
@@ -36181,6 +36337,8 @@ includes reception time as well as the delivery time for the current address.
 This means that it may be longer than the difference between the arrival and
 delivery log line times, because the arrival log line is not written until the
 message has been successfully received.
+If millisecond logging is enabled, short times will be shown with greater
+precision, eg. &`QT=1.578s`&.
 .next
 &%queue_time_overall%&: The amount of time the message has been in the queue on
 the local host is logged as QT=<&'time'&> on &"Completed"& lines, for
@@ -36633,8 +36791,7 @@ autodetection of some well known compression extensions.
 .cindex "&'exipick'&"
 John Jetmore's &'exipick'& utility is included in the Exim distribution. It
 lists messages from the queue according to a variety of criteria. For details
-of &'exipick'&'s facilities, visit the web page at
-&url(http://www.exim.org/eximwiki/ToolExipickManPage) or run &'exipick'& with
+of &'exipick'&'s facilities, run &'exipick'& with
 the &%--help%& option.
 
 
@@ -37884,6 +38041,13 @@ the contents of files on the spool via the Exim monitor (which runs
 unprivileged), Exim must be built to allow group read access to its spool
 files.
 
+.new
+By default, regular users are trusted to perform basic testing and
+introspection commands, as themselves.  This setting can be tightened by
+setting the &%commandline_checks_require_admin%& option.
+This affects most of the checking options,
+such as &%-be%& and anything else &%-b*%&.
+.wen
 
 
 .section "Spool files" "SECID275"
@@ -38004,6 +38168,13 @@ file remains in existence. When Exim next processes the message, it notices the
 -J file and uses it to update the -H file before starting the next delivery
 attempt.
 
+.new
+Files whose names end with -K or .eml may also be seen in the spool.
+These are temporaries used for DKIM or malware processing, when that is used.
+They should be tidied up by normal operations; any old ones are probably
+relics of crashes and can be removed.
+.wen
+
 .section "Format of the -H file" "SECID282"
 .cindex "uid (user id)" "in spool file"
 .cindex "gid (group id)" "in spool file"
@@ -38081,8 +38252,8 @@ The address of an authenticated sender &-- the value of the
 &$authenticated_sender$& variable.
 
 .vitem "&%-body_linecount%&&~<&'number'&>"
-This records the number of lines in the body of the message, and is always
-present.
+This records the number of lines in the body of the message, and is
+present unless &%-spool_file_wireformat%& is.
 
 .vitem "&%-body_zerocount%&&~<&'number'&>"
 This records the number of binary zero bytes in the body of the message, and is
@@ -38164,6 +38335,14 @@ to ensure that the caller is displayed in queue listings).
 If a message was scanned by SpamAssassin, this is present. It records the value
 of &$spam_score_int$&.
 
+.new
+.vitem &%-spool_file_wireformat%&
+The -D file for this message is in wire-format (for ESMTP CHUNKING)
+rather than Unix-format.
+The line-ending is CRLF rather than newline.
+There is still, however, no leading-dot-stuffing.
+.wen
+
 .vitem &%-tls_certificate_verified%&
 A TLS certificate was received from the client that sent this message, and the
 certificate was verified by the server.
@@ -38271,6 +38450,20 @@ unqualified domain &'foundation'&.
 .ecindex IIDforspo2
 .ecindex IIDforspo3
 
+.new
+.section "Format of the -D file" "SECID282a"
+The data file is traditionally in Unix-standard format: lines are ended with
+an ASCII newline character.
+However, when the &%spool_wireformat%& main option is used some -D files
+can have an alternate format.
+This is flagged by a &%-spool_file_wireformat%& line in the corresponding -H file.
+The -D file lines (not including the first name-component line) are
+suitable for direct copying to the wire when transmitting using the
+ESMTP CHUNKING option, meaning lower processing overhead.
+Lines are terminated with an ASCII CRLF pair.
+There is no dot-stuffing (and no dot-termination).
+.wen
+
 . ////////////////////////////////////////////////////////////////////////////
 . ////////////////////////////////////////////////////////////////////////////
 
@@ -38325,22 +38518,28 @@ senders).
 Signing is enabled by setting private options on the SMTP transport.
 These options take (expandable) strings as arguments.
 
-.option dkim_domain smtp string&!! unset
-MANDATORY:
-The domain you want to sign with. The result of this expanded
-option is put into the &%$dkim_domain%& expansion variable.
+.option dkim_domain smtp string list&!! unset
+The domain(s) you want to sign with.
+.new
+After expansion, this can be a list.
+Each element in turn is put into the &%$dkim_domain%& expansion variable
+while expanding the remaining signing options.
+.wen
 If it is empty after expansion, DKIM signing is not done.
 
-.option dkim_selector smtp string&!! unset
-MANDATORY:
-This sets the key selector string. You can use the &%$dkim_domain%& expansion
-variable to look up a matching selector. The result is put in the expansion
+.option dkim_selector smtp string list&!! unset
+This sets the key selector string.
+.new
+After expansion, which can use &$dkim_domain$&, this can be a list.
+Each element in turn is put in the expansion
 variable &%$dkim_selector%& which may be used in the &%dkim_private_key%&
 option along with &%$dkim_domain%&.
+If the option is empty after expansion, DKIM signing is not done for this domain.
+.wen
 
 .option dkim_private_key smtp string&!! unset
-MANDATORY:
-This sets the private key to use. You can use the &%$dkim_domain%& and
+This sets the private key to use.
+You can use the &%$dkim_domain%& and
 &%$dkim_selector%& expansion variables to determine the private key to use.
 The result can either
 .ilist
@@ -38353,16 +38552,28 @@ be "0", "false" or the empty string, in which case the message will not
 be signed. This case will not result in an error, even if &%dkim_strict%&
 is set.
 .endlist
+If the option is empty after expansion, DKIM signing is not done.
+
+.new
+.option dkim_hash smtp string&!! sha256
+Can be set alternatively to &"sha1"& to use an alternate hash
+method.  Note that sha1 is now condidered insecure, and deprecated.
+
+.option dkim_identity smtp string&!! unset
+If set after expansion, the value is used to set an "i=" tag in
+the signing header.  The DKIM standards restrict the permissible
+syntax of this optional tag to a mail address, with possibly-empty
+local part, an @, and a domain identical to or subdomain of the "d="
+tag value.  Note that Exim does not check the value.
+.wen
 
 .option dkim_canon smtp string&!! unset
-OPTIONAL:
 This option sets the canonicalization method used when signing a message.
 The DKIM RFC currently supports two methods: "simple" and "relaxed".
 The option defaults to "relaxed" when unset. Note: the current implementation
 only supports using the same canonicalization method for both headers and body.
 
 .option dkim_strict smtp string&!! unset
-OPTIONAL:
 This  option  defines  how  Exim  behaves  when  signing a message that
 should be signed fails for some reason.  When the expansion evaluates to
 either "1" or "true", Exim will defer. Otherwise Exim will send the message
@@ -38370,11 +38581,10 @@ unsigned. You can use the &%$dkim_domain%& and &%$dkim_selector%& expansion
 variables here.
 
 .option dkim_sign_headers smtp string&!! unset
-OPTIONAL:
-When set, this option must expand to (or be specified as) a colon-separated
+If set, this option must expand to (or be specified as) a colon-separated
 list of header names. Headers with these names will be included in the message
-signature. When unspecified, the header names recommended in RFC4871 will be
-used.
+signature.
+When unspecified, the header names recommended in RFC4871 will be used.
 
 
 .section "Verifying DKIM signatures in incoming mail" "SECID514"
@@ -38385,7 +38595,7 @@ Verification of DKIM signatures in SMTP incoming email is implemented via the
 syntactically(!) correct signature in the incoming message.
 A missing ACL definition defaults to accept.
 If any ACL call does not accept, the message is not accepted.
-If a cutthrough delivery was in progress for the message it is
+If a cutthrough delivery was in progress for the message, that is
 summarily dropped (having wasted the transmission effort).
 
 To evaluate the signature in the ACL a large number of expansion variables
@@ -38488,7 +38698,7 @@ The algorithm used. One of 'rsa-sha1' or 'rsa-sha256'.
 .vitem &%$dkim_canon_body%&
 The body canonicalization method. One of 'relaxed' or 'simple'.
 
-.vitem &%dkim_canon_headers%&
+.vitem &%$dkim_canon_headers%&
 The header canonicalization method. One of 'relaxed' or 'simple'.
 
 .vitem &%$dkim_copiedheaders%&
@@ -38897,7 +39107,7 @@ The current list of events is:
 &`msg:rcpt:host:defer    after    transport  `& per recipient per host
 &`msg:rcpt:defer         after    transport  `& per recipient
 &`msg:host:defer         after    transport  `& per attempt
-&`msg:fail:delivery      after    main       `& per recipient
+&`msg:fail:delivery      after    transport  `& per recipient
 &`msg:fail:internal      after    main       `& per recipient
 &`tcp:connect            before   transport  `& per connection
 &`tcp:close              after    transport  `& per connection
@@ -38914,6 +39124,11 @@ The second column in the table above describes whether the event fires
 before or after the action is associates with.  Those which fire before
 can be used to affect that action (more on this below).
 
+.new
+The third column in the table above says what section of the configumration
+should define the event action.
+.wen
+
 An additional variable, &$event_data$&, is filled with information varying
 with the event type:
 .display
index 1d43cbcd251ad1e0191acd428fd7b225db815844..1ff867b62fbed819c51a7a56ed1108de0ddb494e 100644 (file)
@@ -1861,7 +1861,7 @@ A0117: Here! This is a contribution from a RedHat user, somewhat edited. On
 
 ==>      adduser exim
 
-       (3) Now you can prepare to build Exim. Go to \?http://www.exim.org?\ or
+       (3) Now you can prepare to build Exim. Go to \?https://www.exim.org?\ or
        one of its mirrors, or the master ftp site
        \?ftp://ftp.csx.cam.ac.uk/pub/software/email/exim/exim4?\, and download
        \(exim-4.20.tar.gz)\ or whatever the current release is. Then:
@@ -7122,7 +7122,7 @@ C037:  An elegant way of using ETRN, which does immediate delivery if the host
 C042:  ``Since the Exim 4 configuration needed to get Mailman to work differs a
        little bit from Exim 3 and since I still haven't seen a recipe for
        Mailman with Exim 4, I'm providing my configuration (based heavily on
-       \?http://www.exim.org/howto/mailman.html?\).''
+       \?https://www.exim.org/howto/mailman21.html?\).''
 
 C043:  ``Attached is an Exim 4 config file which is designed for an Exim server
        that is put in front of an Exchange 5.5 system but which verifies the
index 5b5dcbd7f7c37bc77cb4b5b2228301c98891c2c9..8f1b6b7ad0ecac60956989bee15e1dc67d7ffedd 100644 (file)
@@ -24,7 +24,7 @@ JH/03 Rework the transport continued-connection mechanism: when TLS is active,
       the passed-on TCP connection.  Instead, proxy the child (and any
       subsequent ones) for TLS via a unix-domain socket channel.  Logging is
       affected: the continued delivery log lines do not have any DNSSEC, TLS
-      cipher, Certificate or OCSP information.
+      Certificate or OCSP information.  TLS cipher information is still logged.
 
 JH/04 Shorten the log line for daemon startup by collapsing adjacent sets of
       identical IP addresses on different listening ports.  Will also affect
@@ -34,6 +34,138 @@ PP/02 Bug 2070: uClibc defines __GLIBC__ without providing glibc headers;
       add noisy ifdef guards to special-case this sillyness.
       Patch from Bernd Kuhls.
 
+JH/05 Tighten up the checking in isip4 (et al): dotted-quad components larger
+      than 255 are no longer allowed.
+
+JH/06 Default openssl_options to include +no_ticket, to reduce load on peers.
+      Disable the session-cache too, which might reduce our load.  Since we
+      currrectly use a new context for every connection, both as server and
+      client, there is no benefit for these.
+      GnuTLS appears to not support tickets server-side by default (we don't
+      call gnutls_session_ticket_enable_server()) but client side is enabled
+      by default on recent versions (3.1.3 +) unless the PFS priority string
+      is used (3.2.4 +).
+
+PP/03 Add $SOURCE_DATE_EPOCH support for reproducible builds, per spec at
+      <https://reproducible-builds.org/specs/source-date-epoch/>.
+
+JH/07 Fix smtp transport use of limited max_rcpt under mua_wrapper. Previously
+      the check for any unsuccessful recipients did not notice the limit, and
+      erroneously found still-pending ones.
+
+JH/08 Pipeline CHUNKING command and data together, on kernels that support
+      MSG_MORE.  Only in-clear (not on TLS connections).
+
+JH/09 Avoid using a temporary file during transport using dkim.  Unless a
+      transport-filter is involved we can buffer the headers in memory for
+      creating the signature, and read the spool data file once for the
+      signature and again for transmission.
+
+JH/10 Enable use of sendfile in Linux builds as default.  It was disabled in
+      4.77 as the kernel support then wasn't solid, having issues in 64bit
+      mode.  Now, it's been long enough.  Add support for FreeBSD also.
+
+JH/11 Bug 2104: Fix continued use of a transport connection with TLS.  In the
+      case where the routing stage had gathered several addresses to send to
+      a host before calling the transport for the first, we previously failed
+      to close down TLS in the old transport process before passing the TCP
+      connection to the new process.  The new one sent a STARTTLS command
+      which naturally failed, giving a failed delivery and bloating the retry
+      database.  Investigation and fix prototype from Wolfgang Breyha.
+
+JH/12 Fix check on SMTP command input synchronisation.  Previously there were
+      false-negatives in the check that the sender had not preempted a response
+      or prompt from Exim (running as a server), due to that code's lack of
+      awareness of the SMTP input buffering.
+
+PP/04 Add commandline_checks_require_admin option.
+      Exim drops privileges sanely, various checks such as -be aren't a
+      security problem, as long as you trust local users with access to their
+      own account.  When invoked by services which pass untrusted data to
+      Exim, this might be an issue.  Set this option in main configuration
+      AND make fixes to the calling application, such as using `--` to stop
+      processing options.
+
+JH/13 Do pipelining under TLS.  Previously, although safe, no advantage was
+      taken.  Now take care to pack both (client) MAIL,RCPT,DATA, and (server)
+      responses to those, into a single TLS record each way (this usually means
+      a single packet).  As a side issue, smtp_enforce_sync now works on TLS
+      connections.
+
+PP/05 OpenSSL/1.1: use DH_bits() for more accurate DH param sizes.  This
+      affects you only if you're dancing at the edge of the param size limits.
+      If you are, and this message makes sense to you, then: raise the
+      configured limit or use OpenSSL 1.1.  Nothing we can do for older
+      versions.
+
+JH/14 For the "sock" variant of the malware scanner interface, accept an empty
+      cmdline element to get the documented default one.  Previously it was
+      inaccessible.
+
+JH/15 Fix a crash in the smtp transport caused when two hosts in succession
+      are unsuable for non-message-specific reasons - eg. connection timeout,
+      banner-time rejection.
+
+JH/16 Fix logging of delivery remote port, when specified by router, under
+      callout/hold.
+
+PP/06 Repair manualroute's ability to take options in any order, even if one
+      is the name of a transport.
+      Fixes bug 2140.
+
+HS/01 Cleanup, prevent repeated use of -p/-oMr (CVE-2017-1000369)
+
+JH/17 Change the list-building routines interface to use the expanding-string
+      triplet model, for better allocation and copying behaviour.
+
+JH/18 Prebuild the data-structure for "builtin" macros, for faster startup.
+      Previously it was constructed the first time a possibly-matching string
+      was met in the configuration file input during startup; now it is done
+      during compilation.
+
+JH/19 Bug 2141: Use the full-complex API for Berkeley DB rather than the legacy-
+      compatible one, to avoid the (poorly documented) possibility of a config
+      file in the working directory redirecting the DB files, possibly correpting
+      some existing file.  CVE-2017-10140 assigned for BDB.
+
+JH/20 Bug 2147: Do not defer for a verify-with-callout-and-random which is not
+      cache-hot.  Previously, although the result was properly cached, the
+      initial verify call returned a defer.
+
+JH/21 Bug 2151: Avoid using SIZE on the MAIL for a callout verify, on any but
+      the main verify for receipient in uncached-mode.
+
+JH/22 Retire historical build files to an "unsupported" subdir.  These are
+      defined as "ones for which we have no current evidence of testing".
+
+JH/23 DKIM: enforce the DNS pubkey record "h" permitted-hashes optional field,
+      if present.  Previously it was ignored.
+
+JH/24 Start using specified-initialisers in C structure init coding.  This is
+      a C99 feature (it's 2017, so now considered safe).
+
+JH/25 Use one-bit bitfields for flags in the "addr" data structure.  Previously
+      if was a fixed-sized field and bitmask ops via macros; it is now more
+      extensible.
+
+PP/07 GitHub PR 56: Apply MariaDB build fix.
+      Patch provided by Jaroslav Škarvada.
+
+PP/08 Bug 2161: Fix regression in sieve quoted-printable handling introduced
+      during Coverity cleanups [4.87 JH/47]
+      Diagnosis and fix provided by Michael Fischer v. Mollard.
+
+JH/26 Fix DKIM bug: when the pseudoheader generated for signing was exactly
+      the right size to place the terminating semicolon on its own folded
+      line, the header hash was calculated to an incorrect value thanks to
+      the (relaxed) space the fold became.
+
+HS/02 Fix Bug 2130: large writes from the transport subprocess where chunked
+      and confused the parent.
+
+JH/27 Fix SOCKS bug: an unitialized pointer was deref'd by the transport process
+      which could crash as a result.  This could lead to undeliverable messages.
+
 
 Exim version 4.89
 -----------------
index 872371fcb43de21489ffee2dd84059198dcdf590..39fce1eab71e533a9592a8225ac984b7a4a0a34d 100644 (file)
@@ -23,6 +23,43 @@ Version 4.90
 
  4. A malware connection type for the FPSCAND protocol.
 
+ 5. An option for recipient verify callouts to hold the connection open for
+    further recipients and for delivery.
+
+ 6. The reproducible build $SOURCE_DATE_EPOCH environment variable is now
+    supported.
+
+ 7. Optionally, an alternate format for spool data-files which matches the
+    wire format - meaning more efficient reception and transmission (at the
+    cost of difficulty with standard Unix tools).  Only used for messages
+    received using the ESMTP CHUNKING option, and when a new main-section
+    option "spool_wireformat" (false by default) is set.
+
+ 8. New main configuration option "commandline_checks_require_admin" to
+    restrict who can use various introspection options.
+
+ 9. New option modifier "no_check" for quota and quota_filecount
+    appendfile transport.
+
+10. Variable $smtp_command_history returning a comma-sep list of recent
+    SMTP commands.
+
+11. Millisecond timetamps in logs, on log_selector "millisec".  Also affects
+    log elements QT, DT and D, and timstamps in debug output.
+
+12. TCP Fast Open logging.  As a server, logs when the SMTP banner was sent
+    while still in SYN_RECV state; as a client logs when the connection
+    is opened with a TFO cookie.
+
+13. DKIM support for multiple signing, by domain and/or key-selector.
+    DKIM support for multiple hashes, and for alternate-identity tags.
+
+14. Exipick understands -C|--config for an alternative Exim
+    configuration file.
+
+15. TCP Fast Open used, with data-on-SYN, for client SMTP via SOCKS5 proxy,
+    for ${readsocket } expansions, and for ClamAV.
+
 
 Version 4.89
 ------------
@@ -382,7 +419,8 @@ Version 4.82
     It adds new expansion variables $dmarc_ar_header, $dmarc_status,
     $dmarc_status_text, and $dmarc_used_domain.  It adds a new acl modifier
     dmarc_status.  It adds new control flags dmarc_disable_verify and
-    dmarc_enable_forensic.
+    dmarc_enable_forensic. The default for the dmarc_tld_file option is
+    "/etc/exim/opendmarc.tlds" and can be changed via EDITME.
 
 22. Add expansion variable $authenticated_fail_id, which is the username
     provided to the authentication method which failed.  It is available
index b6439e6ed3e83cea69dc5ed6e6e8a6ad55d6ed68..5728643a8bb01bce129cd00bb66d7a8fc0ce2d97 100644 (file)
@@ -137,6 +137,7 @@ command                              string*         unset         lmtp
 command_group                        string          unset         queryprogram      4.00
 command_timeout                      time            5m            smtp
 command_user                         string          unset         queryprogram      4.00
+commandline_checks_require_admin     boolean         false         main              4.90
 condition                            string*         unset         routers           4.00
 connect_timeout                      time            0s            smtp              1.60
 connection_max_messages              integer         500           smtp              4.00 replaces batch_max
@@ -529,6 +530,7 @@ socket                               string*         unset         lmtp
 spamd_address                        string*         +             main              4.50 with content scan
 split_spool_directory                boolean         false         main              1.70
 spool_directory                      string          ++            main
+spool_wireformat                     boolean         false         main              4.90
 sqlite_lock_timeout                  time            5s            main              4.53
 strict_acl_vars                      boolean         false         main              4.64
 srv_fail_domains                     domain list     unset         dnslookup         4.43
index 0b1afb2478f0e142e123c454554dea2f78cd5d78..1e826aee172153f9fff248170fa425c5c348c353 100644 (file)
@@ -595,12 +595,14 @@ package controlled locations (/usr/include and /usr/lib).
 
 2. Use the following global settings to configure DMARC:
 
-Required:
+Optional:
 dmarc_tld_file      Defines the location of a text file of valid
                     top level domains the opendmarc library uses
                     during domain parsing. Maintained by Mozilla,
                     the most current version can be downloaded
                     from a link at http://publicsuffix.org/list/.
+                    If unset, "/etc/exim/opendmarc.tlds" (hardcoded)
+                    is used.
 
 Optional:
 dmarc_history_file  Defines the location of a file to log results
index 2a100bbddede0862ca3ec1597df5fb5d4f841aba..b262a7b53792c3884cd9f6e2561cda0effaee30d 100644 (file)
@@ -105,11 +105,10 @@ cscope.files: FRC
        echo "-q" > $@
        echo "-p3" >> $@
        find src Local OS exim_monitor -name "*.[cshyl]" -print \
-                   -o -name "os.h*" -print \
+                   -o -name "os.[ch]*" -print \
                    -o -name "*akefile*" -print \
                    -o -name config.h.defaults -print \
                    -o -name EDITME -print >> $@
-       ls OS/* >> $@
 
 FRC:
 
diff --git a/src/OS/Makefile-AIX b/src/OS/Makefile-AIX
deleted file mode 100644 (file)
index fc32aa2..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-# Exim: OS-specific make file for AIX
-# Written by Nick Waterman (nick@cimio.co.uk)
-# Modified by PH following a message from Mike Meredith
-
-# Note that the output of uname -m is probably not what Philip expected,
-# so you might end up with more build-AIX-random_number directories than
-# you expected if you have too many AIX boxes, but it seems to work... I
-# blame IBM.
-
-# Note that nowadays you have to pay extra for a cc compiler with AIX!
-
-CC=gcc
-
-# This needs to be in here rather than os.h-AIX because of regexp stuff.
-# basically strchr is a #define, which means "extern char *strchr()"
-# ruins things. __STR31__ seems to get around this by magic. The AIX
-# include files are quite a confusing maze.
-# Mike M says this is not necessary any more; possibly this is related to
-# using gcc. Commented out by PH.
-#CFLAGS = -D__STR31__
-
-CFLAGS = -mcpu=power4 -maix64 -O3
-
-# Needed for vfork() and vfork() only?
-
-LIBS = -lbsd -lm
-
-# End
diff --git a/src/OS/Makefile-BSDI b/src/OS/Makefile-BSDI
deleted file mode 100644 (file)
index d56aa9b..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-# Exim: OS-specific make file for BSDI aka BSD/OS. Its antique link editor
-# cannot handle the TextPop overriding.
-
-CFLAGS=-O
-CHOWN_COMMAND=/usr/sbin/chown
-
-HAVE_SA_LEN=YES
-
-X11=/usr/X11
-XINCLUDE=-I$(X11)/include
-XLFLAGS=-L$(X11)/lib
-X11_LD_LIB=$(X11)/lib
-
-LIBS_EXIMON=-lSM -lICE -lipc -lm
-EXIMON_TEXTPOP=
-
-EXIWHAT_PS_ARG=-ax
-EXIWHAT_EGREP_ARG='/exim( |$$)'
-EXIWHAT_KILL_SIGNAL=-USR1
-
-# End
index f6b42f353ad79cc23ae08e64ac66f255031e0841..67ac082bac8a9a0bc76a27aa24824da4acc667d2 100644 (file)
@@ -36,7 +36,7 @@ FE       = $(FULLECHO)
 # are set up, and finally it goes to the main Exim target.
 
 all:       utils exim
-config:    $(EDITME) checklocalmake Makefile os.c config.h version.h
+config:    $(EDITME) checklocalmake Makefile os.c config.h version.h macro.c
 
 checklocalmake: 
        @if $(SHELL) $(SCRIPTS)/newer $(EDITME)-$(OSTYPE) $(EDITME) || \
@@ -79,29 +79,41 @@ Makefile: ../OS/Makefile-Base ../OS/Makefile-Default \
 
 # Build (link) the os.h file
 
+#os.h: $(SCRIPTS)/Configure-os.h \
+#      $(O)/os.h-AIX           $(O)/os.h-BSDI  $(O)/os.h-cygwin \
+#      $(O)/os.h-Darwin        $(O)/os.h-DGUX  $(O)/os.h-DragonFly \
+#      $(O)/os.h-FreeBSD       $(O)/os.h-GNU   $(O)/os.h-GNUkFreeBSD \
+#      $(O)/os.h-GNUkNetBSD    $(O)/os.h-HI-OSF \
+#      $(O)/os.h-HI-UX         $(O)/os.h-HP-UX $(O)/os.h-HP-UX-9 \
+#      $(O)/os.h-IRIX          $(O)/os.h-IRIX6 $(O)/os.h-IRIX632 \
+#      $(O)/os.h-IRIX65        $(O)/os.h-Linux $(O)/os.h-mips \
+#      $(O)/os.h-NetBSD        $(O)/os.h-NetBSD-a.out \
+#      $(O)/os.h-OpenBSD       $(O)/os.h-OpenUNIX      $(O)/os.h-OSF1 \
+#      $(O)/os.h-QNX           $(O)/os.h-SCO           $(O)/os.h-SCO_SV \
+#      $(O)/os.h-SunOS4        $(O)/os.h-SunOS5        $(O)/os.h-SunOS5-hal \
+#      $(O)/os.h-ULTRIX        $(O)/os.h-UNIX_SV \
+#      $(O)/os.h-Unixware7     $(O)/os.h-USG
+#      $(SHELL) $(SCRIPTS)/Configure-os.h
+
 os.h:  $(SCRIPTS)/Configure-os.h \
-       $(O)/os.h-AIX           $(O)/os.h-BSDI  $(O)/os.h-cygwin \
-       $(O)/os.h-Darwin        $(O)/os.h-DGUX  $(O)/os.h-DragonFly \
-       $(O)/os.h-FreeBSD       $(O)/os.h-GNU   $(O)/os.h-GNUkFreeBSD \
-       $(O)/os.h-GNUkNetBSD    $(O)/os.h-HI-OSF \
-       $(O)/os.h-HI-UX         $(O)/os.h-HP-UX $(O)/os.h-HP-UX-9 \
-       $(O)/os.h-IRIX          $(O)/os.h-IRIX6 $(O)/os.h-IRIX632 \
-       $(O)/os.h-IRIX65        $(O)/os.h-Linux $(O)/os.h-mips \
-       $(O)/os.h-NetBSD        $(O)/os.h-NetBSD-a.out \
-       $(O)/os.h-OpenBSD       $(O)/os.h-OpenUNIX      $(O)/os.h-OSF1 \
-       $(O)/os.h-QNX           $(O)/os.h-SCO           $(O)/os.h-SCO_SV \
-       $(O)/os.h-SunOS4        $(O)/os.h-SunOS5        $(O)/os.h-SunOS5-hal \
-       $(O)/os.h-ULTRIX        $(O)/os.h-UNIX_SV \
-       $(O)/os.h-Unixware7     $(O)/os.h-USG
+       $(O)/os.h-FreeBSD       \
+       $(O)/os.h-Linux         \
+       $(O)/os.h-OpenBSD       \
+       $(O)/os.h-SunOS5
        $(SHELL) $(SCRIPTS)/Configure-os.h
 
 # Build the os.c file
 
+#os.c:   ../src/os.c \
+#      $(SCRIPTS)/Configure-os.c \
+#      $(O)/os.c-cygwin        $(O)/os.c-GNU   $(O)/os.c-HI-OSF \
+#      $(O)/os.c-IRIX          $(O)/os.c-IRIX6 $(O)/os.c-IRIX632 \
+#      $(O)/os.c-IRIX65        $(O)/os.c-Linux $(O)/os.c-OSF1
+#      $(SHELL) $(SCRIPTS)/Configure-os.c
+
 os.c:   ../src/os.c \
        $(SCRIPTS)/Configure-os.c \
-       $(O)/os.c-cygwin        $(O)/os.c-GNU   $(O)/os.c-HI-OSF \
-       $(O)/os.c-IRIX          $(O)/os.c-IRIX6 $(O)/os.c-IRIX632 \
-       $(O)/os.c-IRIX65        $(O)/os.c-Linux $(O)/os.c-OSF1
+       $(O)/os.c-Linux
        $(SHELL) $(SCRIPTS)/Configure-os.c
 
 # Build the config.h file.
@@ -109,6 +121,114 @@ os.c:   ../src/os.c \
 config.h: Makefile buildconfig ../src/config.h.defaults $(EDITME)
        $(SHELL) $(SCRIPTS)/Configure-config.h "$(MAKE)"
 
+# Build the builtin-macros data struct
+
+MACRO_HSRC = macro_predef.h os.h globals.h config.h \
+       routers/accept.h routers/dnslookup.h routers/ipliteral.h \
+       routers/iplookup.h routers/manualroute.h routers/queryprogram.h \
+       routers/redirect.h
+
+OBJ_MACRO = macro_predef.o \
+       macro-globals.o macro-readconf.o macro-route.o macro-transport.o macro-drtables.o \
+       macro-appendfile.o macro-autoreply.o macro-lmtp.o macro-pipe.o macro-queuefile.o \
+       macro-smtp.o macro-accept.o macro-dnslookup.o macro-ipliteral.o macro-iplookup.o \
+       macro-manualroute.o macro-queryprogram.o macro-redirect.o \
+       macro-auth-spa.o macro-cram_md5.o macro-cyrus_sasl.o macro-dovecot.o macro-gsasl_exim.o \
+       macro-heimdal_gssapi.o macro-plaintext.o macro-spa.o macro-tls.o\
+
+$(OBJ_MACRO):  $(MACRO_HSRC)
+
+macro_predef.o :       macro_predef.c
+       @echo "$(CC) -DMACRO_PREDEF macro_predef.c"
+       $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ macro_predef.c
+macro-globals.o :      globals.c
+       @echo "$(CC) -DMACRO_PREDEF globals.c"
+       $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ globals.c
+macro-readconf.o :     readconf.c
+       @echo "$(CC) -DMACRO_PREDEF readconf.c"
+       $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ readconf.c
+macro-route.o :                route.c
+       @echo "$(CC) -DMACRO_PREDEF route.c"
+       $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ route.c
+macro-transport.o:     transport.c
+       @echo "$(CC) -DMACRO_PREDEF transport.c"
+       $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ transport.c
+macro-drtables.o :     drtables.c
+       @echo "$(CC) -DMACRO_PREDEF drtables.c"
+       $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ drtables.c
+macro-appendfile.o :   transports/appendfile.c
+       @echo "$(CC) -DMACRO_PREDEF transports/appendfile.c"
+       $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ transports/appendfile.c
+macro-autoreply.o :    transports/autoreply.c
+       @echo "$(CC) -DMACRO_PREDEF transports/autoreply.c"
+       $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ transports/autoreply.c
+macro-lmtp.o:          transports/lmtp.c
+       @echo "$(CC) -DMACRO_PREDEF transports/lmtp.c"
+       $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ transports/lmtp.c
+macro-pipe.o :         transports/pipe.c
+       @echo "$(CC) -DMACRO_PREDEF transports/pipe.c"
+       $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ transports/pipe.c
+macro-queuefile.o :    transports/queuefile.c
+       @echo "$(CC) -DMACRO_PREDEF transports/queuefile.c"
+       $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ transports/queuefile.c
+macro-smtp.o :         transports/smtp.c
+       @echo "$(CC) -DMACRO_PREDEF transports/smtp.c"
+       $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ transports/smtp.c
+macro-accept.o :       routers/accept.c
+       @echo "$(CC) -DMACRO_PREDEF routers/accept.c"
+       $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ routers/accept.c
+macro-dnslookup.o :    routers/dnslookup.c
+       @echo "$(CC) -DMACRO_PREDEF routers/dnslookup.c"
+       $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ routers/dnslookup.c
+macro-ipliteral.o :    routers/ipliteral.c
+       @echo "$(CC) -DMACRO_PREDEF routers/ipliteral.c"
+       $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ routers/ipliteral.c
+macro-iplookup.o :     routers/iplookup.c
+       @echo "$(CC) -DMACRO_PREDEF routers/iplookup.c"
+       $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ routers/iplookup.c
+macro-manualroute.o :  routers/manualroute.c
+       @echo "$(CC) -DMACRO_PREDEF routers/manualroute.c"
+       $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ routers/manualroute.c
+macro-queryprogram.o : routers/queryprogram.c
+       @echo "$(CC) -DMACRO_PREDEF routers/queryprogram.c"
+       $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ routers/queryprogram.c
+macro-redirect.o :     routers/redirect.c
+       @echo "$(CC) -DMACRO_PREDEF routers/redirect.c"
+       $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ routers/redirect.c
+macro-auth-spa.o :     auths/auth-spa.c
+       @echo "$(CC) -DMACRO_PREDEF auths/auth-spa.c"
+       $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ auths/auth-spa.c
+macro-cram_md5.o :     auths/cram_md5.c
+       @echo "$(CC) -DMACRO_PREDEF auths/cram_md5.c"
+       $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ auths/cram_md5.c
+macro-cyrus_sasl.o :   auths/cyrus_sasl.c
+       @echo "$(CC) -DMACRO_PREDEF auths/cyrus_sasl.c"
+       $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ auths/cyrus_sasl.c
+macro-dovecot.o:       auths/dovecot.c
+       @echo "$(CC) -DMACRO_PREDEF auths/dovecot.c"
+       $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ auths/dovecot.c
+macro-gsasl_exim.o :   auths/gsasl_exim.c
+       @echo "$(CC) -DMACRO_PREDEF auths/gsasl_exim.c"
+       $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ auths/gsasl_exim.c
+macro-heimdal_gssapi.o:        auths/heimdal_gssapi.c
+       @echo "$(CC) -DMACRO_PREDEF auths/heimdal_gssapi.c"
+       $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ auths/heimdal_gssapi.c
+macro-plaintext.o :    auths/plaintext.c
+       @echo "$(CC) -DMACRO_PREDEF auths/plaintext.c"
+       $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ auths/plaintext.c
+macro-spa.o :          auths/spa.c
+       @echo "$(CC) -DMACRO_PREDEF auths/spa.c"
+       $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ auths/spa.c
+macro-tls.o:           auths/tls.c
+       @echo "$(CC) -DMACRO_PREDEF auths/tls.c"
+       $(FE)$(CC) -c $(CFLAGS) -DMACRO_PREDEF $(INCLUDE) -o $@ auths/tls.c
+
+macro_predef: $(OBJ_MACRO)
+       @echo "$(LNCC) -o $@"
+       $(FE)$(LNCC) -o $@ $(LFLAGS) $(OBJ_MACRO)
+
+macro.c: macro_predef
+       ./macro_predef > macro.c
 
 # This target is recognized specially by GNU make. It records those targets
 # that do not correspond to files that are being built and which should
@@ -331,13 +451,13 @@ OBJ_LOOKUPS = lookups/lf_quote.o lookups/lf_check_file.o lookups/lf_sqlperform.o
 
 OBJ_EXIM = acl.o base64.o child.o crypt16.o daemon.o dbfn.o debug.o deliver.o \
         directory.o dns.o drtables.o enq.o exim.o expand.o filter.o \
-        filtertest.o globals.o dkim.o hash.o \
+        filtertest.o globals.o dkim.o dkim_transport.o hash.o \
         header.o host.o ip.o log.o lss.o match.o moan.o \
         os.o parse.o queue.o \
         rda.o readconf.o receive.o retry.o rewrite.o rfc2047.o \
         route.o search.o sieve.o smtp_in.o smtp_out.o spool_in.o spool_out.o \
         std-crypto.o store.o string.o tls.o tod.o transport.o tree.o verify.o \
-        environment.o \
+        environment.o macro.o \
         $(OBJ_LOOKUPS) \
         local_scan.o $(EXIM_PERL) $(OBJ_WITH_CONTENT_SCAN) \
         $(OBJ_EXPERIMENTAL)
@@ -452,7 +572,7 @@ OBJ_MONBIN = util-spool_in.o \
             util-store.o \
             util-string.o \
             util-queue.o \
-            tod.o \
+            util-tod.o \
             tree.o \
             $(MONBIN)
 
@@ -557,7 +677,8 @@ exim_tidydb.o:   $(HDRS) exim_dbutil.c
 
 exim_dbmbuild.o: $(HDRS) exim_dbmbuild.c
        @echo "$(CC) exim_dbmbuild.c"
-       $(FE)$(CC) -c $(CFLAGS) $(INCLUDE) -o exim_dbmbuild.o exim_dbmbuild.c
+       $(FE)$(CC) -c $(CFLAGS) $(INCLUDE) -DCOMPILE_UTILITY \
+               -o exim_dbmbuild.o exim_dbmbuild.c
 
 # Utilities use special versions of some modules - typically with debugging
 # calls cut out.
@@ -578,6 +699,10 @@ util-queue.o:   $(HDRS) queue.c
        @echo "$(CC) -DCOMPILE_UTILITY queue.c"
        $(FE)$(CC) -c $(CFLAGS) $(INCLUDE) -DCOMPILE_UTILITY -o util-queue.o queue.c
 
+util-tod.o:   $(HDRS) tod.c
+       @echo "$(CC) -DCOMPILE_UTILITY tod.c"
+       $(FE)$(CC) -c $(CFLAGS) $(INCLUDE) -DCOMPILE_UTILITY -o util-tod.o tod.c
+
 util-os.o:       $(HDRS) os.c
        @echo "$(CC) -DCOMPILE_UTILITY os.c"
        $(FE)$(CC) -c $(CFLAGS) $(INCLUDE) \
@@ -602,7 +727,7 @@ crypt16.o:       $(HDRS) crypt16.c
 daemon.o:        $(HDRS) daemon.c
 dbfn.o:          $(HDRS) dbfn.c
 debug.o:         $(HDRS) debug.c
-deliver.o:       $(HDRS) deliver.c
+deliver.o:       $(HDRS) transports/smtp.h deliver.c
 directory.o:     $(HDRS) directory.c
 dns.o:           $(HDRS) dns.c
 enq.o:           $(HDRS) enq.c
@@ -647,6 +772,7 @@ transport.o:     $(HDRS) transport.c
 tree.o:          $(HDRS) tree.c
 verify.o:        $(HDRS) transports/smtp.h verify.c
 dkim.o:          $(HDRS) pdkim/pdkim.h dkim.c
+dkim_transport.o: $(HDRS) dkim_transport.c
 
 # Dependencies for WITH_CONTENT_SCAN modules
 
diff --git a/src/OS/Makefile-CYGWIN b/src/OS/Makefile-CYGWIN
deleted file mode 100644 (file)
index 006e9fe..0000000
+++ /dev/null
@@ -1,113 +0,0 @@
-# OS-specific file for Cygwin.
-
-# This file provided by Pierre A. Humblet <Pierre.Humblet@ieee.org>
-
-HAVE_IPV6 = yes
-HAVE_ICONV = yes
-# Use c99 to have %z 
-CFLAGS= -g -Wall -std=c99 -U __STRICT_ANSI__
-LIBS= -lcrypt -lresolv
-LIBS_EXIM= -liconv
-EXIWHAT_PS_ARG=-as
-EXIWHAT_KILL_SIGNAL=-USR1
-EXIWHAT_EGREP_ARG='/(EXIM|exim)[0-9. -]*$$'
-
-DBMLIB=-lgdbm
-USE_GDBM=YES
-
-# Some OS add a suffix to executables
-EXE = .exe
-
-# To add a resource file with an icon
-LIBS_EXIM +=../Local/exim_res.o
-
-# To produce a linker map
-#LIBS_EXIM+=-Wl,-Map,Exim.Map
-
-
-##################################################
-# The following is normally set in local/Makefile.
-# Makefile.cygwin provides defaults with which the
-# precompiled version is built
-##################################################
-
-BIN_DIRECTORY=/usr/bin
-CONFIGURE_FILE=/etc/exim.conf
-EXIM_USER=18   # This changes if user exim exists
-EXIM_GROUP=544 # Administrators
-SPOOL_DIRECTORY=/var/spool/exim
-LOG_FILE_PATH=/var/log/exim/exim_%s.log
-TIMEZONE_DEFAULT = ""
-
-AUTH_CRAM_MD5=yes
-AUTH_PLAINTEXT=yes
-AUTH_SPA=yes
-
-SUPPORT_TLS=yes
-TLS_LIBS=-lssl -lcrypto
-
-ROUTER_ACCEPT=yes
-ROUTER_DNSLOOKUP=yes
-ROUTER_IPLITERAL=yes
-ROUTER_MANUALROUTE=yes
-ROUTER_QUERYPROGRAM=yes
-ROUTER_REDIRECT=yes
-
-TRANSPORT_APPENDFILE=yes
-TRANSPORT_AUTOREPLY=yes
-TRANSPORT_PIPE=yes
-TRANSPORT_SMTP=yes
-
-SUPPORT_MAILDIR=yes
-SUPPORT_MAILSTORE=yes
-SUPPORT_MBX=yes
-
-LOOKUP_DBM=yes
-LOOKUP_LSEARCH=yes
-
-# LOOKUP_CDB=yes
-LOOKUP_DNSDB=yes
-LOOKUP_DSEARCH=yes
-LOOKUP_LDAP=yes
-# LOOKUP_MYSQL=yes
-# LOOKUP_NIS=yes
-# LOOKUP_NISPLUS=yes
-# LOOKUP_ORACLE=yes
-LOOKUP_PASSWD=yes
-# LOOKUP_PGSQL=yes
-# LOOKUP_WHOSON=yes
-
-LDAP_LIB_TYPE=OPENLDAP2
-LOOKUP_LIBS=-lldap -llber
-
-WITH_CONTENT_SCAN=yes
-
-# It is important to define these variables but the values are always overridden
-CONFIGURE_OWNER=18
-CONFIGURE_GROUP=544
-
-EXICYCLOG_MAX=10
-
-COMPRESS_COMMAND=/usr/bin/gzip
-COMPRESS_SUFFIX=gz
-ZCAT_COMMAND=/usr/bin/zcat
-
-# EXIM_PERL=perl.o
-
-# Comment the two lines below if you do not have PAM, e.g. from
-# ftp://ftp.uni-erlangen.de/pub/pc/gnuwin32/cygwin/porters/Humblet_Pierre_A
-SUPPORT_PAM=yes
-CFLAGS += -DINCLUDE_PAM -I ../pam -I ../../pam
-
-# All modes are in octal and must start with 0
-EXIMDB_DIRECTORY_MODE    = 01777
-EXIMDB_MODE              = 0666
-EXIMDB_LOCKFILE_MODE     = 0666
-INPUT_DIRECTORY_MODE  = 01777
-LOG_DIRECTORY_MODE    = 01777
-LOG_MODE              = 0666
-MSGLOG_DIRECTORY_MODE = 01777
-SPOOL_DIRECTORY_MODE  = 01777
-SPOOL_MODE            = 0600
-
-# End
diff --git a/src/OS/Makefile-DGUX b/src/OS/Makefile-DGUX
deleted file mode 100644 (file)
index 667c63f..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-# Exim: OS-specific make file for DGUX
-#
-# Written by Ken Bailey (K.Bailey@rbgkew.org.uk) Feb 1998
-# on dgux R4.11MU04 generic AViiON mc88100
-# with no X
-
-# Minor tidies to remove settings that are actually the default,
-# in line with the style of other system files - PH.
-
-BASENAME_COMMAND=/bin/basename
-CHOWN_COMMAND=/bin/chown
-CHGRP_COMMAND=/bin/chgrp
-CHMOD_COMMAND=/bin/chmod
-
-# PERL
-# Perl is not necessary for running Exim itself, but some Perl utilities
-# are provided for processing the logs. Perl 5 is assumed.
-# DG ship perl version 4.036 in /bin/perl so need to use locally installed perl
-
-PERL_COMMAND=/usr/local/bin/perl
-
-# dg's version of gcc likes O2
-
-CFLAGS=-O2
-
-RANLIB=@true
-LIBS=-lsocket -lnsl -lm
-LIBRESOLV=-lresolv
-DBMLIB=-ldbm
-
-# End
-
diff --git a/src/OS/Makefile-Darwin b/src/OS/Makefile-Darwin
deleted file mode 100644 (file)
index be0d952..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-# Exim: OS-specific make file for Darwin (Mac OS X).
-
-CC=cc
-
-BASENAME_COMMAND=look_for_it
-CHOWN_COMMAND=/usr/sbin/chown
-CHMOD_COMMAND=/bin/chmod
-
-HAVE_SA_LEN=YES
-
-# Removed -DBIND_8_COMPAT for 4.61
-# CFLAGS=-O -no-cpp-precomp -DBIND_8_COMPAT
-
-CFLAGS=-O -no-cpp-precomp
-LIBRESOLV=-lresolv
-
-USE_DB = yes
-DBMLIB =
-
-X11=/usr/X11R6
-XINCLUDE=-I$(X11)/include
-XLFLAGS=-L$(X11)/lib
-X11_LD_LIB=$(X11)/lib
-
-EXIWHAT_PS_ARG=ax
-EXIWHAT_EGREP_ARG='/exim( |$$)'
-EXIWHAT_KILL_SIGNAL=-USR1
-
-# End
diff --git a/src/OS/Makefile-DragonFly b/src/OS/Makefile-DragonFly
deleted file mode 100644 (file)
index c49c59f..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-# Exim: OS-specific make file for DragonFly
-# There's no setting of CFLAGS here, to allow the system default
-# for "make" to be the default.
-
-CHOWN_COMMAND=/usr/sbin/chown
-CHMOD_COMMAND=/bin/chmod
-
-HAVE_SA_LEN=YES
-
-# crypt() is in a separate library
-LIBS=-lcrypt -lm
-
-# DragonFly always ships with Berkeley DB
-USE_DB=yes
-
-# X11 may be under /usr/pkg/xorg/ for example.
-# X11=/usr/X11R6
-X11=$(X11BASE)
-
-XINCLUDE=-I$(X11)/include
-XLFLAGS=-L$(X11)/lib
-XLFLAGS+=-Wl,-rpath,${X11BASE}/lib
-X11_LD_LIB=$(X11)/lib
-
-EXIWHAT_PS_ARG=-ax
-EXIWHAT_EGREP_ARG='/exim( |$$)'
-EXIWHAT_MULTIKILL_CMD='killall -m'
-EXIWHAT_MULTIKILL_ARG='^exim($$|-[0-9.]+-[0-9]+$$)'
-EXIWHAT_KILL_SIGNAL=-USR1
-
-# End
diff --git a/src/OS/Makefile-GNU b/src/OS/Makefile-GNU
deleted file mode 100644 (file)
index e464341..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-# Exim: OS-specific make file for GNU and variants.
-
-HAVE_ICONV=yes
-
-BASENAME_COMMAND=look_for_it
-CHOWN_COMMAND=look_for_it
-CHGRP_COMMAND=look_for_it
-CHMOD_COMMAND=look_for_it
-
-CFLAGS ?= -O -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
-
-DBMLIB = -ldb
-USE_DB = yes
-
-LIBS = -lnsl -lcrypt -lm
-LIBRESOLV = -lresolv
-
-X11=/usr/X11R6
-XINCLUDE=-I$(X11)/include
-XLFLAGS=-L$(X11)/lib
-X11_LD_LIB=$(X11)/lib
-
-EXIWHAT_PS_ARG=ax
-EXIWHAT_EGREP_ARG='/exim( |$$)'
-EXIWHAT_MULTIKILL_CMD=killall
-EXIWHAT_MULTIKILL_ARG=exim
-EXIWHAT_KILL_SIGNAL=-USR1
-
-# End
diff --git a/src/OS/Makefile-GNUkFreeBSD b/src/OS/Makefile-GNUkFreeBSD
deleted file mode 100644 (file)
index 8019281..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-# Exim: OS-specific make file for GNU and variants.
-
-HAVE_ICONV=yes
-
-BASENAME_COMMAND=look_for_it
-CHOWN_COMMAND=look_for_it
-CHGRP_COMMAND=look_for_it
-CHMOD_COMMAND=look_for_it
-
-CFLAGS ?= -O -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
-
-DBMLIB = -ldb
-USE_DB = yes
-
-LIBS = -lnsl -lcrypt -lm
-LIBRESOLV = -lresolv
-
-X11=/usr/X11R6
-XINCLUDE=-I$(X11)/include
-XLFLAGS=-L$(X11)/lib
-X11_LD_LIB=$(X11)/lib
-
-EXIWHAT_PS_ARG=ax
-EXIWHAT_EGREP_ARG='/exim( |$$)'
-EXIWHAT_MULTIKILL_CMD=killall
-EXIWHAT_MULTIKILL_ARG=exim4
-EXIWHAT_KILL_SIGNAL=-USR1
-
-# End
diff --git a/src/OS/Makefile-GNUkNetBSD b/src/OS/Makefile-GNUkNetBSD
deleted file mode 100644 (file)
index 8019281..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-# Exim: OS-specific make file for GNU and variants.
-
-HAVE_ICONV=yes
-
-BASENAME_COMMAND=look_for_it
-CHOWN_COMMAND=look_for_it
-CHGRP_COMMAND=look_for_it
-CHMOD_COMMAND=look_for_it
-
-CFLAGS ?= -O -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
-
-DBMLIB = -ldb
-USE_DB = yes
-
-LIBS = -lnsl -lcrypt -lm
-LIBRESOLV = -lresolv
-
-X11=/usr/X11R6
-XINCLUDE=-I$(X11)/include
-XLFLAGS=-L$(X11)/lib
-X11_LD_LIB=$(X11)/lib
-
-EXIWHAT_PS_ARG=ax
-EXIWHAT_EGREP_ARG='/exim( |$$)'
-EXIWHAT_MULTIKILL_CMD=killall
-EXIWHAT_MULTIKILL_ARG=exim4
-EXIWHAT_KILL_SIGNAL=-USR1
-
-# End
diff --git a/src/OS/Makefile-HI-OSF b/src/OS/Makefile-HI-OSF
deleted file mode 100644 (file)
index da3d487..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-# Exim: OS-specific make file for HI-OSF/1-MJ and HI-UX/MPP
-
-CC=cc
-CFLAGS=-O
-RANLIB=@true
-EXIWHAT_EGREP_ARG='/exim( |$$)'
-
-# End
diff --git a/src/OS/Makefile-HI-UX b/src/OS/Makefile-HI-UX
deleted file mode 100644 (file)
index 870ee84..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-# Exim: OS-specific make file for HI-UX
-
-CC=cc -Aa -D_HIUX_SOURCE
-HAVE_SETRESUID=YES
-HAVE_SETEUID=NO
-XINCLUDE=-I/usr/include/X11R5
-XLFLAGS=-L/usr/lib/X11R5
-DBMLIB = -lndbm
-NEED_H_ERRNO=1
-RANLIB=@true
-
-# End
diff --git a/src/OS/Makefile-HP-UX b/src/OS/Makefile-HP-UX
deleted file mode 100644 (file)
index ea35144..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-# Exim: OS-specific make file for HP-UX later than 9
-
-# HP ANSI C compiler
-#CC=cc
-#CFLAGS=+O2 +Onolimit -z -D_XOPEN_SOURCE_EXTENDED
-# Users of the A.06.00 compiler might need to use +O1 rather than +O2 as
-# there have been some problems reported with this compiler with +O2 set.
-
-# gcc
-CFLAGS=-O -D_XOPEN_SOURCE_EXTENDED
-LDFLAGS=-Wl,-z
-LIBS=-lm
-
-BASENAME_COMMAND=/bin/basename
-HAVE_ICONV=yes
-HAVE_SETRESUID=YES
-HAVE_SETEUID=NO
-XINCLUDE=-I/usr/include/X11R6 -I/usr/contrib/X11R6/include
-XLFLAGS=-L/usr/lib/X11R6 -L/usr/contrib/X11R6/lib
-X11_LD_LIB=/usr/contrib/X11R6/lib
-EXIMON_TEXTPOP=
-DBMLIB=-lndbm
-RANLIB=@true
-
-OS_C_INCLUDES=setenv.c
-
-# End
diff --git a/src/OS/Makefile-HP-UX-9 b/src/OS/Makefile-HP-UX-9
deleted file mode 100644 (file)
index 1530009..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-# Exim: OS-specific make file for HP-UX 9
-
-CFLAGS=-O
-BASENAME_COMMAND=/bin/basename
-HAVE_ICONV=yes
-HAVE_SETRESUID=YES
-HAVE_SETEUID=NO
-XINCLUDE=-I/usr/include/X11R5
-XLFLAGS=-L/usr/lib/X11R5 -L/usr/contrib/X11R5/lib
-X11_LD_LIB=/usr/contrib/X11R5/lib
-EXIMON_TEXTPOP=
-DBMLIB=-lndbm
-RANLIB=@true
-
-# End
diff --git a/src/OS/Makefile-IRIX b/src/OS/Makefile-IRIX
deleted file mode 100644 (file)
index 7b95783..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-# Exim: OS-specific make file for IRIX
-
-HAVE_ICONV=yes
-BASENAME_COMMAND=/sbin/basename
-HOSTNAME_COMMAND=/usr/bsd/hostname
-CFLAGS=-OPT:Olimit=1500
-LIBS=-lmld -lm
-XINCLUDE=-I/usr/include/X11
-vfork=fork
-RANLIB=@true
-
-# End
diff --git a/src/OS/Makefile-IRIX6 b/src/OS/Makefile-IRIX6
deleted file mode 100644 (file)
index be01138..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-# Exim: OS-specific make file for IRIX6 on 64-bit systems
-
-HAVE_ICONV=yes
-HOSTNAME_COMMAND=/usr/bsd/hostname
-CFLAGS=-O2 -n32 -OPT:Olimit=4000
-LFLAGS=-n32
-LIBS=-lelf -lm
-XINCLUDE=-I/usr/include/X11
-XLFLAGS=
-vfork=fork
-RANLIB=@true
-
-# End
diff --git a/src/OS/Makefile-IRIX632 b/src/OS/Makefile-IRIX632
deleted file mode 100644 (file)
index b567fc6..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-# Exim: OS-specific make file for IRIX 6 on 32-bit systems.
-# There seems to be some variation. The commented settings show
-# some alternatives.
-
-HAVE_ICONV=yes
-HOSTNAME_COMMAND=/usr/bsd/hostname
-#CFLAGS=-OPT:Olimit=1500 -32 -mips2
-CFLAGS=-32
-LFLAGS=-32
-#LIBS=-lmld
-LIBS=-lelf -lm
-XINCLUDE=-I/usr/include/X11
-vfork=fork
-RANLIB=@true
-
-# End
diff --git a/src/OS/Makefile-IRIX65 b/src/OS/Makefile-IRIX65
deleted file mode 100644 (file)
index 50e7745..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-# Exim: OS-specific make file for IRIX 6.5
-
-HAVE_ICONV=yes
-HOSTNAME_COMMAND=/usr/bsd/hostname
-CC=cc
-CFLAGS=-O2 -OPT:Olimit=0
-# CFLAGS=-O2 # override with this (in your Local/Makefile) if using gcc
-LFLAGS=-Wl,-LD_MSG:off=85
-LFLAGS=
-# nlist has moved from libmld to libelf
-LIBS=-lelf -lm
-XINCLUDE=-I/usr/include/X11
-vfork=fork
-RANLIB=@true
-
-# End
diff --git a/src/OS/Makefile-NetBSD b/src/OS/Makefile-NetBSD
deleted file mode 100644 (file)
index 35d03a2..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-# Exim: OS-specific make file for NetBSD (ELF object format)
-
-CHOWN_COMMAND=/usr/sbin/chown
-CHMOD_COMMAND=/bin/chmod
-
-CFLAGS ?= -O2
-
-HAVE_SA_LEN=YES
-HAVE_IPV6=YES
-LIBS=-lcrypt -lm
-
-X11=/usr/X11R6
-XINCLUDE=-I$(X11)/include
-XLFLAGS=-L$(X11)/lib
-X11_LD_LIB=$(X11)/lib
-
-EXIWHAT_PS_ARG=-ax
-EXIWHAT_EGREP_ARG='/exim( |$$)'
-EXIWHAT_KILL_SIGNAL=-USR1
-
-# NetBSD always ships with Berkeley DB
-USE_DB=yes
-
-# NetBSD ELF linker needs a -R flag.
-XLFLAGS+=-Wl,-R$(X11)/lib/
-
-# End
diff --git a/src/OS/Makefile-NetBSD-a.out b/src/OS/Makefile-NetBSD-a.out
deleted file mode 100644 (file)
index e210efd..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-# Exim: OS-specific make file for NetBSD (a.out/COFF object format)
-
-CHOWN_COMMAND=/usr/sbin/chown
-CHMOD_COMMAND=/bin/chmod
-
-CFLAGS ?= -O2
-
-HAVE_SA_LEN=YES
-HAVE_IPV6=YES
-LIBS=-lcrypt -lm
-
-X11=/usr/X11R6
-XINCLUDE=-I$(X11)/include
-XLFLAGS=-L$(X11)/lib
-X11_LD_LIB=$(X11)/lib
-
-EXIWHAT_PS_ARG=-ax
-EXIWHAT_EGREP_ARG='/exim( |$$)'
-EXIWHAT_KILL_SIGNAL=-USR1
-
-# NetBSD always ships with Berkeley DB
-USE_DB=yes
-
-# End
diff --git a/src/OS/Makefile-OSF1 b/src/OS/Makefile-OSF1
deleted file mode 100644 (file)
index 811ca07..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-# Exim: OS-specific make file for OSF1
-
-CFLAGS=-O
-LIBS=-liconv -lm
-HAVE_CRYPT16=yes
-HAVE_ICONV=yes
-HOSTNAME_COMMAND=/usr/bin/hostname
-EXIWHAT_EGREP_ARG='/exim( |$$)'
-
-# End
diff --git a/src/OS/Makefile-OpenUNIX b/src/OS/Makefile-OpenUNIX
deleted file mode 100644 (file)
index e4d7261..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-# Exim: OS-specific make file for OpenUNIX
-
-CC=/usr/bin/cc
-CFLAGS=-O -I/usr/local/include
-LFLAGS=-L/usr/local/lib
-
-LIBS=-lsocket -lnsl -lelf -lgen -lresolv -lm
-EXTRALIBS_EXIMON=-lICE -lSM
-
-RANLIB=@true
-ERRNO_QUOTA=0
-
-X11=/usr/lib/X11
-XINCLUDE=-I/usr/include/X11
-XLFLAGS=-L/usr/lib -L$(X11)/lib
-
-# End
diff --git a/src/OS/Makefile-QNX b/src/OS/Makefile-QNX
deleted file mode 100644 (file)
index 3cf81c4..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-# Exim: OS-specific makefile for QNX
-
-BASENAME_COMMAND=/bin/basename
-MAKE_SHELL=/usr/bin/bash
-
-CHOWN_COMMAND=/bin/chown
-CHGRP_COMMAND=/bin/chgrp
-CHMOD_COMMAND=/bin/chmod
-HOSTNAME_COMMAND=/bin/hostname
-MV_COMMAND=/bin/mv
-PERL_COMMAND=/usr/bin/perl
-RM_COMMAND=/bin/rm
-
-AR=ar -rc
-
-CC=cc
-CFLAGS=-Otax
-LIBIDENTCFLAGS=
-
-RANLIB=@true
-DBMLIB=-ldb
-USE_DB=yes
-LIBS=-lsocket -lm
-
-X11=/usr/X11R6
-XINCLUDE=-I$(X11)/include
-XLFLAGS=-L$(X11)/lib
-X11_LD_LIB=$(X11)/lib
-
-# End
diff --git a/src/OS/Makefile-SCO b/src/OS/Makefile-SCO
deleted file mode 100644 (file)
index baa61d8..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-# Exim: OS-specific make file for SCO
-
-# It was reported that some versions of gcc (e.g. 2.8.1) require this to be
-# CFLAGS=-melf
-
-CFLAGS=-b elf
-
-RANLIB=@true
-DBMLIB=-lndbm
-ERRNO_QUOTA=0
-LIBS=-lsocket -lm
-HAVE_ICONV=yes
-
-X11=/usr/lib/X11
-XINCLUDE=-I/usr/include/X11
-XLFLAGS=-L/usr/lib -L$(X11)/lib
-X11_LD_LIB=$(X11)/lib
-
-# Changes from Frank Bernhardt (30/09/04)
-
-BASENAME_COMMAND=/bin/basename
-CHOWN_COMMAND=/bin/chown
-CHGRP_COMMAND=/bin/chgrp
-CHMOD_COMMAND=/bin/chmod
-HOSTNAME_COMMAND=/usr/bin/hostname
-TOUCH_COMMAND=/bin/touch
-
-# End
diff --git a/src/OS/Makefile-SCO_SV b/src/OS/Makefile-SCO_SV
deleted file mode 100644 (file)
index 249b81a..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-# Exim: OS-specific make file for SCO_SV release 5 (tested on 5.0.5 & 5.0.5)
-#       (see the UNIX_SV files for SCO 4.2)
-# Supplied by: Tony Earnshaw <tonye@ilion.nl>
-
-# Note that 'gcc -melf -m486' applies to gcc 2.7.2 and higher;
-# 2.7.1 and SCO's SDK need '-belf'.
-
-# Removed -lwrap (PH 27/7/00) because not all systems have it
-
-CFLAGS=-melf -O3 -m486
-LFLAGS=-L/lib -L/usr/lib -L/usr/local/lib
-LIBS=-ltinfo -lsocket -lm
-
-HAVE_ICONV=yes
-
-RANLIB=@true
-DBMLIB=-lndbm
-ERRNO_QUOTA=0
-
-X11=/usr/lib/X11
-XINCLUDE=-I/usr/include/X11
-XLFLAGS=-L/usr/lib -L$(X11)/lib
-X11_LD_LIB=$(X11)/lib
-
-# Changes from Frank Bernhardt (30/9/04)
-
-BASENAME_COMMAND=/bin/basename
-CHOWN_COMMAND=/bin/chown
-CHGRP_COMMAND=/bin/chgrp
-CHMOD_COMMAND=/bin/chmod
-HOSTNAME_COMMAND=/usr/bin/hostname
-TOUCH_COMMAND=/bin/touch
-
-# End
diff --git a/src/OS/Makefile-SunOS4 b/src/OS/Makefile-SunOS4
deleted file mode 100644 (file)
index c876998..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-# Exim: OS-specific make file for SunOS4
-
-CFLAGS=-O
-
-CHOWN_COMMAND=/usr/etc/chown
-HOSTNAME_COMMAND=/usr/bin/hostname
-EXIT_FAILURE=1
-EXIT_SUCCESS=0
-LIBRESOLV=-lresolv
-XINCLUDE=-I/usr/include/X11
-
-EXIWHAT_PS_ARG=-ax
-EXIWHAT_EGREP_ARG='/exim( |$$)'
-EXIWHAT_KILL_SIGNAL=-30
-
-# End
diff --git a/src/OS/Makefile-SunOS5-hal b/src/OS/Makefile-SunOS5-hal
deleted file mode 100644 (file)
index 05ea893..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-# Exim: OS-specific make file for SunOS5 on a HAL
-
-# Note: The HAL runs a standard SunOS5 except that it has a 64 bit C
-# compiler called hcc.  To make things work pass the -KV7 flag to force
-# 32bit compilation - this is necessary to interwork with some libraries.
-
-CC=hcc
-CFLAGS=-O -KV7
-LIBIDENTCFLAGS="-KV7 -O -DHAVE_ANSIHEADERS"
-LIBIDENTNAME=sunos5
-RANLIB=@true
-LIBS=-lsocket -lnsl -lkstat -lm
-LIBRESOLV=-lresolv
-X11=/usr/X11R6
-XINCLUDE=-I$(X11)/include
-XLFLAGS=-L$(X11)/lib -R$(X11)/lib
-
-# End
diff --git a/src/OS/Makefile-ULTRIX b/src/OS/Makefile-ULTRIX
deleted file mode 100644 (file)
index 9e912b3..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-# Exim: OS-specific make file for Ultrix
-
-MAKE_SHELL=/usr/bin/sh5
-
-CFLAGS=-O
-
-# This can either be /usr/include/X11 or /usr/include/mit depending on
-# the particular version of ULTRIX.
-
-XINCLUDE=-I/usr/include/X11 -I/usr/include/mit
-
-DBMLIB=-lgdbm
-
-EXIWHAT_PS_ARG=-ax
-EXIWHAT_EGREP_ARG='/exim( |$$)'
-EXIWHAT_KILL_SIGNAL=-USR1
-
-# End
diff --git a/src/OS/Makefile-UNIX_SV b/src/OS/Makefile-UNIX_SV
deleted file mode 100644 (file)
index bfcfae1..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-# Exim: OS-specific make file for SCO SVR4.2MP (and maybe Unixware)
-#
-#  *** Note that for SCO 5 the configuration file is called SCO_SV,
-#  *** and that Unixware7 has its own configuration. This is an old
-#  *** file that is retained for compatibility.
-#
-# Note that SCO does not include dbm/ndbm with their standard compiler
-# (it is available with /usr/ucb/cc, but that has bugs of its own). You
-# should install gcc and gdbm, then execute 'make install-compat' in the
-# gdbm source directory.
-
-CC=gcc -I/usr/local/include
-CFLAGS=-O
-
-RANLIB=@true
-DBMLIB=-lgdbm -L/usr/local/lib
-ERRNO_QUOTA=0
-LIBS=-lsocket -lelf -lgen -lnsl -lresolv -lm
-
-X11=/usr/lib/X11
-XINCLUDE=-I/usr/include/X11
-XLFLAGS=-L/usr/lib -L$(X11)/lib
-
-# End
diff --git a/src/OS/Makefile-USG b/src/OS/Makefile-USG
deleted file mode 100644 (file)
index 753a2d7..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-# Exim: OS-specific make file for Unixware 2.x
-#
-# Note that Unixware does not include db/dbm/ndbm with their standard compiler
-# (it is available with /usr/ucb/cc, but that has bugs of its own). You
-# should install gcc and Berkeley DB (or another dbm library if you really
-# insist). If you use a different dbm library you will need to override
-# DBMLIB below.
-#
-# DB 1.85 and 2.x can be found at http://www.sleepycat.com/.
-# They have different characteristics. See the discussion of dbm libraries
-# in doc/dbm.discuss.txt in the Exim distribution.
-#
-# DB needs to be compiled with gcc and you need a 'cc' in your path
-# before the Unixware CC to compile it.
-#
-# Don't bother even starting to install exim on Unixware unless
-# you have installed gcc and use it for everything.
-
-CC=gcc -I/usr/local/include
-CFLAGS=-O
-
-RANLIB=@true
-DBMLIB=-ldb -L/usr/local/lib
-USE_DB=YES
-ERRNO_QUOTA=0
-LIBS=-lsocket -lelf -lgen -lnsl -lresolv -lm
-
-X11=/usr/lib/X11
-XINCLUDE=-I/usr/include/X11
-XLFLAGS=-L/usr/lib -L$(X11)/lib
-X11_LD_LIB=$(X11)/lib
-
-# End
diff --git a/src/OS/Makefile-Unixware7 b/src/OS/Makefile-Unixware7
deleted file mode 100644 (file)
index 88a8838..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-# Exim: OS-specific make file for Unixware7
-# Based on information from James FitzGibbon <james@ehlo.com>
-
-# If you want to use libbind, you need to
-#     add -I/usr/local/bind/include to CFLAGS
-#     add -L/usr/local/bind/lib to LFLAGS
-#     remove -lresolv from LIBS
-#     add LOOKUP_LIBS=-lbind
-# The new settings should go in your Local/Makefile rather than here; then
-# they will be usable for subsequent Exim releases.
-
-CC=/usr/bin/cc
-CFLAGS=-O -I/usr/local/include
-LFLAGS=-L/usr/local/lib
-
-HAVE_ICONV=yes
-
-LIBS=-lsocket -lnsl -lelf -lgen -lresolv -lm
-
-# Removed on the advice of Larry Rosenman
-# EXTRALIBS=-lwrap
-
-EXTRALIBS_EXIMON=-lICE -lSM
-
-RANLIB=@true
-ERRNO_QUOTA=0
-
-X11=/usr/lib/X11
-XINCLUDE=-I/usr/include/X11
-XLFLAGS=-L/usr/lib -L$(X11)/lib
-
-# End
diff --git a/src/OS/Makefile-mips b/src/OS/Makefile-mips
deleted file mode 100644 (file)
index ff33139..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-# Exim: OS-specific make file for RiscOS4bsd
-
-HOSTNAME_COMMAND=/usr/ucb/hostname
-EXIT_FAILURE=1
-EXIT_SUCCESS=0
-LIBRESOLV=-lresolv
-LIBS=-liberty -lm
-XINCLUDE=-I/usr/X11R6/include
-
-CFLAGS=-O
-
-EXIWHAT_PS_ARG=-ax
-EXIWHAT_EGREP_ARG='/exim( |$$)'
-EXIWHAT_KILL_SIGNAL=-30
-
-# End
diff --git a/src/OS/os.c-BSDI b/src/OS/os.c-BSDI
deleted file mode 100644 (file)
index 3cef2ac..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*************************************************
-*     Exim - an Internet mail transport agent    *
-*************************************************/
-
-/* Copyright (c) 2016 Heiko Schlittermann <hs@schlittermann.de> */
-/* See the file NOTICE for conditions of use and distribution. */
-
-/* BSDI-specific code. This is concatenated onto the generic
-src/os.c file. */
-
-#ifndef OS_UNSETENV
-#define OS_UNSETENV
-
-int
-os_unsetenv(const unsigned char * name)
-{
-unsetenv((char *)name);
-return 0;
-}
diff --git a/src/OS/os.c-FreeBSD b/src/OS/os.c-FreeBSD
new file mode 100644 (file)
index 0000000..715a9ed
--- /dev/null
@@ -0,0 +1,24 @@
+/*************************************************
+*     Exim - an Internet mail transport agent    *
+*************************************************/
+
+/* Copyright (c) Jeremy Harris 2017 */
+/* See the file NOTICE for conditions of use and distribution. */
+
+/* FreeBSD-specific code. This is concatenated onto the generic
+src/os.c file. */
+
+
+/*************
+* Sendfile   *
+*************/
+
+ssize_t
+os_sendfile(int out, int in, off_t * off, size_t cnt)
+{
+off_t written;
+return sendfile(in, out, *off, cnt, NULL, &written, 0) < 0
+  ? (ssize_t) -1 : (ssize_t) written;
+}
+
+/* End of os.c-Linux */
diff --git a/src/OS/os.c-GNU b/src/OS/os.c-GNU
deleted file mode 100644 (file)
index e5d6ff6..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*************************************************
-*     Exim - an Internet mail transport agent    *
-*************************************************/
-
-/* See the file NOTICE for conditions of use and distribution. */
-
-/* GNU-specific code. This is concatenated onto the generic src/os.c file.
-GNU/Hurd has approximately the same way to determine the load average as NeXT,
-so a variant of this could also be in the generic os.c file. See the GNU EMacs
-getloadavg.c file, from which this snippet was derived. getloadavg.c from Emacs
-is copyrighted by the FSF under the terms of the GPLv2 or any later version.
-Changes are hereby placed under the same license, as requested by the GPL. */
-
-#ifndef OS_LOAD_AVERAGE
-#define OS_LOAD_AVERAGE
-
-#include <mach.h>
-
-static processor_set_t default_set;
-static int getloadavg_initialized;
-
-int
-os_getloadavg (void)
-{
-host_t host;
-struct processor_set_basic_info info;
-unsigned info_count;
-
-if (!getloadavg_initialized)
-  {
-  if (processor_set_default (mach_host_self(), &default_set) == KERN_SUCCESS)
-    getloadavg_initialized = 1;
-  }
-
-if (getloadavg_initialized)
-  {
-  info_count = PROCESSOR_SET_BASIC_INFO_COUNT;
-  if (processor_set_info(default_set, PROCESSOR_SET_BASIC_INFO, &host,
-       (processor_set_info_t)&info, &info_count) != KERN_SUCCESS)
-    getloadavg_initialized = 0;
-  else
-    {
-    #if LOAD_SCALE == 1000
-    return info.load_average;
-    #else
-    return (int) (((double) info.load_average * 1000) / LOAD_SCALE));
-    #endif
-    }
-  }
-
-return -1;
-}
-#endif  /* OS_LOAD_AVERAGE */
-
-/* End of os.c-GNU */
diff --git a/src/OS/os.c-HI-OSF b/src/OS/os.c-HI-OSF
deleted file mode 100644 (file)
index 5e3d336..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*************************************************
-*     Exim - an Internet mail transport agent    *
-*************************************************/
-
-/* Copyright (c) University of Cambridge 2001 */
-/* See the file NOTICE for conditions of use and distribution. */
-
-/* HI-OSF-specific code. This is concatenated onto the generic
-src/os.c file. OSF has an apparently unique way of getting the
-load average, so we provide a unique function here, and define
-OS_LOAD_AVERAGE to stop src/os.c trying to provide the function. */
-
-#ifndef OS_LOAD_AVERAGE
-#define OS_LOAD_AVERAGE
-
-#include <sys/table.h>
-
-int
-os_getloadavg(void)
-{
-double avg;
-struct tbl_loadavg load_avg;
-
-table (TBL_LOADAVG, 0, &load_avg, 1, sizeof (load_avg));
-
-avg = (load_avg.tl_lscale == 0)?
-  load_avg.tl_avenrun.d[0] :
-  (load_avg.tl_avenrun.l[0] / (double)load_avg.tl_lscale);
-
-return (int)(avg * 1000.0);
-}
-
-#endif  /* OS_LOAD_AVERAGE */
-
-/* End of os.c-HI-OSF */
diff --git a/src/OS/os.c-HP-UX b/src/OS/os.c-HP-UX
deleted file mode 100644 (file)
index fdd8708..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/*************************************************
-*     Exim - an Internet mail transport agent    *
-*************************************************/
-
-/* Copyright (c) University of Cambridge 2016 */
-/* Copyright (c) Jeremy Harris 2016 */
-/* See the file NOTICE for conditions of use and distribution. */
-
-/* HP-UX-specific code. This is concatenated onto the generic
-src/os.c file. */
-
-#ifndef COMPILE_UTILITY
-# include "setenv.c"
-#endif
-
-/* End of os.c-SunHP-UX */
diff --git a/src/OS/os.c-IRIX b/src/OS/os.c-IRIX
deleted file mode 100644 (file)
index 487091a..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-/*************************************************
-*     Exim - an Internet mail transport agent    *
-*************************************************/
-
-/* Copyright (c) University of Cambridge 2001 */
-/* See the file NOTICE for conditions of use and distribution. */
-
-/* Irix-specific code. This is concatenated onto the generic src/os.c file.
-Irix has a unique way of finding all the network interfaces, so we provide a
-unique function here, and define FIND_RUNNING_INTERFACES to stop src/os.c
-trying to provide the function. The macro may be set initially anyway, when
-compiling os. for utilities that don't want this function. */
-
-#ifndef FIND_RUNNING_INTERFACES
-#define FIND_RUNNING_INTERFACES
-
-/* This is the special form of the function using sysctl() which is the only
-form that returns all the aliases on IRIX systems. This code has its origins
-in a sample program that came from within SGI. */
-
-#include <sys/sysctl.h>
-#include <net/if_dl.h>
-#include <net/if_types.h>
-#include <net/soioctl.h>
-#include <net/route.h>
-
-#define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(__uint64_t) -1))) \
-                    : sizeof(__uint64_t))
-#ifdef _HAVE_SA_LEN
-#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
-#else
-#define ADVANCE(x, n) (x += ROUNDUP(_FAKE_SA_LEN_DST(n)))
-#endif
-
-
-ip_address_item *
-os_find_running_interfaces(void)
-{
-ip_address_item *yield = NULL;
-ip_address_item *last = NULL;
-ip_address_item *next;
-
-size_t needed;
-int mib[6];
-char *buf, *nextaddr, *lim;
-register struct if_msghdr *ifm;
-
-mib[0] = CTL_NET;
-mib[1] = PF_ROUTE;
-mib[2] = 0;
-mib[3] = 0;
-mib[4] = NET_RT_IFLIST;
-mib[5] = 0;
-
-/* Get an estimate of the amount of store needed, then get the store and
-get the data into it. Any error causes a panic death. */
-
-if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
-  log_write(0, LOG_PANIC_DIE, "iflist-sysctl-estimate failed: %s",
-    strerror(errno));
-
-buf = store_get(needed);
-
-if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
-  log_write(0, LOG_PANIC_DIE, "sysctl of ifnet list failed: %s",
-    strerror(errno));
-
-/* Now fish out the data for each interface */
-
-lim  = buf + needed;
-for (nextaddr = buf; nextaddr < lim; nextaddr += ifm->ifm_msglen)
-  {
-  ifm = (struct if_msghdr *)nextaddr;
-
-  if (ifm->ifm_type != RTM_IFINFO)
-    {
-    struct ifa_msghdr *ifam = (struct ifa_msghdr *)ifm;
-    struct sockaddr_in *mask = NULL, *addr = NULL;
-
-    if ((ifam->ifam_addrs & RTA_NETMASK) != 0)
-      mask = (struct sockaddr_in *)(ifam + 1);
-
-    if ((ifam->ifam_addrs & RTA_IFA) != 0)
-      {
-      char *cp = (char *)mask;
-      struct sockaddr *sa = (struct sockaddr *)mask;
-      ADVANCE(cp, sa);
-      addr = (struct sockaddr_in *)cp;
-      }
-
-    /* Create a data block for the address, fill in the data, and put it on
-    the chain. This data has to survive for ever, so use malloc. */
-
-    if (addr != NULL)
-      {
-      next = store_malloc(sizeof(ip_address_item));
-      next->next = NULL;
-      next->port = 0;
-      (void)host_ntoa(-1, addr, next->address, NULL);
-
-      if (yield == NULL) yield = last = next; else
-        {
-        last->next = next;
-        last = next;
-        }
-
-      DEBUG(D_interface) debug_printf("Actual local interface address is %s\n",
-        last->address);
-      }
-    }
-  }
-
-return yield;
-}
-
-#endif  /* FIND_RUNNING_INTERFACES */
-
-/* End of os.c-IRIX */
diff --git a/src/OS/os.c-IRIX6 b/src/OS/os.c-IRIX6
deleted file mode 100644 (file)
index 487091a..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-/*************************************************
-*     Exim - an Internet mail transport agent    *
-*************************************************/
-
-/* Copyright (c) University of Cambridge 2001 */
-/* See the file NOTICE for conditions of use and distribution. */
-
-/* Irix-specific code. This is concatenated onto the generic src/os.c file.
-Irix has a unique way of finding all the network interfaces, so we provide a
-unique function here, and define FIND_RUNNING_INTERFACES to stop src/os.c
-trying to provide the function. The macro may be set initially anyway, when
-compiling os. for utilities that don't want this function. */
-
-#ifndef FIND_RUNNING_INTERFACES
-#define FIND_RUNNING_INTERFACES
-
-/* This is the special form of the function using sysctl() which is the only
-form that returns all the aliases on IRIX systems. This code has its origins
-in a sample program that came from within SGI. */
-
-#include <sys/sysctl.h>
-#include <net/if_dl.h>
-#include <net/if_types.h>
-#include <net/soioctl.h>
-#include <net/route.h>
-
-#define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(__uint64_t) -1))) \
-                    : sizeof(__uint64_t))
-#ifdef _HAVE_SA_LEN
-#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
-#else
-#define ADVANCE(x, n) (x += ROUNDUP(_FAKE_SA_LEN_DST(n)))
-#endif
-
-
-ip_address_item *
-os_find_running_interfaces(void)
-{
-ip_address_item *yield = NULL;
-ip_address_item *last = NULL;
-ip_address_item *next;
-
-size_t needed;
-int mib[6];
-char *buf, *nextaddr, *lim;
-register struct if_msghdr *ifm;
-
-mib[0] = CTL_NET;
-mib[1] = PF_ROUTE;
-mib[2] = 0;
-mib[3] = 0;
-mib[4] = NET_RT_IFLIST;
-mib[5] = 0;
-
-/* Get an estimate of the amount of store needed, then get the store and
-get the data into it. Any error causes a panic death. */
-
-if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
-  log_write(0, LOG_PANIC_DIE, "iflist-sysctl-estimate failed: %s",
-    strerror(errno));
-
-buf = store_get(needed);
-
-if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
-  log_write(0, LOG_PANIC_DIE, "sysctl of ifnet list failed: %s",
-    strerror(errno));
-
-/* Now fish out the data for each interface */
-
-lim  = buf + needed;
-for (nextaddr = buf; nextaddr < lim; nextaddr += ifm->ifm_msglen)
-  {
-  ifm = (struct if_msghdr *)nextaddr;
-
-  if (ifm->ifm_type != RTM_IFINFO)
-    {
-    struct ifa_msghdr *ifam = (struct ifa_msghdr *)ifm;
-    struct sockaddr_in *mask = NULL, *addr = NULL;
-
-    if ((ifam->ifam_addrs & RTA_NETMASK) != 0)
-      mask = (struct sockaddr_in *)(ifam + 1);
-
-    if ((ifam->ifam_addrs & RTA_IFA) != 0)
-      {
-      char *cp = (char *)mask;
-      struct sockaddr *sa = (struct sockaddr *)mask;
-      ADVANCE(cp, sa);
-      addr = (struct sockaddr_in *)cp;
-      }
-
-    /* Create a data block for the address, fill in the data, and put it on
-    the chain. This data has to survive for ever, so use malloc. */
-
-    if (addr != NULL)
-      {
-      next = store_malloc(sizeof(ip_address_item));
-      next->next = NULL;
-      next->port = 0;
-      (void)host_ntoa(-1, addr, next->address, NULL);
-
-      if (yield == NULL) yield = last = next; else
-        {
-        last->next = next;
-        last = next;
-        }
-
-      DEBUG(D_interface) debug_printf("Actual local interface address is %s\n",
-        last->address);
-      }
-    }
-  }
-
-return yield;
-}
-
-#endif  /* FIND_RUNNING_INTERFACES */
-
-/* End of os.c-IRIX */
diff --git a/src/OS/os.c-IRIX632 b/src/OS/os.c-IRIX632
deleted file mode 100644 (file)
index 487091a..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-/*************************************************
-*     Exim - an Internet mail transport agent    *
-*************************************************/
-
-/* Copyright (c) University of Cambridge 2001 */
-/* See the file NOTICE for conditions of use and distribution. */
-
-/* Irix-specific code. This is concatenated onto the generic src/os.c file.
-Irix has a unique way of finding all the network interfaces, so we provide a
-unique function here, and define FIND_RUNNING_INTERFACES to stop src/os.c
-trying to provide the function. The macro may be set initially anyway, when
-compiling os. for utilities that don't want this function. */
-
-#ifndef FIND_RUNNING_INTERFACES
-#define FIND_RUNNING_INTERFACES
-
-/* This is the special form of the function using sysctl() which is the only
-form that returns all the aliases on IRIX systems. This code has its origins
-in a sample program that came from within SGI. */
-
-#include <sys/sysctl.h>
-#include <net/if_dl.h>
-#include <net/if_types.h>
-#include <net/soioctl.h>
-#include <net/route.h>
-
-#define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(__uint64_t) -1))) \
-                    : sizeof(__uint64_t))
-#ifdef _HAVE_SA_LEN
-#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
-#else
-#define ADVANCE(x, n) (x += ROUNDUP(_FAKE_SA_LEN_DST(n)))
-#endif
-
-
-ip_address_item *
-os_find_running_interfaces(void)
-{
-ip_address_item *yield = NULL;
-ip_address_item *last = NULL;
-ip_address_item *next;
-
-size_t needed;
-int mib[6];
-char *buf, *nextaddr, *lim;
-register struct if_msghdr *ifm;
-
-mib[0] = CTL_NET;
-mib[1] = PF_ROUTE;
-mib[2] = 0;
-mib[3] = 0;
-mib[4] = NET_RT_IFLIST;
-mib[5] = 0;
-
-/* Get an estimate of the amount of store needed, then get the store and
-get the data into it. Any error causes a panic death. */
-
-if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
-  log_write(0, LOG_PANIC_DIE, "iflist-sysctl-estimate failed: %s",
-    strerror(errno));
-
-buf = store_get(needed);
-
-if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
-  log_write(0, LOG_PANIC_DIE, "sysctl of ifnet list failed: %s",
-    strerror(errno));
-
-/* Now fish out the data for each interface */
-
-lim  = buf + needed;
-for (nextaddr = buf; nextaddr < lim; nextaddr += ifm->ifm_msglen)
-  {
-  ifm = (struct if_msghdr *)nextaddr;
-
-  if (ifm->ifm_type != RTM_IFINFO)
-    {
-    struct ifa_msghdr *ifam = (struct ifa_msghdr *)ifm;
-    struct sockaddr_in *mask = NULL, *addr = NULL;
-
-    if ((ifam->ifam_addrs & RTA_NETMASK) != 0)
-      mask = (struct sockaddr_in *)(ifam + 1);
-
-    if ((ifam->ifam_addrs & RTA_IFA) != 0)
-      {
-      char *cp = (char *)mask;
-      struct sockaddr *sa = (struct sockaddr *)mask;
-      ADVANCE(cp, sa);
-      addr = (struct sockaddr_in *)cp;
-      }
-
-    /* Create a data block for the address, fill in the data, and put it on
-    the chain. This data has to survive for ever, so use malloc. */
-
-    if (addr != NULL)
-      {
-      next = store_malloc(sizeof(ip_address_item));
-      next->next = NULL;
-      next->port = 0;
-      (void)host_ntoa(-1, addr, next->address, NULL);
-
-      if (yield == NULL) yield = last = next; else
-        {
-        last->next = next;
-        last = next;
-        }
-
-      DEBUG(D_interface) debug_printf("Actual local interface address is %s\n",
-        last->address);
-      }
-    }
-  }
-
-return yield;
-}
-
-#endif  /* FIND_RUNNING_INTERFACES */
-
-/* End of os.c-IRIX */
diff --git a/src/OS/os.c-IRIX65 b/src/OS/os.c-IRIX65
deleted file mode 100644 (file)
index 487091a..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-/*************************************************
-*     Exim - an Internet mail transport agent    *
-*************************************************/
-
-/* Copyright (c) University of Cambridge 2001 */
-/* See the file NOTICE for conditions of use and distribution. */
-
-/* Irix-specific code. This is concatenated onto the generic src/os.c file.
-Irix has a unique way of finding all the network interfaces, so we provide a
-unique function here, and define FIND_RUNNING_INTERFACES to stop src/os.c
-trying to provide the function. The macro may be set initially anyway, when
-compiling os. for utilities that don't want this function. */
-
-#ifndef FIND_RUNNING_INTERFACES
-#define FIND_RUNNING_INTERFACES
-
-/* This is the special form of the function using sysctl() which is the only
-form that returns all the aliases on IRIX systems. This code has its origins
-in a sample program that came from within SGI. */
-
-#include <sys/sysctl.h>
-#include <net/if_dl.h>
-#include <net/if_types.h>
-#include <net/soioctl.h>
-#include <net/route.h>
-
-#define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(__uint64_t) -1))) \
-                    : sizeof(__uint64_t))
-#ifdef _HAVE_SA_LEN
-#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
-#else
-#define ADVANCE(x, n) (x += ROUNDUP(_FAKE_SA_LEN_DST(n)))
-#endif
-
-
-ip_address_item *
-os_find_running_interfaces(void)
-{
-ip_address_item *yield = NULL;
-ip_address_item *last = NULL;
-ip_address_item *next;
-
-size_t needed;
-int mib[6];
-char *buf, *nextaddr, *lim;
-register struct if_msghdr *ifm;
-
-mib[0] = CTL_NET;
-mib[1] = PF_ROUTE;
-mib[2] = 0;
-mib[3] = 0;
-mib[4] = NET_RT_IFLIST;
-mib[5] = 0;
-
-/* Get an estimate of the amount of store needed, then get the store and
-get the data into it. Any error causes a panic death. */
-
-if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
-  log_write(0, LOG_PANIC_DIE, "iflist-sysctl-estimate failed: %s",
-    strerror(errno));
-
-buf = store_get(needed);
-
-if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
-  log_write(0, LOG_PANIC_DIE, "sysctl of ifnet list failed: %s",
-    strerror(errno));
-
-/* Now fish out the data for each interface */
-
-lim  = buf + needed;
-for (nextaddr = buf; nextaddr < lim; nextaddr += ifm->ifm_msglen)
-  {
-  ifm = (struct if_msghdr *)nextaddr;
-
-  if (ifm->ifm_type != RTM_IFINFO)
-    {
-    struct ifa_msghdr *ifam = (struct ifa_msghdr *)ifm;
-    struct sockaddr_in *mask = NULL, *addr = NULL;
-
-    if ((ifam->ifam_addrs & RTA_NETMASK) != 0)
-      mask = (struct sockaddr_in *)(ifam + 1);
-
-    if ((ifam->ifam_addrs & RTA_IFA) != 0)
-      {
-      char *cp = (char *)mask;
-      struct sockaddr *sa = (struct sockaddr *)mask;
-      ADVANCE(cp, sa);
-      addr = (struct sockaddr_in *)cp;
-      }
-
-    /* Create a data block for the address, fill in the data, and put it on
-    the chain. This data has to survive for ever, so use malloc. */
-
-    if (addr != NULL)
-      {
-      next = store_malloc(sizeof(ip_address_item));
-      next->next = NULL;
-      next->port = 0;
-      (void)host_ntoa(-1, addr, next->address, NULL);
-
-      if (yield == NULL) yield = last = next; else
-        {
-        last->next = next;
-        last = next;
-        }
-
-      DEBUG(D_interface) debug_printf("Actual local interface address is %s\n",
-        last->address);
-      }
-    }
-  }
-
-return yield;
-}
-
-#endif  /* FIND_RUNNING_INTERFACES */
-
-/* End of os.c-IRIX */
index 4bca77615d5f2d5b6aabffa885885b4dc9e0c9d6..dd65c8b3930cfbe71326db9c3cbcfc1be29962f3 100644 (file)
@@ -150,4 +150,16 @@ return yield;
 
 #endif  /* FIND_RUNNING_INTERFACES */
 
+
+/*************
+* Sendfile   *
+*************/
+#include <sys/sendfile.h>
+
+ssize_t
+os_sendfile(int out, int in, off_t * off, size_t cnt)
+{
+return sendfile(out, in, off, cnt);
+}
+
 /* End of os.c-Linux */
diff --git a/src/OS/os.c-OSF1 b/src/OS/os.c-OSF1
deleted file mode 100644 (file)
index ad91b63..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*************************************************
-*     Exim - an Internet mail transport agent    *
-*************************************************/
-
-/* Copyright (c) University of Cambridge 2001 */
-/* See the file NOTICE for conditions of use and distribution. */
-
-/* OSF1-specific code. This is concatenated onto the generic src/os.c file.
-OSF1 has an apparently unique way of getting the load average, so we provide a
-unique function here, and define OS_LOAD_AVERAGE to stop src/os.c trying to
-provide the function. The macro may be set initially anyway, when compiling os.
-for utilities that don't want this function. */
-
-#ifndef OS_LOAD_AVERAGE
-#define OS_LOAD_AVERAGE
-
-#include <sys/table.h>
-
-int
-os_getloadavg(void)
-{
-double avg;
-struct tbl_loadavg load_avg;
-
-table (TBL_LOADAVG, 0, &load_avg, 1, sizeof (load_avg));
-
-avg = (load_avg.tl_lscale == 0)?
-  load_avg.tl_avenrun.d[0] :
-  (load_avg.tl_avenrun.l[0] / (double)load_avg.tl_lscale);
-
-return (int)(avg * 1000.0);
-}
-
-#endif  /* OS_LOAD_AVERAGE */
-
-/* End of os.c-OSF1 */
diff --git a/src/OS/os.c-cygwin b/src/OS/os.c-cygwin
deleted file mode 100644 (file)
index c9464aa..0000000
+++ /dev/null
@@ -1,531 +0,0 @@
-/*************************************************
-*     Exim - an Internet mail transport agent    *
-*************************************************/
-
-/* Cygwin-specific code. December 2002. Updated Jan 2015.
-   This is prefixed to the src/os.c file.
-
-   This code was supplied by Pierre A. Humblet <Pierre.Humblet@ieee.org>
-*/
-
-/* We need a special mkdir that
-   allows names starting with // */
-#undef mkdir
-int cygwin_mkdir( const char *path, mode_t mode )
-{
-  const char * p = path;
-  if (*p == '/') while(*(p+1) == '/') p++;
-  return mkdir(p, mode);
-}
-
-#ifndef COMPILE_UTILITY /* Utilities don't need special code */
-
-#ifdef INCLUDE_PAM
-#include "../pam/pam.c"
-#endif
-#include <alloca.h>
-
-unsigned int cygwin_WinVersion;
-
-/* Conflict between Windows definitions and others */
-#ifdef NOERROR
-#undef NOERROR
-#endif
-#ifdef DELETE
-#undef DELETE
-#endif
-
-#include <windows.h>
-#include <ntstatus.h>
-#include <lmcons.h>
-
-#define EqualLuid(Luid1, Luid2) \
-  ((Luid1.LowPart == Luid2.LowPart) && (Luid1.HighPart == Luid2.HighPart))
-#include <sys/cygwin.h>
-
-/* Special static variables */
-static BOOL cygwin_debug = FALSE;
-static int fakesetugid = 1; /* when not privileged, setugid = noop */
-
-#undef setuid
-int cygwin_setuid(uid_t uid )
-{
-  int res = 0;
-  if (fakesetugid == 0) { 
-    res = setuid(uid);
-    if (cygwin_debug)
-      fprintf(stderr, "setuid %u %u %d pid: %d\n",
-              uid, getuid(),res, getpid());
-  }
-  return res;
-}
-
-#undef setgid
-int cygwin_setgid(gid_t gid )
-{
-  int res = 0;
-  if (fakesetugid == 0) { 
-    res = setgid(gid);
-    if (cygwin_debug)
-      fprintf(stderr, "setgid %u %u %d pid: %d\n",
-              gid, getgid(), res, getpid());
-  }
-  return res;
-}
-
-/* Background processes run at lower priority */
-static void cygwin_setpriority()
-{
-  if (!SetPriorityClass(GetCurrentProcess(), BELOW_NORMAL_PRIORITY_CLASS))
-    SetPriorityClass(GetCurrentProcess(), IDLE_PRIORITY_CLASS);
-  return;
-}
-
-
-/* GetVersion()
-   MSB: 1 for 95/98/ME; Next 7: build number, except for 95/98/ME
-   Next byte: 0
-   Next byte: minor version of OS
-   Low  byte: major version of OS (3 or 4 for for NT, 5 for 2000 and XP) */
-//#define VERSION_IS_58M(x) (x & 0x80000000) /* 95, 98, Me   */
-//#define VERSION_IS_NT(x)  ((x & 0XFF) < 5) /* NT 4 or 3.51 */
-
-/*
-  Routine to find if process or thread is privileged
-*/
-
-enum {
-  CREATE_BIT = 1,
-};
-
-static DWORD get_privileges ()
-{
-  char buffer[1024];
-  DWORD i, length;
-  HANDLE hToken = NULL;
-  PTOKEN_PRIVILEGES privs;
-  LUID cluid, rluid;
-  DWORD ret = 0;
-
-  privs = (PTOKEN_PRIVILEGES) buffer;
-
-  if (OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY, &hToken)
-      && LookupPrivilegeValue (NULL, SE_CREATE_TOKEN_NAME, &cluid)
-      && LookupPrivilegeValue(NULL, SE_RESTORE_NAME, &rluid)
-      && (GetTokenInformation( hToken, TokenPrivileges,
-                               privs, sizeof (buffer), &length)
-          || (GetLastError () == ERROR_INSUFFICIENT_BUFFER
-              && (privs = (PTOKEN_PRIVILEGES) alloca (length))
-              && GetTokenInformation(hToken, TokenPrivileges,
-                                     privs, length, &length)))) {
-    for (i = 0; i < privs->PrivilegeCount; i++) {
-      if (EqualLuid(privs->Privileges[i].Luid, cluid))
-        ret |= CREATE_BIT;
-      if (ret == (CREATE_BIT))
-        break;
-    }
-  }
-  else
-    fprintf(stderr, "has_create_token_privilege %u\n", GetLastError());
-
-  if (hToken)
-    CloseHandle(hToken);
-
-  return ret;
-}
-
-/* 
-  We use cygwin_premain to fake a few things 
-       and to provide some debug info 
-*/
-void cygwin_premain2(int argc, char ** argv, struct per_process * ptr)
-{
-  int i, res, is_daemon = 0, is_spoolwritable, is_privileged, is_eximuser;
-  uid_t myuid, systemuid;
-  gid_t mygid, adminsgid;
-  struct passwd * pwp = NULL;
-  struct stat buf;
-  char *cygenv;
-  SID(1, SystemSid, SECURITY_LOCAL_SYSTEM_RID);
-  SID(2, AdminsSid, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS);
-  DWORD priv_flags;
-
-  myuid = getuid();
-  mygid = getgid();
-  cygwin_WinVersion = GetVersion();
-  if ((cygenv = getenv("CYGWIN")) == NULL) cygenv = "";
-  /* Produce some debugging on stderr,
-     cannot yet use exim's debug functions.
-     Exim does not use -c and ignores -n.
-     Set lower priority for daemons */
-  for (i = 1; i < argc; i++) {
-    if (argv[i][0] == '-') {
-      if (argv[i][1] == 'c') {
-        ssize_t size;
-        wchar_t *win32_path;
-        argv[i][1] = 'n';  /* Replace -c by -n */
-        cygwin_debug = TRUE;
-        fprintf(stderr, "CYGWIN = \"%s\".\n", cygenv);
-        if (((size = cygwin_conv_path(CCP_POSIX_TO_WIN_W,"/", win32_path, 0)) > 0)
-        && ((win32_path = malloc(size)) != NULL)
-         && (cygwin_conv_path(CCP_POSIX_TO_WIN_W,"/", win32_path, size) == 0)) {
-               fprintf(stderr, " Root / mapped to %ls.\n", win32_path);
-               free(win32_path);
-       }
-      }
-      else if (argv[i][1] == 'b' && argv[i][2] == 'd') {
-        is_daemon = 1;
-        cygwin_setpriority();
-    }
-  }
-  }
-
-  /* Nt/2000/XP
-     We initially set the exim uid & gid to those of the "exim user",
-       or to the root uid (SYSTEM) and exim gid (ADMINS),
-     If privileged, we setuid to those.
-     We always set the configure uid to the system uid.
-     We always set the root uid to the real uid
-       to allow exim imposed restrictions (bypassable by recompiling)
-       and to avoid exec that cause loss of privilege
-     If not privileged and unable to chown,
-       we set the exim uid to our uid.
-     If unprivileged and /var/spool/exim is writable and not running as listening daemon, 
-       we fake all subsequent setuid. */
-
-  /* Get the system and admins uid from their sids */
-  if ((systemuid = cygwin_internal(CW_GET_UID_FROM_SID, & SystemSid)) == -1) {
-       fprintf(stderr, "Cannot map System sid. Aborting\n");
-       exit(1);
-  }
-  if ((adminsgid = cygwin_internal(CW_GET_GID_FROM_SID, & AdminsSid)) == -1) {
-       fprintf(stderr, "Cannot map Admins sid. Aborting\n");
-       exit(1);
-  }
-
-  priv_flags = get_privileges ();
-  is_privileged = !!(priv_flags & CREATE_BIT);
-
-  /* Call getpwnam for account exim after getting the local exim name */
-  char exim_username[DNLEN + UNLEN + 2];
-  if (cygwin_internal(CW_CYGNAME_FROM_WINNAME, "exim", exim_username, sizeof exim_username) != 0)
-     pwp = getpwnam (exim_username);
-
-  /* If cannot setuid to exim or and is not the daemon (which is assumed to be
-     able to chown or to be the exim user) set the exim ugid to our ugid to avoid
-     chown failures after creating files and to be able to setuid to exim in 
-     exim.c ( "privilege not needed" ). */
-  if ((is_privileged == 0) && (!is_daemon)) {
-    exim_uid = myuid;
-    exim_gid = mygid;
-  }
-  else if (pwp != NULL) {
-    exim_uid = pwp->pw_uid;  /* Set it according to passwd */
-    exim_gid = pwp->pw_gid;
-    is_eximuser = 1;
-  }
-  else {
-    exim_uid = systemuid;
-    exim_gid = adminsgid;
-    is_eximuser = 0;
-  }
-
-  res = stat("/var/spool/exim", &buf);
-  /* Check if writable (and can be stat) */
-  is_spoolwritable = ((res == 0) && ((buf.st_mode & S_IWOTH) != 0));
-
-  fakesetugid = (is_privileged == 0) && (is_daemon == 0) && (is_spoolwritable == 1);
-
-  if (is_privileged) {             /* Can setuid */
-     if (cygwin_setgid(exim_gid) /* Setuid to exim */
-         || cygwin_setuid(exim_uid)) {
-          fprintf(stderr, "Unable to setuid/gid to exim. priv_flags: %x\n", priv_flags);
-          exit(0);          /* Problem... Perhaps not in 544 */
-     }
-  }
-
-  /* Set the configuration file uid and gid to the system uid and admins gid. */
-  config_uid = systemuid;
-  config_gid = adminsgid;
-
-  /* Pretend we are root to avoid useless exec
-     and avoid exim set limitations.
-     We are limited by file access rights */
-  root_uid = getuid ();
-
-  if (cygwin_debug) {
-    fprintf(stderr, "Starting uid %u, gid %u, priv_flags %x, is_privileged %d, is_daemon %d, is_spoolwritable %d.\n",
-            myuid, mygid, priv_flags, is_privileged, is_daemon, is_spoolwritable);
-    fprintf(stderr, "root_uid %u, exim_uid %u, exim_gid %u, config_uid %u, config_gid %u, is_eximuser %d.\n",
-            root_uid, exim_uid, exim_gid, config_uid, config_gid, is_eximuser);
-  }
-  return;
-}
-
-#ifndef OS_LOAD_AVERAGE /* Can be set on command line */
-#define OS_LOAD_AVERAGE /* src/os.c need not provide it */
-
-/*****************************************************************
- Functions for average load measurements
-
- Uses NtQuerySystemInformation.
- This requires definitions that are not part of
- standard include files.
-
- This is discouraged starting with WinXP.
-
-*************************************************************/
-/* Structure to compute the load average efficiently */
-typedef struct {
-  DWORD Lock;
-  unsigned long long Time100ns;   /* Last measurement time */
-  unsigned long long IdleCount;   /* Latest cumulative idle time */
-  unsigned long long LastCounter; /* Last measurement counter */
-  unsigned long long PerfFreq;    /* Perf counter frequency */
-  int LastLoad;                   /* Last reported load, or -1 */
-} cygwin_perf_t;
-
-static struct {
-   HANDLE handle;
-   pid_t pid;
-   cygwin_perf_t *perf;
-} cygwin_load = {NULL, 0, NULL};
-
-#include <ntdef.h>
-
-typedef enum _SYSTEM_INFORMATION_CLASS
-{
-  SystemBasicInformation = 0,
-  SystemPerformanceInformation = 2,
-  SystemTimeOfDayInformation = 3,
-  SystemProcessesAndThreadsInformation = 5,
-  SystemProcessorTimes = 8,
-  SystemPagefileInformation = 18,
-  /* There are a lot more of these... */
-} SYSTEM_INFORMATION_CLASS;
-
-typedef struct _SYSTEM_BASIC_INFORMATION
-{
-  ULONG Unknown;
-  ULONG MaximumIncrement;
-  ULONG PhysicalPageSize;
-  ULONG NumberOfPhysicalPages;
-  ULONG LowestPhysicalPage;
-  ULONG HighestPhysicalPage;
-  ULONG AllocationGranularity;
-  ULONG LowestUserAddress;
-  ULONG HighestUserAddress;
-  ULONG ActiveProcessors;
-  UCHAR NumberProcessors;
-} SYSTEM_BASIC_INFORMATION, *PSYSTEM_BASIC_INFORMATION;
-
-typedef struct __attribute__ ((aligned (8))) _SYSTEM_PROCESSOR_TIMES
-{
-  LARGE_INTEGER IdleTime;
-  LARGE_INTEGER KernelTime;
-  LARGE_INTEGER UserTime;
-  LARGE_INTEGER DpcTime;
-  LARGE_INTEGER InterruptTime;
-  ULONG InterruptCount;
-} SYSTEM_PROCESSOR_TIMES, *PSYSTEM_PROCESSOR_TIMES;
-
-typedef NTSTATUS NTAPI (*NtQuerySystemInformation_t) (SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG);
-typedef ULONG NTAPI (*RtlNtStatusToDosError_t) (NTSTATUS);
-
-static NtQuerySystemInformation_t NtQuerySystemInformation;
-static RtlNtStatusToDosError_t RtlNtStatusToDosError;
-
-/*****************************************************************
- *
- LoadNtdll()
- Load special functions from the NTDLL
- Return TRUE if success.
-
- *****************************************************************/
-
-static BOOL LoadNtdll()
-{
-  HINSTANCE hinstLib;
-
-  if ((hinstLib = LoadLibrary("NTDLL.DLL"))
-      && (NtQuerySystemInformation =
-          (NtQuerySystemInformation_t) GetProcAddress(hinstLib,
-                                                        "NtQuerySystemInformation"))
-      && (RtlNtStatusToDosError =
-          (RtlNtStatusToDosError_t) GetProcAddress(hinstLib,
-                                                     "RtlNtStatusToDosError")))
-    return TRUE;
-
-  DEBUG(D_load)
-    debug_printf("perf: load: %u (Windows)\n", GetLastError());
-  return FALSE;
-}
-/*****************************************************************
- *
- ReadStat()
- Measures current Time100ns and IdleCount
- Return TRUE if success.
-
- *****************************************************************/
-
-static BOOL ReadStat(unsigned long long int *Time100nsPtr,
-                     unsigned long long int *IdleCountPtr)
-{
-  NTSTATUS ret;
-  SYSTEM_BASIC_INFORMATION sbi;
-  PSYSTEM_PROCESSOR_TIMES spt;
-
-  *Time100nsPtr = *IdleCountPtr = 0;
-
-  if ((ret = NtQuerySystemInformation(SystemBasicInformation,
-                                      (PVOID) &sbi, sizeof sbi, NULL))
-      != STATUS_SUCCESS) {
-    DEBUG(D_load)
-      debug_printf("Perf: NtQuerySystemInformation: %u (Windows)\n",
-                   RtlNtStatusToDosError(ret));
-  }
-  else if (!(spt = (PSYSTEM_PROCESSOR_TIMES) alloca(sizeof(spt[0]) * sbi.NumberProcessors))) {
-    DEBUG(D_load)
-      debug_printf("Perf: alloca: errno %d (%s)\n", errno, strerror(errno));
-  }
-  else if ((ret = NtQuerySystemInformation(SystemProcessorTimes, (PVOID) spt,
-                                           sizeof spt[0] * sbi.NumberProcessors, NULL))
-           != STATUS_SUCCESS) {
-    DEBUG(D_load)
-      debug_printf("Perf: NtQuerySystemInformation: %u (Windows)\n",
-                   RtlNtStatusToDosError(ret));
-  }
-  else {
-    int i;
-    for (i = 0; i < sbi.NumberProcessors; i++) {
-      *Time100nsPtr += spt[i].KernelTime.QuadPart;;
-      *Time100nsPtr += spt[i].UserTime.QuadPart;
-      *IdleCountPtr += spt[i].IdleTime.QuadPart;
-    }
-    return TRUE;
-  }
-  return FALSE;
-}
-
-/*****************************************************************
- *
- InitLoadAvg()
- Initialize the cygwin_load.perf structure.
- and set cygwin_load.perf->Flag to TRUE if successful.
- This is called the first time os_getloadavg is called
- *****************************************************************/
-static void InitLoadAvg(cygwin_perf_t *this)
-{
-  BOOL success = TRUE;
-
-  /* Get perf frequency and counter */
-  QueryPerformanceFrequency((LARGE_INTEGER *)& this->PerfFreq);
-  QueryPerformanceCounter((LARGE_INTEGER *)& this->LastCounter);
-
-  /* Get initial values for Time100ns and IdleCount */
-  success = success
-            && ReadStat( & this->Time100ns,
-                         & this->IdleCount);
-  /* If success, set the Load to 0, else to -1 */
-  if (success) this->LastLoad = 0;
-  else {
-    log_write(0, LOG_MAIN, "Cannot obtain Load Average");
-    this->LastLoad = -1;
-  }
-}
-
-
-/*****************************************************************
- *
- os_getloadavg()
-
- Return -1 if not available;
- Return the previous value if less than AVERAGING sec old.
- else return the processor load on a [0 - 1000] scale.
-
- The first time we are called we initialize the counts
- and return 0 or -1.
- The initial load cannot be measured as we use the processor 100%
-*****************************************************************/
-static SECURITY_ATTRIBUTES sa = {sizeof (SECURITY_ATTRIBUTES), NULL, TRUE};
-#define AVERAGING 10
-
-int os_getloadavg()
-{
-  unsigned long long Time100ns, IdleCount, CurrCounter;
-  int value;
-  pid_t newpid;
-
-  /* New process.
-     Reload the dlls and the file mapping */
-  if ((newpid = getpid()) != cygwin_load.pid) {
-    BOOL new;
-    cygwin_load.pid = newpid;
-
-    if (!LoadNtdll()) {
-      log_write(0, LOG_MAIN, "Cannot obtain Load Average");
-      cygwin_load.perf = NULL;
-      return -1;
-    }
-
-    if ((new = !cygwin_load.handle)) {
-      cygwin_load.handle = CreateFileMapping (INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE,
-                                              0, sizeof(cygwin_perf_t), NULL);
-      DEBUG(D_load)
-        debug_printf("Perf: CreateFileMapping: handle %p\n", (void *) cygwin_load.handle);
-    }
-    cygwin_load.perf = (cygwin_perf_t *) MapViewOfFile (cygwin_load.handle,
-                                                        FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
-    DEBUG(D_load)
-      debug_printf("Perf: MapViewOfFile: addr %p\n", (void *) cygwin_load.perf);
-    if (new && cygwin_load.perf)
-      InitLoadAvg(cygwin_load.perf);
-  }
-
-  /* Check if initialized OK */
-  if (!cygwin_load.perf || cygwin_load.perf->LastLoad < 0)
-    return -1;
-
-  /* If we cannot get the lock, we return 0.
-     This is to prevent any lock-up possibility.
-     Finding a lock busy is unlikely, and giving up only
-     results in an immediate delivery .*/
-
-  if (InterlockedCompareExchange(&cygwin_load.perf->Lock, 1, 0)) {
-    DEBUG(D_load)
-      debug_printf("Perf: Lock busy\n");
-    return 0;
-  }
-
-    /* Get the current time (PerfCounter) */
-    QueryPerformanceCounter((LARGE_INTEGER *)& CurrCounter);
-    /* Calls closer than AVERAGING sec apart use the previous value */
-  if (CurrCounter - cygwin_load.perf->LastCounter >
-      AVERAGING * cygwin_load.perf->PerfFreq) {
-      /* Get Time100ns and IdleCount */
-      if (ReadStat( & Time100ns, & IdleCount)) { /* Success */
-        /* Return processor load on 1000 scale */
-      value = 1000 - ((1000 * (IdleCount - cygwin_load.perf->IdleCount)) /
-                      (Time100ns - cygwin_load.perf->Time100ns));
-      cygwin_load.perf->Time100ns = Time100ns;
-      cygwin_load.perf->IdleCount = IdleCount;
-      cygwin_load.perf->LastCounter = CurrCounter;
-      cygwin_load.perf->LastLoad = value;
-      DEBUG(D_load)
-        debug_printf("Perf: New load average %d\n", value);
-      }
-      else { /* Something bad happened.
-                Refuse to measure the load anymore
-                but don't bother releasing the buffer */
-        log_write(0, LOG_MAIN, "Cannot obtain Load Average");
-      cygwin_load.perf->LastLoad = -1;
-    }
-  }
-  else
-  DEBUG(D_load)
-      debug_printf("Perf: Old load average %d\n", cygwin_load.perf->LastLoad);
-  cygwin_load.perf->Lock = 0;
-  return cygwin_load.perf->LastLoad;
-}
-#endif /* OS_LOAD_AVERAGE */
-#endif /* COMPILE_UTILITY */
diff --git a/src/OS/os.h-AIX b/src/OS/os.h-AIX
deleted file mode 100644 (file)
index 5cd4501..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/* Exim: OS-specific C header file for AIX */
-/* Written by Nick Waterman <nick@cimio.co.uk> */
-/* Modified by Philip Hazel with data from
-   Niels Provos <provos@wserver.physnet.uni-hamburg.de>
-   Juozas Simkevicius <juozas@omnitel.net> for load averages
-*/
-
-#define HAVE_DEV_KMEM
-#define LOAD_AVG_SYMBOL "avenrun"
-#define KERNEL_PATH     "/unix"
-#define LOAD_AVG_TYPE   int
-#define FSCALE          65536.0
-
-#define HAVE_SYS_VFS_H
-#define HAVE_SYS_STATFS_H
-
-/* Now tell AIX to emulate BSD as badly as it can. */
-
-#define _BSD 44
-
-typedef struct flock flock_t;
-
-/* default is non-const */
-#define ICONV_ARG2_TYPE const char **
-
-
-/* End */
diff --git a/src/OS/os.h-BSDI b/src/OS/os.h-BSDI
deleted file mode 100644 (file)
index a1705ec..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-/* Exim: OS-specific C header file for BSDI */
-
-#define HAVE_BSD_GETLOADAVG
-#define HAVE_SETCLASSRESOURCES
-#define HAVE_MMAP
-#define HAVE_SYS_MOUNT_H
-#define SIOCGIFCONF_GIVES_ADDR
-#define OS_UNSETENV
-
-typedef struct flock flock_t;
-
-/* default is non-const */
-#define ICONV_ARG2_TYPE const char **
-
-/* End */
diff --git a/src/OS/os.h-DGUX b/src/OS/os.h-DGUX
deleted file mode 100644 (file)
index 9040f0e..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/* Exim: OS-specific C header file for DGUX */
-
-/* Written by Ken Bailey (K.Bailey@rbgkew.org.uk) Feb 1998 */
-/* on dgux R4.11MU04 generic AViiON mc88100                */
-/* Modified Dec 1998 by PH after message from Ken.         */
-
-#define HAVE_SYS_STATVFS_H
-#define F_FAVAIL                 f_favail
-
-#define NO_SYSEXITS              /* DGUX doesn't ship sysexits.h */
-#define NO_IP_VAR_H              /* DGUX has no netinet/ip_var.h */
-
-#define os_strsignal             dg_strsignal
-#define OS_STRSIGNAL
-
-#define HAVE_MMAP
-
-/* The definition of ipoptions in netinet/in.h (masquerading as ip_opts) used
-in smtp_in.c is for Intel DG _IX86_ABI only. You may be able to get this to
-work on Intel DG but it's certainly easier to skip it on M88k. This means we
-forego the detection of some source-routing based IP attacks. */
-
-#define NO_IP_OPTIONS
-
-/* default is non-const */
-#define ICONV_ARG2_TYPE const char **
-
-/* End */
diff --git a/src/OS/os.h-Darwin b/src/OS/os.h-Darwin
deleted file mode 100644 (file)
index f408740..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-/* Exim: OS-specific C header file for Darwin (Mac OS X) */
-
-/* #define CRYPT_H */  /* Apparently this isn't needed */
-
-#define HAVE_MMAP
-#define HAVE_SYS_MOUNT_H
-#define PAM_H_IN_PAM
-#define SIOCGIFCONF_GIVES_ADDR
-
-/* OSX 10.2 does not have poll.h, 10.3 does emulate it badly. */
-#define NO_POLL_H
-
-#define F_FREESP     O_TRUNC
-typedef struct flock flock_t;
-
-#define BASE_62 36  /* HFS+ aliases lower and upper cases in filenames.
-                               Consider reducing MAX_LOCALHOST_NUMBER */
-
-#ifndef        _BSD_SOCKLEN_T_
-#define _BSD_SOCKLEN_T_ int32_t                 /* socklen_t (duh) */
-#endif
-
-/* Settings for handling IP options. There's no netinet/ip_var.h. The IP
-option handling is in the style of the later GLIBCs but the GLIBC macros
-aren't set, so we invent a new one. */
-
-#define NO_IP_VAR_H
-#define DARWIN_IP_OPTIONS
-
-/* Need this for the DNS lookup code. Remember to remove if we get round to
-updating Exim to use the newer interface. */
-
-#define BIND_8_COMPAT
-
-/* It's not .so for dynamic libraries on Darwin. */
-#define DYNLIB_FN_EXT "dylib"
-
-/* We currently need some assistance getting OFF_T_FMT correct on MacOS */
-#ifdef OFF_T_FMT
-# undef OFF_T_FMT
-#endif
-#define OFF_T_FMT "%lld"
-#define LONGLONG_T long int
-
-/* default is non-const */
-#define ICONV_ARG2_TYPE const char **
-
-/* End */
diff --git a/src/OS/os.h-DragonFly b/src/OS/os.h-DragonFly
deleted file mode 100644 (file)
index 4c2f1d5..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-/* Exim: OS-specific C header file for DragonFly */
-
-#define HAVE_BSD_GETLOADAVG
-#define HAVE_MMAP
-#define HAVE_SYS_MOUNT_H
-#define SIOCGIFCONF_GIVES_ADDR
-
-typedef struct flock flock_t;
-
-/* default is non-const */
-#define ICONV_ARG2_TYPE const char **
-
-/* End */
index bf43e0a3cec0415c6681db719e063a2e5b9cd89a..3a06e766ed365a75e01f8ac99305e309a57ad8d3 100644 (file)
@@ -1,5 +1,7 @@
 /* Exim: OS-specific C header file for FreeBSD */
 
+#include <sys/types.h>
+
 #define HAVE_BSD_GETLOADAVG
 #define HAVE_SETCLASSRESOURCES
 #define HAVE_MMAP
@@ -34,4 +36,29 @@ typedef struct flock flock_t;
 /* for more specific version constraints, include <sys/param.h> and look at
  * __FreeBSD_version */
 
+
+/* When using DKIM, setting OS_SENDFILE can increase
+performance on outgoing mail a bit. */
+
+#define OS_SENDFILE
+extern ssize_t os_sendfile(int, int, off_t *, size_t);
+
+
+/*******************/
+
+/* TCP_FASTOPEN support.  There does not seems to be a
+MSG_FASTOPEN defined yet... */
+
+#include <netinet/tcp.h>        /* for TCP_FASTOPEN */
+#include <sys/socket.h>         /* for MSG_FASTOPEN */
+#if defined(TCP_FASTOPEN) && !defined(MSG_FASTOPEN)
+# define MSG_FASTOPEN 0x20000000
+#endif
+/* for TCP state-variable values, for TFO logging */
+#include <netinet/tcp_fsm.h>
+#define TCP_SYN_RECV TCPS_SYN_RECEIVED
+
+/*******************/
+
 /* End */
diff --git a/src/OS/os.h-GNU b/src/OS/os.h-GNU
deleted file mode 100644 (file)
index 4499316..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/* Exim: OS-specific C header file for GNU/Hurd */
-
-#define CRYPT_H
-#define GLIBC_IP_OPTIONS
-#define HAVE_BSD_GETLOADAVG
-#define HAVE_MMAP
-#define HAVE_SYS_VFS_H
-#define NO_IP_VAR_H
-#define SIG_IGN_WORKS
-#define SIOCGIFCONF_GIVES_ADDR
-
-#define F_FREESP     O_TRUNC
-typedef struct flock flock_t;
-
-#define os_strsignal strsignal
-#define OS_STRSIGNAL
-
-/* Hurd-specific bits below */
-
-/* default is non-const */
-#define ICONV_ARG2_TYPE const char **
-
-/* End */
diff --git a/src/OS/os.h-GNUkFreeBSD b/src/OS/os.h-GNUkFreeBSD
deleted file mode 100644 (file)
index ab35031..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/* Exim: OS-specific C header file for GNU/kFreeBSD */
-
-#define CRYPT_H
-#define GLIBC_IP_OPTIONS
-#define HAVE_MMAP
-#define HAVE_BSD_GETLOADAVG
-#define HAVE_SYS_VFS_H
-#define NO_IP_VAR_H
-#define SIG_IGN_WORKS
-
-#define F_FREESP     O_TRUNC
-typedef struct flock flock_t;
-
-#define os_strsignal strsignal
-#define OS_STRSIGNAL
-
-/* kFreeBSD-specific bits below */
-
-#define HAVE_SYS_MOUNT_H
-#define SIOCGIFCONF_GIVES_ADDR
-
-/* default is non-const */
-#define ICONV_ARG2_TYPE const char **
-
-/* End */
diff --git a/src/OS/os.h-GNUkNetBSD b/src/OS/os.h-GNUkNetBSD
deleted file mode 100644 (file)
index bc3bc25..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/* Exim: OS-specific C header file for GNU/kNetBSD */
-
-#define CRYPT_H
-#define GLIBC_IP_OPTIONS
-#define HAVE_MMAP
-#define HAVE_BSD_GETLOADAVG
-#define HAVE_SYS_VFS_H
-#define NO_IP_VAR_H
-#define SIG_IGN_WORKS
-
-#define F_FREESP     O_TRUNC
-typedef struct flock flock_t;
-
-#define os_strsignal strsignal
-#define OS_STRSIGNAL
-
-/* kNetBSD-specific bits below */
-
-#define HAVE_SYS_MOUNT_H
-#define SIOCGIFCONF_GIVES_ADDR
-
-/* default is non-const */
-#define ICONV_ARG2_TYPE const char **
-
-/* End */
diff --git a/src/OS/os.h-HI-OSF b/src/OS/os.h-HI-OSF
deleted file mode 100644 (file)
index 0f50fb6..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-/* Exim: OS-specific C header file for HI-OSF/1-MJ and HI-UX/MPP */
-
-#define HAVE_SYS_MOUNT_H
-
-typedef struct flock           flock_t;
-#define F_FREESP               O_TRUNC
-#define DN_EXPAND_ARG4_TYPE    u_char *
-
-/* default is non-const */
-#define ICONV_ARG2_TYPE const char **
-
-/* End */
diff --git a/src/OS/os.h-HI-UX b/src/OS/os.h-HI-UX
deleted file mode 100644 (file)
index f3df963..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/* Exim: OS-specific C header file for HI-UX */
-
-#define LOAD_AVG_NEEDS_ROOT
-#define HAVE_DEV_KMEM
-#define LOAD_AVG_TYPE       double
-#define LOAD_AVG_SYMBOL     "avenrun"
-#define KERNEL_PATH         "/HI-UX"
-#define FSCALE              1.0
-
-#define HAVE_SYS_VFS_H
-
-#define SELECT_ARG2_TYPE    int
-#define F_FREESP            O_TRUNC
-#define NEED_H_ERRNO        1
-
-typedef struct flock flock_t;
-
-/* default is non-const */
-#define ICONV_ARG2_TYPE const char **
-
-/* End */
diff --git a/src/OS/os.h-HP-UX b/src/OS/os.h-HP-UX
deleted file mode 100644 (file)
index 4998734..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-/* Exim: OS-specific C header file for HP-UX versions greater than 9 */
-
-#define EXIM_SOCKLEN_T size_t
-
-#define LOAD_AVG_NEEDS_ROOT
-#define HAVE_DEV_KMEM
-#define LOAD_AVG_TYPE   double
-#define LOAD_AVG_SYMBOL "avenrun"
-#define KERNEL_PATH     "/stand/vmunix"
-#define FSCALE          1.0
-
-#define HAVE_SYS_STATVFS_H
-
-#define F_FREESP           O_TRUNC
-#define NEED_H_ERRNO       1
-
-typedef struct flock flock_t;
-
-typedef struct __res_state *res_state;
-
-#define LLONG_MIN LONG_LONG_MIN
-#define LLONG_MAX LONG_LONG_MAX
-
-#define strtoll(a,b,c) strtoimax(a,b,c)
-
-/* Determined by sockaddr_un */
-
-struct sockaddr_storage
-{
-  short ss_family;
-  char __ss_padding[92];
-};
-
-/* End */
diff --git a/src/OS/os.h-HP-UX-9 b/src/OS/os.h-HP-UX-9
deleted file mode 100644 (file)
index 5a260d6..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-/* Exim: OS-specific C header file for HP-UX version 9 */
-
-#define LOAD_AVG_NEEDS_ROOT
-#define HAVE_DEV_KMEM
-#define LOAD_AVG_TYPE   double
-#define LOAD_AVG_SYMBOL "avenrun"
-#define KERNEL_PATH     "/hp-ux"
-#define FSCALE          1.0
-
-#define HAVE_SYS_VFS_H
-
-#define SELECT_ARG2_TYPE   int
-#define F_FREESP           O_TRUNC
-#define NEED_H_ERRNO       1
-
-#define killpg(pgid,sig)   kill(-(pgid),sig)
-
-typedef struct flock flock_t;
-
-/* default is non-const */
-#define ICONV_ARG2_TYPE const char **
-
-/* End */
diff --git a/src/OS/os.h-IRIX b/src/OS/os.h-IRIX
deleted file mode 100644 (file)
index 1d4bf46..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-/* Exim: OS-specific C header file for IRIX */
-
-#define DN_EXPAND_ARG4_TYPE  u_char *
-
-#define LOAD_AVG_NEEDS_ROOT
-#define HAVE_DEV_KMEM
-#define LOAD_AVG_TYPE   long
-#define LOAD_AVG_SYMBOL "avenrun"
-#define KERNEL_PATH     "/unix"
-#define FSCALE          1000.0
-
-#define HAVE_MMAP
-#define HAVE_SYS_STATVFS_H
-#define F_FAVAIL        f_favail
-#define vfork fork
-
-/* End */
diff --git a/src/OS/os.h-IRIX6 b/src/OS/os.h-IRIX6
deleted file mode 100644 (file)
index bf30767..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/* Exim: OS-specific C header file for IRIX */
-
-#define CRYPT_H
-#define LOAD_AVG_NEEDS_ROOT
-#define HAVE_DEV_KMEM
-#define LOAD_AVG_TYPE   long
-#define LOAD_AVG_SYMBOL "avenrun"
-#define KERNEL_PATH     "/unix"
-#define FSCALE          1000.0
-
-#define HAVE_MMAP
-#define HAVE_SYS_STATVFS_H
-#define F_FAVAIL        f_favail
-#define vfork fork
-
-/* End */
diff --git a/src/OS/os.h-IRIX632 b/src/OS/os.h-IRIX632
deleted file mode 100644 (file)
index 90f1c58..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/* Exim: OS-specific C header file for IRIX */
-
-#define CRYPT_H
-#define DN_EXPAND_ARG4_TYPE  u_char *
-
-#define LOAD_AVG_NEEDS_ROOT
-#define HAVE_DEV_KMEM
-#define LOAD_AVG_TYPE   long
-#define LOAD_AVG_SYMBOL "avenrun"
-#define KERNEL_PATH     "/unix"
-#define FSCALE          1000.0
-
-#define HAVE_MMAP
-#define HAVE_SYS_STATVFS_H
-#define F_FAVAIL        f_favail
-#define vfork fork
-
-/* End */
diff --git a/src/OS/os.h-IRIX65 b/src/OS/os.h-IRIX65
deleted file mode 100644 (file)
index 4b248fe..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/* Exim: OS-specific C header file for IRIX 6.5 */
-
-#define CRYPT_H
-#define LOAD_AVG_NEEDS_ROOT
-#define HAVE_DEV_KMEM
-#define LOAD_AVG_TYPE   long
-#define LOAD_AVG_SYMBOL "avenrun"
-#define KERNEL_PATH     "/unix"
-#define FSCALE          1000.0
-
-#define HAVE_MMAP
-#define HAVE_SYS_STATVFS_H
-#define F_FAVAIL        f_favail
-#define vfork fork
-
-/* End */
index cc1cef99be849c10d487aef94e5a767f02d95b38..cc1f3cab2df2544983f3fc42aac851c107fe971b 100644 (file)
@@ -5,6 +5,7 @@ does not pull in <features.h>.  Best to just pull it in now and have done
 with the issue. */
 
 #include <features.h>
+#include <sys/types.h>
 
 
 #define CRYPT_H
@@ -15,12 +16,14 @@ with the issue. */
 #define NO_IP_VAR_H
 #define SIG_IGN_WORKS
 
-/* When using the DKIM, setting HAVE_LINUX_SENDFILE can increase
+/* When using DKIM, setting OS_SENDFILE can increase
 performance on outgoing mail a bit. Note: With older glibc versions
 this setting will conflict with the _FILE_OFFSET_BITS=64 setting
-defined as part of the Linux CFLAGS. */
+defined as part of the Linux CFLAGS.  As of 2017 those are declared
+to be too old to build by default. */
 
-/* #define HAVE_LINUX_SENDFILE */
+#define OS_SENDFILE
+extern ssize_t os_sendfile(int, int, off_t *, size_t);
 
 #define F_FREESP     O_TRUNC
 typedef struct flock flock_t;
@@ -29,8 +32,8 @@ typedef struct flock flock_t;
 #define OS_STRSIGNAL
 
 #if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__NetBSD_kernel__)
-#define SIOCGIFCONF_GIVES_ADDR
-#define HAVE_SYS_MOUNT_H
+# define SIOCGIFCONF_GIVES_ADDR
+# define HAVE_SYS_MOUNT_H
 #endif
 
 #if defined(__linux__)
@@ -69,6 +72,8 @@ then change the 0 to 1 in the next block. */
 # define EXIM_HAVE_OPENAT
 #endif
 
+/* TCP Fast Open support */
+
 #include <netinet/tcp.h>       /* for TCP_FASTOPEN */
 #include <sys/socket.h>                /* for MSG_FASTOPEN */
 #if defined(TCP_FASTOPEN) && !defined(MSG_FASTOPEN)
diff --git a/src/OS/os.h-NetBSD b/src/OS/os.h-NetBSD
deleted file mode 100644 (file)
index d2d3e0d..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/* Exim: OS-specific C header file for NetBSD */
-
-#define HAVE_BSD_GETLOADAVG
-#define HAVE_GETIFADDRS
-#define HAVE_MMAP
-#define HAVE_SYS_MOUNT_H
-#define SIOCGIFCONF_GIVES_ADDR
-#define HAVE_ARC4RANDOM
-
-typedef struct flock flock_t;
-
-#define os_strsignal strsignal
-#define OS_STRSIGNAL
-
-#define os_get_dns_resolver_res __res_get_state
-#define os_put_dns_resolver_res(RP) __res_put_state(RP)
-#define OS_GET_DNS_RESOLVER_RES
-
-#include <sys/param.h>
-
-#if __NetBSD_Version__ >= 299000900
-#define HAVE_SYS_STATVFS_H
-#endif
-
-/* default is non-const */
-#define ICONV_ARG2_TYPE const char **
-
-/* End */
diff --git a/src/OS/os.h-NetBSD-a.out b/src/OS/os.h-NetBSD-a.out
deleted file mode 100644 (file)
index 29a8fee..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-/* Exim: OS-specific C header file for NetBSD (a.out binary format) */
-
-#include "../OS/os.h-NetBSD"     /* Same as for ELF format */
-
-/* End */
diff --git a/src/OS/os.h-OSF1 b/src/OS/os.h-OSF1
deleted file mode 100644 (file)
index 6b5fa49..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/* Exim: OS-specific C header file for OSF1 */
-
-#define HAVE_SYS_MOUNT_H
-#define HAVE_GETIPNODEBYNAME    1
-
-typedef struct flock flock_t;
-#define F_FREESP     O_TRUNC
-
-/* This was here for some time, but it seems that now (June 2005) things have
-changed. */
-/* #define EXIM_SOCKLEN_T    size_t */
-
-/* Still not "socklen_t", which is the most common setting */
-#define EXIM_SOCKLEN_T       int
-
-/* End */
diff --git a/src/OS/os.h-OpenUNIX b/src/OS/os.h-OpenUNIX
deleted file mode 100644 (file)
index 67d1063..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/* Exim: OS-specific C header file for OpenUNIX */
-
-#define NO_SYSEXITS
-
-#define LOAD_AVG_NEEDS_ROOT
-#define HAVE_DEV_KMEM
-#define LOAD_AVG_TYPE   short
-#define LOAD_AVG_SYMBOL "avenrun"
-#define KERNEL_PATH     "/stand/unix"
-#define FSCALE          256
-
-#define HAVE_SYS_STATVFS_H
-#define _SVID3
-#define NEED_H_ERRNO
-
-/* default is non-const */
-#define ICONV_ARG2_TYPE const char **
-
-/* End */
diff --git a/src/OS/os.h-QNX b/src/OS/os.h-QNX
deleted file mode 100644 (file)
index 798f799..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/* Exim: OS-specific C header file for QNX */
-/* Modified for QNX 6.2.0 with diffs from Samuli Tuomola. */
-
-#include <sys/select.h>
-
-/* This include is wrapped in an ifdef so as to be skipped for QNXRTP, which
-doesn't have/need this header file. From Karsten P. Hoffmann. */
-
-#ifdef __QNX__
-#include <unix.h>
-#endif
-
-#undef HAVE_STATFS
-#undef HAVE_VFS_H
-#undef HAVE_SYS_MOUNT_H
-
-#define NO_SYSEXITS
-
-extern int h_errno;
-
-/* default is non-const */
-#define ICONV_ARG2_TYPE const char **
-
-/* End */
diff --git a/src/OS/os.h-SCO b/src/OS/os.h-SCO
deleted file mode 100644 (file)
index e5e915e..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-/* Exim: OS-specific C header file for SCO */
-
-#define DN_EXPAND_ARG4_TYPE    u_char *
-
-#define LOAD_AVG_NEEDS_ROOT
-#define HAVE_DEV_KMEM
-#define LOAD_AVG_TYPE   short
-#define LOAD_AVG_SYMBOL "avenrun"
-#define KERNEL_PATH     "/unix"
-#define FSCALE          256
-#define EXIM_SOCKLEN_T  int
-
-#define HAVE_SYS_STATVFS_H
-#define F_FAVAIL        f_favail
-#define _SVID3
-#define NEED_H_ERRNO
-
-/* default is non-const */
-#define ICONV_ARG2_TYPE const char **
-
-/* End */
diff --git a/src/OS/os.h-SCO_SV b/src/OS/os.h-SCO_SV
deleted file mode 100644 (file)
index 0ca29f7..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/* Exim: OS-specific C header file for SCO_SV */
-
-#define LOAD_AVG_NEEDS_ROOT
-#define HAVE_DEV_KMEM
-#define LOAD_AVG_TYPE   short
-#define LOAD_AVG_SYMBOL "avenrun"
-#define KERNEL_PATH     "/unix"
-#define FSCALE          256
-#define EXIM_SOCKLEN_T  int
-
-#define HAVE_SYS_STATVFS_H
-#define F_FAVAIL        f_favail
-#define _SVID3
-#define NEED_H_ERRNO
-
-/* default is non-const */
-#define ICONV_ARG2_TYPE const char **
-
-/* End */
diff --git a/src/OS/os.h-SunOS4 b/src/OS/os.h-SunOS4
deleted file mode 100644 (file)
index 6555620..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/* Exim: OS-specific C header file for SunOS4 */
-
-#define LOAD_AVG_NEEDS_ROOT
-#define HAVE_DEV_KMEM
-#define LOAD_AVG_TYPE   long
-#define LOAD_AVG_SYMBOL "_avenrun"
-#define KERNEL_PATH     "/vmunix"
-
-#define HAVE_MMAP
-#define HAVE_SYS_VFS_H
-
-#define F_FREESP     O_TRUNC
-#define EXIT_FAILURE 1
-#define EXIT_SUCCESS 0
-typedef struct flock flock_t;
-
-#define STRERROR_FROM_ERRLIST
-#define memmove(a, b, c) bcopy(b, a, c)
-#define strtoul(str, ptr, base) ((unsigned int)strtol((str),(ptr),(base)))
-
-extern char *strerror(int);
-extern int   sys_nerr;
-extern char *sys_errlist[];
-
-/* In ANSI C strtod() is defined in stdlib.h, but in SunOS4 it is defined in
-floatingpoint.h which is called from math.h, which Exim doesn't include. */
-
-extern double strtod(const char *, char **);
-
-/* SunOS4 seems to define getc, ungetc, feof and ferror as macros only, not
-as functions. We need to have them as assignable functions. Setting this
-flag causes this to get done in exim.h. */
-
-#define FUDGE_GETC_AND_FRIENDS
-
-/* default is non-const */
-#define ICONV_ARG2_TYPE const char **
-
-/* End */
diff --git a/src/OS/os.h-SunOS5-hal b/src/OS/os.h-SunOS5-hal
deleted file mode 100644 (file)
index cd9e877..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-/* Exim: OS-specific C header file for SunOS5 on HAL */
-
-#define HAVE_MMAP
-
-#define HAVE_KSTAT
-#define LOAD_AVG_KSTAT        "system_misc"
-#define LOAD_AVG_KSTAT_MODULE "unix"
-#define LOAD_AVG_SYMBOL       "avenrun_1min"
-#define LOAD_AVG_FIELD         value.ul
-
-/* default is non-const */
-#define ICONV_ARG2_TYPE const char **
-
-/* End */
diff --git a/src/OS/os.h-ULTRIX b/src/OS/os.h-ULTRIX
deleted file mode 100644 (file)
index 08db5ae..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/* Exim: OS-specific C header file for Ultrix */
-
-/* Well, it *does* have statfs(), but its structure is called something
-different, all the members have different names, and the function returns
-1 on success rather than 0. As this is for a minority function, and I think
-a minority operating system, easiest just to say "no" until someone asks. */
-
-#undef HAVE_STATFS
-
-#define F_FREESP     O_TRUNC
-#define NEED_H_ERRNO
-#define NO_OPENLOG
-typedef struct flock flock_t;
-
-/* default is non-const */
-#define ICONV_ARG2_TYPE const char **
-
-/* End */
diff --git a/src/OS/os.h-UNIX_SV b/src/OS/os.h-UNIX_SV
deleted file mode 100644 (file)
index 4943a07..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/* Exim: OS-specific C header file for SCO SVR4.2 (and maybe Unixware) */
-
-/**
-*** Note that for SCO 5 the configuration file is called SCO_SV,
-*** and that Unixware7 has its own configuration. This is an old
-*** file that is retained for compatibility.
-**/
-
-#define NO_SYSEXITS
-
-#define LOAD_AVG_NEEDS_ROOT
-#define HAVE_DEV_KMEM
-#define LOAD_AVG_TYPE   short
-#define LOAD_AVG_SYMBOL "avenrun"
-#define KERNEL_PATH     "/stand/unix"
-#define FSCALE          256
-
-#define HAVE_SYS_STATVFS_H
-#define _SVID3
-#define NEED_H_ERRNO
-
-/* default is non-const */
-#define ICONV_ARG2_TYPE const char **
-
-/* End */
diff --git a/src/OS/os.h-USG b/src/OS/os.h-USG
deleted file mode 100644 (file)
index e769220..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/* Exim: OS-specific C header file for Unixware 2.x */
-
-#define NO_SYSEXITS
-
-#define LOAD_AVG_NEEDS_ROOT
-#define HAVE_DEV_KMEM
-#define LOAD_AVG_TYPE   short
-#define LOAD_AVG_SYMBOL "avenrun"
-#define KERNEL_PATH     "/stand/unix"
-#define FSCALE          256
-
-#define HAVE_SYS_STATVFS_H
-#define _SVID3
-#define NEED_H_ERRNO
-
-/* default is non-const */
-#define ICONV_ARG2_TYPE const char **
-
-/* End */
diff --git a/src/OS/os.h-Unixware7 b/src/OS/os.h-Unixware7
deleted file mode 100644 (file)
index 4d3ed42..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-/* Exim: OS-specific C header file for Unixware 7 */
-
-#define NO_SYSEXITS
-
-#define EXIM_SOCKLEN_T size_t
-
-#define LOAD_AVG_NEEDS_ROOT
-#define HAVE_DEV_KMEM
-#define LOAD_AVG_TYPE   short
-#define LOAD_AVG_SYMBOL "avenrun"
-#define KERNEL_PATH     "/stand/unix"
-#define FSCALE          256
-
-#define HAVE_SYS_STATVFS_H
-#define _SVID3
-#define NEED_H_ERRNO
-
-/* End */
diff --git a/src/OS/os.h-cygwin b/src/OS/os.h-cygwin
deleted file mode 100644 (file)
index 6ef59e0..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-/* Exim: OS-specific C header file for Cygwin */
-
-/* This code was supplied by Pierre A. Humblet <Pierre.Humblet@ieee.org>
-   December 2002. Updated Jan 2015. */
-
-/* Redefine the set*id calls to run when faking root */
-#include <unistd.h>   /* Do not redefine in unitsd.h */
-int cygwin_setuid(uid_t uid );
-int cygwin_setgid(gid_t gid );
-#define setuid cygwin_setuid
-#define setgid cygwin_setgid
-
-#define os_strsignal strsignal
-#define OS_STRSIGNAL
-#define BASE_62 36  /* Windows aliases lower and upper cases in filenames.
-                       Consider reducing MAX_LOCALHOST_NUMBER */
-#define CRYPT_H
-#define HAVE_MMAP
-#define HAVE_SYS_VFS_H
-#define NO_IP_VAR_H
-#define NO_IP_OPTIONS
-/* Defining LOAD_AVG_NEEDS_ROOT causes an initial
-   call to os_getloadavg. In our case this is beneficial
-   because it initializes the counts */
-#define LOAD_AVG_NEEDS_ROOT
-
-typedef struct flock flock_t;
-
-/* Macro to define variable length SID structures */
-#define SID(n, name, sid...) \
-struct  { \
-  BYTE  Revision; \
-  BYTE  SubAuthorityCount; \
-  SID_IDENTIFIER_AUTHORITY IdentifierAuthority; \
-  DWORD SubAuthority[n]; \
-} name = { SID_REVISION, n, {SECURITY_NT_AUTHORITY}, {sid}}
-
-/* default is non-const */
-#define ICONV_ARG2_TYPE const char **
-
-/* End */
diff --git a/src/OS/os.h-mips b/src/OS/os.h-mips
deleted file mode 100644 (file)
index 325e3a1..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/* Exim: OS-specific C header file for RiscOS4bsd */
-
-#define LOAD_AVG_NEEDS_ROOT
-#define HAVE_DEV_KMEM
-#define LOAD_AVG_TYPE   long
-#define LOAD_AVG_SYMBOL "_avenrun"
-#define KERNEL_PATH     "/unix"
-
-#define HAVE_MMAP
-#define HAVE_SYS_VFS_H
-
-#define F_FREESP     O_TRUNC
-#define EXIT_FAILURE 1
-#define EXIT_SUCCESS 0
-typedef struct flock flock_t;
-
-#define STRERROR_FROM_ERRLIST
-#define memmove(a, b, c) bcopy(b, a, c)
-
-extern char *strerror(int);
-extern int   sys_nerr;
-extern char *sys_errlist[];
-
-/* default is non-const */
-#define ICONV_ARG2_TYPE const char **
-
-/* End */
diff --git a/src/OS/unsupported/Makefile-AIX b/src/OS/unsupported/Makefile-AIX
new file mode 100644 (file)
index 0000000..fc32aa2
--- /dev/null
@@ -0,0 +1,28 @@
+# Exim: OS-specific make file for AIX
+# Written by Nick Waterman (nick@cimio.co.uk)
+# Modified by PH following a message from Mike Meredith
+
+# Note that the output of uname -m is probably not what Philip expected,
+# so you might end up with more build-AIX-random_number directories than
+# you expected if you have too many AIX boxes, but it seems to work... I
+# blame IBM.
+
+# Note that nowadays you have to pay extra for a cc compiler with AIX!
+
+CC=gcc
+
+# This needs to be in here rather than os.h-AIX because of regexp stuff.
+# basically strchr is a #define, which means "extern char *strchr()"
+# ruins things. __STR31__ seems to get around this by magic. The AIX
+# include files are quite a confusing maze.
+# Mike M says this is not necessary any more; possibly this is related to
+# using gcc. Commented out by PH.
+#CFLAGS = -D__STR31__
+
+CFLAGS = -mcpu=power4 -maix64 -O3
+
+# Needed for vfork() and vfork() only?
+
+LIBS = -lbsd -lm
+
+# End
diff --git a/src/OS/unsupported/Makefile-BSDI b/src/OS/unsupported/Makefile-BSDI
new file mode 100644 (file)
index 0000000..d56aa9b
--- /dev/null
@@ -0,0 +1,21 @@
+# Exim: OS-specific make file for BSDI aka BSD/OS. Its antique link editor
+# cannot handle the TextPop overriding.
+
+CFLAGS=-O
+CHOWN_COMMAND=/usr/sbin/chown
+
+HAVE_SA_LEN=YES
+
+X11=/usr/X11
+XINCLUDE=-I$(X11)/include
+XLFLAGS=-L$(X11)/lib
+X11_LD_LIB=$(X11)/lib
+
+LIBS_EXIMON=-lSM -lICE -lipc -lm
+EXIMON_TEXTPOP=
+
+EXIWHAT_PS_ARG=-ax
+EXIWHAT_EGREP_ARG='/exim( |$$)'
+EXIWHAT_KILL_SIGNAL=-USR1
+
+# End
diff --git a/src/OS/unsupported/Makefile-CYGWIN b/src/OS/unsupported/Makefile-CYGWIN
new file mode 100644 (file)
index 0000000..006e9fe
--- /dev/null
@@ -0,0 +1,113 @@
+# OS-specific file for Cygwin.
+
+# This file provided by Pierre A. Humblet <Pierre.Humblet@ieee.org>
+
+HAVE_IPV6 = yes
+HAVE_ICONV = yes
+# Use c99 to have %z 
+CFLAGS= -g -Wall -std=c99 -U __STRICT_ANSI__
+LIBS= -lcrypt -lresolv
+LIBS_EXIM= -liconv
+EXIWHAT_PS_ARG=-as
+EXIWHAT_KILL_SIGNAL=-USR1
+EXIWHAT_EGREP_ARG='/(EXIM|exim)[0-9. -]*$$'
+
+DBMLIB=-lgdbm
+USE_GDBM=YES
+
+# Some OS add a suffix to executables
+EXE = .exe
+
+# To add a resource file with an icon
+LIBS_EXIM +=../Local/exim_res.o
+
+# To produce a linker map
+#LIBS_EXIM+=-Wl,-Map,Exim.Map
+
+
+##################################################
+# The following is normally set in local/Makefile.
+# Makefile.cygwin provides defaults with which the
+# precompiled version is built
+##################################################
+
+BIN_DIRECTORY=/usr/bin
+CONFIGURE_FILE=/etc/exim.conf
+EXIM_USER=18   # This changes if user exim exists
+EXIM_GROUP=544 # Administrators
+SPOOL_DIRECTORY=/var/spool/exim
+LOG_FILE_PATH=/var/log/exim/exim_%s.log
+TIMEZONE_DEFAULT = ""
+
+AUTH_CRAM_MD5=yes
+AUTH_PLAINTEXT=yes
+AUTH_SPA=yes
+
+SUPPORT_TLS=yes
+TLS_LIBS=-lssl -lcrypto
+
+ROUTER_ACCEPT=yes
+ROUTER_DNSLOOKUP=yes
+ROUTER_IPLITERAL=yes
+ROUTER_MANUALROUTE=yes
+ROUTER_QUERYPROGRAM=yes
+ROUTER_REDIRECT=yes
+
+TRANSPORT_APPENDFILE=yes
+TRANSPORT_AUTOREPLY=yes
+TRANSPORT_PIPE=yes
+TRANSPORT_SMTP=yes
+
+SUPPORT_MAILDIR=yes
+SUPPORT_MAILSTORE=yes
+SUPPORT_MBX=yes
+
+LOOKUP_DBM=yes
+LOOKUP_LSEARCH=yes
+
+# LOOKUP_CDB=yes
+LOOKUP_DNSDB=yes
+LOOKUP_DSEARCH=yes
+LOOKUP_LDAP=yes
+# LOOKUP_MYSQL=yes
+# LOOKUP_NIS=yes
+# LOOKUP_NISPLUS=yes
+# LOOKUP_ORACLE=yes
+LOOKUP_PASSWD=yes
+# LOOKUP_PGSQL=yes
+# LOOKUP_WHOSON=yes
+
+LDAP_LIB_TYPE=OPENLDAP2
+LOOKUP_LIBS=-lldap -llber
+
+WITH_CONTENT_SCAN=yes
+
+# It is important to define these variables but the values are always overridden
+CONFIGURE_OWNER=18
+CONFIGURE_GROUP=544
+
+EXICYCLOG_MAX=10
+
+COMPRESS_COMMAND=/usr/bin/gzip
+COMPRESS_SUFFIX=gz
+ZCAT_COMMAND=/usr/bin/zcat
+
+# EXIM_PERL=perl.o
+
+# Comment the two lines below if you do not have PAM, e.g. from
+# ftp://ftp.uni-erlangen.de/pub/pc/gnuwin32/cygwin/porters/Humblet_Pierre_A
+SUPPORT_PAM=yes
+CFLAGS += -DINCLUDE_PAM -I ../pam -I ../../pam
+
+# All modes are in octal and must start with 0
+EXIMDB_DIRECTORY_MODE    = 01777
+EXIMDB_MODE              = 0666
+EXIMDB_LOCKFILE_MODE     = 0666
+INPUT_DIRECTORY_MODE  = 01777
+LOG_DIRECTORY_MODE    = 01777
+LOG_MODE              = 0666
+MSGLOG_DIRECTORY_MODE = 01777
+SPOOL_DIRECTORY_MODE  = 01777
+SPOOL_MODE            = 0600
+
+# End
diff --git a/src/OS/unsupported/Makefile-DGUX b/src/OS/unsupported/Makefile-DGUX
new file mode 100644 (file)
index 0000000..667c63f
--- /dev/null
@@ -0,0 +1,32 @@
+# Exim: OS-specific make file for DGUX
+#
+# Written by Ken Bailey (K.Bailey@rbgkew.org.uk) Feb 1998
+# on dgux R4.11MU04 generic AViiON mc88100
+# with no X
+
+# Minor tidies to remove settings that are actually the default,
+# in line with the style of other system files - PH.
+
+BASENAME_COMMAND=/bin/basename
+CHOWN_COMMAND=/bin/chown
+CHGRP_COMMAND=/bin/chgrp
+CHMOD_COMMAND=/bin/chmod
+
+# PERL
+# Perl is not necessary for running Exim itself, but some Perl utilities
+# are provided for processing the logs. Perl 5 is assumed.
+# DG ship perl version 4.036 in /bin/perl so need to use locally installed perl
+
+PERL_COMMAND=/usr/local/bin/perl
+
+# dg's version of gcc likes O2
+
+CFLAGS=-O2
+
+RANLIB=@true
+LIBS=-lsocket -lnsl -lm
+LIBRESOLV=-lresolv
+DBMLIB=-ldbm
+
+# End
+
diff --git a/src/OS/unsupported/Makefile-Darwin b/src/OS/unsupported/Makefile-Darwin
new file mode 100644 (file)
index 0000000..be0d952
--- /dev/null
@@ -0,0 +1,29 @@
+# Exim: OS-specific make file for Darwin (Mac OS X).
+
+CC=cc
+
+BASENAME_COMMAND=look_for_it
+CHOWN_COMMAND=/usr/sbin/chown
+CHMOD_COMMAND=/bin/chmod
+
+HAVE_SA_LEN=YES
+
+# Removed -DBIND_8_COMPAT for 4.61
+# CFLAGS=-O -no-cpp-precomp -DBIND_8_COMPAT
+
+CFLAGS=-O -no-cpp-precomp
+LIBRESOLV=-lresolv
+
+USE_DB = yes
+DBMLIB =
+
+X11=/usr/X11R6
+XINCLUDE=-I$(X11)/include
+XLFLAGS=-L$(X11)/lib
+X11_LD_LIB=$(X11)/lib
+
+EXIWHAT_PS_ARG=ax
+EXIWHAT_EGREP_ARG='/exim( |$$)'
+EXIWHAT_KILL_SIGNAL=-USR1
+
+# End
diff --git a/src/OS/unsupported/Makefile-DragonFly b/src/OS/unsupported/Makefile-DragonFly
new file mode 100644 (file)
index 0000000..c49c59f
--- /dev/null
@@ -0,0 +1,31 @@
+# Exim: OS-specific make file for DragonFly
+# There's no setting of CFLAGS here, to allow the system default
+# for "make" to be the default.
+
+CHOWN_COMMAND=/usr/sbin/chown
+CHMOD_COMMAND=/bin/chmod
+
+HAVE_SA_LEN=YES
+
+# crypt() is in a separate library
+LIBS=-lcrypt -lm
+
+# DragonFly always ships with Berkeley DB
+USE_DB=yes
+
+# X11 may be under /usr/pkg/xorg/ for example.
+# X11=/usr/X11R6
+X11=$(X11BASE)
+
+XINCLUDE=-I$(X11)/include
+XLFLAGS=-L$(X11)/lib
+XLFLAGS+=-Wl,-rpath,${X11BASE}/lib
+X11_LD_LIB=$(X11)/lib
+
+EXIWHAT_PS_ARG=-ax
+EXIWHAT_EGREP_ARG='/exim( |$$)'
+EXIWHAT_MULTIKILL_CMD='killall -m'
+EXIWHAT_MULTIKILL_ARG='^exim($$|-[0-9.]+-[0-9]+$$)'
+EXIWHAT_KILL_SIGNAL=-USR1
+
+# End
diff --git a/src/OS/unsupported/Makefile-GNU b/src/OS/unsupported/Makefile-GNU
new file mode 100644 (file)
index 0000000..e464341
--- /dev/null
@@ -0,0 +1,29 @@
+# Exim: OS-specific make file for GNU and variants.
+
+HAVE_ICONV=yes
+
+BASENAME_COMMAND=look_for_it
+CHOWN_COMMAND=look_for_it
+CHGRP_COMMAND=look_for_it
+CHMOD_COMMAND=look_for_it
+
+CFLAGS ?= -O -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
+
+DBMLIB = -ldb
+USE_DB = yes
+
+LIBS = -lnsl -lcrypt -lm
+LIBRESOLV = -lresolv
+
+X11=/usr/X11R6
+XINCLUDE=-I$(X11)/include
+XLFLAGS=-L$(X11)/lib
+X11_LD_LIB=$(X11)/lib
+
+EXIWHAT_PS_ARG=ax
+EXIWHAT_EGREP_ARG='/exim( |$$)'
+EXIWHAT_MULTIKILL_CMD=killall
+EXIWHAT_MULTIKILL_ARG=exim
+EXIWHAT_KILL_SIGNAL=-USR1
+
+# End
diff --git a/src/OS/unsupported/Makefile-GNUkFreeBSD b/src/OS/unsupported/Makefile-GNUkFreeBSD
new file mode 100644 (file)
index 0000000..8019281
--- /dev/null
@@ -0,0 +1,29 @@
+# Exim: OS-specific make file for GNU and variants.
+
+HAVE_ICONV=yes
+
+BASENAME_COMMAND=look_for_it
+CHOWN_COMMAND=look_for_it
+CHGRP_COMMAND=look_for_it
+CHMOD_COMMAND=look_for_it
+
+CFLAGS ?= -O -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
+
+DBMLIB = -ldb
+USE_DB = yes
+
+LIBS = -lnsl -lcrypt -lm
+LIBRESOLV = -lresolv
+
+X11=/usr/X11R6
+XINCLUDE=-I$(X11)/include
+XLFLAGS=-L$(X11)/lib
+X11_LD_LIB=$(X11)/lib
+
+EXIWHAT_PS_ARG=ax
+EXIWHAT_EGREP_ARG='/exim( |$$)'
+EXIWHAT_MULTIKILL_CMD=killall
+EXIWHAT_MULTIKILL_ARG=exim4
+EXIWHAT_KILL_SIGNAL=-USR1
+
+# End
diff --git a/src/OS/unsupported/Makefile-GNUkNetBSD b/src/OS/unsupported/Makefile-GNUkNetBSD
new file mode 100644 (file)
index 0000000..8019281
--- /dev/null
@@ -0,0 +1,29 @@
+# Exim: OS-specific make file for GNU and variants.
+
+HAVE_ICONV=yes
+
+BASENAME_COMMAND=look_for_it
+CHOWN_COMMAND=look_for_it
+CHGRP_COMMAND=look_for_it
+CHMOD_COMMAND=look_for_it
+
+CFLAGS ?= -O -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
+
+DBMLIB = -ldb
+USE_DB = yes
+
+LIBS = -lnsl -lcrypt -lm
+LIBRESOLV = -lresolv
+
+X11=/usr/X11R6
+XINCLUDE=-I$(X11)/include
+XLFLAGS=-L$(X11)/lib
+X11_LD_LIB=$(X11)/lib
+
+EXIWHAT_PS_ARG=ax
+EXIWHAT_EGREP_ARG='/exim( |$$)'
+EXIWHAT_MULTIKILL_CMD=killall
+EXIWHAT_MULTIKILL_ARG=exim4
+EXIWHAT_KILL_SIGNAL=-USR1
+
+# End
diff --git a/src/OS/unsupported/Makefile-HI-OSF b/src/OS/unsupported/Makefile-HI-OSF
new file mode 100644 (file)
index 0000000..da3d487
--- /dev/null
@@ -0,0 +1,8 @@
+# Exim: OS-specific make file for HI-OSF/1-MJ and HI-UX/MPP
+
+CC=cc
+CFLAGS=-O
+RANLIB=@true
+EXIWHAT_EGREP_ARG='/exim( |$$)'
+
+# End
diff --git a/src/OS/unsupported/Makefile-HI-UX b/src/OS/unsupported/Makefile-HI-UX
new file mode 100644 (file)
index 0000000..870ee84
--- /dev/null
@@ -0,0 +1,12 @@
+# Exim: OS-specific make file for HI-UX
+
+CC=cc -Aa -D_HIUX_SOURCE
+HAVE_SETRESUID=YES
+HAVE_SETEUID=NO
+XINCLUDE=-I/usr/include/X11R5
+XLFLAGS=-L/usr/lib/X11R5
+DBMLIB = -lndbm
+NEED_H_ERRNO=1
+RANLIB=@true
+
+# End
diff --git a/src/OS/unsupported/Makefile-HP-UX b/src/OS/unsupported/Makefile-HP-UX
new file mode 100644 (file)
index 0000000..ea35144
--- /dev/null
@@ -0,0 +1,27 @@
+# Exim: OS-specific make file for HP-UX later than 9
+
+# HP ANSI C compiler
+#CC=cc
+#CFLAGS=+O2 +Onolimit -z -D_XOPEN_SOURCE_EXTENDED
+# Users of the A.06.00 compiler might need to use +O1 rather than +O2 as
+# there have been some problems reported with this compiler with +O2 set.
+
+# gcc
+CFLAGS=-O -D_XOPEN_SOURCE_EXTENDED
+LDFLAGS=-Wl,-z
+LIBS=-lm
+
+BASENAME_COMMAND=/bin/basename
+HAVE_ICONV=yes
+HAVE_SETRESUID=YES
+HAVE_SETEUID=NO
+XINCLUDE=-I/usr/include/X11R6 -I/usr/contrib/X11R6/include
+XLFLAGS=-L/usr/lib/X11R6 -L/usr/contrib/X11R6/lib
+X11_LD_LIB=/usr/contrib/X11R6/lib
+EXIMON_TEXTPOP=
+DBMLIB=-lndbm
+RANLIB=@true
+
+OS_C_INCLUDES=setenv.c
+
+# End
diff --git a/src/OS/unsupported/Makefile-HP-UX-9 b/src/OS/unsupported/Makefile-HP-UX-9
new file mode 100644 (file)
index 0000000..1530009
--- /dev/null
@@ -0,0 +1,15 @@
+# Exim: OS-specific make file for HP-UX 9
+
+CFLAGS=-O
+BASENAME_COMMAND=/bin/basename
+HAVE_ICONV=yes
+HAVE_SETRESUID=YES
+HAVE_SETEUID=NO
+XINCLUDE=-I/usr/include/X11R5
+XLFLAGS=-L/usr/lib/X11R5 -L/usr/contrib/X11R5/lib
+X11_LD_LIB=/usr/contrib/X11R5/lib
+EXIMON_TEXTPOP=
+DBMLIB=-lndbm
+RANLIB=@true
+
+# End
diff --git a/src/OS/unsupported/Makefile-IRIX b/src/OS/unsupported/Makefile-IRIX
new file mode 100644 (file)
index 0000000..7b95783
--- /dev/null
@@ -0,0 +1,12 @@
+# Exim: OS-specific make file for IRIX
+
+HAVE_ICONV=yes
+BASENAME_COMMAND=/sbin/basename
+HOSTNAME_COMMAND=/usr/bsd/hostname
+CFLAGS=-OPT:Olimit=1500
+LIBS=-lmld -lm
+XINCLUDE=-I/usr/include/X11
+vfork=fork
+RANLIB=@true
+
+# End
diff --git a/src/OS/unsupported/Makefile-IRIX6 b/src/OS/unsupported/Makefile-IRIX6
new file mode 100644 (file)
index 0000000..be01138
--- /dev/null
@@ -0,0 +1,13 @@
+# Exim: OS-specific make file for IRIX6 on 64-bit systems
+
+HAVE_ICONV=yes
+HOSTNAME_COMMAND=/usr/bsd/hostname
+CFLAGS=-O2 -n32 -OPT:Olimit=4000
+LFLAGS=-n32
+LIBS=-lelf -lm
+XINCLUDE=-I/usr/include/X11
+XLFLAGS=
+vfork=fork
+RANLIB=@true
+
+# End
diff --git a/src/OS/unsupported/Makefile-IRIX632 b/src/OS/unsupported/Makefile-IRIX632
new file mode 100644 (file)
index 0000000..b567fc6
--- /dev/null
@@ -0,0 +1,16 @@
+# Exim: OS-specific make file for IRIX 6 on 32-bit systems.
+# There seems to be some variation. The commented settings show
+# some alternatives.
+
+HAVE_ICONV=yes
+HOSTNAME_COMMAND=/usr/bsd/hostname
+#CFLAGS=-OPT:Olimit=1500 -32 -mips2
+CFLAGS=-32
+LFLAGS=-32
+#LIBS=-lmld
+LIBS=-lelf -lm
+XINCLUDE=-I/usr/include/X11
+vfork=fork
+RANLIB=@true
+
+# End
diff --git a/src/OS/unsupported/Makefile-IRIX65 b/src/OS/unsupported/Makefile-IRIX65
new file mode 100644 (file)
index 0000000..50e7745
--- /dev/null
@@ -0,0 +1,16 @@
+# Exim: OS-specific make file for IRIX 6.5
+
+HAVE_ICONV=yes
+HOSTNAME_COMMAND=/usr/bsd/hostname
+CC=cc
+CFLAGS=-O2 -OPT:Olimit=0
+# CFLAGS=-O2 # override with this (in your Local/Makefile) if using gcc
+LFLAGS=-Wl,-LD_MSG:off=85
+LFLAGS=
+# nlist has moved from libmld to libelf
+LIBS=-lelf -lm
+XINCLUDE=-I/usr/include/X11
+vfork=fork
+RANLIB=@true
+
+# End
diff --git a/src/OS/unsupported/Makefile-NetBSD b/src/OS/unsupported/Makefile-NetBSD
new file mode 100644 (file)
index 0000000..35d03a2
--- /dev/null
@@ -0,0 +1,27 @@
+# Exim: OS-specific make file for NetBSD (ELF object format)
+
+CHOWN_COMMAND=/usr/sbin/chown
+CHMOD_COMMAND=/bin/chmod
+
+CFLAGS ?= -O2
+
+HAVE_SA_LEN=YES
+HAVE_IPV6=YES
+LIBS=-lcrypt -lm
+
+X11=/usr/X11R6
+XINCLUDE=-I$(X11)/include
+XLFLAGS=-L$(X11)/lib
+X11_LD_LIB=$(X11)/lib
+
+EXIWHAT_PS_ARG=-ax
+EXIWHAT_EGREP_ARG='/exim( |$$)'
+EXIWHAT_KILL_SIGNAL=-USR1
+
+# NetBSD always ships with Berkeley DB
+USE_DB=yes
+
+# NetBSD ELF linker needs a -R flag.
+XLFLAGS+=-Wl,-R$(X11)/lib/
+
+# End
diff --git a/src/OS/unsupported/Makefile-NetBSD-a.out b/src/OS/unsupported/Makefile-NetBSD-a.out
new file mode 100644 (file)
index 0000000..e210efd
--- /dev/null
@@ -0,0 +1,24 @@
+# Exim: OS-specific make file for NetBSD (a.out/COFF object format)
+
+CHOWN_COMMAND=/usr/sbin/chown
+CHMOD_COMMAND=/bin/chmod
+
+CFLAGS ?= -O2
+
+HAVE_SA_LEN=YES
+HAVE_IPV6=YES
+LIBS=-lcrypt -lm
+
+X11=/usr/X11R6
+XINCLUDE=-I$(X11)/include
+XLFLAGS=-L$(X11)/lib
+X11_LD_LIB=$(X11)/lib
+
+EXIWHAT_PS_ARG=-ax
+EXIWHAT_EGREP_ARG='/exim( |$$)'
+EXIWHAT_KILL_SIGNAL=-USR1
+
+# NetBSD always ships with Berkeley DB
+USE_DB=yes
+
+# End
diff --git a/src/OS/unsupported/Makefile-OSF1 b/src/OS/unsupported/Makefile-OSF1
new file mode 100644 (file)
index 0000000..811ca07
--- /dev/null
@@ -0,0 +1,10 @@
+# Exim: OS-specific make file for OSF1
+
+CFLAGS=-O
+LIBS=-liconv -lm
+HAVE_CRYPT16=yes
+HAVE_ICONV=yes
+HOSTNAME_COMMAND=/usr/bin/hostname
+EXIWHAT_EGREP_ARG='/exim( |$$)'
+
+# End
diff --git a/src/OS/unsupported/Makefile-OpenUNIX b/src/OS/unsupported/Makefile-OpenUNIX
new file mode 100644 (file)
index 0000000..e4d7261
--- /dev/null
@@ -0,0 +1,17 @@
+# Exim: OS-specific make file for OpenUNIX
+
+CC=/usr/bin/cc
+CFLAGS=-O -I/usr/local/include
+LFLAGS=-L/usr/local/lib
+
+LIBS=-lsocket -lnsl -lelf -lgen -lresolv -lm
+EXTRALIBS_EXIMON=-lICE -lSM
+
+RANLIB=@true
+ERRNO_QUOTA=0
+
+X11=/usr/lib/X11
+XINCLUDE=-I/usr/include/X11
+XLFLAGS=-L/usr/lib -L$(X11)/lib
+
+# End
diff --git a/src/OS/unsupported/Makefile-QNX b/src/OS/unsupported/Makefile-QNX
new file mode 100644 (file)
index 0000000..3cf81c4
--- /dev/null
@@ -0,0 +1,30 @@
+# Exim: OS-specific makefile for QNX
+
+BASENAME_COMMAND=/bin/basename
+MAKE_SHELL=/usr/bin/bash
+
+CHOWN_COMMAND=/bin/chown
+CHGRP_COMMAND=/bin/chgrp
+CHMOD_COMMAND=/bin/chmod
+HOSTNAME_COMMAND=/bin/hostname
+MV_COMMAND=/bin/mv
+PERL_COMMAND=/usr/bin/perl
+RM_COMMAND=/bin/rm
+
+AR=ar -rc
+
+CC=cc
+CFLAGS=-Otax
+LIBIDENTCFLAGS=
+
+RANLIB=@true
+DBMLIB=-ldb
+USE_DB=yes
+LIBS=-lsocket -lm
+
+X11=/usr/X11R6
+XINCLUDE=-I$(X11)/include
+XLFLAGS=-L$(X11)/lib
+X11_LD_LIB=$(X11)/lib
+
+# End
diff --git a/src/OS/unsupported/Makefile-SCO b/src/OS/unsupported/Makefile-SCO
new file mode 100644 (file)
index 0000000..baa61d8
--- /dev/null
@@ -0,0 +1,28 @@
+# Exim: OS-specific make file for SCO
+
+# It was reported that some versions of gcc (e.g. 2.8.1) require this to be
+# CFLAGS=-melf
+
+CFLAGS=-b elf
+
+RANLIB=@true
+DBMLIB=-lndbm
+ERRNO_QUOTA=0
+LIBS=-lsocket -lm
+HAVE_ICONV=yes
+
+X11=/usr/lib/X11
+XINCLUDE=-I/usr/include/X11
+XLFLAGS=-L/usr/lib -L$(X11)/lib
+X11_LD_LIB=$(X11)/lib
+
+# Changes from Frank Bernhardt (30/09/04)
+
+BASENAME_COMMAND=/bin/basename
+CHOWN_COMMAND=/bin/chown
+CHGRP_COMMAND=/bin/chgrp
+CHMOD_COMMAND=/bin/chmod
+HOSTNAME_COMMAND=/usr/bin/hostname
+TOUCH_COMMAND=/bin/touch
+
+# End
diff --git a/src/OS/unsupported/Makefile-SCO_SV b/src/OS/unsupported/Makefile-SCO_SV
new file mode 100644 (file)
index 0000000..249b81a
--- /dev/null
@@ -0,0 +1,34 @@
+# Exim: OS-specific make file for SCO_SV release 5 (tested on 5.0.5 & 5.0.5)
+#       (see the UNIX_SV files for SCO 4.2)
+# Supplied by: Tony Earnshaw <tonye@ilion.nl>
+
+# Note that 'gcc -melf -m486' applies to gcc 2.7.2 and higher;
+# 2.7.1 and SCO's SDK need '-belf'.
+
+# Removed -lwrap (PH 27/7/00) because not all systems have it
+
+CFLAGS=-melf -O3 -m486
+LFLAGS=-L/lib -L/usr/lib -L/usr/local/lib
+LIBS=-ltinfo -lsocket -lm
+
+HAVE_ICONV=yes
+
+RANLIB=@true
+DBMLIB=-lndbm
+ERRNO_QUOTA=0
+
+X11=/usr/lib/X11
+XINCLUDE=-I/usr/include/X11
+XLFLAGS=-L/usr/lib -L$(X11)/lib
+X11_LD_LIB=$(X11)/lib
+
+# Changes from Frank Bernhardt (30/9/04)
+
+BASENAME_COMMAND=/bin/basename
+CHOWN_COMMAND=/bin/chown
+CHGRP_COMMAND=/bin/chgrp
+CHMOD_COMMAND=/bin/chmod
+HOSTNAME_COMMAND=/usr/bin/hostname
+TOUCH_COMMAND=/bin/touch
+
+# End
diff --git a/src/OS/unsupported/Makefile-SunOS4 b/src/OS/unsupported/Makefile-SunOS4
new file mode 100644 (file)
index 0000000..c876998
--- /dev/null
@@ -0,0 +1,16 @@
+# Exim: OS-specific make file for SunOS4
+
+CFLAGS=-O
+
+CHOWN_COMMAND=/usr/etc/chown
+HOSTNAME_COMMAND=/usr/bin/hostname
+EXIT_FAILURE=1
+EXIT_SUCCESS=0
+LIBRESOLV=-lresolv
+XINCLUDE=-I/usr/include/X11
+
+EXIWHAT_PS_ARG=-ax
+EXIWHAT_EGREP_ARG='/exim( |$$)'
+EXIWHAT_KILL_SIGNAL=-30
+
+# End
diff --git a/src/OS/unsupported/Makefile-SunOS5-hal b/src/OS/unsupported/Makefile-SunOS5-hal
new file mode 100644 (file)
index 0000000..05ea893
--- /dev/null
@@ -0,0 +1,18 @@
+# Exim: OS-specific make file for SunOS5 on a HAL
+
+# Note: The HAL runs a standard SunOS5 except that it has a 64 bit C
+# compiler called hcc.  To make things work pass the -KV7 flag to force
+# 32bit compilation - this is necessary to interwork with some libraries.
+
+CC=hcc
+CFLAGS=-O -KV7
+LIBIDENTCFLAGS="-KV7 -O -DHAVE_ANSIHEADERS"
+LIBIDENTNAME=sunos5
+RANLIB=@true
+LIBS=-lsocket -lnsl -lkstat -lm
+LIBRESOLV=-lresolv
+X11=/usr/X11R6
+XINCLUDE=-I$(X11)/include
+XLFLAGS=-L$(X11)/lib -R$(X11)/lib
+
+# End
diff --git a/src/OS/unsupported/Makefile-ULTRIX b/src/OS/unsupported/Makefile-ULTRIX
new file mode 100644 (file)
index 0000000..9e912b3
--- /dev/null
@@ -0,0 +1,18 @@
+# Exim: OS-specific make file for Ultrix
+
+MAKE_SHELL=/usr/bin/sh5
+
+CFLAGS=-O
+
+# This can either be /usr/include/X11 or /usr/include/mit depending on
+# the particular version of ULTRIX.
+
+XINCLUDE=-I/usr/include/X11 -I/usr/include/mit
+
+DBMLIB=-lgdbm
+
+EXIWHAT_PS_ARG=-ax
+EXIWHAT_EGREP_ARG='/exim( |$$)'
+EXIWHAT_KILL_SIGNAL=-USR1
+
+# End
diff --git a/src/OS/unsupported/Makefile-UNIX_SV b/src/OS/unsupported/Makefile-UNIX_SV
new file mode 100644 (file)
index 0000000..bfcfae1
--- /dev/null
@@ -0,0 +1,24 @@
+# Exim: OS-specific make file for SCO SVR4.2MP (and maybe Unixware)
+#
+#  *** Note that for SCO 5 the configuration file is called SCO_SV,
+#  *** and that Unixware7 has its own configuration. This is an old
+#  *** file that is retained for compatibility.
+#
+# Note that SCO does not include dbm/ndbm with their standard compiler
+# (it is available with /usr/ucb/cc, but that has bugs of its own). You
+# should install gcc and gdbm, then execute 'make install-compat' in the
+# gdbm source directory.
+
+CC=gcc -I/usr/local/include
+CFLAGS=-O
+
+RANLIB=@true
+DBMLIB=-lgdbm -L/usr/local/lib
+ERRNO_QUOTA=0
+LIBS=-lsocket -lelf -lgen -lnsl -lresolv -lm
+
+X11=/usr/lib/X11
+XINCLUDE=-I/usr/include/X11
+XLFLAGS=-L/usr/lib -L$(X11)/lib
+
+# End
diff --git a/src/OS/unsupported/Makefile-USG b/src/OS/unsupported/Makefile-USG
new file mode 100644 (file)
index 0000000..753a2d7
--- /dev/null
@@ -0,0 +1,33 @@
+# Exim: OS-specific make file for Unixware 2.x
+#
+# Note that Unixware does not include db/dbm/ndbm with their standard compiler
+# (it is available with /usr/ucb/cc, but that has bugs of its own). You
+# should install gcc and Berkeley DB (or another dbm library if you really
+# insist). If you use a different dbm library you will need to override
+# DBMLIB below.
+#
+# DB 1.85 and 2.x can be found at http://www.sleepycat.com/.
+# They have different characteristics. See the discussion of dbm libraries
+# in doc/dbm.discuss.txt in the Exim distribution.
+#
+# DB needs to be compiled with gcc and you need a 'cc' in your path
+# before the Unixware CC to compile it.
+#
+# Don't bother even starting to install exim on Unixware unless
+# you have installed gcc and use it for everything.
+
+CC=gcc -I/usr/local/include
+CFLAGS=-O
+
+RANLIB=@true
+DBMLIB=-ldb -L/usr/local/lib
+USE_DB=YES
+ERRNO_QUOTA=0
+LIBS=-lsocket -lelf -lgen -lnsl -lresolv -lm
+
+X11=/usr/lib/X11
+XINCLUDE=-I/usr/include/X11
+XLFLAGS=-L/usr/lib -L$(X11)/lib
+X11_LD_LIB=$(X11)/lib
+
+# End
diff --git a/src/OS/unsupported/Makefile-Unixware7 b/src/OS/unsupported/Makefile-Unixware7
new file mode 100644 (file)
index 0000000..88a8838
--- /dev/null
@@ -0,0 +1,32 @@
+# Exim: OS-specific make file for Unixware7
+# Based on information from James FitzGibbon <james@ehlo.com>
+
+# If you want to use libbind, you need to
+#     add -I/usr/local/bind/include to CFLAGS
+#     add -L/usr/local/bind/lib to LFLAGS
+#     remove -lresolv from LIBS
+#     add LOOKUP_LIBS=-lbind
+# The new settings should go in your Local/Makefile rather than here; then
+# they will be usable for subsequent Exim releases.
+
+CC=/usr/bin/cc
+CFLAGS=-O -I/usr/local/include
+LFLAGS=-L/usr/local/lib
+
+HAVE_ICONV=yes
+
+LIBS=-lsocket -lnsl -lelf -lgen -lresolv -lm
+
+# Removed on the advice of Larry Rosenman
+# EXTRALIBS=-lwrap
+
+EXTRALIBS_EXIMON=-lICE -lSM
+
+RANLIB=@true
+ERRNO_QUOTA=0
+
+X11=/usr/lib/X11
+XINCLUDE=-I/usr/include/X11
+XLFLAGS=-L/usr/lib -L$(X11)/lib
+
+# End
diff --git a/src/OS/unsupported/Makefile-mips b/src/OS/unsupported/Makefile-mips
new file mode 100644 (file)
index 0000000..ff33139
--- /dev/null
@@ -0,0 +1,16 @@
+# Exim: OS-specific make file for RiscOS4bsd
+
+HOSTNAME_COMMAND=/usr/ucb/hostname
+EXIT_FAILURE=1
+EXIT_SUCCESS=0
+LIBRESOLV=-lresolv
+LIBS=-liberty -lm
+XINCLUDE=-I/usr/X11R6/include
+
+CFLAGS=-O
+
+EXIWHAT_PS_ARG=-ax
+EXIWHAT_EGREP_ARG='/exim( |$$)'
+EXIWHAT_KILL_SIGNAL=-30
+
+# End
diff --git a/src/OS/unsupported/README b/src/OS/unsupported/README
new file mode 100644 (file)
index 0000000..73790ae
--- /dev/null
@@ -0,0 +1,14 @@
+Files in this directory are historical.  They may have worked once but the
+project has no assurance that they still do.
+
+If you need to use one for a build for your platform, copy it up one directory
+level first.  We'll reinstate it given a current version and evidence of testing.
+For the latter please look into the project regression testsuite, and please
+consider operating a buildfarm animal in the long term (it runs the testsuite).
+
+The buildfarm status page is:
+  https://buildfarm.exim.org/cgi-bin/show_status.pl
+There's a "register" link there with a link to how-to instructions.  Please do
+monitor the status of your animal on an ongoing basis.  The exim-users or
+exim-dev mailinglist are good places to ask for help and to discuss any regressions
+seen in test runs.  There is also the #exim IRC channel on Freenode.
diff --git a/src/OS/unsupported/os.c-BSDI b/src/OS/unsupported/os.c-BSDI
new file mode 100644 (file)
index 0000000..03a7a1c
--- /dev/null
@@ -0,0 +1,19 @@
+/*************************************************
+*     Exim - an Internet mail transport agent    *
+*************************************************/
+
+/* Copyright (c) 2016 Heiko Schlittermann <hs@schlittermann.de> */
+/* See the file NOTICE for conditions of use and distribution. */
+
+/* BSDI-specific code. This is concatenated onto the generic
+src/os.c file. */
+
+#ifndef OS_UNSETENV
+#define OS_UNSETENV
+
+int
+os_unsetenv(const uschar * name)
+{
+unsetenv(CS name);
+return 0;
+}
diff --git a/src/OS/unsupported/os.c-GNU b/src/OS/unsupported/os.c-GNU
new file mode 100644 (file)
index 0000000..e5d6ff6
--- /dev/null
@@ -0,0 +1,55 @@
+/*************************************************
+*     Exim - an Internet mail transport agent    *
+*************************************************/
+
+/* See the file NOTICE for conditions of use and distribution. */
+
+/* GNU-specific code. This is concatenated onto the generic src/os.c file.
+GNU/Hurd has approximately the same way to determine the load average as NeXT,
+so a variant of this could also be in the generic os.c file. See the GNU EMacs
+getloadavg.c file, from which this snippet was derived. getloadavg.c from Emacs
+is copyrighted by the FSF under the terms of the GPLv2 or any later version.
+Changes are hereby placed under the same license, as requested by the GPL. */
+
+#ifndef OS_LOAD_AVERAGE
+#define OS_LOAD_AVERAGE
+
+#include <mach.h>
+
+static processor_set_t default_set;
+static int getloadavg_initialized;
+
+int
+os_getloadavg (void)
+{
+host_t host;
+struct processor_set_basic_info info;
+unsigned info_count;
+
+if (!getloadavg_initialized)
+  {
+  if (processor_set_default (mach_host_self(), &default_set) == KERN_SUCCESS)
+    getloadavg_initialized = 1;
+  }
+
+if (getloadavg_initialized)
+  {
+  info_count = PROCESSOR_SET_BASIC_INFO_COUNT;
+  if (processor_set_info(default_set, PROCESSOR_SET_BASIC_INFO, &host,
+       (processor_set_info_t)&info, &info_count) != KERN_SUCCESS)
+    getloadavg_initialized = 0;
+  else
+    {
+    #if LOAD_SCALE == 1000
+    return info.load_average;
+    #else
+    return (int) (((double) info.load_average * 1000) / LOAD_SCALE));
+    #endif
+    }
+  }
+
+return -1;
+}
+#endif  /* OS_LOAD_AVERAGE */
+
+/* End of os.c-GNU */
diff --git a/src/OS/unsupported/os.c-HI-OSF b/src/OS/unsupported/os.c-HI-OSF
new file mode 100644 (file)
index 0000000..5e3d336
--- /dev/null
@@ -0,0 +1,35 @@
+/*************************************************
+*     Exim - an Internet mail transport agent    *
+*************************************************/
+
+/* Copyright (c) University of Cambridge 2001 */
+/* See the file NOTICE for conditions of use and distribution. */
+
+/* HI-OSF-specific code. This is concatenated onto the generic
+src/os.c file. OSF has an apparently unique way of getting the
+load average, so we provide a unique function here, and define
+OS_LOAD_AVERAGE to stop src/os.c trying to provide the function. */
+
+#ifndef OS_LOAD_AVERAGE
+#define OS_LOAD_AVERAGE
+
+#include <sys/table.h>
+
+int
+os_getloadavg(void)
+{
+double avg;
+struct tbl_loadavg load_avg;
+
+table (TBL_LOADAVG, 0, &load_avg, 1, sizeof (load_avg));
+
+avg = (load_avg.tl_lscale == 0)?
+  load_avg.tl_avenrun.d[0] :
+  (load_avg.tl_avenrun.l[0] / (double)load_avg.tl_lscale);
+
+return (int)(avg * 1000.0);
+}
+
+#endif  /* OS_LOAD_AVERAGE */
+
+/* End of os.c-HI-OSF */
diff --git a/src/OS/unsupported/os.c-HP-UX b/src/OS/unsupported/os.c-HP-UX
new file mode 100644 (file)
index 0000000..fdd8708
--- /dev/null
@@ -0,0 +1,16 @@
+/*************************************************
+*     Exim - an Internet mail transport agent    *
+*************************************************/
+
+/* Copyright (c) University of Cambridge 2016 */
+/* Copyright (c) Jeremy Harris 2016 */
+/* See the file NOTICE for conditions of use and distribution. */
+
+/* HP-UX-specific code. This is concatenated onto the generic
+src/os.c file. */
+
+#ifndef COMPILE_UTILITY
+# include "setenv.c"
+#endif
+
+/* End of os.c-SunHP-UX */
diff --git a/src/OS/unsupported/os.c-IRIX b/src/OS/unsupported/os.c-IRIX
new file mode 100644 (file)
index 0000000..1f6b0e1
--- /dev/null
@@ -0,0 +1,118 @@
+/*************************************************
+*     Exim - an Internet mail transport agent    *
+*************************************************/
+
+/* Copyright (c) University of Cambridge 2001 */
+/* See the file NOTICE for conditions of use and distribution. */
+
+/* Irix-specific code. This is concatenated onto the generic src/os.c file.
+Irix has a unique way of finding all the network interfaces, so we provide a
+unique function here, and define FIND_RUNNING_INTERFACES to stop src/os.c
+trying to provide the function. The macro may be set initially anyway, when
+compiling os. for utilities that don't want this function. */
+
+#ifndef FIND_RUNNING_INTERFACES
+#define FIND_RUNNING_INTERFACES
+
+/* This is the special form of the function using sysctl() which is the only
+form that returns all the aliases on IRIX systems. This code has its origins
+in a sample program that came from within SGI. */
+
+#include <sys/sysctl.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/soioctl.h>
+#include <net/route.h>
+
+#define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(__uint64_t) -1))) \
+                    : sizeof(__uint64_t))
+#ifdef _HAVE_SA_LEN
+#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
+#else
+#define ADVANCE(x, n) (x += ROUNDUP(_FAKE_SA_LEN_DST(n)))
+#endif
+
+
+ip_address_item *
+os_find_running_interfaces(void)
+{
+ip_address_item *yield = NULL;
+ip_address_item *last = NULL;
+ip_address_item *next;
+
+size_t needed;
+int mib[6];
+char *buf, *nextaddr, *lim;
+register struct if_msghdr *ifm;
+
+mib[0] = CTL_NET;
+mib[1] = PF_ROUTE;
+mib[2] = 0;
+mib[3] = 0;
+mib[4] = NET_RT_IFLIST;
+mib[5] = 0;
+
+/* Get an estimate of the amount of store needed, then get the store and
+get the data into it. Any error causes a panic death. */
+
+if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+  log_write(0, LOG_PANIC_DIE, "iflist-sysctl-estimate failed: %s",
+    strerror(errno));
+
+buf = store_get(needed);
+
+if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
+  log_write(0, LOG_PANIC_DIE, "sysctl of ifnet list failed: %s",
+    strerror(errno));
+
+/* Now fish out the data for each interface */
+
+lim  = buf + needed;
+for (nextaddr = buf; nextaddr < lim; nextaddr += ifm->ifm_msglen)
+  {
+  ifm = (struct if_msghdr *)nextaddr;
+
+  if (ifm->ifm_type != RTM_IFINFO)
+    {
+    struct ifa_msghdr *ifam = (struct ifa_msghdr *)ifm;
+    struct sockaddr_in *mask = NULL, *addr = NULL;
+
+    if ((ifam->ifam_addrs & RTA_NETMASK) != 0)
+      mask = (struct sockaddr_in *)(ifam + 1);
+
+    if ((ifam->ifam_addrs & RTA_IFA) != 0)
+      {
+      char *cp = CS mask;
+      struct sockaddr *sa = (struct sockaddr *)mask;
+      ADVANCE(cp, sa);
+      addr = (struct sockaddr_in *)cp;
+      }
+
+    /* Create a data block for the address, fill in the data, and put it on
+    the chain. This data has to survive for ever, so use malloc. */
+
+    if (addr != NULL)
+      {
+      next = store_malloc(sizeof(ip_address_item));
+      next->next = NULL;
+      next->port = 0;
+      (void)host_ntoa(-1, addr, next->address, NULL);
+
+      if (yield == NULL) yield = last = next; else
+        {
+        last->next = next;
+        last = next;
+        }
+
+      DEBUG(D_interface) debug_printf("Actual local interface address is %s\n",
+        last->address);
+      }
+    }
+  }
+
+return yield;
+}
+
+#endif  /* FIND_RUNNING_INTERFACES */
+
+/* End of os.c-IRIX */
diff --git a/src/OS/unsupported/os.c-IRIX6 b/src/OS/unsupported/os.c-IRIX6
new file mode 100644 (file)
index 0000000..1f6b0e1
--- /dev/null
@@ -0,0 +1,118 @@
+/*************************************************
+*     Exim - an Internet mail transport agent    *
+*************************************************/
+
+/* Copyright (c) University of Cambridge 2001 */
+/* See the file NOTICE for conditions of use and distribution. */
+
+/* Irix-specific code. This is concatenated onto the generic src/os.c file.
+Irix has a unique way of finding all the network interfaces, so we provide a
+unique function here, and define FIND_RUNNING_INTERFACES to stop src/os.c
+trying to provide the function. The macro may be set initially anyway, when
+compiling os. for utilities that don't want this function. */
+
+#ifndef FIND_RUNNING_INTERFACES
+#define FIND_RUNNING_INTERFACES
+
+/* This is the special form of the function using sysctl() which is the only
+form that returns all the aliases on IRIX systems. This code has its origins
+in a sample program that came from within SGI. */
+
+#include <sys/sysctl.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/soioctl.h>
+#include <net/route.h>
+
+#define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(__uint64_t) -1))) \
+                    : sizeof(__uint64_t))
+#ifdef _HAVE_SA_LEN
+#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
+#else
+#define ADVANCE(x, n) (x += ROUNDUP(_FAKE_SA_LEN_DST(n)))
+#endif
+
+
+ip_address_item *
+os_find_running_interfaces(void)
+{
+ip_address_item *yield = NULL;
+ip_address_item *last = NULL;
+ip_address_item *next;
+
+size_t needed;
+int mib[6];
+char *buf, *nextaddr, *lim;
+register struct if_msghdr *ifm;
+
+mib[0] = CTL_NET;
+mib[1] = PF_ROUTE;
+mib[2] = 0;
+mib[3] = 0;
+mib[4] = NET_RT_IFLIST;
+mib[5] = 0;
+
+/* Get an estimate of the amount of store needed, then get the store and
+get the data into it. Any error causes a panic death. */
+
+if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+  log_write(0, LOG_PANIC_DIE, "iflist-sysctl-estimate failed: %s",
+    strerror(errno));
+
+buf = store_get(needed);
+
+if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
+  log_write(0, LOG_PANIC_DIE, "sysctl of ifnet list failed: %s",
+    strerror(errno));
+
+/* Now fish out the data for each interface */
+
+lim  = buf + needed;
+for (nextaddr = buf; nextaddr < lim; nextaddr += ifm->ifm_msglen)
+  {
+  ifm = (struct if_msghdr *)nextaddr;
+
+  if (ifm->ifm_type != RTM_IFINFO)
+    {
+    struct ifa_msghdr *ifam = (struct ifa_msghdr *)ifm;
+    struct sockaddr_in *mask = NULL, *addr = NULL;
+
+    if ((ifam->ifam_addrs & RTA_NETMASK) != 0)
+      mask = (struct sockaddr_in *)(ifam + 1);
+
+    if ((ifam->ifam_addrs & RTA_IFA) != 0)
+      {
+      char *cp = CS mask;
+      struct sockaddr *sa = (struct sockaddr *)mask;
+      ADVANCE(cp, sa);
+      addr = (struct sockaddr_in *)cp;
+      }
+
+    /* Create a data block for the address, fill in the data, and put it on
+    the chain. This data has to survive for ever, so use malloc. */
+
+    if (addr != NULL)
+      {
+      next = store_malloc(sizeof(ip_address_item));
+      next->next = NULL;
+      next->port = 0;
+      (void)host_ntoa(-1, addr, next->address, NULL);
+
+      if (yield == NULL) yield = last = next; else
+        {
+        last->next = next;
+        last = next;
+        }
+
+      DEBUG(D_interface) debug_printf("Actual local interface address is %s\n",
+        last->address);
+      }
+    }
+  }
+
+return yield;
+}
+
+#endif  /* FIND_RUNNING_INTERFACES */
+
+/* End of os.c-IRIX */
diff --git a/src/OS/unsupported/os.c-IRIX632 b/src/OS/unsupported/os.c-IRIX632
new file mode 100644 (file)
index 0000000..1f6b0e1
--- /dev/null
@@ -0,0 +1,118 @@
+/*************************************************
+*     Exim - an Internet mail transport agent    *
+*************************************************/
+
+/* Copyright (c) University of Cambridge 2001 */
+/* See the file NOTICE for conditions of use and distribution. */
+
+/* Irix-specific code. This is concatenated onto the generic src/os.c file.
+Irix has a unique way of finding all the network interfaces, so we provide a
+unique function here, and define FIND_RUNNING_INTERFACES to stop src/os.c
+trying to provide the function. The macro may be set initially anyway, when
+compiling os. for utilities that don't want this function. */
+
+#ifndef FIND_RUNNING_INTERFACES
+#define FIND_RUNNING_INTERFACES
+
+/* This is the special form of the function using sysctl() which is the only
+form that returns all the aliases on IRIX systems. This code has its origins
+in a sample program that came from within SGI. */
+
+#include <sys/sysctl.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/soioctl.h>
+#include <net/route.h>
+
+#define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(__uint64_t) -1))) \
+                    : sizeof(__uint64_t))
+#ifdef _HAVE_SA_LEN
+#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
+#else
+#define ADVANCE(x, n) (x += ROUNDUP(_FAKE_SA_LEN_DST(n)))
+#endif
+
+
+ip_address_item *
+os_find_running_interfaces(void)
+{
+ip_address_item *yield = NULL;
+ip_address_item *last = NULL;
+ip_address_item *next;
+
+size_t needed;
+int mib[6];
+char *buf, *nextaddr, *lim;
+register struct if_msghdr *ifm;
+
+mib[0] = CTL_NET;
+mib[1] = PF_ROUTE;
+mib[2] = 0;
+mib[3] = 0;
+mib[4] = NET_RT_IFLIST;
+mib[5] = 0;
+
+/* Get an estimate of the amount of store needed, then get the store and
+get the data into it. Any error causes a panic death. */
+
+if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+  log_write(0, LOG_PANIC_DIE, "iflist-sysctl-estimate failed: %s",
+    strerror(errno));
+
+buf = store_get(needed);
+
+if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
+  log_write(0, LOG_PANIC_DIE, "sysctl of ifnet list failed: %s",
+    strerror(errno));
+
+/* Now fish out the data for each interface */
+
+lim  = buf + needed;
+for (nextaddr = buf; nextaddr < lim; nextaddr += ifm->ifm_msglen)
+  {
+  ifm = (struct if_msghdr *)nextaddr;
+
+  if (ifm->ifm_type != RTM_IFINFO)
+    {
+    struct ifa_msghdr *ifam = (struct ifa_msghdr *)ifm;
+    struct sockaddr_in *mask = NULL, *addr = NULL;
+
+    if ((ifam->ifam_addrs & RTA_NETMASK) != 0)
+      mask = (struct sockaddr_in *)(ifam + 1);
+
+    if ((ifam->ifam_addrs & RTA_IFA) != 0)
+      {
+      char *cp = CS mask;
+      struct sockaddr *sa = (struct sockaddr *)mask;
+      ADVANCE(cp, sa);
+      addr = (struct sockaddr_in *)cp;
+      }
+
+    /* Create a data block for the address, fill in the data, and put it on
+    the chain. This data has to survive for ever, so use malloc. */
+
+    if (addr != NULL)
+      {
+      next = store_malloc(sizeof(ip_address_item));
+      next->next = NULL;
+      next->port = 0;
+      (void)host_ntoa(-1, addr, next->address, NULL);
+
+      if (yield == NULL) yield = last = next; else
+        {
+        last->next = next;
+        last = next;
+        }
+
+      DEBUG(D_interface) debug_printf("Actual local interface address is %s\n",
+        last->address);
+      }
+    }
+  }
+
+return yield;
+}
+
+#endif  /* FIND_RUNNING_INTERFACES */
+
+/* End of os.c-IRIX */
diff --git a/src/OS/unsupported/os.c-IRIX65 b/src/OS/unsupported/os.c-IRIX65
new file mode 100644 (file)
index 0000000..1f6b0e1
--- /dev/null
@@ -0,0 +1,118 @@
+/*************************************************
+*     Exim - an Internet mail transport agent    *
+*************************************************/
+
+/* Copyright (c) University of Cambridge 2001 */
+/* See the file NOTICE for conditions of use and distribution. */
+
+/* Irix-specific code. This is concatenated onto the generic src/os.c file.
+Irix has a unique way of finding all the network interfaces, so we provide a
+unique function here, and define FIND_RUNNING_INTERFACES to stop src/os.c
+trying to provide the function. The macro may be set initially anyway, when
+compiling os. for utilities that don't want this function. */
+
+#ifndef FIND_RUNNING_INTERFACES
+#define FIND_RUNNING_INTERFACES
+
+/* This is the special form of the function using sysctl() which is the only
+form that returns all the aliases on IRIX systems. This code has its origins
+in a sample program that came from within SGI. */
+
+#include <sys/sysctl.h>
+#include <net/if_dl.h>
+#include <net/if_types.h>
+#include <net/soioctl.h>
+#include <net/route.h>
+
+#define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(__uint64_t) -1))) \
+                    : sizeof(__uint64_t))
+#ifdef _HAVE_SA_LEN
+#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
+#else
+#define ADVANCE(x, n) (x += ROUNDUP(_FAKE_SA_LEN_DST(n)))
+#endif
+
+
+ip_address_item *
+os_find_running_interfaces(void)
+{
+ip_address_item *yield = NULL;
+ip_address_item *last = NULL;
+ip_address_item *next;
+
+size_t needed;
+int mib[6];
+char *buf, *nextaddr, *lim;
+register struct if_msghdr *ifm;
+
+mib[0] = CTL_NET;
+mib[1] = PF_ROUTE;
+mib[2] = 0;
+mib[3] = 0;
+mib[4] = NET_RT_IFLIST;
+mib[5] = 0;
+
+/* Get an estimate of the amount of store needed, then get the store and
+get the data into it. Any error causes a panic death. */
+
+if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+  log_write(0, LOG_PANIC_DIE, "iflist-sysctl-estimate failed: %s",
+    strerror(errno));
+
+buf = store_get(needed);
+
+if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0)
+  log_write(0, LOG_PANIC_DIE, "sysctl of ifnet list failed: %s",
+    strerror(errno));
+
+/* Now fish out the data for each interface */
+
+lim  = buf + needed;
+for (nextaddr = buf; nextaddr < lim; nextaddr += ifm->ifm_msglen)
+  {
+  ifm = (struct if_msghdr *)nextaddr;
+
+  if (ifm->ifm_type != RTM_IFINFO)
+    {
+    struct ifa_msghdr *ifam = (struct ifa_msghdr *)ifm;
+    struct sockaddr_in *mask = NULL, *addr = NULL;
+
+    if ((ifam->ifam_addrs & RTA_NETMASK) != 0)
+      mask = (struct sockaddr_in *)(ifam + 1);
+
+    if ((ifam->ifam_addrs & RTA_IFA) != 0)
+      {
+      char *cp = CS mask;
+      struct sockaddr *sa = (struct sockaddr *)mask;
+      ADVANCE(cp, sa);
+      addr = (struct sockaddr_in *)cp;
+      }
+
+    /* Create a data block for the address, fill in the data, and put it on
+    the chain. This data has to survive for ever, so use malloc. */
+
+    if (addr != NULL)
+      {
+      next = store_malloc(sizeof(ip_address_item));
+      next->next = NULL;
+      next->port = 0;
+      (void)host_ntoa(-1, addr, next->address, NULL);
+
+      if (yield == NULL) yield = last = next; else
+        {
+        last->next = next;
+        last = next;
+        }
+
+      DEBUG(D_interface) debug_printf("Actual local interface address is %s\n",
+        last->address);
+      }
+    }
+  }
+
+return yield;
+}
+
+#endif  /* FIND_RUNNING_INTERFACES */
+
+/* End of os.c-IRIX */
diff --git a/src/OS/unsupported/os.c-OSF1 b/src/OS/unsupported/os.c-OSF1
new file mode 100644 (file)
index 0000000..ad91b63
--- /dev/null
@@ -0,0 +1,36 @@
+/*************************************************
+*     Exim - an Internet mail transport agent    *
+*************************************************/
+
+/* Copyright (c) University of Cambridge 2001 */
+/* See the file NOTICE for conditions of use and distribution. */
+
+/* OSF1-specific code. This is concatenated onto the generic src/os.c file.
+OSF1 has an apparently unique way of getting the load average, so we provide a
+unique function here, and define OS_LOAD_AVERAGE to stop src/os.c trying to
+provide the function. The macro may be set initially anyway, when compiling os.
+for utilities that don't want this function. */
+
+#ifndef OS_LOAD_AVERAGE
+#define OS_LOAD_AVERAGE
+
+#include <sys/table.h>
+
+int
+os_getloadavg(void)
+{
+double avg;
+struct tbl_loadavg load_avg;
+
+table (TBL_LOADAVG, 0, &load_avg, 1, sizeof (load_avg));
+
+avg = (load_avg.tl_lscale == 0)?
+  load_avg.tl_avenrun.d[0] :
+  (load_avg.tl_avenrun.l[0] / (double)load_avg.tl_lscale);
+
+return (int)(avg * 1000.0);
+}
+
+#endif  /* OS_LOAD_AVERAGE */
+
+/* End of os.c-OSF1 */
diff --git a/src/OS/unsupported/os.c-cygwin b/src/OS/unsupported/os.c-cygwin
new file mode 100644 (file)
index 0000000..c9464aa
--- /dev/null
@@ -0,0 +1,531 @@
+/*************************************************
+*     Exim - an Internet mail transport agent    *
+*************************************************/
+
+/* Cygwin-specific code. December 2002. Updated Jan 2015.
+   This is prefixed to the src/os.c file.
+
+   This code was supplied by Pierre A. Humblet <Pierre.Humblet@ieee.org>
+*/
+
+/* We need a special mkdir that
+   allows names starting with // */
+#undef mkdir
+int cygwin_mkdir( const char *path, mode_t mode )
+{
+  const char * p = path;
+  if (*p == '/') while(*(p+1) == '/') p++;
+  return mkdir(p, mode);
+}
+
+#ifndef COMPILE_UTILITY /* Utilities don't need special code */
+
+#ifdef INCLUDE_PAM
+#include "../pam/pam.c"
+#endif
+#include <alloca.h>
+
+unsigned int cygwin_WinVersion;
+
+/* Conflict between Windows definitions and others */
+#ifdef NOERROR
+#undef NOERROR
+#endif
+#ifdef DELETE
+#undef DELETE
+#endif
+
+#include <windows.h>
+#include <ntstatus.h>
+#include <lmcons.h>
+
+#define EqualLuid(Luid1, Luid2) \
+  ((Luid1.LowPart == Luid2.LowPart) && (Luid1.HighPart == Luid2.HighPart))
+#include <sys/cygwin.h>
+
+/* Special static variables */
+static BOOL cygwin_debug = FALSE;
+static int fakesetugid = 1; /* when not privileged, setugid = noop */
+
+#undef setuid
+int cygwin_setuid(uid_t uid )
+{
+  int res = 0;
+  if (fakesetugid == 0) { 
+    res = setuid(uid);
+    if (cygwin_debug)
+      fprintf(stderr, "setuid %u %u %d pid: %d\n",
+              uid, getuid(),res, getpid());
+  }
+  return res;
+}
+
+#undef setgid
+int cygwin_setgid(gid_t gid )
+{
+  int res = 0;
+  if (fakesetugid == 0) { 
+    res = setgid(gid);
+    if (cygwin_debug)
+      fprintf(stderr, "setgid %u %u %d pid: %d\n",
+              gid, getgid(), res, getpid());
+  }
+  return res;
+}
+
+/* Background processes run at lower priority */
+static void cygwin_setpriority()
+{
+  if (!SetPriorityClass(GetCurrentProcess(), BELOW_NORMAL_PRIORITY_CLASS))
+    SetPriorityClass(GetCurrentProcess(), IDLE_PRIORITY_CLASS);
+  return;
+}
+
+
+/* GetVersion()
+   MSB: 1 for 95/98/ME; Next 7: build number, except for 95/98/ME
+   Next byte: 0
+   Next byte: minor version of OS
+   Low  byte: major version of OS (3 or 4 for for NT, 5 for 2000 and XP) */
+//#define VERSION_IS_58M(x) (x & 0x80000000) /* 95, 98, Me   */
+//#define VERSION_IS_NT(x)  ((x & 0XFF) < 5) /* NT 4 or 3.51 */
+
+/*
+  Routine to find if process or thread is privileged
+*/
+
+enum {
+  CREATE_BIT = 1,
+};
+
+static DWORD get_privileges ()
+{
+  char buffer[1024];
+  DWORD i, length;
+  HANDLE hToken = NULL;
+  PTOKEN_PRIVILEGES privs;
+  LUID cluid, rluid;
+  DWORD ret = 0;
+
+  privs = (PTOKEN_PRIVILEGES) buffer;
+
+  if (OpenProcessToken (GetCurrentProcess(), TOKEN_QUERY, &hToken)
+      && LookupPrivilegeValue (NULL, SE_CREATE_TOKEN_NAME, &cluid)
+      && LookupPrivilegeValue(NULL, SE_RESTORE_NAME, &rluid)
+      && (GetTokenInformation( hToken, TokenPrivileges,
+                               privs, sizeof (buffer), &length)
+          || (GetLastError () == ERROR_INSUFFICIENT_BUFFER
+              && (privs = (PTOKEN_PRIVILEGES) alloca (length))
+              && GetTokenInformation(hToken, TokenPrivileges,
+                                     privs, length, &length)))) {
+    for (i = 0; i < privs->PrivilegeCount; i++) {
+      if (EqualLuid(privs->Privileges[i].Luid, cluid))
+        ret |= CREATE_BIT;
+      if (ret == (CREATE_BIT))
+        break;
+    }
+  }
+  else
+    fprintf(stderr, "has_create_token_privilege %u\n", GetLastError());
+
+  if (hToken)
+    CloseHandle(hToken);
+
+  return ret;
+}
+
+/* 
+  We use cygwin_premain to fake a few things 
+       and to provide some debug info 
+*/
+void cygwin_premain2(int argc, char ** argv, struct per_process * ptr)
+{
+  int i, res, is_daemon = 0, is_spoolwritable, is_privileged, is_eximuser;
+  uid_t myuid, systemuid;
+  gid_t mygid, adminsgid;
+  struct passwd * pwp = NULL;
+  struct stat buf;
+  char *cygenv;
+  SID(1, SystemSid, SECURITY_LOCAL_SYSTEM_RID);
+  SID(2, AdminsSid, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS);
+  DWORD priv_flags;
+
+  myuid = getuid();
+  mygid = getgid();
+  cygwin_WinVersion = GetVersion();
+  if ((cygenv = getenv("CYGWIN")) == NULL) cygenv = "";
+  /* Produce some debugging on stderr,
+     cannot yet use exim's debug functions.
+     Exim does not use -c and ignores -n.
+     Set lower priority for daemons */
+  for (i = 1; i < argc; i++) {
+    if (argv[i][0] == '-') {
+      if (argv[i][1] == 'c') {
+        ssize_t size;
+        wchar_t *win32_path;
+        argv[i][1] = 'n';  /* Replace -c by -n */
+        cygwin_debug = TRUE;
+        fprintf(stderr, "CYGWIN = \"%s\".\n", cygenv);
+        if (((size = cygwin_conv_path(CCP_POSIX_TO_WIN_W,"/", win32_path, 0)) > 0)
+        && ((win32_path = malloc(size)) != NULL)
+         && (cygwin_conv_path(CCP_POSIX_TO_WIN_W,"/", win32_path, size) == 0)) {
+               fprintf(stderr, " Root / mapped to %ls.\n", win32_path);
+               free(win32_path);
+       }
+      }
+      else if (argv[i][1] == 'b' && argv[i][2] == 'd') {
+        is_daemon = 1;
+        cygwin_setpriority();
+    }
+  }
+  }
+
+  /* Nt/2000/XP
+     We initially set the exim uid & gid to those of the "exim user",
+       or to the root uid (SYSTEM) and exim gid (ADMINS),
+     If privileged, we setuid to those.
+     We always set the configure uid to the system uid.
+     We always set the root uid to the real uid
+       to allow exim imposed restrictions (bypassable by recompiling)
+       and to avoid exec that cause loss of privilege
+     If not privileged and unable to chown,
+       we set the exim uid to our uid.
+     If unprivileged and /var/spool/exim is writable and not running as listening daemon, 
+       we fake all subsequent setuid. */
+
+  /* Get the system and admins uid from their sids */
+  if ((systemuid = cygwin_internal(CW_GET_UID_FROM_SID, & SystemSid)) == -1) {
+       fprintf(stderr, "Cannot map System sid. Aborting\n");
+       exit(1);
+  }
+  if ((adminsgid = cygwin_internal(CW_GET_GID_FROM_SID, & AdminsSid)) == -1) {
+       fprintf(stderr, "Cannot map Admins sid. Aborting\n");
+       exit(1);
+  }
+
+  priv_flags = get_privileges ();
+  is_privileged = !!(priv_flags & CREATE_BIT);
+
+  /* Call getpwnam for account exim after getting the local exim name */
+  char exim_username[DNLEN + UNLEN + 2];
+  if (cygwin_internal(CW_CYGNAME_FROM_WINNAME, "exim", exim_username, sizeof exim_username) != 0)
+     pwp = getpwnam (exim_username);
+
+  /* If cannot setuid to exim or and is not the daemon (which is assumed to be
+     able to chown or to be the exim user) set the exim ugid to our ugid to avoid
+     chown failures after creating files and to be able to setuid to exim in 
+     exim.c ( "privilege not needed" ). */
+  if ((is_privileged == 0) && (!is_daemon)) {
+    exim_uid = myuid;
+    exim_gid = mygid;
+  }
+  else if (pwp != NULL) {
+    exim_uid = pwp->pw_uid;  /* Set it according to passwd */
+    exim_gid = pwp->pw_gid;
+    is_eximuser = 1;
+  }
+  else {
+    exim_uid = systemuid;
+    exim_gid = adminsgid;
+    is_eximuser = 0;
+  }
+
+  res = stat("/var/spool/exim", &buf);
+  /* Check if writable (and can be stat) */
+  is_spoolwritable = ((res == 0) && ((buf.st_mode & S_IWOTH) != 0));
+
+  fakesetugid = (is_privileged == 0) && (is_daemon == 0) && (is_spoolwritable == 1);
+
+  if (is_privileged) {             /* Can setuid */
+     if (cygwin_setgid(exim_gid) /* Setuid to exim */
+         || cygwin_setuid(exim_uid)) {
+          fprintf(stderr, "Unable to setuid/gid to exim. priv_flags: %x\n", priv_flags);
+          exit(0);          /* Problem... Perhaps not in 544 */
+     }
+  }
+
+  /* Set the configuration file uid and gid to the system uid and admins gid. */
+  config_uid = systemuid;
+  config_gid = adminsgid;
+
+  /* Pretend we are root to avoid useless exec
+     and avoid exim set limitations.
+     We are limited by file access rights */
+  root_uid = getuid ();
+
+  if (cygwin_debug) {
+    fprintf(stderr, "Starting uid %u, gid %u, priv_flags %x, is_privileged %d, is_daemon %d, is_spoolwritable %d.\n",
+            myuid, mygid, priv_flags, is_privileged, is_daemon, is_spoolwritable);
+    fprintf(stderr, "root_uid %u, exim_uid %u, exim_gid %u, config_uid %u, config_gid %u, is_eximuser %d.\n",
+            root_uid, exim_uid, exim_gid, config_uid, config_gid, is_eximuser);
+  }
+  return;
+}
+
+#ifndef OS_LOAD_AVERAGE /* Can be set on command line */
+#define OS_LOAD_AVERAGE /* src/os.c need not provide it */
+
+/*****************************************************************
+ Functions for average load measurements
+
+ Uses NtQuerySystemInformation.
+ This requires definitions that are not part of
+ standard include files.
+
+ This is discouraged starting with WinXP.
+
+*************************************************************/
+/* Structure to compute the load average efficiently */
+typedef struct {
+  DWORD Lock;
+  unsigned long long Time100ns;   /* Last measurement time */
+  unsigned long long IdleCount;   /* Latest cumulative idle time */
+  unsigned long long LastCounter; /* Last measurement counter */
+  unsigned long long PerfFreq;    /* Perf counter frequency */
+  int LastLoad;                   /* Last reported load, or -1 */
+} cygwin_perf_t;
+
+static struct {
+   HANDLE handle;
+   pid_t pid;
+   cygwin_perf_t *perf;
+} cygwin_load = {NULL, 0, NULL};
+
+#include <ntdef.h>
+
+typedef enum _SYSTEM_INFORMATION_CLASS
+{
+  SystemBasicInformation = 0,
+  SystemPerformanceInformation = 2,
+  SystemTimeOfDayInformation = 3,
+  SystemProcessesAndThreadsInformation = 5,
+  SystemProcessorTimes = 8,
+  SystemPagefileInformation = 18,
+  /* There are a lot more of these... */
+} SYSTEM_INFORMATION_CLASS;
+
+typedef struct _SYSTEM_BASIC_INFORMATION
+{
+  ULONG Unknown;
+  ULONG MaximumIncrement;
+  ULONG PhysicalPageSize;
+  ULONG NumberOfPhysicalPages;
+  ULONG LowestPhysicalPage;
+  ULONG HighestPhysicalPage;
+  ULONG AllocationGranularity;
+  ULONG LowestUserAddress;
+  ULONG HighestUserAddress;
+  ULONG ActiveProcessors;
+  UCHAR NumberProcessors;
+} SYSTEM_BASIC_INFORMATION, *PSYSTEM_BASIC_INFORMATION;
+
+typedef struct __attribute__ ((aligned (8))) _SYSTEM_PROCESSOR_TIMES
+{
+  LARGE_INTEGER IdleTime;
+  LARGE_INTEGER KernelTime;
+  LARGE_INTEGER UserTime;
+  LARGE_INTEGER DpcTime;
+  LARGE_INTEGER InterruptTime;
+  ULONG InterruptCount;
+} SYSTEM_PROCESSOR_TIMES, *PSYSTEM_PROCESSOR_TIMES;
+
+typedef NTSTATUS NTAPI (*NtQuerySystemInformation_t) (SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG);
+typedef ULONG NTAPI (*RtlNtStatusToDosError_t) (NTSTATUS);
+
+static NtQuerySystemInformation_t NtQuerySystemInformation;
+static RtlNtStatusToDosError_t RtlNtStatusToDosError;
+
+/*****************************************************************
+ *
+ LoadNtdll()
+ Load special functions from the NTDLL
+ Return TRUE if success.
+
+ *****************************************************************/
+
+static BOOL LoadNtdll()
+{
+  HINSTANCE hinstLib;
+
+  if ((hinstLib = LoadLibrary("NTDLL.DLL"))
+      && (NtQuerySystemInformation =
+          (NtQuerySystemInformation_t) GetProcAddress(hinstLib,
+                                                        "NtQuerySystemInformation"))
+      && (RtlNtStatusToDosError =
+          (RtlNtStatusToDosError_t) GetProcAddress(hinstLib,
+                                                     "RtlNtStatusToDosError")))
+    return TRUE;
+
+  DEBUG(D_load)
+    debug_printf("perf: load: %u (Windows)\n", GetLastError());
+  return FALSE;
+}
+/*****************************************************************
+ *
+ ReadStat()
+ Measures current Time100ns and IdleCount
+ Return TRUE if success.
+
+ *****************************************************************/
+
+static BOOL ReadStat(unsigned long long int *Time100nsPtr,
+                     unsigned long long int *IdleCountPtr)
+{
+  NTSTATUS ret;
+  SYSTEM_BASIC_INFORMATION sbi;
+  PSYSTEM_PROCESSOR_TIMES spt;
+
+  *Time100nsPtr = *IdleCountPtr = 0;
+
+  if ((ret = NtQuerySystemInformation(SystemBasicInformation,
+                                      (PVOID) &sbi, sizeof sbi, NULL))
+      != STATUS_SUCCESS) {
+    DEBUG(D_load)
+      debug_printf("Perf: NtQuerySystemInformation: %u (Windows)\n",
+                   RtlNtStatusToDosError(ret));
+  }
+  else if (!(spt = (PSYSTEM_PROCESSOR_TIMES) alloca(sizeof(spt[0]) * sbi.NumberProcessors))) {
+    DEBUG(D_load)
+      debug_printf("Perf: alloca: errno %d (%s)\n", errno, strerror(errno));
+  }
+  else if ((ret = NtQuerySystemInformation(SystemProcessorTimes, (PVOID) spt,
+                                           sizeof spt[0] * sbi.NumberProcessors, NULL))
+           != STATUS_SUCCESS) {
+    DEBUG(D_load)
+      debug_printf("Perf: NtQuerySystemInformation: %u (Windows)\n",
+                   RtlNtStatusToDosError(ret));
+  }
+  else {
+    int i;
+    for (i = 0; i < sbi.NumberProcessors; i++) {
+      *Time100nsPtr += spt[i].KernelTime.QuadPart;;
+      *Time100nsPtr += spt[i].UserTime.QuadPart;
+      *IdleCountPtr += spt[i].IdleTime.QuadPart;
+    }
+    return TRUE;
+  }
+  return FALSE;
+}
+
+/*****************************************************************
+ *
+ InitLoadAvg()
+ Initialize the cygwin_load.perf structure.
+ and set cygwin_load.perf->Flag to TRUE if successful.
+ This is called the first time os_getloadavg is called
+ *****************************************************************/
+static void InitLoadAvg(cygwin_perf_t *this)
+{
+  BOOL success = TRUE;
+
+  /* Get perf frequency and counter */
+  QueryPerformanceFrequency((LARGE_INTEGER *)& this->PerfFreq);
+  QueryPerformanceCounter((LARGE_INTEGER *)& this->LastCounter);
+
+  /* Get initial values for Time100ns and IdleCount */
+  success = success
+            && ReadStat( & this->Time100ns,
+                         & this->IdleCount);
+  /* If success, set the Load to 0, else to -1 */
+  if (success) this->LastLoad = 0;
+  else {
+    log_write(0, LOG_MAIN, "Cannot obtain Load Average");
+    this->LastLoad = -1;
+  }
+}
+
+
+/*****************************************************************
+ *
+ os_getloadavg()
+
+ Return -1 if not available;
+ Return the previous value if less than AVERAGING sec old.
+ else return the processor load on a [0 - 1000] scale.
+
+ The first time we are called we initialize the counts
+ and return 0 or -1.
+ The initial load cannot be measured as we use the processor 100%
+*****************************************************************/
+static SECURITY_ATTRIBUTES sa = {sizeof (SECURITY_ATTRIBUTES), NULL, TRUE};
+#define AVERAGING 10
+
+int os_getloadavg()
+{
+  unsigned long long Time100ns, IdleCount, CurrCounter;
+  int value;
+  pid_t newpid;
+
+  /* New process.
+     Reload the dlls and the file mapping */
+  if ((newpid = getpid()) != cygwin_load.pid) {
+    BOOL new;
+    cygwin_load.pid = newpid;
+
+    if (!LoadNtdll()) {
+      log_write(0, LOG_MAIN, "Cannot obtain Load Average");
+      cygwin_load.perf = NULL;
+      return -1;
+    }
+
+    if ((new = !cygwin_load.handle)) {
+      cygwin_load.handle = CreateFileMapping (INVALID_HANDLE_VALUE, &sa, PAGE_READWRITE,
+                                              0, sizeof(cygwin_perf_t), NULL);
+      DEBUG(D_load)
+        debug_printf("Perf: CreateFileMapping: handle %p\n", (void *) cygwin_load.handle);
+    }
+    cygwin_load.perf = (cygwin_perf_t *) MapViewOfFile (cygwin_load.handle,
+                                                        FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
+    DEBUG(D_load)
+      debug_printf("Perf: MapViewOfFile: addr %p\n", (void *) cygwin_load.perf);
+    if (new && cygwin_load.perf)
+      InitLoadAvg(cygwin_load.perf);
+  }
+
+  /* Check if initialized OK */
+  if (!cygwin_load.perf || cygwin_load.perf->LastLoad < 0)
+    return -1;
+
+  /* If we cannot get the lock, we return 0.
+     This is to prevent any lock-up possibility.
+     Finding a lock busy is unlikely, and giving up only
+     results in an immediate delivery .*/
+
+  if (InterlockedCompareExchange(&cygwin_load.perf->Lock, 1, 0)) {
+    DEBUG(D_load)
+      debug_printf("Perf: Lock busy\n");
+    return 0;
+  }
+
+    /* Get the current time (PerfCounter) */
+    QueryPerformanceCounter((LARGE_INTEGER *)& CurrCounter);
+    /* Calls closer than AVERAGING sec apart use the previous value */
+  if (CurrCounter - cygwin_load.perf->LastCounter >
+      AVERAGING * cygwin_load.perf->PerfFreq) {
+      /* Get Time100ns and IdleCount */
+      if (ReadStat( & Time100ns, & IdleCount)) { /* Success */
+        /* Return processor load on 1000 scale */
+      value = 1000 - ((1000 * (IdleCount - cygwin_load.perf->IdleCount)) /
+                      (Time100ns - cygwin_load.perf->Time100ns));
+      cygwin_load.perf->Time100ns = Time100ns;
+      cygwin_load.perf->IdleCount = IdleCount;
+      cygwin_load.perf->LastCounter = CurrCounter;
+      cygwin_load.perf->LastLoad = value;
+      DEBUG(D_load)
+        debug_printf("Perf: New load average %d\n", value);
+      }
+      else { /* Something bad happened.
+                Refuse to measure the load anymore
+                but don't bother releasing the buffer */
+        log_write(0, LOG_MAIN, "Cannot obtain Load Average");
+      cygwin_load.perf->LastLoad = -1;
+    }
+  }
+  else
+  DEBUG(D_load)
+      debug_printf("Perf: Old load average %d\n", cygwin_load.perf->LastLoad);
+  cygwin_load.perf->Lock = 0;
+  return cygwin_load.perf->LastLoad;
+}
+#endif /* OS_LOAD_AVERAGE */
+#endif /* COMPILE_UTILITY */
diff --git a/src/OS/unsupported/os.h-AIX b/src/OS/unsupported/os.h-AIX
new file mode 100644 (file)
index 0000000..5cd4501
--- /dev/null
@@ -0,0 +1,27 @@
+/* Exim: OS-specific C header file for AIX */
+/* Written by Nick Waterman <nick@cimio.co.uk> */
+/* Modified by Philip Hazel with data from
+   Niels Provos <provos@wserver.physnet.uni-hamburg.de>
+   Juozas Simkevicius <juozas@omnitel.net> for load averages
+*/
+
+#define HAVE_DEV_KMEM
+#define LOAD_AVG_SYMBOL "avenrun"
+#define KERNEL_PATH     "/unix"
+#define LOAD_AVG_TYPE   int
+#define FSCALE          65536.0
+
+#define HAVE_SYS_VFS_H
+#define HAVE_SYS_STATFS_H
+
+/* Now tell AIX to emulate BSD as badly as it can. */
+
+#define _BSD 44
+
+typedef struct flock flock_t;
+
+/* default is non-const */
+#define ICONV_ARG2_TYPE const char **
+
+
+/* End */
diff --git a/src/OS/unsupported/os.h-BSDI b/src/OS/unsupported/os.h-BSDI
new file mode 100644 (file)
index 0000000..a1705ec
--- /dev/null
@@ -0,0 +1,15 @@
+/* Exim: OS-specific C header file for BSDI */
+
+#define HAVE_BSD_GETLOADAVG
+#define HAVE_SETCLASSRESOURCES
+#define HAVE_MMAP
+#define HAVE_SYS_MOUNT_H
+#define SIOCGIFCONF_GIVES_ADDR
+#define OS_UNSETENV
+
+typedef struct flock flock_t;
+
+/* default is non-const */
+#define ICONV_ARG2_TYPE const char **
+
+/* End */
diff --git a/src/OS/unsupported/os.h-DGUX b/src/OS/unsupported/os.h-DGUX
new file mode 100644 (file)
index 0000000..9040f0e
--- /dev/null
@@ -0,0 +1,28 @@
+/* Exim: OS-specific C header file for DGUX */
+
+/* Written by Ken Bailey (K.Bailey@rbgkew.org.uk) Feb 1998 */
+/* on dgux R4.11MU04 generic AViiON mc88100                */
+/* Modified Dec 1998 by PH after message from Ken.         */
+
+#define HAVE_SYS_STATVFS_H
+#define F_FAVAIL                 f_favail
+
+#define NO_SYSEXITS              /* DGUX doesn't ship sysexits.h */
+#define NO_IP_VAR_H              /* DGUX has no netinet/ip_var.h */
+
+#define os_strsignal             dg_strsignal
+#define OS_STRSIGNAL
+
+#define HAVE_MMAP
+
+/* The definition of ipoptions in netinet/in.h (masquerading as ip_opts) used
+in smtp_in.c is for Intel DG _IX86_ABI only. You may be able to get this to
+work on Intel DG but it's certainly easier to skip it on M88k. This means we
+forego the detection of some source-routing based IP attacks. */
+
+#define NO_IP_OPTIONS
+
+/* default is non-const */
+#define ICONV_ARG2_TYPE const char **
+
+/* End */
diff --git a/src/OS/unsupported/os.h-Darwin b/src/OS/unsupported/os.h-Darwin
new file mode 100644 (file)
index 0000000..f408740
--- /dev/null
@@ -0,0 +1,48 @@
+/* Exim: OS-specific C header file for Darwin (Mac OS X) */
+
+/* #define CRYPT_H */  /* Apparently this isn't needed */
+
+#define HAVE_MMAP
+#define HAVE_SYS_MOUNT_H
+#define PAM_H_IN_PAM
+#define SIOCGIFCONF_GIVES_ADDR
+
+/* OSX 10.2 does not have poll.h, 10.3 does emulate it badly. */
+#define NO_POLL_H
+
+#define F_FREESP     O_TRUNC
+typedef struct flock flock_t;
+
+#define BASE_62 36  /* HFS+ aliases lower and upper cases in filenames.
+                               Consider reducing MAX_LOCALHOST_NUMBER */
+
+#ifndef        _BSD_SOCKLEN_T_
+#define _BSD_SOCKLEN_T_ int32_t                 /* socklen_t (duh) */
+#endif
+
+/* Settings for handling IP options. There's no netinet/ip_var.h. The IP
+option handling is in the style of the later GLIBCs but the GLIBC macros
+aren't set, so we invent a new one. */
+
+#define NO_IP_VAR_H
+#define DARWIN_IP_OPTIONS
+
+/* Need this for the DNS lookup code. Remember to remove if we get round to
+updating Exim to use the newer interface. */
+
+#define BIND_8_COMPAT
+
+/* It's not .so for dynamic libraries on Darwin. */
+#define DYNLIB_FN_EXT "dylib"
+
+/* We currently need some assistance getting OFF_T_FMT correct on MacOS */
+#ifdef OFF_T_FMT
+# undef OFF_T_FMT
+#endif
+#define OFF_T_FMT "%lld"
+#define LONGLONG_T long int
+
+/* default is non-const */
+#define ICONV_ARG2_TYPE const char **
+
+/* End */
diff --git a/src/OS/unsupported/os.h-DragonFly b/src/OS/unsupported/os.h-DragonFly
new file mode 100644 (file)
index 0000000..4c2f1d5
--- /dev/null
@@ -0,0 +1,13 @@
+/* Exim: OS-specific C header file for DragonFly */
+
+#define HAVE_BSD_GETLOADAVG
+#define HAVE_MMAP
+#define HAVE_SYS_MOUNT_H
+#define SIOCGIFCONF_GIVES_ADDR
+
+typedef struct flock flock_t;
+
+/* default is non-const */
+#define ICONV_ARG2_TYPE const char **
+
+/* End */
diff --git a/src/OS/unsupported/os.h-GNU b/src/OS/unsupported/os.h-GNU
new file mode 100644 (file)
index 0000000..4499316
--- /dev/null
@@ -0,0 +1,23 @@
+/* Exim: OS-specific C header file for GNU/Hurd */
+
+#define CRYPT_H
+#define GLIBC_IP_OPTIONS
+#define HAVE_BSD_GETLOADAVG
+#define HAVE_MMAP
+#define HAVE_SYS_VFS_H
+#define NO_IP_VAR_H
+#define SIG_IGN_WORKS
+#define SIOCGIFCONF_GIVES_ADDR
+
+#define F_FREESP     O_TRUNC
+typedef struct flock flock_t;
+
+#define os_strsignal strsignal
+#define OS_STRSIGNAL
+
+/* Hurd-specific bits below */
+
+/* default is non-const */
+#define ICONV_ARG2_TYPE const char **
+
+/* End */
diff --git a/src/OS/unsupported/os.h-GNUkFreeBSD b/src/OS/unsupported/os.h-GNUkFreeBSD
new file mode 100644 (file)
index 0000000..ab35031
--- /dev/null
@@ -0,0 +1,25 @@
+/* Exim: OS-specific C header file for GNU/kFreeBSD */
+
+#define CRYPT_H
+#define GLIBC_IP_OPTIONS
+#define HAVE_MMAP
+#define HAVE_BSD_GETLOADAVG
+#define HAVE_SYS_VFS_H
+#define NO_IP_VAR_H
+#define SIG_IGN_WORKS
+
+#define F_FREESP     O_TRUNC
+typedef struct flock flock_t;
+
+#define os_strsignal strsignal
+#define OS_STRSIGNAL
+
+/* kFreeBSD-specific bits below */
+
+#define HAVE_SYS_MOUNT_H
+#define SIOCGIFCONF_GIVES_ADDR
+
+/* default is non-const */
+#define ICONV_ARG2_TYPE const char **
+
+/* End */
diff --git a/src/OS/unsupported/os.h-GNUkNetBSD b/src/OS/unsupported/os.h-GNUkNetBSD
new file mode 100644 (file)
index 0000000..bc3bc25
--- /dev/null
@@ -0,0 +1,25 @@
+/* Exim: OS-specific C header file for GNU/kNetBSD */
+
+#define CRYPT_H
+#define GLIBC_IP_OPTIONS
+#define HAVE_MMAP
+#define HAVE_BSD_GETLOADAVG
+#define HAVE_SYS_VFS_H
+#define NO_IP_VAR_H
+#define SIG_IGN_WORKS
+
+#define F_FREESP     O_TRUNC
+typedef struct flock flock_t;
+
+#define os_strsignal strsignal
+#define OS_STRSIGNAL
+
+/* kNetBSD-specific bits below */
+
+#define HAVE_SYS_MOUNT_H
+#define SIOCGIFCONF_GIVES_ADDR
+
+/* default is non-const */
+#define ICONV_ARG2_TYPE const char **
+
+/* End */
diff --git a/src/OS/unsupported/os.h-HI-OSF b/src/OS/unsupported/os.h-HI-OSF
new file mode 100644 (file)
index 0000000..0f50fb6
--- /dev/null
@@ -0,0 +1,12 @@
+/* Exim: OS-specific C header file for HI-OSF/1-MJ and HI-UX/MPP */
+
+#define HAVE_SYS_MOUNT_H
+
+typedef struct flock           flock_t;
+#define F_FREESP               O_TRUNC
+#define DN_EXPAND_ARG4_TYPE    u_char *
+
+/* default is non-const */
+#define ICONV_ARG2_TYPE const char **
+
+/* End */
diff --git a/src/OS/unsupported/os.h-HI-UX b/src/OS/unsupported/os.h-HI-UX
new file mode 100644 (file)
index 0000000..f3df963
--- /dev/null
@@ -0,0 +1,21 @@
+/* Exim: OS-specific C header file for HI-UX */
+
+#define LOAD_AVG_NEEDS_ROOT
+#define HAVE_DEV_KMEM
+#define LOAD_AVG_TYPE       double
+#define LOAD_AVG_SYMBOL     "avenrun"
+#define KERNEL_PATH         "/HI-UX"
+#define FSCALE              1.0
+
+#define HAVE_SYS_VFS_H
+
+#define SELECT_ARG2_TYPE    int
+#define F_FREESP            O_TRUNC
+#define NEED_H_ERRNO        1
+
+typedef struct flock flock_t;
+
+/* default is non-const */
+#define ICONV_ARG2_TYPE const char **
+
+/* End */
diff --git a/src/OS/unsupported/os.h-HP-UX b/src/OS/unsupported/os.h-HP-UX
new file mode 100644 (file)
index 0000000..4998734
--- /dev/null
@@ -0,0 +1,34 @@
+/* Exim: OS-specific C header file for HP-UX versions greater than 9 */
+
+#define EXIM_SOCKLEN_T size_t
+
+#define LOAD_AVG_NEEDS_ROOT
+#define HAVE_DEV_KMEM
+#define LOAD_AVG_TYPE   double
+#define LOAD_AVG_SYMBOL "avenrun"
+#define KERNEL_PATH     "/stand/vmunix"
+#define FSCALE          1.0
+
+#define HAVE_SYS_STATVFS_H
+
+#define F_FREESP           O_TRUNC
+#define NEED_H_ERRNO       1
+
+typedef struct flock flock_t;
+
+typedef struct __res_state *res_state;
+
+#define LLONG_MIN LONG_LONG_MIN
+#define LLONG_MAX LONG_LONG_MAX
+
+#define strtoll(a,b,c) strtoimax(a,b,c)
+
+/* Determined by sockaddr_un */
+
+struct sockaddr_storage
+{
+  short ss_family;
+  char __ss_padding[92];
+};
+
+/* End */
diff --git a/src/OS/unsupported/os.h-HP-UX-9 b/src/OS/unsupported/os.h-HP-UX-9
new file mode 100644 (file)
index 0000000..5a260d6
--- /dev/null
@@ -0,0 +1,23 @@
+/* Exim: OS-specific C header file for HP-UX version 9 */
+
+#define LOAD_AVG_NEEDS_ROOT
+#define HAVE_DEV_KMEM
+#define LOAD_AVG_TYPE   double
+#define LOAD_AVG_SYMBOL "avenrun"
+#define KERNEL_PATH     "/hp-ux"
+#define FSCALE          1.0
+
+#define HAVE_SYS_VFS_H
+
+#define SELECT_ARG2_TYPE   int
+#define F_FREESP           O_TRUNC
+#define NEED_H_ERRNO       1
+
+#define killpg(pgid,sig)   kill(-(pgid),sig)
+
+typedef struct flock flock_t;
+
+/* default is non-const */
+#define ICONV_ARG2_TYPE const char **
+
+/* End */
diff --git a/src/OS/unsupported/os.h-IRIX b/src/OS/unsupported/os.h-IRIX
new file mode 100644 (file)
index 0000000..1d4bf46
--- /dev/null
@@ -0,0 +1,17 @@
+/* Exim: OS-specific C header file for IRIX */
+
+#define DN_EXPAND_ARG4_TYPE  u_char *
+
+#define LOAD_AVG_NEEDS_ROOT
+#define HAVE_DEV_KMEM
+#define LOAD_AVG_TYPE   long
+#define LOAD_AVG_SYMBOL "avenrun"
+#define KERNEL_PATH     "/unix"
+#define FSCALE          1000.0
+
+#define HAVE_MMAP
+#define HAVE_SYS_STATVFS_H
+#define F_FAVAIL        f_favail
+#define vfork fork
+
+/* End */
diff --git a/src/OS/unsupported/os.h-IRIX6 b/src/OS/unsupported/os.h-IRIX6
new file mode 100644 (file)
index 0000000..bf30767
--- /dev/null
@@ -0,0 +1,16 @@
+/* Exim: OS-specific C header file for IRIX */
+
+#define CRYPT_H
+#define LOAD_AVG_NEEDS_ROOT
+#define HAVE_DEV_KMEM
+#define LOAD_AVG_TYPE   long
+#define LOAD_AVG_SYMBOL "avenrun"
+#define KERNEL_PATH     "/unix"
+#define FSCALE          1000.0
+
+#define HAVE_MMAP
+#define HAVE_SYS_STATVFS_H
+#define F_FAVAIL        f_favail
+#define vfork fork
+
+/* End */
diff --git a/src/OS/unsupported/os.h-IRIX632 b/src/OS/unsupported/os.h-IRIX632
new file mode 100644 (file)
index 0000000..90f1c58
--- /dev/null
@@ -0,0 +1,18 @@
+/* Exim: OS-specific C header file for IRIX */
+
+#define CRYPT_H
+#define DN_EXPAND_ARG4_TYPE  u_char *
+
+#define LOAD_AVG_NEEDS_ROOT
+#define HAVE_DEV_KMEM
+#define LOAD_AVG_TYPE   long
+#define LOAD_AVG_SYMBOL "avenrun"
+#define KERNEL_PATH     "/unix"
+#define FSCALE          1000.0
+
+#define HAVE_MMAP
+#define HAVE_SYS_STATVFS_H
+#define F_FAVAIL        f_favail
+#define vfork fork
+
+/* End */
diff --git a/src/OS/unsupported/os.h-IRIX65 b/src/OS/unsupported/os.h-IRIX65
new file mode 100644 (file)
index 0000000..4b248fe
--- /dev/null
@@ -0,0 +1,16 @@
+/* Exim: OS-specific C header file for IRIX 6.5 */
+
+#define CRYPT_H
+#define LOAD_AVG_NEEDS_ROOT
+#define HAVE_DEV_KMEM
+#define LOAD_AVG_TYPE   long
+#define LOAD_AVG_SYMBOL "avenrun"
+#define KERNEL_PATH     "/unix"
+#define FSCALE          1000.0
+
+#define HAVE_MMAP
+#define HAVE_SYS_STATVFS_H
+#define F_FAVAIL        f_favail
+#define vfork fork
+
+/* End */
diff --git a/src/OS/unsupported/os.h-NetBSD b/src/OS/unsupported/os.h-NetBSD
new file mode 100644 (file)
index 0000000..d2d3e0d
--- /dev/null
@@ -0,0 +1,28 @@
+/* Exim: OS-specific C header file for NetBSD */
+
+#define HAVE_BSD_GETLOADAVG
+#define HAVE_GETIFADDRS
+#define HAVE_MMAP
+#define HAVE_SYS_MOUNT_H
+#define SIOCGIFCONF_GIVES_ADDR
+#define HAVE_ARC4RANDOM
+
+typedef struct flock flock_t;
+
+#define os_strsignal strsignal
+#define OS_STRSIGNAL
+
+#define os_get_dns_resolver_res __res_get_state
+#define os_put_dns_resolver_res(RP) __res_put_state(RP)
+#define OS_GET_DNS_RESOLVER_RES
+
+#include <sys/param.h>
+
+#if __NetBSD_Version__ >= 299000900
+#define HAVE_SYS_STATVFS_H
+#endif
+
+/* default is non-const */
+#define ICONV_ARG2_TYPE const char **
+
+/* End */
diff --git a/src/OS/unsupported/os.h-NetBSD-a.out b/src/OS/unsupported/os.h-NetBSD-a.out
new file mode 100644 (file)
index 0000000..29a8fee
--- /dev/null
@@ -0,0 +1,5 @@
+/* Exim: OS-specific C header file for NetBSD (a.out binary format) */
+
+#include "../OS/os.h-NetBSD"     /* Same as for ELF format */
+
+/* End */
diff --git a/src/OS/unsupported/os.h-OSF1 b/src/OS/unsupported/os.h-OSF1
new file mode 100644 (file)
index 0000000..6b5fa49
--- /dev/null
@@ -0,0 +1,16 @@
+/* Exim: OS-specific C header file for OSF1 */
+
+#define HAVE_SYS_MOUNT_H
+#define HAVE_GETIPNODEBYNAME    1
+
+typedef struct flock flock_t;
+#define F_FREESP     O_TRUNC
+
+/* This was here for some time, but it seems that now (June 2005) things have
+changed. */
+/* #define EXIM_SOCKLEN_T    size_t */
+
+/* Still not "socklen_t", which is the most common setting */
+#define EXIM_SOCKLEN_T       int
+
+/* End */
diff --git a/src/OS/unsupported/os.h-OpenUNIX b/src/OS/unsupported/os.h-OpenUNIX
new file mode 100644 (file)
index 0000000..67d1063
--- /dev/null
@@ -0,0 +1,19 @@
+/* Exim: OS-specific C header file for OpenUNIX */
+
+#define NO_SYSEXITS
+
+#define LOAD_AVG_NEEDS_ROOT
+#define HAVE_DEV_KMEM
+#define LOAD_AVG_TYPE   short
+#define LOAD_AVG_SYMBOL "avenrun"
+#define KERNEL_PATH     "/stand/unix"
+#define FSCALE          256
+
+#define HAVE_SYS_STATVFS_H
+#define _SVID3
+#define NEED_H_ERRNO
+
+/* default is non-const */
+#define ICONV_ARG2_TYPE const char **
+
+/* End */
diff --git a/src/OS/unsupported/os.h-QNX b/src/OS/unsupported/os.h-QNX
new file mode 100644 (file)
index 0000000..798f799
--- /dev/null
@@ -0,0 +1,24 @@
+/* Exim: OS-specific C header file for QNX */
+/* Modified for QNX 6.2.0 with diffs from Samuli Tuomola. */
+
+#include <sys/select.h>
+
+/* This include is wrapped in an ifdef so as to be skipped for QNXRTP, which
+doesn't have/need this header file. From Karsten P. Hoffmann. */
+
+#ifdef __QNX__
+#include <unix.h>
+#endif
+
+#undef HAVE_STATFS
+#undef HAVE_VFS_H
+#undef HAVE_SYS_MOUNT_H
+
+#define NO_SYSEXITS
+
+extern int h_errno;
+
+/* default is non-const */
+#define ICONV_ARG2_TYPE const char **
+
+/* End */
diff --git a/src/OS/unsupported/os.h-SCO b/src/OS/unsupported/os.h-SCO
new file mode 100644 (file)
index 0000000..e5e915e
--- /dev/null
@@ -0,0 +1,21 @@
+/* Exim: OS-specific C header file for SCO */
+
+#define DN_EXPAND_ARG4_TYPE    u_char *
+
+#define LOAD_AVG_NEEDS_ROOT
+#define HAVE_DEV_KMEM
+#define LOAD_AVG_TYPE   short
+#define LOAD_AVG_SYMBOL "avenrun"
+#define KERNEL_PATH     "/unix"
+#define FSCALE          256
+#define EXIM_SOCKLEN_T  int
+
+#define HAVE_SYS_STATVFS_H
+#define F_FAVAIL        f_favail
+#define _SVID3
+#define NEED_H_ERRNO
+
+/* default is non-const */
+#define ICONV_ARG2_TYPE const char **
+
+/* End */
diff --git a/src/OS/unsupported/os.h-SCO_SV b/src/OS/unsupported/os.h-SCO_SV
new file mode 100644 (file)
index 0000000..0ca29f7
--- /dev/null
@@ -0,0 +1,19 @@
+/* Exim: OS-specific C header file for SCO_SV */
+
+#define LOAD_AVG_NEEDS_ROOT
+#define HAVE_DEV_KMEM
+#define LOAD_AVG_TYPE   short
+#define LOAD_AVG_SYMBOL "avenrun"
+#define KERNEL_PATH     "/unix"
+#define FSCALE          256
+#define EXIM_SOCKLEN_T  int
+
+#define HAVE_SYS_STATVFS_H
+#define F_FAVAIL        f_favail
+#define _SVID3
+#define NEED_H_ERRNO
+
+/* default is non-const */
+#define ICONV_ARG2_TYPE const char **
+
+/* End */
diff --git a/src/OS/unsupported/os.h-SunOS4 b/src/OS/unsupported/os.h-SunOS4
new file mode 100644 (file)
index 0000000..6555620
--- /dev/null
@@ -0,0 +1,39 @@
+/* Exim: OS-specific C header file for SunOS4 */
+
+#define LOAD_AVG_NEEDS_ROOT
+#define HAVE_DEV_KMEM
+#define LOAD_AVG_TYPE   long
+#define LOAD_AVG_SYMBOL "_avenrun"
+#define KERNEL_PATH     "/vmunix"
+
+#define HAVE_MMAP
+#define HAVE_SYS_VFS_H
+
+#define F_FREESP     O_TRUNC
+#define EXIT_FAILURE 1
+#define EXIT_SUCCESS 0
+typedef struct flock flock_t;
+
+#define STRERROR_FROM_ERRLIST
+#define memmove(a, b, c) bcopy(b, a, c)
+#define strtoul(str, ptr, base) ((unsigned int)strtol((str),(ptr),(base)))
+
+extern char *strerror(int);
+extern int   sys_nerr;
+extern char *sys_errlist[];
+
+/* In ANSI C strtod() is defined in stdlib.h, but in SunOS4 it is defined in
+floatingpoint.h which is called from math.h, which Exim doesn't include. */
+
+extern double strtod(const char *, char **);
+
+/* SunOS4 seems to define getc, ungetc, feof and ferror as macros only, not
+as functions. We need to have them as assignable functions. Setting this
+flag causes this to get done in exim.h. */
+
+#define FUDGE_GETC_AND_FRIENDS
+
+/* default is non-const */
+#define ICONV_ARG2_TYPE const char **
+
+/* End */
diff --git a/src/OS/unsupported/os.h-SunOS5-hal b/src/OS/unsupported/os.h-SunOS5-hal
new file mode 100644 (file)
index 0000000..cd9e877
--- /dev/null
@@ -0,0 +1,14 @@
+/* Exim: OS-specific C header file for SunOS5 on HAL */
+
+#define HAVE_MMAP
+
+#define HAVE_KSTAT
+#define LOAD_AVG_KSTAT        "system_misc"
+#define LOAD_AVG_KSTAT_MODULE "unix"
+#define LOAD_AVG_SYMBOL       "avenrun_1min"
+#define LOAD_AVG_FIELD         value.ul
+
+/* default is non-const */
+#define ICONV_ARG2_TYPE const char **
+
+/* End */
diff --git a/src/OS/unsupported/os.h-ULTRIX b/src/OS/unsupported/os.h-ULTRIX
new file mode 100644 (file)
index 0000000..08db5ae
--- /dev/null
@@ -0,0 +1,18 @@
+/* Exim: OS-specific C header file for Ultrix */
+
+/* Well, it *does* have statfs(), but its structure is called something
+different, all the members have different names, and the function returns
+1 on success rather than 0. As this is for a minority function, and I think
+a minority operating system, easiest just to say "no" until someone asks. */
+
+#undef HAVE_STATFS
+
+#define F_FREESP     O_TRUNC
+#define NEED_H_ERRNO
+#define NO_OPENLOG
+typedef struct flock flock_t;
+
+/* default is non-const */
+#define ICONV_ARG2_TYPE const char **
+
+/* End */
diff --git a/src/OS/unsupported/os.h-UNIX_SV b/src/OS/unsupported/os.h-UNIX_SV
new file mode 100644 (file)
index 0000000..4943a07
--- /dev/null
@@ -0,0 +1,25 @@
+/* Exim: OS-specific C header file for SCO SVR4.2 (and maybe Unixware) */
+
+/**
+*** Note that for SCO 5 the configuration file is called SCO_SV,
+*** and that Unixware7 has its own configuration. This is an old
+*** file that is retained for compatibility.
+**/
+
+#define NO_SYSEXITS
+
+#define LOAD_AVG_NEEDS_ROOT
+#define HAVE_DEV_KMEM
+#define LOAD_AVG_TYPE   short
+#define LOAD_AVG_SYMBOL "avenrun"
+#define KERNEL_PATH     "/stand/unix"
+#define FSCALE          256
+
+#define HAVE_SYS_STATVFS_H
+#define _SVID3
+#define NEED_H_ERRNO
+
+/* default is non-const */
+#define ICONV_ARG2_TYPE const char **
+
+/* End */
diff --git a/src/OS/unsupported/os.h-USG b/src/OS/unsupported/os.h-USG
new file mode 100644 (file)
index 0000000..e769220
--- /dev/null
@@ -0,0 +1,19 @@
+/* Exim: OS-specific C header file for Unixware 2.x */
+
+#define NO_SYSEXITS
+
+#define LOAD_AVG_NEEDS_ROOT
+#define HAVE_DEV_KMEM
+#define LOAD_AVG_TYPE   short
+#define LOAD_AVG_SYMBOL "avenrun"
+#define KERNEL_PATH     "/stand/unix"
+#define FSCALE          256
+
+#define HAVE_SYS_STATVFS_H
+#define _SVID3
+#define NEED_H_ERRNO
+
+/* default is non-const */
+#define ICONV_ARG2_TYPE const char **
+
+/* End */
diff --git a/src/OS/unsupported/os.h-Unixware7 b/src/OS/unsupported/os.h-Unixware7
new file mode 100644 (file)
index 0000000..4d3ed42
--- /dev/null
@@ -0,0 +1,18 @@
+/* Exim: OS-specific C header file for Unixware 7 */
+
+#define NO_SYSEXITS
+
+#define EXIM_SOCKLEN_T size_t
+
+#define LOAD_AVG_NEEDS_ROOT
+#define HAVE_DEV_KMEM
+#define LOAD_AVG_TYPE   short
+#define LOAD_AVG_SYMBOL "avenrun"
+#define KERNEL_PATH     "/stand/unix"
+#define FSCALE          256
+
+#define HAVE_SYS_STATVFS_H
+#define _SVID3
+#define NEED_H_ERRNO
+
+/* End */
diff --git a/src/OS/unsupported/os.h-cygwin b/src/OS/unsupported/os.h-cygwin
new file mode 100644 (file)
index 0000000..6ef59e0
--- /dev/null
@@ -0,0 +1,41 @@
+/* Exim: OS-specific C header file for Cygwin */
+
+/* This code was supplied by Pierre A. Humblet <Pierre.Humblet@ieee.org>
+   December 2002. Updated Jan 2015. */
+
+/* Redefine the set*id calls to run when faking root */
+#include <unistd.h>   /* Do not redefine in unitsd.h */
+int cygwin_setuid(uid_t uid );
+int cygwin_setgid(gid_t gid );
+#define setuid cygwin_setuid
+#define setgid cygwin_setgid
+
+#define os_strsignal strsignal
+#define OS_STRSIGNAL
+#define BASE_62 36  /* Windows aliases lower and upper cases in filenames.
+                       Consider reducing MAX_LOCALHOST_NUMBER */
+#define CRYPT_H
+#define HAVE_MMAP
+#define HAVE_SYS_VFS_H
+#define NO_IP_VAR_H
+#define NO_IP_OPTIONS
+/* Defining LOAD_AVG_NEEDS_ROOT causes an initial
+   call to os_getloadavg. In our case this is beneficial
+   because it initializes the counts */
+#define LOAD_AVG_NEEDS_ROOT
+
+typedef struct flock flock_t;
+
+/* Macro to define variable length SID structures */
+#define SID(n, name, sid...) \
+struct  { \
+  BYTE  Revision; \
+  BYTE  SubAuthorityCount; \
+  SID_IDENTIFIER_AUTHORITY IdentifierAuthority; \
+  DWORD SubAuthority[n]; \
+} name = { SID_REVISION, n, {SECURITY_NT_AUTHORITY}, {sid}}
+
+/* default is non-const */
+#define ICONV_ARG2_TYPE const char **
+
+/* End */
diff --git a/src/OS/unsupported/os.h-mips b/src/OS/unsupported/os.h-mips
new file mode 100644 (file)
index 0000000..325e3a1
--- /dev/null
@@ -0,0 +1,27 @@
+/* Exim: OS-specific C header file for RiscOS4bsd */
+
+#define LOAD_AVG_NEEDS_ROOT
+#define HAVE_DEV_KMEM
+#define LOAD_AVG_TYPE   long
+#define LOAD_AVG_SYMBOL "_avenrun"
+#define KERNEL_PATH     "/unix"
+
+#define HAVE_MMAP
+#define HAVE_SYS_VFS_H
+
+#define F_FREESP     O_TRUNC
+#define EXIT_FAILURE 1
+#define EXIT_SUCCESS 0
+typedef struct flock flock_t;
+
+#define STRERROR_FROM_ERRLIST
+#define memmove(a, b, c) bcopy(b, a, c)
+
+extern char *strerror(int);
+extern int   sys_nerr;
+extern char *sys_errlist[];
+
+/* default is non-const */
+#define ICONV_ARG2_TYPE const char **
+
+/* End */
index 54032362c1775b66380f492ce187299d5fe82203..46ad834daea4f561900b8da84bace937ff0191d1 100644 (file)
@@ -191,7 +191,7 @@ uschar *queue_name             = US"";
 
 int     received_count         = 0;
 uschar *received_protocol      = NULL;
-int     received_time          = 0;
+struct timeval received_time   = { 0, 0 };
 int     recipients_count       = 0;
 recipient_item *recipients_list = NULL;
 int     recipients_list_max    = 0;
index a7e874a8731848725cb586da359610f10c732894..67294368a65812056cc50a7df2971ff4f9f5a589 100644 (file)
@@ -100,6 +100,7 @@ typedef void hctx;
 
 #include "local_scan.h"
 #include "structs.h"
+#include "blob.h"
 #include "globals.h"
 #include "dbstuff.h"
 #include "functions.h"
index 9ff994ced48909eda7eaffd92e85e820f599aa15..73aa0e56759c66fb0243b8c2773dabc8bfa4971e 100644 (file)
@@ -281,12 +281,8 @@ if (LOG != NULL)
     if (strstric(buffer, US"frozen", FALSE) != NULL)
       {
       queue_item *qq = find_queue(id, queue_noop, 0);
-      if (qq != NULL)
-        {
-        if (strstric(buffer, US"unfrozen", FALSE) != NULL)
-          qq->frozen = FALSE;
-        else qq->frozen = TRUE;
-        }
+      if (qq)
+        qq->frozen = strstric(buffer, US"unfrozen", FALSE) == NULL;
       }
 
     /* Notice defer messages, and add the destination if it
index 3034a041ced68139fc26900b38ca2a498880e898..00471ce3dfc6d6dd65ca37e040a6599e00852529 100644 (file)
@@ -631,7 +631,7 @@ signal(SIGCHLD, sigchld_handler);
 
 /* Get the buffer for storing the string for the log display. */
 
-log_display_buffer = (uschar *)store_malloc(log_buffer_size);
+log_display_buffer = US store_malloc(log_buffer_size);
 log_display_buffer[0] = 0;
 
 /* Initialize the data structures for the stripcharts */
index 6deb909da5b6d44e2888770d25945678d7356eb4..935e826877d6a94ed5aea1729934f8375d787415 100644 (file)
@@ -174,7 +174,7 @@ static void
 bodyAction(Widget w, XtPointer client_data, XtPointer call_data)
 {
 int i;
-Widget text = text_create((uschar *)client_data, text_depth);
+Widget text = text_create(US client_data, text_depth);
 FILE *f = NULL;
 
 w = w;      /* Keep picky compilers happy */
@@ -183,7 +183,7 @@ call_data = call_data;
 for (i = 0; i < (spool_is_split? 2:1); i++)
   {
   uschar * fname;
-  message_subdir[0] = i != 0 ? ((uschar *)client_data)[5] : 0;
+  message_subdir[0] = i != 0 ? (US client_data)[5] : 0;
   fname = spool_fname(US"input", message_subdir, US client_data, US"-D");
   if ((f = fopen(CS fname, "r")))
     break;
@@ -334,9 +334,9 @@ if (!delivery)
   if (rc == 0 && Ustrcmp(action + Ustrlen(action) - 4, "-Mes") == 0)
     {
     queue_item *q = find_queue(id, queue_noop, 0);
-    if (q != NULL)
+    if (q)
       {
-      if (q->sender != NULL) store_free(q->sender);
+      if (q->sender) store_free(q->sender);
       q->sender = store_malloc(Ustrlen(address_arg) + 1);
       Ustrcpy(q->sender, address_arg);
       }
@@ -411,7 +411,7 @@ static void deliverAction(Widget w, XtPointer client_data, XtPointer call_data)
 {
 w = w;      /* Keep picky compilers happy */
 call_data = call_data;
-ActOnMessage((uschar *)client_data, US"-v -M", US"");
+ActOnMessage(US client_data, US"-v -M", US"");
 }
 
 
@@ -424,7 +424,7 @@ static void freezeAction(Widget w, XtPointer client_data, XtPointer call_data)
 {
 w = w;      /* Keep picky compilers happy */
 call_data = call_data;
-ActOnMessage((uschar *)client_data, US"-Mf", US"");
+ActOnMessage(US client_data, US"-Mf", US"");
 }
 
 
@@ -437,7 +437,7 @@ static void thawAction(Widget w, XtPointer client_data, XtPointer call_data)
 {
 w = w;      /* Keep picky compilers happy */
 call_data = call_data;
-ActOnMessage((uschar *)client_data, US"-Mt", US"");
+ActOnMessage(US client_data, US"-Mt", US"");
 }
 
 
@@ -624,7 +624,7 @@ static void giveupAction(Widget w, XtPointer client_data, XtPointer call_data)
 {
 w = w;      /* Keep picky compilers happy */
 call_data = call_data;
-ActOnMessage((uschar *)client_data, US"-v -Mg", US"");
+ActOnMessage(US client_data, US"-v -Mg", US"");
 }
 
 
@@ -637,7 +637,7 @@ static void removeAction(Widget w, XtPointer client_data, XtPointer call_data)
 {
 w = w;      /* Keep picky compilers happy */
 call_data = call_data;
-ActOnMessage((uschar *)client_data, US"-Mrm", US"");
+ActOnMessage(US client_data, US"-Mrm", US"");
 }
 
 
@@ -650,7 +650,7 @@ static void headersAction(Widget w, XtPointer client_data, XtPointer call_data)
 {
 uschar buffer[256];
 header_line *h, *next;
-Widget text = text_create((uschar *)client_data, text_depth);
+Widget text = text_create(US client_data, text_depth);
 void *reset_point;
 
 w = w;      /* Keep picky compilers happy */
@@ -661,7 +661,7 @@ Then use Exim's function to read the header. */
 
 reset_point = store_get(0);
 
-sprintf(CS buffer, "%s-H", (uschar *)client_data);
+sprintf(CS buffer, "%s-H", US client_data);
 if (spool_read_header(buffer, TRUE, FALSE) != spool_read_OK)
   {
   if (errno == ERRNO_SPOOLFORMAT)
index 4bdc57ab93ccc4b3695c7043355328adf0bb61ec..e6b1e91d90d93dd44219100f58bff7c24a054750 100644 (file)
@@ -63,7 +63,8 @@ if it is dest_remove, remove if present and return NULL. The
 address is lowercased to start with, unless it begins with
 "*", which it does for error messages. */
 
-dest_item *find_dest(queue_item *q, uschar *name, int action, BOOL caseless)
+dest_item *
+find_dest(queue_item *q, uschar *name, int action, BOOL caseless)
 {
 dest_item *dd;
 dest_item **d = &(q->destinations);
@@ -108,7 +109,8 @@ return dd;
 *            Clean up a dead queue item          *
 *************************************************/
 
-static void clean_up(queue_item *p)
+static void
+clean_up(queue_item *p)
 {
 dest_item *dd = p->destinations;
 while (dd != NULL)
@@ -149,7 +151,8 @@ return node;
 *             Set up new queue item              *
 *************************************************/
 
-static queue_item *set_up(uschar *name, int dir_char)
+static queue_item *
+set_up(uschar *name, int dir_char)
 {
 int i, rc, save_errno;
 struct stat statdata;
@@ -162,7 +165,7 @@ uschar buffer[256];
 
 q->next = q->prev = NULL;
 q->destinations = NULL;
-Ustrcpy(q->name, name);
+Ustrncpy(q->name, name, sizeof(q->name));
 q->seen = TRUE;
 q->frozen = FALSE;
 q->dir_char = dir_char;
@@ -201,7 +204,7 @@ if it's there. */
 
 else
   {
-  q->update_time = q->input_time = received_time;
+  q->update_time = q->input_time = received_time.tv_sec;
   if ((p = strstric(sender_address+1, qualify_domain, FALSE)) != NULL &&
     *(--p) == '@') *p = 0;
   }
@@ -331,7 +334,8 @@ while (p != NULL)
 
 
 
-queue_item *find_queue(uschar *name, int action, int dir_char)
+queue_item *
+find_queue(uschar *name, int action, int dir_char)
 {
 int first = 0;
 int last = queue_index_size - 1;
index a10aac4fba7636598b3820774c141958b12c28fc..0279654ac9403a51945bcb2bba2183c2a91dddbb 100644 (file)
@@ -25,7 +25,7 @@ Ustrcpy(today, __DATE__);
 if (today[4] == ' ') i = 1;
 today[3] = today[6] = '-';
 
-version_date = (uschar *)malloc(32);
+version_date = US malloc(32);
 version_date[0] = 0;
 Ustrncat(version_date, today+4+i, 3-i);
 Ustrncat(version_date, today, 4);
index b6f2e2e0979a1fa2760638edf01335156faaf486..648960e44036f96bdceb04d2dc7a5c240475ff22 100755 (executable)
@@ -1,4 +1,5 @@
 #! /bin/sh
+export LC_ALL=C
 
 # Shell script to build Makefile in a build directory. It must be called
 # from inside the directory. It does its own checking of when to rebuild; it
index b710c2fd8ab6f133fc3888a09a894d41c5c40e7c..22e5a4bd74b087572213995ea35b138bbc7e6f5b 100755 (executable)
@@ -85,7 +85,7 @@ cd ..
 mkdir pdkim
 cd pdkim
 for f in README Makefile crypt_ver.h pdkim.c \
-  pdkim.h hash.c hash.h rsa.c rsa.h blob.h
+  pdkim.h hash.c hash.h signing.c signing.h blob.h
 do
   ln -s ../../src/pdkim/$f $f
 done
@@ -107,8 +107,10 @@ for f in blob.h dbfunctions.h dbstuff.h exim.h functions.h globals.h \
   setenv.c environment.c \
   sieve.c smtp_in.c smtp_out.c spool_in.c spool_out.c std-crypto.c store.c \
   string.c tls.c tlscert-gnu.c tlscert-openssl.c tls-gnu.c tls-openssl.c \
-  tod.c transport.c tree.c verify.c version.c dkim.c dkim.h dmarc.c dmarc.h \
-  valgrind.h memcheck.h
+  tod.c transport.c tree.c verify.c version.c \
+  dkim.c dkim.h dkim_transport.c dmarc.c dmarc.h \
+  valgrind.h memcheck.h \
+  macro_predef.c macro_predef.h
 do
   ln -s ../src/$f $f
 done
index 9707b9c1c680911372d4b209d6132c28a5882f14..45755c0848944e53fe81438e98cdcb492ec46219 100755 (executable)
@@ -71,10 +71,41 @@ EXIM_COMPILE_NUMBER=$(expr "${EXIM_COMPILE_NUMBER:-0}" + 1)
 
 echo "$EXIM_COMPILE_NUMBER" >cnumber.h
 
+# Reproducible builds, accept a build timestamp override from environ per
+# <https://reproducible-builds.org/specs/source-date-epoch/>.
+# We require a fairly modern date(1) command here, which is not portable
+# to some of the systems Exim is built on.  That's okay, because the scenarios
+# are:
+#  1) Local postmaster building, not using $SOURCE_DATE_EPOCH, doesn't matter
+#  2) Packaging folks who don't care about reproducible builds
+#  3) Packaging folks who care but are using systems where date Just Works
+#  3) Packaging folks who care and can put a modern date(1) in $PATH
+#  4) Packaging folks who care and can supply us with a clean patch to support
+#     their requirements
+#  5) Packaging folks who care but won't do any work to support their strange
+#     old systems and want us to do the work for them.  We don't care either,
+#     they're SOL and have to live without reproducible builds.
+#
+exim_build_date_override=''
+if [ ".${SOURCE_DATE_EPOCH:-}" != "." ]; then
+  fmt='+%d-%b-%Y %H:%M:%S'
+  # Non-reproducible, we use __DATE__ and __TIME__ in C, which respect timezone
+  # (think localtime, not gmtime); for reproduction between systems, UTC makes
+  # more sense and the examples available use UTC without explicitly mandating
+  # it.  I think that we can switch behavior and use UTC for reproducible
+  # builds without it causing any problems: nothing really cares about timezone.
+  # GNU date: "date -d @TS"
+  # BSD date: "date -r TS"
+  exim_build_date_override="$(date -u -d "@${SOURCE_DATE_EPOCH}" "$fmt" 2>/dev/null | date -u -r "${SOURCE_DATE_EPOCH}" "$fmt" 2>/dev/null)"
+fi
+
 ( echo '# automatically generated file - see ../scripts/reversion'
   echo EXIM_RELEASE_VERSION='"'"$EXIM_RELEASE_VERSION"'"'
   echo EXIM_VARIANT_VERSION='"'"$EXIM_VARIANT_VERSION"'"'
   echo EXIM_COMPILE_NUMBER='"'"$EXIM_COMPILE_NUMBER"'"'
+  if [ ".${exim_build_date_override:-}" != "." ]; then
+    echo EXIM_BUILD_DATE_OVERRIDE='"'"${exim_build_date_override}"'"'
+  fi
 ) >version.sh
 
 if [ ! -f version.h ]
@@ -83,6 +114,9 @@ then
   echo '#define EXIM_RELEASE_VERSION "'"$EXIM_RELEASE_VERSION"'"'
   echo '#define EXIM_VARIANT_VERSION "'"$EXIM_VARIANT_VERSION"'"'
   echo '#define EXIM_VERSION_STR EXIM_RELEASE_VERSION EXIM_VARIANT_VERSION'
+  if [ ".${exim_build_date_override:-}" != "." ]; then
+    echo '#define EXIM_BUILD_DATE_OVERRIDE "'"${exim_build_date_override}"'"'
+  fi
 ) >version.h
 fi
 
index 5ac5a55dcc17bcd6b1404474d4d70362b609b5a6..e604acd8b06cad9d6e82fc06e387db39d4e6e8ab 100644 (file)
@@ -473,6 +473,7 @@ EXIM_MONITOR=eximon.bin
 # Uncomment the following line to add DMARC checking capability, implemented
 # using libopendmarc libraries.  You must have SPF support enabled also.
 # EXPERIMENTAL_DMARC=yes
+# DMARC_TLD_FILE= /etc/exim/opendmarc.tlds
 # CFLAGS += -I/usr/local/include
 # LDFLAGS += -lopendmarc
 
index efab1d31e22691cdfa917ff229136af8338d5b09..b5ffa0193ed58372ca72918d9d922eaf543f502f 100644 (file)
@@ -22,13 +22,14 @@ enum { ACL_ACCEPT, ACL_DEFER, ACL_DENY, ACL_DISCARD, ACL_DROP, ACL_REQUIRE,
 /* ACL verbs */
 
 static uschar *verbs[] = {
-    US"accept",
-    US"defer",
-    US"deny",
-    US"discard",
-    US"drop",
-    US"require",
-    US"warn" };
+    [ACL_ACCEPT] =     US"accept",
+    [ACL_DEFER] =      US"defer",
+    [ACL_DENY] =       US"deny",
+    [ACL_DISCARD] =    US"discard",
+    [ACL_DROP] =       US"drop",
+    [ACL_REQUIRE] =    US"require",
+    [ACL_WARN] =       US"warn"
+};
 
 /* For each verb, the conditions for which "message" or "log_message" are used
 are held as a bitmap. This is to avoid expanding the strings unnecessarily. For
@@ -36,13 +37,13 @@ are held as a bitmap. This is to avoid expanding the strings unnecessarily. For
 the code. */
 
 static int msgcond[] = {
-  (1<<OK) | (1<<FAIL) | (1<<FAIL_DROP),  /* accept */
-  (1<<OK),                               /* defer */
-  (1<<OK),                               /* deny */
-  (1<<OK) | (1<<FAIL) | (1<<FAIL_DROP),  /* discard */
-  (1<<OK),                               /* drop */
-  (1<<FAIL) | (1<<FAIL_DROP),            /* require */
-  (1<<OK)                                /* warn */
+  [ACL_ACCEPT] =       (1<<OK) | (1<<FAIL) | (1<<FAIL_DROP),
+  [ACL_DEFER] =                (1<<OK),
+  [ACL_DENY] =         (1<<OK),
+  [ACL_DISCARD] =      (1<<OK) | (1<<FAIL) | (1<<FAIL_DROP),
+  [ACL_DROP] =         (1<<OK),
+  [ACL_REQUIRE] =      (1<<FAIL) | (1<<FAIL_DROP),
+  [ACL_WARN] =         (1<<OK)
   };
 
 /* ACL condition and modifier codes - keep in step with the table that
@@ -132,213 +133,210 @@ times. */
 } condition_def;
 
 static condition_def conditions[] = {
-  { US"acl",           FALSE, FALSE,   0 },
+  [ACLC_ACL] =                 { US"acl",              FALSE, FALSE,   0 },
 
-  { US"add_header",    TRUE, TRUE,
-    (unsigned int)
-    ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
-      (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
+  [ACLC_ADD_HEADER] =          { US"add_header",       TRUE, TRUE,
+                                 (unsigned int)
+                                 ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
+                                   (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
 #ifndef DISABLE_PRDR
-      (1<<ACL_WHERE_PRDR)|
+                                   (1<<ACL_WHERE_PRDR)|
 #endif
-      (1<<ACL_WHERE_MIME)|(1<<ACL_WHERE_NOTSMTP)|
-      (1<<ACL_WHERE_DKIM)|
-      (1<<ACL_WHERE_NOTSMTP_START)),
+                                   (1<<ACL_WHERE_MIME)|(1<<ACL_WHERE_NOTSMTP)|
+                                   (1<<ACL_WHERE_DKIM)|
+                                   (1<<ACL_WHERE_NOTSMTP_START)),
   },
 
-  { US"authenticated", FALSE, FALSE,
-    (1<<ACL_WHERE_NOTSMTP)|
-      (1<<ACL_WHERE_NOTSMTP_START)|
-      (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO),
+  [ACLC_AUTHENTICATED] =       { US"authenticated",    FALSE, FALSE,
+                                 (1<<ACL_WHERE_NOTSMTP)|
+                                   (1<<ACL_WHERE_NOTSMTP_START)|
+                                   (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO),
   },
 #ifdef EXPERIMENTAL_BRIGHTMAIL
-  { US"bmi_optin",     TRUE, TRUE,
-    (1<<ACL_WHERE_AUTH)|
-      (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
-      (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_MIME)|
+  [ACLC_BMI_OPTIN] =           { US"bmi_optin",        TRUE, TRUE,
+                                 (1<<ACL_WHERE_AUTH)|
+                                   (1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO)|
+                                   (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_MIME)|
 # ifndef DISABLE_PRDR
-      (1<<ACL_WHERE_PRDR)|
+                                   (1<<ACL_WHERE_PRDR)|
 # endif
-      (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
-      (1<<ACL_WHERE_MAILAUTH)|
-      (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
-      (1<<ACL_WHERE_VRFY)|(1<<ACL_WHERE_PREDATA)|
-      (1<<ACL_WHERE_NOTSMTP_START),
+                                   (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
+                                   (1<<ACL_WHERE_MAILAUTH)|
+                                   (1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_STARTTLS)|
+                                   (1<<ACL_WHERE_VRFY)|(1<<ACL_WHERE_PREDATA)|
+                                   (1<<ACL_WHERE_NOTSMTP_START),
   },
 #endif
-  { US"condition",     TRUE, FALSE,    0 },
-  { US"continue",      TRUE, TRUE,     0 },
+  [ACLC_CONDITION] =           { US"condition",        TRUE, FALSE,    0 },
+  [ACLC_CONTINUE] =            { US"continue", TRUE, TRUE,     0 },
 
   /* Certain types of control are always allowed, so we let it through
   always and check in the control processing itself. */
-  { US"control",       TRUE, TRUE,     0 },
+  [ACLC_CONTROL] =             { US"control",  TRUE, TRUE,     0 },
 
 #ifdef EXPERIMENTAL_DCC
-  { US"dcc",           TRUE, FALSE,
-    (unsigned int)
-    ~((1<<ACL_WHERE_DATA)|
+  [ACLC_DCC] =                 { US"dcc",              TRUE, FALSE,
+                                 (unsigned int)
+                                 ~((1<<ACL_WHERE_DATA)|
 # ifndef DISABLE_PRDR
-      (1<<ACL_WHERE_PRDR)|
+                                 (1<<ACL_WHERE_PRDR)|
 # endif
-      (1<<ACL_WHERE_NOTSMTP)),
+                                 (1<<ACL_WHERE_NOTSMTP)),
   },
 #endif
 #ifdef WITH_CONTENT_SCAN
-  { US"decode",                TRUE, FALSE, (unsigned int) ~(1<<ACL_WHERE_MIME) },
+  [ACLC_DECODE] =              { US"decode",           TRUE, FALSE, (unsigned int) ~(1<<ACL_WHERE_MIME) },
 
 #endif
-  { US"delay",         TRUE, TRUE, (1<<ACL_WHERE_NOTQUIT) },
+  [ACLC_DELAY] =               { US"delay",            TRUE, TRUE, (1<<ACL_WHERE_NOTQUIT) },
 #ifndef DISABLE_DKIM
-  { US"dkim_signers",  TRUE, FALSE, (unsigned int) ~(1<<ACL_WHERE_DKIM) },
-  { US"dkim_status",   TRUE, FALSE, (unsigned int) ~(1<<ACL_WHERE_DKIM) },
+  [ACLC_DKIM_SIGNER] =         { US"dkim_signers",     TRUE, FALSE, (unsigned int) ~(1<<ACL_WHERE_DKIM) },
+  [ACLC_DKIM_STATUS] =         { US"dkim_status",      TRUE, FALSE, (unsigned int) ~(1<<ACL_WHERE_DKIM) },
 #endif
 #ifdef EXPERIMENTAL_DMARC
-  { US"dmarc_status",  TRUE, FALSE, (unsigned int) ~(1<<ACL_WHERE_DATA) },
+  [ACLC_DMARC_STATUS] =                { US"dmarc_status",     TRUE, FALSE, (unsigned int) ~(1<<ACL_WHERE_DATA) },
 #endif
 
   /* Explicit key lookups can be made in non-smtp ACLs so pass
   always and check in the verify processing itself. */
-  { US"dnslists",      TRUE, FALSE,    0 },
+  [ACLC_DNSLISTS] =            { US"dnslists", TRUE, FALSE,    0 },
 
-  { US"domains",       FALSE, FALSE,
-    (unsigned int)
-    ~((1<<ACL_WHERE_RCPT)
-      |(1<<ACL_WHERE_VRFY)
+  [ACLC_DOMAINS] =             { US"domains",  FALSE, FALSE,
+                                 (unsigned int)
+                                 ~((1<<ACL_WHERE_RCPT)
+                                   |(1<<ACL_WHERE_VRFY)
 #ifndef DISABLE_PRDR
-      |(1<<ACL_WHERE_PRDR)
+                                 |(1<<ACL_WHERE_PRDR)
 #endif
       ),
   },
-  { US"encrypted",     FALSE, FALSE,
-    (1<<ACL_WHERE_NOTSMTP)|
-      (1<<ACL_WHERE_CONNECT)|
-      (1<<ACL_WHERE_NOTSMTP_START)|
-      (1<<ACL_WHERE_HELO),
+  [ACLC_ENCRYPTED] =           { US"encrypted",        FALSE, FALSE,
+                                 (1<<ACL_WHERE_NOTSMTP)|
+                                   (1<<ACL_WHERE_CONNECT)|
+                                   (1<<ACL_WHERE_NOTSMTP_START)|
+                                   (1<<ACL_WHERE_HELO),
   },
 
-  { US"endpass",       TRUE, TRUE,     0 },
+  [ACLC_ENDPASS] =             { US"endpass",  TRUE, TRUE,     0 },
 
-  { US"hosts",         FALSE, FALSE,
-    (1<<ACL_WHERE_NOTSMTP)|
-      (1<<ACL_WHERE_NOTSMTP_START),
+  [ACLC_HOSTS] =               { US"hosts",            FALSE, FALSE,
+                                 (1<<ACL_WHERE_NOTSMTP)|
+                                   (1<<ACL_WHERE_NOTSMTP_START),
   },
-  { US"local_parts",   FALSE, FALSE,
-    (unsigned int)
-    ~((1<<ACL_WHERE_RCPT)
-      |(1<<ACL_WHERE_VRFY)
-    #ifndef DISABLE_PRDR
-      |(1<<ACL_WHERE_PRDR)
-    #endif
+  [ACLC_LOCAL_PARTS] =         { US"local_parts",      FALSE, FALSE,
+                                 (unsigned int)
+                                 ~((1<<ACL_WHERE_RCPT)
+                                   |(1<<ACL_WHERE_VRFY)
+#ifndef DISABLE_PRDR
+                                 |(1<<ACL_WHERE_PRDR)
+#endif
       ),
   },
 
-  { US"log_message",   TRUE, TRUE,     0 },
-  { US"log_reject_target", TRUE, TRUE, 0 },
-  { US"logwrite",      TRUE, TRUE,     0 },
+  [ACLC_LOG_MESSAGE] =         { US"log_message",      TRUE, TRUE,     0 },
+  [ACLC_LOG_REJECT_TARGET] =           { US"log_reject_target", TRUE, TRUE,    0 },
+  [ACLC_LOGWRITE] =            { US"logwrite", TRUE, TRUE,     0 },
 
 #ifdef WITH_CONTENT_SCAN
-  { US"malware",       TRUE, FALSE,
-    (unsigned int)
-    ~((1<<ACL_WHERE_DATA)|
+  [ACLC_MALWARE] =             { US"malware",  TRUE, FALSE,
+                                 (unsigned int)
+                                   ~((1<<ACL_WHERE_DATA)|
 # ifndef DISABLE_PRDR
-      (1<<ACL_WHERE_PRDR)|
+                                   (1<<ACL_WHERE_PRDR)|
 # endif
-      (1<<ACL_WHERE_NOTSMTP)),
+                                   (1<<ACL_WHERE_NOTSMTP)),
   },
 #endif
 
-  { US"message",       TRUE, TRUE,     0 },
+  [ACLC_MESSAGE] =             { US"message",  TRUE, TRUE,     0 },
 #ifdef WITH_CONTENT_SCAN
-  { US"mime_regex",    TRUE, FALSE, (unsigned int) ~(1<<ACL_WHERE_MIME) },
+  [ACLC_MIME_REGEX] =          { US"mime_regex",       TRUE, FALSE, (unsigned int) ~(1<<ACL_WHERE_MIME) },
 #endif
 
-  { US"queue",         TRUE, TRUE,
-    (1<<ACL_WHERE_NOTSMTP)|
+  [ACLC_QUEUE] =               { US"queue",            TRUE, TRUE,
+                                 (1<<ACL_WHERE_NOTSMTP)|
 #ifndef DISABLE_PRDR
-      (1<<ACL_WHERE_PRDR)|
+                                 (1<<ACL_WHERE_PRDR)|
 #endif
-      (1<<ACL_WHERE_DATA),
+                                 (1<<ACL_WHERE_DATA),
   },
 
-  { US"ratelimit",     TRUE, FALSE,    0 },
-  { US"recipients",    FALSE, FALSE, (unsigned int) ~(1<<ACL_WHERE_RCPT) },
+  [ACLC_RATELIMIT] =           { US"ratelimit",        TRUE, FALSE,    0 },
+  [ACLC_RECIPIENTS] =          { US"recipients",       FALSE, FALSE, (unsigned int) ~(1<<ACL_WHERE_RCPT) },
 
 #ifdef WITH_CONTENT_SCAN
-  { US"regex",         TRUE, FALSE,
-    (unsigned int)
-    ~((1<<ACL_WHERE_DATA)|
+  [ACLC_REGEX] =               { US"regex",            TRUE, FALSE,
+                                 (unsigned int)
+                                 ~((1<<ACL_WHERE_DATA)|
 # ifndef DISABLE_PRDR
-      (1<<ACL_WHERE_PRDR)|
+                                   (1<<ACL_WHERE_PRDR)|
 # endif
-      (1<<ACL_WHERE_NOTSMTP)|
-      (1<<ACL_WHERE_MIME)),
+                                   (1<<ACL_WHERE_NOTSMTP)|
+                                   (1<<ACL_WHERE_MIME)),
   },
 
 #endif
-  { US"remove_header", TRUE, TRUE,
-    (unsigned int)
-    ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
-      (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
+  [ACLC_REMOVE_HEADER] =       { US"remove_header",    TRUE, TRUE,
+                                 (unsigned int)
+                                 ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
+                                   (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
 #ifndef DISABLE_PRDR
-      (1<<ACL_WHERE_PRDR)|
+                                   (1<<ACL_WHERE_PRDR)|
 #endif
-      (1<<ACL_WHERE_MIME)|(1<<ACL_WHERE_NOTSMTP)|
-      (1<<ACL_WHERE_NOTSMTP_START)),
+                                   (1<<ACL_WHERE_MIME)|(1<<ACL_WHERE_NOTSMTP)|
+                                   (1<<ACL_WHERE_NOTSMTP_START)),
   },
-  { US"sender_domains",        FALSE, FALSE,
-    (1<<ACL_WHERE_AUTH)|(1<<ACL_WHERE_CONNECT)|
-      (1<<ACL_WHERE_HELO)|
-      (1<<ACL_WHERE_MAILAUTH)|(1<<ACL_WHERE_QUIT)|
-      (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
-      (1<<ACL_WHERE_STARTTLS)|(1<<ACL_WHERE_VRFY),
+  [ACLC_SENDER_DOMAINS] =      { US"sender_domains",   FALSE, FALSE,
+                                 (1<<ACL_WHERE_AUTH)|(1<<ACL_WHERE_CONNECT)|
+                                   (1<<ACL_WHERE_HELO)|
+                                   (1<<ACL_WHERE_MAILAUTH)|(1<<ACL_WHERE_QUIT)|
+                                   (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
+                                   (1<<ACL_WHERE_STARTTLS)|(1<<ACL_WHERE_VRFY),
   },
-  { US"senders",       FALSE, FALSE,
-    (1<<ACL_WHERE_AUTH)|(1<<ACL_WHERE_CONNECT)|
-      (1<<ACL_WHERE_HELO)|
-      (1<<ACL_WHERE_MAILAUTH)|(1<<ACL_WHERE_QUIT)|
-      (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
-      (1<<ACL_WHERE_STARTTLS)|(1<<ACL_WHERE_VRFY),
+  [ACLC_SENDERS] =             { US"senders",  FALSE, FALSE,
+                                 (1<<ACL_WHERE_AUTH)|(1<<ACL_WHERE_CONNECT)|
+                                   (1<<ACL_WHERE_HELO)|
+                                   (1<<ACL_WHERE_MAILAUTH)|(1<<ACL_WHERE_QUIT)|
+                                   (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
+                                   (1<<ACL_WHERE_STARTTLS)|(1<<ACL_WHERE_VRFY),
   },
 
-  { US"set",           TRUE, TRUE,     0 },
+  [ACLC_SET] =                 { US"set",              TRUE, TRUE,     0 },
 
 #ifdef WITH_CONTENT_SCAN
-  { US"spam",          TRUE, FALSE,
-    (unsigned int)
-    ~((1<<ACL_WHERE_DATA)|
+  [ACLC_SPAM] =                        { US"spam",             TRUE, FALSE,
+                                 (unsigned int) ~((1<<ACL_WHERE_DATA)|
 # ifndef DISABLE_PRDR
-      (1<<ACL_WHERE_PRDR)|
+                                 (1<<ACL_WHERE_PRDR)|
 # endif
-      (1<<ACL_WHERE_NOTSMTP)),
+                                 (1<<ACL_WHERE_NOTSMTP)),
   },
 #endif
 #ifdef EXPERIMENTAL_SPF
-  { US"spf",           TRUE, FALSE,
-    (1<<ACL_WHERE_AUTH)|(1<<ACL_WHERE_CONNECT)|
-      (1<<ACL_WHERE_HELO)|
-      (1<<ACL_WHERE_MAILAUTH)|
-      (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
-      (1<<ACL_WHERE_STARTTLS)|(1<<ACL_WHERE_VRFY)|
-      (1<<ACL_WHERE_NOTSMTP)|
-      (1<<ACL_WHERE_NOTSMTP_START),
+  [ACLC_SPF] =                 { US"spf",              TRUE, FALSE,
+                                 (1<<ACL_WHERE_AUTH)|(1<<ACL_WHERE_CONNECT)|
+                                   (1<<ACL_WHERE_HELO)|
+                                   (1<<ACL_WHERE_MAILAUTH)|
+                                   (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
+                                   (1<<ACL_WHERE_STARTTLS)|(1<<ACL_WHERE_VRFY)|
+                                   (1<<ACL_WHERE_NOTSMTP)|
+                                   (1<<ACL_WHERE_NOTSMTP_START),
   },
-  { US"spf_guess",     TRUE, FALSE,
-    (1<<ACL_WHERE_AUTH)|(1<<ACL_WHERE_CONNECT)|
-      (1<<ACL_WHERE_HELO)|
-      (1<<ACL_WHERE_MAILAUTH)|
-      (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
-      (1<<ACL_WHERE_STARTTLS)|(1<<ACL_WHERE_VRFY)|
-      (1<<ACL_WHERE_NOTSMTP)|
-      (1<<ACL_WHERE_NOTSMTP_START),
+  [ACLC_SPF_GUESS] =           { US"spf_guess",        TRUE, FALSE,
+                                 (1<<ACL_WHERE_AUTH)|(1<<ACL_WHERE_CONNECT)|
+                                   (1<<ACL_WHERE_HELO)|
+                                   (1<<ACL_WHERE_MAILAUTH)|
+                                   (1<<ACL_WHERE_ETRN)|(1<<ACL_WHERE_EXPN)|
+                                   (1<<ACL_WHERE_STARTTLS)|(1<<ACL_WHERE_VRFY)|
+                                   (1<<ACL_WHERE_NOTSMTP)|
+                                   (1<<ACL_WHERE_NOTSMTP_START),
   },
 #endif
-  { US"udpsend",       TRUE, TRUE,     0 },
+  [ACLC_UDPSEND] =             { US"udpsend",          TRUE, TRUE,     0 },
 
   /* Certain types of verify are always allowed, so we let it through
   always and check in the verify function itself */
-  { US"verify",                TRUE, FALSE,
-    0
-  },
+  [ACLC_VERIFY] =              { US"verify",           TRUE, FALSE, 0 },
 };
 
 
@@ -399,116 +397,142 @@ typedef struct control_def {
 } control_def;
 
 static control_def controls_list[] = {
+  /*   name                    has_option      forbids */
+[CONTROL_AUTH_UNADVERTISED] =
   { US"allow_auth_unadvertised", FALSE,
-    (unsigned)
-    ~((1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO))
+                                 (unsigned)
+                                 ~((1<<ACL_WHERE_CONNECT)|(1<<ACL_WHERE_HELO))
   },
 #ifdef EXPERIMENTAL_BRIGHTMAIL
-  { US"bmi_run",                 FALSE, 0 },
+[CONTROL_BMI_RUN] =
+  { US"bmi_run",                 FALSE,                0 },
 #endif
+[CONTROL_CASEFUL_LOCAL_PART] =
   { US"caseful_local_part",      FALSE, (unsigned) ~(1<<ACL_WHERE_RCPT) },
+[CONTROL_CASELOWER_LOCAL_PART] =
   { US"caselower_local_part",    FALSE, (unsigned) ~(1<<ACL_WHERE_RCPT) },
-  { US"cutthrough_delivery",     TRUE, 0 },
-  { US"debug",                   TRUE, 0 },
+[CONTROL_CUTTHROUGH_DELIVERY] =
+  { US"cutthrough_delivery",     TRUE,         0 },
+[CONTROL_DEBUG] =
+  { US"debug",                   TRUE,         0 },
 
 #ifndef DISABLE_DKIM
+[CONTROL_DKIM_VERIFY] =
   { US"dkim_disable_verify",     FALSE,
-    (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP)|
+                                 (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP)|
 # ifndef DISABLE_PRDR
-      (1<<ACL_WHERE_PRDR)|
+                                 (1<<ACL_WHERE_PRDR)|
 # endif
-      (1<<ACL_WHERE_NOTSMTP_START)
+                                 (1<<ACL_WHERE_NOTSMTP_START)
   },
 #endif
 
 #ifdef EXPERIMENTAL_DMARC
+[CONTROL_DMARC_VERIFY] =
   { US"dmarc_disable_verify",    FALSE,
-    (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
+         (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
   },
+[CONTROL_DMARC_FORENSIC] =
   { US"dmarc_enable_forensic",   FALSE,
-    (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
+         (1<<ACL_WHERE_DATA)|(1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
   },
 #endif
 
+[CONTROL_DSCP] =
   { US"dscp",                    TRUE,
-    (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)|(1<<ACL_WHERE_NOTQUIT)
+         (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)|(1<<ACL_WHERE_NOTQUIT)
   },
+[CONTROL_ENFORCE_SYNC] =
   { US"enforce_sync",            FALSE,
-    (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
+         (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
   },
 
   /* Pseudo-value for decode errors */
+[CONTROL_ERROR] =
   { US"error",                   FALSE, 0 },
 
+[CONTROL_FAKEDEFER] =
   { US"fakedefer",               TRUE,
-    (unsigned)
-    ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
-      (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
+         (unsigned)
+         ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
+           (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
 #ifndef DISABLE_PRDR
-      (1<<ACL_WHERE_PRDR)|
+           (1<<ACL_WHERE_PRDR)|
 #endif
-      (1<<ACL_WHERE_MIME))
+           (1<<ACL_WHERE_MIME))
   },
+[CONTROL_FAKEREJECT] =
   { US"fakereject",              TRUE,
-    (unsigned)
-    ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
-      (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
+         (unsigned)
+         ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
+           (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
 #ifndef DISABLE_PRDR
-      (1<<ACL_WHERE_PRDR)|
+         (1<<ACL_WHERE_PRDR)|
 #endif
-      (1<<ACL_WHERE_MIME))
+         (1<<ACL_WHERE_MIME))
   },
+[CONTROL_FREEZE] =
   { US"freeze",                  TRUE,
-    (unsigned)
-    ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
-      (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
-      // (1<<ACL_WHERE_PRDR)|    /* Not allow one user to freeze for all */
-      (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_MIME))
+         (unsigned)
+         ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
+           (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
+           // (1<<ACL_WHERE_PRDR)|    /* Not allow one user to freeze for all */
+           (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_MIME))
   },
 
+[CONTROL_NO_CALLOUT_FLUSH] =
   { US"no_callout_flush",        FALSE,
-    (1<<ACL_WHERE_NOTSMTP)| (1<<ACL_WHERE_NOTSMTP_START)
+         (1<<ACL_WHERE_NOTSMTP)| (1<<ACL_WHERE_NOTSMTP_START)
   },
+[CONTROL_NO_DELAY_FLUSH] =
   { US"no_delay_flush",          FALSE,
-    (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
+         (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
   },
   
+[CONTROL_NO_ENFORCE_SYNC] =
   { US"no_enforce_sync",         FALSE,
-    (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
+         (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
   },
 #ifdef WITH_CONTENT_SCAN
+[CONTROL_NO_MBOX_UNSPOOL] =
   { US"no_mbox_unspool",         FALSE,
-    (unsigned)
-    ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
-      (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
-      // (1<<ACL_WHERE_PRDR)|    /* Not allow one user to freeze for all */
-      (1<<ACL_WHERE_MIME))
+       (unsigned)
+       ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
+         (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
+         // (1<<ACL_WHERE_PRDR)|    /* Not allow one user to freeze for all */
+         (1<<ACL_WHERE_MIME))
   },
 #endif
+[CONTROL_NO_MULTILINE] =
   { US"no_multiline_responses",  FALSE,
-    (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
+         (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
   },
+[CONTROL_NO_PIPELINING] =
   { US"no_pipelining",           FALSE,
-    (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
+         (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_NOTSMTP_START)
   },
 
+[CONTROL_QUEUE_ONLY] =
   { US"queue_only",              FALSE,
-    (unsigned)
-    ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
-      (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
-      // (1<<ACL_WHERE_PRDR)|    /* Not allow one user to freeze for all */
-      (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_MIME))
+         (unsigned)
+         ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|
+           (1<<ACL_WHERE_PREDATA)|(1<<ACL_WHERE_DATA)|
+           // (1<<ACL_WHERE_PRDR)|    /* Not allow one user to freeze for all */
+           (1<<ACL_WHERE_NOTSMTP)|(1<<ACL_WHERE_MIME))
   },
+[CONTROL_SUBMISSION] =
   { US"submission",              TRUE,
-    (unsigned)
-    ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|(1<<ACL_WHERE_PREDATA))
+         (unsigned)
+         ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|(1<<ACL_WHERE_PREDATA))
   },
+[CONTROL_SUPPRESS_LOCAL_FIXUPS] =
   { US"suppress_local_fixups",   FALSE,
     (unsigned)
     ~((1<<ACL_WHERE_MAIL)|(1<<ACL_WHERE_RCPT)|(1<<ACL_WHERE_PREDATA)|
       (1<<ACL_WHERE_NOTSMTP_START))
   },
 #ifdef SUPPORT_I18N
+[CONTROL_UTF8_DOWNCONVERT] =
   { US"utf8_downconvert",        TRUE, 0 }
 #endif
 };
@@ -532,24 +556,36 @@ further ACL conditions to distinguish ok, unknown, and defer if required, but
 the aim is to make the usual configuration simple. */
 
 static int csa_return_code[] = {
-  OK, OK, OK, OK,
-  FAIL, FAIL, FAIL, FAIL
+  [CSA_UNKNOWN] =      OK,
+  [CSA_OK] =           OK,
+  [CSA_DEFER_SRV] =    OK,
+  [CSA_DEFER_ADDR] =   OK,
+  [CSA_FAIL_EXPLICIT] =        FAIL,
+  [CSA_FAIL_DOMAIN] =  FAIL,
+  [CSA_FAIL_NOADDR] =  FAIL,
+  [CSA_FAIL_MISMATCH] =        FAIL
 };
 
 static uschar *csa_status_string[] = {
-  US"unknown", US"ok", US"defer", US"defer",
-  US"fail", US"fail", US"fail", US"fail"
+  [CSA_UNKNOWN] =      US"unknown",
+  [CSA_OK] =           US"ok",
+  [CSA_DEFER_SRV] =    US"defer",
+  [CSA_DEFER_ADDR] =   US"defer",
+  [CSA_FAIL_EXPLICIT] =        US"fail",
+  [CSA_FAIL_DOMAIN] =  US"fail",
+  [CSA_FAIL_NOADDR] =  US"fail",
+  [CSA_FAIL_MISMATCH] =        US"fail"
 };
 
 static uschar *csa_reason_string[] = {
-  US"unknown",
-  US"ok",
-  US"deferred (SRV lookup failed)",
-  US"deferred (target address lookup failed)",
-  US"failed (explicit authorization required)",
-  US"failed (host name not authorized)",
-  US"failed (no authorized addresses)",
-  US"failed (client address mismatch)"
+  [CSA_UNKNOWN] =      US"unknown",
+  [CSA_OK] =           US"ok",
+  [CSA_DEFER_SRV] =    US"deferred (SRV lookup failed)",
+  [CSA_DEFER_ADDR] =   US"deferred (target address lookup failed)",
+  [CSA_FAIL_EXPLICIT] =        US"failed (explicit authorization required)",
+  [CSA_FAIL_DOMAIN] =  US"failed (host name not authorized)",
+  [CSA_FAIL_NOADDR] =  US"failed (no authorized addresses)",
+  [CSA_FAIL_MISMATCH] =        US"failed (client address mismatch)"
 };
 
 /* Options for the ratelimit condition. Note that there are two variants of
@@ -567,8 +603,15 @@ enum {
   (((var) == RATE_PER_WHAT) ? ((var) = RATE_##new) : ((var) = RATE_PER_CLASH))
 
 static uschar *ratelimit_option_string[] = {
-  US"?", US"!", US"per_addr", US"per_byte", US"per_cmd",
-  US"per_conn", US"per_mail", US"per_rcpt", US"per_rcpt"
+  [RATE_PER_WHAT] =    US"?",
+  [RATE_PER_CLASH] =   US"!",
+  [RATE_PER_ADDR] =    US"per_addr",
+  [RATE_PER_BYTE] =    US"per_byte",
+  [RATE_PER_CMD] =     US"per_cmd",
+  [RATE_PER_CONN] =    US"per_conn",
+  [RATE_PER_MAIL] =    US"per_mail",
+  [RATE_PER_RCPT] =    US"per_rcpt",
+  [RATE_PER_ALLRCPTS] =        US"per_rcpt"
 };
 
 /* Enable recursion between acl_check_internal() and acl_check_condition() */
@@ -1097,7 +1140,7 @@ if (log_message != NULL && log_message != user_message)
     int length = Ustrlen(text) + 1;
     log_write(0, LOG_MAIN, "%s", text);
     logged = store_malloc(sizeof(string_item) + length);
-    logged->text = (uschar *)logged + sizeof(string_item);
+    logged->text = US logged + sizeof(string_item);
     memcpy(logged->text, text, length);
     logged->next = acl_warn_logged;
     acl_warn_logged = logged;
@@ -1482,6 +1525,7 @@ typedef struct {
   unsigned alt_opt_sep;                /* >0 Non-/ option separator (custom parser) */
   } verify_type_t;
 static verify_type_t verify_type_list[] = {
+    /* name                    value                   where   no-opt opt-sep */
     { US"reverse_host_lookup", VERIFY_REV_HOST_LKUP,   ~0,     FALSE, 0 },
     { US"certificate",         VERIFY_CERT,            ~0,     TRUE, 0 },
     { US"helo",                        VERIFY_HELO,            ~0,     TRUE, 0 },
@@ -1500,7 +1544,7 @@ static verify_type_t verify_type_list[] = {
 enum { CALLOUT_DEFER_OK, CALLOUT_NOCACHE, CALLOUT_RANDOM, CALLOUT_USE_SENDER,
   CALLOUT_USE_POSTMASTER, CALLOUT_POSTMASTER, CALLOUT_FULLPOSTMASTER,
   CALLOUT_MAILFROM, CALLOUT_POSTMASTER_MAILFROM, CALLOUT_MAXWAIT, CALLOUT_CONNECT,
-  CALLOUT_TIME
+  CALLOUT_HOLD, CALLOUT_TIME   /* TIME must be last */
   };
 typedef struct {
   uschar * name;
@@ -1510,6 +1554,7 @@ typedef struct {
   BOOL     timeval;    /* Has a time value */
   } callout_opt_t;
 static callout_opt_t callout_opt_list[] = {
+    /* name                    value                   flag            has-opt         has-time */
     { US"defer_ok",      CALLOUT_DEFER_OK,      0,                             FALSE, FALSE },
     { US"no_cache",      CALLOUT_NOCACHE,       vopt_callout_no_cache,         FALSE, FALSE },
     { US"random",        CALLOUT_RANDOM,        vopt_callout_random,           FALSE, FALSE },
@@ -1521,6 +1566,7 @@ static callout_opt_t callout_opt_list[] = {
     { US"mailfrom",      CALLOUT_MAILFROM,      0,                             TRUE,  FALSE },
     { US"maxwait",       CALLOUT_MAXWAIT,       0,                             TRUE,  TRUE },
     { US"connect",       CALLOUT_CONNECT,       0,                             TRUE,  TRUE },
+    { US"hold",                  CALLOUT_HOLD,          vopt_callout_hold,             FALSE, FALSE },
     { NULL,              CALLOUT_TIME,          0,                             FALSE, TRUE }
   };
 
@@ -1579,13 +1625,13 @@ if (ss == NULL) goto BAD_VERIFY;
 /* Handle name/address consistency verification in a separate function. */
 
 for (vp= verify_type_list;
-     (char *)vp < (char *)verify_type_list + sizeof(verify_type_list);
+     CS vp < CS verify_type_list + sizeof(verify_type_list);
      vp++
     )
   if (vp->alt_opt_sep ? strncmpic(ss, vp->name, vp->alt_opt_sep) == 0
                       : strcmpic (ss, vp->name) == 0)
    break;
-if ((char *)vp >= (char *)verify_type_list + sizeof(verify_type_list))
+if (CS vp >= CS verify_type_list + sizeof(verify_type_list))
   goto BAD_VERIFY;
 
 if (vp->no_options && slash != NULL)
@@ -1744,8 +1790,7 @@ while ((ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size))
         uschar buffer[256];
         while (isspace(*sublist)) sublist++;
 
-        while ((opt = string_nextinlist(&sublist, &optsep, buffer, sizeof(buffer)))
-              != NULL)
+        while ((opt = string_nextinlist(&sublist, &optsep, buffer, sizeof(buffer))))
           {
          callout_opt_t * op;
          double period = 1.0F;
@@ -1767,15 +1812,11 @@ while ((ss = string_nextinlist(&list, &sep, big_buffer, big_buffer_size))
               }
             while (isspace(*opt)) opt++;
            }
-         if (op->timeval)
+         if (op->timeval && (period = readconf_readtime(opt, 0, FALSE)) < 0)
            {
-            period = readconf_readtime(opt, 0, FALSE);
-            if (period < 0)
-              {
-              *log_msgptr = string_sprintf("bad time value in ACL condition "
-                "\"verify %s\"", arg);
-              return ERROR;
-              }
+           *log_msgptr = string_sprintf("bad time value in ACL condition "
+             "\"verify %s\"", arg);
+           return ERROR;
            }
 
          switch(op->value)
@@ -2356,8 +2397,7 @@ if (t != NULL)
 /* We aren't using a pre-computed rate, so get a previously recorded rate
 from the database, which will be updated and written back if required. */
 
-dbm = dbfn_open(US"ratelimit", O_RDWR, &dbblock, TRUE);
-if (dbm == NULL)
+if (!(dbm = dbfn_open(US"ratelimit", O_RDWR, &dbblock, TRUE)))
   {
   store_pool = old_pool;
   sender_rate = NULL;
@@ -2731,8 +2771,9 @@ if (r == HOST_FIND_FAILED || r == HOST_FIND_AGAIN)
 HDEBUG(D_acl)
   debug_printf_indent("udpsend [%s]:%d %s\n", h->address, portnum, arg);
 
+/*XXX this could better use sendto */
 r = s = ip_connectedsocket(SOCK_DGRAM, h->address, portnum, portnum,
-               1, NULL, &errstr);
+               1, NULL, &errstr, NULL);
 if (r < 0) goto defer;
 len = Ustrlen(arg);
 r = send(s, arg, len, 0);
@@ -3069,7 +3110,7 @@ for (; cb != NULL; cb = cb->next)
        break;
 
        case CONTROL_FAKEREJECT:
-       cancel_cutthrough_connection("fakereject");
+       cancel_cutthrough_connection(TRUE, US"fakereject");
        case CONTROL_FAKEDEFER:
        fake_response = (control_type == CONTROL_FAKEDEFER) ? DEFER : FAIL;
        if (*p == '/')
@@ -3100,12 +3141,12 @@ for (; cb != NULL; cb = cb->next)
          *log_msgptr = string_sprintf("syntax error in \"control=%s\"", arg);
          return ERROR;
          }
-       cancel_cutthrough_connection("item frozen");
+       cancel_cutthrough_connection(TRUE, US"item frozen");
        break;
 
        case CONTROL_QUEUE_ONLY:
        queue_only_policy = TRUE;
-       cancel_cutthrough_connection("queueing forced");
+       cancel_cutthrough_connection(TRUE, US"queueing forced");
        break;
 
        case CONTROL_SUBMISSION:
@@ -3534,7 +3575,7 @@ for (; cb != NULL; cb = cb->next)
     break;
 
     case ACLC_RECIPIENTS:
-    rc = match_address_list((const uschar *)addr->address, TRUE, TRUE, &arg, NULL, -1, 0,
+    rc = match_address_list(CUS addr->address, TRUE, TRUE, &arg, NULL, -1, 0,
       CUSS &recipient_data);
     break;
 
@@ -3552,14 +3593,14 @@ for (; cb != NULL; cb = cb->next)
       {
       uschar *sdomain;
       sdomain = Ustrrchr(sender_address, '@');
-      sdomain = (sdomain == NULL)? US"" : sdomain + 1;
+      sdomain = sdomain ? sdomain + 1 : US"";
       rc = match_isinlist(sdomain, &arg, 0, &domainlist_anchor,
         sender_domain_cache, MCL_DOMAIN, TRUE, NULL);
       }
     break;
 
     case ACLC_SENDERS:
-    rc = match_address_list((const uschar *)sender_address, TRUE, TRUE, &arg,
+    rc = match_address_list(CUS sender_address, TRUE, TRUE, &arg,
       sender_address_cache, -1, 0, CUSS &sender_data);
     break;
 
@@ -4334,8 +4375,9 @@ switch (where)
 #ifndef DISABLE_PRDR
   case ACL_WHERE_PRDR:
 #endif
+
     if (host_checking_callout) /* -bhc mode */
-      cancel_cutthrough_connection("host-checking mode");
+      cancel_cutthrough_connection(TRUE, US"host-checking mode");
 
     else if (  rc == OK
            && cutthrough.delivery
@@ -4362,13 +4404,20 @@ switch (where)
     if (rc == OK)
       cutthrough_predata();
     else
-      cancel_cutthrough_connection("predata acl not ok");
+      cancel_cutthrough_connection(TRUE, US"predata acl not ok");
     break;
 
   case ACL_WHERE_QUIT:
   case ACL_WHERE_NOTQUIT:
-    cancel_cutthrough_connection("quit or notquit");
+    /* Drop cutthrough conns, and drop heldopen verify conns if
+    the previous was not DATA */
+    {
+    uschar prev = smtp_connection_had[smtp_ch_index-2];
+    BOOL dropverify = !(prev == SCH_DATA || prev == SCH_BDAT);
+
+    cancel_cutthrough_connection(dropverify, US"quit or conndrop");
     break;
+    }
 
   default:
     break;
index d1df7f2cb66eb1c02039c282d2d4c159e6d1bf6b..6bc3d1f637e6a96da03e0dfd083f4a76f8e5a762 100644 (file)
@@ -83,8 +83,8 @@ int main (int argc, char ** argv)
 
        challenge_str = argv [3];
 
-       if (spa_base64_to_bits ((char *)&challenge, sizeof(challenge),
-                (const char *)(challenge_str))<0)
+       if (spa_base64_to_bits (CS &challenge, sizeof(challenge),
+                CCS (challenge_str))<0)
        {
                 printf("bad base64 data in challenge: %s\n", challenge_str);
                 exit (1);
@@ -229,10 +229,10 @@ extern int DEBUGLEVEL;
 */
 
 /* get single value from an SMB buffer */
-#  define SVAL(buf,pos) (*(uint16x *)((char *)(buf) + (pos)))
-#  define IVAL(buf,pos) (*(uint32x *)((char *)(buf) + (pos)))
-#  define SVALS(buf,pos) (*(int16x *)((char *)(buf) + (pos)))
-#  define IVALS(buf,pos) (*(int32x *)((char *)(buf) + (pos)))
+#  define SVAL(buf,pos) (*(uint16x *)(CS (buf) + (pos)))
+#  define IVAL(buf,pos) (*(uint32x *)(CS (buf) + (pos)))
+#  define SVALS(buf,pos) (*(int16x *)(CS (buf) + (pos)))
+#  define IVALS(buf,pos) (*(int32x *)(CS (buf) + (pos)))
 
 /* store single value in an SMB buffer */
 #  define SSVAL(buf,pos,val) SVAL(buf,pos)=((uint16x)(val))
@@ -856,18 +856,18 @@ spa_smb_encrypt (uschar * passwd, uschar * c8, uschar * p24)
 
   memset (p21, '\0', 21);
   memset (p14, '\0', 14);
-  StrnCpy ((char *) p14, (char *) passwd, 14);
+  StrnCpy (CS  p14, CS  passwd, 14);
 
-  strupper ((char *) p14);
+  strupper (CS  p14);
   E_P16 (p14, p21);
 
   SMBOWFencrypt (p21, c8, p24);
 
 #ifdef DEBUG_PASSWORD
   DEBUG_X (100, ("spa_smb_encrypt: lm#, challenge, response\n"));
-  dump_data (100, (char *) p21, 16);
-  dump_data (100, (char *) c8, 8);
-  dump_data (100, (char *) p24, 24);
+  dump_data (100, CS  p21, 16);
+  dump_data (100, CS  c8, 8);
+  dump_data (100, CS  p24, 24);
 #endif
 }
 
@@ -917,7 +917,7 @@ E_md4hash (uschar * passwd, uschar * p16)
   int16x wpwd[129];
 
   /* Password cannot be longer than 128 characters */
-  len = strlen ((char *) passwd);
+  len = strlen (CS  passwd);
   if (len > 128)
     len = 128;
   /* Password must be converted to NT unicode */
@@ -945,7 +945,7 @@ nt_lm_owf_gen (char *pwd, uschar nt_p16[16], uschar p16[16])
 #ifdef DEBUG_PASSWORD
   DEBUG_X (100, ("nt_lm_owf_gen: pwd, nt#\n"));
   dump_data (120, passwd, strlen (passwd));
-  dump_data (100, (char *) nt_p16, 16);
+  dump_data (100, CS  nt_p16, 16);
 #endif
 
   /* Mangle the passwords into Lanman format */
@@ -960,7 +960,7 @@ nt_lm_owf_gen (char *pwd, uschar nt_p16[16], uschar p16[16])
 #ifdef DEBUG_PASSWORD
   DEBUG_X (100, ("nt_lm_owf_gen: pwd, lm#\n"));
   dump_data (120, passwd, strlen (passwd));
-  dump_data (100, (char *) p16, 16);
+  dump_data (100, CS  p16, 16);
 #endif
   /* clear out local copy of user's password (just being paranoid). */
   memset (passwd, '\0', sizeof (passwd));
@@ -991,9 +991,9 @@ NTLMSSPOWFencrypt (uschar passwd[8], uschar * ntlmchalresp, uschar p24[24])
   E_P24 (p21, ntlmchalresp, p24);
 #ifdef DEBUG_PASSWORD
   DEBUG_X (100, ("NTLMSSPOWFencrypt: p21, c8, p24\n"));
-  dump_data (100, (char *) p21, 21);
-  dump_data (100, (char *) ntlmchalresp, 8);
-  dump_data (100, (char *) p24, 24);
+  dump_data (100, CS  p21, 21);
+  dump_data (100, CS  ntlmchalresp, 8);
+  dump_data (100, CS  p24, 24);
 #endif
 }
 
@@ -1012,9 +1012,9 @@ spa_smb_nt_encrypt (uschar * passwd, uschar * c8, uschar * p24)
 
 #ifdef DEBUG_PASSWORD
   DEBUG_X (100, ("spa_smb_nt_encrypt: nt#, challenge, response\n"));
-  dump_data (100, (char *) p21, 16);
-  dump_data (100, (char *) c8, 8);
-  dump_data (100, (char *) p24, 24);
+  dump_data (100, CS  p21, 16);
+  dump_data (100, CS  c8, 8);
+  dump_data (100, CS  p24, 24);
 #endif
 }
 
@@ -1261,7 +1261,7 @@ spa_bytes_add(ptr, header, b, len*2); \
 #define GetUnicodeString(structPtr, header) \
 unicodeToString(((char*)structPtr) + IVAL(&structPtr->header.offset,0) , SVAL(&structPtr->header.len,0)/2)
 #define GetString(structPtr, header) \
-toString((((char *)structPtr) + IVAL(&structPtr->header.offset,0)), SVAL(&structPtr->header.len,0))
+toString(((CS structPtr) + IVAL(&structPtr->header.offset,0)), SVAL(&structPtr->header.len,0))
 
 #ifdef notdef
 
@@ -1503,8 +1503,8 @@ spa_build_auth_response (SPAAuthChallenge * challenge,
     }
 
   else domain = d = strdup((cf & 0x1)?
-    (const char *)GetUnicodeString(challenge, uDomain) :
-    (const char *)GetString(challenge, uDomain));
+    CCS GetUnicodeString(challenge, uDomain) :
+    CCS GetString(challenge, uDomain));
 
   spa_smb_encrypt (US password, challenge->challengeData, lmRespData);
   spa_smb_nt_encrypt (US password, challenge->challengeData, ntRespData);
index b4677ec5ae8984ec80e436d904d20af940d1bc4e..a5cbec3edffd2ac2940e7ae9652ac1236b64c54b 100644 (file)
@@ -189,7 +189,7 @@ if (pam_error == PAM_SUCCESS)
   return OK;
   }
 
-*errptr = (uschar *)pam_strerror(pamh, pam_error);
+*errptr = US pam_strerror(pamh, pam_error);
 DEBUG(D_auth) debug_printf("PAM error: %s\n", *errptr);
 
 if (pam_error == PAM_USER_UNKNOWN ||
index 1ae38a9a63b9301e6a8fb84072b8239dc1d81503..b9e57c1e9b9d0e0b77e2b5c2c1bd0a1d4ff3495c 100644 (file)
@@ -47,6 +47,17 @@ auth_cram_md5_options_block auth_cram_md5_option_defaults = {
 };
 
 
+#ifdef MACRO_PREDEF
+
+/* Dummy values */
+void auth_cram_md5_init(auth_instance *ablock) {}
+int auth_cram_md5_server(auth_instance *ablock, uschar *data) {return 0;}
+int auth_cram_md5_client(auth_instance *ablock, smtp_inblock *inblock,
+  smtp_outblock *outblock, int timeout, uschar *buffer, int buffsize) {return 0;}
+
+#else  /*!MACRO_PREDEF*/
+
+
 /*************************************************
 *          Initialization entry point            *
 *************************************************/
@@ -68,10 +79,12 @@ if (ob->client_secret != NULL)
   }
 }
 
+#endif /*!MACRO_PREDEF*/
 #endif  /* STAND_ALONE */
 
 
 
+#ifndef MACRO_PREDEF
 /*************************************************
 *      Perform the CRAM-MD5 algorithm            *
 *************************************************/
@@ -108,8 +121,8 @@ and use that. */
 if (len > 64)
   {
   md5_start(&base);
-  md5_end(&base, (uschar *)secret, len, md5secret);
-  secret = (uschar *)md5secret;
+  md5_end(&base, US secret, len, md5secret);
+  secret = US md5secret;
   len = 16;
   }
 
@@ -130,7 +143,7 @@ for (i = 0; i < 64; i++)
 
 md5_start(&base);
 md5_mid(&base, isecret);
-md5_end(&base, (uschar *)challenge, Ustrlen(challenge), md5secret);
+md5_end(&base, US challenge, Ustrlen(challenge), md5secret);
 
 /* Compute the outer MD5 digest */
 
@@ -280,7 +293,8 @@ if (!secret || !name)
 /* Initiate the authentication exchange and read the challenge, which arrives
 in base 64. */
 
-if (smtp_write_command(outblock, FALSE, "AUTH %s\r\n", ablock->public_name) < 0)
+if (smtp_write_command(outblock, SCMD_FLUSH, "AUTH %s\r\n",
+                       ablock->public_name) < 0)
   return FAIL_SEND;
 if (!smtp_read_response(inblock, buffer, buffsize, '3', timeout))
   return FAIL;
@@ -303,20 +317,17 @@ for (p = big_buffer; *p; ) p++;
 *p++ = ' ';
 
 for (i = 0; i < 16; i++)
-  {
-  sprintf(CS p, "%02x", digest[i]);
-  p += 2;
-  }
+  p += sprintf(CS p, "%02x", digest[i]);
 
 /* Send the response, in base 64, and check the result. The response is
 in big_buffer, but b64encode() returns its result in working store,
 so calling smtp_write_command(), which uses big_buffer, is OK. */
 
 buffer[0] = 0;
-if (smtp_write_command(outblock, FALSE, "%s\r\n", b64encode(big_buffer,
+if (smtp_write_command(outblock, SCMD_FLUSH, "%s\r\n", b64encode(big_buffer,
   p - big_buffer)) < 0) return FAIL_SEND;
 
-return smtp_read_response(inblock, (uschar *)buffer, buffsize, '2', timeout)
+return smtp_read_response(inblock, US buffer, buffsize, '2', timeout)
   ? OK : FAIL;
 }
 #endif  /* STAND_ALONE */
@@ -347,4 +358,5 @@ return 0;
 
 #endif
 
+#endif /*!MACRO_PREDEF*/
 /* End of cram_md5.c */
index bab2be36c4780bea78d921ef5deeace8982bf1ad..cbf2446338d8f34fedebf1e4c5a6e1d6773ed891 100644 (file)
@@ -63,6 +63,20 @@ auth_cyrus_sasl_options_block auth_cyrus_sasl_option_defaults = {
 };
 
 
+#ifdef MACRO_PREDEF
+
+/* Dummy values */
+void auth_cyrus_sasl_init(auth_instance *ablock) {}
+int auth_cyrus_sasl_server(auth_instance *ablock, uschar *data) {return 0;}
+int auth_cyrus_sasl_client(auth_instance *ablock, smtp_inblock *inblock,
+  smtp_outblock *outblock, int timeout, uschar *buffer, int buffsize) {return 0;}
+void auth_cyrus_sasl_version_report(FILE *f) {}
+
+#else   /*!MACRO_PREDEF*/
+
+
+
+
 /*************************************************
 *          Initialization entry point            *
 *************************************************/
@@ -525,6 +539,7 @@ auth_cyrus_sasl_client(
 return FAIL;
 }
 
+#endif   /*!MACRO_PREDEF*/
 #endif  /* AUTH_CYRUS_SASL */
 
 /* End of cyrus_sasl.c */
index 5bf7b9cc309d4766ba442fd75e51297c74c81511..2dcaa0e42096d660788c467452be8d7b6c71a4d0 100644 (file)
@@ -71,6 +71,19 @@ auth_dovecot_options_block auth_dovecot_option_defaults = {
 };
 
 
+
+
+#ifdef MACRO_PREDEF
+
+/* Dummy values */
+void auth_dovecot_init(auth_instance *ablock) {}
+int auth_dovecot_server(auth_instance *ablock, uschar *data) {return 0;}
+int auth_dovecot_client(auth_instance *ablock, smtp_inblock *inblock,
+  smtp_outblock *outblock, int timeout, uschar *buffer, int buffsize) {return 0;}
+
+#else   /*!MACRO_PREDEF*/
+
+
 /* Static variables for reading from the socket */
 
 static uschar sbuffer[256];
@@ -380,7 +393,7 @@ fprintf(f, "VERSION\t%d\t%d\r\nSERVICE\tSMTP\r\nCPID\t%d\r\n"
        "AUTH\t%d\t%s\trip=%s\tlip=%s\tresp=%s\r\n",
        VERSION_MAJOR, VERSION_MINOR, getpid(), cuid,
        ablock->public_name, sender_host_address, interface_address,
-       data ? (char *) data : "");
+       data ? CS  data : "");
 
 Subsequently, the command was modified to add "secured" and "valid-client-
 cert" when relevant.
@@ -495,3 +508,6 @@ if (fd >= 0)
 /* Expand server_condition as an authorization check */
 return ret == OK ? auth_check_serv_cond(ablock) : ret;
 }
+
+
+#endif   /*!MACRO_PREDEF*/
index 11bc581b9b75038cfe6dfe46df7bd42b55e97a6f..3857e07389d3563fb3f4a5b04131ba9120474d2d 100644 (file)
@@ -30,7 +30,7 @@ auth_get_data(uschar **aptr, uschar *challenge, int challen)
 {
 int c;
 int p = 0;
-smtp_printf("334 %s\r\n", b64encode(challenge, challen));
+smtp_printf("334 %s\r\n", FALSE, b64encode(challenge, challen));
 while ((c = receive_getc(GETC_BUFFER_UNLIMITED)) != '\n' && c != EOF)
   {
   if (p >= big_buffer_size - 1) return BAD64;
index 71e71394ceedb4e05f8f214bcc23ee179e742984..1bb611c1c9d095c525b931e42f44bd6c44a71997 100644 (file)
@@ -31,7 +31,7 @@ auth_get_no64_data(uschar **aptr, uschar *challenge)
 {
 int c;
 int p = 0;
-smtp_printf("334 %s\r\n", challenge);
+smtp_printf("334 %s\r\n", FALSE, challenge);
 while ((c = receive_getc(GETC_BUFFER_UNLIMITED)) != '\n' && c != EOF)
   {
   if (p >= big_buffer_size - 1) return BAD64;
index 77db2e7757563173210a72bcb6573f950f870867..48621a402a349427f6239c5114cfd8bfcc41a722 100644 (file)
@@ -78,6 +78,20 @@ auth_gsasl_options_block auth_gsasl_option_defaults = {
   FALSE                     /* server_channelbinding */
 };
 
+
+#ifdef MACRO_PREDEF
+
+/* Dummy values */
+void auth_gsasl_init(auth_instance *ablock) {}
+int auth_gsasl_server(auth_instance *ablock, uschar *data) {return 0;}
+int auth_gsasl_client(auth_instance *ablock, smtp_inblock *inblock,
+  smtp_outblock *outblock, int timeout, uschar *buffer, int buffsize) {return 0;}
+void auth_gsasl_version_report(FILE *f) {}
+
+#else   /*!MACRO_PREDEF*/
+
+
+
 /* "Globals" for managing the gsasl interface. */
 
 static Gsasl *gsasl_ctx = NULL;
@@ -143,7 +157,7 @@ auth_gsasl_init(auth_instance *ablock)
               ablock->name,  gsasl_strerror_name(rc), gsasl_strerror(rc));
   HDEBUG(D_auth) debug_printf("GNU SASL supports: %s\n", p);
 
-  supported = gsasl_client_support_p(gsasl_ctx, (const char *)ob->server_mech);
+  supported = gsasl_client_support_p(gsasl_ctx, CCS ob->server_mech);
   if (!supported)
     log_write(0, LOG_PANIC_DIE|LOG_CONFIG_FOR, "%s authenticator:  "
               "GNU SASL does not support mechanism \"%s\"",
@@ -244,7 +258,7 @@ auth_gsasl_server(auth_instance *ablock, uschar *initial_data)
     debug_printf("GNU SASL: initialising session for %s, mechanism %s.\n",
         ablock->name, ob->server_mech);
 
-  rc = gsasl_server_start(gsasl_ctx, (const char *)ob->server_mech, &sctx);
+  rc = gsasl_server_start(gsasl_ctx, CCS ob->server_mech, &sctx);
   if (rc != GSASL_OK) {
     auth_defer_msg = string_sprintf("GNU SASL: session start failure: %s (%s)",
         gsasl_strerror_name(rc), gsasl_strerror(rc));
@@ -294,7 +308,7 @@ auth_gsasl_server(auth_instance *ablock, uschar *initial_data)
       HDEBUG(D_auth) debug_printf("Auth %s: Enabling channel-binding\n",
           ablock->name);
       gsasl_property_set(sctx, GSASL_CB_TLS_UNIQUE,
-          (const char *) tls_channelbinding_b64);
+          CCS  tls_channelbinding_b64);
     } else {
       HDEBUG(D_auth)
         debug_printf("Auth %s: Not enabling channel-binding (data available)\n",
@@ -355,7 +369,7 @@ auth_gsasl_server(auth_instance *ablock, uschar *initial_data)
     if ((rc == GSASL_NEEDS_MORE) ||
         (to_send && *to_send))
       exim_error =
-        auth_get_no64_data((uschar **)&received, (uschar *)to_send);
+        auth_get_no64_data((uschar **)&received, US to_send);
 
     if (to_send) {
       free(to_send);
@@ -435,11 +449,11 @@ server_callback(Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop, auth_insta
   switch (prop) {
     case GSASL_VALIDATE_SIMPLE:
       /* GSASL_AUTHID, GSASL_AUTHZID, and GSASL_PASSWORD */
-      propval = (uschar *) gsasl_property_fast(sctx, GSASL_AUTHID);
+      propval = US  gsasl_property_fast(sctx, GSASL_AUTHID);
       auth_vars[0] = expand_nstring[1] = propval ? propval : US"";
-      propval = (uschar *) gsasl_property_fast(sctx, GSASL_AUTHZID);
+      propval = US  gsasl_property_fast(sctx, GSASL_AUTHZID);
       auth_vars[1] = expand_nstring[2] = propval ? propval : US"";
-      propval = (uschar *) gsasl_property_fast(sctx, GSASL_PASSWORD);
+      propval = US  gsasl_property_fast(sctx, GSASL_PASSWORD);
       auth_vars[2] = expand_nstring[3] = propval ? propval : US"";
       expand_nmax = 3;
       for (i = 1; i <= 3; ++i)
@@ -455,7 +469,7 @@ server_callback(Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop, auth_insta
         cbrc = GSASL_AUTHENTICATION_ERROR;
         break;
       }
-      propval = (uschar *) gsasl_property_fast(sctx, GSASL_AUTHZID);
+      propval = US  gsasl_property_fast(sctx, GSASL_AUTHZID);
       /* We always set $auth1, even if only to empty string. */
       auth_vars[0] = expand_nstring[1] = propval ? propval : US"";
       expand_nlength[1] = Ustrlen(expand_nstring[1]);
@@ -472,7 +486,7 @@ server_callback(Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop, auth_insta
         cbrc = GSASL_AUTHENTICATION_ERROR;
         break;
       }
-      propval = (uschar *) gsasl_property_fast(sctx, GSASL_ANONYMOUS_TOKEN);
+      propval = US  gsasl_property_fast(sctx, GSASL_ANONYMOUS_TOKEN);
       /* We always set $auth1, even if only to empty string. */
       auth_vars[0] = expand_nstring[1] = propval ? propval : US"";
       expand_nlength[1] = Ustrlen(expand_nstring[1]);
@@ -493,9 +507,9 @@ server_callback(Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop, auth_insta
       First coding, we had these values swapped, but for consistency and prior
       to the first release of Exim with this authenticator, they've been
       switched to match the ordering of GSASL_VALIDATE_SIMPLE. */
-      propval = (uschar *) gsasl_property_fast(sctx, GSASL_GSSAPI_DISPLAY_NAME);
+      propval = US  gsasl_property_fast(sctx, GSASL_GSSAPI_DISPLAY_NAME);
       auth_vars[0] = expand_nstring[1] = propval ? propval : US"";
-      propval = (uschar *) gsasl_property_fast(sctx, GSASL_AUTHZID);
+      propval = US  gsasl_property_fast(sctx, GSASL_AUTHZID);
       auth_vars[1] = expand_nstring[2] = propval ? propval : US"";
       expand_nmax = 2;
       for (i = 1; i <= 2; ++i)
@@ -528,11 +542,11 @@ server_callback(Gsasl *ctx, Gsasl_session *sctx, Gsasl_property prop, auth_insta
       a new mechanism is added to the library.  It *shouldn't* result in us
       needing to add more glue, since avoiding that is a large part of the
       point of SASL. */
-      propval = (uschar *) gsasl_property_fast(sctx, GSASL_AUTHID);
+      propval = US  gsasl_property_fast(sctx, GSASL_AUTHID);
       auth_vars[0] = expand_nstring[1] = propval ? propval : US"";
-      propval = (uschar *) gsasl_property_fast(sctx, GSASL_AUTHZID);
+      propval = US  gsasl_property_fast(sctx, GSASL_AUTHZID);
       auth_vars[1] = expand_nstring[2] = propval ? propval : US"";
-      propval = (uschar *) gsasl_property_fast(sctx, GSASL_REALM);
+      propval = US  gsasl_property_fast(sctx, GSASL_REALM);
       auth_vars[2] = expand_nstring[3] = propval ? propval : US"";
       expand_nmax = 3;
       for (i = 1; i <= 3; ++i)
@@ -614,6 +628,7 @@ auth_gsasl_version_report(FILE *f)
           GSASL_VERSION, runtime);
 }
 
+#endif   /*!MACRO_PREDEF*/
 #endif  /* AUTH_GSASL */
 
 /* End of gsasl_exim.c */
index 732a6738180d9006bd45bd1b05c70d29bf6441f4..03a4bec799c06d749e6b8f3b41e9e9712e9d230f 100644 (file)
@@ -76,6 +76,20 @@ auth_heimdal_gssapi_options_block auth_heimdal_gssapi_option_defaults = {
   US"smtp",                 /* server_service */
 };
 
+
+#ifdef MACRO_PREDEF
+
+/* Dummy values */
+void auth_heimdal_init(auth_instance *ablock) {}
+int auth_heimdal_server(auth_instance *ablock, uschar *data) {return 0;}
+int auth_heimdal_client(auth_instance *ablock, smtp_inblock *inblock,
+  smtp_outblock *outblock, int timeout, uschar *buffer, int buffsize) {return 0;}
+void auth_heimdal_gssapi_version_report(FILE *f) {}
+
+#else   /*!MACRO_PREDEF*/
+
+
+
 /* "Globals" for managing the heimdal_gssapi interface. */
 
 /* Utility functions */
@@ -590,6 +604,7 @@ auth_heimdal_gssapi_version_report(FILE *f)
           heimdal_version, heimdal_long_version);
 }
 
+#endif   /*!MACRO_PREDEF*/
 #endif  /* AUTH_HEIMDAL_GSSAPI */
 
 /* End of heimdal_gssapi.c */
index 25655e9ba0756469a9d1d8cfd61c106ee0d01b88..71b8c9952626a5437736f12067e0448b7ca5ba6b 100644 (file)
@@ -334,7 +334,7 @@ int main(void)
 {
 md5 base;
 int i = 0x01020304;
-uschar *ctest = (uschar *)(&i);
+uschar *ctest = US (&i);
 uschar buffer[256];
 uschar digest[16];
 printf("Checking md5: %s-endian\n", (ctest[0] == 0x04)? "little" : "big");
index 161aab6c05cbdb7b3ca70c580d7e9ed85a71370f..8bba05823ed79bf5512ad69724497cd717030b45 100644 (file)
@@ -35,6 +35,18 @@ auth_plaintext_options_block auth_plaintext_option_defaults = {
 };
 
 
+#ifdef MACRO_PREDEF
+
+/* Dummy values */
+void auth_plaintext_init(auth_instance *ablock) {}
+int auth_plaintext_server(auth_instance *ablock, uschar *data) {return 0;}
+int auth_plaintext_client(auth_instance *ablock, smtp_inblock *inblock,
+  smtp_outblock *outblock, int timeout, uschar *buffer, int buffsize) {return 0;}
+
+#else   /*!MACRO_PREDEF*/
+
+
+
 /*************************************************
 *          Initialization entry point            *
 *************************************************/
@@ -173,7 +185,7 @@ int auth_var_idx = 0;
 sent one by one. The first one is sent with the AUTH command; the remainder are
 sent in response to subsequent prompts. Each is expanded before being sent. */
 
-while ((s = string_nextinlist(&text, &sep, big_buffer, big_buffer_size)) != NULL)
+while ((s = string_nextinlist(&text, &sep, big_buffer, big_buffer_size)))
   {
   int i, len, clear_len;
   uschar *ss = expand_string(s);
@@ -184,12 +196,12 @@ while ((s = string_nextinlist(&text, &sep, big_buffer, big_buffer_size)) != NULL
   sending a line containing "*". Save the failed expansion string, because it
   is in big_buffer, and that gets used by the sending function. */
 
-  if (ss == NULL)
+  if (!ss)
     {
     uschar *ssave = string_copy(s);
     if (!first)
       {
-      if (smtp_write_command(outblock, FALSE, "*\r\n") >= 0)
+      if (smtp_write_command(outblock, SCMD_FLUSH, "*\r\n") >= 0)
         (void) smtp_read_response(inblock, US buffer, buffsize, '2', timeout);
       }
     if (expand_string_forcedfail)
@@ -208,17 +220,15 @@ while ((s = string_nextinlist(&text, &sep, big_buffer, big_buffer_size)) != NULL
   needed for the PLAIN mechanism. It must be doubled if really needed. */
 
   for (i = 0; i < len; i++)
-    {
     if (ss[i] == '^')
-      {
-      if (ss[i+1] != '^') ss[i] = 0; else
+      if (ss[i+1] != '^')
+       ss[i] = 0;
+      else
         {
         i++;
         len--;
         memmove(ss + i, ss + i + 1, len - i);
         }
-      }
-    }
 
   /* The first string is attached to the AUTH command; others are sent
   unembellished. */
@@ -226,14 +236,14 @@ while ((s = string_nextinlist(&text, &sep, big_buffer, big_buffer_size)) != NULL
   if (first)
     {
     first = FALSE;
-    if (smtp_write_command(outblock, FALSE, "AUTH %s%s%s\r\n",
+    if (smtp_write_command(outblock, SCMD_FLUSH, "AUTH %s%s%s\r\n",
          ablock->public_name, (len == 0)? "" : " ",
          b64encode(ss, len)) < 0)
       return FAIL_SEND;
     }
   else
     {
-    if (smtp_write_command(outblock, FALSE, "%s\r\n",
+    if (smtp_write_command(outblock, SCMD_FLUSH, "%s\r\n",
           b64encode(ss, len)) < 0)
       return FAIL_SEND;
     }
@@ -255,7 +265,7 @@ while ((s = string_nextinlist(&text, &sep, big_buffer, big_buffer_size)) != NULL
 
   if (text == NULL)
     {
-    if (smtp_write_command(outblock, FALSE, "*\r\n") >= 0)
+    if (smtp_write_command(outblock, SCMD_FLUSH, "*\r\n") >= 0)
       (void)smtp_read_response(inblock, US buffer, buffsize, '2', timeout);
     string_format(buffer, buffsize, "Too few items in client_send in %s "
       "authenticator", ablock->name);
@@ -277,7 +287,7 @@ while ((s = string_nextinlist(&text, &sep, big_buffer, big_buffer_size)) != NULL
     uschar *save_bad = string_copy(buffer);
     if (!ob->client_ignore_invalid_base64)
       {
-      if (smtp_write_command(outblock, FALSE, "*\r\n") >= 0)
+      if (smtp_write_command(outblock, SCMD_FLUSH, "*\r\n") >= 0)
         (void)smtp_read_response(inblock, US buffer, buffsize, '2', timeout);
       string_format(buffer, buffsize, "Invalid base64 string in server "
         "response \"%s\"", save_bad);
@@ -296,4 +306,5 @@ while ((s = string_nextinlist(&text, &sep, big_buffer, big_buffer_size)) != NULL
 return FAIL;
 }
 
+#endif   /*!MACRO_PREDEF*/
 /* End of plaintext.c */
index 645265daa0874fdd83706a2397ac36aa5f72b966..54ba80f92ab9881e92c1ffde53e1ed7a2786b56b 100644 (file)
@@ -113,7 +113,7 @@ return PWCHECK_FAIL;
      s = socket(AF_UNIX, SOCK_STREAM, 0);
      if (s == -1) { return PWCHECK_FAIL; }
 
-     memset((char *)&srvaddr, 0, sizeof(srvaddr));
+     memset(CS &srvaddr, 0, sizeof(srvaddr));
      srvaddr.sun_family = AF_UNIX;
      strncpy(srvaddr.sun_path, CYRUS_PWCHECK_SOCKET, sizeof(srvaddr.sun_path));
      r = connect(s, (struct sockaddr *)&srvaddr, sizeof(srvaddr));
@@ -124,9 +124,9 @@ return PWCHECK_FAIL;
        return PWCHECK_FAIL;
      }
 
-     iov[0].iov_base = (char *)userid;
+     iov[0].iov_base = CS userid;
      iov[0].iov_len = strlen(userid)+1;
-     iov[1].iov_base = (char *)passwd;
+     iov[1].iov_base = CS passwd;
      iov[1].iov_len = strlen(passwd)+1;
 
      retry_writev(s, iov, 2);
@@ -200,7 +200,7 @@ int saslauthd_verify_password(const uschar *userid,
        return PWCHECK_FAIL;
     }
 
-    memset((char *)&srvaddr, 0, sizeof(srvaddr));
+    memset(CS &srvaddr, 0, sizeof(srvaddr));
     srvaddr.sun_family = AF_UNIX;
     strncpy(srvaddr.sun_path, CYRUS_SASLAUTHD_SOCKET,
             sizeof(srvaddr.sun_path));
@@ -343,7 +343,7 @@ static int retry_read(int fd, void *inbuf, unsigned nbyte)
 {
     int n;
     int nread = 0;
-    char *buf = (char *)inbuf;
+    char *buf = CS inbuf;
 
     if (nbyte == 0) return 0;
 
@@ -432,7 +432,7 @@ retry_writev (
 
        for (i = 0; i < iovcnt; i++) {
            if (iov[i].iov_len > (unsigned) n) {
-               iov[i].iov_base = (char *)iov[i].iov_base + n;
+               iov[i].iov_base = CS iov[i].iov_base + n;
                iov[i].iov_len -= n;
                break;
            }
index 4d435a411cd03338269bf87ea4e0d46614bf407f..f14ca5e545f4348cd8c73449b75e25bc3bb2b179 100644 (file)
@@ -71,6 +71,19 @@ auth_spa_options_block auth_spa_option_defaults = {
 };
 
 
+#ifdef MACRO_PREDEF
+
+/* Dummy values */
+void auth_spa_init(auth_instance *ablock) {}
+int auth_spa_server(auth_instance *ablock, uschar *data) {return 0;}
+int auth_spa_client(auth_instance *ablock, smtp_inblock *inblock,
+  smtp_outblock *outblock, int timeout, uschar *buffer, int buffsize) {return 0;}
+
+#else   /*!MACRO_PREDEF*/
+
+
+
+
 /*************************************************
 *          Initialization entry point            *
 *************************************************/
@@ -110,7 +123,7 @@ ablock->server = ob->spa_serverpassword != NULL;
 
 /* For interface, see auths/README */
 
-#define CVAL(buf,pos) (((unsigned char *)(buf))[pos])
+#define CVAL(buf,pos) ((US (buf))[pos])
 #define PVAL(buf,pos) ((unsigned)CVAL(buf,pos))
 #define SVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+1)<<8)
 #define IVAL(buf,pos) (SVAL(buf,pos)|SVAL(buf,(pos)+2)<<16)
@@ -138,7 +151,7 @@ if ((*data == '\0') &&
   return FAIL;
   }
 
-if (spa_base64_to_bits((char *)(&request), sizeof(request), (const char *)(data)) < 0)
+if (spa_base64_to_bits(CS (&request), sizeof(request), CCS (data)) < 0)
   {
   DEBUG(D_auth) debug_printf("auth_spa_server(): bad base64 data in "
   "request: %s\n", data);
@@ -158,7 +171,7 @@ if (auth_get_no64_data(&data, msgbuf) != OK)
   }
 
 /* dump client response */
-if (spa_base64_to_bits((char *)(&response), sizeof(response), (const char *)(data)) < 0)
+if (spa_base64_to_bits(CS (&response), sizeof(response), CCS (data)) < 0)
   {
   DEBUG(D_auth) debug_printf("auth_spa_server(): bad base64 data in "
   "response: %s\n", data);
@@ -261,109 +274,104 @@ auth_spa_client(
   uschar *buffer,                        /* buffer for reading response */
   int buffsize)                          /* size of buffer */
 {
-       auth_spa_options_block *ob =
-               (auth_spa_options_block *)(ablock->options_block);
-       SPAAuthRequest   request;
-       SPAAuthChallenge challenge;
-       SPAAuthResponse  response;
-       char msgbuf[2048];
-       char *domain = NULL;
-       char *username, *password;
-
-       /* Code added by PH to expand the options */
-
-       *buffer = 0;    /* Default no message when cancelled */
-
-       username = CS expand_string(ob->spa_username);
-       if (username == NULL)
-         {
-         if (expand_string_forcedfail) return CANCELLED;
-         string_format(buffer, buffsize, "expansion of \"%s\" failed in %s "
-           "authenticator: %s", ob->spa_username, ablock->name,
-           expand_string_message);
-         return ERROR;
-         }
-
-       password = CS expand_string(ob->spa_password);
-       if (password == NULL)
-         {
-         if (expand_string_forcedfail) return CANCELLED;
-         string_format(buffer, buffsize, "expansion of \"%s\" failed in %s "
-           "authenticator: %s", ob->spa_password, ablock->name,
-           expand_string_message);
-         return ERROR;
-         }
-
-       if (ob->spa_domain != NULL)
-         {
-         domain = CS expand_string(ob->spa_domain);
-         if (domain == NULL)
-           {
-           if (expand_string_forcedfail) return CANCELLED;
-           string_format(buffer, buffsize, "expansion of \"%s\" failed in %s "
-             "authenticator: %s", ob->spa_domain, ablock->name,
-             expand_string_message);
-           return ERROR;
-           }
-         }
-
-       /* Original code */
-
-    if (smtp_write_command(outblock, FALSE, "AUTH %s\r\n",
-         ablock->public_name) < 0)
-               return FAIL_SEND;
-
-       /* wait for the 3XX OK message */
-       if (!smtp_read_response(inblock, (uschar *)buffer, buffsize, '3', timeout))
-               return FAIL;
-
-       DSPA("\n\n%s authenticator: using domain %s\n\n",
-               ablock->name, domain);
-
-       spa_build_auth_request (&request, CS username, domain);
-       spa_bits_to_base64 (US msgbuf, (unsigned char*)&request,
-               spa_request_length(&request));
-
-       DSPA("\n\n%s authenticator: sending request (%s)\n\n", ablock->name,
-               msgbuf);
-
-       /* send the encrypted password */
-       if (smtp_write_command(outblock, FALSE, "%s\r\n", msgbuf) < 0)
-               return FAIL_SEND;
-
-       /* wait for the auth challenge */
-       if (!smtp_read_response(inblock, (uschar *)buffer, buffsize, '3', timeout))
-               return FAIL;
-
-       /* convert the challenge into the challenge struct */
-       DSPA("\n\n%s authenticator: challenge (%s)\n\n",
-               ablock->name, buffer + 4);
-       spa_base64_to_bits ((char *)(&challenge), sizeof(challenge), (const char *)(buffer + 4));
-
-       spa_build_auth_response (&challenge, &response,
-               CS username, CS password);
-       spa_bits_to_base64 (US msgbuf, (unsigned char*)&response,
-               spa_request_length(&response));
-       DSPA("\n\n%s authenticator: challenge response (%s)\n\n", ablock->name,
-               msgbuf);
-
-       /* send the challenge response */
-       if (smtp_write_command(outblock, FALSE, "%s\r\n", msgbuf) < 0)
-               return FAIL_SEND;
-
-       /* If we receive a success response from the server, authentication
-       has succeeded. There may be more data to send, but is there any point
-       in provoking an error here? */
-       if (smtp_read_response(inblock, US buffer, buffsize, '2', timeout))
-               return OK;
-
-       /* Not a success response. If errno != 0 there is some kind of transmission
-       error. Otherwise, check the response code in the buffer. If it starts with
-       '3', more data is expected. */
-       if (errno != 0 || buffer[0] != '3')
-               return FAIL;
-
-       return FAIL;
+auth_spa_options_block *ob =
+       (auth_spa_options_block *)(ablock->options_block);
+SPAAuthRequest   request;
+SPAAuthChallenge challenge;
+SPAAuthResponse  response;
+char msgbuf[2048];
+char *domain = NULL;
+char *username, *password;
+
+/* Code added by PH to expand the options */
+
+*buffer = 0;    /* Default no message when cancelled */
+
+if (!(username = CS expand_string(ob->spa_username)))
+  {
+  if (expand_string_forcedfail) return CANCELLED;
+  string_format(buffer, buffsize, "expansion of \"%s\" failed in %s "
+   "authenticator: %s", ob->spa_username, ablock->name,
+   expand_string_message);
+  return ERROR;
+  }
+
+if (!(password = CS expand_string(ob->spa_password)))
+  {
+  if (expand_string_forcedfail) return CANCELLED;
+  string_format(buffer, buffsize, "expansion of \"%s\" failed in %s "
+   "authenticator: %s", ob->spa_password, ablock->name,
+   expand_string_message);
+  return ERROR;
+  }
+
+if (ob->spa_domain)
+  {
+  if (!(domain = CS expand_string(ob->spa_domain)))
+    {
+    if (expand_string_forcedfail) return CANCELLED;
+    string_format(buffer, buffsize, "expansion of \"%s\" failed in %s "
+                 "authenticator: %s", ob->spa_domain, ablock->name,
+                 expand_string_message);
+    return ERROR;
+    }
+  }
+
+/* Original code */
+
+if (smtp_write_command(outblock, SCMD_FLUSH, "AUTH %s\r\n",
+    ablock->public_name) < 0)
+  return FAIL_SEND;
+
+/* wait for the 3XX OK message */
+if (!smtp_read_response(inblock, US buffer, buffsize, '3', timeout))
+  return FAIL;
+
+DSPA("\n\n%s authenticator: using domain %s\n\n", ablock->name, domain);
+
+spa_build_auth_request (&request, CS username, domain);
+spa_bits_to_base64 (US msgbuf, (unsigned char*)&request,
+       spa_request_length(&request));
+
+DSPA("\n\n%s authenticator: sending request (%s)\n\n", ablock->name, msgbuf);
+
+/* send the encrypted password */
+if (smtp_write_command(outblock, SCMD_FLUSH, "%s\r\n", msgbuf) < 0)
+  return FAIL_SEND;
+
+/* wait for the auth challenge */
+if (!smtp_read_response(inblock, US buffer, buffsize, '3', timeout))
+  return FAIL;
+
+/* convert the challenge into the challenge struct */
+DSPA("\n\n%s authenticator: challenge (%s)\n\n", ablock->name, buffer + 4);
+spa_base64_to_bits (CS (&challenge), sizeof(challenge), CCS (buffer + 4));
+
+spa_build_auth_response (&challenge, &response, CS username, CS password);
+spa_bits_to_base64 (US msgbuf, (unsigned char*)&response,
+       spa_request_length(&response));
+DSPA("\n\n%s authenticator: challenge response (%s)\n\n", ablock->name, msgbuf);
+
+/* send the challenge response */
+if (smtp_write_command(outblock, SCMD_FLUSH, "%s\r\n", msgbuf) < 0)
+       return FAIL_SEND;
+
+/* If we receive a success response from the server, authentication
+has succeeded. There may be more data to send, but is there any point
+in provoking an error here? */
+
+if (smtp_read_response(inblock, US buffer, buffsize, '2', timeout))
+  return OK;
+
+/* Not a success response. If errno != 0 there is some kind of transmission
+error. Otherwise, check the response code in the buffer. If it starts with
+'3', more data is expected. */
+
+if (errno != 0 || buffer[0] != '3')
+  return FAIL;
+
+return FAIL;
 }
 
+#endif   /*!MACRO_PREDEF*/
 /* End of spa.c */
index 99c756374022ab04d69fe566d5ac57d61ff2c4bb..bdcae31941c21f8646cfc4a570f4117f96b24824 100644 (file)
@@ -40,6 +40,19 @@ auth_tls_options_block auth_tls_option_defaults = {
 };
 
 
+#ifdef MACRO_PREDEF
+
+/* Dummy values */
+void auth_tls_init(auth_instance *ablock) {}
+int auth_tls_server(auth_instance *ablock, uschar *data) {return 0;}
+int auth_tls_client(auth_instance *ablock, smtp_inblock *inblock,
+  smtp_outblock *outblock, int timeout, uschar *buffer, int buffsize) {return 0;}
+
+#else   /*!MACRO_PREDEF*/
+
+
+
+
 /*************************************************
 *          Initialization entry point            *
 *************************************************/
@@ -77,4 +90,5 @@ return auth_check_serv_cond(ablock);
 }
 
 
+#endif   /*!MACRO_PREDEF*/
 /* End of tls.c */
index 7cdfe322495504d9fe5b1890c7b380299e948e28..4d189fc0668f5100709469a82928bd6aa1e87823 100644 (file)
@@ -28,7 +28,7 @@ uschar *
 auth_xtextencode(uschar *clear, int len)
 {
 uschar *code;
-uschar *p = (uschar *)clear;
+uschar *p = US clear;
 uschar *pp;
 int c = len;
 int count = 1;
@@ -42,17 +42,13 @@ while (c -- > 0)
 
 pp = code = store_get(count);
 
-p = (uschar *)clear;
+p = US clear;
 c = len;
 while (c-- > 0)
-  {
   if ((x = *p++) < 33 || x > 127 || x == '+' || x == '=')
-    {
-    sprintf(CS pp, "+%.02x", x);   /* There's always room */
-    pp += 3;
-    }
-  else *pp++ = x;
-  }
+    pp += sprintf(CS pp, "+%.02x", x);   /* There's always room */
+  else
+    *pp++ = x;
 
 *pp = 0;
 return code;
index cee77c3c3334c6715a9f02fecb5bc53f36203183..9dcbb74f01ec2f3c1d1818cf735a67043655ca66 100644 (file)
@@ -150,7 +150,7 @@ static uschar dec64table[] = {
 };
 
 int
-b64decode(uschar *code, uschar **ptr)
+b64decode(const uschar *code, uschar **ptr)
 {
 int x, y;
 uschar *result = store_get(3*(Ustrlen(code)/4) + 1);
index 378514939f1598ab82ab901ac9b94557c159c779..546ac1e36837963c173d8e1618ec09973352ba38 100644 (file)
@@ -27,7 +27,7 @@ uschar *bmi_process_message(header_line *header_list, int data_fd) {
   uschar *verdicts = NULL;
   int i,j;
 
-  err = bmiInitSystem(BMI_VERSION, (char *)bmi_config_file, &system);
+  err = bmiInitSystem(BMI_VERSION, CS bmi_config_file, &system);
   if (bmiErrorIsFatal(err) == BMI_TRUE) {
     err_loc = bmiErrorGetLocation(err);
     err_type = bmiErrorGetType(err);
@@ -51,24 +51,24 @@ uschar *bmi_process_message(header_line *header_list, int data_fd) {
     host_address = localhost;
   else
     host_address = sender_host_address;
-  err = bmiProcessConnection((char *)host_address, message);
+  err = bmiProcessConnection(CS host_address, message);
   if (bmiErrorIsFatal(err) == BMI_TRUE) {
     err_loc = bmiErrorGetLocation(err);
     err_type = bmiErrorGetType(err);
     log_write(0, LOG_PANIC,
-               "bmi error [loc %d type %d]: bmiProcessConnection() failed (IP %s).", (int)err_loc, (int)err_type, (char *)host_address);
+               "bmi error [loc %d type %d]: bmiProcessConnection() failed (IP %s).", (int)err_loc, (int)err_type, CS host_address);
     bmiFreeMessage(message);
     bmiFreeSystem(system);
     return NULL;
   };
 
   /* Send envelope sender address */
-  err = bmiProcessFROM((char *)sender_address, message);
+  err = bmiProcessFROM(CS sender_address, message);
   if (bmiErrorIsFatal(err) == BMI_TRUE) {
     err_loc = bmiErrorGetLocation(err);
     err_type = bmiErrorGetType(err);
     log_write(0, LOG_PANIC,
-               "bmi error [loc %d type %d]: bmiProcessFROM() failed (address %s).", (int)err_loc, (int)err_type, (char *)sender_address);
+               "bmi error [loc %d type %d]: bmiProcessFROM() failed (address %s).", (int)err_loc, (int)err_type, CS sender_address);
     bmiFreeMessage(message);
     bmiFreeSystem(system);
     return NULL;
@@ -86,14 +86,14 @@ uschar *bmi_process_message(header_line *header_list, int data_fd) {
       err = bmiOptinMset(optin, r->bmi_optin, ':');
       if (bmiErrorIsFatal(err) == BMI_TRUE) {
         log_write(0, LOG_PANIC|LOG_MAIN,
-                   "bmi warning: [loc %d type %d]: bmiOptinMSet() failed (address '%s', string '%s').", (int)err_loc, (int)err_type, (char *)r->address, (char *)r->bmi_optin);
+                   "bmi warning: [loc %d type %d]: bmiOptinMSet() failed (address '%s', string '%s').", (int)err_loc, (int)err_type, CS r->address, CS r->bmi_optin);
         if (optin != NULL)
           bmiOptinFree(optin);
         optin = NULL;
       };
     };
 
-    err = bmiAccumulateTO((char *)r->address, optin, message);
+    err = bmiAccumulateTO(CS r->address, optin, message);
 
     if (optin != NULL)
       bmiOptinFree(optin);
@@ -102,7 +102,7 @@ uschar *bmi_process_message(header_line *header_list, int data_fd) {
       err_loc = bmiErrorGetLocation(err);
       err_type = bmiErrorGetType(err);
       log_write(0, LOG_PANIC,
-                 "bmi error [loc %d type %d]: bmiAccumulateTO() failed (address %s).", (int)err_loc, (int)err_type, (char *)r->address);
+                 "bmi error [loc %d type %d]: bmiAccumulateTO() failed (address %s).", (int)err_loc, (int)err_type, CS r->address);
       bmiFreeMessage(message);
       bmiFreeSystem(system);
       return NULL;
@@ -126,7 +126,7 @@ uschar *bmi_process_message(header_line *header_list, int data_fd) {
       header_list = header_list->next;
       continue;
     };
-    err = bmiAccumulateHeaders((const char *)header_list->text, header_list->slen, message);
+    err = bmiAccumulateHeaders(CCS header_list->text, header_list->slen, message);
     if (bmiErrorIsFatal(err) == BMI_TRUE) {
       err_loc = bmiErrorGetLocation(err);
       err_type = bmiErrorGetType(err);
@@ -154,7 +154,7 @@ uschar *bmi_process_message(header_line *header_list, int data_fd) {
   do {
     j = fread(data_buffer, 1, sizeof(data_buffer), data_file);
     if (j > 0) {
-      err = bmiAccumulateBody((const char *)data_buffer, j, message);
+      err = bmiAccumulateBody(CCS data_buffer, j, message);
       if (bmiErrorIsFatal(err) == BMI_TRUE) {
         err_loc = bmiErrorGetLocation(err);
         err_type = bmiErrorGetType(err);
@@ -328,7 +328,7 @@ uschar *bmi_get_base64_verdict(uschar *bmi_local_part, uschar *bmi_domain) {
 
   /* loop through verdicts */
   verdict_ptr = bmi_verdicts;
-  while ((verdict_str = (const char *)string_nextinlist(&verdict_ptr, &sep,
+  while ((verdict_str = CCS string_nextinlist(&verdict_ptr, &sep,
                                           verdict_buffer,
                                           Ustrlen(bmi_verdicts)+1)) != NULL) {
 
@@ -350,7 +350,7 @@ uschar *bmi_get_base64_verdict(uschar *bmi_local_part, uschar *bmi_domain) {
       uschar *rcpt_domain;
 
       /* compare address against our subject */
-      rcpt_local_part = (unsigned char *)bmiRecipientAccessAddress(recipient);
+      rcpt_local_part = US bmiRecipientAccessAddress(recipient);
       rcpt_domain = Ustrchr(rcpt_local_part,'@');
       if (rcpt_domain == NULL) {
         rcpt_domain = US"";
@@ -364,7 +364,7 @@ uschar *bmi_get_base64_verdict(uschar *bmi_local_part, uschar *bmi_domain) {
            (strcmpic(rcpt_domain, bmi_domain) == 0) ) {
         /* found verdict */
         bmiFreeVerdict(verdict);
-        return (uschar *)verdict_str;
+        return US verdict_str;
       };
     };
 
index 58e1813091be5fabb4b6c6243a4a40045e8fe928..dbfde89355ddf41776fe680574605ee0cbca77c4 100644 (file)
@@ -8,7 +8,10 @@
 /* The default settings for Exim configuration variables. A #define without
 any data just defines the existence of the variable; it won't get included
 in config.h unless some value is defined in Local/Makefile. If there is data,
-it's a default value. */
+it's a default value.
+
+Do not put spaces between # and the 'define'.
+*/
 
 #define ALT_CONFIG_PREFIX
 #define TRUSTED_CONFIG_LIST
@@ -178,11 +181,13 @@ it's a default value. */
 #define EXPERIMENTAL_DCC
 #define EXPERIMENTAL_DSN_INFO
 #define EXPERIMENTAL_DMARC
+    #define DMARC_TLD_FILE "/etc/exim/opendmarc.tlds"
 #define EXPERIMENTAL_LMDB
 #define EXPERIMENTAL_QUEUEFILE
 #define EXPERIMENTAL_SPF
 #define EXPERIMENTAL_SRS
 
+
 /* For developers */
 #define WANT_DEEPER_PRINTF_CHECKS
 
index ebd06b523114f09c847d23fce968674a292d3193..b91b43746159ef16f3393de4abe749591c1ab85e 100644 (file)
@@ -21,7 +21,7 @@ typedef struct smtp_slot {
 /* An empty slot for initializing (Standard C does not allow constructor
 expressions in assignments except as initializers in declarations). */
 
-static smtp_slot empty_smtp_slot = { 0, NULL };
+static smtp_slot empty_smtp_slot = { .pid = 0, .host_address = NULL };
 
 
 
@@ -109,7 +109,7 @@ never_error(uschar *log_msg, uschar *smtp_msg, int was_errno)
 uschar *emsg = (was_errno <= 0)? US"" :
   string_sprintf(": %s", strerror(was_errno));
 log_write(0, LOG_MAIN|LOG_PANIC, "%s%s", log_msg, emsg);
-if (smtp_out != NULL) smtp_printf("421 %s\r\n", smtp_msg);
+if (smtp_out != NULL) smtp_printf("421 %s\r\n", FALSE, smtp_msg);
 }
 
 
@@ -189,7 +189,7 @@ if (getsockname(accept_socket, (struct sockaddr *)(&interface_sockaddr),
   {
   log_write(0, LOG_MAIN | ((errno == ECONNRESET)? 0 : LOG_PANIC),
     "getsockname() failed: %s", strerror(errno));
-  smtp_printf("421 Local problem: getsockname() failed; please try again later\r\n");
+  smtp_printf("421 Local problem: getsockname() failed; please try again later\r\n", FALSE);
   goto ERROR_RETURN;
   }
 
@@ -222,7 +222,7 @@ if (smtp_accept_max > 0 && smtp_accept_count >= smtp_accept_max)
   DEBUG(D_any) debug_printf("rejecting SMTP connection: count=%d max=%d\n",
     smtp_accept_count, smtp_accept_max);
   smtp_printf("421 Too many concurrent SMTP connections; "
-    "please try again later.\r\n");
+    "please try again later.\r\n", FALSE);
   log_write(L_connection_reject,
             LOG_MAIN, "Connection from %s refused: too many connections",
     whofrom);
@@ -241,7 +241,7 @@ if (smtp_load_reserve >= 0)
     {
     DEBUG(D_any) debug_printf("rejecting SMTP connection: load average = %.2f\n",
       (double)load_average/1000.0);
-    smtp_printf("421 Too much load; please try again later.\r\n");
+    smtp_printf("421 Too much load; please try again later.\r\n", FALSE);
     log_write(L_connection_reject,
               LOG_MAIN, "Connection from %s refused: load average = %.2f",
       whofrom, (double)load_average/1000.0);
@@ -312,7 +312,7 @@ if ((max_for_this_host > 0) &&
       "IP address: count=%d max=%d\n",
       host_accept_count, max_for_this_host);
     smtp_printf("421 Too many concurrent SMTP connections "
-      "from this IP address; please try again later.\r\n");
+      "from this IP address; please try again later.\r\n", FALSE);
     log_write(L_connection_reject,
               LOG_MAIN, "Connection from %s refused: too many connections "
       "from that IP address", whofrom);
@@ -396,7 +396,7 @@ if (pid == 0)
           "(smtp_active_hostname): %s", raw_active_hostname,
           expand_string_message);
         smtp_printf("421 Local configuration error; "
-          "please try again later.\r\n");
+          "please try again later.\r\n", FALSE);
         mac_smtp_fflush();
         search_tidyup();
         _exit(EXIT_FAILURE);
@@ -510,6 +510,7 @@ if (pid == 0)
       search_tidyup();                    /* Close cached databases */
       if (!ok)                            /* Connection was dropped */
         {
+       cancel_cutthrough_connection(TRUE, US"receive dropped");
         mac_smtp_fflush();
         smtp_log_no_mail();               /* Log no mail if configured */
         _exit(EXIT_SUCCESS);
@@ -528,6 +529,7 @@ if (pid == 0)
        if (fcntl(fd, F_SETFL, O_NONBLOCK) == 0)
          for(i = 16; read(fd, buf, sizeof(buf)) > 0 && i > 0; ) i--;
        }
+      cancel_cutthrough_connection(TRUE, US"message setup dropped");
       search_tidyup();
       smtp_log_no_mail();                 /* Log no mail if configured */
 
@@ -653,9 +655,9 @@ if (pid == 0)
         /* Don't ever molest the parent's SSL connection, but do clean up
         the data structures if necessary. */
 
-        #ifdef SUPPORT_TLS
+#ifdef SUPPORT_TLS
         tls_close(TRUE, FALSE);
-        #endif
+#endif
 
         /* Reset SIGHUP and SIGCHLD in the child in both cases. */
 
@@ -665,25 +667,28 @@ if (pid == 0)
         if (geteuid() != root_uid && !deliver_drop_privilege)
           {
           signal(SIGALRM, SIG_DFL);
-          (void)child_exec_exim(CEE_EXEC_PANIC, FALSE, NULL, FALSE,
-           2, US"-Mc", message_id);
+         delivery_re_exec(CEE_EXEC_PANIC);
           /* Control does not return here. */
           }
 
         /* No need to re-exec; SIGALRM remains set to the default handler */
 
-        (void)deliver_message(message_id, FALSE, FALSE);
+        (void) deliver_message(message_id, FALSE, FALSE);
         search_tidyup();
         _exit(EXIT_SUCCESS);
         }
 
       if (dpid > 0)
         {
+       release_cutthrough_connection(US"passed for delivery");
         DEBUG(D_any) debug_printf("forked delivery process %d\n", (int)dpid);
         }
       else
+       {
+       cancel_cutthrough_connection(TRUE, US"delivery fork failed");
         log_write(0, LOG_MAIN|LOG_PANIC, "daemon: delivery process fork "
           "failed: %s", strerror(errno));
+       }
       }
     }
   }
@@ -1168,6 +1173,8 @@ if (daemon_listen && !inetd_wait_mode)
   while ((s = string_nextinlist(&list, &sep, big_buffer, big_buffer_size)))
     if (!isdigit(*s))
       {
+      int size = 0, len = 0;
+
       list = tls_in.on_connect_ports;
       tls_in.on_connect_ports = NULL;
       sep = 0;
@@ -1175,13 +1182,13 @@ if (daemon_listen && !inetd_wait_mode)
        {
         if (!isdigit(*s))
          {
-         struct servent *smtp_service = getservbyname(CS s, "tcp");
+         struct servent * smtp_service = getservbyname(CS s, "tcp");
          if (!smtp_service)
            log_write(0, LOG_PANIC_DIE|LOG_CONFIG, "TCP port \"%s\" not found", s);
-         s= string_sprintf("%d", (int)ntohs(smtp_service->s_port));
+         s = string_sprintf("%d", (int)ntohs(smtp_service->s_port));
          }
        tls_in.on_connect_ports = string_append_listele(tls_in.on_connect_ports,
-           ':', s);
+           &size, &len, ':', s);
        }
       break;
       }
@@ -1201,11 +1208,12 @@ if (daemon_listen && !inetd_wait_mode)
   In the same scan, fill in missing port numbers from the default list. When
   there is more than one item in the list, extra items are created. */
 
-  for (ipa = addresses; ipa != NULL; ipa = ipa->next)
+  for (ipa = addresses; ipa; ipa = ipa->next)
     {
     int i;
 
-    if (Ustrcmp(ipa->address, "0.0.0.0") == 0) ipa->address[0] = 0;
+    if (Ustrcmp(ipa->address, "0.0.0.0") == 0)
+      ipa->address[0] = 0;
     else if (Ustrcmp(ipa->address, "::0") == 0)
       {
       ipa->address[0] = ':';
@@ -1217,12 +1225,14 @@ if (daemon_listen && !inetd_wait_mode)
     if (daemon_smtp_port[0] <= 0)
       log_write(0, LOG_MAIN|LOG_PANIC_DIE, "no port specified for interface "
         "%s and daemon_smtp_port is unset; cannot start daemon",
-        (ipa->address[0] == 0)? US"\"all IPv4\"" :
-        (ipa->address[1] == 0)? US"\"all IPv6\"" : ipa->address);
+        ipa->address[0] == 0 ? US"\"all IPv4\"" :
+        ipa->address[1] == 0 ? US"\"all IPv6\"" : ipa->address);
+
     ipa->port = default_smtp_port[0];
     for (i = 1; default_smtp_port[i] > 0; i++)
       {
       ip_address_item *new = store_get(sizeof(ip_address_item));
+
       memcpy(new->address, ipa->address, Ustrlen(ipa->address) + 1);
       new->port = default_smtp_port[i];
       new->next = ipa->next;
@@ -1237,15 +1247,14 @@ if (daemon_listen && !inetd_wait_mode)
   also simplifies the construction of the "daemon started" log line. */
 
   pipa = &addresses;
-  for (ipa = addresses; ipa != NULL; pipa = &(ipa->next), ipa = ipa->next)
+  for (ipa = addresses; ipa; pipa = &ipa->next, ipa = ipa->next)
     {
     ip_address_item *ipa2;
 
     /* Handle an IPv4 wildcard */
 
     if (ipa->address[0] == 0)
-      {
-      for (ipa2 = ipa; ipa2->next != NULL; ipa2 = ipa2->next)
+      for (ipa2 = ipa; ipa2->next; ipa2 = ipa2->next)
         {
         ip_address_item *ipa3 = ipa2->next;
         if (ipa3->address[0] == ':' &&
@@ -1258,13 +1267,11 @@ if (daemon_listen && !inetd_wait_mode)
           break;
           }
         }
-      }
 
     /* Handle an IPv6 wildcard. */
 
     else if (ipa->address[0] == ':' && ipa->address[1] == 0)
-      {
-      for (ipa2 = ipa; ipa2->next != NULL; ipa2 = ipa2->next)
+      for (ipa2 = ipa; ipa2->next; ipa2 = ipa2->next)
         {
         ip_address_item *ipa3 = ipa2->next;
         if (ipa3->address[0] == 0 && ipa3->port == ipa->port)
@@ -1276,12 +1283,11 @@ if (daemon_listen && !inetd_wait_mode)
           break;
           }
         }
-      }
     }
 
   /* Get a vector to remember all the sockets in */
 
-  for (ipa = addresses; ipa != NULL; ipa = ipa->next)
+  for (ipa = addresses; ipa; ipa = ipa->next)
     listen_socket_count++;
   listen_sockets = store_get(sizeof(int) * listen_socket_count);
 
@@ -1403,20 +1409,20 @@ if (daemon_listen && !inetd_wait_mode)
     available. Just log failure (can get protocol not available, just like
     socket creation can). */
 
-    #ifdef IPV6_V6ONLY
+#ifdef IPV6_V6ONLY
     if (af == AF_INET6 && wildcard &&
-        setsockopt(listen_sockets[sk], IPPROTO_IPV6, IPV6_V6ONLY, (char *)(&on),
+        setsockopt(listen_sockets[sk], IPPROTO_IPV6, IPV6_V6ONLY, CS (&on),
           sizeof(on)) < 0)
       log_write(0, LOG_MAIN, "Setting IPV6_V6ONLY on daemon's IPv6 wildcard "
         "socket failed (%s): carrying on without it", strerror(errno));
-    #endif  /* IPV6_V6ONLY */
+#endif  /* IPV6_V6ONLY */
 
     /* Set SO_REUSEADDR so that the daemon can be restarted while a connection
     is being handled.  Without this, a connection will prevent reuse of the
     smtp port for listening. */
 
     if (setsockopt(listen_sockets[sk], SOL_SOCKET, SO_REUSEADDR,
-                   (uschar *)(&on), sizeof(on)) < 0)
+                   US (&on), sizeof(on)) < 0)
       log_write(0, LOG_MAIN|LOG_PANIC_DIE, "setting SO_REUSEADDR on socket "
         "failed when starting daemon: %s", strerror(errno));
 
@@ -1424,7 +1430,7 @@ if (daemon_listen && !inetd_wait_mode)
     disable this because it breaks some broken clients. */
 
     if (tcp_nodelay) setsockopt(listen_sockets[sk], IPPROTO_TCP, TCP_NODELAY,
-      (uschar *)(&on), sizeof(on));
+      US (&on), sizeof(on));
 
     /* Now bind the socket to the required port; if Exim is being restarted
     it may not always be possible to bind immediately, even with SO_REUSEADDR
@@ -1451,8 +1457,11 @@ if (daemon_listen && !inetd_wait_mode)
         goto SKIP_SOCKET;
         }
       msg = US strerror(errno);
-      addr = wildcard? ((af == AF_INET6)? US"(any IPv6)" : US"(any IPv4)") :
-        ipa->address;
+      addr = wildcard
+        ? af == AF_INET6
+       ? US"(any IPv6)"
+       : US"(any IPv4)"
+       : ipa->address;
       if (daemon_startup_retries <= 0)
         log_write(0, LOG_MAIN|LOG_PANIC_DIE,
           "socket bind() to port %d for address %s failed: %s: "
@@ -1506,7 +1515,7 @@ if (daemon_listen && !inetd_wait_mode)
     are going to ignore. We remove the address from the chain, and back up the
     counts. */
 
-    SKIP_SOCKET:
+  SKIP_SOCKET:
     sk--;                          /* Back up the count */
     listen_socket_count--;         /* Reduce the total */
     if (ipa == addresses) addresses = ipa->next; else
@@ -1522,7 +1531,8 @@ if (daemon_listen && !inetd_wait_mode)
 /* If we are not listening, we want to write a pid file only if -oP was
 explicitly given. */
 
-else if (override_pid_file_path == NULL) write_pid = FALSE;
+else if (!override_pid_file_path)
+  write_pid = FALSE;
 
 /* Write the pid to a known file for assistance in identification, if required.
 We do this before giving up root privilege, because on some systems it is
@@ -1542,25 +1552,22 @@ if (running_in_test_harness || write_pid)
   {
   FILE *f;
 
-  if (override_pid_file_path != NULL)
+  if (override_pid_file_path)
     pid_file_path = override_pid_file_path;
 
   if (pid_file_path[0] == 0)
     pid_file_path = string_sprintf("%s/exim-daemon.pid", spool_directory);
 
-  f = modefopen(pid_file_path, "wb", 0644);
-  if (f != NULL)
+  if ((f = modefopen(pid_file_path, "wb", 0644)))
     {
     (void)fprintf(f, "%d\n", (int)getpid());
     (void)fclose(f);
     DEBUG(D_any) debug_printf("pid written to %s\n", pid_file_path);
     }
   else
-    {
     DEBUG(D_any)
       debug_printf("%s\n", string_open_failed(errno, "pid file %s",
         pid_file_path));
-    }
   }
 
 /* Set up the handler for SIGHUP, which causes a restart of the daemon. */
@@ -1630,7 +1637,7 @@ else if (daemon_listen)
   int i, j;
   int smtp_ports = 0;
   int smtps_ports = 0;
-  ip_address_item * ipa;
+  ip_address_item * ipa, * i2;
   uschar * p = big_buffer;
   uschar * qinfo = queue_interval > 0
     ? string_sprintf("-q%s", readconf_printtime(queue_interval))
@@ -1646,62 +1653,60 @@ else if (daemon_listen)
   for (j = 0; j < 2; j++)
     {
     for (i = 0, ipa = addresses; i < 10 && ipa; i++, ipa = ipa->next)
-       {
-       /* First time round, look for SMTP ports; second time round, look for
-       SMTPS ports. For the first one of each, insert leading text. */
-
-       if (host_is_tls_on_connect_port(ipa->port) == (j > 0))
-         {
-        if (j == 0)
-          {
-          if (smtp_ports++ == 0)
-             {
-             memcpy(p, "SMTP on", 8);
-             p += 7;
-             }
-          }
-        else
-          {
-          if (smtps_ports++ == 0)
-             {
-             (void)sprintf(CS p, "%sSMTPS on",
-               smtp_ports == 0 ? "" : " and for ");
-             while (*p) p++;
-             }
-          }
-
-         /* Now the information about the port (and sometimes interface) */
-
-         if (ipa->address[0] == ':' && ipa->address[1] == 0)
-           {
-           if (ipa->next != NULL && ipa->next->address[0] == 0 &&
-               ipa->next->port == ipa->port)
-             {
-             (void)sprintf(CS p, " port %d (IPv6 and IPv4)", ipa->port);
-             ipa = ipa->next;
-             }
-           else if (ipa->v6_include_v4)
-             (void)sprintf(CS p, " port %d (IPv6 with IPv4)", ipa->port);
-           else
-             (void)sprintf(CS p, " port %d (IPv6)", ipa->port);
-           }
-         else if (ipa->address[0] == 0)
-           (void)sprintf(CS p, " port %d (IPv4)", ipa->port);
-         else if (  i > 0
-                 && host_is_tls_on_connect_port(ipa[-1].port) == (j > 0)
-                 && Ustrcmp(ipa->address, ipa[-1].address) == 0
-                 )
+      {
+      /* First time round, look for SMTP ports; second time round, look for
+      SMTPS ports. For the first one of each, insert leading text. */
+
+      if (host_is_tls_on_connect_port(ipa->port) == (j > 0))
+       {
+       if (j == 0)
+         {
+         if (smtp_ports++ == 0)
+           {
+           memcpy(p, "SMTP on", 8);
+           p += 7;
+           }
+         }
+       else
+         if (smtps_ports++ == 0)
+           p += sprintf(CS p, "%sSMTPS on",
+             smtp_ports == 0 ? "" : " and for ");
+
+       /* Now the information about the port (and sometimes interface) */
+
+       if (ipa->address[0] == ':' && ipa->address[1] == 0)
+         {                                             /* v6 wildcard */
+         if (ipa->next && ipa->next->address[0] == 0 &&
+             ipa->next->port == ipa->port)
            {
-           if (p[-1] == '}') p--;
-           while (isdigit(*--p)) ;
-           (void)sprintf(CS p+1, "%s%d,%d}", *p == ',' ? "" : "{",
-             ipa[-1].port, ipa->port);
+           p += sprintf(CS p, " port %d (IPv6 and IPv4)", ipa->port);
+           ipa = ipa->next;
            }
-         else
-           (void)sprintf(CS p, " [%s]:%d", ipa->address, ipa->port);
-         while (*p != 0) p++;
-         }
-       }
+         else if (ipa->v6_include_v4)
+           p += sprintf(CS p, " port %d (IPv6 with IPv4)", ipa->port);
+         else
+           p += sprintf(CS p, " port %d (IPv6)", ipa->port);
+         }
+       else if (ipa->address[0] == 0)                  /* v4 wildcard */
+         p += sprintf(CS p, " port %d (IPv4)", ipa->port);
+       else                            /* check for previously-seen IP */
+         {
+         for (i2 = addresses; i2 != ipa; i2 = i2->next)
+           if (  host_is_tls_on_connect_port(i2->port) == (j > 0)
+              && Ustrcmp(ipa->address, i2->address) == 0
+              )
+             {                         /* found; append port to list */
+             if (p[-1] == '}') p--;
+             while (isdigit(*--p)) ;
+             p +=  1 + sprintf(CS p+1, "%s%d,%d}", *p == ',' ? "" : "{",
+               i2->port, ipa->port);
+             break;
+             }
+         if (i2 == ipa)                /* first-time IP */
+           p += sprintf(CS p, " [%s]:%d", ipa->address, ipa->port);
+         }
+       }
+      }
 
     if (ipa)
       {
@@ -1962,10 +1967,8 @@ for (;;)
       errno = EINTR;
       }
     else
-      {
       lcount = select(max_socket + 1, (SELECT_ARG2_TYPE *)&select_listen,
         NULL, NULL, NULL);
-      }
 
     if (lcount < 0)
       {
@@ -1991,10 +1994,9 @@ for (;;)
     while (lcount-- > 0)
       {
       int accept_socket = -1;
+
       if (!select_failed)
-        {
         for (sk = 0; sk < listen_socket_count; sk++)
-          {
           if (FD_ISSET(listen_sockets[sk], &select_listen))
             {
             len = sizeof(accepted);
@@ -2003,8 +2005,6 @@ for (;;)
             FD_CLR(listen_sockets[sk], &select_listen);
             break;
             }
-          }
-        }
 
       /* If select or accept has failed and this was not caused by an
       interruption, log the incident and try again. With asymmetric TCP/IP
index 97acccb5ab9fa1e7395b60991edd6004ecd2902a..0a74f1f281714d043498c151a1b295d9bcc2b7f8 100644 (file)
@@ -84,6 +84,7 @@ typedef int CRYPTO_ONCE;
 #ifndef OPENSSL_NO_ERR
 #define        DANESSL_F_PLACEHOLDER           0               /* FIRST! Value TBD */
 static ERR_STRING_DATA dane_str_functs[] = {
+    /* error                           string */
     {DANESSL_F_PLACEHOLDER,            "DANE library"},        /* FIRST!!! */
     {DANESSL_F_ADD_SKID,               "add_skid"},
     {DANESSL_F_ADD_TLSA,               "DANESSL_add_tlsa"},
@@ -101,6 +102,7 @@ static ERR_STRING_DATA dane_str_functs[] = {
     {0,                                        NULL}
 };
 static ERR_STRING_DATA dane_str_reasons[] = {
+    /* error                           string */
     {DANESSL_R_BAD_CERT,       "Bad TLSA record certificate"},
     {DANESSL_R_BAD_CERT_PKEY,  "Bad TLSA record certificate public key"},
     {DANESSL_R_BAD_DATA_LENGTH,        "Bad TLSA record digest length"},
@@ -251,12 +253,12 @@ for (matched = 0; !matched && slist; slist = slist->next)
     {
     case DANESSL_SELECTOR_CERT:
       len = i2d_X509(cert, NULL);
-      buf2 = buf = (unsigned char *) OPENSSL_malloc(len);
+      buf2 = buf = US  OPENSSL_malloc(len);
       if(buf) i2d_X509(cert, &buf2);
       break;
     case DANESSL_SELECTOR_SPKI:
       len = i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), NULL);
-      buf2 = buf = (unsigned char *) OPENSSL_malloc(len);
+      buf2 = buf = US  OPENSSL_malloc(len);
       if(buf) i2d_X509_PUBKEY(X509_get_X509_PUBKEY(cert), &buf2);
       break;
     }
@@ -822,7 +824,7 @@ if (gn->type != GEN_DNS)
   return 0;
 if (ASN1_STRING_type(gn->d.ia5) != V_ASN1_IA5STRING)
   return 0;
-return check_name((const char *) ASN1_STRING_get0_data(gn->d.ia5),
+return check_name(CCS  ASN1_STRING_get0_data(gn->d.ia5),
                  ASN1_STRING_length(gn->d.ia5));
 }
 
@@ -846,12 +848,12 @@ if (!(entry_str = X509_NAME_ENTRY_get_data(entry)))
 
 if ((len = ASN1_STRING_to_UTF8(&namebuf, entry_str)) < 0)
   return 0;
-if (len <= 0 || check_name((char *) namebuf, len) == 0)
+if (len <= 0 || check_name(CS  namebuf, len) == 0)
   {
   OPENSSL_free(namebuf);
   return 0;
   }
-return (char *) namebuf;
+return CS  namebuf;
 }
 
 static int
index c9c6fb707a45dc4350d654768edf952fa57a063d..5529fe93f3891229fb9ebc014f124cd2413e9c97 100644 (file)
@@ -91,7 +91,7 @@ int rc, save_errno;
 BOOL read_only = flags == O_RDONLY;
 BOOL created = FALSE;
 flock_t lock_data;
-uschar buffer[256];
+uschar dirname[256], filename[256];
 
 /* The first thing to do is to open a separate file on which to lock. This
 ensures that Exim has exclusive use of the database before it even tries to
@@ -106,19 +106,20 @@ make the directory as well, just in case. We won't be doing this many times
 unnecessarily, because usually the lock file will be there. If the directory
 exists, there is no error. */
 
-sprintf(CS buffer, "%s/db/%s.lockfile", spool_directory, name);
+snprintf(CS dirname, sizeof(dirname), "%s/db", spool_directory);
+snprintf(CS filename, sizeof(filename), "%s/%s.lockfile", dirname, name);
 
-if ((dbblock->lockfd = Uopen(buffer, O_RDWR, EXIMDB_LOCKFILE_MODE)) < 0)
+if ((dbblock->lockfd = Uopen(filename, O_RDWR, EXIMDB_LOCKFILE_MODE)) < 0)
   {
   created = TRUE;
   (void)directory_make(spool_directory, US"db", EXIMDB_DIRECTORY_MODE, TRUE);
-  dbblock->lockfd = Uopen(buffer, O_RDWR|O_CREAT, EXIMDB_LOCKFILE_MODE);
+  dbblock->lockfd = Uopen(filename, O_RDWR|O_CREAT, EXIMDB_LOCKFILE_MODE);
   }
 
 if (dbblock->lockfd < 0)
   {
   log_write(0, LOG_MAIN, "%s",
-    string_open_failed(errno, "database lock file %s", buffer));
+    string_open_failed(errno, "database lock file %s", filename));
   errno = 0;      /* Indicates locking failure */
   return NULL;
   }
@@ -130,7 +131,7 @@ lock_data.l_type = read_only? F_RDLCK : F_WRLCK;
 lock_data.l_whence = lock_data.l_start = lock_data.l_len = 0;
 
 DEBUG(D_hints_lookup|D_retry|D_route|D_deliver)
-  debug_printf("locking %s\n", buffer);
+  debug_printf("locking %s\n", filename);
 
 sigalrm_seen = FALSE;
 alarm(EXIMDB_LOCK_TIMEOUT);
@@ -141,14 +142,14 @@ if (sigalrm_seen) errno = ETIMEDOUT;
 if (rc < 0)
   {
   log_write(0, LOG_MAIN|LOG_PANIC, "Failed to get %s lock for %s: %s",
-    read_only ? "read" : "write", buffer,
+    read_only ? "read" : "write", filename,
     errno == ETIMEDOUT ? "timed out" : strerror(errno));
   (void)close(dbblock->lockfd);
   errno = 0;       /* Indicates locking failure */
   return NULL;
   }
 
-DEBUG(D_hints_lookup) debug_printf("locked  %s\n", buffer);
+DEBUG(D_hints_lookup) debug_printf("locked  %s\n", filename);
 
 /* At this point we have an opened and locked separate lock file, that is,
 exclusive access to the database, so we can go ahead and open it. If we are
@@ -159,18 +160,15 @@ databases - often this is caused by non-matching db.h and the library. To make
 it easy to pin this down, there are now debug statements on either side of the
 open call. */
 
-sprintf(CS buffer, "%s/db/%s", spool_directory, name);
-DEBUG(D_hints_lookup) debug_printf("EXIM_DBOPEN(%s)\n", buffer);
-EXIM_DBOPEN(buffer, flags, EXIMDB_MODE, &(dbblock->dbptr));
-DEBUG(D_hints_lookup) debug_printf("returned from EXIM_DBOPEN\n");
+snprintf(CS filename, sizeof(filename), "%s/%s", dirname, name);
+EXIM_DBOPEN(filename, dirname, flags, EXIMDB_MODE, &(dbblock->dbptr));
 
 if (!dbblock->dbptr && errno == ENOENT && flags == O_RDWR)
   {
   DEBUG(D_hints_lookup)
-    debug_printf("%s appears not to exist: trying to create\n", buffer);
+    debug_printf("%s appears not to exist: trying to create\n", filename);
   created = TRUE;
-  EXIM_DBOPEN(buffer, flags|O_CREAT, EXIMDB_MODE, &(dbblock->dbptr));
-  DEBUG(D_hints_lookup) debug_printf("returned from EXIM_DBOPEN\n");
+  EXIM_DBOPEN(filename, dirname, flags|O_CREAT, EXIMDB_MODE, &(dbblock->dbptr));
   }
 
 save_errno = errno;
@@ -193,22 +191,22 @@ if (created && geteuid() == root_uid)
   {
   DIR *dd;
   struct dirent *ent;
-  uschar *lastname = Ustrrchr(buffer, '/') + 1;
+  uschar *lastname = Ustrrchr(filename, '/') + 1;
   int namelen = Ustrlen(name);
 
   *lastname = 0;
-  dd = opendir(CS buffer);
+  dd = opendir(CS filename);
 
   while ((ent = readdir(dd)))
     if (Ustrncmp(ent->d_name, name, namelen) == 0)
       {
       struct stat statbuf;
       Ustrcpy(lastname, ent->d_name);
-      if (Ustat(buffer, &statbuf) >= 0 && statbuf.st_uid != exim_uid)
+      if (Ustat(filename, &statbuf) >= 0 && statbuf.st_uid != exim_uid)
         {
-        DEBUG(D_hints_lookup) debug_printf("ensuring %s is owned by exim\n", buffer);
-        if (Uchown(buffer, exim_uid, exim_gid))
-          DEBUG(D_hints_lookup) debug_printf("failed setting %s to owned by exim\n", buffer);
+        DEBUG(D_hints_lookup) debug_printf("ensuring %s is owned by exim\n", filename);
+        if (Uchown(filename, exim_uid, exim_gid))
+          DEBUG(D_hints_lookup) debug_printf("failed setting %s to owned by exim\n", filename);
         }
       }
 
@@ -216,25 +214,25 @@ if (created && geteuid() == root_uid)
   }
 
 /* If the open has failed, return NULL, leaving errno set. If lof is TRUE,
-log the event - also for debugging - but not if the file just doesn't exist. */
+log the event - also for debugging - but debug only if the file just doesn't
+exist. */
 
 if (!dbblock->dbptr)
   {
-  if (save_errno != ENOENT)
-    if (lof)
-      log_write(0, LOG_MAIN, "%s", string_open_failed(save_errno, "DB file %s",
-        buffer));
-    else
-      DEBUG(D_hints_lookup)
-        debug_printf("%s", CS string_open_failed(save_errno, "DB file %s\n",
-          buffer));
+  if (lof && save_errno != ENOENT)
+    log_write(0, LOG_MAIN, "%s", string_open_failed(save_errno, "DB file %s",
+        filename));
+  else
+    DEBUG(D_hints_lookup)
+      debug_printf("%s\n", CS string_open_failed(save_errno, "DB file %s",
+          filename));
   (void)close(dbblock->lockfd);
   errno = save_errno;
   return NULL;
   }
 
 DEBUG(D_hints_lookup)
-  debug_printf("opened hints database %s: flags=%s\n", buffer,
+  debug_printf("opened hints database %s: flags=%s\n", filename,
     flags == O_RDONLY ? "O_RDONLY"
     : flags == O_RDWR ? "O_RDWR"
     : flags == (O_RDWR|O_CREAT) ? "O_RDWR|O_CREAT"
@@ -531,7 +529,7 @@ while (Ufgets(buffer, 256, stdin) != NULL)
     odb = dbfn_open(s, O_RDWR, dbblock + i, TRUE);
     stop = clock();
 
-    if (odb != NULL)
+    if (odb)
       {
       current = i;
       printf("opened %d\n", current);
index 576941b61276c2e1a91620b5d3b19e9166734bf9..aec549f485932f689fabb0994c9928b61f2b2747 100644 (file)
@@ -39,7 +39,7 @@ tdb_traverse to be called) */
 /* Access functions */
 
 /* EXIM_DBOPEN - sets *dbpp to point to an EXIM_DB, NULL if failed */
-#define EXIM_DBOPEN(name, flags, mode, dbpp) \
+#define EXIM_DBOPEN__(name, dirname, flags, mode, dbpp) \
        *(dbpp) = tdb_open(CS name, 0, TDB_DEFAULT, flags, mode)
 
 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
@@ -77,7 +77,7 @@ free() must not die when passed NULL */
 #define EXIM_DBDELETE_CURSOR(cursor) free(cursor)
 
 /* EXIM_DBCLOSE */
-#define EXIM_DBCLOSE(db)        tdb_close(db)
+#define EXIM_DBCLOSE__(db)        tdb_close(db)
 
 /* Datum access types - these are intended to be assignable */
 
@@ -113,87 +113,176 @@ definition of DB_VERSION_STRING, which is present in versions 2.x onwards. */
 /***************** Berkeley db 3.x/4.x native definitions ******************/
 
 /* Basic DB type */
-#define EXIM_DB       DB
-
+#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
+# define EXIM_DB       DB_ENV
 /* Cursor type, for scanning */
-#define EXIM_CURSOR   DBC
+# define EXIM_CURSOR   DBC
 
 /* The datum type used for queries */
-#define EXIM_DATUM    DBT
+# define EXIM_DATUM    DBT
 
 /* Some text for messages */
-#define EXIM_DBTYPE   "db (v3/4)"
+# define EXIM_DBTYPE   "db (v4.1+)"
+
+/* Only more-recent versions.  5+ ? */
+# ifndef DB_FORCESYNC
+#  define DB_FORCESYNC 0
+# endif
+
 
 /* Access functions */
 
 /* EXIM_DBOPEN - sets *dbpp to point to an EXIM_DB, NULL if failed. The
-API changed for DB 4.1. */
+API changed for DB 4.1. - and we also starting using the "env" with a
+specified working dir, to avoid the DBCONFIG file trap. */
+
+# define ENV_TO_DB(env) ((DB *)((env)->app_private))
+
+# define EXIM_DBOPEN__(name, dirname, flags, mode, dbpp) \
+  if (  db_env_create(dbpp, 0) != 0                                            \
+     || ((*dbpp)->set_errcall(*dbpp, dbfn_bdb_error_callback), 0)              \
+     || (*dbpp)->open(*dbpp, CS dirname, DB_CREATE|DB_INIT_MPOOL|DB_PRIVATE, 0) != 0\
+     )                                                                         \
+    *dbpp = NULL;                                      \
+  else if (db_create((DB **) &((*dbpp)->app_private), *dbpp, 0) != 0)          \
+    {                                                  \
+    ((DB_ENV *)(*dbpp))->close((DB_ENV *)(*dbpp), 0);  \
+    *dbpp = NULL;                                      \
+    }                                                  \
+  else if (ENV_TO_DB(*dbpp)->open(ENV_TO_DB(*dbpp), NULL, CS name, NULL,       \
+             (flags) == O_RDONLY ? DB_UNKNOWN : DB_HASH,                       \
+             (flags) == O_RDONLY ? DB_RDONLY : DB_CREATE,                      \
+             mode) != 0                                                        \
+         )                                                                     \
+    {                                                  \
+    ENV_TO_DB(*dbpp)->close(ENV_TO_DB(*dbpp), 0);      \
+    ((DB_ENV *)(*dbpp))->close((DB_ENV *)(*dbpp), 0);  \
+    *dbpp = NULL;                                      \
+    }
 
-#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
-#define EXIM_DBOPEN(name, flags, mode, dbpp) \
-       if (db_create(dbpp, NULL, 0) != 0 || \
-         ((*dbpp)->set_errcall(*dbpp, dbfn_bdb_error_callback), \
-         ((*dbpp)->open)(*dbpp, NULL, CS name, NULL, \
-         ((flags) == O_RDONLY)? DB_UNKNOWN : DB_HASH, \
-         ((flags) == O_RDONLY)? DB_RDONLY : DB_CREATE, \
-         mode)) != 0) *(dbpp) = NULL
-#else
-#define EXIM_DBOPEN(name, flags, mode, dbpp) \
+/* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
+# define EXIM_DBGET(db, key, data)      \
+       (ENV_TO_DB(db)->get(ENV_TO_DB(db), NULL, &key, &data, 0) == 0)
+
+/* EXIM_DBPUT - returns nothing useful, assumes replace mode */
+# define EXIM_DBPUT(db, key, data)      \
+       ENV_TO_DB(db)->put(ENV_TO_DB(db), NULL, &key, &data, 0)
+
+/* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
+# define EXIM_DBPUTB(db, key, data)      \
+       ENV_TO_DB(db)->put(ENV_TO_DB(db), NULL, &key, &data, DB_NOOVERWRITE)
+
+/* Return values from EXIM_DBPUTB */
+
+# define EXIM_DBPUTB_OK  0
+# define EXIM_DBPUTB_DUP DB_KEYEXIST
+
+/* EXIM_DBDEL */
+# define EXIM_DBDEL(db, key)     ENV_TO_DB(db)->del(ENV_TO_DB(db), NULL, &key, 0)
+
+/* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
+
+# define EXIM_DBCREATE_CURSOR(db, cursor) \
+       ENV_TO_DB(db)->cursor(ENV_TO_DB(db), NULL, cursor, 0)
+
+/* EXIM_DBSCAN - returns TRUE if data is returned, FALSE at end */
+# define EXIM_DBSCAN(db, key, data, first, cursor)      \
+       ((cursor)->c_get(cursor, &key, &data,         \
+         (first? DB_FIRST : DB_NEXT)) == 0)
+
+/* EXIM_DBDELETE_CURSOR - terminate scanning operation */
+# define EXIM_DBDELETE_CURSOR(cursor) \
+       (cursor)->c_close(cursor)
+
+/* EXIM_DBCLOSE */
+# define EXIM_DBCLOSE__(db) \
+       (ENV_TO_DB(db)->close(ENV_TO_DB(db), 0) , ((DB_ENV *)(db))->close((DB_ENV *)(db), DB_FORCESYNC))
+
+/* Datum access types - these are intended to be assignable. */
+
+# define EXIM_DATUM_SIZE(datum)  (datum).size
+# define EXIM_DATUM_DATA(datum)  (datum).data
+
+/* The whole datum structure contains other fields that must be cleared
+before use, but we don't have to free anything after reading data. */
+
+# define EXIM_DATUM_INIT(datum)   memset(&datum, 0, sizeof(datum))
+# define EXIM_DATUM_FREE(datum)
+
+#else  /* pre- 4.1 */
+
+# define EXIM_DB       DB
+
+/* Cursor type, for scanning */
+# define EXIM_CURSOR   DBC
+
+/* The datum type used for queries */
+# define EXIM_DATUM    DBT
+
+/* Some text for messages */
+# define EXIM_DBTYPE   "db (v3/4)"
+
+/* Access functions */
+
+/* EXIM_DBOPEN - sets *dbpp to point to an EXIM_DB, NULL if failed. */
+
+# define EXIM_DBOPEN__(name, dirname, flags, mode, dbpp) \
        if (db_create(dbpp, NULL, 0) != 0 || \
          ((*dbpp)->set_errcall(*dbpp, dbfn_bdb_error_callback), \
          ((*dbpp)->open)(*dbpp, CS name, NULL, \
          ((flags) == O_RDONLY)? DB_UNKNOWN : DB_HASH, \
          ((flags) == O_RDONLY)? DB_RDONLY : DB_CREATE, \
          mode)) != 0) *(dbpp) = NULL
-#endif
 
 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
-#define EXIM_DBGET(db, key, data)      \
+# define EXIM_DBGET(db, key, data)      \
        ((db)->get(db, NULL, &key, &data, 0) == 0)
 
 /* EXIM_DBPUT - returns nothing useful, assumes replace mode */
-#define EXIM_DBPUT(db, key, data)      \
+# define EXIM_DBPUT(db, key, data)      \
        (db)->put(db, NULL, &key, &data, 0)
 
 /* EXIM_DBPUTB - non-overwriting for use by dbmbuild */
-#define EXIM_DBPUTB(db, key, data)      \
+# define EXIM_DBPUTB(db, key, data)      \
        (db)->put(db, NULL, &key, &data, DB_NOOVERWRITE)
 
 /* Return values from EXIM_DBPUTB */
 
-#define EXIM_DBPUTB_OK  0
-#define EXIM_DBPUTB_DUP DB_KEYEXIST
+# define EXIM_DBPUTB_OK  0
+# define EXIM_DBPUTB_DUP DB_KEYEXIST
 
 /* EXIM_DBDEL */
-#define EXIM_DBDEL(db, key)     (db)->del(db, NULL, &key, 0)
+# define EXIM_DBDEL(db, key)     (db)->del(db, NULL, &key, 0)
 
 /* EXIM_DBCREATE_CURSOR - initialize for scanning operation */
 
-#define EXIM_DBCREATE_CURSOR(db, cursor) \
+# define EXIM_DBCREATE_CURSOR(db, cursor) \
        (db)->cursor(db, NULL, cursor, 0)
 
 /* EXIM_DBSCAN - returns TRUE if data is returned, FALSE at end */
-#define EXIM_DBSCAN(db, key, data, first, cursor)      \
+# define EXIM_DBSCAN(db, key, data, first, cursor)      \
        ((cursor)->c_get(cursor, &key, &data,         \
          (first? DB_FIRST : DB_NEXT)) == 0)
 
 /* EXIM_DBDELETE_CURSOR - terminate scanning operation */
-#define EXIM_DBDELETE_CURSOR(cursor) \
+# define EXIM_DBDELETE_CURSOR(cursor) \
        (cursor)->c_close(cursor)
 
 /* EXIM_DBCLOSE */
-#define EXIM_DBCLOSE(db)        (db)->close(db, 0)
+# define EXIM_DBCLOSE__(db)        (db)->close(db, 0)
 
 /* Datum access types - these are intended to be assignable. */
 
-#define EXIM_DATUM_SIZE(datum)  (datum).size
-#define EXIM_DATUM_DATA(datum)  (datum).data
+# define EXIM_DATUM_SIZE(datum)  (datum).size
+# define EXIM_DATUM_DATA(datum)  (datum).data
 
 /* The whole datum structure contains other fields that must be cleared
 before use, but we don't have to free anything after reading data. */
 
-#define EXIM_DATUM_INIT(datum)   memset(&datum, 0, sizeof(datum))
-#define EXIM_DATUM_FREE(datum)
+# define EXIM_DATUM_INIT(datum)   memset(&datum, 0, sizeof(datum))
+# define EXIM_DATUM_FREE(datum)
+
+#endif
 
 
 #else /* DB_VERSION_MAJOR >= 3 */
@@ -215,7 +304,7 @@ before use, but we don't have to free anything after reading data. */
 /* Access functions */
 
 /* EXIM_DBOPEN - sets *dbpp to point to an EXIM_DB, NULL if failed */
-#define EXIM_DBOPEN(name, flags, mode, dbpp)         \
+#define EXIM_DBOPEN__(name, dirname, flags, mode, dbpp)         \
        if ((errno = db_open(CS name, DB_HASH,           \
          ((flags) == O_RDONLY)? DB_RDONLY : DB_CREATE, \
          mode, NULL, NULL, dbpp)) != 0) *(dbpp) = NULL
@@ -264,7 +353,7 @@ the new option that is available, so I guess that it happened at 2.5.x. */
        (cursor)->c_close(cursor)
 
 /* EXIM_DBCLOSE */
-#define EXIM_DBCLOSE(db)        (db)->close(db, 0)
+#define EXIM_DBCLOSE__(db)        (db)->close(db, 0)
 
 /* Datum access types - these are intended to be assignable. */
 
@@ -312,7 +401,7 @@ before been able to pass successfully. */
 /* Access functions */
 
 /* EXIM_DBOPEN - sets *dbpp to point to an EXIM_DB, NULL if failed */
-#define EXIM_DBOPEN(name, flags, mode, dbpp) \
+#define EXIM_DBOPEN__(name, dirname, flags, mode, dbpp) \
        *(dbpp) = dbopen(CS name, flags, mode, DB_HASH, NULL)
 
 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
@@ -347,7 +436,7 @@ refer to cursor, to keep picky compilers happy. */
 #define EXIM_DBDELETE_CURSOR(cursor) { cursor = cursor; }
 
 /* EXIM_DBCLOSE */
-#define EXIM_DBCLOSE(db)        (db)->close(db)
+#define EXIM_DBCLOSE__(db)        (db)->close(db)
 
 /* Datum access types - these are intended to be assignable */
 
@@ -389,7 +478,7 @@ typedef struct {
 /* Access functions */
 
 /* EXIM_DBOPEN - returns a EXIM_DB *, NULL if failed */
-#define EXIM_DBOPEN(name, flags, mode, dbpp) \
+#define EXIM_DBOPEN__(name, dirname, flags, mode, dbpp) \
      { (*(dbpp)) = (EXIM_DB *) malloc(sizeof(EXIM_DB));\
        if (*(dbpp) != NULL) { \
          (*(dbpp))->lkey.dptr = NULL;\
@@ -435,7 +524,7 @@ refer to cursor, to keep picky compilers happy. */
 #define EXIM_DBDELETE_CURSOR(cursor) { cursor = cursor; }
 
 /* EXIM_DBCLOSE */
-#define EXIM_DBCLOSE(db) \
+#define EXIM_DBCLOSE__(db) \
 { gdbm_close((db)->gdbm);\
   if ((db)->lkey.dptr != NULL) free((db)->lkey.dptr);\
   free(db); }
@@ -478,7 +567,7 @@ interface */
 /* Access functions */
 
 /* EXIM_DBOPEN - returns a EXIM_DB *, NULL if failed */
-#define EXIM_DBOPEN(name, flags, mode, dbpp) \
+#define EXIM_DBOPEN__(name, dirname, flags, mode, dbpp) \
        *(dbpp) = dbm_open(CS name, flags, mode)
 
 /* EXIM_DBGET - returns TRUE if successful, FALSE otherwise */
@@ -513,7 +602,7 @@ refer to cursor, to keep picky compilers happy. */
 #define EXIM_DBDELETE_CURSOR(cursor) { cursor = cursor; }
 
 /* EXIM_DBCLOSE */
-#define EXIM_DBCLOSE(db) dbm_close(db)
+#define EXIM_DBCLOSE__(db) dbm_close(db)
 
 /* Datum access types - these are intended to be assignable */
 
@@ -528,6 +617,34 @@ after reading data. */
 
 #endif /* USE_GDBM */
 
+
+
+
+
+# ifdef COMPILE_UTILITY
+
+#  define EXIM_DBOPEN(name, dirname, flags, mode, dbpp) \
+  EXIM_DBOPEN__(name, dirname, flags, mode, dbpp)
+#  define EXIM_DBCLOSE(db) EXIM_DBCLOSE__(db)
+
+# else
+
+#  define EXIM_DBOPEN(name, dirname, flags, mode, dbpp) \
+  do { \
+  DEBUG(D_hints_lookup) \
+    debug_printf("EXIM_DBOPEN: file <%s> dir <%s> flags 0x%x\n", \
+      (name), (dirname), flags); \
+  EXIM_DBOPEN__(name, dirname, flags, mode, dbpp); \
+  DEBUG(D_hints_lookup) debug_printf("returned from EXIM_DBOPEN: %p\n", *dbpp); \
+  } while(0)
+#  define EXIM_DBCLOSE(db) \
+  do { \
+  DEBUG(D_hints_lookup) debug_printf("EXIM_DBCLOSE(%p)\n", db); \
+  EXIM_DBCLOSE__(db); \
+  } while(0)
+
+#  endif
+
 /********************* End of dbm library definitions **********************/
 
 
index fcdc5a89725143587756b30aba5a3a400ea2d255..a11e12df47300e74840ca003889684a4966d41ab 100644 (file)
@@ -185,10 +185,10 @@ dcc_process(uschar **listptr)
 
   /* If sockip contains an ip, we use a tcp socket, otherwise a UNIX socket */
   if(Ustrcmp(sockip, "")){
-    ipaddress = gethostbyname((char *)sockip);
-    bzero((char *) &serv_addr_in, sizeof(serv_addr_in));
+    ipaddress = gethostbyname(CS sockip);
+    bzero(CS  &serv_addr_in, sizeof(serv_addr_in));
     serv_addr_in.sin_family = AF_INET;
-    bcopy((char *)ipaddress->h_addr, (char *)&serv_addr_in.sin_addr.s_addr, ipaddress->h_length);
+    bcopy(CS ipaddress->h_addr, CS &serv_addr_in.sin_addr.s_addr, ipaddress->h_length);
     serv_addr_in.sin_port = htons(portnr);
     if ((sockfd = socket(AF_INET, SOCK_STREAM,0)) < 0){
       DEBUG(D_acl)
index 35571547f656ed6c465509d6da102d357ab89ff1..09e03f1e499f81a9476a6ce279af089803ed631e 100644 (file)
@@ -182,17 +182,21 @@ if (debug_ptr == debug_buffer)
   {
   DEBUG(D_timestamp)
     {
-    time_t now = time(NULL);
-    struct tm *t = timestamps_utc? gmtime(&now) : localtime(&now);
-    (void) sprintf(CS debug_ptr, "%02d:%02d:%02d ", t->tm_hour, t->tm_min,
-      t->tm_sec);
-    while(*debug_ptr != 0) debug_ptr++;
+    struct timeval now;
+    time_t tmp;
+    struct tm * t;
+
+    gettimeofday(&now, NULL);
+    tmp = now.tv_sec;
+    t = timestamps_utc ? gmtime(&tmp) : localtime(&tmp);
+    debug_ptr += sprintf(CS debug_ptr,
+      LOGGING(millisec) ? "%02d:%02d:%02d.%03d " : "%02d:%02d:%02d ",
+      t->tm_hour, t->tm_min, t->tm_sec, (int)(now.tv_usec/1000));
     }
 
   DEBUG(D_pid)
     {
-    sprintf(CS debug_ptr, "%5d ", (int)getpid());
-    while(*debug_ptr != 0) debug_ptr++;
+    debug_ptr += sprintf(CS debug_ptr, "%5d ", (int)getpid());
     }
 
   /* Set up prefix if outputting for host checking and not debugging */
index cb4616e6cd24143a3934e9c9792c02e41c86aefe..73921980e263f4bb1ae94cce318398020c814fd9 100644 (file)
@@ -9,6 +9,7 @@
 
 
 #include "exim.h"
+#include "transports/smtp.h"
 #include <assert.h>
 
 
@@ -381,6 +382,7 @@ for (addr2 = addr->next; addr2; addr2 = addr2->next)
   addr2->transport_return = addr->transport_return;
   addr2->basic_errno =     addr->basic_errno;
   addr2->more_errno =      addr->more_errno;
+  addr2->delivery_usec =    addr->delivery_usec;
   addr2->special_action =   addr->special_action;
   addr2->message =         addr->message;
   addr2->user_message =            addr->user_message;
@@ -750,7 +752,12 @@ if (LOGGING(proxy) && proxy_local_address)
   }
 #endif
 
-return d_log_interface(s, sp, pp);
+s = d_log_interface(s, sp, pp);
+
+if (testflag(addr, af_tcp_fastopen))
+  s = string_catn(s, sp, pp, US" TFO", 4);
+
+return s;
 }
 
 
@@ -841,7 +848,7 @@ deliver_host =   addr->host_used ? addr->host_used->name : NULL;
          addr->host_used
           || Ustrcmp(addr->transport->driver_name, "smtp") == 0
          || Ustrcmp(addr->transport->driver_name, "lmtp") == 0
-        ? addr->message : NULL); 
+        ? addr->message : NULL);
 
 deliver_host_port =    save_port;
 deliver_host_address = save_address;
@@ -1028,6 +1035,43 @@ return str;
 }
 
 
+
+void
+timesince(struct timeval * diff, struct timeval * then)
+{
+gettimeofday(diff, NULL);
+diff->tv_sec -= then->tv_sec;
+if ((diff->tv_usec -= then->tv_usec) < 0)
+  {
+  diff->tv_sec--;
+  diff->tv_usec += 1000*1000;
+  }
+}
+
+
+
+static uschar *
+string_timediff(struct timeval * diff)
+{
+static uschar buf[sizeof("0.000s")];
+
+if (diff->tv_sec >= 5 || !LOGGING(millisec))
+  return readconf_printtime((int)diff->tv_sec);
+
+sprintf(CS buf, "%d.%03ds", (int)diff->tv_sec, (int)diff->tv_usec/1000);
+return buf;
+}
+
+
+uschar *
+string_timesince(struct timeval * then)
+{
+struct timeval diff;
+
+timesince(&diff, then);
+return string_timediff(&diff);
+}
+
 /******************************************************************************/
 
 
@@ -1156,11 +1200,11 @@ else
     }
 
 #ifndef DISABLE_PRDR
-  if (addr->flags & af_prdr_used)
+  if (testflag(addr, af_prdr_used))
     s = string_catn(s, &size, &ptr, US" PRDR", 5);
 #endif
 
-  if (addr->flags & af_chunking_used)
+  if (testflag(addr, af_chunking_used))
     s = string_catn(s, &size, &ptr, US" K", 2);
   }
 
@@ -1190,11 +1234,13 @@ if (  LOGGING(smtp_confirmation)
 
 if (LOGGING(queue_time))
   s = string_append(s, &size, &ptr, 2, US" QT=",
-    readconf_printtime( (int) ((long)time(NULL) - (long)received_time)) );
+    string_timesince(&received_time));
 
 if (LOGGING(deliver_time))
-  s = string_append(s, &size, &ptr, 2, US" DT=",
-    readconf_printtime(addr->more_errno));
+  {
+  struct timeval diff = {.tv_sec = addr->more_errno, .tv_usec = addr->delivery_usec};
+  s = string_append(s, &size, &ptr, 2, US" DT=", string_timediff(&diff));
+  }
 
 /* string_cat() always leaves room for the terminator. Release the
 store we used to build the line after writing it. */
@@ -1616,7 +1662,7 @@ else
   later (with a log entry). */
 
   if (!*sender_address && message_age >= ignore_bounce_errors_after)
-    setflag(addr, af_ignore_error);
+    addr->prop.ignore_error = TRUE;
 
   /* Freeze the message if requested, or if this is a bounce message (or other
   message with null sender) and this address does not have its own errors
@@ -1624,7 +1670,7 @@ else
   to ignore occurs later, instead of sending a message. Logging of freezing
   occurs later, just before writing the -H file. */
 
-  if (  !testflag(addr, af_ignore_error)
+  if (  !addr->prop.ignore_error
      && (  addr->special_action == SPECIAL_FREEZE
         || (sender_address[0] == 0 && !addr->prop.errors_address)
      )  )
@@ -2175,7 +2221,7 @@ if (  !shadowing
   addr->return_filename =
     spool_fname(US"msglog", message_subdir, message_id,
       string_sprintf("-%d-%d", getpid(), return_count++));
-  
+
   if ((addr->return_file = open_msglog_file(addr->return_filename, 0400, &error)) < 0)
     {
     common_error(TRUE, addr, errno, US"Unable to %s file for %s transport "
@@ -2346,6 +2392,7 @@ if ((pid = fork()) == 0)
       || (ret = write(pfd[pipe_write], &addr2->flags, sizeof(addr2->flags))) != sizeof(addr2->flags)
       || (ret = write(pfd[pipe_write], &addr2->basic_errno,    sizeof(int))) != sizeof(int)
       || (ret = write(pfd[pipe_write], &addr2->more_errno,     sizeof(int))) != sizeof(int)
+      || (ret = write(pfd[pipe_write], &addr2->delivery_usec,  sizeof(int))) != sizeof(int)
       || (ret = write(pfd[pipe_write], &addr2->special_action, sizeof(int))) != sizeof(int)
       || (ret = write(pfd[pipe_write], &addr2->transport,
         sizeof(transport_instance *))) != sizeof(transport_instance *)
@@ -2413,6 +2460,7 @@ for (addr2 = addr; addr2; addr2 = addr2->next)
     len = read(pfd[pipe_read], &addr2->flags, sizeof(addr2->flags));
     len = read(pfd[pipe_read], &addr2->basic_errno,    sizeof(int));
     len = read(pfd[pipe_read], &addr2->more_errno,     sizeof(int));
+    len = read(pfd[pipe_read], &addr2->delivery_usec,  sizeof(int));
     len = read(pfd[pipe_read], &addr2->special_action, sizeof(int));
     len = read(pfd[pipe_read], &addr2->transport,
       sizeof(transport_instance *));
@@ -2638,8 +2686,8 @@ time_t now = time(NULL);
 
 while (addr_local)
   {
-  time_t delivery_start;
-  int deliver_time;
+  struct timeval delivery_start;
+  struct timeval deliver_time;
   address_item *addr2, *addr3, *nextaddr;
   int logflags = LOG_MAIN;
   int logchar = dont_deliver? '*' : '=';
@@ -2734,7 +2782,8 @@ while (addr_local)
       BOOL ok =
            tp == next->transport
        && !previously_transported(next, TRUE)
-       && (addr->flags & (af_pfr|af_file)) == (next->flags & (af_pfr|af_file))
+       && testflag(addr, af_pfr) == testflag(next, af_pfr)
+       && testflag(addr, af_file) == testflag(next, af_file)
        && (!uses_lp  || Ustrcmp(next->local_part, addr->local_part) == 0)
        && (!uses_dom || Ustrcmp(next->domain, addr->domain) == 0)
        && same_strings(next->prop.errors_address, addr->prop.errors_address)
@@ -2935,9 +2984,10 @@ while (addr_local)
   single delivery. */
 
   deliver_set_expansions(addr);
-  delivery_start = time(NULL);
+
+  gettimeofday(&delivery_start, NULL);
   deliver_local(addr, FALSE);
-  deliver_time = (int)(time(NULL) - delivery_start);
+  timesince(&deliver_time, &delivery_start);
 
   /* If a shadow transport (which must perforce be another local transport), is
   defined, and its condition is met, we must pass the message to the shadow
@@ -3074,7 +3124,11 @@ while (addr_local)
 
     /* Done with this address */
 
-    if (result == OK) addr2->more_errno = deliver_time;
+    if (result == OK)
+      {
+      addr2->more_errno = deliver_time.tv_sec;
+      addr2->delivery_usec = deliver_time.tv_usec;
+      }
     post_process_one(addr2, result, logflags, DTYPE_TRANSPORT, logchar);
 
     /* If a pipe delivery generated text to be sent back, the result may be
@@ -3216,6 +3270,9 @@ small items (less than PIPE_BUF, which seems to be at least 512 in any Unix and
 often bigger) so even if we are reading while the subprocess is still going, we
 should never have only a partial item in the buffer.
 
+hs12: This assumption is not true anymore, since we got quit large items (certificate
+information and such)
+
 Argument:
   poffset     the offset of the parlist item
   eop         TRUE if the process has completed
@@ -3234,147 +3291,113 @@ address_item *addrlist = p->addrlist;
 address_item *addr = p->addr;
 pid_t pid = p->pid;
 int fd = p->fd;
-uschar *endptr = big_buffer;
-uschar *ptr = endptr;
+
 uschar *msg = p->msg;
 BOOL done = p->done;
-BOOL finished = FALSE;
-/* minimum size to read is header size including id, subid and length */
-int required = PIPE_HEADER_SIZE;
 
 /* Loop through all items, reading from the pipe when necessary. The pipe
-is set up to be non-blocking, but there are two different Unix mechanisms in
-use. Exim uses O_NONBLOCK if it is defined. This returns 0 for end of file,
-and EAGAIN for no more data. If O_NONBLOCK is not defined, Exim uses O_NDELAY,
-which returns 0 for both end of file and no more data. We distinguish the
-two cases by taking 0 as end of file only when we know the process has
-completed.
-
-Each separate item is written to the pipe in a single write(), and as they are
-all short items, the writes will all be atomic and we should never find
-ourselves in the position of having read an incomplete item. "Short" in this
-case can mean up to about 1K in the case when there is a long error message
-associated with an address. */
+used to be non-blocking. But I do not see a reason for using non-blocking I/O
+here, as the preceding select() tells us, if data is available for reading.
 
-DEBUG(D_deliver) debug_printf("reading pipe for subprocess %d (%s)\n",
-  (int)p->pid, eop? "ended" : "not ended");
+A read() on a "selected" handle should never block, but(!) it may return
+less data then we expected. (The buffer size we pass to read() shouldn't be
+understood as a "request", but as a "limit".)
 
-while (!done)
-  {
-  retry_item *r, **rp;
-  int remaining = endptr - ptr;
-  uschar header[PIPE_HEADER_SIZE + 1];
-  uschar id, subid;
-  uschar *endc;
+Each separate item is written to the pipe in a timely manner. But, especially for
+larger items, the read(2) may already return partial data from the write(2).
 
-  /* Read (first time) or top up the chars in the buffer if necessary.
-  There will be only one read if we get all the available data (i.e. don't
-  fill the buffer completely). */
+The write is atomic mostly (depending on the amount written), but atomic does
+not imply "all or noting", it just is "not intermixed" with other writes on the
+same channel (pipe).
 
-  if (remaining < required && !finished)
-    {
-    int len;
-    int available = big_buffer_size - remaining;
-
-    if (remaining > 0) memmove(big_buffer, ptr, remaining);
-
-    ptr = big_buffer;
-    endptr = big_buffer + remaining;
-    len = read(fd, endptr, available);
-
-    DEBUG(D_deliver) debug_printf("read() yielded %d\n", len);
-
-    /* If the result is EAGAIN and the process is not complete, just
-    stop reading any more and process what we have already. */
-
-    if (len < 0)
-      {
-      if (!eop && errno == EAGAIN) len = 0; else
-        {
-        msg = string_sprintf("failed to read pipe from transport process "
-          "%d for transport %s: %s", pid, addr->transport->driver_name,
-          strerror(errno));
-        break;
-        }
-      }
+*/
 
-    /* If the length is zero (eof or no-more-data), just process what we
-    already have. Note that if the process is still running and we have
-    read all the data in the pipe (but less that "available") then we
-    won't read any more, as "finished" will get set. */
+DEBUG(D_deliver) debug_printf("reading pipe for subprocess %d (%s)\n",
+  (int)p->pid, eop? "ended" : "not ended yet");
 
-    endptr += len;
-    remaining += len;
-    finished = len != available;
+while (!done)
+  {
+  retry_item *r, **rp;
+  uschar pipeheader[PIPE_HEADER_SIZE+1];
+  uschar *id = &pipeheader[0];
+  uschar *subid = &pipeheader[1];
+  uschar *ptr = big_buffer;
+  size_t required = PIPE_HEADER_SIZE; /* first the pipehaeder, later the data */
+  ssize_t got;
+
+  DEBUG(D_deliver) debug_printf(
+    "expect %lu bytes (pipeheader) from tpt process %d\n", (u_long)required, pid);
+
+  /* We require(!) all the PIPE_HEADER_SIZE bytes here, as we know,
+  they're written in a timely manner, so waiting for the write shouldn't hurt a lot.
+  If we get less, we can assume the subprocess do be done and do not expect any further
+  information from it. */
+
+  got = readn(fd, pipeheader, required);
+  if (got != required)
+    {
+      msg = string_sprintf("got %d of %d bytes (pipeheader) "
+        "from transport process %d for transport %s",
+        got, PIPE_HEADER_SIZE, pid, addr->transport->driver_name);
+      done = TRUE;
+      break;
     }
 
-  /* If we are at the end of the available data, exit the loop. */
-  if (ptr >= endptr) break;
+  pipeheader[PIPE_HEADER_SIZE] = '\0';
+  DEBUG(D_deliver)
+    debug_printf("got %ld bytes (pipeheader) from transport process %d\n",
+      (long) got, pid);
 
-  /* copy and read header */
-  memcpy(header, ptr, PIPE_HEADER_SIZE);
-  header[PIPE_HEADER_SIZE] = '\0';
-  id = header[0];
-  subid = header[1];
-  required = Ustrtol(header + 2, &endc, 10) + PIPE_HEADER_SIZE;     /* header + data */
+  {
+  /* If we can't decode the pipeheader, the subprocess seems to have a
+  problem, we do not expect any furher information from it. */
+  char *endc;
+  required = Ustrtol(pipeheader+2, &endc, 10);
   if (*endc)
     {
-    msg = string_sprintf("failed to read pipe from transport process "
-      "%d for transport %s: error reading size from header", pid, addr->transport->driver_name);
+    msg = string_sprintf("failed to read pipe "
+      "from transport process %d for transport %s: error decoding size from header",
+      pid, addr->transport->driver_name);
     done = TRUE;
     break;
     }
+  }
 
   DEBUG(D_deliver)
-    debug_printf("header read  id:%c,subid:%c,size:%s,required:%d,remaining:%d,finished:%d\n",
-                    id, subid, header+2, required, remaining, finished);
-
-  /* is there room for the dataset we want to read ? */
-  if (required > big_buffer_size - PIPE_HEADER_SIZE)
-    {
-    msg = string_sprintf("failed to read pipe from transport process "
-      "%d for transport %s: big_buffer too small! required size=%d buffer size=%d", pid, addr->transport->driver_name,
-      required, big_buffer_size - PIPE_HEADER_SIZE);
-    done = TRUE;
-    break;
-    }
-
-  /* We wrote all datasets with atomic write() calls.  Remaining < required only
-  happens if big_buffer was too small to get all available data from pipe;
-  finished has to be false as well. */
-
-  if (remaining < required)
-    {
-    if (!finished)
-      continue;
-    msg = string_sprintf("failed to read pipe from transport process "
-      "%d for transport %s: required size=%d > remaining size=%d and finished=true",
-      pid, addr->transport->driver_name, required, remaining);
-    done = TRUE;
-    break;
+    debug_printf("expect %lu bytes (pipedata) from transport process %d\n",
+      (u_long)required, pid);
+
+  /* Same as above, the transport process will write the bytes announced
+  in a timely manner, so we can just wait for the bytes, getting less than expected
+  is considered a problem of the subprocess, we do not expect anything else from it. */
+  got = readn(fd, big_buffer, required);
+  if (got != required)
+    {
+      msg = string_sprintf("got only %d of %d bytes (pipedata) "
+        "from transport process %d for transport %s",
+        got, required, pid, addr->transport->driver_name);
+      done = TRUE;
+      break;
     }
 
-  /* Step past the header */
-  ptr += PIPE_HEADER_SIZE;
-
   /* Handle each possible type of item, assuming the complete item is
   available in store. */
 
-  switch (id)
+  switch (*id)
     {
     /* Host items exist only if any hosts were marked unusable. Match
     up by checking the IP address. */
 
     case 'H':
-    for (h = addrlist->host_list; h; h = h->next)
-      {
-      if (!h->address || Ustrcmp(h->address, ptr+2) != 0) continue;
-      h->status = ptr[0];
-      h->why = ptr[1];
-      }
-    ptr += 2;
-    while (*ptr++);
-    break;
+      for (h = addrlist->host_list; h; h = h->next)
+       {
+       if (!h->address || Ustrcmp(h->address, ptr+2) != 0) continue;
+       h->status = ptr[0];
+       h->why = ptr[1];
+       }
+      ptr += 2;
+      while (*ptr++);
+      break;
 
     /* Retry items are sent in a preceding R item for each address. This is
     kept separate to keep each message short enough to guarantee it won't
@@ -3388,62 +3411,61 @@ while (!done)
     that a "delete" item is dropped in favour of an "add" item. */
 
     case 'R':
-    if (!addr) goto ADDR_MISMATCH;
+      if (!addr) goto ADDR_MISMATCH;
 
-    DEBUG(D_deliver|D_retry)
-      debug_printf("reading retry information for %s from subprocess\n",
-        ptr+1);
+      DEBUG(D_deliver|D_retry)
+       debug_printf("reading retry information for %s from subprocess\n",
+         ptr+1);
 
-    /* Cut out any "delete" items on the list. */
+      /* Cut out any "delete" items on the list. */
 
-    for (rp = &(addr->retries); (r = *rp); rp = &r->next)
-      if (Ustrcmp(r->key, ptr+1) == 0)           /* Found item with same key */
-        {
-        if ((r->flags & rf_delete) == 0) break;  /* It was not "delete" */
-        *rp = r->next;                           /* Excise a delete item */
-        DEBUG(D_deliver|D_retry)
-          debug_printf("  existing delete item dropped\n");
-        }
+      for (rp = &addr->retries; (r = *rp); rp = &r->next)
+       if (Ustrcmp(r->key, ptr+1) == 0)           /* Found item with same key */
+         {
+         if (!(r->flags & rf_delete)) break;      /* It was not "delete" */
+         *rp = r->next;                           /* Excise a delete item */
+         DEBUG(D_deliver|D_retry)
+           debug_printf("  existing delete item dropped\n");
+         }
 
-    /* We want to add a delete item only if there is no non-delete item;
-    however we still have to step ptr through the data. */
+      /* We want to add a delete item only if there is no non-delete item;
+      however we still have to step ptr through the data. */
 
-    if (!r || (*ptr & rf_delete) == 0)
-      {
-      r = store_get(sizeof(retry_item));
-      r->next = addr->retries;
-      addr->retries = r;
-      r->flags = *ptr++;
-      r->key = string_copy(ptr);
-      while (*ptr++);
-      memcpy(&(r->basic_errno), ptr, sizeof(r->basic_errno));
-      ptr += sizeof(r->basic_errno);
-      memcpy(&(r->more_errno), ptr, sizeof(r->more_errno));
-      ptr += sizeof(r->more_errno);
-      r->message = (*ptr)? string_copy(ptr) : NULL;
-      DEBUG(D_deliver|D_retry)
-        debug_printf("  added %s item\n",
-          ((r->flags & rf_delete) == 0)? "retry" : "delete");
-      }
+      if (!r || !(*ptr & rf_delete))
+       {
+       r = store_get(sizeof(retry_item));
+       r->next = addr->retries;
+       addr->retries = r;
+       r->flags = *ptr++;
+       r->key = string_copy(ptr);
+       while (*ptr++);
+       memcpy(&r->basic_errno, ptr, sizeof(r->basic_errno));
+       ptr += sizeof(r->basic_errno);
+       memcpy(&r->more_errno, ptr, sizeof(r->more_errno));
+       ptr += sizeof(r->more_errno);
+       r->message = *ptr ? string_copy(ptr) : NULL;
+       DEBUG(D_deliver|D_retry) debug_printf("  added %s item\n",
+           r->flags & rf_delete ? "delete" : "retry");
+       }
 
-    else
-      {
-      DEBUG(D_deliver|D_retry)
-        debug_printf("  delete item not added: non-delete item exists\n");
-      ptr++;
-      while(*ptr++);
-      ptr += sizeof(r->basic_errno) + sizeof(r->more_errno);
-      }
+      else
+       {
+       DEBUG(D_deliver|D_retry)
+         debug_printf("  delete item not added: non-delete item exists\n");
+       ptr++;
+       while(*ptr++);
+       ptr += sizeof(r->basic_errno) + sizeof(r->more_errno);
+       }
 
-    while(*ptr++);
-    break;
+      while(*ptr++);
+      break;
 
     /* Put the amount of data written into the parlist block */
 
     case 'S':
-    memcpy(&(p->transport_count), ptr, sizeof(transport_count));
-    ptr += sizeof(transport_count);
-    break;
+      memcpy(&(p->transport_count), ptr, sizeof(transport_count));
+      ptr += sizeof(transport_count);
+      break;
 
     /* Address items are in the order of items on the address chain. We
     remember the current address value in case this function is called
@@ -3454,164 +3476,163 @@ while (!done)
 
 #ifdef SUPPORT_TLS
     case 'X':
-    if (!addr) goto ADDR_MISMATCH;          /* Below, in 'A' handler */
-    switch (subid)
-      {
-      case '1':
-      addr->cipher = NULL;
-      addr->peerdn = NULL;
-
-      if (*ptr)
-       addr->cipher = string_copy(ptr);
-      while (*ptr++);
-      if (*ptr)
-       addr->peerdn = string_copy(ptr);
-      break;
-
-      case '2':
-      if (*ptr)
-       (void) tls_import_cert(ptr, &addr->peercert);
-      else
-       addr->peercert = NULL;
-      break;
+      if (!addr) goto ADDR_MISMATCH;          /* Below, in 'A' handler */
+      switch (*subid)
+       {
+       case '1':
+         addr->cipher = NULL;
+         addr->peerdn = NULL;
 
-      case '3':
-      if (*ptr)
-       (void) tls_import_cert(ptr, &addr->ourcert);
-      else
-       addr->ourcert = NULL;
-      break;
+         if (*ptr)
+           addr->cipher = string_copy(ptr);
+         while (*ptr++);
+         if (*ptr)
+           addr->peerdn = string_copy(ptr);
+         break;
+
+       case '2':
+         if (*ptr)
+           (void) tls_import_cert(ptr, &addr->peercert);
+         else
+           addr->peercert = NULL;
+         break;
+
+       case '3':
+         if (*ptr)
+           (void) tls_import_cert(ptr, &addr->ourcert);
+         else
+           addr->ourcert = NULL;
+         break;
 
 # ifndef DISABLE_OCSP
-      case '4':
-      addr->ocsp = OCSP_NOT_REQ;
-      if (*ptr)
-       addr->ocsp = *ptr - '0';
-      break;
+       case '4':
+         addr->ocsp = *ptr ? *ptr - '0' : OCSP_NOT_REQ;
+         break;
 # endif
-      }
-    while (*ptr++);
-    break;
+       }
+      while (*ptr++);
+      break;
 #endif /*SUPPORT_TLS*/
 
     case 'C':  /* client authenticator information */
-    switch (subid)
-      {
-      case '1':
-       addr->authenticator = (*ptr)? string_copy(ptr) : NULL;
-       break;
-      case '2':
-       addr->auth_id = (*ptr)? string_copy(ptr) : NULL;
-       break;
-      case '3':
-       addr->auth_sndr = (*ptr)? string_copy(ptr) : NULL;
-       break;
-      }
-    while (*ptr++);
-    break;
+      switch (*subid)
+       {
+       case '1': addr->authenticator = *ptr ? string_copy(ptr) : NULL; break;
+       case '2': addr->auth_id = *ptr ? string_copy(ptr) : NULL;       break;
+       case '3': addr->auth_sndr = *ptr ? string_copy(ptr) : NULL;     break;
+       }
+      while (*ptr++);
+      break;
 
 #ifndef DISABLE_PRDR
     case 'P':
-    addr->flags |= af_prdr_used;
-    break;
+      setflag(addr, af_prdr_used);
+      break;
 #endif
 
     case 'K':
-    addr->flags |= af_chunking_used;
-    break;
+      setflag(addr, af_chunking_used);
+      break;
 
-    case 'D':
-    if (!addr) goto ADDR_MISMATCH;
-    memcpy(&(addr->dsn_aware), ptr, sizeof(addr->dsn_aware));
-    ptr += sizeof(addr->dsn_aware);
-    DEBUG(D_deliver) debug_printf("DSN read: addr->dsn_aware = %d\n", addr->dsn_aware);
-    break;
+    case 'T':
+      setflag(addr, af_tcp_fastopen);
+      break;
 
-    case 'A':
-    if (!addr)
-      {
-      ADDR_MISMATCH:
-      msg = string_sprintf("address count mismatch for data read from pipe "
-        "for transport process %d for transport %s", pid,
-          addrlist->transport->driver_name);
-      done = TRUE;
+    case 'D':
+      if (!addr) goto ADDR_MISMATCH;
+      memcpy(&(addr->dsn_aware), ptr, sizeof(addr->dsn_aware));
+      ptr += sizeof(addr->dsn_aware);
+      DEBUG(D_deliver) debug_printf("DSN read: addr->dsn_aware = %d\n", addr->dsn_aware);
       break;
-      }
 
-    switch (subid)
-      {
-#ifdef SUPPORT_SOCKS
-      case '2':        /* proxy information; must arrive before A0 and applies to that addr XXX oops*/
-       proxy_session = TRUE;   /*XXX should this be cleared somewhere? */
-       if (*ptr == 0)
-         ptr++;
-       else
-         {
-         proxy_local_address = string_copy(ptr);
-         while(*ptr++);
-         memcpy(&proxy_local_port, ptr, sizeof(proxy_local_port));
-         ptr += sizeof(proxy_local_port);
-         }
+    case 'A':
+      if (!addr)
+       {
+       ADDR_MISMATCH:
+       msg = string_sprintf("address count mismatch for data read from pipe "
+         "for transport process %d for transport %s", pid,
+           addrlist->transport->driver_name);
+       done = TRUE;
        break;
-#endif
+       }
 
-#ifdef EXPERIMENTAL_DSN_INFO
-      case '1':        /* must arrive before A0, and applies to that addr */
-               /* Two strings: smtp_greeting and helo_response */
-       addr->smtp_greeting = string_copy(ptr);
-       while(*ptr++);
-       addr->helo_response = string_copy(ptr);
-       while(*ptr++);
-       break;
-#endif
+      switch (*subid)
+       {
+  #ifdef SUPPORT_SOCKS
+       case '2':       /* proxy information; must arrive before A0 and applies to that addr XXX oops*/
+         proxy_session = TRUE; /*XXX should this be cleared somewhere? */
+         if (*ptr == 0)
+           ptr++;
+         else
+           {
+           proxy_local_address = string_copy(ptr);
+           while(*ptr++);
+           memcpy(&proxy_local_port, ptr, sizeof(proxy_local_port));
+           ptr += sizeof(proxy_local_port);
+           }
+         break;
+  #endif
 
-      case '0':
-       addr->transport_return = *ptr++;
-       addr->special_action = *ptr++;
-       memcpy(&(addr->basic_errno), ptr, sizeof(addr->basic_errno));
-       ptr += sizeof(addr->basic_errno);
-       memcpy(&(addr->more_errno), ptr, sizeof(addr->more_errno));
-       ptr += sizeof(addr->more_errno);
-       memcpy(&(addr->flags), ptr, sizeof(addr->flags));
-       ptr += sizeof(addr->flags);
-       addr->message = (*ptr)? string_copy(ptr) : NULL;
-       while(*ptr++);
-       addr->user_message = (*ptr)? string_copy(ptr) : NULL;
-       while(*ptr++);
+  #ifdef EXPERIMENTAL_DSN_INFO
+       case '1':       /* must arrive before A0, and applies to that addr */
+                       /* Two strings: smtp_greeting and helo_response */
+         addr->smtp_greeting = string_copy(ptr);
+         while(*ptr++);
+         addr->helo_response = string_copy(ptr);
+         while(*ptr++);
+         break;
+  #endif
+
+       case '0':
+         DEBUG(D_deliver) debug_printf("A0 %s tret %d\n", addr->address, *ptr);
+         addr->transport_return = *ptr++;
+         addr->special_action = *ptr++;
+         memcpy(&addr->basic_errno, ptr, sizeof(addr->basic_errno));
+         ptr += sizeof(addr->basic_errno);
+         memcpy(&addr->more_errno, ptr, sizeof(addr->more_errno));
+         ptr += sizeof(addr->more_errno);
+         memcpy(&addr->delivery_usec, ptr, sizeof(addr->delivery_usec));
+         ptr += sizeof(addr->delivery_usec);
+         memcpy(&addr->flags, ptr, sizeof(addr->flags));
+         ptr += sizeof(addr->flags);
+         addr->message = *ptr ? string_copy(ptr) : NULL;
+         while(*ptr++);
+         addr->user_message = *ptr ? string_copy(ptr) : NULL;
+         while(*ptr++);
 
-       /* Always two strings for host information, followed by the port number and DNSSEC mark */
+         /* Always two strings for host information, followed by the port number and DNSSEC mark */
 
-       if (*ptr != 0)
-         {
-         h = store_get(sizeof(host_item));
-         h->name = string_copy(ptr);
-         while (*ptr++);
-         h->address = string_copy(ptr);
-         while(*ptr++);
-         memcpy(&(h->port), ptr, sizeof(h->port));
-         ptr += sizeof(h->port);
-         h->dnssec = *ptr == '2' ? DS_YES
-                   : *ptr == '1' ? DS_NO
-                   : DS_UNK;
-         ptr++;
-         addr->host_used = h;
-         }
-       else ptr++;
+         if (*ptr)
+           {
+           h = store_get(sizeof(host_item));
+           h->name = string_copy(ptr);
+           while (*ptr++);
+           h->address = string_copy(ptr);
+           while(*ptr++);
+           memcpy(&h->port, ptr, sizeof(h->port));
+           ptr += sizeof(h->port);
+           h->dnssec = *ptr == '2' ? DS_YES
+                     : *ptr == '1' ? DS_NO
+                     : DS_UNK;
+           ptr++;
+           addr->host_used = h;
+           }
+         else ptr++;
 
-       /* Finished with this address */
+         /* Finished with this address */
 
-       addr = addr->next;
-       break;
-      }
-    break;
+         addr = addr->next;
+         break;
+       }
+      break;
 
     /* Local interface address/port */
     case 'I':
-    if (*ptr) sending_ip_address = string_copy(ptr);
-    while (*ptr++) ;
-    if (*ptr) sending_port = atoi(CS ptr);
-    while (*ptr++) ;
-    break;
+      if (*ptr) sending_ip_address = string_copy(ptr);
+      while (*ptr++) ;
+      if (*ptr) sending_port = atoi(CS ptr);
+      while (*ptr++) ;
+      break;
 
     /* Z marks the logical end of the data. It is followed by '0' if
     continue_transport was NULL at the end of transporting, otherwise '1'.
@@ -3620,23 +3641,23 @@ while (!done)
     most normal messages it will remain NULL all the time. */
 
     case 'Z':
-    if (*ptr == '0')
-      {
-      continue_transport = NULL;
-      continue_hostname = NULL;
-      }
-    done = TRUE;
-    DEBUG(D_deliver) debug_printf("Z0%c item read\n", *ptr);
-    break;
+      if (*ptr == '0')
+       {
+       continue_transport = NULL;
+       continue_hostname = NULL;
+       }
+      done = TRUE;
+      DEBUG(D_deliver) debug_printf("Z0%c item read\n", *ptr);
+      break;
 
     /* Anything else is a disaster. */
 
     default:
-    msg = string_sprintf("malformed data (%d) read from pipe for transport "
-      "process %d for transport %s", ptr[-1], pid,
-        addr->transport->driver_name);
-    done = TRUE;
-    break;
+      msg = string_sprintf("malformed data (%d) read from pipe for transport "
+       "process %d for transport %s", ptr[-1], pid,
+         addr->transport->driver_name);
+      done = TRUE;
+      break;
     }
   }
 
@@ -3646,7 +3667,7 @@ call the function again when the process finishes. */
 p->done = done;
 
 /* If the process hadn't finished, and we haven't seen the end of the data
-or suffered a disaster, update the rest of the state, and return FALSE to
+or if we suffered a disaster, update the rest of the state, and return FALSE to
 indicate "not finished". */
 
 if (!eop && !done)
@@ -3679,6 +3700,7 @@ if (msg)
     addr->transport_return = DEFER;
     addr->special_action = SPECIAL_FREEZE;
     addr->message = msg;
+    log_write(0, LOG_MAIN|LOG_PANIC, "Delivery status for %s: %s\n", addr->address, addr->message);
     }
 
 /* Return TRUE to indicate we have got all we need from this process, even
@@ -3898,14 +3920,12 @@ for (;;)   /* Normally we do not repeat this loop */
     maxpipe = 0;
     FD_ZERO(&select_pipes);
     for (poffset = 0; poffset < remote_max_parallel; poffset++)
-      {
       if (parlist[poffset].pid != 0)
         {
         int fd = parlist[poffset].fd;
         FD_SET(fd, &select_pipes);
         if (fd > maxpipe) maxpipe = fd;
         }
-      }
 
     /* Stick in a 60-second timeout, just in case. */
 
@@ -3938,7 +3958,6 @@ for (;;)   /* Normally we do not repeat this loop */
         {
         readycount--;
         if (par_read_pipe(poffset, FALSE))    /* Finished with this pipe */
-          {
           for (;;)                            /* Loop for signals */
             {
             pid_t endedpid = waitpid(pid, &status, 0);
@@ -3948,7 +3967,6 @@ for (;;)   /* Normally we do not repeat this loop */
                 "%d (errno = %d) from waitpid() for process %d",
                 (int)endedpid, errno, (int)pid);
             }
-          }
         }
       }
 
@@ -4080,47 +4098,45 @@ while (parcount > max)
   }
 }
 
-
-
-
 static void
-rmt_dlv_checked_write(int fd, char id, char subid, void * buf, int size)
+rmt_dlv_checked_write(int fd, char id, char subid, void * buf, ssize_t size)
 {
-uschar writebuffer[PIPE_HEADER_SIZE + BIG_BUFFER_SIZE];
-int header_length;
-int ret;
+uschar pipe_header[PIPE_HEADER_SIZE+1];
+size_t total_len = PIPE_HEADER_SIZE + size;
+
+struct iovec iov[2] = {
+  { pipe_header, PIPE_HEADER_SIZE },  /* indication about the data to expect */
+  { buf, size }                       /* *the* data */
+};
+
+ssize_t ret;
 
 /* we assume that size can't get larger then BIG_BUFFER_SIZE which currently is set to 16k */
 /* complain to log if someone tries with buffer sizes we can't handle*/
 
-if (size > 99999)
+if (size > BIG_BUFFER_SIZE-1)
   {
   log_write(0, LOG_MAIN|LOG_PANIC_DIE,
-    "Failed writing transport result to pipe: can't handle buffers > 99999 bytes. truncating!\n");
-  size = 99999;
+    "Failed writing transport result to pipe: can't handle buffers > %d bytes. truncating!\n",
+      BIG_BUFFER_SIZE-1);
+  size = BIG_BUFFER_SIZE;
   }
 
-/* to keep the write() atomic we build header in writebuffer and copy buf behind */
-/* two write() calls would increase the complexity of reading from pipe */
+/* Should we check that we do not write more than PIPE_BUF? What would
+that help? */
 
 /* convert size to human readable string prepended by id and subid */
-header_length = snprintf(CS writebuffer, PIPE_HEADER_SIZE+1, "%c%c%05d", id, subid, size);
-if (header_length != PIPE_HEADER_SIZE)
-  {
+if (PIPE_HEADER_SIZE != snprintf(CS pipe_header, PIPE_HEADER_SIZE+1, "%c%c%05ld",
+    id, subid, (long)size))
   log_write(0, LOG_MAIN|LOG_PANIC_DIE, "header snprintf failed\n");
-  writebuffer[0] = '\0';
-  }
 
-DEBUG(D_deliver) debug_printf("header write id:%c,subid:%c,size:%d,final:%s\n",
-                                 id, subid, size, writebuffer);
+DEBUG(D_deliver) debug_printf("header write id:%c,subid:%c,size:%ld,final:%s\n",
+                                 id, subid, (long)size, pipe_header);
 
-if (buf && size > 0)
-  memcpy(writebuffer + PIPE_HEADER_SIZE, buf, size);
-
-size += PIPE_HEADER_SIZE;
-if ((ret = write(fd, writebuffer, size)) != size)
-  log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Failed writing transport result to pipe: %s\n",
-    ret == -1 ? strerror(errno) : "short write");
+if ((ret = writev(fd, iov, 2)) != total_len)
+  log_write(0, LOG_MAIN|LOG_PANIC_DIE,
+    "Failed writing transport result to pipe (%ld of %ld bytes): %s",
+    (long)ret, (long)total_len, ret == -1 ? strerror(errno) : "short write");
 }
 
 /*************************************************
@@ -4436,6 +4452,23 @@ for (delivery_count = 0; addr_remote; delivery_count++)
   if (tp->setup)
     (void)((tp->setup)(addr->transport, addr, NULL, uid, gid, NULL));
 
+  /* If we have a connection still open from a verify stage (lazy-close)
+  treat it as if it is a continued connection (apart from the counter used
+  for the log line mark). */
+
+  if (cutthrough.fd >= 0 && cutthrough.callout_hold_only)
+    {
+    DEBUG(D_deliver)
+      debug_printf("lazy-callout-close: have conn still open from verification\n");
+    continue_transport = cutthrough.transport;
+    continue_hostname = string_copy(cutthrough.host.name);
+    continue_host_address = string_copy(cutthrough.host.address);
+    continue_sequence = 1;
+    sending_ip_address = cutthrough.snd_ip;
+    sending_port = cutthrough.snd_port;
+    smtp_peer_options = cutthrough.peer_options;
+    }
+
   /* If this is a run to continue delivery down an already-established
   channel, check that this set of addresses matches the transport and
   the channel. If it does not, defer the addresses. If a host list exists,
@@ -4446,14 +4479,31 @@ for (delivery_count = 0; addr_remote; delivery_count++)
   if (continue_transport)
     {
     BOOL ok = Ustrcmp(continue_transport, tp->name) == 0;
-    if (ok && addr->host_list)
+
+    /* If the transport is about to override the host list do not check
+    it here but take the cost of running the transport process to discover
+    if the continued_hostname connection is suitable.  This is a layering
+    violation which is unfortunate as it requires we haul in the smtp
+    include file. */
+
+    if (ok)
       {
-      host_item *h;
-      ok = FALSE;
-      for (h = addr->host_list; h; h = h->next)
-        if (Ustrcmp(h->name, continue_hostname) == 0)
-/*XXX should also check port here */
-          { ok = TRUE; break; }
+      smtp_transport_options_block * ob;
+
+      if (  !(  Ustrcmp(tp->info->driver_name, "smtp") == 0
+            && (ob = (smtp_transport_options_block *)tp->options_block)
+            && ob->hosts_override && ob->hosts
+            )
+        && addr->host_list
+        )
+       {
+       host_item * h;
+       ok = FALSE;
+       for (h = addr->host_list; h; h = h->next)
+         if (Ustrcmp(h->name, continue_hostname) == 0)
+  /*XXX should also check port here */
+           { ok = TRUE; break; }
+       }
       }
 
     /* Addresses not suitable; defer or queue for fallback hosts (which
@@ -4461,7 +4511,10 @@ for (delivery_count = 0; addr_remote; delivery_count++)
 
     if (!ok)
       {
-      DEBUG(D_deliver) debug_printf("not suitable for continue_transport\n");
+      DEBUG(D_deliver) debug_printf("not suitable for continue_transport (%s)\n",
+       Ustrcmp(continue_transport, tp->name) != 0
+       ? string_sprintf("tpt %s vs %s", continue_transport, tp->name)
+       : string_sprintf("no host matching %s", continue_hostname));
       if (serialize_key) enq_end(serialize_key);
 
       if (addr->fallback_hosts && !fallback)
@@ -4492,9 +4545,12 @@ for (delivery_count = 0; addr_remote; delivery_count++)
 
     /* Set a flag indicating whether there are further addresses that list
     the continued host. This tells the transport to leave the channel open,
-    but not to pass it to another delivery process. */
+    but not to pass it to another delivery process. We'd like to do that
+    for non-continue_transport cases too but the knowlege of which host is
+    connected to is too hard to manage.  Perhaps we need a finer-grain
+    interface to the transport. */
 
-    for (next = addr_remote; next; next = next->next)
+    for (next = addr_remote; next && !continue_more; next = next->next)
       {
       host_item *h;
       for (h = next->host_list; h; h = h->next)
@@ -4527,11 +4583,15 @@ for (delivery_count = 0; addr_remote; delivery_count++)
     that it can use either of them, though it prefers O_NONBLOCK, which
     distinguishes between EOF and no-more-data. */
 
+/* The data appears in a timely manner and we already did a select on
+all pipes, so I do not see a reason to use non-blocking IO here
+
 #ifdef O_NONBLOCK
     (void)fcntl(pfd[pipe_read], F_SETFL, O_NONBLOCK);
 #else
     (void)fcntl(pfd[pipe_read], F_SETFL, O_NDELAY);
 #endif
+*/
 
     /* If the maximum number of subprocesses already exist, wait for a process
     to finish. If we ran out of file descriptors, parmax will have been reduced
@@ -4574,10 +4634,12 @@ for (delivery_count = 0; addr_remote; delivery_count++)
 
   search_tidyup();
 
+
   if ((pid = fork()) == 0)
     {
     int fd = pfd[pipe_write];
     host_item *h;
+    DEBUG(D_deliver) debug_selector |= D_pid;  // hs12
 
     /* Setting this global in the subprocess means we need never clear it */
     transport_name = tp->name;
@@ -4598,7 +4660,7 @@ for (delivery_count = 0; addr_remote; delivery_count++)
     predictable settings for each delivery process, so do something explicit
     here rather they rely on the fixed reset in the random number function. */
 
-    random_seed = running_in_test_harness? 42 + 2*delivery_count : 0;
+    random_seed = running_in_test_harness ? 42 + 2*delivery_count : 0;
 
     /* Set close-on-exec on the pipe so that it doesn't get passed on to
     a new process that may be forked to do another delivery down the same
@@ -4713,13 +4775,17 @@ for (delivery_count = 0; addr_remote; delivery_count++)
         if (!addr->peerdn)
          *ptr++ = 0;
        else
-          {
-          ptr += sprintf(CS ptr, "%.512s", addr->peerdn);
-          ptr++;
-          }
+          ptr += sprintf(CS ptr, "%.512s", addr->peerdn) + 1;
 
         rmt_dlv_checked_write(fd, 'X', '1', big_buffer, ptr - big_buffer);
         }
+      else if (continue_proxy_cipher)
+       {
+        ptr = big_buffer + sprintf(CS big_buffer, "%.128s", continue_proxy_cipher) + 1;
+       *ptr++ = 0;
+        rmt_dlv_checked_write(fd, 'X', '1', big_buffer, ptr - big_buffer);
+       }
+
       if (addr->peercert)
        {
         ptr = big_buffer;
@@ -4764,16 +4830,18 @@ for (delivery_count = 0; addr_remote; delivery_count++)
        }
 
 #ifndef DISABLE_PRDR
-      if (addr->flags & af_prdr_used)
+      if (testflag(addr, af_prdr_used))
        rmt_dlv_checked_write(fd, 'P', '0', NULL, 0);
 #endif
 
-      if (addr->flags & af_chunking_used)
+      if (testflag(addr, af_chunking_used))
        rmt_dlv_checked_write(fd, 'K', '0', NULL, 0);
 
+      if (testflag(addr, af_tcp_fastopen))
+       rmt_dlv_checked_write(fd, 'T', '0', NULL, 0);
+
       memcpy(big_buffer, &addr->dsn_aware, sizeof(addr->dsn_aware));
       rmt_dlv_checked_write(fd, 'D', '0', big_buffer, sizeof(addr->dsn_aware));
-      DEBUG(D_deliver) debug_printf("DSN write: addr->dsn_aware = %d\n", addr->dsn_aware);
 
       /* Retry information: for most success cases this will be null. */
 
@@ -4781,9 +4849,9 @@ for (delivery_count = 0; addr_remote; delivery_count++)
         {
         sprintf(CS big_buffer, "%c%.500s", r->flags, r->key);
         ptr = big_buffer + Ustrlen(big_buffer+2) + 3;
-        memcpy(ptr, &(r->basic_errno), sizeof(r->basic_errno));
+        memcpy(ptr, &r->basic_errno, sizeof(r->basic_errno));
         ptr += sizeof(r->basic_errno);
-        memcpy(ptr, &(r->more_errno), sizeof(r->more_errno));
+        memcpy(ptr, &r->more_errno, sizeof(r->more_errno));
         ptr += sizeof(r->more_errno);
         if (!r->message) *ptr++ = 0; else
           {
@@ -4832,11 +4900,13 @@ for (delivery_count = 0; addr_remote; delivery_count++)
 
       sprintf(CS big_buffer, "%c%c", addr->transport_return, addr->special_action);
       ptr = big_buffer + 2;
-      memcpy(ptr, &(addr->basic_errno), sizeof(addr->basic_errno));
+      memcpy(ptr, &addr->basic_errno, sizeof(addr->basic_errno));
       ptr += sizeof(addr->basic_errno);
-      memcpy(ptr, &(addr->more_errno), sizeof(addr->more_errno));
+      memcpy(ptr, &addr->more_errno, sizeof(addr->more_errno));
       ptr += sizeof(addr->more_errno);
-      memcpy(ptr, &(addr->flags), sizeof(addr->flags));
+      memcpy(ptr, &addr->delivery_usec, sizeof(addr->delivery_usec));
+      ptr += sizeof(addr->delivery_usec);
+      memcpy(ptr, &addr->flags, sizeof(addr->flags));
       ptr += sizeof(addr->flags);
 
       if (!addr->message) *ptr++ = 0; else
@@ -4849,7 +4919,7 @@ for (delivery_count = 0; addr_remote; delivery_count++)
         {
         ptr += sprintf(CS ptr, "%.256s", addr->host_used->name) + 1;
         ptr += sprintf(CS ptr, "%.64s", addr->host_used->address) + 1;
-        memcpy(ptr, &(addr->host_used->port), sizeof(addr->host_used->port));
+        memcpy(ptr, &addr->host_used->port, sizeof(addr->host_used->port));
         ptr += sizeof(addr->host_used->port);
 
         /* DNS lookup status */
@@ -4888,9 +4958,22 @@ for (delivery_count = 0; addr_remote; delivery_count++)
 
   (void)close(pfd[pipe_write]);
 
+  /* If we have a connection still open from a verify stage (lazy-close)
+  release its TLS library context (if any) as responsibility was passed to
+  the delivery child process. */
+
+  if (cutthrough.fd >= 0 && cutthrough.callout_hold_only)
+    {
+#ifdef SUPPORT_TLS
+    tls_close(FALSE, FALSE);
+#endif
+    (void) close(cutthrough.fd);
+    release_cutthrough_connection(US"passed to transport proc");
+    }
+
   /* Fork failed; defer with error message */
 
-  if (pid < 0)
+  if (pid == -1)
     {
     (void)close(pfd[pipe_read]);
     panicmsg = string_sprintf("fork failed for remote delivery to %s: %s",
@@ -5512,14 +5595,15 @@ give up; if the message has been around for sufficiently long, remove it. */
 
     if (rc != spool_read_hdrerror)
       {
-      received_time = 0;
+      received_time.tv_sec = received_time.tv_usec = 0;
+      /*XXX subsec precision?*/
       for (i = 0; i < 6; i++)
-       received_time = received_time * BASE_62 + tab62[id[i] - '0'];
+       received_time.tv_sec = received_time.tv_sec * BASE_62 + tab62[id[i] - '0'];
       }
 
     /* If we've had this malformed message too long, sling it. */
 
-    if (now - received_time > keep_malformed)
+    if (now - received_time.tv_sec > keep_malformed)
       {
       Uunlink(spool_fname(US"msglog", message_subdir, id, US""));
       Uunlink(spool_fname(US"input", message_subdir, id, US"-D"));
@@ -5914,11 +5998,11 @@ else if (system_filter && process_recipients != RECIP_FAIL_TIMEOUT)
         uschar *type;
         p->uid = uid;
         p->gid = gid;
-        setflag(p, af_uid_set |
-                   af_gid_set |
-                   af_allow_file |
-                   af_allow_pipe |
-                   af_allow_reply);
+        setflag(p, af_uid_set);
+        setflag(p, af_gid_set);
+        setflag(p, af_allow_file);
+        setflag(p, af_allow_pipe);
+        setflag(p, af_allow_reply);
 
         /* Find the name of the system filter's appropriate pfr transport */
 
@@ -6020,9 +6104,7 @@ spool if the message is deferred, and in any case there are casing
 complications for local addresses. */
 
 if (process_recipients != RECIP_IGNORE)
-  {
   for (i = 0; i < recipients_count; i++)
-    {
     if (!tree_search(tree_nonrecipients, recipients_list[i].address))
       {
       recipient_item *r = recipients_list + i;
@@ -6138,8 +6220,6 @@ if (process_recipients != RECIP_IGNORE)
        }
 #endif
       }
-    }
-  }
 
 DEBUG(D_deliver)
   {
@@ -6204,10 +6284,8 @@ while (addr_new)           /* Loop until all addresses dealt with */
   not exist. In both cases, dbm_file is NULL. */
 
   if (!(dbm_file = dbfn_open(US"retry", O_RDONLY, &dbblock, FALSE)))
-    {
     DEBUG(D_deliver|D_retry|D_route|D_hints_lookup)
       debug_printf("no retry data available\n");
-    }
 
   /* Scan the current batch of new addresses, to handle pipes, files and
   autoreplies, and determine which others are ready for routing. */
@@ -6243,8 +6321,8 @@ while (addr_new)           /* Loop until all addresses dealt with */
         addr->local_part = addr->address;
         addr->message =
           US"filter autoreply generated syntactically invalid recipient";
-        setflag(addr, af_ignore_error);
-        (void)post_process_one(addr, FAIL, LOG_MAIN, DTYPE_ROUTER, 0);
+        addr->prop.ignore_error = TRUE;
+        (void) post_process_one(addr, FAIL, LOG_MAIN, DTYPE_ROUTER, 0);
         continue;   /* with the next new address */
         }
 
@@ -6599,7 +6677,6 @@ while (addr_new)           /* Loop until all addresses dealt with */
       if ((rc = match_isinlist(addr->domain, (const uschar **)&queue_domains, 0,
             &domainlist_anchor, addr->domain_cache, MCL_DOMAIN, TRUE, NULL))
               != OK)
-        {
         if (rc == DEFER)
           {
           addr->basic_errno = ERRNO_LISTDEFER;
@@ -6611,7 +6688,6 @@ while (addr_new)           /* Loop until all addresses dealt with */
           addr->next = okaddr;
           okaddr = addr;
           }
-        }
       else
         {
         addr->basic_errno = ERRNO_QUEUE_DOMAIN;
@@ -6646,7 +6722,7 @@ while (addr_new)           /* Loop until all addresses dealt with */
          &addr_succeed, v_none)) == DEFER)
       retry_add_item(addr,
         addr->router->retry_use_local_part
-        ?  string_sprintf("R:%s@%s", addr->local_part, addr->domain)
+        ? string_sprintf("R:%s@%s", addr->local_part, addr->domain)
        : string_sprintf("R:%s", addr->domain),
        0);
 
@@ -6740,15 +6816,14 @@ while (addr_new)           /* Loop until all addresses dealt with */
         addr2->host_list = addr->host_list;
         addr2->fallback_hosts = addr->fallback_hosts;
         addr2->prop.errors_address = addr->prop.errors_address;
-        copyflag(addr2, addr, af_hide_child | af_local_host_removed);
+        copyflag(addr2, addr, af_hide_child);
+        copyflag(addr2, addr, af_local_host_removed);
 
         DEBUG(D_deliver|D_route)
-          {
           debug_printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
                        "routing %s\n"
                        "Routing for %s copied from %s\n",
             addr2->address, addr2->address, addr->address);
-          }
         }
       }
     }  /* Continue with routing the next address. */
@@ -6910,7 +6985,7 @@ if (addr_local || addr_remote)
   if (journal_fd < 0)
     {
     uschar * fname = spool_fname(US"input", message_subdir, id, US"-J");
-    
+
     if ((journal_fd = Uopen(fname,
 #ifdef O_CLOEXEC
                        O_CLOEXEC |
@@ -7038,6 +7113,7 @@ phase, to minimize cases of half-done things. */
 
 DEBUG(D_deliver)
   debug_printf(">>>>>>>>>>>>>>>> deliveries are done >>>>>>>>>>>>>>>>\n");
+cancel_cutthrough_connection(TRUE, US"deliveries are done");
 
 /* Root privilege is no longer needed */
 
@@ -7174,7 +7250,7 @@ if (addr_senddsn)
     FILE *f = fdopen(fd, "wb");
     /* header only as required by RFC. only failure DSN needs to honor RET=FULL */
     uschar * bound;
-    transport_ctx tctx = {0};
+    transport_ctx tctx = {{0}};
 
     DEBUG(D_deliver)
       debug_printf("sending error message to: %s\n", sender_address);
@@ -7254,8 +7330,9 @@ if (addr_senddsn)
 
     /* Write the original email out */
 
+    tctx.u.fd = fileno(f);
     tctx.options = topt_add_return_path | topt_no_body;
-    transport_write_message(fileno(f), &tctx, 0);
+    transport_write_message(&tctx, 0);
     fflush(f);
 
     fprintf(f,"\n--%s--\n", bound);
@@ -7311,19 +7388,18 @@ while (addr_failed)
   if (sender_address[0] == 0 && !addr_failed->prop.errors_address)
     {
     if (  !testflag(addr_failed, af_retry_timedout)
-       && !testflag(addr_failed, af_ignore_error))
-      {
+       && !addr_failed->prop.ignore_error)
       log_write(0, LOG_MAIN|LOG_PANIC, "internal error: bounce message "
         "failure is neither frozen nor ignored (it's been ignored)");
-      }
-    setflag(addr_failed, af_ignore_error);
+
+    addr_failed->prop.ignore_error = TRUE;
     }
 
   /* If the first address on the list has af_ignore_error set, just remove
   it from the list, throw away any saved message file, log it, and
   mark the recipient done. */
 
-  if (  testflag(addr_failed, af_ignore_error)
+  if (  addr_failed->prop.ignore_error
      || (  addr_failed->dsn_flags & rf_dsnflags
         && (addr_failed->dsn_flags & rf_notify_failure) != rf_notify_failure
      )  )
@@ -7711,14 +7787,15 @@ wording. */
       transport_filter_argv = NULL;   /* Just in case */
       return_path = sender_address;   /* In case not previously set */
        {                             /* Dummy transport for headers add */
-       transport_ctx tctx = {0};
+       transport_ctx tctx = {{0}};
        transport_instance tb = {0};
 
+       tctx.u.fd = fileno(f);
        tctx.tblock = &tb;
        tctx.options = topt;
        tb.add_headers = dsnnotifyhdr;
 
-       transport_write_message(fileno(f), &tctx, 0);
+       transport_write_message(&tctx, 0);
        }
       fflush(f);
 
@@ -7750,7 +7827,7 @@ wording. */
       if (rc != 0)
         {
         uschar *s = US"";
-        if (now - received_time < retry_maximum_timeout && !addr_defer)
+        if (now - received_time.tv_sec < retry_maximum_timeout && !addr_defer)
           {
           addr_defer = (address_item *)(+1);
           deliver_freeze = TRUE;
@@ -7836,7 +7913,7 @@ if (!addr_defer)
 
   if (LOGGING(queue_time_overall))
     log_write(0, LOG_MAIN, "Completed QT=%s",
-      readconf_printtime( (int) ((long)time(NULL) - (long)received_time)) );
+      string_timesince(&received_time));
   else
     log_write(0, LOG_MAIN, "Completed");
 
@@ -7974,7 +8051,7 @@ else if (addr_defer != (address_item *)(+1))
     {
     int count;
     int show_time;
-    int queue_time = time(NULL) - received_time;
+    int queue_time = time(NULL) - received_time.tv_sec;
 
     /* When running in the test harness, there's an option that allows us to
     fudge this time so as to get repeatability of the tests. Take the first
@@ -8032,7 +8109,7 @@ else if (addr_defer != (address_item *)(+1))
         FILE *wmf = NULL;
         FILE *f = fdopen(fd, "wb");
        uschar * bound;
-       transport_ctx tctx = {0};
+       transport_ctx tctx = {{0}};
 
         if (warn_message_file)
           if (!(wmf = Ufopen(warn_message_file, "rb")))
@@ -8179,12 +8256,13 @@ else if (addr_defer != (address_item *)(+1))
 
         fflush(f);
         /* header only as required by RFC. only failure DSN needs to honor RET=FULL */
+       tctx.u.fd = fileno(f);
         tctx.options = topt_add_return_path | topt_no_body;
         transport_filter_argv = NULL;   /* Just in case */
         return_path = sender_address;   /* In case not previously set */
 
         /* Write the original email out */
-        transport_write_message(fileno(f), &tctx, 0);
+        transport_write_message(&tctx, 0);
         fflush(f);
 
         fprintf(f,"\n--%s--\n", bound);
@@ -8414,6 +8492,72 @@ deliver_datafile = -1;
 return new_sender_address;
 }
 
+
+
+void
+delivery_re_exec(int exec_type)
+{
+uschar * where;
+
+if (cutthrough.fd >= 0 && cutthrough.callout_hold_only)
+  {
+  int pfd[2], channel_fd = cutthrough.fd, pid;
+
+  smtp_peer_options = cutthrough.peer_options;
+  continue_sequence = 0;
+
+#ifdef SUPPORT_TLS
+  if (cutthrough.is_tls)
+    {
+    smtp_peer_options |= OPTION_TLS;
+    sending_ip_address = cutthrough.snd_ip;
+    sending_port = cutthrough.snd_port;
+
+    where = US"socketpair";
+    if (socketpair(AF_UNIX, SOCK_STREAM, 0, pfd) != 0)
+      goto fail;
+
+    where = US"fork";
+    if ((pid = fork()) < 0)
+      goto fail;
+
+    else if (pid == 0)         /* child: fork again to totally disconnect */
+      {
+      close(pfd[1]);
+      if ((pid = fork()))
+       _exit(pid ? EXIT_FAILURE : EXIT_SUCCESS);
+      smtp_proxy_tls(big_buffer, big_buffer_size, pfd[0], 5*60);
+      exim_exit(0);
+      }
+
+    close(pfd[0]);
+    waitpid(pid, NULL, 0);
+    (void) close(channel_fd);  /* release the client socket */
+    channel_fd = pfd[1];
+    }
+#endif
+
+  transport_do_pass_socket(cutthrough.transport, cutthrough.host.name,
+    cutthrough.host.address, message_id, channel_fd);
+  }
+else
+  {
+  cancel_cutthrough_connection(TRUE, US"non-continued delivery");
+  (void) child_exec_exim(exec_type, FALSE, NULL, FALSE, 2, US"-Mc", message_id);
+  }
+return;                /* compiler quietening; control does not reach here. */
+
+fail:
+  log_write(0,
+    LOG_MAIN | (exec_type == CEE_EXEC_EXIT ? LOG_PANIC : LOG_PANIC_DIE),
+    "delivery re-exec %s failed: %s", where, strerror(errno));
+
+  /* Get here if exec_type == CEE_EXEC_EXIT.
+  Note: this must be _exit(), not exit(). */
+
+  _exit(EX_EXECFAILED);
+}
+
 /* vi: aw ai sw=2
 */
 /* End of deliver.c */
index f510214439b23605335945a27a40911ade2da981..cd8a16ae61b8cd04f96143d4325a6a097bd3bda1 100644 (file)
@@ -20,6 +20,12 @@ pdkim_signature *dkim_signatures = NULL;
 pdkim_signature *dkim_cur_sig = NULL;
 static const uschar * dkim_collect_error = NULL;
 
+
+
+/*XXX the caller only uses the first record if we return multiple.
+Could we hand back an allocated string?
+*/
+
 static int
 dkim_exim_query_dns_txt(char *name, char *answer)
 {
@@ -48,7 +54,7 @@ for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
       uschar len = rr->data[rr_offset++];
       snprintf(answer + answer_offset,
                PDKIM_DNS_TXT_MAX_RECLEN - answer_offset,
-               "%.*s", (int)len, (char *) (rr->data + rr_offset));
+               "%.*s", (int)len, CS  (rr->data + rr_offset));
       rr_offset += len;
       answer_offset += len;
       if (answer_offset >= PDKIM_DNS_TXT_MAX_RECLEN)
@@ -104,7 +110,7 @@ int rc;
 
 store_pool = POOL_PERM;
 if (  dkim_collect_input
-   && (rc = pdkim_feed(dkim_verify_ctx, CS data, len)) != PDKIM_OK)
+   && (rc = pdkim_feed(dkim_verify_ctx, data, len)) != PDKIM_OK)
   {
   dkim_collect_error = pdkim_errstr(rc);
   log_write(0, LOG_MAIN,
@@ -164,17 +170,15 @@ for (sig = dkim_signatures; sig; sig = sig->next)
   logmsg = string_append(logmsg, &size, &ptr, 7, 
        " c=", sig->canon_headers == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
        "/",   sig->canon_body    == PDKIM_CANON_SIMPLE ? "simple" : "relaxed",
-       " a=", sig->algo == PDKIM_ALGO_RSA_SHA256
-               ? "rsa-sha256"
-               : sig->algo == PDKIM_ALGO_RSA_SHA1 ? "rsa-sha1" : "err",
+       " a=", dkim_sig_to_a_tag(sig),
        string_sprintf(" b=%d",
                        (int)sig->sighash.len > -1 ? sig->sighash.len * 8 : 0));
-  if ((s= sig->identity)) string_append(logmsg, &size, &ptr, 2, " i=", s);
-  if (sig->created > 0) string_append(logmsg, &size, &ptr, 1,
+  if ((s= sig->identity)) logmsg = string_append(logmsg, &size, &ptr, 2, " i=", s);
+  if (sig->created > 0) logmsg = string_append(logmsg, &size, &ptr, 1,
                                      string_sprintf(" t=%lu", sig->created));
-  if (sig->expires > 0) string_append(logmsg, &size, &ptr, 1,
+  if (sig->expires > 0) logmsg = string_append(logmsg, &size, &ptr, 1,
                                      string_sprintf(" x=%lu", sig->expires));
-  if (sig->bodylength > -1) string_append(logmsg, &size, &ptr, 1,
+  if (sig->bodylength > -1) logmsg = string_append(logmsg, &size, &ptr, 1,
                                      string_sprintf(" l=%lu", sig->bodylength));
 
   switch (sig->verify_status)
@@ -251,10 +255,12 @@ for (sig = dkim_signatures; sig; sig = sig->next)
   /* Build a colon-separated list of signing domains (and identities, if present) in dkim_signers */
 
   if (sig->domain)
-    dkim_signers = string_append_listele(dkim_signers, ':', sig->domain);
+    dkim_signers = string_append_listele(dkim_signers, &dkim_signers_size,
+      &dkim_signers_ptr, ':', sig->domain);
 
   if (sig->identity)
-    dkim_signers = string_append_listele(dkim_signers, ':', sig->identity);
+    dkim_signers = string_append_listele(dkim_signers, &dkim_signers_size,
+      &dkim_signers_ptr, ':', sig->identity);
 
   /* Process next signature */
   }
@@ -336,12 +342,7 @@ if (!dkim_verify_ctx || dkim_disable_verify || !dkim_cur_sig)
 switch (what)
   {
   case DKIM_ALGO:
-    switch (dkim_cur_sig->algo)
-      {
-      case PDKIM_ALGO_RSA_SHA1:        return US"rsa-sha1";
-      case PDKIM_ALGO_RSA_SHA256:
-      default:                 return US"rsa-sha256";
-      }
+    return dkim_sig_to_a_tag(dkim_cur_sig);
 
   case DKIM_BODYLENGTH:
     return dkim_cur_sig->bodylength >= 0
@@ -448,222 +449,239 @@ switch (what)
 }
 
 
-uschar *
-dkim_exim_sign(int dkim_fd, struct ob_dkim * dkim, const uschar ** errstr)
+/* Generate signatures for the given file, returning a string.
+If a prefix is given, prepend it to the file for the calculations.
+*/
+
+blob *
+dkim_exim_sign(int fd, off_t off, uschar * prefix,
+  struct ob_dkim * dkim, const uschar ** errstr)
 {
 const uschar * dkim_domain;
 int sep = 0;
-uschar *seen_items = NULL;
-int seen_items_size = 0;
-int seen_items_offset = 0;
-uschar itembuf[256];
-uschar *dkim_canon_expanded;
-uschar *dkim_sign_headers_expanded;
-uschar *dkim_private_key_expanded;
-pdkim_ctx *ctx = NULL;
-uschar *rc = NULL;
-uschar *sigbuf = NULL;
+uschar * seen_doms = NULL;
+int seen_doms_size = 0;
+int seen_doms_offset = 0;
+pdkim_ctx ctx;
+pdkim_signature * sig;
+blob * sigbuf = NULL;
 int sigsize = 0;
-int sigptr = 0;
-pdkim_signature *signature;
-int pdkim_canon;
 int pdkim_rc;
 int sread;
-char buf[4096];
+uschar buf[4096];
 int save_errno = 0;
 int old_pool = store_pool;
+uschar * errwhen;
 
 store_pool = POOL_MAIN;
 
+pdkim_init_context(&ctx, dkim->dot_stuffed, &dkim_exim_query_dns_txt);
+
 if (!(dkim_domain = expand_cstring(dkim->dkim_domain)))
-  {
   /* expansion error, do not send message. */
-  log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
-            "dkim_domain: %s", expand_string_message);
-  goto bad;
-  }
+  { errwhen = US"dkim_domain"; goto expand_bad; }
 
 /* Set $dkim_domain expansion variable to each unique domain in list. */
 
-while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep,
-                                  itembuf, sizeof(itembuf))))
+while ((dkim_signing_domain = string_nextinlist(&dkim_domain, &sep, NULL, 0)))
   {
-  if (!dkim_signing_domain || dkim_signing_domain[0] == '\0')
+  const uschar * dkim_sel;
+  int sel_sep = 0;
+
+  if (dkim_signing_domain[0] == '\0')
     continue;
 
   /* Only sign once for each domain, no matter how often it
   appears in the expanded list. */
 
-  if (seen_items)
-    {
-    const uschar *seen_items_list = seen_items;
-    if (match_isinlist(dkim_signing_domain,
-                       &seen_items_list, 0, NULL, NULL, MCL_STRING, TRUE,
-                       NULL) == OK)
-      continue;
-
-    seen_items =
-      string_append(seen_items, &seen_items_size, &seen_items_offset, 1, ":");
-    }
+  if (match_isinlist(dkim_signing_domain, CUSS &seen_doms,
+      0, NULL, NULL, MCL_STRING, TRUE, NULL) == OK)
+    continue;
 
-  seen_items =
-    string_append(seen_items, &seen_items_size, &seen_items_offset, 1,
-                dkim_signing_domain);
-  seen_items[seen_items_offset] = '\0';
+  seen_doms = string_append_listele(seen_doms, &seen_doms_size,
+    &seen_doms_offset, ':', dkim_signing_domain);
 
-  /* Set up $dkim_selector expansion variable. */
+  /* Set $dkim_selector expansion variable to each selector in list,
+  for this domain. */
 
+  if (!(dkim_sel = expand_string(dkim->dkim_selector)))
   if (!(dkim_signing_selector = expand_string(dkim->dkim_selector)))
-    {
-    log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
-              "dkim_selector: %s", expand_string_message);
-    goto bad;
-    }
-
-  /* Get canonicalization to use */
-
-  dkim_canon_expanded = dkim->dkim_canon
-    ? expand_string(dkim->dkim_canon) : US"relaxed";
-  if (!dkim_canon_expanded)
-    {
-    /* expansion error, do not send message. */
-    log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
-              "dkim_canon: %s", expand_string_message);
-    goto bad;
-    }
+    { errwhen = US"dkim_selector"; goto expand_bad; }
 
-  if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0)
-    pdkim_canon = PDKIM_CANON_RELAXED;
-  else if (Ustrcmp(dkim_canon_expanded, "simple") == 0)
-    pdkim_canon = PDKIM_CANON_SIMPLE;
-  else
+  while ((dkim_signing_selector = string_nextinlist(&dkim_sel, &sel_sep,
+         NULL, 0)))
     {
-    log_write(0, LOG_MAIN,
-              "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",
-              dkim_canon_expanded);
-    pdkim_canon = PDKIM_CANON_RELAXED;
-    }
-
-  dkim_sign_headers_expanded = NULL;
-  if (dkim->dkim_sign_headers)
-    if (!(dkim_sign_headers_expanded = expand_string(dkim->dkim_sign_headers)))
+    uschar * dkim_canon_expanded;
+    int pdkim_canon;
+    uschar * dkim_sign_headers_expanded = NULL;
+    uschar * dkim_private_key_expanded;
+    uschar * dkim_hash_expanded;
+    uschar * dkim_identity_expanded = NULL;
+
+    /* Get canonicalization to use */
+
+    dkim_canon_expanded = dkim->dkim_canon
+      ? expand_string(dkim->dkim_canon) : US"relaxed";
+    if (!dkim_canon_expanded)  /* expansion error, do not send message. */
+      { errwhen = US"dkim_canon"; goto expand_bad; }
+
+    if (Ustrcmp(dkim_canon_expanded, "relaxed") == 0)
+      pdkim_canon = PDKIM_CANON_RELAXED;
+    else if (Ustrcmp(dkim_canon_expanded, "simple") == 0)
+      pdkim_canon = PDKIM_CANON_SIMPLE;
+    else
       {
-      log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
-                "dkim_sign_headers: %s", expand_string_message);
-      goto bad;
+      log_write(0, LOG_MAIN,
+                "DKIM: unknown canonicalization method '%s', defaulting to 'relaxed'.\n",
+                dkim_canon_expanded);
+      pdkim_canon = PDKIM_CANON_RELAXED;
       }
-                       /* else pass NULL, which means default header list */
 
-  /* Get private key to use. */
+    if (  dkim->dkim_sign_headers
+       && !(dkim_sign_headers_expanded = expand_string(dkim->dkim_sign_headers)))
+      { errwhen = US"dkim_sign_header"; goto expand_bad; }
+    /* else pass NULL, which means default header list */
 
-  if (!(dkim_private_key_expanded = expand_string(dkim->dkim_private_key)))
-    {
-    log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand "
-              "dkim_private_key: %s", expand_string_message);
-    goto bad;
-    }
+    /* Get private key to use. */
 
-  if (  Ustrlen(dkim_private_key_expanded) == 0
-     || Ustrcmp(dkim_private_key_expanded, "0") == 0
-     || Ustrcmp(dkim_private_key_expanded, "false") == 0
-     )
-    continue;          /* don't sign, but no error */
+    if (!(dkim_private_key_expanded = expand_string(dkim->dkim_private_key)))
+      { errwhen = US"dkim_private_key"; goto expand_bad; }
 
-  if (dkim_private_key_expanded[0] == '/')
-    {
-    int privkey_fd, off = 0, len;
+    if (  Ustrlen(dkim_private_key_expanded) == 0
+       || Ustrcmp(dkim_private_key_expanded, "0") == 0
+       || Ustrcmp(dkim_private_key_expanded, "false") == 0
+       )
+      continue;                /* don't sign, but no error */
 
-    /* Looks like a filename, load the private key. */
+    if (dkim_private_key_expanded[0] == '/')
+      {
+      int privkey_fd, off = 0, len;
 
-    memset(big_buffer, 0, big_buffer_size);
+      /* Looks like a filename, load the private key. */
 
-    if ((privkey_fd = open(CS dkim_private_key_expanded, O_RDONLY)) < 0)
-      {
-      log_write(0, LOG_MAIN | LOG_PANIC, "unable to open "
-                "private key file for reading: %s",
-                dkim_private_key_expanded);
-      goto bad;
-      }
+      memset(big_buffer, 0, big_buffer_size);
 
-    do
-      {
-      if ((len = read(privkey_fd, big_buffer + off, big_buffer_size - 2 - off)) < 0)
+      if ((privkey_fd = open(CS dkim_private_key_expanded, O_RDONLY)) < 0)
        {
-       (void) close(privkey_fd);
-       log_write(0, LOG_MAIN|LOG_PANIC, "unable to read private key file: %s",
+       log_write(0, LOG_MAIN | LOG_PANIC, "unable to open "
+                  "private key file for reading: %s",
                   dkim_private_key_expanded);
        goto bad;
        }
-      off += len;
+
+      do
+       {
+       if ((len = read(privkey_fd, big_buffer + off, big_buffer_size - 2 - off)) < 0)
+         {
+         (void) close(privkey_fd);
+         log_write(0, LOG_MAIN|LOG_PANIC, "unable to read private key file: %s",
+                    dkim_private_key_expanded);
+         goto bad;
+         }
+       off += len;
+       }
+      while (len > 0);
+
+      (void) close(privkey_fd);
+      big_buffer[off] = '\0';
+      dkim_private_key_expanded = big_buffer;
       }
-    while (len > 0);
 
-    (void) close(privkey_fd);
-    big_buffer[off] = '\0';
-    dkim_private_key_expanded = big_buffer;
-    }
+    if (!(dkim_hash_expanded = expand_string(dkim->dkim_hash)))
+      { errwhen = US"dkim_hash"; goto expand_bad; }
 
-  if (!(ctx = pdkim_init_sign(CS dkim_signing_domain,
-                       CS dkim_signing_selector,
-                       CS dkim_private_key_expanded,
-                       PDKIM_ALGO_RSA_SHA256,
-                       dkim->dot_stuffed,
-                       &dkim_exim_query_dns_txt,
-                       errstr
-                       )))
-    goto bad;
-  dkim_private_key_expanded[0] = '\0';
-  pdkim_set_optional(ctx,
-                     CS dkim_sign_headers_expanded,
-                     NULL,
-                     pdkim_canon,
-                     pdkim_canon, -1, 0, 0);
-
-  lseek(dkim_fd, 0, SEEK_SET);
-
-  while ((sread = read(dkim_fd, &buf, sizeof(buf))) > 0)
-    if ((pdkim_rc = pdkim_feed(ctx, buf, sread)) != PDKIM_OK)
-      goto pk_bad;
+    if (dkim->dkim_identity)
+      if (!(dkim_identity_expanded = expand_string(dkim->dkim_identity)))
+       { errwhen = US"dkim_identity"; goto expand_bad; }
+      else if (!*dkim_identity_expanded)
+       dkim_identity_expanded = NULL;
 
-  /* Handle failed read above. */
-  if (sread == -1)
-    {
-    debug_printf("DKIM: Error reading -K file.\n");
-    save_errno = errno;
-    goto bad;
+  /*XXX so we currently nail signing to RSA + this hash.
+  Need to extract algo from privkey and check for disallowed combos. */
+
+    if (!(sig = pdkim_init_sign(&ctx, dkim_signing_domain,
+                         dkim_signing_selector,
+                         dkim_private_key_expanded,
+                         dkim_hash_expanded,
+                         errstr
+                         )))
+      goto bad;
+    dkim_private_key_expanded[0] = '\0';
+
+    pdkim_set_optional(sig,
+                       CS dkim_sign_headers_expanded,
+                       dkim_identity_expanded,
+                       pdkim_canon,
+                       pdkim_canon, -1, 0, 0);
+
+    if (!ctx.sig)              /* link sig to context chain */
+      ctx.sig = sig;
+    else
+      {
+      pdkim_signature * n = ctx.sig;
+      while (n->next) n = n->next;
+      n->next = sig;
+      }
     }
+  }
 
-  if ((pdkim_rc = pdkim_feed_finish(ctx, &signature, errstr)) != PDKIM_OK)
-    goto pk_bad;
+if (prefix)
+  pdkim_feed(&ctx, prefix, Ustrlen(prefix));
 
-  sigbuf = string_append(sigbuf, &sigsize, &sigptr, 2,
-                         US signature->signature_header, US"\r\n");
+if (lseek(fd, off, SEEK_SET) < 0)
+  sread = -1;
+else
+  while ((sread = read(fd, &buf, sizeof(buf))) > 0)
+    if ((pdkim_rc = pdkim_feed(&ctx, buf, sread)) != PDKIM_OK)
+      goto pk_bad;
 
-  pdkim_free_ctx(ctx);
-  ctx = NULL;
+/* Handle failed read above. */
+if (sread == -1)
+  {
+  debug_printf("DKIM: Error reading -K file.\n");
+  save_errno = errno;
+  goto bad;
   }
 
-if (sigbuf)
+/* Build string of headers, one per signature */
+
+if ((pdkim_rc = pdkim_feed_finish(&ctx, &sig, errstr)) != PDKIM_OK)
+  goto pk_bad;
+
+sigbuf = store_get(sizeof(blob));
+sigbuf->data = NULL;
+sigbuf->len = 0;
+
+while (sig)
   {
-  sigbuf[sigptr] = '\0';
-  rc = sigbuf;
+  int len = sigbuf->len;
+  sigbuf->data = string_append(sigbuf->data, &sigsize, &len, 2,
+                       US sig->signature_header, US"\r\n");
+  sigbuf->len = len;
+  sig = sig->next;
   }
+
+if (sigbuf->data)
+  sigbuf->data[sigbuf->len] = '\0';
 else
-  rc = US"";
+  sigbuf->data = US"";
 
 CLEANUP:
-  if (ctx)
-    pdkim_free_ctx(ctx);
   store_pool = old_pool;
   errno = save_errno;
-  return rc;
+  return sigbuf;
 
 pk_bad:
   log_write(0, LOG_MAIN|LOG_PANIC,
                "DKIM: signing failed: %.100s", pdkim_errstr(pdkim_rc));
 bad:
-  rc = NULL;
+  sigbuf = NULL;
   goto CLEANUP;
+
+expand_bad:
+  log_write(0, LOG_MAIN | LOG_PANIC, "failed to expand %s: %s",
+             errwhen, expand_string_message);
+  goto bad;
 }
 
 #endif
index bfdc7d42b519275ecfd9b27a0cc4675b59c9d1ab..a3419db42fb4973536307cdb9d0f51e3368e1fa8 100644 (file)
@@ -6,7 +6,7 @@
 /* See the file NOTICE for conditions of use and distribution. */
 
 void    dkim_exim_init(void);
-uschar *dkim_exim_sign(int, struct ob_dkim *, const uschar **);
+blob *  dkim_exim_sign(int, off_t, uschar *, struct ob_dkim *, const uschar **);
 void    dkim_exim_verify_init(BOOL);
 void    dkim_exim_verify_feed(uschar *, int);
 void    dkim_exim_verify_finish(void);
diff --git a/src/src/dkim_transport.c b/src/src/dkim_transport.c
new file mode 100644 (file)
index 0000000..85a73dc
--- /dev/null
@@ -0,0 +1,365 @@
+/*************************************************
+*     Exim - an Internet mail transport agent    *
+*************************************************/
+
+/* Copyright (c) University of Cambridge 1995 - 2016 */
+/* See the file NOTICE for conditions of use and distribution. */
+
+/* Transport shim for dkim signing */
+
+
+#include "exim.h"
+
+#ifndef DISABLE_DKIM   /* rest of file */
+
+
+static BOOL
+dkt_sign_fail(struct ob_dkim * dkim, int * errp)
+{
+if (dkim->dkim_strict)
+  {
+  uschar * dkim_strict_result = expand_string(dkim->dkim_strict);
+
+  if (dkim_strict_result)
+    if ( (strcmpic(dkim->dkim_strict, US"1") == 0) ||
+        (strcmpic(dkim->dkim_strict, US"true") == 0) )
+      {
+      /* Set errno to something halfway meaningful */
+      *errp = EACCES;
+      log_write(0, LOG_MAIN, "DKIM: message could not be signed,"
+       " and dkim_strict is set. Deferring message delivery.");
+      return FALSE;
+      }
+  }
+return TRUE;
+}
+
+/* Send the file at in_fd down the output fd */
+
+static BOOL
+dkt_send_file(int out_fd, int in_fd, off_t off, size_t size)
+{
+DEBUG(D_transport) debug_printf("send file fd=%d size=%u\n", out_fd, (unsigned)(size - off));
+
+/*XXX should implement timeout, like transport_write_block_fd() ? */
+
+#ifdef OS_SENDFILE
+/* We can use sendfile() to shove the file contents
+   to the socket. However only if we don't use TLS,
+   as then there's another layer of indirection
+   before the data finally hits the socket. */
+if (tls_out.active != out_fd)
+  {
+  ssize_t copied = 0;
+
+  while(copied >= 0 && off < size)
+    copied = os_sendfile(out_fd, in_fd, &off, size - off);
+  if (copied < 0)
+    return FALSE;
+  }
+else
+
+#endif
+
+  {
+  int sread, wwritten;
+
+  /* Rewind file */
+  if (lseek(in_fd, off, SEEK_SET) < 0) return FALSE;
+
+  /* Send file down the original fd */
+  while((sread = read(in_fd, deliver_out_buffer, DELIVER_OUT_BUFFER_SIZE)) > 0)
+    {
+    uschar * p = deliver_out_buffer;
+    /* write the chunk */
+
+    while (sread)
+      {
+#ifdef SUPPORT_TLS
+      wwritten = tls_out.active == out_fd
+       ? tls_write(FALSE, p, sread, FALSE)
+       : write(out_fd, CS p, sread);
+#else
+      wwritten = write(out_fd, CS p, sread);
+#endif
+      if (wwritten == -1)
+       return FALSE;
+      p += wwritten;
+      sread -= wwritten;
+      }
+    }
+
+  if (sread == -1)
+    return FALSE;
+  }
+
+return TRUE;
+}
+
+
+
+
+/* This function is a wrapper around transport_write_message().
+   It is only called from the smtp transport if DKIM or Domainkeys support
+   is active and no transport filter is to be used.
+
+Arguments:
+  As for transport_write_message() in transort.c, with additional arguments
+  for DKIM.
+
+Returns:       TRUE on success; FALSE (with errno) for any failure
+*/
+
+static BOOL
+dkt_direct(transport_ctx * tctx, struct ob_dkim * dkim,
+  const uschar ** err)
+{
+int save_fd = tctx->u.fd;
+int save_options = tctx->options;
+BOOL save_wireformat = spool_file_wireformat;
+uschar * hdrs;
+blob * dkim_signature;
+int hsize;
+const uschar * errstr;
+BOOL rc;
+
+DEBUG(D_transport) debug_printf("dkim signing direct-mode\n");
+
+/* Get headers in string for signing and transmission.  Do CRLF
+and dotstuffing (but no body nor dot-termination) */
+
+tctx->u.msg = NULL;
+tctx->options = tctx->options & ~(topt_end_dot | topt_use_bdat)
+  | topt_output_string | topt_no_body;
+
+rc = transport_write_message(tctx, 0);
+hdrs = tctx->u.msg;
+hdrs[hsize = tctx->msg_ptr] = '\0';
+
+tctx->u.fd = save_fd;
+tctx->options = save_options;
+if (!rc) return FALSE;
+
+/* Get signatures for headers plus spool data file */
+
+dkim->dot_stuffed = !!(save_options & topt_end_dot);
+
+if (!(dkim_signature = dkim_exim_sign(deliver_datafile, SPOOL_DATA_START_OFFSET,
+                                   hdrs, dkim, &errstr)))
+  if (!(rc = dkt_sign_fail(dkim, &errno)))
+    {
+    *err = errstr;
+    return FALSE;
+    }
+
+/* Write the signature and headers into the deliver-out-buffer.  This should
+mean they go out in the same packet as the MAIL, RCPT and (first) BDAT commands
+(transport_write_message() sizes the BDAT for the buffered amount) - for short
+messages, the BDAT LAST command.  We want no dotstuffing expansion here, it
+having already been done - but we have to say we want CRLF output format, and
+temporarily set the marker for possible already-CRLF input. */
+
+tctx->options &= ~topt_escape_headers;
+spool_file_wireformat = TRUE;
+transport_write_reset(0);
+if (  (  dkim_signature
+      && dkim_signature->len > 0
+      && !write_chunk(tctx, dkim_signature->data, dkim_signature->len)
+      )
+   || !write_chunk(tctx, hdrs, hsize)
+   )
+  return FALSE;
+
+spool_file_wireformat = save_wireformat;
+tctx->options = save_options | topt_no_headers | topt_continuation;
+
+if (!(transport_write_message(tctx, 0)))
+  return FALSE;
+
+tctx->options = save_options;
+return TRUE;
+}
+
+
+/* This function is a wrapper around transport_write_message().
+   It is only called from the smtp transport if DKIM or Domainkeys support
+   is active and a transport filter is to be used.  The function sets up a
+   replacement fd into a -K file, then calls the normal function. This way, the
+   exact bits that exim would have put "on the wire" will end up in the file
+   (except for TLS encapsulation, which is the very very last thing). When we
+   are done signing the file, send the signed message down the original fd (or
+   TLS fd).
+
+Arguments:
+  As for transport_write_message() in transort.c, with additional arguments
+  for DKIM.
+
+Returns:       TRUE on success; FALSE (with errno) for any failure
+*/
+
+static BOOL
+dkt_via_kfile(transport_ctx * tctx, struct ob_dkim * dkim, const uschar ** err)
+{
+int dkim_fd;
+int save_errno = 0;
+BOOL rc;
+uschar * dkim_spool_name;
+blob * dkim_signature;
+int options, dlen;
+off_t k_file_size;
+const uschar * errstr;
+
+dkim_spool_name = spool_fname(US"input", message_subdir, message_id,
+                   string_sprintf("-%d-K", (int)getpid()));
+
+DEBUG(D_transport) debug_printf("dkim signing via file %s\n", dkim_spool_name);
+
+if ((dkim_fd = Uopen(dkim_spool_name, O_RDWR|O_CREAT|O_TRUNC, SPOOL_MODE)) < 0)
+  {
+  /* Can't create spool file. Ugh. */
+  rc = FALSE;
+  save_errno = errno;
+  *err = string_sprintf("dkim spoolfile create: %s", strerror(errno));
+  goto CLEANUP;
+  }
+
+/* Call transport utility function to write the -K file; does the CRLF expansion
+(but, in the CHUNKING case, neither dot-stuffing nor dot-termination). */
+
+  {
+  int save_fd = tctx->u.fd;
+  tctx->u.fd = dkim_fd;
+  options = tctx->options;
+  tctx->options &= ~topt_use_bdat;
+
+  rc = transport_write_message(tctx, 0);
+
+  tctx->u.fd = save_fd;
+  tctx->options = options;
+  }
+
+/* Save error state. We must clean up before returning. */
+if (!rc)
+  {
+  save_errno = errno;
+  goto CLEANUP;
+  }
+
+/* Feed the file to the goats^W DKIM lib */
+
+dkim->dot_stuffed = !!(options & topt_end_dot);
+if (!(dkim_signature = dkim_exim_sign(dkim_fd, 0, NULL, dkim, &errstr)))
+  {
+  dlen = 0;
+  if (!(rc = dkt_sign_fail(dkim, &save_errno)))
+    {
+    *err = errstr;
+    goto CLEANUP;
+    }
+  }
+else
+  dlen = dkim_signature->len;
+
+#ifndef OS_SENDFILE
+if (options & topt_use_bdat)
+#endif
+  if ((k_file_size = lseek(dkim_fd, 0, SEEK_END)) < 0)
+    {
+    *err = string_sprintf("dkim spoolfile seek: %s", strerror(errno));
+    goto CLEANUP;
+    }
+
+if (options & topt_use_bdat)
+  {
+  /* On big messages output a precursor chunk to get any pipelined
+  MAIL & RCPT commands flushed, then reap the responses so we can
+  error out on RCPT rejects before sending megabytes. */
+
+  if (  dlen + k_file_size > DELIVER_OUT_BUFFER_SIZE
+     && dlen > 0)
+    {
+    if (  tctx->chunk_cb(tctx, dlen, 0) != OK
+       || !transport_write_block(tctx,
+                   dkim_signature->data, dlen, FALSE)
+       || tctx->chunk_cb(tctx, 0, tc_reap_prev) != OK
+       )
+      goto err;
+    dlen = 0;
+    }
+
+  /* Send the BDAT command for the entire message, as a single LAST-marked
+  chunk. */
+
+  if (tctx->chunk_cb(tctx, dlen + k_file_size, tc_chunk_last) != OK)
+    goto err;
+  }
+
+if(dlen > 0 && !transport_write_block(tctx, dkim_signature->data, dlen, TRUE))
+  goto err;
+
+if (!dkt_send_file(tctx->u.fd, dkim_fd, 0, k_file_size))
+  {
+  save_errno = errno;
+  rc = FALSE;
+  }
+
+CLEANUP:
+  /* unlink -K file */
+  if (dkim_fd >= 0) (void)close(dkim_fd);
+  Uunlink(dkim_spool_name);
+  errno = save_errno;
+  return rc;
+
+err:
+  save_errno = errno;
+  rc = FALSE;
+  goto CLEANUP;
+}
+
+
+
+/***************************************************************************************************
+*    External interface to write the message, while signing it with DKIM and/or Domainkeys         *
+***************************************************************************************************/
+
+/* This function is a wrapper around transport_write_message().
+   It is only called from the smtp transport if DKIM or Domainkeys support
+   is compiled in.
+
+Arguments:
+  As for transport_write_message() in transort.c, with additional arguments
+  for DKIM.
+
+Returns:       TRUE on success; FALSE (with errno) for any failure
+*/
+
+BOOL
+dkim_transport_write_message(transport_ctx * tctx,
+  struct ob_dkim * dkim, const uschar ** err)
+{
+/* If we can't sign, just call the original function. */
+
+if (!(dkim->dkim_private_key && dkim->dkim_domain && dkim->dkim_selector))
+  return transport_write_message(tctx, 0);
+
+/* If there is no filter command set up, construct the message and calculate
+a dkim signature of it, send the signature and a reconstructed message. This
+avoids using a temprary file. */
+
+if (  !transport_filter_argv
+   || !*transport_filter_argv
+   || !**transport_filter_argv
+   )
+  return dkt_direct(tctx, dkim, err);
+
+/* Use the transport path to write a file, calculate a dkim signature,
+send the signature and then send the file. */
+
+return dkt_via_kfile(tctx, dkim, err);
+}
+
+#endif /* whole file */
+
+/* vi: aw ai sw=2
+*/
+/* End of dkim_transport.c */
index c005d4ab9cc6dd9bd16763be190292a3a81f7329..704b0c88d582939967275c3cfb6c82c76144b444 100644 (file)
@@ -44,6 +44,7 @@ typedef struct dmarc_exim_p {
 } dmarc_exim_p;
 
 static dmarc_exim_p dmarc_policy_description[] = {
+  /* name              value */
   { US"",           DMARC_RECORD_P_UNSPECIFIED },
   { US"none",       DMARC_RECORD_P_NONE },
   { US"quarantine", DMARC_RECORD_P_QUARANTINE },
@@ -83,8 +84,7 @@ int dmarc_init()
 int *netmask   = NULL;   /* Ignored */
 int is_ipv6    = 0;
 char *tld_file = (dmarc_tld_file == NULL) ?
-                "/etc/exim/opendmarc.tlds" :
-                (char *)dmarc_tld_file;
+                DMARC_TLD_FILE : CS dmarc_tld_file;
 
 /* Set some sane defaults.  Also clears previous results when
  * multiple messages in one connection. */
@@ -308,7 +308,7 @@ if (!dmarc_abort && !sender_host_authenticated)
                            sr == SPF_RESULT_PERMERROR ? ARES_RESULT_PERMERROR :
                            ARES_RESULT_UNKNOWN;
     origin = DMARC_POLICY_SPF_ORIGIN_MAILFROM;
-    spf_human_readable = (uschar *)spf_response->header_comment;
+    spf_human_readable = US spf_response->header_comment;
     DEBUG(D_receive)
       debug_printf("DMARC using SPF sender domain = %s\n", spf_sender_domain);
     }
@@ -336,7 +336,7 @@ if (!dmarc_abort && !sender_host_authenticated)
                  vs == PDKIM_VERIFY_FAIL ? DMARC_POLICY_DKIM_OUTCOME_FAIL :
                  vs == PDKIM_VERIFY_INVALID ? DMARC_POLICY_DKIM_OUTCOME_TMPFAIL :
                  DMARC_POLICY_DKIM_OUTCOME_NONE;
-    libdm_status = opendmarc_policy_store_dkim(dmarc_pctx, (uschar *)sig->domain,
+    libdm_status = opendmarc_policy_store_dkim(dmarc_pctx, US sig->domain,
                                               dkim_result, US"");
     DEBUG(D_receive)
       debug_printf("DMARC adding DKIM sender domain = %s\n", sig->domain);
@@ -400,7 +400,7 @@ if (!dmarc_abort && !sender_host_authenticated)
   /* Can't use exim's string manipulation functions so allocate memory
    * for libopendmarc using its max hostname length definition. */
 
-  uschar *dmarc_domain = (uschar *)calloc(DMARC_MAXHOSTNAMELEN, sizeof(uschar));
+  uschar *dmarc_domain = US calloc(DMARC_MAXHOSTNAMELEN, sizeof(uschar));
   libdm_status = opendmarc_policy_fetch_utilized_domain(dmarc_pctx,
     dmarc_domain, DMARC_MAXHOSTNAMELEN-1);
   dmarc_used_domain = string_copy(dmarc_domain);
index e29f86c4828378d00d7ca70c1578ae1ece41b959..4950079b4dc971114adad67c810222bbdc0d3671 100644 (file)
@@ -271,10 +271,7 @@ else
     {
     int j;
     for (j = 0; j < 32; j += 4)
-      {
-      sprintf(CS pp, "%x.", (v6[i] >> j) & 15);
-      pp += 2;
-      }
+      pp += sprintf(CS pp, "%x.", (v6[i] >> j) & 15);
     }
   Ustrcpy(pp, "ip6.arpa.");
 
@@ -1019,7 +1016,7 @@ switch (type)
   assertion field. */
   case T_CSA:
     {
-    uschar *srvname, *namesuff, *tld, *p;
+    uschar *srvname, *namesuff, *tld;
     int priority, weight, port;
     int limit, rc, i;
     BOOL ipv6;
index 3e1c5e626be352617a4e1f0885cca4fc36db2adb..10b4ae8e0051ad054bfd17a08356f9e2952ff5ad 100644 (file)
@@ -19,8 +19,6 @@ all described in src/EDITME. */
 lookup_info **lookup_list;
 int lookup_list_count = 0;
 
-static int lookup_list_init_done = 0;
-
 /* Table of information about all possible authentication mechanisms. All
 entries are always present if any mechanism is declared, but the functions are
 set to NULL for those that are not compiled into the binary. */
@@ -63,117 +61,117 @@ auth_info auths_available[] = {
 
 #ifdef AUTH_CRAM_MD5
   {
-  US"cram_md5",                              /* lookup name */
-  auth_cram_md5_options,
-  &auth_cram_md5_options_count,
-  &auth_cram_md5_option_defaults,
-  sizeof(auth_cram_md5_options_block),
-  auth_cram_md5_init,                        /* init function */
-  auth_cram_md5_server,                      /* server function */
-  auth_cram_md5_client,                      /* client function */
-  NULL                                       /* diagnostic function */
+  .driver_name =       US"cram_md5",                              /* lookup name */
+  .options =           auth_cram_md5_options,
+  .options_count =     &auth_cram_md5_options_count,
+  .options_block =     &auth_cram_md5_option_defaults,
+  .options_len =       sizeof(auth_cram_md5_options_block),
+  .init =              auth_cram_md5_init,
+  .servercode =                auth_cram_md5_server,
+  .clientcode =                auth_cram_md5_client,
+  .version_report =    NULL
   },
 #endif
 
 #ifdef AUTH_CYRUS_SASL
   {
-  US"cyrus_sasl",           /* lookup name */
-  auth_cyrus_sasl_options,
-  &auth_cyrus_sasl_options_count,
-  &auth_cyrus_sasl_option_defaults,
-  sizeof(auth_cyrus_sasl_options_block),
-  auth_cyrus_sasl_init,                      /* init function */
-  auth_cyrus_sasl_server,                    /* server function */
-  NULL,                                      /* client function */
-  auth_cyrus_sasl_version_report             /* diagnostic function */
+  .driver_name =       US"cyrus_sasl",
+  .options =           auth_cyrus_sasl_options,
+  .options_count =     &auth_cyrus_sasl_options_count,
+  .options_block =     &auth_cyrus_sasl_option_defaults,
+  .options_len =       sizeof(auth_cyrus_sasl_options_block),
+  .init =              auth_cyrus_sasl_init,
+  .servercode =                auth_cyrus_sasl_server,
+  .clientcode =                NULL,
+  .version_report =    auth_cyrus_sasl_version_report
   },
 #endif
 
 #ifdef AUTH_DOVECOT
   {
-  US"dovecot",                                /* lookup name */
-  auth_dovecot_options,
-  &auth_dovecot_options_count,
-  &auth_dovecot_option_defaults,
-  sizeof(auth_dovecot_options_block),
-  auth_dovecot_init,                          /* init function */
-  auth_dovecot_server,                        /* server function */
-  NULL,                                       /* client function */
-  NULL                                        /* diagnostic function */
+  .driver_name =       US"dovecot",
+  .options =           auth_dovecot_options,
+  .options_count =     &auth_dovecot_options_count,
+  .options_block =     &auth_dovecot_option_defaults,
+  .options_len =       sizeof(auth_dovecot_options_block),
+  .init =              auth_dovecot_init,
+  .servercode =                auth_dovecot_server,
+  .clientcode =                NULL,
+  .version_report =    NULL
   },
 #endif
 
 #ifdef AUTH_GSASL
   {
-  US"gsasl",                                  /* lookup name */
-  auth_gsasl_options,
-  &auth_gsasl_options_count,
-  &auth_gsasl_option_defaults,
-  sizeof(auth_gsasl_options_block),
-  auth_gsasl_init,                            /* init function */
-  auth_gsasl_server,                          /* server function */
-  NULL,                                       /* client function */
-  auth_gsasl_version_report                   /* diagnostic function */
+  .driver_name =       US"gsasl",
+  .options =           auth_gsasl_options,
+  .options_count =     &auth_gsasl_options_count,
+  .options_block =     &auth_gsasl_option_defaults,
+  .options_len =       sizeof(auth_gsasl_options_block),
+  .init =              auth_gsasl_init,
+  .servercode =                auth_gsasl_server,
+  .clientcode =                NULL,
+  .version_report =    auth_gsasl_version_report
   },
 #endif
 
 #ifdef AUTH_HEIMDAL_GSSAPI
   {
-  US"heimdal_gssapi",                         /* lookup name */
-  auth_heimdal_gssapi_options,
-  &auth_heimdal_gssapi_options_count,
-  &auth_heimdal_gssapi_option_defaults,
-  sizeof(auth_heimdal_gssapi_options_block),
-  auth_heimdal_gssapi_init,                   /* init function */
-  auth_heimdal_gssapi_server,                 /* server function */
-  NULL,                                       /* client function */
-  auth_heimdal_gssapi_version_report          /* diagnostic function */
+  .driver_name =       US"heimdal_gssapi",
+  .options =           auth_heimdal_gssapi_options,
+  .options_count        &auth_heimdal_gssapi_options_count,
+  .options_block =     &auth_heimdal_gssapi_option_defaults,
+  .options_len =       sizeof(auth_heimdal_gssapi_options_block),
+  .init =              auth_heimdal_gssapi_init,
+  .servercode =                auth_heimdal_gssapi_server,
+  .clientcode =                NULL,
+  .version_report =    auth_heimdal_gssapi_version_report
   },
 #endif
 
 #ifdef AUTH_PLAINTEXT
   {
-  US"plaintext",                             /* lookup name */
-  auth_plaintext_options,
-  &auth_plaintext_options_count,
-  &auth_plaintext_option_defaults,
-  sizeof(auth_plaintext_options_block),
-  auth_plaintext_init,                       /* init function */
-  auth_plaintext_server,                     /* server function */
-  auth_plaintext_client,                     /* client function */
-  NULL                                       /* diagnostic function */
+  .driver_name =       US"plaintext",
+  .options =           auth_plaintext_options,
+  .options_count =     &auth_plaintext_options_count,
+  .options_block =     &auth_plaintext_option_defaults,
+  .options_len =       sizeof(auth_plaintext_options_block),
+  .init =              auth_plaintext_init,
+  .servercode =                auth_plaintext_server,
+  .clientcode =                auth_plaintext_client,
+  .version_report =    NULL
   },
 #endif
 
 #ifdef AUTH_SPA
   {
-  US"spa",                                   /* lookup name */
-  auth_spa_options,
-  &auth_spa_options_count,
-  &auth_spa_option_defaults,
-  sizeof(auth_spa_options_block),
-  auth_spa_init,                             /* init function */
-  auth_spa_server,                           /* server function */
-  auth_spa_client,                           /* client function */
-  NULL                                       /* diagnostic function */
+  .driver_name =       US"spa",
+  .options =           auth_spa_options,
+  .options_count =     &auth_spa_options_count,
+  .options_block =     &auth_spa_option_defaults,
+  .options_len =       sizeof(auth_spa_options_block),
+  .init =              auth_spa_init,
+  .servercode =                auth_spa_server,
+  .clientcode =                auth_spa_client,
+  .version_report =    NULL
   },
 #endif
 
 #ifdef AUTH_TLS
   {
-  US"tls",                                   /* lookup name */
-  auth_tls_options,
-  &auth_tls_options_count,
-  &auth_tls_option_defaults,
-  sizeof(auth_tls_options_block),
-  auth_tls_init,                             /* init function */
-  auth_tls_server,                           /* server function */
-  NULL,                                      /* client function */
-  NULL                                       /* diagnostic function */
+  .driver_name =       US"tls",
+  .options =           auth_tls_options,
+  .options_count =     &auth_tls_options_count,
+  .options_block =     &auth_tls_option_defaults,
+  .options_len =       sizeof(auth_tls_options_block),
+  .init =              auth_tls_init,
+  .servercode =                auth_tls_server,
+  .clientcode =                NULL,
+  .version_report =    NULL
   },
 #endif
 
-{ US"", NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL  }
+{ .driver_name = US"" }                /* end marker */
 };
 
 
@@ -242,96 +240,96 @@ exim binary. */
 router_info routers_available[] = {
 #ifdef ROUTER_ACCEPT
   {
-  US"accept",
-  accept_router_options,
-  &accept_router_options_count,
-  &accept_router_option_defaults,
-  sizeof(accept_router_options_block),
-  accept_router_init,
-  accept_router_entry,
-  NULL,     /* no tidyup entry */
-  ri_yestransport
+  .driver_name =       US"accept",
+  .options =           accept_router_options,
+  .options_count =     &accept_router_options_count,
+  .options_block =     &accept_router_option_defaults,
+  .options_len =       sizeof(accept_router_options_block),
+  .init =              accept_router_init,
+  .code =              accept_router_entry,
+  .tidyup =            NULL,     /* no tidyup entry */
+  .ri_flags =          ri_yestransport
   },
 #endif
 #ifdef ROUTER_DNSLOOKUP
   {
-  US"dnslookup",
-  dnslookup_router_options,
-  &dnslookup_router_options_count,
-  &dnslookup_router_option_defaults,
-  sizeof(dnslookup_router_options_block),
-  dnslookup_router_init,
-  dnslookup_router_entry,
-  NULL,     /* no tidyup entry */
-  ri_yestransport
+  .driver_name =       US"dnslookup",
+  .options =           dnslookup_router_options,
+  .options_count =     &dnslookup_router_options_count,
+  .options_block =     &dnslookup_router_option_defaults,
+  .options_len =       sizeof(dnslookup_router_options_block),
+  .init =              dnslookup_router_init,
+  .code =              dnslookup_router_entry,
+  .tidyup =            NULL,     /* no tidyup entry */
+  .ri_flags =          ri_yestransport
   },
 #endif
 #ifdef ROUTER_IPLITERAL
   {
-  US"ipliteral",
-  ipliteral_router_options,
-  &ipliteral_router_options_count,
-  &ipliteral_router_option_defaults,
-  sizeof(ipliteral_router_options_block),
-  ipliteral_router_init,
-  ipliteral_router_entry,
-  NULL,     /* no tidyup entry */
-  ri_yestransport
+  .driver_name =       US"ipliteral",
+  .options =           ipliteral_router_options,
+  .options_count =     &ipliteral_router_options_count,
+  .options_block =     &ipliteral_router_option_defaults,
+  .options_len =       sizeof(ipliteral_router_options_block),
+  .init =              ipliteral_router_init,
+  .code =              ipliteral_router_entry,
+  .tidyup =            NULL,     /* no tidyup entry */
+  .ri_flags =          ri_yestransport
   },
 #endif
 #ifdef ROUTER_IPLOOKUP
   {
-  US"iplookup",
-  iplookup_router_options,
-  &iplookup_router_options_count,
-  &iplookup_router_option_defaults,
-  sizeof(iplookup_router_options_block),
-  iplookup_router_init,
-  iplookup_router_entry,
-  NULL,     /* no tidyup entry */
-  ri_notransport
+  .driver_name =       US"iplookup",
+  .options =           iplookup_router_options,
+  .options_count =     &iplookup_router_options_count,
+  .options_block =     &iplookup_router_option_defaults,
+  .options_len =       sizeof(iplookup_router_options_block),
+  .init =              iplookup_router_init,
+  .code =              iplookup_router_entry,
+  .tidyup =            NULL,     /* no tidyup entry */
+  .ri_flags =          ri_notransport
   },
 #endif
 #ifdef ROUTER_MANUALROUTE
   {
-  US"manualroute",
-  manualroute_router_options,
-  &manualroute_router_options_count,
-  &manualroute_router_option_defaults,
-  sizeof(manualroute_router_options_block),
-  manualroute_router_init,
-  manualroute_router_entry,
-  NULL,     /* no tidyup entry */
-  0
+  .driver_name =       US"manualroute",
+  .options =           manualroute_router_options,
+  .options_count =     &manualroute_router_options_count,
+  .options_block =     &manualroute_router_option_defaults,
+  .options_len =       sizeof(manualroute_router_options_block),
+  .init =              manualroute_router_init,
+  .code =              manualroute_router_entry,
+  .tidyup =            NULL,     /* no tidyup entry */
+  .ri_flags =          0
   },
 #endif
 #ifdef ROUTER_QUERYPROGRAM
   {
-  US"queryprogram",
-  queryprogram_router_options,
-  &queryprogram_router_options_count,
-  &queryprogram_router_option_defaults,
-  sizeof(queryprogram_router_options_block),
-  queryprogram_router_init,
-  queryprogram_router_entry,
-  NULL,     /* no tidyup entry */
-  0
+  .driver_name =       US"queryprogram",
+  .options =           queryprogram_router_options,
+  .options_count =     &queryprogram_router_options_count,
+  .options_block =     &queryprogram_router_option_defaults,
+  .options_len =       sizeof(queryprogram_router_options_block),
+  .init =              queryprogram_router_init,
+  .code =              queryprogram_router_entry,
+  .tidyup =            NULL,     /* no tidyup entry */
+  .ri_flags =          0
   },
 #endif
 #ifdef ROUTER_REDIRECT
   {
-  US"redirect",
-  redirect_router_options,
-  &redirect_router_options_count,
-  &redirect_router_option_defaults,
-  sizeof(redirect_router_options_block),
-  redirect_router_init,
-  redirect_router_entry,
-  NULL,     /* no tidyup entry */
-  ri_notransport
+  .driver_name =       US"redirect",
+  .options =           redirect_router_options,
+  .options_count =     &redirect_router_options_count,
+  .options_block =     &redirect_router_option_defaults,
+  .options_len =       sizeof(redirect_router_options_block),
+  .init =              redirect_router_init,
+  .code =              redirect_router_entry,
+  .tidyup =            NULL,     /* no tidyup entry */
+  .ri_flags =          ri_notransport
   },
 #endif
-{ US"", NULL, NULL, NULL, 0, NULL, NULL, NULL, 0 }
+{ US"" }
 };
 
 
@@ -339,91 +337,94 @@ router_info routers_available[] = {
 transport_info transports_available[] = {
 #ifdef TRANSPORT_APPENDFILE
   {
-  US"appendfile",                              /* driver name */
-  appendfile_transport_options,                /* local options table */
-  &appendfile_transport_options_count,         /* number of entries */
-  &appendfile_transport_option_defaults,       /* private options defaults */
-  sizeof(appendfile_transport_options_block),  /* size of private block */
-  appendfile_transport_init,                   /* init entry point */
-  appendfile_transport_entry,                  /* main entry point */
-  NULL,                                        /* no tidyup entry */
-  NULL,                                        /* no closedown entry */
-  TRUE,                                        /* local flag */
+  .driver_name =       US"appendfile",
+  .options =           appendfile_transport_options,
+  .options_count =     &appendfile_transport_options_count,
+  .options_block =     &appendfile_transport_option_defaults,       /* private options defaults */
+  .options_len =       sizeof(appendfile_transport_options_block),
+  .init =              appendfile_transport_init,
+  .code =              appendfile_transport_entry,
+  .tidyup =            NULL,
+  .closedown =         NULL,
+  .local =             TRUE
   },
 #endif
 #ifdef TRANSPORT_AUTOREPLY
   {
-  US"autoreply",                               /* driver name */
-  autoreply_transport_options,                 /* local options table */
-  &autoreply_transport_options_count,          /* number of entries */
-  &autoreply_transport_option_defaults,        /* private options defaults */
-  sizeof(autoreply_transport_options_block),   /* size of private block */
-  autoreply_transport_init,                    /* init entry point */
-  autoreply_transport_entry,                   /* main entry point */
-  NULL,                                        /* no tidyup entry */
-  NULL,                                        /* no closedown entry */
-  TRUE                                         /* local flag */
+  .driver_name =       US"autoreply",
+  .options =           autoreply_transport_options,
+  .options_count =     &autoreply_transport_options_count,
+  .options_block =     &autoreply_transport_option_defaults,
+  .options_len =       sizeof(autoreply_transport_options_block),
+  .init =              autoreply_transport_init,
+  .code =              autoreply_transport_entry,
+  .tidyup =            NULL,
+  .closedown =         NULL,
+  .local =             TRUE
   },
 #endif
 #ifdef TRANSPORT_LMTP
   {
-  US"lmtp",                                    /* driver name */
-  lmtp_transport_options,                      /* local options table */
-  &lmtp_transport_options_count,               /* number of entries */
-  &lmtp_transport_option_defaults,             /* private options defaults */
-  sizeof(lmtp_transport_options_block),        /* size of private block */
-  lmtp_transport_init,                         /* init entry point */
-  lmtp_transport_entry,                        /* main entry point */
-  NULL,                                        /* no tidyup entry */
-  NULL,                                        /* no closedown entry */
-  TRUE                                         /* local flag */
+  .driver_name =       US"lmtp",
+  .options =           lmtp_transport_options,
+  .options_count =     &lmtp_transport_options_count,
+  .options_block =     &lmtp_transport_option_defaults,
+  .options_len =       sizeof(lmtp_transport_options_block),
+  .init =              lmtp_transport_init,
+  .code =              lmtp_transport_entry,
+  .tidyup =            NULL,
+  .closedown =         NULL,
+  .local =             TRUE
   },
 #endif
 #ifdef TRANSPORT_PIPE
   {
-  US"pipe",                                    /* driver name */
-  pipe_transport_options,                      /* local options table */
-  &pipe_transport_options_count,               /* number of entries */
-  &pipe_transport_option_defaults,             /* private options defaults */
-  sizeof(pipe_transport_options_block),        /* size of private block */
-  pipe_transport_init,                         /* init entry point */
-  pipe_transport_entry,                        /* main entry point */
-  NULL,                                        /* no tidyup entry */
-  NULL,                                        /* no closedown entry */
-  TRUE                                         /* local flag */
+  .driver_name =       US"pipe",
+  .options =           pipe_transport_options,
+  .options_count =     &pipe_transport_options_count,
+  .options_block =     &pipe_transport_option_defaults,
+  .options_len =       sizeof(pipe_transport_options_block),
+  .init =              pipe_transport_init,
+  .code =              pipe_transport_entry,
+  .tidyup =            NULL,
+  .closedown =         NULL,
+  .local =             TRUE
   },
 #endif
 #ifdef EXPERIMENTAL_QUEUEFILE
   {
-  US"queuefile",                               /* driver name */
-  queuefile_transport_options,                 /* local options table */
-  &queuefile_transport_options_count,          /* number of entries */
-  &queuefile_transport_option_defaults,        /* private options defaults */
-  sizeof(queuefile_transport_options_block),   /* size of private block */
-  queuefile_transport_init,                    /* init entry point */
-  queuefile_transport_entry,                   /* main entry point */
-  NULL,                                        /* no tidyup entry */
-  NULL,                                        /* no closedown entry */
-  TRUE                                         /* local flag */
+  .driver_name =       US"queuefile",
+  .options =           queuefile_transport_options,
+  .options_count =     &queuefile_transport_options_count,
+  .options_block =     &queuefile_transport_option_defaults,
+  .options_len =       sizeof(queuefile_transport_options_block),
+  .init =              queuefile_transport_init,
+  .code =              queuefile_transport_entry,
+  .tidyup =            NULL,
+  .closedown =         NULL,
+  .local =             TRUE
   },
 #endif
 #ifdef TRANSPORT_SMTP
   {
-  US"smtp",                                    /* driver name */
-  smtp_transport_options,                      /* local options table */
-  &smtp_transport_options_count,               /* number of entries */
-  &smtp_transport_option_defaults,             /* private options defaults */
-  sizeof(smtp_transport_options_block),        /* size of private block */
-  smtp_transport_init,                         /* init entry point */
-  smtp_transport_entry,                        /* main entry point */
-  NULL,                                        /* no tidyup entry */
-  smtp_transport_closedown,                    /* close down passed channel */
-  FALSE                                        /* local flag */
+  .driver_name =       US"smtp",
+  .options =           smtp_transport_options,
+  .options_count =     &smtp_transport_options_count,
+  .options_block =     &smtp_transport_option_defaults,
+  .options_len =       sizeof(smtp_transport_options_block),
+  .init =              smtp_transport_init,
+  .code =              smtp_transport_entry,
+  .tidyup =            NULL,
+  .closedown =         smtp_transport_closedown,
+  .local =             FALSE
   },
 #endif
-{ US"", NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, FALSE }
+{ US"" }
 };
 
+
+#ifndef MACRO_PREDEF
+
 struct lookupmodulestr
 {
   void *dl;
@@ -545,10 +546,12 @@ init_lookup_list(void)
   int moduleerrors = 0;
 #endif
   struct lookupmodulestr *p;
+  static BOOL lookup_list_init_done = FALSE;
+
 
   if (lookup_list_init_done)
     return;
-  lookup_list_init_done = 1;
+  lookup_list_init_done = TRUE;
 
 #if defined(LOOKUP_CDB) && LOOKUP_CDB!=2
   addlookupmodule(NULL, &cdb_lookup_module_info);
@@ -721,4 +724,5 @@ init_lookup_list(void)
   lookupmodules = NULL;
 }
 
+#endif /*!MACRO_PREDEF*/
 /* End of drtables.c */
index faa5cb73b53a1bbdfd3cd75fcba9eb7003289f6d..1899267be74d048bef2d313f7b8fe9e876582787 100644 (file)
@@ -4,6 +4,9 @@ use warnings;
 use strict;
 BEGIN { pop @INC if $INC[-1] eq '.' };
 
+use Pod::Usage;
+use Getopt::Long;
+
 # Copyright (c) 2007-2015 University of Cambridge.
 # See the file NOTICE for conditions of use and distribution.
 
@@ -33,7 +36,6 @@ BEGIN { pop @INC if $INC[-1] eq '.' };
 # Typical run time acceleration: 4 times
 
 
-use Getopt::Std qw(getopts);
 use POSIX qw(mktime);
 
 
@@ -43,7 +45,7 @@ use POSIX qw(mktime);
 
 sub seconds {
 my($year,$month,$day,$hour,$min,$sec,$tzs,$tzh,$tzm) =
-  $_[0] =~ /^(\d{4})-(\d\d)-(\d\d)\s(\d\d):(\d\d):(\d\d)(?>\s([+-])(\d\d)(\d\d))?/o;
+  $_[0] =~ /^(\d{4})-(\d\d)-(\d\d)\s(\d\d):(\d\d):(\d\d)(?:.\d+)?(?>\s([+-])(\d\d)(\d\d))?/o;
 
 my $seconds = mktime $sec, $min, $hour, $day, $month - 1, $year - 1900;
 
@@ -60,10 +62,17 @@ return $seconds;
 # This subroutine processes a single line (in $_) from a log file. Program
 # defensively against short lines finding their way into the log.
 
-my (%saved, %id_list, $pattern, $queue_time, $insensitive, $invert);
+my (%saved, %id_list, $pattern);
+
+my $queue_time  = -1;
+my $insensitive = 1;
+my $invert      = 0;
+my $related     = 0;
+my $use_pager   = 1;
+my $literal     = 0;
+
 
 # If using "related" option, have to track extra message IDs
-my $related;
 my $related_re='';
 my @Mids = ();
 
@@ -74,7 +83,7 @@ sub do_line {
 if (!/^\d{4}-/o) { $_ =~ s/^.*? exim\b.*?: //o; }
 
 return unless
-  my($date,$id) = /^(\d{4}-\d\d-\d\d \d\d:\d\d:\d\d (?:[+-]\d{4} )?)(?:\[\d+\] )?(\w{6}\-\w{6}\-\w{2})?/o;
+  my($date,$id) = /^(\d{4}-\d\d-\d\d \d\d:\d\d:\d\d(?:\.\d+)? (?:[+-]\d{4} )?)(?:\[\d+\] )?(\w{6}\-\w{6}\-\w{2})?/o;
 
 # Handle the case when the log line belongs to a specific message. We save
 # lines for specific messages until the message is complete. Then either print
@@ -115,7 +124,7 @@ if (defined $id)
   if (index($_, 'Completed') != -1 ||
       index($_, 'SMTP data timeout') != -1 ||
         (index($_, 'rejected') != -1 &&
-          /^(\d{4}-\d\d-\d\d \d\d:\d\d:\d\d (?:[+-]\d{4} )?)(?:\[\d+\] )?\w{6}\-\w{6}\-\w{2} rejected/o))
+          /^(\d{4}-\d\d-\d\d \d\d:\d\d:\d\d(?:\.\d+)? (?:[+-]\d{4} )?)(?:\[\d+\] )?\w{6}\-\w{6}\-\w{2} rejected/o))
     {
     if ($queue_time != -1 &&
         $saved{$id} =~ /^(\d{4}-\d\d-\d\d \d\d:\d\d:\d\d ([+-]\d{4} )?)/o)
@@ -205,18 +214,37 @@ sub get_related_ids {
 # which is an additional condition. The -M flag will also display "related"
 # loglines (msgid from matched lines is searched in following lines).
 
-getopts('Ilvt:M',\my %args);
-$queue_time  = $args{'t'}? $args{'t'} : -1;
-$insensitive = $args{'I'}? 0 : 1;
-$invert      = $args{'v'}? 1 : 0;
-$related     = $args{'M'}? 1 : 0;
-
-die "usage: exigrep [-I] [-l] [-M] [-t <seconds>] [-v] <pattern> [<log file>]...\n"
-  if ($#ARGV < 0);
+GetOptions(
+    'I|sensitive' => sub { $insensitive = 0 },
+      'l|literal' => \$literal,
+      'M|related' => \$related,
+      't|queue-time=i' => \$queue_time,
+      'pager!'         => \$use_pager,
+      'v|invert'       => \$invert,
+      'h|help'         => sub { pod2usage(-exit => 0, -verbose => 1) },
+      'm|man'          => sub {
+        pod2usage(
+            -exit      => 0,
+            -verbose   => 2,
+            -noperldoc => system('perldoc -V 2>/dev/null >&2')
+        );
+      },
+) and @ARGV or pod2usage;
 
 $pattern = shift @ARGV;
-$pattern = quotemeta $pattern if $args{l};
+$pattern = quotemeta $pattern if $literal;
 
+# Start a pager if output goes to a terminal
+if (-t 1 and $use_pager)
+  {
+  foreach ($ENV{PAGER}//(), 'less', 'more')
+    {
+    local $ENV{LESS} .= ' --no-init --quit-if-one-screen';
+    open(my $pager, '|-', $_) or next;
+    select $pager;
+    last;
+    }
+  }
 
 # If file arguments are given, open each one and process according as it is
 # is compressed or not.
@@ -256,4 +284,83 @@ for (keys %id_list)
   print "+++ $_ has not completed +++\n$saved{$_}\n";
   }
 
-# End of exigrep
+__END__
+
+=head1 NAME
+
+exigrep - search Exim's main log
+
+=head1 SYNOPSIS
+
+B<exigrep> [options] pattern [log] ...
+
+=head1 DESCRIPTION
+
+The B<exigrep> utility is a Perl script that searches one or more main log
+files for entries that match a given pattern.  When it finds  a  match,
+it  extracts  all  the  log  entries for the relevant message, not just
+those that match the pattern.  Thus, B<exigrep> can extract  complete  log
+entries  for  a  given  message, or all mail for a given user, or for a
+given host, for example.
+
+If no file names are given on the command line, the standard input is read.
+
+For known file extensions indicating compression (F<.gz>, F<.bz2>, F<.xz>, and F<.lzma>)
+a suitable de-compressor is used, if available.
+
+The output is sent through a pager if a terminal is connected to STDOUT. As
+pager are considered: C<$ENV{PAGER}>, C<less>, C<more>.
+
+=head1 OPTIONS
+
+=over
+
+=item B<-l>|B<--literal>
+
+This means 'literal', that is, treat all characters in the
+pattern  as standing for themselves.  Otherwise the pattern must be a
+Perl regular expression.  The pattern match is case-insensitive.
+
+=item B<-t>|B<--queue-time> I<seconds>
+
+Limit the output to messages that spent at least I<seconds> in the
+queue.
+
+=item B<-I>|B<--sensitive>
+
+Do a case sensitive search.
+
+=item B<-v>|B<--invert>
+
+Invert the meaning of the search pattern. That is, print message log
+entries that are not related to that pattern.
+
+=item B<-M>|B<--related>
+
+Search for related messages too.
+
+=item B<--no-pager>
+
+Do not use a pager, even if STDOUT is connected to a terminal.
+
+=item B<-h>|B<--help>
+
+Print a short reference help. For more detailed help try L<exigrep(8)>,
+or C<exigrep -m>.
+
+=item B<-m>|B<--man>
+
+Print this manual page of B<exigrep>.
+
+=back
+
+=head1 SEE ALSO
+
+L<exim(8)>, L<perlre(1)>, L<Exim|http://exim.org/>
+
+=head1 AUTHOR
+
+This  manual  page  was stitched together from spec.txt by Andreas Metzler L<ametzler at downhill.at.eu.org>
+and updated by Heiko Schlittermann L<hs@schlittermann.de>.
+
+=cut
index fd08cc780d7c233fa103ca03b2d244f675bafb56..f09b26902a3a7b77b818b741503f0501c3a870f9 100644 (file)
@@ -212,8 +212,7 @@ int fd;
 
 os_restarting_signal(sig, usr1_handler);
 
-fd = Uopen(process_log_path, O_APPEND|O_WRONLY, LOG_MODE);
-if (fd < 0)
+if ((fd = Uopen(process_log_path, O_APPEND|O_WRONLY, LOG_MODE)) < 0)
   {
   /* If we are already running as the Exim user, try to create it in the
   current process (assuming spool_directory exists). Otherwise, if we are
@@ -345,7 +344,7 @@ Arguments:
 Returns:      -1, 0, or +1
 */
 
-int
+static int
 exim_tvcmp(struct timeval *t1, struct timeval *t2)
 {
 if (t1->tv_sec > t2->tv_sec) return +1;
@@ -1443,10 +1442,9 @@ for (m = macros; m; m = m->next) if (m->command_line)
       }
   if (!found)
     return FALSE;
-  if (m->replacement == NULL)
+  if (!m->replacement)
     continue;
-  len = Ustrlen(m->replacement);
-  if (len == 0)
+  if ((len = m->replen) == 0)
     continue;
   n = pcre_exec(regex_whitelisted_macro, NULL, CS m->replacement, len,
    0, PCRE_EOPT, NULL, 0);
@@ -2457,7 +2455,7 @@ for (i = 1; i < argc; i++)
           exit(EXIT_FAILURE);
           }
 
-      m = macro_create(name, s, TRUE, FALSE);
+      m = macro_create(string_copy(name), string_copy(s), TRUE);
 
       if (clmacro_count >= MAX_CLMACROS)
         {
@@ -2710,7 +2708,7 @@ for (i = 1; i < argc; i++)
 
       /* Set up $sending_ip_address and $sending_port, unless proxied */
 
-      if (!continue_proxy)
+      if (!continue_proxy_cipher)
        if (getsockname(fileno(stdin), (struct sockaddr *)(&interface_sock),
            &size) == 0)
          sending_ip_address = host_ntoa(-1, &interface_sock, NULL,
@@ -2739,7 +2737,7 @@ for (i = 1; i < argc; i++)
     /* -MCD: set the smtp_use_dsn flag; this indicates that the host
        that exim is connected to supports the esmtp extension DSN */
 
-       case 'D': smtp_peer_options |= PEER_OFFERED_DSN; break;
+       case 'D': smtp_peer_options |= OPTION_DSN; break;
 
     /* -MCG: set the queue name, to a non-default value */
 
@@ -2749,12 +2747,12 @@ for (i = 1; i < argc; i++)
 
     /* -MCK: the peer offered CHUNKING.  Must precede -MC */
 
-       case 'K': smtp_peer_options |= PEER_OFFERED_CHUNKING; break;
+       case 'K': smtp_peer_options |= OPTION_CHUNKING; break;
 
     /* -MCP: set the smtp_use_pipelining flag; this is useful only when
     it preceded -MC (see above) */
 
-       case 'P': smtp_peer_options |= PEER_OFFERED_PIPE; break;
+       case 'P': smtp_peer_options |= OPTION_PIPE; break;
 
     /* -MCQ: pass on the pid of the queue-running process that started
     this chain of deliveries and the fd of its synchronizing pipe; this
@@ -2769,25 +2767,27 @@ for (i = 1; i < argc; i++)
     /* -MCS: set the smtp_use_size flag; this is useful only when it
     precedes -MC (see above) */
 
-       case 'S': smtp_peer_options |= PEER_OFFERED_SIZE; break;
+       case 'S': smtp_peer_options |= OPTION_SIZE; break;
 
 #ifdef SUPPORT_TLS
     /* -MCt: similar to -MCT below but the connection is still open
     via a proxy proces which handles the TLS context and coding.
-    Require two arguments for the proxied local address and port.  */
+    Require three arguments for the proxied local address and port,
+    and the TLS cipher.  */
 
-       case 't': continue_proxy = TRUE;
-                 if (++i < argc) sending_ip_address = argv[i];
+       case 't': if (++i < argc) sending_ip_address = argv[i];
                  else badarg = TRUE;
                  if (++i < argc) sending_port = (int)(Uatol(argv[i]));
                  else badarg = TRUE;
+                 if (++i < argc) continue_proxy_cipher = argv[i];
+                 else badarg = TRUE;
                  /*FALLTHROUGH*/
 
     /* -MCT: set the tls_offered flag; this is useful only when it
     precedes -MC (see above). The flag indicates that the host to which
     Exim is connected has offered TLS support. */
 
-       case 'T': smtp_peer_options |= PEER_OFFERED_TLS; break;
+       case 'T': smtp_peer_options |= OPTION_TLS; break;
 #endif
 
        default:  badarg = TRUE; break;
@@ -3104,7 +3104,14 @@ for (i = 1; i < argc; i++)
 
       /* -oMr: Received protocol */
 
-      else if (Ustrcmp(argrest, "Mr") == 0) received_protocol = argv[++i];
+      else if (Ustrcmp(argrest, "Mr") == 0)
+
+        if (received_protocol)
+          {
+          fprintf(stderr, "received_protocol is set already\n");
+          exit(EXIT_FAILURE);
+          }
+        else received_protocol = argv[++i];
 
       /* -oMs: Set sender host name */
 
@@ -3200,7 +3207,15 @@ for (i = 1; i < argc; i++)
 
     if (*argrest != 0)
       {
-      uschar *hn = Ustrchr(argrest, ':');
+      uschar *hn;
+
+      if (received_protocol)
+        {
+        fprintf(stderr, "received_protocol is set already\n");
+        exit(EXIT_FAILURE);
+        }
+
+      hn = Ustrchr(argrest, ':');
       if (hn == NULL)
         {
         received_protocol = argrest;
@@ -3809,6 +3824,10 @@ defined) */
 
 readconf_main(checking || list_options);
 
+if (builtin_macros_create_trigger) DEBUG(D_any)
+  debug_printf("Builtin macros created (expensive) due to config line '%.*s'\n",
+    Ustrlen(builtin_macros_create_trigger)-1, builtin_macros_create_trigger);
+
 /* Now in directory "/" */
 
 if (cleanup_environment() == FALSE)
@@ -3828,17 +3847,13 @@ if (real_uid == root_uid || real_uid == exim_uid || real_gid == exim_gid)
 else
   {
   int i, j;
-  for (i = 0; i < group_count; i++)
-    {
-    if (group_list[i] == exim_gid) admin_user = TRUE;
-    else if (admin_groups != NULL)
-      {
-      for (j = 1; j <= (int)(admin_groups[0]); j++)
+  for (i = 0; i < group_count && !admin_user; i++)
+    if (group_list[i] == exim_gid)
+      admin_user = TRUE;
+    else if (admin_groups)
+      for (j = 1; j <= (int)admin_groups[0] && !admin_user; j++)
         if (admin_groups[j] == group_list[i])
-          { admin_user = TRUE; break; }
-      }
-    if (admin_user) break;
-    }
+          admin_user = TRUE;
   }
 
 /* Another group of privileged users are the trusted users. These are root,
@@ -3852,29 +3867,28 @@ else
   {
   int i, j;
 
-  if (trusted_users != NULL)
-    {
-    for (i = 1; i <= (int)(trusted_users[0]); i++)
+  if (trusted_users)
+    for (i = 1; i <= (int)trusted_users[0] && !trusted_caller; i++)
       if (trusted_users[i] == real_uid)
-        { trusted_caller = TRUE; break; }
-    }
+        trusted_caller = TRUE;
 
-  if (!trusted_caller && trusted_groups != NULL)
-    {
-    for (i = 1; i <= (int)(trusted_groups[0]); i++)
-      {
+  if (trusted_groups)
+    for (i = 1; i <= (int)trusted_groups[0] && !trusted_caller; i++)
       if (trusted_groups[i] == real_gid)
         trusted_caller = TRUE;
-      else for (j = 0; j < group_count; j++)
-        {
+      else for (j = 0; j < group_count && !trusted_caller; j++)
         if (trusted_groups[i] == group_list[j])
-          { trusted_caller = TRUE; break; }
-        }
-      if (trusted_caller) break;
-      }
-    }
+          trusted_caller = TRUE;
   }
 
+/* At this point, we know if the user is privileged and some command-line
+options become possibly imperssible, depending upon the configuration file. */
+
+if (checking && commandline_checks_require_admin && !admin_user) {
+  fprintf(stderr, "exim: those command-line flags are set to require admin\n");
+  exit(EXIT_FAILURE);
+}
+
 /* Handle the decoding of logging options. */
 
 decode_bits(log_selector, log_selector_size, log_notall,
@@ -4117,9 +4131,8 @@ if (((debug_selector & D_any) != 0 || LOGGING(arguments))
       quote = US"";
       while (*pp != 0) if (isspace(*pp++)) { quote = US"\""; break; }
       }
-    sprintf(CS p, " %s%.*s%s", quote, (int)(big_buffer_size -
+    p += sprintf(CS p, " %s%.*s%s", quote, (int)(big_buffer_size -
       (p - big_buffer) - 4), printing, quote);
-    while (*p) p++;
     }
 
   if (LOGGING(arguments))
@@ -4140,6 +4153,7 @@ if (Uchdir(spool_directory) != 0)
   int dummy;
   (void)directory_make(spool_directory, US"", SPOOL_DIRECTORY_MODE, FALSE);
   dummy = /* quieten compiler */ Uchdir(spool_directory);
+  dummy = dummy;       /* yet more compiler quietening, sigh */
   }
 
 /* Handle calls with the -bi option. This is a sendmail option to rebuild *the*
@@ -4350,11 +4364,8 @@ if (!unprivileged &&                      /* originally had root AND */
         (msg_action_arg < 0 ||            /*       and               */
           msg_action != MSG_DELIVER) &&   /* not delivering and      */
         (!checking || !address_test_mode) /* not address checking    */
-        )
-      ))
-  {
+   )  ) )
   exim_setugid(exim_uid, exim_gid, TRUE, US"privilege not needed");
-  }
 
 /* When we are retaining a privileged uid, we still change to the exim gid. */
 
@@ -4368,7 +4379,6 @@ else
   there's no security risk.  For me, it's { exim -bV } on a just-built binary,
   no need to complain then. */
   if (rv == -1)
-    {
     if (!(unprivileged || removed_privilege))
       {
       fprintf(stderr,
@@ -4378,7 +4388,6 @@ else
     else
       DEBUG(D_any) debug_printf("changing group to %ld failed: %s\n",
           (long int)exim_gid, strerror(errno));
-    }
   }
 
 /* Handle a request to scan a file for malware */
@@ -4528,8 +4537,9 @@ if (test_retry_arg >= 0)
       }
     }
 
-  yield = retry_find_config(s1, s2, basic_errno, more_errno);
-  if (yield == NULL) printf("No retry information found\n"); else
+  if (!(yield = retry_find_config(s1, s2, basic_errno, more_errno)))
+    printf("No retry information found\n");
+  else
     {
     retry_rule *r;
     more_errno = yield->more_errno;
@@ -4561,7 +4571,7 @@ if (test_retry_arg >= 0)
       printf("auth_failed  ");
     else printf("*  ");
 
-    for (r = yield->rules; r != NULL; r = r->next)
+    for (r = yield->rules; r; r = r->next)
       {
       printf("%c,%s", r->rule, readconf_printtime(r->timeout)); /* Do not */
       printf(",%s", readconf_printtime(r->p1));                 /* amalgamate */
@@ -5327,15 +5337,13 @@ if (smtp_input)
 else
   {
   thismessage_size_limit = expand_string_integer(message_size_limit, TRUE);
-  if (expand_string_message != NULL)
-    {
+  if (expand_string_message)
     if (thismessage_size_limit == -1)
       log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to expand "
         "message_size_limit: %s", expand_string_message);
     else
       log_write(0, LOG_MAIN|LOG_PANIC_DIE, "invalid value for "
         "message_size_limit: %s", expand_string_message);
-    }
   }
 
 /* Loop for several messages when reading SMTP input. If we fork any child
@@ -5432,6 +5440,7 @@ while (more)
       more = receive_msg(extract_recipients);
       if (message_id[0] == 0)
         {
+       cancel_cutthrough_connection(TRUE, US"receive dropped");
         if (more) goto moreloop;
         smtp_log_no_mail();               /* Log no mail if configured */
         exim_exit(EXIT_FAILURE);
@@ -5439,6 +5448,7 @@ while (more)
       }
     else
       {
+      cancel_cutthrough_connection(TRUE, US"message setup dropped");
       smtp_log_no_mail();               /* Log no mail if configured */
       exim_exit((rc == 0)? EXIT_SUCCESS : EXIT_FAILURE);
       }
@@ -5582,7 +5592,7 @@ while (more)
 
     if (!receive_timeout)
       {
-      struct timeval t = { 30*60, 0 }; /* 30 minutes */
+      struct timeval t = { .tv_sec = 30*60, .tv_usec = 0 };    /* 30 minutes */
       fd_set r;
 
       FD_ZERO(&r); FD_SET(0, &r);
@@ -5714,21 +5724,28 @@ while (more)
   not if queue_only is set (case 0). Case 1 doesn't happen here (too many
   connections). */
 
-  if (local_queue_only) switch(queue_only_reason)
+  if (local_queue_only)
     {
-    case 2:
-    log_write(L_delay_delivery,
-              LOG_MAIN, "no immediate delivery: more than %d messages "
-      "received in one connection", smtp_accept_queue_per_connection);
-    break;
+    cancel_cutthrough_connection(TRUE, US"no delivery; queueing");
+    switch(queue_only_reason)
+      {
+      case 2:
+       log_write(L_delay_delivery,
+               LOG_MAIN, "no immediate delivery: more than %d messages "
+         "received in one connection", smtp_accept_queue_per_connection);
+       break;
 
-    case 3:
-    log_write(L_delay_delivery,
-              LOG_MAIN, "no immediate delivery: load average %.2f",
-              (double)load_average/1000.0);
-    break;
+      case 3:
+       log_write(L_delay_delivery,
+               LOG_MAIN, "no immediate delivery: load average %.2f",
+               (double)load_average/1000.0);
+      break;
+      }
     }
 
+  else if (queue_only_policy || deliver_freeze)
+    cancel_cutthrough_connection(TRUE, US"no delivery; queueing");
+
   /* Else do the delivery unless the ACL or local_scan() called for queue only
   or froze the message. Always deliver in a separate process. A fork failure is
   not a disaster, as the delivery will eventually happen on a subsequent queue
@@ -5737,7 +5754,7 @@ while (more)
   thereby defer the delivery if it tries to use (for example) a cached ldap
   connection that the parent has called unbind on. */
 
-  else if (!queue_only_policy && !deliver_freeze)
+  else
     {
     pid_t pid;
     search_tidyup();
@@ -5753,8 +5770,7 @@ while (more)
 
       if (geteuid() != root_uid && !deliver_drop_privilege && !unprivileged)
         {
-        (void)child_exec_exim(CEE_EXEC_EXIT, FALSE, NULL, FALSE,
-               2, US"-Mc", message_id);
+       delivery_re_exec(CEE_EXEC_EXIT);
         /* Control does not return here. */
         }
 
@@ -5768,22 +5784,27 @@ while (more)
 
     if (pid < 0)
       {
+      cancel_cutthrough_connection(TRUE, US"delivery fork failed");
       log_write(0, LOG_MAIN|LOG_PANIC, "failed to fork automatic delivery "
         "process: %s", strerror(errno));
       }
+    else
+      {
+      release_cutthrough_connection(US"msg passed for delivery");
 
-    /* In the parent, wait if synchronous delivery is required. This will
-    always be the case in MUA wrapper mode. */
+      /* In the parent, wait if synchronous delivery is required. This will
+      always be the case in MUA wrapper mode. */
 
-    else if (synchronous_delivery)
-      {
-      int status;
-      while (wait(&status) != pid);
-      if ((status & 0x00ff) != 0)
-        log_write(0, LOG_MAIN|LOG_PANIC,
-          "process %d crashed with signal %d while delivering %s",
-          (int)pid, status & 0x00ff, message_id);
-      if (mua_wrapper && (status & 0xffff) != 0) exim_exit(EXIT_FAILURE);
+      if (synchronous_delivery)
+       {
+       int status;
+       while (wait(&status) != pid);
+       if ((status & 0x00ff) != 0)
+         log_write(0, LOG_MAIN|LOG_PANIC,
+           "process %d crashed with signal %d while delivering %s",
+           (int)pid, status & 0x00ff, message_id);
+       if (mua_wrapper && (status & 0xffff) != 0) exim_exit(EXIT_FAILURE);
+       }
       }
     }
 
@@ -5818,4 +5839,50 @@ exim_exit(EXIT_SUCCESS);   /* Never returns */
 return 0;                  /* To stop compiler warning */
 }
 
+/*************************************************
+*          read as much as requested             *
+*************************************************/
+
+/* The syscall read(2) doesn't always returns as much as we want. For
+several reasons it might get less. (Not talking about signals, as syscalls
+are restartable). When reading from a network or pipe connection the sender
+might send in smaller chunks, with delays between these chunks. The read(2)
+may return such a chunk.
+
+The more the writer writes and the smaller the pipe between write and read is,
+the more we get the chance of reading leass than requested. (See bug 2130)
+
+This function read(2)s until we got all the data we *requested*.
+
+Note: This function may block. Use it only if you're sure about the
+amount of data you will get.
+
+Argument:
+  fd          the file descriptor to read from
+  buffer      pointer to a buffer of size len
+  len         the requested(!) amount of bytes
+
+Returns:      the amount of bytes read
+*/
+ssize_t
+readn(int fd, void *buffer, size_t len)
+{
+  void *next = buffer;
+  void *end = buffer + len;
+
+  while (next < end)
+    {
+    ssize_t got = read(fd, next, end - next);
+
+    /* I'm not sure if there are signals that can interrupt us,
+    for now I assume the worst */
+    if (got == -1 && errno == EINTR) continue;
+    if (got <= 0) return next - buffer;
+    next += got;
+    }
+
+  return len;
+}
+
+
 /* End of exim.c */
index d03b48c66abaa52b6f2ea366dbb62f0d00589b10..f8dd9a9ba11897321443035beaf249d998121d46 100644 (file)
@@ -492,6 +492,7 @@ config.h, mytypes.h, and store.h, so we don't need to mention them explicitly.
 #include "macros.h"
 #include "dbstuff.h"
 #include "structs.h"
+#include "blob.h"
 #include "globals.h"
 #include "hash.h"
 #include "functions.h"
@@ -596,5 +597,9 @@ default to EDQUOT if it exists, otherwise ENOSPC. */
 # undef DISABLE_DNSSEC
 #endif
 
+/* Wrapper around read(2) to read all the data we requested (BLOCKING) */
+ssize_t
+readn(int fd, void *buffer, size_t len);
+
 #endif
 /* End of exim.h */
index 85ae9012bc73ff1968be99b82843b02b30529d25..7431bbc030204f5d1e9df4e014d359d913c29a33 100644 (file)
@@ -30,6 +30,7 @@ characters. */
 
 #include "exim.h"
 
+uschar * spool_directory = NULL;       /* dummy for dbstuff.h */
 
 #define max_insize   20000
 #define max_outsize 100000
@@ -151,6 +152,7 @@ uschar *bptr;
 uschar  keybuffer[256];
 uschar  temp_dbmname[512];
 uschar  real_dbmname[512];
+uschar  dirname[512];
 uschar *buffer = malloc(max_outsize);
 uschar *line = malloc(max_insize);
 
@@ -205,10 +207,14 @@ if (strlen(argv[arg+1]) > sizeof(temp_dbmname) - 20)
 Ustrcpy(temp_dbmname, argv[arg+1]);
 Ustrcat(temp_dbmname, ".dbmbuild_temp");
 
+Ustrcpy(dirname, temp_dbmname);
+if ((bptr = Ustrrchr(dirname, '/')))
+  *bptr = '\0';
+
 /* It is apparently necessary to open with O_RDWR for this to work
 with gdbm-1.7.3, though no reading is actually going to be done. */
 
-EXIM_DBOPEN(temp_dbmname, O_RDWR|O_CREAT|O_EXCL, 0644, &d);
+EXIM_DBOPEN(temp_dbmname, dirname, O_RDWR|O_CREAT|O_EXCL, 0644, &d);
 
 if (d == NULL)
   {
index c710772edb229c18c34eef61ce9b2a98adcbb371..fb455bbd38d0e62b9673e277bd2b897621f95af3 100644 (file)
@@ -253,18 +253,19 @@ dbfn_open(uschar *name, int flags, open_db *dbblock, BOOL lof)
 int rc;
 struct flock lock_data;
 BOOL read_only = flags == O_RDONLY;
-uschar buffer[256];
+uschar dirname[256], filename[256];
 
 /* The first thing to do is to open a separate file on which to lock. This
 ensures that Exim has exclusive use of the database before it even tries to
 open it. If there is a database, there should be a lock file in existence. */
 
-sprintf(CS buffer, "%s/db/%.200s.lockfile", spool_directory, name);
+snprintf(CS dirname, sizeof(dirname), "%s/db", spool_directory);
+snprintf(CS filename, sizeof(filename), "%s/%.200s.lockfile", dirname, name);
 
-dbblock->lockfd = Uopen(buffer, flags, 0);
+dbblock->lockfd = Uopen(filename, flags, 0);
 if (dbblock->lockfd < 0)
   {
-  printf("** Failed to open database lock file %s: %s\n", buffer,
+  printf("** Failed to open database lock file %s: %s\n", filename,
     strerror(errno));
   return NULL;
   }
@@ -286,7 +287,7 @@ if (rc < 0)
   {
   printf("** Failed to get %s lock for %s: %s",
     flags & O_WRONLY ? "write" : "read",
-    buffer,
+    filename,
     errno == ETIMEDOUT ? "timed out" : strerror(errno));
   (void)close(dbblock->lockfd);
   return NULL;
@@ -295,12 +296,12 @@ if (rc < 0)
 /* At this point we have an opened and locked separate lock file, that is,
 exclusive access to the database, so we can go ahead and open it. */
 
-sprintf(CS buffer, "%s/db/%s", spool_directory, name);
-EXIM_DBOPEN(buffer, flags, 0, &(dbblock->dbptr));
+sprintf(CS filename, "%s/%s", dirname, name);
+EXIM_DBOPEN(filename, dirname, flags, 0, &(dbblock->dbptr));
 
 if (dbblock->dbptr == NULL)
   {
-  printf("** Failed to open DBM file %s for %s:\n   %s%s\n", buffer,
+  printf("** Failed to open DBM file %s for %s:\n   %s%s\n", filename,
     read_only? "reading" : "writing", strerror(errno),
     #ifdef USE_DB
     " (or Berkeley DB error while opening)"
@@ -516,15 +517,16 @@ uschar keybuffer[1024];
 
 dbdata_type = check_args(argc, argv, US"dumpdb", US"");
 spool_directory = argv[1];
-dbm = dbfn_open(argv[2], O_RDONLY, &dbblock, FALSE);
-if (dbm == NULL) exit(1);
+if (!(dbm = dbfn_open(argv[2], O_RDONLY, &dbblock, FALSE)))
+  exit(1);
 
 /* Scan the file, formatting the information for each entry. Note
 that data is returned in a malloc'ed block, in order that it be
 correctly aligned. */
 
-key = dbfn_scan(dbm, TRUE, &cursor);
-while (key != NULL)
+for (key = dbfn_scan(dbm, TRUE, &cursor);
+     key;
+     key = dbfn_scan(dbm, FALSE, &cursor))
   {
   dbdata_retry *retry;
   dbdata_wait *wait;
@@ -546,9 +548,8 @@ while (key != NULL)
     return 1;
     }
   Ustrcpy(keybuffer, key);
-  value = dbfn_read_with_length(dbm, keybuffer, &length);
 
-  if (value == NULL)
+  if (!(value = dbfn_read_with_length(dbm, keybuffer, &length)))
     fprintf(stderr, "**** Entry \"%s\" was in the key scan, but the record "
                     "was not found in the file - something is wrong!\n",
       CS keybuffer);
@@ -668,7 +669,6 @@ while (key != NULL)
       }
     store_reset(value);
     }
-  key = dbfn_scan(dbm, FALSE, &cursor);
   }
 
 dbfn_close(dbm);
@@ -775,8 +775,9 @@ for(;;)
     {
     int verify = 1;
     spool_directory = argv[1];
-    dbm = dbfn_open(argv[2], O_RDWR, &dbblock, FALSE);
-    if (dbm == NULL) continue;
+
+    if (!(dbm = dbfn_open(argv[2], O_RDWR, &dbblock, FALSE)))
+      continue;
 
     if (Ustrcmp(field, "d") == 0)
       {
@@ -972,11 +973,10 @@ for(;;)
   /* Handle a read request, or verify after an update. */
 
   spool_directory = argv[1];
-  dbm = dbfn_open(argv[2], O_RDONLY, &dbblock, FALSE);
-  if (dbm == NULL) continue;
+  if (!(dbm = dbfn_open(argv[2], O_RDONLY, &dbblock, FALSE)))
+    continue;
 
-  record = dbfn_read_with_length(dbm, name, &oldlength);
-  if (record == NULL)
+  if (!(record = dbfn_read_with_length(dbm, name, &oldlength)))
     {
     printf("record %s not found\n", name);
     name[0] = 0;
@@ -1159,8 +1159,8 @@ oldest = time(NULL) - maxkeep;
 printf("Tidying Exim hints database %s/db/%s\n", argv[1], argv[2]);
 
 spool_directory = argv[1];
-dbm = dbfn_open(argv[2], O_RDWR, &dbblock, FALSE);
-if (dbm == NULL) exit(1);
+if (!(dbm = dbfn_open(argv[2], O_RDWR, &dbblock, FALSE)))
+  exit(1);
 
 /* Prepare for building file names */
 
@@ -1173,14 +1173,14 @@ to the file while scanning it. Pity the man page doesn't warn you about that.
 Therefore, we scan and build a list of all the keys. Then we use that to
 read the records and possibly update them. */
 
-key = dbfn_scan(dbm, TRUE, &cursor);
-while (key != NULL)
+for (key = dbfn_scan(dbm, TRUE, &cursor);
+     key;
+     key = dbfn_scan(dbm, FALSE, &cursor))
   {
   key_item *k = store_get(sizeof(key_item) + Ustrlen(key));
   k->next = keychain;
   keychain = k;
   Ustrcpy(k->key, key);
-  key = dbfn_scan(dbm, FALSE, &cursor);
   }
 
 /* Now scan the collected keys and operate on the records, resetting
@@ -1188,7 +1188,7 @@ the store each time round. */
 
 reset_point = store_get(0);
 
-while (keychain != NULL)
+while (keychain)
   {
   dbdata_generic *value;
 
index a2113f1068949fc661f000041638124a9c015a94..727ee44b9d4a2d96a0b0bc7998f02166785ff15e 100644 (file)
@@ -896,6 +896,7 @@ sub unformat_time {
 # POSIX::mktime.  We expect the timestamp to be of the form
 # "$year-$mon-$day $hour:$min:$sec", with month going from 1 to 12,
 # and the year to be absolute (we do the necessary conversions). The
+# seconds value can be followed by decimals, which we ignore. The
 # timestamp may be followed with an offset from UTC like "+$hh$mm"; if the
 # offset is not present, and we have not been told that the log is in UTC
 # (with the -utc option), then we adjust the time by the current local
@@ -919,7 +920,7 @@ sub seconds {
   # Is the timestamp the same as the last one?
   return $last_time if ($last_timestamp eq $timestamp);
 
-  return 0 unless ($timestamp =~ /^((\d{4})\-(\d\d)-(\d\d))\s(\d\d):(\d\d):(\d\d)( ([+-])(\d\d)(\d\d))?/o);
+  return 0 unless ($timestamp =~ /^((\d{4})\-(\d\d)-(\d\d))\s(\d\d):(\d\d):(\d\d)(?:\.\d+)?( ([+-])(\d\d)(\d\d))?/o);
 
   unless ($last_date eq $1) {
     $last_date = $1;
@@ -931,7 +932,7 @@ sub seconds {
   my $time = $date_seconds + ($5 * 3600) + ($6 * 60) + $7;
 
   # SC. Use caching. Also note we want seconds not minutes.
-  #my($this_offset) = ($10 * 60 + $11) * ($9 . "1") if defined $8;
+  #my($this_offset) = ($10 * 60 + $12) * ($9 . "1") if defined $8;
   if (defined $8 && ($8 ne $last_offset)) {
     $last_offset = $8;
     $offset_seconds = ($10 * 60 + $11) * 60;
@@ -939,7 +940,7 @@ sub seconds {
   }
 
 
-  if (defined $7) {
+  if (defined $8) {
     #$time -= $this_offset;
     $time -= $offset_seconds;
   } elsif (defined $localtime_offset) {
@@ -1853,12 +1854,23 @@ sub generate_parser {
 
     $length = length($_);
     next if ($length < 38);
-    next unless /^(\\d{4}\\-\\d\\d-\\d\\d\\s(\\d\\d):(\\d\\d):\\d\\d( [-+]\\d\\d\\d\\d)?)( \\[\\d+\\])?/o;
-
-    ($tod,$m_hour,$m_min) = ($1,$2,$3);
+    next unless /^
+               (\\d{4}\\-\\d\\d-\\d\\d\\s      # 1: YYYYMMDD HHMMSS
+                       (\\d\\d)                # 2: HH
+                       :
+                       (\\d\\d)                # 3: MM
+                       :\\d\\d
+               )
+               (\\.\\d+)?                      # 4: subseconds
+               (\s[-+]\\d\\d\\d\\d)?           # 5: tz-offset
+               (\s\\[\\d+\\])?                 # 6: pid
+               /ox;
+
+    $tod = defined($5) ?  $1 . $5 : $1;
+    ($m_hour,$m_min) = ($2,$3);
 
     # PH - watch for GMT offsets in the timestamp.
-    if (defined($4)) {
+    if (defined($5)) {
       $extra = 6;
       next if ($length < 44);
     }
@@ -1866,9 +1878,15 @@ sub generate_parser {
       $extra = 0;
     }
 
+    # watch for subsecond precision
+    if (defined($4)) {
+      $extra += length($4);
+      next if ($length < 38 + $extra);
+    }
+
     # PH - watch for PID added after the timestamp.
-    if (defined($5)) {
-      $extra += length($5);
+    if (defined($6)) {
+      $extra += length($6);
       next if ($length < 38 + $extra);
     }
 
index 4999d843f2d3877bc870b61f2aae213e50c31c92..4751f76570e46dc3d36bade6ea99f5a4ff8d8360 100644 (file)
@@ -42,6 +42,7 @@ $| = 1; # unbuffer STDOUT
 Getopt::Long::Configure("bundling_override");
 GetOptions(
   'spool=s'     => \$G::spool,      # exim spool dir
+  'C|Config=s'  => \$G::config,     # use alternative Exim configuration file
   'input-dir=s' => \$G::input_dir,  # name of the "input" dir
   'finput'      => \$G::finput,     # same as "--input-dir Finput"
   'bp'          => \$G::mailq_bp,   # List the queue (noop - default)
@@ -115,8 +116,8 @@ $G::msg_ids         = {};                  # short circuit when crit is only MID
 $G::caseless        = $G::caseful ? 0 : 1; # nocase by default, case if both
 @G::recipients_crit = ();                  # holds per-recip criteria
 $spool              = defined $G::spool ? $G::spool
-                     : do { chomp($_ = `$exim -n -bP spool_directory`);
-                       $_ // $spool };
+                     : do { chomp($_ = `$exim @{[defined $G::config ? "-C $G::config" : '']} -n -bP spool_directory`)
+                             and $_ or $spool };
 my $input_dir       = $G::input_dir || ($G::finput ? "Finput" : "input");
 my $count_only      = 1 if ($G::mailq_bpc  || $G::qgrep_c);
 my $unsorted        = 1 if ($G::mailq_bpr  || $G::mailq_bpra ||
@@ -1354,6 +1355,11 @@ Same as '-bpu --unsorted' (exim)
 
 Same as -bp, but only show undelivered messages (exim)
 
+=item -C | --config <config>
+
+Use <config> to determine the proper spool directory. (See C<--spool>
+or C<--input> for alternative ways to specify the directories to operate on.)
+
 =item -c
 
 Show a count of matching messages (exiqgrep)
@@ -1432,8 +1438,7 @@ Same as '$shown_message_size eq <string>' (exiqgrep)
 
 =item --spool <path>
 
-Set the path to the exim spool to use.  This value will have the argument to --input or 'input' appended, or be ignored if --input is a full path. If not specified, exipick uses the value from C<exim -bP spool_directory>, and if this fails, the  F<SPOOL_DIRECTORY>
-from build time (F<Local/Makefile>) is used.
+Set the path to the exim spool to use.  This value will have the argument to --input or 'input' appended, or be ignored if --input is a full path. If not specified, exipick uses the value from C<exim [-C config] -n -bP spool_directory>, and if this call fails, the  F</opt/exim/spool> from build time (F<Local/Makefile>) is used. See also --config.
 
 =item --show-rules
 
index b96b2897a7061b8d56ca85b16f5008470e508f55..353b8ea56b6cdb6a19f0226d826b681bd9254e72 100644 (file)
@@ -642,7 +642,7 @@ static var_entry var_table[] = {
   { "received_ip_address", vtype_stringptr,   &interface_address },
   { "received_port",       vtype_int,         &interface_port },
   { "received_protocol",   vtype_stringptr,   &received_protocol },
-  { "received_time",       vtype_int,         &received_time },
+  { "received_time",       vtype_int,         &received_time.tv_sec },
   { "recipient_data",      vtype_stringptr,   &recipient_data },
   { "recipient_verify_failure",vtype_stringptr,&recipient_verify_failure },
   { "recipients",          vtype_string_func, &fn_recipients },
@@ -680,6 +680,7 @@ static var_entry var_table[] = {
   { "smtp_active_hostname", vtype_stringptr,  &smtp_active_hostname },
   { "smtp_command",        vtype_stringptr,   &smtp_cmd_buffer },
   { "smtp_command_argument", vtype_stringptr, &smtp_cmd_argument },
+  { "smtp_command_history", vtype_string_func, &smtp_cmd_hist },
   { "smtp_count_at_connection_start", vtype_int, &smtp_accept_count },
   { "smtp_notquit_reason", vtype_stringptr,   &smtp_notquit_reason },
   { "sn0",                 vtype_filter_int,  &filter_sn[0] },
@@ -1483,9 +1484,7 @@ while (*s != 0)
 /* If value2 is unset, just compute one number */
 
 if (value2 < 0)
-  {
   s = string_sprintf("%d", total % value1);
-  }
 
 /* Otherwise do a div/mod hash */
 
@@ -1554,11 +1553,9 @@ for (i = 0; i < 2; i++)
   int size = 0;
   header_line *h;
 
-  for (h = header_list; size < header_insert_maxlen && h != NULL; h = h->next)
-    {
-    if (h->type != htype_old && h->text != NULL)  /* NULL => Received: placeholder */
-      {
-      if (name == NULL || (len <= h->slen && strncmpic(name, h->text, len) == 0))
+  for (h = header_list; size < header_insert_maxlen && h; h = h->next)
+    if (h->type != htype_old && h->text)  /* NULL => Received: placeholder */
+      if (!name || (len <= h->slen && strncmpic(name, h->text, len) == 0))
         {
         int ilen;
         uschar *t;
@@ -1580,7 +1577,7 @@ for (i = 0; i < 2; i++)
         that contains an address list, except when asked for raw headers. Only
         need to do this once. */
 
-        if (!want_raw && name != NULL && comma == 0 &&
+        if (!want_raw && name && comma == 0 &&
             Ustrchr("BCFRST", h->type) != NULL)
           comma = 1;
 
@@ -1613,8 +1610,6 @@ for (i = 0; i < 2; i++)
             }
           }
         }
-      }
-    }
 
   /* At end of first pass, return NULL if no header found. Then truncate size
   if necessary, and get the buffer to hold the data, returning the buffer size.
@@ -1632,9 +1627,7 @@ for (i = 0; i < 2; i++)
 /* That's all we do for raw header expansion. */
 
 if (want_raw)
-  {
   *ptr = 0;
-  }
 
 /* Otherwise, remove a final newline and a redundant added comma. Then we do
 RFC 2047 decoding, translating the charset if requested. The rfc2047_decode2()
@@ -1838,7 +1831,7 @@ switch (vp->type)
   case vtype_msgbody:                        /* Pointer to msgbody string */
   case vtype_msgbody_end:                    /* Ditto, the end of the msg */
     ss = (uschar **)(val);
-    if (*ss == NULL && deliver_datafile >= 0)  /* Read body when needed */
+    if (!*ss && deliver_datafile >= 0)  /* Read body when needed */
       {
       uschar *body;
       off_t start_offset = SPOOL_DATA_START_OFFSET;
@@ -1871,7 +1864,7 @@ switch (vp->type)
            { if (body[--len] == '\n' || body[len] == 0) body[len] = ' '; }
        }
       }
-    return (*ss == NULL)? US"" : *ss;
+    return *ss ? *ss : US"";
 
   case vtype_todbsdin:                       /* BSD inbox time of day */
     return tod_stamp(tod_bsdin);
@@ -2384,8 +2377,10 @@ switch(cond_type)
       case 3: return NULL;
       }
 
-    *resetok = FALSE;  /* eval_acl() might allocate; do not reclaim */
-    if (yield != NULL) switch(eval_acl(sub, nelem(sub), &user_msg))
+    if (yield != NULL)
+      {
+      *resetok = FALSE;        /* eval_acl() might allocate; do not reclaim */
+      switch(eval_acl(sub, nelem(sub), &user_msg))
        {
        case OK:
          cond = TRUE;
@@ -2406,6 +2401,7 @@ switch(cond_type)
           expand_string_message = string_sprintf("error from acl \"%s\"", sub[0]);
          return NULL;
        }
+      }
     return s;
     }
 
@@ -4712,8 +4708,7 @@ while (*s != 0)
 
       /* Open the file and read it */
 
-      f = Ufopen(sub_arg[0], "rb");
-      if (f == NULL)
+      if (!(f = Ufopen(sub_arg[0], "rb")))
         {
         expand_string_message = string_open_failed(errno, "%s", sub_arg[0]);
         goto EXPAND_FAILED;
@@ -4724,7 +4719,8 @@ while (*s != 0)
       continue;
       }
 
-    /* Handle "readsocket" to insert data from a Unix domain socket */
+    /* Handle "readsocket" to insert data from a socket, either
+    Inet or Unix domain */
 
     case EITEM_READSOCK:
       {
@@ -4732,10 +4728,10 @@ while (*s != 0)
       int timeout = 5;
       int save_ptr = ptr;
       FILE *f;
-      struct sockaddr_un sockun;         /* don't call this "sun" ! */
       uschar *arg;
       uschar *sub_arg[4];
       BOOL do_shutdown = TRUE;
+      blob reqstr;
 
       if (expand_forbid & RDO_READSOCK)
         {
@@ -4753,6 +4749,11 @@ while (*s != 0)
         case 3: goto EXPAND_FAILED;
         }
 
+      /* Grab the request string, if any */
+
+      reqstr.data = sub_arg[1];
+      reqstr.len = Ustrlen(sub_arg[1]);
+
       /* Sort out timeout, if given.  The second arg is a list with the first element
       being a time value.  Any more are options of form "name=value".  Currently the
       only option recognised is "shutdown". */
@@ -4787,12 +4788,12 @@ while (*s != 0)
         if (Ustrncmp(sub_arg[0], "inet:", 5) == 0)
           {
           int port;
-          uschar *server_name = sub_arg[0] + 5;
-          uschar *port_name = Ustrrchr(server_name, ':');
+          uschar * server_name = sub_arg[0] + 5;
+          uschar * port_name = Ustrrchr(server_name, ':');
 
           /* Sort out the port */
 
-          if (port_name == NULL)
+          if (!port_name)
             {
             expand_string_message =
               string_sprintf("missing port for readsocket %s", sub_arg[0]);
@@ -4814,7 +4815,7 @@ while (*s != 0)
           else
             {
             struct servent *service_info = getservbyname(CS port_name, "tcp");
-            if (service_info == NULL)
+            if (!service_info)
               {
               expand_string_message = string_sprintf("unknown port \"%s\"",
                 port_name);
@@ -4824,17 +4825,20 @@ while (*s != 0)
             }
 
          fd = ip_connectedsocket(SOCK_STREAM, server_name, port, port,
-                 timeout, NULL, &expand_string_message);
+                 timeout, NULL, &expand_string_message, &reqstr);
          callout_address = NULL;
          if (fd < 0)
               goto SOCK_FAIL;
+         reqstr.len = 0;
           }
 
         /* Handle a Unix domain socket */
 
         else
           {
+         struct sockaddr_un sockun;         /* don't call this "sun" ! */
           int rc;
+
           if ((fd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
             {
             expand_string_message = string_sprintf("failed to create socket: %s",
@@ -4868,14 +4872,13 @@ while (*s != 0)
        /* Allow sequencing of test actions */
        if (running_in_test_harness) millisleep(100);
 
-        /* Write the request string, if not empty */
+        /* Write the request string, if not empty or already done */
 
-        if (sub_arg[1][0] != 0)
+        if (reqstr.len)
           {
-          int len = Ustrlen(sub_arg[1]);
           DEBUG(D_expand) debug_printf_indent("writing \"%s\" to socket\n",
-            sub_arg[1]);
-          if (write(fd, sub_arg[1], len) != len)
+            reqstr.data);
+          if (write(fd, reqstr.data, reqstr.len) != reqstr.len)
             {
             expand_string_message = string_sprintf("request write to socket "
               "failed: %s", strerror(errno));
@@ -5991,7 +5994,9 @@ while (*s != 0)
         {
        uschar * dstitem;
        uschar * newlist = NULL;
+       int size = 0, len = 0;
        uschar * newkeylist = NULL;
+       int ksize = 0, klen = 0;
        uschar * srcfield;
 
         DEBUG(D_expand) debug_printf_indent("%s: $item = \"%s\"\n", name, srcitem);
@@ -6036,33 +6041,33 @@ while (*s != 0)
            /* New-item sorts before this dst-item.  Append new-item,
            then dst-item, then remainder of dst list. */
 
-           newlist = string_append_listele(newlist, sep, srcitem);
-           newkeylist = string_append_listele(newkeylist, sep, srcfield);
+           newlist = string_append_listele(newlist, &size, &len, sep, srcitem);
+           newkeylist = string_append_listele(newkeylist, &ksize, &klen, sep, srcfield);
            srcitem = NULL;
 
-           newlist = string_append_listele(newlist, sep, dstitem);
-           newkeylist = string_append_listele(newkeylist, sep, dstfield);
+           newlist = string_append_listele(newlist, &size, &len, sep, dstitem);
+           newkeylist = string_append_listele(newkeylist, &ksize, &klen, sep, dstfield);
 
            while ((dstitem = string_nextinlist(&dstlist, &sep, NULL, 0)))
              {
              if (!(dstfield = string_nextinlist(&dstkeylist, &sep, NULL, 0)))
                goto sort_mismatch;
-             newlist = string_append_listele(newlist, sep, dstitem);
-             newkeylist = string_append_listele(newkeylist, sep, dstfield);
+             newlist = string_append_listele(newlist, &size, &len, sep, dstitem);
+             newkeylist = string_append_listele(newkeylist, &ksize, &klen, sep, dstfield);
              }
 
            break;
            }
 
-         newlist = string_append_listele(newlist, sep, dstitem);
-         newkeylist = string_append_listele(newkeylist, sep, dstfield);
+         newlist = string_append_listele(newlist, &size, &len, sep, dstitem);
+         newkeylist = string_append_listele(newkeylist, &ksize, &klen, sep, dstfield);
          }
 
        /* If we ran out of dstlist without consuming srcitem, append it */
        if (srcitem)
          {
-         newlist = string_append_listele(newlist, sep, srcitem);
-         newkeylist = string_append_listele(newkeylist, sep, srcfield);
+         newlist = string_append_listele(newlist, &size, &len, sep, srcitem);
+         newkeylist = string_append_listele(newkeylist, &ksize, &klen, sep, srcfield);
          }
 
        dstlist = newlist;
@@ -6466,7 +6471,7 @@ while (*s != 0)
          blob b;
          char st[3];
 
-         if (!exim_sha_init(&h, HASH_SHA256))
+         if (!exim_sha_init(&h, HASH_SHA2_256))
            {
            expand_string_message = US"unrecognised sha256 variant";
            goto EXPAND_FAILED;
@@ -6660,19 +6665,19 @@ while (*s != 0)
            char * cp;
            char tok[3];
            tok[0] = sep; tok[1] = ':'; tok[2] = 0;
-           while ((cp= strpbrk((const char *)item, tok)))
+           while ((cp= strpbrk(CCS item, tok)))
              {
-              yield = string_catn(yield, &size, &ptr, item, cp-(char *)item);
+              yield = string_catn(yield, &size, &ptr, item, cp-CS item);
              if (*cp++ == ':') /* colon in a non-colon-sep list item, needs doubling */
                {
                 yield = string_catn(yield, &size, &ptr, US"::", 2);
-               item = (uschar *)cp;
+               item = US cp;
                }
              else              /* sep in item; should already be doubled; emit once */
                {
-                yield = string_catn(yield, &size, &ptr, (uschar *)tok, 1);
+                yield = string_catn(yield, &size, &ptr, US tok, 1);
                if (*cp == sep) cp++;
-               item = (uschar *)cp;
+               item = US cp;
                }
              }
            }
index a5c3b5dfaaf50155189842c7c52edee42aa8233a..86232c1870471fab889688cb0613e9036305bffa 100644 (file)
@@ -91,7 +91,7 @@ static const char *mailargs[] = {  /* "to" must be first, and */
 
 /* The count of string arguments */
 
-#define MAILARGS_STRING_COUNT (sizeof(mailargs)/sizeof(uschar *))
+#define MAILARGS_STRING_COUNT (nelem(mailargs))
 
 /* The count of string arguments that are actually passed over as strings
 (once_repeat is converted to an int). */
@@ -185,7 +185,7 @@ static const char *cond_words[] = {
    "match",
    "matches"};
 
-static int cond_word_count = (sizeof(cond_words)/sizeof(uschar *));
+static int cond_word_count = nelem(cond_words);
 
 static int cond_types[] = { cond_BEGINS, cond_BEGINS, cond_CONTAINS,
   cond_CONTAINS, cond_ENDS, cond_ENDS, cond_IS, cond_MATCHES, cond_MATCHES,
@@ -207,7 +207,7 @@ static const char *command_list[] = {
   "noerror", "pipe",    "save",    "seen", "testprint", "unseen",   "vacation"
 };
 
-static int command_list_count = sizeof(command_list)/sizeof(uschar *);
+static int command_list_count = nelem(command_list);
 
 /* This table contains the number of expanded arguments in the bottom 4 bits.
 If the top bit is set, it means that the default for the command is "seen". */
@@ -1815,7 +1815,7 @@ while (commands != NULL)
       addr = deliver_make_addr(expargs[0], TRUE);  /* TRUE => copy s */
       addr->prop.errors_address = (s == NULL)?
         s : string_copy(s);                        /* Default is NULL */
-      if (commands->noerror) setflag(addr, af_ignore_error);
+      if (commands->noerror) addr->prop.ignore_error = TRUE;
       addr->next = *generated;
       *generated = addr;
       }
@@ -1855,8 +1855,9 @@ while (commands != NULL)
       mode value. */
 
       addr = deliver_make_addr(s, TRUE);  /* TRUE => copy s */
-      setflag(addr, af_pfr|af_file);
-      if (commands->noerror) setflag(addr, af_ignore_error);
+      setflag(addr, af_pfr);
+      setflag(addr, af_file);
+      if (commands->noerror) addr->prop.ignore_error = TRUE;
       addr->mode = mode;
       addr->next = *generated;
       *generated = addr;
@@ -1884,8 +1885,9 @@ while (commands != NULL)
       has been split up into separate arguments. */
 
       addr = deliver_make_addr(s, TRUE);  /* TRUE => copy s */
-      setflag(addr, af_pfr|af_expand_pipe);
-      if (commands->noerror) setflag(addr, af_ignore_error);
+      setflag(addr, af_pfr);
+      setflag(addr, af_expand_pipe);
+      if (commands->noerror) addr->prop.ignore_error = TRUE;
       addr->next = *generated;
       *generated = addr;
 
@@ -2220,7 +2222,7 @@ while (commands != NULL)
       uschar *to = commands->args[mailarg_index_to].u;
       int size = 0;
       int ptr = 0;
-      int badflag = 0;
+      BOOL badflag;
 
       if (to == NULL) to = expand_string(US"$reply_address");
       while (isspace(*to)) to++;
@@ -2292,16 +2294,15 @@ while (commands != NULL)
         while (isspace(*tt)) tt++;
         }
 
-      if (log_addr == NULL)
-        {
+      if ((badflag = !log_addr))
         log_addr = string_sprintf(">**bad-reply**");
-        badflag = af_bad_reply;
-        }
-      else log_addr[ptr] = 0;
+      else
+        log_addr[ptr] = 0;
 
       addr = deliver_make_addr(log_addr, FALSE);
-      setflag(addr, (af_pfr|badflag));
-      if (commands->noerror) setflag(addr, af_ignore_error);
+      setflag(addr, af_pfr);
+      if (badflag) setflag(addr, af_bad_reply);
+      if (commands->noerror) addr->prop.ignore_error = TRUE;
       addr->next = *generated;
       *generated = addr;
       addr->reply = store_get(sizeof(reply_item));
index a7d9c1116cd0cebf4046ed0d70bcd20fecc5064b..9d1f6dc6e118ac7ae2c8e5b8750fa0ed43fa1979 100644 (file)
@@ -14,7 +14,7 @@ are in in fact in separate headers. */
 
 #ifdef EXIM_PERL
 extern uschar *call_perl_cat(uschar *, int *, int *, uschar **, uschar *,
-                 uschar **);
+                 uschar **) WARN_UNUSED_RESULT;
 extern void    cleanup_perl(void);
 extern uschar *init_perl(uschar *);
 #endif
@@ -51,18 +51,20 @@ extern int     tls_client_start(int, host_item *, address_item *,
 # endif
                uschar **);
 extern void    tls_close(BOOL, BOOL);
+extern BOOL    tls_could_read(void);
 extern int     tls_export_cert(uschar *, size_t, void *);
 extern int     tls_feof(void);
 extern int     tls_ferror(void);
 extern void    tls_free_cert(void **);
 extern int     tls_getc(unsigned);
+extern uschar *tls_getbuf(unsigned *);
 extern void    tls_get_cache(void);
 extern int     tls_import_cert(const uschar *, void **);
 extern int     tls_read(BOOL, uschar *, size_t);
 extern int     tls_server_start(const uschar *, uschar **);
 extern BOOL    tls_smtp_buffered(void);
 extern int     tls_ungetc(int);
-extern int     tls_write(BOOL, const uschar *, size_t);
+extern int     tls_write(BOOL, const uschar *, size_t, BOOL);
 extern uschar *tls_validate_require_cipher(void);
 extern void    tls_version_report(FILE *);
 # ifndef USE_GNUTLS
@@ -102,26 +104,28 @@ extern uschar *auth_xtextencode(uschar *, int);
 extern int     auth_xtextdecode(uschar *, uschar **);
 
 extern uschar *b64encode(uschar *, int);
-extern int     b64decode(uschar *, uschar **);
+extern int     b64decode(const uschar *, uschar **);
 extern int     bdat_getc(unsigned);
+extern uschar *bdat_getbuf(unsigned *);
 extern int     bdat_ungetc(int);
 extern void    bdat_flush_data(void);
 
 extern void    bits_clear(unsigned int *, size_t, int *);
 extern void    bits_set(unsigned int *, size_t, int *);
 
-extern void    cancel_cutthrough_connection(const char *);
+extern void    cancel_cutthrough_connection(BOOL, const uschar *);
 extern int     check_host(void *, const uschar *, const uschar **, uschar **);
 extern uschar **child_exec_exim(int, BOOL, int *, BOOL, int, ...);
 extern pid_t   child_open_uid(const uschar **, const uschar **, int,
                 uid_t *, gid_t *, int *, int *, uschar *, BOOL);
 extern BOOL    cleanup_environment(void);
+extern void    cutthrough_data_puts(uschar *, int);
+extern void    cutthrough_data_put_nl(void);
 extern uschar *cutthrough_finaldot(void);
 extern BOOL    cutthrough_flush_send(void);
 extern BOOL    cutthrough_headers_send(void);
 extern BOOL    cutthrough_predata(void);
-extern BOOL    cutthrough_puts(uschar *, int);
-extern BOOL    cutthrough_put_nl(void);
+extern void    release_cutthrough_connection(const uschar *);
 
 extern void    daemon_go(void);
 
@@ -149,10 +153,11 @@ extern int     deliver_split_address(address_item *);
 extern void    deliver_succeeded(address_item *);
 
 extern uschar *deliver_get_sender_address (uschar *id);
+extern void    delivery_re_exec(int);
 
 extern BOOL    directory_make(const uschar *, const uschar *, int, BOOL);
 #ifndef DISABLE_DKIM
-extern BOOL    dkim_transport_write_message(int, transport_ctx *,
+extern BOOL    dkim_transport_write_message(transport_ctx *,
                  struct ob_dkim *, const uschar ** errstr);
 #endif
 extern dns_address *dns_address_from_rr(dns_answer *, dns_record *);
@@ -179,7 +184,6 @@ extern const uschar * exim_errstr(int);
 extern void    exim_exit(int);
 extern void    exim_nullstd(void);
 extern void    exim_setugid(uid_t, gid_t, BOOL, uschar *);
-extern int     exim_tvcmp(struct timeval *, struct timeval *);
 extern void    exim_wait_tick(struct timeval *, int);
 extern int     exp_bool(address_item *addr,
   uschar *mtype, uschar *mname, unsigned dgb_opt, uschar *oname, BOOL bvalue,
@@ -231,9 +235,9 @@ extern uschar *imap_utf7_encode(uschar *, const uschar *,
 extern void    invert_address(uschar *, uschar *);
 extern int     ip_addr(void *, int, const uschar *, int);
 extern int     ip_bind(int, int, uschar *, int);
-extern int     ip_connect(int, int, const uschar *, int, int, BOOL);
+extern int     ip_connect(int, int, const uschar *, int, int, const blob *);
 extern int     ip_connectedsocket(int, const uschar *, int, int,
-                 int, host_item *, uschar **);
+                 int, host_item *, uschar **, const blob *);
 extern int     ip_get_address_family(int);
 extern void    ip_keepalive(int, const uschar *, BOOL);
 extern int     ip_recv(int, uschar *, int, int);
@@ -250,7 +254,7 @@ extern int     log_create(uschar *);
 extern int     log_create_as_exim(uschar *);
 extern void    log_close_all(void);
 
-extern macro_item * macro_create(const uschar *, const uschar *, BOOL, BOOL);
+extern macro_item * macro_create(const uschar *, const uschar *, BOOL);
 extern void    mainlog_close(void);
 #ifdef WITH_CONTENT_SCAN
 extern int     malware(const uschar *, int);
@@ -259,6 +263,7 @@ extern void    malware_init(void);
 #endif
 extern int     match_address_list(const uschar *, BOOL, BOOL, const uschar **,
                  unsigned int *, int, int, const uschar **);
+extern int     match_address_list_basic(const uschar *, const uschar **, int);
 extern int     match_check_list(const uschar **, int, tree_node **, unsigned int **,
                  int(*)(void *, const uschar *, const uschar **, uschar **), void *, int,
                  const uschar *, const uschar **);
@@ -323,8 +328,6 @@ extern void    readconf_driver_init(uschar *, driver_instance **,
 extern uschar *readconf_find_option(void *);
 extern void    readconf_main(BOOL);
 extern void    readconf_options_from_list(optionlist *, unsigned, const uschar *, uschar *);
-extern void    readconf_options_routers(void);
-extern void    readconf_options_transports(void);
 extern void    readconf_print(uschar *, uschar *, BOOL);
 extern uschar *readconf_printtime(int);
 extern uschar *readconf_readname(uschar *, int, uschar *);
@@ -390,10 +393,11 @@ extern int     sieve_interpret(uschar *, int, uschar *, uschar *, uschar *,
 extern void    sigalrm_handler(int);
 extern BOOL    smtp_buffered(void);
 extern void    smtp_closedown(uschar *);
-extern int     smtp_connect(host_item *, int, int, uschar *, int,
+extern uschar *smtp_cmd_hist(void);
+extern int     smtp_connect(host_item *, int, uschar *, int,
                 transport_instance *);
 extern int     smtp_sock_connect(host_item *, int, int, uschar *,
-                transport_instance * tb, int);
+                transport_instance * tb, int, const blob *);
 extern int     smtp_feof(void);
 extern int     smtp_ferror(void);
 extern uschar *smtp_get_connection_info(void);
@@ -401,22 +405,25 @@ extern BOOL    smtp_get_interface(uschar *, int, address_item *,
                  uschar **, uschar *);
 extern BOOL    smtp_get_port(uschar *, address_item *, int *, uschar *);
 extern int     smtp_getc(unsigned);
+extern uschar *smtp_getbuf(unsigned *);
 extern void    smtp_get_cache(void);
 extern int     smtp_handle_acl_fail(int, int, uschar *, uschar *);
 extern void    smtp_log_no_mail(void);
 extern void    smtp_message_code(uschar **, int *, uschar **, uschar **, BOOL);
+extern void    smtp_proxy_tls(uschar *, size_t, int, int);
 extern BOOL    smtp_read_response(smtp_inblock *, uschar *, int, int, int);
 extern void    smtp_respond(uschar *, int, BOOL, uschar *);
 extern void    smtp_notquit_exit(uschar *, uschar *, uschar *, ...);
+extern void    smtp_port_for_connect(host_item *, int);
 extern void    smtp_send_prohibition_message(int, uschar *);
 extern int     smtp_setup_msg(void);
 extern BOOL    smtp_start_session(void);
 extern int     smtp_ungetc(int);
 extern BOOL    smtp_verify_helo(void);
-extern int     smtp_write_command(smtp_outblock *, BOOL, const char *, ...) PRINTF_FUNCTION(3,4);
+extern int     smtp_write_command(smtp_outblock *, int, const char *, ...) PRINTF_FUNCTION(3,4);
 #ifdef WITH_CONTENT_SCAN
 extern int     spam(const uschar **);
-extern FILE   *spool_mbox(unsigned long *, const uschar *);
+extern FILE   *spool_mbox(unsigned long *, const uschar *, uschar **);
 #endif
 extern BOOL    spool_move_message(uschar *, uschar *, uschar *, uschar *);
 extern uschar *spool_dname(const uschar *, uschar *);
@@ -430,12 +437,12 @@ extern int     stdin_getc(unsigned);
 extern int     stdin_feof(void);
 extern int     stdin_ferror(void);
 extern int     stdin_ungetc(int);
-extern uschar *string_append(uschar *, int *, int *, int, ...);
-extern uschar *string_append_listele(uschar *, uschar, const uschar *);
-extern uschar *string_append_listele_n(uschar *, uschar, const uschar *, unsigned);
+extern uschar *string_append(uschar *, int *, int *, int, ...) WARN_UNUSED_RESULT;
+extern uschar *string_append_listele(uschar *, int *, int *, uschar, const uschar *) WARN_UNUSED_RESULT;
+extern uschar *string_append_listele_n(uschar *, int *, int *, uschar, const uschar *, unsigned) WARN_UNUSED_RESULT;
 extern uschar *string_base62(unsigned long int);
-extern uschar *string_cat(uschar *, int *, int *, const uschar *);
-extern uschar *string_catn(uschar *, int *, int *, const uschar *, int);
+extern uschar *string_cat(uschar *, int *, int *, const uschar *) WARN_UNUSED_RESULT;
+extern uschar *string_catn(uschar *, int *, int *, const uschar *, int) WARN_UNUSED_RESULT;
 extern int     string_compare_by_pointer(const void *, const void *);
 extern uschar *string_copy_dnsdomain(uschar *);
 extern uschar *string_copy_malloc(const uschar *);
@@ -453,6 +460,7 @@ extern uschar *string_nextinlist(const uschar **, int *, uschar *, int);
 extern uschar *string_open_failed(int, const char *, ...) PRINTF_FUNCTION(2,3);
 extern const uschar *string_printing2(const uschar *, BOOL);
 extern uschar *string_split_message(uschar *);
+extern uschar *string_timesince(struct timeval *);
 extern uschar *string_unprinting(uschar *);
 #ifdef SUPPORT_I18N
 extern uschar *string_address_utf8_to_alabel(const uschar *, uschar **);
@@ -466,23 +474,27 @@ extern int     strcmpic(const uschar *, const uschar *);
 extern int     strncmpic(const uschar *, const uschar *, int);
 extern uschar *strstric(uschar *, uschar *, BOOL);
 
+extern void    timesince(struct timeval * diff, struct timeval * then);
+extern void    tls_modify_variables(tls_support *);
 extern uschar *tod_stamp(int);
 
-extern void    tls_modify_variables(tls_support *);
 extern BOOL    transport_check_waiting(const uschar *, const uschar *, int, uschar *,
                  BOOL *, oicf, void*);
 extern void    transport_init(void);
+extern void    transport_do_pass_socket(const uschar *, const uschar *,
+                const uschar *, uschar *, int);
 extern BOOL    transport_pass_socket(const uschar *, const uschar *, const uschar *, uschar *,
                  int);
 extern uschar *transport_rcpt_address(address_item *, BOOL);
 extern BOOL    transport_set_up_command(const uschar ***, uschar *,
                 BOOL, int, address_item *, uschar *, uschar **);
 extern void    transport_update_waiting(host_item *, uschar *);
-extern BOOL    transport_write_block(int, uschar *, int);
+extern BOOL    transport_write_block(transport_ctx *, uschar *, int, BOOL);
+extern void    transport_write_reset(int);
 extern BOOL    transport_write_string(int, const char *, ...);
-extern BOOL    transport_headers_send(int, transport_ctx *,
-                 BOOL (*)(int, transport_ctx *, uschar *, int));
-extern BOOL    transport_write_message(int, transport_ctx *, int);
+extern BOOL    transport_headers_send(transport_ctx *,
+                 BOOL (*)(transport_ctx *, uschar *, int));
+extern BOOL    transport_write_message(transport_ctx *, int);
 extern void    tree_add_duplicate(uschar *, address_item *);
 extern void    tree_add_nonrecipient(uschar *);
 extern void    tree_add_unusable(host_item *);
@@ -516,6 +528,7 @@ extern BOOL    verify_sender(int *, uschar **);
 extern BOOL    verify_sender_preliminary(int *, uschar **);
 extern void    version_init(void);
 
+extern BOOL    write_chunk(transport_ctx *, uschar *, int);
 extern ssize_t write_to_fd_buf(int, const uschar *, size_t);
 
 /* vi: aw
index f3e4bad96bb5b3c0c01e26b799a9aefd83e476d4..57041fc4e2b05d217832459dfe1475d83650134f 100644 (file)
@@ -101,38 +101,38 @@ cluttered in several places (e.g. during logging) if we can always refer to
 them. Also, the tls_ variables are now always visible. */
 
 tls_support tls_in = {
- -1,   /* tls_active */
- 0,    /* tls_bits */
- FALSE,/* tls_certificate_verified */
+ .active =             -1,
+ .bits =               0,
+ .certificate_verified = FALSE,
 #ifdef EXPERIMENTAL_DANE
- FALSE,/* dane_verified */
- 0,    /* tlsa_usage */
+ .dane_verified =      FALSE,
+ .tlsa_usage =         0,
 #endif
- NULL, /* tls_cipher */
- FALSE,/* tls_on_connect */
- NULL, /* tls_on_connect_ports */
- NULL, /* tls_ourcert */
- NULL, /* tls_peercert */
- NULL, /* tls_peerdn */
- NULL, /* tls_sni */
- 0     /* tls_ocsp */
+ .cipher =             NULL,
+ .on_connect =         FALSE,
+ .on_connect_ports =   NULL,
+ .ourcert =            NULL,
+ .peercert =           NULL,
+ .peerdn =             NULL,
+ .sni =                        NULL,
+ .ocsp =               OCSP_NOT_REQ
 };
 tls_support tls_out = {
- -1,   /* tls_active */
- 0,    /* tls_bits */
- FALSE,/* tls_certificate_verified */
+ .active =             -1,
+ .bits =               0,
+ .certificate_verified = FALSE,
 #ifdef EXPERIMENTAL_DANE
- FALSE,/* dane_verified */
- 0,    /* tlsa_usage */
+ .dane_verified =      FALSE,
+ .tlsa_usage =         0,
 #endif
- NULL, /* tls_cipher */
- FALSE,/* tls_on_connect */
- NULL, /* tls_on_connect_ports */
- NULL, /* tls_ourcert */
- NULL, /* tls_peercert */
- NULL, /* tls_peerdn */
- NULL, /* tls_sni */
- 0     /* tls_ocsp */
+ .cipher =             NULL,
+ .on_connect =         FALSE,
+ .on_connect_ports =   NULL,
+ .ourcert =            NULL,
+ .peercert =           NULL,
+ .peerdn =             NULL,
+ .sni =                        NULL,
+ .ocsp =               OCSP_NOT_REQ
 };
 
 uschar *dsn_envid              = NULL;
@@ -182,10 +182,12 @@ const pcre *regex_UTF8         = NULL;
 incoming TCP/IP. The defaults use stdin. We never need these for any
 stand-alone tests. */
 
-#ifndef STAND_ALONE
+#if !defined(STAND_ALONE) && !defined(MACRO_PREDEF)
 int (*lwr_receive_getc)(unsigned) = stdin_getc;
+uschar * (*lwr_receive_getbuf)(unsigned *) = NULL;
 int (*lwr_receive_ungetc)(int) = stdin_ungetc;
 int (*receive_getc)(unsigned)  = stdin_getc;
+uschar * (*receive_getbuf)(unsigned *)  = NULL;
 void (*receive_get_cache)(void)= NULL;
 int (*receive_ungetc)(int)     = stdin_ungetc;
 int (*receive_feof)(void)      = stdin_feof;
@@ -326,78 +328,82 @@ uschar *add_environment        = NULL;
 address_item  *addr_duplicate  = NULL;
 
 address_item address_defaults = {
-  NULL,                 /* next */
-  NULL,                 /* parent */
-  NULL,                 /* first */
-  NULL,                 /* dupof */
-  NULL,                 /* start_router */
-  NULL,                 /* router */
-  NULL,                 /* transport */
-  NULL,                 /* host_list */
-  NULL,                 /* host_used */
-  NULL,                 /* fallback_hosts */
-  NULL,                 /* reply */
-  NULL,                 /* retries */
-  NULL,                 /* address */
-  NULL,                 /* unique */
-  NULL,                 /* cc_local_part */
-  NULL,                 /* lc_local_part */
-  NULL,                 /* local_part */
-  NULL,                 /* prefix */
-  NULL,                 /* suffix */
-  NULL,                 /* domain */
-  NULL,                 /* address_retry_key */
-  NULL,                 /* domain_retry_key */
-  NULL,                 /* current_dir */
-  NULL,                 /* home_dir */
-  NULL,                 /* message */
-  NULL,                 /* user_message */
-  NULL,                 /* onetime_parent */
-  NULL,                 /* pipe_expandn */
-  NULL,                 /* return_filename */
-  NULL,                 /* self_hostname */
-  NULL,                 /* shadow_message */
+  .next =              NULL,
+  .parent =            NULL,
+  .first =             NULL,
+  .dupof =             NULL,
+  .start_router =      NULL,
+  .router =            NULL,
+  .transport =         NULL,
+  .host_list =         NULL,
+  .host_used =         NULL,
+  .fallback_hosts =    NULL,
+  .reply =             NULL,
+  .retries =           NULL,
+  .address =           NULL,
+  .unique =            NULL,
+  .cc_local_part =     NULL,
+  .lc_local_part =     NULL,
+  .local_part =                NULL,
+  .prefix =            NULL,
+  .suffix =            NULL,
+  .domain =            NULL,
+  .address_retry_key = NULL,
+  .domain_retry_key =  NULL,
+  .current_dir =       NULL,
+  .home_dir =          NULL,
+  .message =           NULL,
+  .user_message =      NULL,
+  .onetime_parent =    NULL,
+  .pipe_expandn =      NULL,
+  .return_filename =   NULL,
+  .self_hostname =     NULL,
+  .shadow_message =    NULL,
 #ifdef SUPPORT_TLS
-  NULL,                 /* cipher */
-  NULL,                        /* ourcert */
-  NULL,                        /* peercert */
-  NULL,                 /* peerdn */
-  OCSP_NOT_REQ,         /* ocsp */
+  .cipher =            NULL,
+  .ourcert =           NULL,
+  .peercert =          NULL,
+  .peerdn =            NULL,
+  .ocsp =              OCSP_NOT_REQ,
 #endif
 #ifdef EXPERIMENTAL_DSN_INFO
-  NULL,                        /* smtp_greeting */
-  NULL,                        /* helo_response */
+  .smtp_greeting =     NULL,
+  .helo_response =     NULL,
 #endif
-  NULL,                        /* authenticator */
-  NULL,                        /* auth_id */
-  NULL,                        /* auth_sndr */
-  NULL,                 /* dsn_orcpt */
-  0,                    /* dsn_flags */
-  0,                    /* dsn_aware */
-  (uid_t)(-1),          /* uid */
-  (gid_t)(-1),          /* gid */
-  0,                    /* flags */
-  { 0 },                /* domain_cache - any larger array should be zeroed */
-  { 0 },                /* localpart_cache - ditto */
-  -1,                   /* mode */
-  0,                    /* more_errno */
-  ERRNO_UNKNOWNERROR,   /* basic_errno */
-  0,                    /* child_count */
-  -1,                   /* return_file */
-  SPECIAL_NONE,         /* special_action */
-  DEFER,                /* transport_return */
-  {                     /* fields that are propagated to children */
-    NULL,               /* address_data */
-    NULL,               /* domain_data */
-    NULL,               /* localpart_data */
-    NULL,               /* errors_address */
-    NULL,               /* extra_headers */
-    NULL,               /* remove_headers */
+  .authenticator =     NULL,
+  .auth_id =           NULL,
+  .auth_sndr =         NULL,
+  .dsn_orcpt =         NULL,
+  .dsn_flags =         0,
+  .dsn_aware =         0,
+  .uid =               (uid_t)(-1),
+  .gid =               (gid_t)(-1),
+  .flags =             { 0 },
+  .domain_cache =      { 0 },                /* domain_cache - any larger array should be zeroed */
+  .localpart_cache =   { 0 },                /* localpart_cache - ditto */
+  .mode =              -1,
+  .more_errno =                0,
+  .delivery_usec =     0,
+  .basic_errno =       ERRNO_UNKNOWNERROR,
+  .child_count =       0,
+  .return_file =       -1,
+  .special_action =    SPECIAL_NONE,
+  .transport_return =  DEFER,
+  .prop = {                                    /* fields that are propagated to children */
+    .address_data =    NULL,
+    .domain_data =     NULL,
+    .localpart_data =  NULL,
+    .errors_address =  NULL,
+    .extra_headers =   NULL,
+    .remove_headers =  NULL,
 #ifdef EXPERIMENTAL_SRS
-    NULL,               /* srs_sender */
+    .srs_sender =      NULL,
 #endif
+    .ignore_error =    FALSE,
 #ifdef SUPPORT_I18N
-    FALSE,             /* utf8 */
+    .utf8_msg =                FALSE,
+    .utf8_downcvt =    FALSE,
+    .utf8_downcvt_maybe = FALSE
 #endif
   }
 };
@@ -422,22 +428,22 @@ BOOL    authentication_failed  = FALSE;
 auth_instance  *auths          = NULL;
 uschar *auth_advertise_hosts   = US"*";
 auth_instance auth_defaults    = {
-    NULL,                      /* chain pointer */
-    NULL,                      /* name */
-    NULL,                      /* info */
-    NULL,                      /* private options block pointer */
-    NULL,                      /* driver_name */
-    NULL,                      /* advertise_condition */
-    NULL,                      /* client_condition */
-    NULL,                      /* public_name */
-    NULL,                      /* set_id */
-    NULL,                      /* set_client_id */
-    NULL,                      /* server_mail_auth_condition */
-    NULL,                      /* server_debug_string */
-    NULL,                      /* server_condition */
-    FALSE,                     /* client */
-    FALSE,                     /* server */
-    FALSE                      /* advertised */
+    .next =            NULL,
+    .name =            NULL,
+    .info =            NULL,
+    .options_block =   NULL,
+    .driver_name =     NULL,
+    .advertise_condition = NULL,
+    .client_condition =        NULL,
+    .public_name =     NULL,
+    .set_id =          NULL,
+    .set_client_id =   NULL,
+    .mail_auth_condition = NULL,
+    .server_debug_string = NULL,
+    .server_condition =        NULL,
+    .client =          FALSE,
+    .server =          FALSE,
+    .advertised =      FALSE
 };
 
 uschar *auth_defer_msg         = US"reason not recorded";
@@ -470,6 +476,7 @@ int     bmi_deliver            = 1;
 int     bmi_run                = 0;
 uschar *bmi_verdicts           = NULL;
 #endif
+int     bsmtp_transaction_linecount = 0;
 int     body_8bitmime          = 0;
 int     body_linecount         = 0;
 int     body_zerocount         = 0;
@@ -481,7 +488,7 @@ int     bounce_return_linesize_limit = 998;
 BOOL    bounce_return_message  = TRUE;
 int     bounce_return_size_limit = 100*1024;
 uschar *bounce_sender_authentication = NULL;
-int     bsmtp_transaction_linecount = 0;
+uschar *builtin_macros_create_trigger = NULL;
 
 uschar *callout_address        = NULL;
 int     callout_cache_domain_positive_expire = 7*24*60*60;
@@ -508,6 +515,7 @@ uschar *client_authenticated_id = NULL;
 uschar *client_authenticated_sender = NULL;
 int     clmacro_count          = 0;
 uschar *clmacros[MAX_CLMACROS];
+BOOL    commandline_checks_require_admin = FALSE;
 BOOL    config_changed         = FALSE;
 FILE   *config_file            = NULL;
 const uschar *config_filename  = NULL;
@@ -529,19 +537,21 @@ uid_t   config_uid             = 0;
 #endif
 
 int     connection_max_messages= -1;
+uschar *continue_proxy_cipher  = NULL;
 uschar *continue_hostname      = NULL;
 uschar *continue_host_address  = NULL;
 BOOL    continue_more          = FALSE;
 int     continue_sequence      = 1;
-BOOL    continue_proxy        = FALSE;
 uschar *continue_transport     = NULL;
 
 uschar *csa_status             = NULL;
 cut_t   cutthrough = {
-  FALSE,                               /* delivery: when to attempt */
-  FALSE,                               /* on defer: spool locally */
-  -1,                                  /* fd: open connection */
-  0,                                   /* nrcpt: number of addresses */
+  .callout_hold_only = FALSE,                          /* verify-only: normal delivery */
+  .delivery =          FALSE,                          /* when to attempt */
+  .defer_pass =                FALSE,                          /* on defer: spool locally */
+  .is_tls =            FALSE,                          /* not a TLS conn yet */
+  .fd =                        -1,                             /* open connection */
+  .nrcpt =             0,                              /* number of addresses */
 };
 
 BOOL    daemon_listen          = FALSE;
@@ -757,19 +767,20 @@ int     header_maxsize         = HEADER_MAXSIZE;
 int     header_line_maxsize    = 0;
 
 header_name header_names[] = {
-  { US"bcc",            3, TRUE,  htype_bcc },
-  { US"cc",             2, TRUE,  htype_cc },
-  { US"date",           4, TRUE,  htype_date },
-  { US"delivery-date", 13, FALSE, htype_delivery_date },
-  { US"envelope-to",   11, FALSE, htype_envelope_to },
-  { US"from",           4, TRUE,  htype_from },
-  { US"message-id",    10, TRUE,  htype_id },
-  { US"received",       8, FALSE, htype_received },
-  { US"reply-to",       8, FALSE, htype_reply_to },
-  { US"return-path",   11, FALSE, htype_return_path },
-  { US"sender",         6, TRUE,  htype_sender },
-  { US"subject",        7, FALSE, htype_subject },
-  { US"to",             2, TRUE,  htype_to }
+  /* name              len     allow_resent    htype */
+  { US"bcc",            3,     TRUE,           htype_bcc },
+  { US"cc",             2,     TRUE,           htype_cc },
+  { US"date",           4,     TRUE,           htype_date },
+  { US"delivery-date", 13,     FALSE,          htype_delivery_date },
+  { US"envelope-to",   11,     FALSE,          htype_envelope_to },
+  { US"from",           4,     TRUE,           htype_from },
+  { US"message-id",    10,     TRUE,           htype_id },
+  { US"received",       8,     FALSE,          htype_received },
+  { US"reply-to",       8,     FALSE,          htype_reply_to },
+  { US"return-path",   11,     FALSE,          htype_return_path },
+  { US"sender",         6,     TRUE,           htype_sender },
+  { US"subject",        7,     FALSE,          htype_subject },
+  { US"to",             2,     TRUE,           htype_to }
 };
 
 int header_names_size          = sizeof(header_names)/sizeof(header_name);
@@ -887,6 +898,7 @@ bit_table log_options[]        = { /* must be in alphabetical order */
   BIT_TABLE(L, incoming_interface),
   BIT_TABLE(L, incoming_port),
   BIT_TABLE(L, lost_incoming_connection),
+  BIT_TABLE(L, millisec),
   BIT_TABLE(L, outgoing_interface),
   BIT_TABLE(L, outgoing_port),
   BIT_TABLE(L, pid),
@@ -933,9 +945,6 @@ uschar *lookup_dnssec_authenticated = NULL;
 int     lookup_open_max        = 25;
 uschar *lookup_value           = NULL;
 
-macro_item  *macros            = NULL;
-macro_item  *mlast             = NULL;
-BOOL    macros_builtin_created = FALSE;
 uschar *mailstore_basename     = NULL;
 #ifdef WITH_CONTENT_SCAN
 uschar *malware_name           = NULL;  /* Virus Name */
@@ -1103,7 +1112,7 @@ uschar *received_header_text   = US
 
 int     received_headers_max   = 30;
 uschar *received_protocol      = NULL;
-int     received_time          = 0;
+struct timeval received_time   = { 0, 0 };
 uschar *recipient_data         = NULL;
 uschar *recipient_unqualified_hosts = NULL;
 uschar *recipient_verify_failure = NULL;
@@ -1146,83 +1155,83 @@ uid_t   root_uid               = ROOT_UID;
 
 router_instance  *routers  = NULL;
 router_instance  router_defaults = {
-    NULL,                      /* chain pointer */
-    NULL,                      /* name */
-    NULL,                      /* info */
-    NULL,                      /* private options block pointer */
-    NULL,                      /* driver name */
+    .next =                    NULL,
+    .name =                    NULL,
+    .info =                    NULL,
+    .options_block =           NULL,
+    .driver_name =             NULL,
 
-    NULL,                      /* address_data */
+    .address_data =            NULL,
 #ifdef EXPERIMENTAL_BRIGHTMAIL
-    NULL,                      /* bmi_rule */
+    .bmi_rule =                        NULL,
 #endif
-    NULL,                      /* cannot_route_message */
-    NULL,                      /* condition */
-    NULL,                      /* current_directory */
-    NULL,                      /* debug_string */
-    NULL,                      /* domains */
-    NULL,                      /* errors_to */
-    NULL,                      /* expand_gid */
-    NULL,                      /* expand_uid */
-    NULL,                      /* expand_more */
-    NULL,                      /* expand_unseen */
-    NULL,                      /* extra_headers */
-    NULL,                      /* fallback_hosts */
-    NULL,                      /* home_directory */
-    NULL,                      /* ignore_target_hosts */
-    NULL,                      /* local_parts */
-    NULL,                      /* pass_router_name */
-    NULL,                      /* prefix */
-    NULL,                      /* redirect_router_name */
-    NULL,                      /* remove_headers */
-    NULL,                      /* require_files */
-    NULL,                      /* router_home_directory */
-    US"freeze",                /* self */
-    NULL,                      /* senders */
-    NULL,                      /* suffix */
-    NULL,                      /* translate_ip_address */
-    NULL,                      /* transport_name */
-
-    TRUE,                      /* address_test */
+    .cannot_route_message =    NULL,
+    .condition =               NULL,
+    .current_directory =       NULL,
+    .debug_string =            NULL,
+    .domains =                 NULL,
+    .errors_to =               NULL,
+    .expand_gid =              NULL,
+    .expand_uid =              NULL,
+    .expand_more =             NULL,
+    .expand_unseen =           NULL,
+    .extra_headers =           NULL,
+    .fallback_hosts =          NULL,
+    .home_directory =          NULL,
+    .ignore_target_hosts =     NULL,
+    .local_parts =             NULL,
+    .pass_router_name =                NULL,
+    .prefix =                  NULL,
+    .redirect_router_name =    NULL,
+    .remove_headers =          NULL,
+    .require_files =           NULL,
+    .router_home_directory =   NULL,
+    .self =                    US"freeze",
+    .senders =                 NULL,
+    .suffix =                  NULL,
+    .translate_ip_address =    NULL,
+    .transport_name =          NULL,
+
+    .address_test =            TRUE,
 #ifdef EXPERIMENTAL_BRIGHTMAIL
-    FALSE,                     /* bmi_deliver_alternate */
-    FALSE,                     /* bmi_deliver_default */
-    FALSE,                     /* bmi_dont_deliver */
+    .bmi_deliver_alternate =   FALSE,
+    .bmi_deliver_default =     FALSE,
+    .bmi_dont_deliver =                FALSE,
 #endif
-    TRUE,                      /* expn */
-    FALSE,                     /* caseful_local_part */
-    FALSE,                     /* check_local_user */
-    FALSE,                     /* disable_logging */
-    FALSE,                     /* fail_verify_recipient */
-    FALSE,                     /* fail_verify_sender */
-    FALSE,                     /* gid_set */
-    FALSE,                     /* initgroups */
-    TRUE_UNSET,                /* log_as_local */
-    TRUE,                      /* more */
-    FALSE,                     /* pass_on_timeout */
-    FALSE,                     /* prefix_optional */
-    TRUE,                      /* repeat_use */
-    TRUE_UNSET,                /* retry_use_local_part - fudge "unset" */
-    FALSE,                     /* same_domain_copy_routing */
-    FALSE,                     /* self_rewrite */
-    FALSE,                     /* suffix_optional */
-    FALSE,                     /* verify_only */
-    TRUE,                      /* verify_recipient */
-    TRUE,                      /* verify_sender */
-    FALSE,                     /* uid_set */
-    FALSE,                     /* unseen */
-    FALSE,                     /* dsn_lasthop */
-
-    self_freeze,               /* self_code */
-    (uid_t)(-1),               /* uid */
-    (gid_t)(-1),               /* gid */
-
-    NULL,                      /* fallback_hostlist */
-    NULL,                      /* transport instance */
-    NULL,                      /* pass_router */
-    NULL,                      /* redirect_router */
-
-    { NULL, NULL },            /* dnssec_domains {require,request} */
+    .expn =                    TRUE,
+    .caseful_local_part =      FALSE,
+    .check_local_user =                FALSE,
+    .disable_logging =         FALSE,
+    .fail_verify_recipient =   FALSE,
+    .fail_verify_sender =      FALSE,
+    .gid_set =                 FALSE,
+    .initgroups =              FALSE,
+    .log_as_local =            TRUE_UNSET,
+    .more =                    TRUE,
+    .pass_on_timeout =         FALSE,
+    .prefix_optional =         FALSE,
+    .repeat_use =              TRUE,
+    .retry_use_local_part =    TRUE_UNSET,
+    .same_domain_copy_routing =        FALSE,
+    .self_rewrite =            FALSE,
+    .suffix_optional =         FALSE,
+    .verify_only =             FALSE,
+    .verify_recipient =                TRUE,
+    .verify_sender =           TRUE,
+    .uid_set =                 FALSE,
+    .unseen =                  FALSE,
+    .dsn_lasthop =             FALSE,
+
+    .self_code =               self_freeze,
+    .uid =                     (uid_t)(-1),
+    .gid =                     (gid_t)(-1),
+
+    .fallback_hostlist =       NULL,
+    .transport =               NULL,
+    .pass_router =             NULL,
+    .redirect_router =         NULL,
+
+    .dnssec =                  { NULL, NULL },            /* dnssec_domains {require,request} */
 };
 
 uschar *router_name            = NULL;
@@ -1303,7 +1312,7 @@ BOOL    smtp_check_spool_space = TRUE;
 int     smtp_ch_index          = 0;
 uschar *smtp_cmd_argument      = NULL;
 uschar *smtp_cmd_buffer        = NULL;
-time_t  smtp_connection_start  = 0;
+struct timeval smtp_connection_start  = {0,0};
 uschar  smtp_connection_had[SMTP_HBUFF_SIZE];
 int     smtp_connect_backlog   = 20;
 double  smtp_delay_mail        = 0.0;
@@ -1360,6 +1369,8 @@ uschar *spf_smtp_comment       = NULL;
 BOOL    split_spool_directory  = FALSE;
 uschar *spool_directory        = US SPOOL_DIRECTORY
                            "\0<--------------Space to patch spool_directory->";
+BOOL    spool_file_wireformat  = FALSE;
+BOOL    spool_wireformat       = FALSE;
 #ifdef EXPERIMENTAL_SRS
 uschar *srs_config             = NULL;
 uschar *srs_db_address         = NULL;
@@ -1406,7 +1417,12 @@ BOOL    system_filter_uid_set  = FALSE;
 BOOL    system_filtering       = FALSE;
 
 BOOL    tcp_fastopen_ok        = FALSE;
+blob   tcp_fastopen_nodata    = { .data = NULL, .len = 0 };
+BOOL    tcp_in_fastopen        = FALSE;
+BOOL    tcp_in_fastopen_logged = FALSE;
 BOOL    tcp_nodelay            = TRUE;
+BOOL    tcp_out_fastopen       = FALSE;
+BOOL    tcp_out_fastopen_logged= FALSE;
 #ifdef USE_TCP_WRAPPERS
 uschar *tcp_wrappers_daemon_name = US TCP_WRAPPERS_DAEMON_NAME;
 #endif
@@ -1418,59 +1434,59 @@ BOOL    timestamps_utc         = FALSE;
 transport_instance  *transports = NULL;
 
 transport_instance  transport_defaults = {
-    NULL,                     /* chain pointer */
-    NULL,                     /* name */
-    NULL,                     /* info */
-    NULL,                     /* private options block pointer */
-    NULL,                     /* driver name */
-    NULL,                     /* setup entry point */
-    1,                        /* batch_max */
-    NULL,                     /* batch_id */
-    NULL,                     /* home_dir */
-    NULL,                     /* current_dir */
-    NULL,                     /* expand-multi-domain */
-    TRUE,                     /* multi-domain */
-    FALSE,                    /* overrides_hosts */
-    100,                      /* max_addresses */
-    500,                      /* connection_max_messages */
-    FALSE,                    /* deliver_as_creator */
-    FALSE,                    /* disable_logging */
-    FALSE,                    /* initgroups */
-    FALSE,                    /* uid_set */
-    FALSE,                    /* gid_set */
-    (uid_t)(-1),              /* uid */
-    (gid_t)(-1),              /* gid */
-    NULL,                     /* expand_uid */
-    NULL,                     /* expand_gid */
-    NULL,                     /* warn_message */
-    NULL,                     /* shadow */
-    NULL,                     /* shadow_condition */
-    NULL,                     /* filter_command */
-    NULL,                     /* add_headers */
-    NULL,                     /* remove_headers */
-    NULL,                     /* return_path */
-    NULL,                     /* debug_string */
-    NULL,                     /* max_parallel */
-    NULL,                     /* message_size_limit */
-    NULL,                     /* headers_rewrite */
-    NULL,                     /* rewrite_rules */
-    0,                        /* rewrite_existflags */
-    300,                      /* filter_timeout */
-    FALSE,                    /* body_only */
-    FALSE,                    /* delivery_date_add */
-    FALSE,                    /* envelope_to_add */
-    FALSE,                    /* headers_only */
-    FALSE,                    /* rcpt_include_affixes */
-    FALSE,                    /* return_path_add */
-    FALSE,                    /* return_output */
-    FALSE,                    /* return_fail_output */
-    FALSE,                    /* log_output */
-    FALSE,                    /* log_fail_output */
-    FALSE,                    /* log_defer_output */
-    TRUE_UNSET                /* retry_use_local_part: BOOL, but set neither
-                                 1 nor 0 so can detect unset */
+    .next =                    NULL,
+    .name =                    NULL,
+    .info =                    NULL,
+    .options_block =           NULL,
+    .driver_name =             NULL,
+    .setup =                   NULL,
+    .batch_max =               1,
+    .batch_id =                        NULL,
+    .home_dir =                        NULL,
+    .current_dir =             NULL,
+    .expand_multi_domain =     NULL,
+    .multi_domain =            TRUE,
+    .overrides_hosts =         FALSE,
+    .max_addresses =           100,
+    .connection_max_messages = 500,
+    .deliver_as_creator =      FALSE,
+    .disable_logging =         FALSE,
+    .initgroups =              FALSE,
+    .uid_set =                 FALSE,
+    .gid_set =                 FALSE,
+    .uid =                     (uid_t)(-1),
+    .gid =                     (gid_t)(-1),
+    .expand_uid =              NULL,
+    .expand_gid =              NULL,
+    .warn_message =            NULL,
+    .shadow =                  NULL,
+    .shadow_condition =                NULL,
+    .filter_command =          NULL,
+    .add_headers =             NULL,
+    .remove_headers =          NULL,
+    .return_path =             NULL,
+    .debug_string =            NULL,
+    .max_parallel =            NULL,
+    .message_size_limit =      NULL,
+    .headers_rewrite =         NULL,
+    .rewrite_rules =           NULL,
+    .rewrite_existflags =      0,
+    .filter_timeout =          300,
+    .body_only =               FALSE,
+    .delivery_date_add =       FALSE,
+    .envelope_to_add =         FALSE,
+    .headers_only =            FALSE,
+    .rcpt_include_affixes =    FALSE,
+    .return_path_add =         FALSE,
+    .return_output =           FALSE,
+    .return_fail_output =      FALSE,
+    .log_output =              FALSE,
+    .log_fail_output =         FALSE,
+    .log_defer_output =                FALSE,
+    .retry_use_local_part =    TRUE_UNSET,     /* retry_use_local_part: BOOL, but set neither
+                                                1 nor 0 so can detect unset */
 #ifndef DISABLE_EVENT
-   ,NULL                     /* event_action */
+   .event_action =             NULL
 #endif
 };
 
index 750a960ebe2dbc761c85932fe2ac685986181bed..2957587b0c2b299c5c1878d2395530024c6dc801 100644 (file)
@@ -137,8 +137,10 @@ extern uschar  *dsn_advertise_hosts;   /* host for which TLS is advertised */
 incoming TCP/IP. */
 
 extern int (*lwr_receive_getc)(unsigned);
+extern uschar * (*lwr_receive_getbuf)(unsigned *);
 extern int (*lwr_receive_ungetc)(int);
 extern int (*receive_getc)(unsigned);
+extern uschar * (*receive_getbuf)(unsigned *);
 extern void (*receive_get_cache)(void);
 extern int (*receive_ungetc)(int);
 extern int (*receive_feof)(void);
@@ -246,6 +248,7 @@ extern int     bmi_deliver;            /* Flag that determines if the message sh
 extern int     bmi_run;                /* Flag that determines if message should be run through Brightmail server */
 extern uschar *bmi_verdicts;           /* BASE64-encoded verdicts with recipient lists */
 #endif
+extern int     bsmtp_transaction_linecount; /* Start of last transaction */
 extern int     body_8bitmime;          /* sender declared BODY= ; 7=7BIT, 8=8BITMIME */
 extern uschar *bounce_message_file;    /* Template file */
 extern uschar *bounce_message_text;    /* One-liner */
@@ -255,7 +258,7 @@ extern int     bounce_return_linesize_limit; /* Max line length in return */
 extern BOOL    bounce_return_message;  /* Include message in bounce */
 extern int     bounce_return_size_limit; /* Max amount to return */
 extern uschar *bounce_sender_authentication; /* AUTH address for bounces */
-extern int     bsmtp_transaction_linecount; /* Start of last transaction */
+extern uschar *builtin_macros_create_trigger; /* config file line causing lazy-create */
 
 extern uschar *callout_address;         /* Address used for a malware/spamd/verify etc. callout */
 extern int     callout_cache_domain_positive_expire; /* Time for positive domain callout cache records to expire */
@@ -279,6 +282,7 @@ extern uschar *client_authenticated_id;     /* "login" name used for SMTP AUTH *
 extern uschar *client_authenticated_sender; /* AUTH option to SMTP MAIL FROM (not yet used) */
 extern int     clmacro_count;          /* Number of command line macros */
 extern uschar *clmacros[];             /* Copy of them, for re-exec */
+extern BOOL    commandline_checks_require_admin; /* belt and braces for insecure setups */
 extern int     connection_max_messages;/* Max down one SMTP connection */
 extern BOOL    config_changed;         /* True if -C used */
 extern FILE   *config_file;            /* Configuration file */
@@ -289,21 +293,27 @@ extern uschar *config_main_filelist;   /* List of possible config files */
 extern uschar *config_main_filename;   /* File name actually used */
 extern uschar *config_main_directory;  /* Directory where the main config file was found */
 extern uid_t   config_uid;             /* Additional owner */
+extern uschar *continue_proxy_cipher;  /* TLS cipher for proxied continued delivery */
 extern uschar *continue_hostname;      /* Host for continued delivery */
 extern uschar *continue_host_address;  /* IP address for ditto */
 extern BOOL    continue_more;          /* Flag more addresses waiting */
 extern int     continue_sequence;      /* Sequence num for continued delivery */
-extern BOOL    continue_proxy;        /* Continued delivery is proxied for TLS */
 extern uschar *continue_transport;     /* Transport for continued delivery */
 
 extern uschar *csa_status;             /* Client SMTP Authorization result */
 
 typedef struct {
+  unsigned     callout_hold_only:1;    /* Conn is only for verify callout */
   unsigned     delivery:1;             /* When to attempt */
   unsigned     defer_pass:1;           /* Pass 4xx to caller rather than spooling */
+  unsigned     is_tls:1;              /* Conn has TLS active */
   int          fd;                     /* Open connection */
   int          nrcpt;                  /* Count of addresses */
+  uschar *     transport;             /* Name of transport */
   uschar *     interface;              /* (address of) */
+  uschar *     snd_ip;                /* sending_ip_address */
+  int         snd_port;               /* sending_port */
+  unsigned     peer_options;          /* smtp_peer_options */
   host_item    host;                   /* Host used */
   address_item addr;                   /* (Chain of) addresses */
 } cut_t;
@@ -555,7 +565,6 @@ extern uschar *lookup_value;           /* Value looked up from file */
 
 extern macro_item *macros;             /* Configuration macros */
 extern macro_item *mlast;              /* Last item in macro list */
-extern BOOL    macros_builtin_created; /* Flag for lazy-create */
 extern uschar *mailstore_basename;     /* For mailstore deliveries */
 #ifdef WITH_CONTENT_SCAN
 extern uschar *malware_name;           /* Name of virus or malware ("W32/Klez-H") */
@@ -712,7 +721,7 @@ extern int     received_count;         /* Count of Received: headers */
 extern uschar *received_for;           /* For "for" field */
 extern uschar *received_header_text;   /* Definition of Received: header */
 extern int     received_headers_max;   /* Max count of Received: headers */
-extern int     received_time;          /* Time the message was received */
+extern struct timeval received_time;   /* Time the message was received */
 extern uschar *recipient_data;         /* lookup data for recipients */
 extern uschar *recipient_unqualified_hosts; /* Permitted unqualified recipients */
 extern uschar *recipient_verify_failure; /* What went wrong */
@@ -811,7 +820,7 @@ extern BOOL    smtp_check_spool_space; /* TRUE to check SMTP SIZE value */
 extern int     smtp_ch_index;          /* Index in smtp_connection_had */
 extern uschar *smtp_cmd_argument;      /* For all SMTP commands */
 extern uschar *smtp_cmd_buffer;        /* SMTP command buffer */
-extern time_t  smtp_connection_start;  /* Start time of SMTP connection */
+extern struct timeval smtp_connection_start; /* Start time of SMTP connection */
 extern uschar  smtp_connection_had[];  /* Recent SMTP commands */
 extern int     smtp_connect_backlog;   /* Max backlog permitted */
 extern double  smtp_delay_mail;        /* Current MAIL delay */
@@ -865,6 +874,8 @@ extern uschar *spf_smtp_comment;       /* spf comment to include in SMTP reply *
 #endif
 extern BOOL    split_spool_directory;  /* TRUE to use multiple subdirs */
 extern uschar *spool_directory;        /* Name of spool directory */
+extern BOOL    spool_file_wireformat;  /* current -D file has CRLF rather than NL */
+extern BOOL    spool_wireformat;       /* can write wireformat -D files */
 #ifdef EXPERIMENTAL_SRS
 extern uschar *srs_config;             /* SRS config secret:max age:hash length:use timestamp:use hash */
 extern uschar *srs_db_address;         /* SRS db address */
@@ -911,7 +922,12 @@ extern BOOL    system_filter_uid_set;  /* TRUE if uid set */
 extern BOOL    system_filtering;       /* TRUE when running system filter */
 
 extern BOOL    tcp_fastopen_ok;               /* appears to be supported by kernel */
+extern blob    tcp_fastopen_nodata;    /* for zero-data TFO connect requests */
+extern BOOL    tcp_in_fastopen;               /* conn used fastopen */
+extern BOOL    tcp_in_fastopen_logged; /* one-time logging */
 extern BOOL    tcp_nodelay;            /* Controls TCP_NODELAY on daemon */
+extern BOOL    tcp_out_fastopen;       /* conn used fastopen */
+extern BOOL    tcp_out_fastopen_logged; /* one-time logging */
 #ifdef USE_TCP_WRAPPERS
 extern uschar *tcp_wrappers_daemon_name; /* tcpwrappers daemon lookup name */
 #endif
index 7590d55b7f16356ff91ad7eda23c7c07db841287..19ab1efd09b5782bbfa4fa57256d91ec59e6bfdc 100644 (file)
@@ -33,11 +33,14 @@ sha1;
 BOOL
 exim_sha_init(hctx * h, hashmethod m)
 {
+/*XXX extend for sha512 */
 switch (h->method = m)
   {
-  case HASH_SHA1:   h->hashlen = 20; SHA1_Init  (&h->u.sha1); break;
-  case HASH_SHA256: h->hashlen = 32; SHA256_Init(&h->u.sha2); break;
-  default:         h->hashlen = 0; return FALSE;
+  case HASH_SHA1:     h->hashlen = 20; SHA1_Init  (&h->u.sha1);     break;
+  case HASH_SHA2_256: h->hashlen = 32; SHA256_Init(&h->u.sha2_256); break;
+  case HASH_SHA2_384: h->hashlen = 48; SHA384_Init(&h->u.sha2_512); break;
+  case HASH_SHA2_512: h->hashlen = 64; SHA512_Init(&h->u.sha2_512); break;
+  default:           h->hashlen = 0; return FALSE;
   }
 return TRUE;
 }
@@ -48,10 +51,12 @@ exim_sha_update(hctx * h, const uschar * data, int len)
 {
 switch (h->method)
   {
-  case HASH_SHA1:   SHA1_Update  (&h->u.sha1, data, len); break;
-  case HASH_SHA256: SHA256_Update(&h->u.sha2, data, len); break;
+  case HASH_SHA1:     SHA1_Update  (&h->u.sha1,     data, len); break;
+  case HASH_SHA2_256: SHA256_Update(&h->u.sha2_256, data, len); break;
+  case HASH_SHA2_384: SHA384_Update(&h->u.sha2_512, data, len); break;
+  case HASH_SHA2_512: SHA512_Update(&h->u.sha2_512, data, len); break;
   /* should be blocked by init not handling these, but be explicit to
-   * guard against accidents later (and hush up clang -Wswitch) */
+  guard against accidents later (and hush up clang -Wswitch) */
   default: assert(0);
   }
 }
@@ -63,8 +68,10 @@ exim_sha_finish(hctx * h, blob * b)
 b->data = store_get(b->len = h->hashlen);
 switch (h->method)
   {
-  case HASH_SHA1:   SHA1_Final  (b->data, &h->u.sha1); break;
-  case HASH_SHA256: SHA256_Final(b->data, &h->u.sha2); break;
+  case HASH_SHA1:     SHA1_Final  (b->data, &h->u.sha1);     break;
+  case HASH_SHA2_256: SHA256_Final(b->data, &h->u.sha2_256); break;
+  case HASH_SHA2_384: SHA384_Final(b->data, &h->u.sha2_512); break;
+  case HASH_SHA2_512: SHA512_Final(b->data, &h->u.sha2_512); break;
   default: assert(0);
   }
 }
@@ -77,12 +84,17 @@ switch (h->method)
 BOOL
 exim_sha_init(hctx * h, hashmethod m)
 {
+/*XXX extend for sha512 */
 switch (h->method = m)
   {
-  case HASH_SHA1:     h->hashlen = 20; gnutls_hash_init(&h->sha, GNUTLS_DIG_SHA1); break;
-  case HASH_SHA256:   h->hashlen = 32; gnutls_hash_init(&h->sha, GNUTLS_DIG_SHA256); break;
+  case HASH_SHA1:     h->hashlen = 20; gnutls_hash_init(&h->sha, GNUTLS_DIG_SHA1);   break;
+  case HASH_SHA2_256: h->hashlen = 32; gnutls_hash_init(&h->sha, GNUTLS_DIG_SHA256); break;
+  case HASH_SHA2_384: h->hashlen = 48; gnutls_hash_init(&h->sha, GNUTLS_DIG_SHA384); break;
+  case HASH_SHA2_512: h->hashlen = 64; gnutls_hash_init(&h->sha, GNUTLS_DIG_SHA512); break;
 #ifdef EXIM_HAVE_SHA3
   case HASH_SHA3_256: h->hashlen = 32; gnutls_hash_init(&h->sha, GNUTLS_DIG_SHA3_256); break;
+  case HASH_SHA3_384: h->hashlen = 48; gnutls_hash_init(&h->sha, GNUTLS_DIG_SHA3_384); break;
+  case HASH_SHA3_512: h->hashlen = 64; gnutls_hash_init(&h->sha, GNUTLS_DIG_SHA3_512); break;
 #endif
   default: h->hashlen = 0; return FALSE;
   }
@@ -112,10 +124,16 @@ gnutls_hash_output(h->sha, b->data);
 BOOL
 exim_sha_init(hctx * h, hashmethod m)
 {
+/*XXX extend for sha512 */
 switch (h->method = m)
   {
-  case HASH_SHA1:   h->hashlen = 20; gcry_md_open(&h->sha, GCRY_MD_SHA1, 0); break;
-  case HASH_SHA256: h->hashlen = 32; gcry_md_open(&h->sha, GCRY_MD_SHA256, 0); break;
+  case HASH_SHA1:     h->hashlen = 20; gcry_md_open(&h->sha, GCRY_MD_SHA1, 0);   break;
+  case HASH_SHA2_256: h->hashlen = 32; gcry_md_open(&h->sha, GCRY_MD_SHA256, 0); break;
+  case HASH_SHA2_384: h->hashlen = 48; gcry_md_open(&h->sha, GCRY_MD_SHA384, 0); break;
+  case HASH_SHA2_512: h->hashlen = 64; gcry_md_open(&h->sha, GCRY_MD_SHA512, 0); break;
+  case HASH_SHA3_256: h->hashlen = 32; gcry_md_open(&h->sha, GCRY_MD_SHA3_256, 0); break;
+  case HASH_SHA3_384: h->hashlen = 48; gcry_md_open(&h->sha, GCRY_MD_SHA3_384, 0); break;
+  case HASH_SHA3_512: h->hashlen = 64; gcry_md_open(&h->sha, GCRY_MD_SHA3_512, 0); break;
   default:         h->hashlen = 0; return FALSE;
   }
 return TRUE;
@@ -145,10 +163,11 @@ memcpy(b->data, gcry_md_read(h->sha, 0), h->hashlen);
 BOOL
 exim_sha_init(hctx * h, hashmethod m)
 {
+/*XXX extend for sha512 */
 switch (h->method = m)
   {
   case HASH_SHA1:   h->hashlen = 20; sha1_starts(&h->u.sha1);    break;
-  case HASH_SHA256: h->hashlen = 32; sha2_starts(&h->u.sha2, 0); break;
+  case HASH_SHA2_256: h->hashlen = 32; sha2_starts(&h->u.sha2, 0); break;
   default:         h->hashlen = 0; return FALSE;
   }
 return TRUE;
@@ -161,7 +180,7 @@ exim_sha_update(hctx * h, const uschar * data, int len)
 switch (h->method)
   {
   case HASH_SHA1:   sha1_update(h->u.sha1, US data, len); break;
-  case HASH_SHA256: sha2_update(h->u.sha2, US data, len); break;
+  case HASH_SHA2_256: sha2_update(h->u.sha2, US data, len); break;
   }
 }
 
@@ -173,7 +192,7 @@ b->data = store_get(b->len = h->hashlen);
 switch (h->method)
   {
   case HASH_SHA1:   sha1_finish(h->u.sha1, b->data); break;
-  case HASH_SHA256: sha2_finish(h->u.sha2, b->data); break;
+  case HASH_SHA2_256: sha2_finish(h->u.sha2, b->data); break;
   }
 }
 
@@ -417,16 +436,6 @@ native_sha1_end(&h->sha1, NULL, 0, b->data);
 
 
 #endif
-/******************************************************************************/
-
-/* Common to all library versions */
-int
-exim_sha_hashlen(hctx * h)
-{
-return h->method == HASH_SHA1 ? 20
-     : h->method == HASH_SHA256 ? 32
-     : 0;
-}
 
 
 /******************************************************************************/
@@ -776,7 +785,7 @@ int main(void)
 sha1 base;
 int j;
 int i = 0x01020304;
-uschar *ctest = (uschar *)(&i);
+uschar *ctest = US (&i);
 uschar buffer[256];
 uschar digest[20];
 uschar s[41];
index 09b65944d393f3ee6e392edc7b539062d41e1058..337dc991063460fe35f9b4f0d898303c70f8638b 100644 (file)
@@ -12,7 +12,6 @@
 #define HASH_H
 
 #include "sha_ver.h"
-#include "blob.h"
 
 #ifdef SHA_OPENSSL
 # include <openssl/sha.h>
 typedef enum hashmethod {
   HASH_BADTYPE,
   HASH_SHA1,
-  HASH_SHA256,
+
+  HASH_SHA2_256,
+  HASH_SHA2_384,
+  HASH_SHA2_512,
+
   HASH_SHA3_224,
   HASH_SHA3_256,
   HASH_SHA3_384,
@@ -46,7 +49,8 @@ typedef struct {
 #ifdef SHA_OPENSSL
   union {
     SHA_CTX      sha1;       /* SHA1 block                                */
-    SHA256_CTX   sha2;       /* SHA256 block                              */
+    SHA256_CTX   sha2_256;   /* SHA256 or 224 block                       */
+    SHA512_CTX   sha2_512;   /* SHA512 or 384 block                       */
   } u;
 
 #elif defined(SHA_GNUTLS)
@@ -70,7 +74,6 @@ typedef struct {
 extern BOOL     exim_sha_init(hctx *, hashmethod);
 extern void     exim_sha_update(hctx *, const uschar *a, int);
 extern void     exim_sha_finish(hctx *, blob *);
-extern int      exim_sha_hashlen(hctx *);
 
 #endif
 /* End of File */
index b5af8f92b01822e45f72943047e8c790c591bbd8..ec262805e3dbb8796bc2b0a7f6b54eb44f669633 100644 (file)
@@ -737,16 +737,14 @@ host_build_ifacelist(const uschar *list, uschar *name)
 {
 int sep = 0;
 uschar *s;
-uschar buffer[64];
-ip_address_item *yield = NULL;
-ip_address_item *last = NULL;
-ip_address_item *next;
+ip_address_item * yield = NULL, * last = NULL, * next;
 
-while ((s = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL)
+while ((s = string_nextinlist(&list, &sep, NULL, 0)))
   {
   int ipv;
   int port = host_address_extract_port(s);            /* Leaves just the IP address */
-  if ((ipv = string_is_ip_address(s, NULL)) == 0)
+
+  if (!(ipv = string_is_ip_address(s, NULL)))
     log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Malformed IP address \"%s\" in %s",
       s, name);
 
@@ -764,7 +762,9 @@ while ((s = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL)
   next->port = port;
   next->v6_include_v4 = FALSE;
 
-  if (yield == NULL) yield = last = next; else
+  if (!yield)
+    yield = last = next;
+  else
     {
     last->next = next;
     last = next;
@@ -919,21 +919,21 @@ if (type < 0)
   if (family == AF_INET6)
     {
     struct sockaddr_in6 *sk = (struct sockaddr_in6 *)arg;
-    yield = (uschar *)inet_ntop(family, &(sk->sin6_addr), CS addr_buffer,
+    yield = US inet_ntop(family, &(sk->sin6_addr), CS addr_buffer,
       sizeof(addr_buffer));
     if (portptr != NULL) *portptr = ntohs(sk->sin6_port);
     }
   else
     {
     struct sockaddr_in *sk = (struct sockaddr_in *)arg;
-    yield = (uschar *)inet_ntop(family, &(sk->sin_addr), CS addr_buffer,
+    yield = US inet_ntop(family, &(sk->sin_addr), CS addr_buffer,
       sizeof(addr_buffer));
     if (portptr != NULL) *portptr = ntohs(sk->sin_port);
     }
   }
 else
   {
-  yield = (uschar *)inet_ntop(type, arg, CS addr_buffer, sizeof(addr_buffer));
+  yield = US inet_ntop(type, arg, CS addr_buffer, sizeof(addr_buffer));
   }
 
 /* If the result is a mapped IPv4 address, show it in V4 format. */
@@ -1160,10 +1160,7 @@ tt--;   /* lose final separator */
 if (mask < 0)
   *tt = 0;
 else
-  {
-  sprintf(CS tt, "/%d", mask);
-  while (*tt) tt++;
-  }
+  tt += sprintf(CS tt, "/%d", mask);
 
 return tt - buffer;
 }
@@ -1587,7 +1584,7 @@ if (hosts->h_name == NULL || hosts->h_name[0] == 0 || hosts->h_name[0] == '.')
 /* Copy and lowercase the name, which is in static storage in many systems.
 Put it in permanent memory. */
 
-s = (uschar *)hosts->h_name;
+s = US hosts->h_name;
 len = Ustrlen(s) + 1;
 t = sender_host_name = store_get_perm(len);
 while (*s != 0) *t++ = tolower(*s++);
@@ -1742,7 +1739,7 @@ while ((ordername = string_nextinlist(&list, &sep, buffer, sizeof(buffer))))
         truncated and dn_expand may fail. */
 
         if (dn_expand(dnsa.answer, dnsa.answer + dnsa.answerlen,
-             (uschar *)(rr->data), (DN_EXPAND_ARG4_TYPE)(s), ssize) < 0)
+             US (rr->data), (DN_EXPAND_ARG4_TYPE)(s), ssize) < 0)
           {
           log_write(0, LOG_MAIN, "host name alias list truncated for %s",
             sender_host_address);
@@ -2099,7 +2096,7 @@ for (i = 1; i <= times;
 
   if (hostdata->h_name[0] != 0 &&
       Ustrcmp(host->name, hostdata->h_name) != 0)
-    host->name = string_copy_dnsdomain((uschar *)hostdata->h_name);
+    host->name = string_copy_dnsdomain(US hostdata->h_name);
   if (fully_qualified_name != NULL) *fully_qualified_name = host->name;
 
   /* Get the list of addresses. IPv4 and IPv6 addresses can be distinguished
index bf564662d057ac9c93419bfd939a6f4ba052f918..266eaf41484c9f9840a155b5d7f322b6126b36d0 100644 (file)
@@ -175,14 +175,15 @@ Arguments:
   address     the remote address, in text form
   port        the remote port
   timeout     a timeout (zero for indefinite timeout)
-  fastopen    TRUE iff TCP_FASTOPEN can be used
+  fastopen    non-null iff TCP_FASTOPEN can be used; may indicate early-data to
+               be sent in SYN segment
 
 Returns:      0 on success; -1 on failure, with errno set
 */
 
 int
 ip_connect(int sock, int af, const uschar *address, int port, int timeout,
-  BOOL fastopen)
+  const blob * fastopen)
 {
 struct sockaddr_in s_in4;
 struct sockaddr *s_ptr;
@@ -228,25 +229,47 @@ if (timeout > 0) alarm(timeout);
 /* TCP Fast Open, if the system has a cookie from a previous call to
 this peer, can send data in the SYN packet.  The peer can send data
 before it gets our ACK of its SYN,ACK - the latter is useful for
-the SMTP banner.  Is there any usage where the former might be?
-We might extend the ip_connect() args for data if so.  For now,
-connect in FASTOPEN mode but with zero data.
-*/
+the SMTP banner.  Other (than SMTP) cases of TCP connections can
+possibly use the data-on-syn, so support that too.  */
 
 if (fastopen)
   {
-  if (  (rc = sendto(sock, NULL, 0, MSG_FASTOPEN, s_ptr, s_len)) < 0
-     && errno == EOPNOTSUPP
-     )
+  if ((rc = sendto(sock, fastopen->data, fastopen->len,
+                   MSG_FASTOPEN | MSG_DONTWAIT, s_ptr, s_len)) >= 0)
+    {
+    DEBUG(D_transport|D_v)
+      debug_printf("TCP_FASTOPEN mode connection, with data\n");
+    tcp_out_fastopen = TRUE;
+    }
+  else if (errno == EINPROGRESS)       /* expected for nonready peer */
+    {
+    if (!fastopen->data)
+      {
+      DEBUG(D_transport|D_v)
+       debug_printf("TCP_FASTOPEN mode connection, no data\n");
+      tcp_out_fastopen = TRUE;
+      rc = 0;
+      }
+    else if (  (rc = send(sock, fastopen->data, fastopen->len, 0)) < 0
+           && errno == EINPROGRESS)    /* expected for nonready peer */
+      rc = 0;
+    }
+  else if(errno == EOPNOTSUPP)
     {
     DEBUG(D_transport)
       debug_printf("Tried TCP Fast Open but apparently not enabled by sysctl\n");
-    rc = connect(sock, s_ptr, s_len);
+    goto legacy_connect;
     }
   }
 else
 #endif
-  rc = connect(sock, s_ptr, s_len);
+  {
+legacy_connect:
+  if ((rc = connect(sock, s_ptr, s_len)) >= 0)
+    if (  fastopen && fastopen->data && fastopen->len
+       && send(sock, fastopen->data, fastopen->len, 0) < 0)
+       rc = -1;
+  }
 
 save_errno = errno;
 alarm(0);
@@ -289,21 +312,22 @@ Arguments:
   address       the remote address, in text form
   portlo,porthi the remote port range
   timeout       a timeout
-  connhost     if not NULL, host_item filled in with connection details
+  connhost     if not NULL, host_item to be filled in with connection details
   errstr        pointer for allocated string on error
+  fastopen     with SOCK_STREAM, if non-null, request TCP Fast Open.
+               Additionally, optional early-data to send
 
 Return:
   socket fd, or -1 on failure (having allocated an error string)
 */
 int
 ip_connectedsocket(int type, const uschar * hostname, int portlo, int porthi,
-       int timeout, host_item * connhost, uschar ** errstr)
+      int timeout, host_item * connhost, uschar ** errstr, const blob * fastopen)
 {
 int namelen, port;
 host_item shost;
 host_item *h;
 int af = 0, fd, fd4 = -1, fd6 = -1;
-BOOL fastopen = tcp_fastopen_ok && type == SOCK_STREAM;
 
 shost.next = NULL;
 shost.address = NULL;
@@ -381,6 +405,7 @@ bad:
 }
 
 
+/*XXX TFO? */
 int
 ip_tcpsocket(const uschar * hostport, uschar ** errstr, int tmo)
 {
@@ -401,7 +426,7 @@ if (scan != 3)
   }
 
 return ip_connectedsocket(SOCK_STREAM, hostname, portlow, porthigh,
-                         tmo, NULL, errstr);
+                         tmo, NULL, errstr, NULL);
 }
 
 int
@@ -457,7 +482,7 @@ ip_keepalive(int sock, const uschar *address, BOOL torf)
 {
 int fodder = 1;
 if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
-    (uschar *)(&fodder), sizeof(fodder)) != 0)
+    US (&fodder), sizeof(fodder)) != 0)
   log_write(0, LOG_MAIN, "setsockopt(SO_KEEPALIVE) on connection %s %s "
     "failed: %s", torf? "to":"from", address, strerror(errno));
 }
@@ -492,7 +517,7 @@ if (time_left <= 0)
 
 do
   {
-  struct timeval tv = { time_left, 0 };
+  struct timeval tv = { .tv_sec = time_left, .tv_usec = 0 };
   FD_ZERO (&select_inset);
   FD_SET (fd, &select_inset);
 
index bc4fc8e25841f9ee2e87c8f116d467e90e89f5ad..c03d8703251fc25a2e89d3d29ac6d223409b4014 100644 (file)
@@ -186,8 +186,8 @@ extern void    receive_add_recipient(uschar *, int);
 extern BOOL    receive_remove_recipient(uschar *);
 extern uschar *rfc2047_decode(uschar *, BOOL, uschar *, int, int *, uschar **);
 extern int     smtp_fflush(void);
-extern void    smtp_printf(const char *, ...) PRINTF_FUNCTION(1,2);
-extern void    smtp_vprintf(const char *, va_list);
+extern void    smtp_printf(const char *, BOOL, ...) PRINTF_FUNCTION(1,3);
+extern void    smtp_vprintf(const char *, BOOL, va_list);
 extern uschar *string_copy(const uschar *);
 extern uschar *string_copyn(const uschar *, int);
 extern uschar *string_sprintf(const char *, ...) ALMOST_PRINTF(1,2);
index ddd71377e2f75bb335db55a2e37948af10b32e15..fd72bb1ad849a3085f3d6a6002460d0dc3467a97 100644 (file)
@@ -147,7 +147,7 @@ int linecount = 0;
 
 if (running_in_test_harness) return;
 
-if (!syslog_timestamp) s += log_timezone? 26 : 20;
+if (!syslog_timestamp) s += log_timezone ? 26 : 20;
 if (!syslog_pid && LOGGING(pid))
     memmove(s + pid_position[0], s + pid_position[1], pid_position[1] - pid_position[0]);
 
@@ -223,10 +223,10 @@ Returns:     The function does not return
 static void
 die(uschar *s1, uschar *s2)
 {
-if (s1 != NULL)
+if (s1)
   {
   write_syslog(LOG_CRIT, s1);
-  if (debug_file != NULL) debug_printf("%s\n", s1);
+  if (debug_file) debug_printf("%s\n", s1);
   if (log_stderr != NULL && log_stderr != debug_file)
     fprintf(log_stderr, "%s\n", s1);
   }
@@ -272,7 +272,7 @@ if (fd < 0 && errno == ENOENT)
   *lastslash = 0;
   created = directory_make(NULL, name, LOG_DIRECTORY_MODE, FALSE);
   DEBUG(D_any) debug_printf("%s log directory %s\n",
-    created? "created" : "failed to create", name);
+    created ? "created" : "failed to create", name);
   *lastslash = '/';
   if (created) fd = Uopen(name,
 #ifdef O_CLOEXEC
@@ -391,7 +391,7 @@ it gets statted to see if it has been cycled. With a datestamp, the datestamp
 will be compared. The static slot for saving it is the same size as buffer,
 and the text has been checked above to fit, so this use of strcpy() is OK. */
 
-if (type == lt_main)
+if (type == lt_main && string_datestamp_offset >= 0)
   {
   Ustrcpy(mainlog_name, buffer);
   mainlog_datestamp = mainlog_name + string_datestamp_offset;
@@ -399,7 +399,7 @@ if (type == lt_main)
 
 /* Ditto for the reject log */
 
-else if (type == lt_reject)
+else if (type == lt_reject && string_datestamp_offset >= 0)
   {
   Ustrcpy(rejectlog_name, buffer);
   rejectlog_datestamp = rejectlog_name + string_datestamp_offset;
@@ -446,10 +446,8 @@ else if (string_datestamp_offset >= 0)
 /* If the file name is too long, it is an unrecoverable disaster */
 
 if (!ok)
-  {
   die(US"exim: log file path too long: aborting",
       US"Logging failure; please try later");
-  }
 
 /* We now have the file name. Try to open an existing file. After a successful
 open, arrange for automatic closure on exec(), and then return. */
@@ -559,10 +557,7 @@ if ((flags & (LOG_CONFIG_FOR & ~LOG_CONFIG)) != 0)
   }
 
 if ((flags & (LOG_CONFIG_IN & ~LOG_CONFIG)) != 0)
-  {
-  sprintf(CS ptr, " in line %d of %s", config_lineno, config_filename);
-  while (*ptr) ptr++;
-  }
+  ptr += sprintf(CS ptr, " in line %d of %s", config_lineno, config_filename);
 
 Ustrcpy(ptr, ":\n  ");
 return ptr + 4;
@@ -736,7 +731,7 @@ Returns:    nothing
 void
 log_write(unsigned int selector, int flags, const char *format, ...)
 {
-uschar *ptr;
+uschar * ptr;
 int length;
 int paniclogfd;
 ssize_t written_len;
@@ -862,13 +857,12 @@ DEBUG(D_any|D_v)
       }
     }
 
-  sprintf(CS ptr, "%s%s%s%s\n  ",
+  ptr += sprintf(CS ptr, "%s%s%s%s\n  ",
     ((flags & LOG_MAIN) != 0)?    " MAIN"   : "",
     ((flags & LOG_PANIC) != 0)?   " PANIC"  : "",
     ((flags & LOG_PANIC_DIE) == LOG_PANIC_DIE)? " DIE" : "",
     ((flags & LOG_REJECT) != 0)?  " REJECT" : "");
 
-  while(*ptr) ptr++;
   if ((flags & LOG_CONFIG) != 0) ptr = log_config_info(ptr, flags);
 
   va_start(ap, format);
@@ -903,22 +897,17 @@ if (!write_rejectlog) flags &= ~LOG_REJECT;
 when called by a utility. */
 
 ptr = log_buffer;
-sprintf(CS ptr, "%s ", tod_stamp(tod_log));
-while(*ptr) ptr++;
+ptr += sprintf(CS ptr, "%s ", tod_stamp(tod_log));
 
 if (LOGGING(pid))
   {
-  sprintf(CS ptr, "[%d] ", (int)getpid());
   if (!syslog_pid) pid_position[0] = ptr - log_buffer; /* remember begin … */
-  while (*ptr) ptr++;
+  ptr += sprintf(CS ptr, "[%d] ", (int)getpid());
   if (!syslog_pid) pid_position[1] = ptr - log_buffer; /*  … and end+1 of the PID */
   }
 
 if (really_exim && message_id[0] != 0)
-  {
-  sprintf(CS ptr, "%s ", message_id);
-  while(*ptr) ptr++;
-  }
+  ptr += sprintf(CS ptr, "%s ", message_id);
 
 if ((flags & LOG_CONFIG) != 0) ptr = log_config_info(ptr, flags);
 
@@ -933,10 +922,7 @@ this way because it kind of fits with LOG_RECIPIENTS. */
 
 if ((flags & LOG_SENDER) != 0 &&
     ptr < log_buffer + LOG_BUFFER_SIZE - 10 - Ustrlen(raw_sender))
-  {
-  sprintf(CS ptr, " from <%s>", raw_sender);
-  while (*ptr) ptr++;
-  }
+  ptr += sprintf(CS ptr, " from <%s>", raw_sender);
 
 /* Add list of recipients to the message if required; the raw list,
 before rewriting, was saved in raw_recipients. There may be none, if an ACL
@@ -946,19 +932,16 @@ if ((flags & LOG_RECIPIENTS) != 0 && ptr < log_buffer + LOG_BUFFER_SIZE - 6 &&
      raw_recipients_count > 0)
   {
   int i;
-  sprintf(CS ptr, " for");
-  while (*ptr) ptr++;
+  ptr += sprintf(CS ptr, " for");
   for (i = 0; i < raw_recipients_count; i++)
     {
-    uschar *s = raw_recipients[i];
+    uschar * s = raw_recipients[i];
     if (log_buffer + LOG_BUFFER_SIZE - ptr < Ustrlen(s) + 3) break;
-    sprintf(CS ptr, " %s", s);
-    while (*ptr) ptr++;
+    ptr += sprintf(CS ptr, " %s", s);
     }
   }
 
-sprintf(CS  ptr, "\n");
-while(*ptr) ptr++;
+ptr += sprintf(CS  ptr, "\n");
 length = ptr - log_buffer;
 
 /* Handle loggable errors when running a utility, or when address testing.
@@ -1000,7 +983,7 @@ if (  flags & LOG_MAIN
     operation. This happens at midnight, at which point we want to roll over
     the file. Closing it has the desired effect. */
 
-    if (mainlog_datestamp != NULL)
+    if (mainlog_datestamp)
       {
       uschar *nowstamp = tod_stamp(string_datestamp_type);
       if (Ustrncmp (mainlog_datestamp, nowstamp, Ustrlen(nowstamp)) != 0)
@@ -1084,11 +1067,9 @@ if ((flags & LOG_REJECT) != 0)
 
     /* A header with a NULL text is an unfilled in Received: header */
 
-    for (h = header_list; h != NULL; h = h->next)
+    for (h = header_list; h; h = h->next) if (h->text)
       {
-      BOOL fitted;
-      if (h->text == NULL) continue;
-      fitted = string_format(ptr, LOG_BUFFER_SIZE - (ptr-log_buffer),
+      BOOL fitted = string_format(ptr, LOG_BUFFER_SIZE - (ptr-log_buffer),
         "%c %s", h->type, h->text);
       while(*ptr) ptr++;
       if (!fitted)         /* Buffer is full; truncate */
@@ -1118,7 +1099,7 @@ if ((flags & LOG_REJECT) != 0)
     {
     struct stat statbuf;
 
-    if (rejectlog_datestamp != NULL)
+    if (rejectlog_datestamp)
       {
       uschar *nowstamp = tod_stamp(string_datestamp_type);
       if (Ustrncmp (rejectlog_datestamp, nowstamp, Ustrlen(nowstamp)) != 0)
@@ -1175,9 +1156,7 @@ if ((flags & LOG_PANIC) != 0)
     fprintf(log_stderr, "%s", CS log_buffer);
 
   if ((logging_mode & LOG_MODE_SYSLOG) != 0)
-    {
     write_syslog(LOG_ALERT, log_buffer);
-    }
 
   /* If this panic logging was caused by a failure to open the main log,
   the original log line is in panic_save_buffer. Make an attempt to write it. */
index bc610467c1b06c963366e8c84c423d0a03a71637..153fcf24f6d61d1f62ebe6199cc3ea0c356d9009 100644 (file)
@@ -390,8 +390,8 @@ for (loop = 0; (loop < hash_offlen); ++loop)
   {
   uschar packbuf[8];
 
-  if (lseek(cdbp->fileno, (off_t) cur_offset,SEEK_SET) == -1) return DEFER;
-  if (cdb_bread(cdbp->fileno, packbuf,8) == -1) return DEFER;
+  if (lseek(cdbp->fileno, (off_t) cur_offset, SEEK_SET) == -1) return DEFER;
+  if (cdb_bread(cdbp->fileno, packbuf, 8) == -1) return DEFER;
 
   item_hash = cdb_unpack(packbuf);
   item_posn = cdb_unpack(packbuf + 4);
index b8c42d59665f1ea77e718a962b5bdeda3404a847..4b03c35f1de49f95a20c0757f5f4367acd0c20bf 100644 (file)
 static void *
 dbmdb_open(uschar *filename, uschar **errmsg)
 {
+uschar * dirname = string_copy(filename);
+uschar * s;
 EXIM_DB *yield = NULL;
-EXIM_DBOPEN(filename, O_RDONLY, 0, &yield);
+
+if ((s = Ustrrchr(dirname, '/'))) *s = '\0';
+EXIM_DBOPEN(filename, dirname, O_RDONLY, 0, &yield);
 if (yield == NULL)
   {
   int save_errno = errno;
index c4b5b53eca41e2e0a7be6b42157d2c879dac1afc..bf3acd6ef03d3d1ce0cb8a39d153949d217542b7 100644 (file)
@@ -410,7 +410,7 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0)))
         if (outsep2 == NULL)
           {
           /* output only the first item of data */
-          yield = string_catn(yield, &size, &ptr, (uschar *)(rr->data+1),
+          yield = string_catn(yield, &size, &ptr, US (rr->data+1),
             (rr->data)[0]);
           }
         else
index b29fccca78cbcb8d790fe3b6b6843feca3269d7d..7f1775c1ffb7e1f5f4e99ad3cb43b28e4ed68abf 100644 (file)
@@ -291,35 +291,35 @@ has the password removed. This copy is also used for debugging output. */
                 (char *) store_get(sizeof(char) * var->sqllen);
             break;
         case SQL_SHORT:
-            var->sqldata = (char *) store_get(sizeof(short));
+            var->sqldata = CS  store_get(sizeof(short));
             break;
         case SQL_LONG:
-            var->sqldata = (char *) store_get(sizeof(ISC_LONG));
+            var->sqldata = CS  store_get(sizeof(ISC_LONG));
             break;
 #ifdef SQL_INT64
         case SQL_INT64:
-            var->sqldata = (char *) store_get(sizeof(ISC_INT64));
+            var->sqldata = CS  store_get(sizeof(ISC_INT64));
             break;
 #endif
         case SQL_FLOAT:
-            var->sqldata = (char *) store_get(sizeof(float));
+            var->sqldata = CS  store_get(sizeof(float));
             break;
         case SQL_DOUBLE:
-            var->sqldata = (char *) store_get(sizeof(double));
+            var->sqldata = CS  store_get(sizeof(double));
             break;
 #ifdef SQL_TIMESTAMP
         case SQL_DATE:
-            var->sqldata = (char *) store_get(sizeof(ISC_QUAD));
+            var->sqldata = CS  store_get(sizeof(ISC_QUAD));
             break;
 #else
         case SQL_TIMESTAMP:
-            var->sqldata = (char *) store_get(sizeof(ISC_TIMESTAMP));
+            var->sqldata = CS  store_get(sizeof(ISC_TIMESTAMP));
             break;
         case SQL_TYPE_DATE:
-            var->sqldata = (char *) store_get(sizeof(ISC_DATE));
+            var->sqldata = CS  store_get(sizeof(ISC_DATE));
             break;
         case SQL_TYPE_TIME:
-            var->sqldata = (char *) store_get(sizeof(ISC_TIME));
+            var->sqldata = CS  store_get(sizeof(ISC_TIME));
             break;
 #endif
         }
index a6888d5a9923166ac62993b6bad05e3eba8757aa..55f273fd9ace1064a4210b5b13b2071fb83a507c 100644 (file)
@@ -85,7 +85,7 @@ Lmdbstrct * lmdb_p = handle;
 dbkey.mv_data = CS keystring;
 dbkey.mv_size = length;
 
-DEBUG(D_lookup) debug_printf("LMDB: lookup key: %s\n", (char *)keystring);
+DEBUG(D_lookup) debug_printf("LMDB: lookup key: %s\n", CS keystring);
 
 if ((ret = mdb_get(lmdb_p->txn, lmdb_p->db_dbi, &dbkey, &data)) == 0)
   {
index 5cf15af3a5879008587f5af0f0ca27906616babc..ddc7dc8414484d29962e475e3ed9e3d10a0fc378 100644 (file)
@@ -13,6 +13,7 @@ functions. */
 #include "lf_functions.h"
 
 #include <mysql.h>       /* The system header */
+#include <mysql_version.h>
 
 
 /* Structure and anchor for caching connections. */
index 6e7b015bc8c0ee3c4720433cf5798a2630d97e6a..0b01fdbce9b1d9df7007c848fc1ea123774df377 100644 (file)
@@ -23,7 +23,7 @@ sqlite_open(uschar *filename, uschar **errmsg)
 sqlite3 *db = NULL;
 int ret;
 
-ret = sqlite3_open((char *)filename, &db);
+ret = sqlite3_open(CS filename, &db);
 if (ret != 0)
   {
   *errmsg = (void *)sqlite3_errmsg(db);
@@ -86,7 +86,7 @@ sqlite_find(void *handle, uschar *filename, const uschar *query, int length,
 int ret;
 struct strbuf res = { NULL, 0, 0 };
 
-ret = sqlite3_exec(handle, (char *)query, sqlite_callback, &res, (char **)errmsg);
+ret = sqlite3_exec(handle, CS query, sqlite_callback, &res, (char **)errmsg);
 if (ret != SQLITE_OK)
   {
   debug_printf("sqlite3_exec failed: %s\n", *errmsg);
diff --git a/src/src/macro_predef.c b/src/src/macro_predef.c
new file mode 100644 (file)
index 0000000..6b3157f
--- /dev/null
@@ -0,0 +1,279 @@
+/*************************************************
+*     Exim - an Internet mail transport agent    *
+*************************************************/
+
+/* Copyright (c) Jeremy Harris 2017 */
+/* See the file NOTICE for conditions of use and distribution. */
+
+/* Create a static data structure with the predefined macros, to be
+included in the main Exim build */
+
+#include "exim.h"
+#include "macro_predef.h"
+
+unsigned mp_index = 0;
+
+/* Global dummy variables */
+
+void fn_smtp_receive_timeout(const uschar * name, const uschar * str) {}
+uschar * syslog_facility_str;
+
+/******************************************************************************/
+
+void
+builtin_macro_create(const uschar * name)
+{
+printf ("static macro_item p%d = { ", mp_index);
+if (mp_index == 0)
+  printf(".next=NULL,");
+else
+  printf(".next=&p%d,", mp_index-1);
+
+printf(" .command_line=FALSE, .namelen=%d, .replen=1,"
+       " .name=US\"%s\", .replacement=US\"y\" };\n",
+       Ustrlen(name), CS name);
+mp_index++;
+}
+
+void
+spf(uschar * buf, int len, const uschar * fmt, ...)
+{
+va_list ap;
+va_start(ap, fmt);
+
+while (*fmt && len > 1)
+  if (*fmt == '%' && fmt[1] == 'T')
+    {
+    uschar * s = va_arg(ap, uschar *);
+    while (*s && len-- > 1)
+      *buf++ = toupper(*s++);
+    fmt += 2;
+    }
+  else
+    {
+    *buf++ = *fmt++; len--;
+    }
+*buf = '\0';
+va_end(ap);
+}
+
+void
+options_from_list(optionlist * opts, unsigned nopt,
+  const uschar * section, uschar * group)
+{
+int i;
+const uschar * s;
+uschar buf[64];
+
+/* The 'previously-defined-substring' rule for macros in config file
+lines is done thus for these builtin macros: we know that the table
+we source from is in strict alpha order, hence the builtins portion
+of the macros list is in reverse-alpha (we prepend them) - so longer
+macros that have substrings are always discovered first during
+expansion. */
+
+for (i = 0; i < nopt; i++)  if (*(s = US opts[i].name) && *s != '*')
+  {
+  if (group)
+    spf(buf, sizeof(buf), CUS"_OPT_%T_%T_%T", section, group, s);
+  else
+    spf(buf, sizeof(buf), CUS"_OPT_%T_%T", section, s);
+  builtin_macro_create(buf);
+  }
+}
+
+
+/******************************************************************************/
+
+
+/* Create compile-time feature macros */
+static void
+features(void)
+{
+/* Probably we could work out a static initialiser for wherever
+macros are stored, but this will do for now. Some names are awkward
+due to conflicts with other common macros. */
+
+#ifdef SUPPORT_CRYPTEQ
+  builtin_macro_create(US"_HAVE_CRYPTEQ");
+#endif
+#if HAVE_ICONV
+  builtin_macro_create(US"_HAVE_ICONV");
+#endif
+#if HAVE_IPV6
+  builtin_macro_create(US"_HAVE_IPV6");
+#endif
+#ifdef HAVE_SETCLASSRESOURCES
+  builtin_macro_create(US"_HAVE_SETCLASSRESOURCES");
+#endif
+#ifdef SUPPORT_PAM
+  builtin_macro_create(US"_HAVE_PAM");
+#endif
+#ifdef EXIM_PERL
+  builtin_macro_create(US"_HAVE_PERL");
+#endif
+#ifdef EXPAND_DLFUNC
+  builtin_macro_create(US"_HAVE_DLFUNC");
+#endif
+#ifdef USE_TCP_WRAPPERS
+  builtin_macro_create(US"_HAVE_TCPWRAPPERS");
+#endif
+#ifdef SUPPORT_TLS
+  builtin_macro_create(US"_HAVE_TLS");
+# ifdef USE_GNUTLS
+  builtin_macro_create(US"_HAVE_GNUTLS");
+# else
+  builtin_macro_create(US"_HAVE_OPENSSL");
+# endif
+#endif
+#ifdef SUPPORT_TRANSLATE_IP_ADDRESS
+  builtin_macro_create(US"_HAVE_TRANSLATE_IP_ADDRESS");
+#endif
+#ifdef SUPPORT_MOVE_FROZEN_MESSAGES
+  builtin_macro_create(US"_HAVE_MOVE_FROZEN_MESSAGES");
+#endif
+#ifdef WITH_CONTENT_SCAN
+  builtin_macro_create(US"_HAVE_CONTENT_SCANNING");
+#endif
+#ifndef DISABLE_DKIM
+  builtin_macro_create(US"_HAVE_DKIM");
+#endif
+#ifndef DISABLE_DNSSEC
+  builtin_macro_create(US"_HAVE_DNSSEC");
+#endif
+#ifndef DISABLE_EVENT
+  builtin_macro_create(US"_HAVE_EVENT");
+#endif
+#ifdef SUPPORT_I18N
+  builtin_macro_create(US"_HAVE_I18N");
+#endif
+#ifndef DISABLE_OCSP
+  builtin_macro_create(US"_HAVE_OCSP");
+#endif
+#ifndef DISABLE_PRDR
+  builtin_macro_create(US"_HAVE_PRDR");
+#endif
+#ifdef SUPPORT_PROXY
+  builtin_macro_create(US"_HAVE_PROXY");
+#endif
+#ifdef SUPPORT_SOCKS
+  builtin_macro_create(US"_HAVE_SOCKS");
+#endif
+#ifdef TCP_FASTOPEN
+  builtin_macro_create(US"_HAVE_TCP_FASTOPEN");
+#endif
+#ifdef EXPERIMENTAL_LMDB
+  builtin_macro_create(US"_HAVE_LMDB");
+#endif
+#ifdef EXPERIMENTAL_SPF
+  builtin_macro_create(US"_HAVE_SPF");
+#endif
+#ifdef EXPERIMENTAL_SRS
+  builtin_macro_create(US"_HAVE_SRS");
+#endif
+#ifdef EXPERIMENTAL_BRIGHTMAIL
+  builtin_macro_create(US"_HAVE_BRIGHTMAIL");
+#endif
+#ifdef EXPERIMENTAL_DANE
+  builtin_macro_create(US"_HAVE_DANE");
+#endif
+#ifdef EXPERIMENTAL_DCC
+  builtin_macro_create(US"_HAVE_DCC");
+#endif
+#ifdef EXPERIMENTAL_DMARC
+  builtin_macro_create(US"_HAVE_DMARC");
+#endif
+#ifdef EXPERIMENTAL_DSN_INFO
+  builtin_macro_create(US"_HAVE_DSN_INFO");
+#endif
+
+#ifdef LOOKUP_LSEARCH
+  builtin_macro_create(US"_HAVE_LOOKUP_LSEARCH");
+#endif
+#ifdef LOOKUP_CDB
+  builtin_macro_create(US"_HAVE_LOOKUP_CDB");
+#endif
+#ifdef LOOKUP_DBM
+  builtin_macro_create(US"_HAVE_LOOKUP_DBM");
+#endif
+#ifdef LOOKUP_DNSDB
+  builtin_macro_create(US"_HAVE_LOOKUP_DNSDB");
+#endif
+#ifdef LOOKUP_DSEARCH
+  builtin_macro_create(US"_HAVE_LOOKUP_DSEARCH");
+#endif
+#ifdef LOOKUP_IBASE
+  builtin_macro_create(US"_HAVE_LOOKUP_IBASE");
+#endif
+#ifdef LOOKUP_LDAP
+  builtin_macro_create(US"_HAVE_LOOKUP_LDAP");
+#endif
+#ifdef EXPERIMENTAL_LMDB
+  builtin_macro_create(US"_HAVE_LOOKUP_LMDB");
+#endif
+#ifdef LOOKUP_MYSQL
+  builtin_macro_create(US"_HAVE_LOOKUP_MYSQL");
+#endif
+#ifdef LOOKUP_NIS
+  builtin_macro_create(US"_HAVE_LOOKUP_NIS");
+#endif
+#ifdef LOOKUP_NISPLUS
+  builtin_macro_create(US"_HAVE_LOOKUP_NISPLUS");
+#endif
+#ifdef LOOKUP_ORACLE
+  builtin_macro_create(US"_HAVE_LOOKUP_ORACLE");
+#endif
+#ifdef LOOKUP_PASSWD
+  builtin_macro_create(US"_HAVE_LOOKUP_PASSWD");
+#endif
+#ifdef LOOKUP_PGSQL
+  builtin_macro_create(US"_HAVE_LOOKUP_PGSQL");
+#endif
+#ifdef LOOKUP_REDIS
+  builtin_macro_create(US"_HAVE_LOOKUP_REDIS");
+#endif
+#ifdef LOOKUP_SQLITE
+  builtin_macro_create(US"_HAVE_LOOKUP_SQLITE");
+#endif
+#ifdef LOOKUP_TESTDB
+  builtin_macro_create(US"_HAVE_LOOKUP_TESTDB");
+#endif
+#ifdef LOOKUP_WHOSON
+  builtin_macro_create(US"_HAVE_LOOKUP_WHOSON");
+#endif
+
+#ifdef TRANSPORT_APPENDFILE
+# ifdef SUPPORT_MAILDIR
+  builtin_macro_create(US"_HAVE_TRANSPORT_APPEND_MAILDIR");
+# endif
+# ifdef SUPPORT_MAILSTORE
+  builtin_macro_create(US"_HAVE_TRANSPORT_APPEND_MAILSTORE");
+# endif
+# ifdef SUPPORT_MBX
+  builtin_macro_create(US"_HAVE_TRANSPORT_APPEND_MBX");
+# endif
+#endif
+}
+
+
+static void
+options(void)
+{
+options_main();
+options_routers();
+options_transports();
+options_auths();
+}
+
+
+int
+main(void)
+{
+printf("#include \"exim.h\"\n");
+features();
+options();
+
+printf("macro_item * macros = &p%d;\n", mp_index-1);
+printf("macro_item * mlast = &p0;\n");
+exit(0);
+}
diff --git a/src/src/macro_predef.h b/src/src/macro_predef.h
new file mode 100644 (file)
index 0000000..1d3ba7f
--- /dev/null
@@ -0,0 +1,18 @@
+/*************************************************
+*     Exim - an Internet mail transport agent    *
+*************************************************/
+
+/* Copyright (c) Jeremy Harris 2017 */
+/* See the file NOTICE for conditions of use and distribution. */
+
+/* Global functions */
+
+extern void spf(uschar *, int, const uschar *, ...);
+extern void builtin_macro_create(const uschar *);
+extern void options_from_list(optionlist *, unsigned, const uschar *, uschar *);
+
+extern void options_main(void);
+extern void options_routers(void);
+extern void options_transports(void);
+extern void options_auths(void);
+
index 004d6dfd7304f894bb28a2badd97375d64c380ed..eaa7f21ef2793c1edf63c11d37dc226c734cb3e5 100644 (file)
@@ -27,20 +27,16 @@ a string as a text string. This is sometimes useful for debugging output. */
   (running_in_test_harness? (test_harness_load_avg += 10) : os_getloadavg())
 
 
-/* The address_item structure has a word full of 1-bit flags. These macros
+/* The address_item structure has a struct full of 1-bit flags. These macros
 manipulate them. */
 
-#define setflag(addr,flag)    addr->flags |= (flag)
-#define clearflag(addr,flag)  addr->flags &= ~(flag)
+#define setflag(addr, flagname)    addr->flags.flagname = TRUE
+#define clearflag(addr, flagname)  addr->flags.flagname = FALSE
 
-#define testflag(addr,flag)       ((addr->flags & (flag)) != 0)
-#define testflagsall(addr,flag)   ((addr->flags & (flag)) == (flag))
+#define testflag(addr, flagname)   (addr->flags.flagname)
 
-#define copyflag(addrnew,addrold,flag) \
-  addrnew->flags = (addrnew->flags & ~(flag)) | (addrold->flags & (flag))
-
-#define orflag(addrnew,addrold,flag) \
-  addrnew->flags |= addrold->flags & (flag)
+#define copyflag(addrnew, addrold, flagname) \
+  addrnew->flags.flagname = addrold->flags.flagname
 
 
 /* For almost all calls to convert things to printing characters, we want to
@@ -467,6 +463,7 @@ enum {
   Li_ident_timeout,
   Li_incoming_interface,
   Li_incoming_port,
+  Li_millisec,
   Li_outgoing_interface,
   Li_outgoing_port,
   Li_pid,
@@ -721,7 +718,8 @@ enum { v_none, v_sender, v_recipient, v_expn };
 #define vopt_callout_no_cache     0x0040   /* disable callout cache */
 #define vopt_callout_recipsender  0x0080   /* use real sender to verify recip */
 #define vopt_callout_recippmaster 0x0100   /* use postmaster to verify recip */
-#define vopt_success_on_redirect  0x0200
+#define vopt_callout_hold        0x0200   /* lazy close connection */
+#define vopt_success_on_redirect  0x0400
 
 /* Values for fields in callout cache records */
 
@@ -853,6 +851,16 @@ enum {
 #define topt_no_body            0x040  /* Omit body */
 #define topt_escape_headers     0x080  /* Apply escape check to headers */
 #define topt_use_bdat          0x100  /* prepend chunks with RFC3030 BDAT header */
+#define topt_output_string     0x200  /* create string rather than write to fd */
+#define topt_continuation      0x400  /* do not reset buffer */
+
+/* Options for smtp_write_command */
+
+enum { 
+  SCMD_FLUSH = 0,      /* write to kernel */
+  SCMD_MORE,           /* write to kernel, but likely more soon */
+  SCMD_BUFFER          /* stash in application cmd output buffer */
+};
 
 /* Flags for recipient_block, used in DSN support */
 
@@ -961,14 +969,14 @@ enum { FILTER_UNSET, FILTER_FORWARD, FILTER_EXIM, FILTER_SIEVE };
 
 /* Codes for ESMTP facilities offered by peer */
 
-#define PEER_OFFERED_TLS       BIT(0)
-#define PEER_OFFERED_IGNQ      BIT(1)
-#define PEER_OFFERED_PRDR      BIT(2)
-#define PEER_OFFERED_UTF8      BIT(3)
-#define PEER_OFFERED_DSN       BIT(4)
-#define PEER_OFFERED_PIPE      BIT(5)
-#define PEER_OFFERED_SIZE      BIT(6)
-#define PEER_OFFERED_CHUNKING  BIT(7)
+#define OPTION_TLS     BIT(0)
+#define OPTION_IGNQ    BIT(1)
+#define OPTION_PRDR    BIT(2)
+#define OPTION_UTF8    BIT(3)
+#define OPTION_DSN     BIT(4)
+#define OPTION_PIPE    BIT(5)
+#define OPTION_SIZE    BIT(6)
+#define OPTION_CHUNKING        BIT(7)
 
 /* Argument for *_getc */
 
index f9c4c414f71633c5af3c8bc21cca3b4a33f55a23..32f2e9e492461fd4209e70570925df71a29bf4fb 100644 (file)
@@ -104,7 +104,7 @@ static inline int
 test_byte_order()
 {
   short int word = 0x0001;
-  char *byte = (char *) &word;
+  char *byte = CS  &word;
   return(byte[0] ? LITTLE_MY_ENDIAN : BIG_MY_ENDIAN);
 }
 
@@ -147,9 +147,10 @@ uses the returned in_addr to get a second connection to the same system.
 */
 static inline int
 m_tcpsocket(const uschar * hostname, unsigned int port,
-       host_item * host, uschar ** errstr)
+       host_item * host, uschar ** errstr, const blob * fastopen)
 {
-return ip_connectedsocket(SOCK_STREAM, hostname, port, port, 5, host, errstr);
+return ip_connectedsocket(SOCK_STREAM, hostname, port, port, 5,
+                         host, errstr, fastopen);
 }
 
 static int
@@ -202,7 +203,11 @@ const pcre * cre = NULL;
 if (!(list_ele = string_nextinlist(list, sep, NULL, 0)))
   *errstr = US listerr;
 else
+  {
+  DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "RE: ",
+    string_printing(list_ele));
   cre = m_pcre_compile(CUS list_ele, errstr);
+  }
 return cre;
 }
 
@@ -413,16 +418,16 @@ is via malware(), or there's malware_in_file() used for testing/debugging.
 
 Arguments:
   malware_re    match condition for "malware="
-  eml_filename  the file holding the email to be scanned
+  scan_filename  the file holding the email to be scanned, if we're faking
+               this up for the -bmalware test, else NULL
   timeout      if nonzero, non-default timeoutl
-  faking        whether or not we're faking this up for the -bmalware test
 
 Returns:        Exim message processing code (OK, FAIL, DEFER, ...)
                 where true means malware was found (condition applies)
 */
 static int
-malware_internal(const uschar * malware_re, const uschar * eml_filename,
-  int timeout, BOOL faking)
+malware_internal(const uschar * malware_re, const uschar * scan_filename,
+  int timeout)
 {
 int sep = 0;
 const uschar *av_scanner_work = av_scanner;
@@ -435,21 +440,24 @@ struct scan * scanent;
 const uschar * scanner_options;
 int sock = -1;
 time_t tmo;
+uschar * eml_filename, * eml_dir;
+
+if (!malware_re)
+  return FAIL;         /* empty means "don't match anything" */
 
-/* make sure the eml mbox file is spooled up */
-if (!(mbox_file = spool_mbox(&mbox_size, faking ? eml_filename : NULL)))
+/* Ensure the eml mbox file is spooled up */
+
+if (!(mbox_file = spool_mbox(&mbox_size, scan_filename, &eml_filename)))
   return malware_errlog_defer(US"error while creating mbox spool file");
 
-/* none of our current scanners need the mbox
-   file as a stream, so we can close it right away */
-(void)fclose(mbox_file);
+/* None of our current scanners need the mbox file as a stream (they use
+the name), so we can close it right away.  Get the directory too. */
 
-if (!malware_re)
-  return FAIL;         /* empty means "don't match anything" */
+(void) fclose(mbox_file);
+eml_dir = string_copyn(eml_filename, Ustrrchr(eml_filename, '/') - eml_filename);
 
 /* parse 1st option */
-  if ( (strcmpic(malware_re, US"false") == 0) ||
-     (Ustrcmp(malware_re,"0") == 0) )
+if (strcmpic(malware_re, US"false") == 0  ||  Ustrcmp(malware_re,"0") == 0)
   return FAIL;         /* explicitly no matching */
 
 /* special cases (match anything except empty) */
@@ -469,9 +477,6 @@ if (  strcmpic(malware_re,US"true") == 0
 else if (!(re = m_pcre_compile(malware_re, &errstr)))
   return malware_errlog_defer(errstr);
 
-/* Reset sep that is set by previous string_nextinlist() call */
-sep = 0;
-
 /* if av_scanner starts with a dollar, expand it first */
 if (*av_scanner == '$')
   {
@@ -503,10 +508,15 @@ if (!malware_ok)
        scanner_name));
     if (strcmpic(scanner_name, US scanent->name) != 0)
       continue;
+    DEBUG(D_acl) debug_printf_indent("Malware scan:  %s tmo=%s\n",
+      scanner_name, readconf_printtime(timeout));
+
     if (!(scanner_options = string_nextinlist(&av_scanner_work, &sep, NULL, 0)))
       scanner_options = scanent->options_default;
     if (scanent->conn == MC_NONE)
       break;
+
+    DEBUG(D_acl) debug_printf_indent("%15s%10s%s\n", "", "socket: ", scanner_options);
     switch(scanent->conn)
     {
     case MC_TCP:  sock = ip_tcpsocket(scanner_options, &errstr, 5);    break;
@@ -518,7 +528,6 @@ if (!malware_ok)
       return m_errlog_defer(scanent, CUS callout_address, errstr);
     break;
   }
-  DEBUG(D_acl) debug_printf_indent("Malware scan: %s tmo %s\n", scanner_name, readconf_printtime(timeout));
 
   switch (scanent->scancode)
     {
@@ -602,7 +611,8 @@ if (!malware_ok)
 
        if ((fsize = lseek(drweb_fd, 0, SEEK_END)) == -1)
          {
-         int err = errno;
+         int err;
+badseek:  err = errno;
          (void)close(drweb_fd);
          return m_errlog_defer_3(scanent, NULL,
            string_sprintf("can't seek spool file %s: %s",
@@ -619,7 +629,8 @@ if (!malware_ok)
            sock);
          }
        drweb_slen = htonl(fsize);
-       lseek(drweb_fd, 0, SEEK_SET);
+       if (lseek(drweb_fd, 0, SEEK_SET) < 0)
+         goto badseek;
 
        DEBUG(D_acl) debug_printf_indent("Malware scan: issuing %s remote scan [%s]\n",
            scanner_name, scanner_options);
@@ -780,7 +791,7 @@ if (!malware_ok)
       if (buf[0] != '2')               /* aveserver is having problems */
        return m_errlog_defer_3(scanent, CUS callout_address,
          string_sprintf("unavailable (Responded: %s).",
-                         ((buf[0] != 0) ? buf : (uschar *)"nothing") ),
+                         ((buf[0] != 0) ? buf : US "nothing") ),
          sock);
 
       /* prepare our command */
@@ -825,7 +836,7 @@ if (!malware_ok)
       if (buf[0] != '2')               /* aveserver is having problems */
        return m_errlog_defer_3(scanent, CUS callout_address,
          string_sprintf("unable to quit dialogue (Responded: %s).",
-                       ((buf[0] != 0) ? buf : (uschar *)"nothing") ),
+                       ((buf[0] != 0) ? buf : US "nothing") ),
          sock);
 
       if (result == DEFER)
@@ -1091,8 +1102,7 @@ if (!malware_ok)
        }
       scanner_fd = fileno(scanner_out);
 
-      file_name = string_sprintf("%s/scan/%s/%s_scanner_output",
-                               spool_directory, message_id, message_id);
+      file_name = string_sprintf("%s/%s_scanner_output", eml_dir, message_id);
 
       if (!(scanner_record = modefopen(file_name, "wb", SPOOL_MODE)))
        {
@@ -1245,6 +1255,7 @@ if (!malware_ok)
 #else
       uint32_t send_size, send_final_zeroblock;
 #endif
+      blob cmd_str;
 
       /*XXX if unixdomain socket, only one server supported. Needs fixing;
       there's no reason we should not mix local and remote servers */
@@ -1340,6 +1351,19 @@ if (!malware_ok)
          string_sprintf("local/SCAN mode incompatible with" \
            " : in path to email filename [%s]", eml_filename));
 
+      /* Set up the very first data we will be sending */
+      if (!use_scan_command)
+#ifdef WITH_OLD_CLAMAV_STREAM
+       { cmd_str.data = US"STREAM\n"; cmd_str.len = 7; }
+#else
+       { cmd_str.data = US"zINSTREAM"; cmd_str.len = 10; }
+#endif
+      else
+       {
+       cmd_str.data = string_sprintf("SCAN %s\n", eml_filename);
+       cmd_str.len = Ustrlen(cmd_str.data);
+       }
+
       /* We have some network servers specified */
       if (num_servers)
        {
@@ -1349,7 +1373,7 @@ if (!malware_ok)
 
        while (num_servers > 0)
          {
-         int i = random_number( num_servers );
+         int i = random_number(num_servers);
          clamd_address * cd = cv[i];
 
          DEBUG(D_acl) debug_printf_indent("trying server name %s, port %u\n",
@@ -1359,11 +1383,12 @@ if (!malware_ok)
           * on both connections (as one host could resolve to multiple ips) */
          for (;;)
            {
-           sock= m_tcpsocket(cd->hostspec, cd->tcp_port, &connhost, &errstr);
-           if (sock >= 0)
+           if ((sock = m_tcpsocket(cd->hostspec, cd->tcp_port,
+                                   &connhost, &errstr, &cmd_str)) >= 0)
              {
              /* Connection successfully established with a server */
              hostname = cd->hostspec;
+             cmd_str.len = 0;
              break;
              }
            if (cd->retry <= 0) break;
@@ -1412,9 +1437,10 @@ if (!malware_ok)
            "Malware scan: issuing %s old-style remote scan (PORT)\n",
            scanner_name);
 
-       /* Pass the string to ClamAV (7 = "STREAM\n") */
-       if (m_sock_send(sock, US"STREAM\n", 7, &errstr) < 0)
-         return m_errlog_defer(scanent, CUS callout_address, errstr);
+       /* Pass the string to ClamAV (7 = "STREAM\n"), if not already sent */
+       if (cmd_str.len)
+         if (m_sock_send(sock, cmd_str.data, cmd_str.len, &errstr) < 0)
+           return m_errlog_defer(scanent, CUS callout_address, errstr);
 
        memset(av_buffer2, 0, sizeof(av_buffer2));
        bread = ip_recv(sock, av_buffer2, sizeof(av_buffer2), tmo-time(NULL));
@@ -1434,13 +1460,13 @@ if (!malware_ok)
                  "ClamAV returned null", sock);
 
        av_buffer2[bread] = '\0';
-       if( sscanf(CS av_buffer2, "PORT %u\n", &port) != 1 )
+       if(sscanf(CS av_buffer2, "PORT %u\n", &port) != 1)
          return m_errlog_defer_3(scanent, CUS callout_address,
            string_sprintf("Expected port information from clamd, got '%s'",
              av_buffer2),
            sock);
 
-       sockData = m_tcpsocket(connhost.address, port, NULL, &errstr);
+       sockData = m_tcpsocket(connhost.address, port, NULL, &errstr, NULL);
        if (sockData < 0)
          return m_errlog_defer_3(scanent, CUS callout_address, errstr, sock);
 
@@ -1454,12 +1480,13 @@ if (!malware_ok)
            "Malware scan: issuing %s new-style remote scan (zINSTREAM)\n",
            scanner_name);
 
-       /* Pass the string to ClamAV (10 = "zINSTREAM\0") */
-       if (send(sock, "zINSTREAM", 10, 0) < 0)
-         return m_errlog_defer_3(scanent, CUS hostname,
-           string_sprintf("unable to send zINSTREAM to socket (%s)",
-             strerror(errno)),
-           sock);
+       /* Pass the string to ClamAV (10 = "zINSTREAM\0"), if not already sent */
+       if (cmd_str.len)
+         if (send(sock, cmd_str.data, cmd_str.len, 0) < 0)
+           return m_errlog_defer_3(scanent, CUS hostname,
+             string_sprintf("unable to send zINSTREAM to socket (%s)",
+               strerror(errno)),
+             sock);
 
 # define CLOSE_SOCKDATA /**/
 #endif
@@ -1476,7 +1503,8 @@ if (!malware_ok)
          }
        if ((fsize = lseek(clam_fd, 0, SEEK_END)) < 0)
          {
-         int err = errno;
+         int err;
+b_seek:   err = errno;
          CLOSE_SOCKDATA; (void)close(clam_fd);
          return m_errlog_defer_3(scanent, NULL,
            string_sprintf("can't seek spool file %s: %s",
@@ -1492,7 +1520,8 @@ if (!malware_ok)
              eml_filename),
            sock);
          }
-       lseek(clam_fd, 0, SEEK_SET);
+       if (lseek(clam_fd, 0, SEEK_SET) < 0)
+         goto b_seek;
 
        if (!(clamav_fbuf = US malloc(fsize_uint)))
          {
@@ -1558,17 +1587,17 @@ if (!malware_ok)
        scanned twice, in the broken out files and from the original .eml.
        Since ClamAV now handles emails (and has for quite some time) we can
        just use the email file itself. */
-       /* Pass the string to ClamAV (7 = "SCAN \n" + \0) */
-       file_name = string_sprintf("SCAN %s\n", eml_filename);
+       /* Pass the string to ClamAV (7 = "SCAN \n" + \0), if not already sent */
 
        DEBUG(D_acl) debug_printf_indent(
            "Malware scan: issuing %s local-path scan [%s]\n",
            scanner_name, scanner_options);
 
-       if (send(sock, file_name, Ustrlen(file_name), 0) < 0)
-         return m_errlog_defer_3(scanent, CUS callout_address,
-           string_sprintf("unable to write to socket (%s)", strerror(errno)),
-           sock);
+       if (cmd_str.len)
+         if (send(sock, cmd_str.data, cmd_str.len, 0) < 0)
+           return m_errlog_defer_3(scanent, CUS callout_address,
+             string_sprintf("unable to write to socket (%s)", strerror(errno)),
+             sock);
 
        /* Do not shut down the socket for writing; a user report noted that
         * clamd 0.70 does not react well to this. */
@@ -1695,8 +1724,10 @@ if (!malware_ok)
       const pcre *sockline_name_re;
 
       /* find scanner command line */
-      if ((sockline_scanner = string_nextinlist(&av_scanner_work, &sep,
-                                         NULL, 0)))
+      if (  (sockline_scanner = string_nextinlist(&av_scanner_work, &sep,
+                                         NULL, 0))
+        && *sockline_scanner
+        )
       {        /* check for no expansions apart from one %s */
        uschar * s = Ustrchr(sockline_scanner, '%');
        if (s++)
@@ -1706,6 +1737,8 @@ if (!malware_ok)
       }
       else
        sockline_scanner = sockline_scanner_default;
+      DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "cmdline: ",
+       string_printing(sockline_scanner));
 
       /* find scanner output trigger */
       sockline_trig_re = m_pcre_nextinlist(&av_scanner_work, &sep,
@@ -1720,9 +1753,9 @@ if (!malware_ok)
        return m_errlog_defer_3(scanent, NULL, errstr, sock);
 
       /* prepare scanner call - security depends on expansions check above */
-      commandline = string_sprintf("%s/scan/%s/%s.eml", spool_directory, message_id, message_id);
-      commandline = string_sprintf( CS sockline_scanner, CS commandline);
-
+      commandline = string_sprintf( CS sockline_scanner, CS eml_filename);
+      DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "expanded: ",
+       string_printing(commandline));
 
       /* Pass the command string to the socket */
       if (m_sock_send(sock, commandline, Ustrlen(commandline), &errstr) < 0)
@@ -1741,12 +1774,16 @@ if (!malware_ok)
                US"buffer too small", sock);
       av_buffer[bread] = '\0';
       linebuffer = string_copy(av_buffer);
+      DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "answer: ",
+       string_printing(linebuffer));
 
       /* try trigger match */
       if (regex_match_and_setup(sockline_trig_re, linebuffer, 0, -1))
        {
        if (!(malware_name = m_pcre_exec(sockline_name_re, av_buffer)))
          malware_name = US "unknown";
+       DEBUG(D_acl) debug_printf_indent("%15s%10s'%s'\n", "", "name: ",
+         string_printing(malware_name));
        }
       else /* no virus found */
        malware_name = NULL;
@@ -1844,8 +1881,7 @@ if (!malware_ok)
                }
              else
                {
-               scanrequest = string_sprintf("SCAN %s/scan/%s\n",
-                   spool_directory, message_id);
+               scanrequest = string_sprintf("SCAN %s\n", eml_dir);
                avast_stage = AVA_RSP;          /* just sent command */
                }
 
@@ -2000,14 +2036,9 @@ Returns:      Exim message processing code (OK, FAIL, DEFER, ...)
 int
 malware(const uschar * malware_re, int timeout)
 {
-uschar * scan_filename;
-int ret;
+int ret = malware_internal(malware_re, NULL, timeout);
 
-scan_filename = string_sprintf("%s/scan/%s/%s.eml",
-                 spool_directory, message_id, message_id);
-ret = malware_internal(malware_re, scan_filename, timeout, FALSE);
 if (ret == DEFER) av_failed = TRUE;
-
 return ret;
 }
 
@@ -2045,7 +2076,7 @@ recipients_list = NULL;
 receive_add_recipient(US"malware-victim@example.net", -1);
 enable_dollar_recipients = TRUE;
 
-ret = malware_internal(US"*", eml_filename, 0,  TRUE);
+ret = malware_internal(US"*", eml_filename, 0);
 
 Ustrncpy(spooled_message_id, message_id, sizeof(spooled_message_id));
 spool_mbox_ok = 1;
index fa42187dd1be5bbb22d1a65989582db5033e3d19..93777c6febe7ba7443784a286062b74c005d817c 100644 (file)
@@ -1326,4 +1326,25 @@ return match_check_list(listptr, sep, &addresslist_anchor, &local_cache_bits,
     valueptr);
 }
 
+/* Simpler version of match_address_list; always caseless, expanding,
+no cache bits, no value-return.
+
+Arguments:
+  address         address to test
+  listptr         list to check against
+  sep             separator character for the list;
+                  may be 0 to get separator from the list;
+                  may be UCHAR_MAX+1 for one-item list
+
+Returns:          OK    for a positive match, or end list after a negation;
+                  FAIL  for a negative match, or end list after non-negation;
+                  DEFER if a lookup deferred
+*/
+
+int
+match_address_list_basic(const uschar *address, const uschar **listptr, int sep)
+{
+return match_address_list(address, TRUE, TRUE, listptr, NULL, -1, sep, NULL);
+}
+
 /* End of match.c */
index 821cb541d8ea42ded344a04c87e0fdef81335f1f..61dabd2ac6561be2b0f88f3526147ed54d88adcc 100644 (file)
@@ -16,6 +16,7 @@ FILE *mime_stream = NULL;
 uschar *mime_current_boundary = NULL;
 
 static mime_header mime_header_list[] = {
+  /*   name                    namelen         value */
   { US"content-type:",              13, &mime_content_type },
   { US"content-disposition:",       20, &mime_content_disposition },
   { US"content-transfer-encoding:", 26, &mime_content_transfer_encoding },
@@ -26,6 +27,7 @@ static mime_header mime_header_list[] = {
 static int mime_header_list_size = nelem(mime_header_list);
 
 static mime_parameter mime_parameter_list[] = {
+  /*   name    namelen  value */
   { US"name=",     5, &mime_filename },
   { US"filename=", 9, &mime_filename },
   { US"charset=",  8, &mime_charset  },
@@ -157,24 +159,16 @@ while (fgets(CS ibuf, MIME_MAX_LINE_LENGTH, in) != NULL)
        {
        /* Error from decoder. ipos is unchanged. */
        mime_set_anomaly(MIME_ANOMALY_BROKEN_QP);
-       *opos = '=';
-       ++opos;
+       *opos++ = '=';
        ++ipos;
        }
       else if (decode_qp_result == -1)
        break;
       else if (decode_qp_result >= 0)
-       {
-       *opos = decode_qp_result;
-       ++opos;
-       }
+       *opos++ = decode_qp_result;
       }
     else
-      {
-      *opos = *ipos;
-      ++opos;
-      ++ipos;
-      }
+      *opos++ = *ipos++;
     }
   /* something to write? */
   len = opos - obuf;
@@ -225,9 +219,8 @@ mime_decode(const uschar **listptr)
 {
 int sep = 0;
 const uschar *list = *listptr;
-uschar *option;
-uschar option_buffer[1024];
-uschar decode_path[1024];
+uschar * option;
+uschar * decode_path;
 FILE *decode_file = NULL;
 long f_pos = 0;
 ssize_t size_counter = 0;
@@ -237,12 +230,10 @@ if (!mime_stream || (f_pos = ftell(mime_stream)) < 0)
   return FAIL;
 
 /* build default decode path (will exist since MBOX must be spooled up) */
-(void)string_format(decode_path,1024,"%s/scan/%s",spool_directory,message_id);
+decode_path = string_sprintf("%s/scan/%s", spool_directory, message_id);
 
 /* try to find 1st option */
-if ((option = string_nextinlist(&list, &sep,
-                               option_buffer,
-                               sizeof(option_buffer))) != NULL)
+if ((option = string_nextinlist(&list, &sep, NULL, 0)))
   {
   /* parse 1st option */
   if ((Ustrcmp(option,"false") == 0) || (Ustrcmp(option,"0") == 0))
index b288a32cbcb8e47c6cb54489a3b52a153f5c022d..a74705739496ed5781f616d24984046dd1a43b1f 100644 (file)
@@ -30,11 +30,13 @@ local_scan.h includes it and exim.h includes them both (to get this earlier). */
 the arguments of printf-like functions. This is done by a macro. */
 
 #if defined(__GNUC__) || defined(__clang__)
-# define PRINTF_FUNCTION(A,B)  __attribute__((format(printf,A,B)))
-# define ARG_UNUSED  __attribute__((__unused__))
+# define PRINTF_FUNCTION(A,B)  __attribute__((format(printf,A,B)))
+# define ARG_UNUSED            __attribute__((__unused__))
+# define WARN_UNUSED_RESULT    __attribute__((__warn_unused_result__))
 #else
 # define PRINTF_FUNCTION(A,B)
 # define ARG_UNUSED  /**/
+# define WARN_UNUSED_RESULT /**/
 #endif
 
 #ifdef WANT_DEEPER_PRINTF_CHECKS
index ca24e8dd27e47d42df5140e55de39cd0a072c6d8..6eadc38b15833d3223629fea92ba9e4663a9b3f5 100644 (file)
@@ -6,9 +6,14 @@
 /* See the file NOTICE for conditions of use and distribution. */
 
 #ifdef STAND_ALONE
-#include <signal.h>
-#include <stdio.h>
-#include <time.h>
+# include <signal.h>
+# include <stdio.h>
+# include <time.h>
+#endif
+
+#ifndef CS
+# define CS (char *)
+# define US (unsigned char *)
 #endif
 
 /* This source file contains "default" system-dependent functions which
@@ -413,7 +418,7 @@ if (avg_kd < 0)
   }
 
 if (lseek (avg_kd, avg_offset, 0) == -1L
-    || read (avg_kd, (char *)(&avg), sizeof (avg)) != sizeof(avg))
+    || read (avg_kd, CS (&avg), sizeof (avg)) != sizeof(avg))
   return -1;
 
 return (int)(((double)avg/FSCALE)*1000.0);
@@ -645,7 +650,7 @@ ifc.V_ifc_family = V_FAMILY_QUERY;
 ifc.V_ifc_flags = 0;
 #endif
 
-if (ioctl(vs, V_GIFCONF, (char *)&ifc) < 0)
+if (ioctl(vs, V_GIFCONF, CS &ifc) < 0)
   log_write(0, LOG_PANIC_DIE, "Unable to get interface configuration: %d %s",
     errno, strerror(errno));
 
@@ -680,7 +685,7 @@ find its length, and then recopy the correct length. */
 
 for (cp = buf; cp < buf + ifc.V_ifc_len; cp += len)
   {
-  memcpy((char *)&ifreq, cp, sizeof(ifreq));
+  memcpy(CS &ifreq, cp, sizeof(ifreq));
 
   #ifndef HAVE_SA_LEN
   len = sizeof(struct V_ifreq);
@@ -710,7 +715,7 @@ for (cp = buf; cp < buf + ifc.V_ifc_len; cp += len)
   interface hasn't been "plumbed" to any protocol (IPv4 or IPv6). Therefore,
   we now just treat this case as "down" as well. */
 
-  if (ioctl(vs, V_GIFFLAGS, (char *)&ifreq) < 0)
+  if (ioctl(vs, V_GIFFLAGS, CS &ifreq) < 0)
     {
     continue;
     /*************
@@ -726,7 +731,7 @@ for (cp = buf; cp < buf + ifc.V_ifc_len; cp += len)
   GIFFLAGS may have wrecked the data. */
 
   #ifndef SIOCGIFCONF_GIVES_ADDR
-  if (ioctl(vs, V_GIFADDR, (char *)&ifreq) < 0)
+  if (ioctl(vs, V_GIFADDR, CS &ifreq) < 0)
     log_write(0, LOG_PANIC_DIE, "Unable to get IP address for %s interface: "
       "%d %s", ifreq.V_ifr_name, errno, strerror(errno));
   addrp = &ifreq.V_ifr_addr;
@@ -846,7 +851,7 @@ os_get_dns_resolver_res(void)
 int
 os_unsetenv(const unsigned char * name)
 {
-return unsetenv((char *)name);
+return unsetenv(CS name);
 }
 #endif
 
@@ -865,7 +870,7 @@ this, for all other systems we provide our own getcwd() */
 unsigned char *
 os_getcwd(unsigned char * buffer, size_t size)
 {
-return (unsigned char *) getcwd((char *)buffer, size);
+return US  getcwd(CS buffer, size);
 }
 #else
 #ifndef PATH_MAX
@@ -874,7 +879,7 @@ return (unsigned char *) getcwd((char *)buffer, size);
 unsigned char *
 os_getcwd(unsigned char * buffer, size_t size)
 {
-char * b = (char *)buffer;
+char * b = CS buffer;
 
 if (!size) size = PATH_MAX;
 if (!b && !(b = malloc(size))) return NULL;
index 94a1af6ab274908905550697b3bbba29830b96ed..68a83b0e802bc2c6032e302d7e6182766a618668 100644 (file)
@@ -620,8 +620,8 @@ parse_extract_address(uschar *mailbox, uschar **errorptr, int *start, int *end,
 {
 uschar *yield = store_get(Ustrlen(mailbox) + 1);
 uschar *startptr, *endptr;
-uschar *s = (uschar *)mailbox;
-uschar *t = (uschar *)yield;
+uschar *s = US mailbox;
+uschar *t = US yield;
 
 *domain = 0;
 
@@ -745,7 +745,7 @@ if (*s == '<')
     *errorptr = s[-1] == 0
       ? US"'>' missing at end of address"
       : string_sprintf("malformed address: %.32s may not follow %.*s",
-         s-1, s - (uschar *)mailbox - 1, mailbox);
+         s-1, s - US mailbox - 1, mailbox);
     goto PARSE_FAILED;
     }
 
@@ -798,13 +798,13 @@ if (*s != 0)
   else
     {
     *errorptr = string_sprintf("malformed address: %.32s may not follow %.*s",
-      s, s - (uschar *)mailbox, mailbox);
+      s, s - US mailbox, mailbox);
     goto PARSE_FAILED;
     }
   }
-*start = startptr - (uschar *)mailbox;      /* Return offsets */
+*start = startptr - US mailbox;      /* Return offsets */
 while (isspace(endptr[-1])) endptr--;
-*end = endptr - (uschar *)mailbox;
+*end = endptr - US mailbox;
 
 /* Although this code has no limitation on the length of address extracted,
 other parts of Exim may have limits, and in any case, RFC 2821 limits local
@@ -913,8 +913,7 @@ for (; len > 0; len--)
       }
     else
       {
-      sprintf(CS t, "=%02X", ch);
-      while (*t != 0) t++;
+      t += sprintf(CS t, "=%02X", ch);
       coded = TRUE;
       first_byte = !first_byte;
       }
index c298568ead615987de814eb4b664b59fda00aed0..10631ceaada06b7fb83e9343dab7743fdb427e45 100644 (file)
@@ -1,6 +1,6 @@
 # Make file for building the pdkim library.
 
-OBJ = pdkim.o rsa.o
+OBJ = pdkim.o signing.o
 
 pdkim.a:         $(OBJ)
                 @$(RM_COMMAND) -f pdkim.a
@@ -13,6 +13,6 @@ pdkim.a:         $(OBJ)
                 $(FE)$(CC) -c $(CFLAGS) $(INCLUDE) -I. $*.c
 
 pdkim.o: $(HDRS) crypt_ver.h pdkim.h pdkim.c
-rsa.o:   $(HDRS) crypt_ver.h rsa.h rsa.c
+signing.o: $(HDRS) crypt_ver.h signing.h signing.c
 
 # End
index cd2171c8233fc71f3d32f94c24f5e203cfbcf67e..439d99b3a5fa68a31960633ed7f8f3405d916cc2 100644 (file)
@@ -5,7 +5,7 @@
 /* Copyright (c) Jeremy Harris 2016 */
 /* See the file NOTICE for conditions of use and distribution. */
 
-/* RSA and SHA routine selection for PDKIM */
+/* Signing and hashing routine selection for PDKIM */
 
 #include "../exim.h"
 #include "../sha_ver.h"
 # include <gnutls/gnutls.h>
 
 # if GNUTLS_VERSION_NUMBER >= 0x30000
-#  define RSA_GNUTLS
+#  define SIGN_GNUTLS
 # else
-#  define RSA_GCRYPT
+#  define SIGN_GCRYPT
 # endif
 
 #else
-# define RSA_OPENSSL
+# define SIGN_OPENSSL
 #endif
 
index 5fc6045d0b49995a74bfffe62ca1bad58aecdcc4..695288162740d0598e7f4caab42c7110908ef38d 100644 (file)
 
 #include "crypt_ver.h"
 
-#ifdef RSA_OPENSSL
+#ifdef SIGN_OPENSSL
 # include <openssl/rsa.h>
 # include <openssl/ssl.h>
 # include <openssl/err.h>
-#elif defined(RSA_GNUTLS)
+#elif defined(SIGN_GNUTLS)
 # include <gnutls/gnutls.h>
 # include <gnutls/x509.h>
 #endif
 
 #include "pdkim.h"
-#include "rsa.h"
+#include "signing.h"
 
 #define PDKIM_SIGNATURE_VERSION     "1"
 #define PDKIM_PUB_RECORD_VERSION    US "DKIM1"
@@ -73,24 +73,24 @@ const uschar * pdkim_querymethods[] = {
   US"dns/txt",
   NULL
 };
-const uschar * pdkim_algos[] = {
-  US"rsa-sha256",
-  US"rsa-sha1",
-  NULL
-};
 const uschar * pdkim_canons[] = {
   US"simple",
   US"relaxed",
   NULL
 };
-const uschar * pdkim_hashes[] = {
-  US"sha256",
-  US"sha1",
-  NULL
+
+typedef struct {
+  const uschar * dkim_hashname;
+  hashmethod    exim_hashmethod;
+} pdkim_hashtype;
+static const pdkim_hashtype pdkim_hashes[] = {
+  { US"sha1",   HASH_SHA1 },
+  { US"sha256", HASH_SHA2_256 },
+  { US"sha512", HASH_SHA2_512 }
 };
+
 const uschar * pdkim_keytypes[] = {
-  US"rsa",
-  NULL
+  US"rsa"
 };
 
 typedef struct pdkim_combined_canon_entry {
@@ -110,7 +110,20 @@ pdkim_combined_canon_entry pdkim_combined_canons[] = {
 };
 
 
+static blob lineending = {.data = US"\r\n", .len = 2};
+
 /* -------------------------------------------------------------------------- */
+uschar *
+dkim_sig_to_a_tag(const pdkim_signature * sig)
+{
+if (  sig->keytype < 0  || sig->keytype > nelem(pdkim_keytypes)
+   || sig->hashtype < 0 || sig->hashtype > nelem(pdkim_hashes))
+  return US"err";
+return string_sprintf("%s-%s",
+  pdkim_keytypes[sig->keytype], pdkim_hashes[sig->hashtype].dkim_hashname);
+}
+
+
 
 const char *
 pdkim_verify_status_str(int status)
@@ -132,6 +145,7 @@ switch(ext_status)
   {
   case PDKIM_VERIFY_FAIL_BODY: return "PDKIM_VERIFY_FAIL_BODY";
   case PDKIM_VERIFY_FAIL_MESSAGE: return "PDKIM_VERIFY_FAIL_MESSAGE";
+  case PDKIM_VERIFY_FAIL_SIG_ALGO_MISMATCH: return "PDKIM_VERIFY_FAIL_SIG_ALGO_MISMATCH";
   case PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE: return "PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE";
   case PDKIM_VERIFY_INVALID_BUFFER_SIZE: return "PDKIM_VERIFY_INVALID_BUFFER_SIZE";
   case PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD: return "PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD";
@@ -155,7 +169,7 @@ switch(status)
   case PDKIM_ERR_BUFFER_TOO_SMALL:     return US"BUFFER_TOO_SMALL";
   case PDKIM_SIGN_PRIVKEY_WRAP:        return US"PRIVKEY_WRAP";
   case PDKIM_SIGN_PRIVKEY_B64D:        return US"PRIVKEY_B64D";
-  default: return "(unknown)";
+  default: return US"(unknown)";
   }
 }
 
@@ -288,7 +302,7 @@ found:
 /* Performs "relaxed" canonicalization of a header. */
 
 static uschar *
-pdkim_relax_header(const uschar * header, int crlf)
+pdkim_relax_header(const uschar * header, BOOL append_crlf)
 {
 BOOL past_field_name = FALSE;
 BOOL seen_wsp = FALSE;
@@ -299,8 +313,8 @@ uschar * q = relaxed;
 for (p = header; *p; p++)
   {
   uschar c = *p;
-  /* Ignore CR & LF */
-  if (c == '\r' || c == '\n')
+
+  if (c == '\r' || c == '\n')  /* Ignore CR & LF */
     continue;
   if (c == '\t' || c == ' ')
     {
@@ -312,8 +326,8 @@ for (p = header; *p; p++)
   else
     if (!past_field_name && c == ':')
       {
-      if (seen_wsp) q--;       /* This removes WSP before the colon */
-      seen_wsp = TRUE;         /* This removes WSP after the colon */
+      if (seen_wsp) q--;       /* This removes WSP immediately before the colon */
+      seen_wsp = TRUE;         /* This removes WSP immediately after the colon */
       past_field_name = TRUE;
       }
     else
@@ -326,7 +340,7 @@ for (p = header; *p; p++)
 
 if (q > relaxed && q[-1] == ' ') q--; /* Squash eventual trailing SP */
 
-if (crlf) { *q++ = '\r'; *q++ = '\n'; }
+if (append_crlf) { *q++ = '\r'; *q++ = '\n'; }
 *q = '\0';
 return relaxed;
 }
@@ -335,10 +349,10 @@ return relaxed;
 /* -------------------------------------------------------------------------- */
 #define PDKIM_QP_ERROR_DECODE -1
 
-static uschar *
-pdkim_decode_qp_char(uschar *qp_p, int *c)
+static const uschar *
+pdkim_decode_qp_char(const uschar *qp_p, int *c)
 {
-uschar *initial_pos = qp_p;
+const uschar *initial_pos = qp_p;
 
 /* Advance one char */
 qp_p++;
@@ -361,11 +375,11 @@ return initial_pos;
 /* -------------------------------------------------------------------------- */
 
 static uschar *
-pdkim_decode_qp(uschar * str)
+pdkim_decode_qp(const uschar * str)
 {
 int nchar = 0;
 uschar * q;
-uschar * p = str;
+const uschar * p = str;
 uschar * n = store_get(Ustrlen(str)+1);
 
 *n = '\0';
@@ -393,7 +407,7 @@ return n;
 /* -------------------------------------------------------------------------- */
 
 static void
-pdkim_decode_base64(uschar *str, blob * b)
+pdkim_decode_base64(const uschar * str, blob * b)
 {
 int dlen;
 dlen = b64decode(str, &b->data);
@@ -414,7 +428,7 @@ return b64encode(b->data, b->len);
 #define PDKIM_HDR_VALUE 2
 
 static pdkim_signature *
-pdkim_parse_sig_header(pdkim_ctx *ctx, uschar * raw_hdr)
+pdkim_parse_sig_header(pdkim_ctx * ctx, uschar * raw_hdr)
 {
 pdkim_signature * sig;
 uschar *p, *q;
@@ -430,8 +444,9 @@ memset(sig, 0, sizeof(pdkim_signature));
 sig->bodylength = -1;
 
 /* Set so invalid/missing data error display is accurate */
-sig->algo = -1;
 sig->version = 0;
+sig->keytype = -1;
+sig->hashtype = -1;
 
 q = sig->rawsig_no_b_val = store_get(Ustrlen(raw_hdr)+1);
 
@@ -504,13 +519,18 @@ for (p = raw_hdr; ; p++)
              Ustrcmp(cur_val, PDKIM_SIGNATURE_VERSION) == 0 ? 1 : -1;
            break;
          case 'a':
-           for (i = 0; pdkim_algos[i]; i++)
-             if (Ustrcmp(cur_val, pdkim_algos[i]) == 0)
-               {
-               sig->algo = i;
-               break;
-               }
+           {
+           uschar * s = Ustrchr(cur_val, '-');
+
+           for(i = 0; i < nelem(pdkim_keytypes); i++)
+             if (Ustrncmp(cur_val, pdkim_keytypes[i], s - cur_val) == 0)
+               { sig->keytype = i; break; }
+           for (++s, i = 0; i < nelem(pdkim_hashes); i++)
+             if (Ustrcmp(s, pdkim_hashes[i].dkim_hashname) == 0)
+               { sig->hashtype = i; break; }
            break;
+           }
+
          case 'c':
            for (i = 0; pdkim_combined_canons[i].str; i++)
              if (Ustrcmp(cur_val, pdkim_combined_canons[i].str) == 0)
@@ -582,10 +602,12 @@ DEBUG(D_acl)
          "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
   }
 
+/*XXX hash method: extend for sha512 */
 if (!exim_sha_init(&sig->body_hash_ctx,
-              sig->algo == PDKIM_ALGO_RSA_SHA1 ? HASH_SHA1 : HASH_SHA256))
+              pdkim_hashes[sig->hashtype].exim_hashmethod))
   {
-  DEBUG(D_acl) debug_printf("PDKIM: hash init internal error\n");
+  DEBUG(D_acl)
+    debug_printf("PDKIM: hash init error, possibly nonhandled hashtype\n");
   return NULL;
   }
 return sig;
@@ -597,190 +619,145 @@ return sig;
 static pdkim_pubkey *
 pdkim_parse_pubkey_record(pdkim_ctx *ctx, const uschar *raw_record)
 {
-pdkim_pubkey *pub;
-const uschar *p;
-uschar * cur_tag = NULL; int ts = 0, tl = 0;
-uschar * cur_val = NULL; int vs = 0, vl = 0;
-int where = PDKIM_HDR_LIMBO;
+const uschar * ele;
+int sep = ';';
+pdkim_pubkey * pub;
 
 pub = store_get(sizeof(pdkim_pubkey));
 memset(pub, 0, sizeof(pdkim_pubkey));
 
-for (p = raw_record; ; p++)
+while ((ele = string_nextinlist(&raw_record, &sep, NULL, 0)))
+  {
+  const uschar * val;
+
+  if ((val = Ustrchr(ele, '=')))
     {
-    uschar c = *p;
+    int taglen = val++ - ele;
 
-    /* Ignore FWS */
-    if (c != '\r' && c != '\n') switch (where)
+    DEBUG(D_acl) debug_printf(" %.*s=%s\n", taglen, ele, val);
+    switch (ele[0])
       {
-      case PDKIM_HDR_LIMBO:            /* In limbo, just wait for a tag-char to appear */
-       if (!(c >= 'a' && c <= 'z'))
-         break;
-       where = PDKIM_HDR_TAG;
-       /*FALLTHROUGH*/
-
-      case PDKIM_HDR_TAG:
-       if (c >= 'a' && c <= 'z')
-         cur_tag = string_catn(cur_tag, &ts, &tl, p, 1);
-
-       if (c == '=')
-         {
-         cur_tag[tl] = '\0';
-         where = PDKIM_HDR_VALUE;
-         }
-       break;
-
-      case PDKIM_HDR_VALUE:
-       if (c == ';' || c == '\0')
-         {
-         if (tl && vl)
-           {
-           cur_val[vl] = '\0';
-           pdkim_strtrim(cur_val);
-           DEBUG(D_acl) debug_printf(" %s=%s\n", cur_tag, cur_val);
-
-           switch (cur_tag[0])
-             {
-             case 'v':
-               pub->version = string_copy(cur_val); break;
-             case 'h':
-             case 'k':
-/* This field appears to never be used. Also, unclear why
-a 'k' (key-type_ would go in this field name.  There is a field
-"keytype", also never used.
-               pub->hashes = string_copy(cur_val);
-*/
-               break;
-             case 'g':
-               pub->granularity = string_copy(cur_val); break;
-             case 'n':
-               pub->notes = pdkim_decode_qp(cur_val); break;
-             case 'p':
-               pdkim_decode_base64(US cur_val, &pub->key); break;
-             case 's':
-               pub->srvtype = string_copy(cur_val); break;
-             case 't':
-               if (Ustrchr(cur_val, 'y') != NULL) pub->testing = 1;
-               if (Ustrchr(cur_val, 's') != NULL) pub->no_subdomaining = 1;
+      case 'v': pub->version = val;                    break;
+      case 'h': pub->hashes = val;                     break;
+      case 'k': break;
+      case 'g': pub->granularity = val;                        break;
+      case 'n': pub->notes = pdkim_decode_qp(val);     break;
+      case 'p': pdkim_decode_base64(val, &pub->key);   break;
+      case 's': pub->srvtype = val;                    break;
+      case 't': if (Ustrchr(val, 'y')) pub->testing = 1;
+               if (Ustrchr(val, 's')) pub->no_subdomaining = 1;
                break;
-             default:
-               DEBUG(D_acl) debug_printf(" Unknown tag encountered\n");
-               break;
-             }
-           }
-         tl = 0;
-         vl = 0;
-         where = PDKIM_HDR_LIMBO;
-         }
-       else
-         cur_val = string_catn(cur_val, &vs, &vl, p, 1);
-       break;
+      default:  DEBUG(D_acl) debug_printf(" Unknown tag encountered\n"); break;
       }
-
-    if (c == '\0') break;
     }
+  }
 
 /* Set fallback defaults */
 if (!pub->version    ) pub->version     = string_copy(PDKIM_PUB_RECORD_VERSION);
-else if (Ustrcmp(pub->version, PDKIM_PUB_RECORD_VERSION) != 0) return NULL;
+else if (Ustrcmp(pub->version, PDKIM_PUB_RECORD_VERSION) != 0)
+  {
+  DEBUG(D_acl) debug_printf(" Bad v= field\n");
+  return NULL;
+  }
 
-if (!pub->granularity) pub->granularity = string_copy(US"*");
+if (!pub->granularity) pub->granularity = US"*";
 /*
-if (!pub->keytype    ) pub->keytype     = string_copy(US"rsa");
+if (!pub->keytype    ) pub->keytype     = US"rsa";
 */
-if (!pub->srvtype    ) pub->srvtype     = string_copy(US"*");
+if (!pub->srvtype    ) pub->srvtype     = US"*";
 
 /* p= is required */
 if (pub->key.data)
   return pub;
 
+DEBUG(D_acl) debug_printf(" Missing p= field\n");
 return NULL;
 }
 
 
 /* -------------------------------------------------------------------------- */
 
-static int
-pdkim_update_bodyhash(pdkim_ctx * ctx, const char * data, int len)
+/* Update the bodyhash for one sig, with some additional data.
+If we have to relax the data for this sig, return our copy of it. */
+
+/*XXX Currently we calculate a hash for each sig.  But it is possible
+that multi-signing will be wanted using different signing algos
+(rsa, ec) using the same hash and canonicalization.  Consider in future
+hanging the hash+cacnon from the ctx and only referencing from the sig,
+so that it can be calculated only once - being over the body this
+caould be meagbytes, hence expensive. */
+
+static blob *
+pdkim_update_sig_bodyhash(pdkim_signature * sig, blob * orig_data, blob * relaxed_data)
 {
-pdkim_signature * sig;
-uschar * relaxed_data = NULL;  /* Cache relaxed version of data */
-int relaxed_len = 0;
+blob * canon_data = orig_data;
+/* Defaults to simple canon (no further treatment necessary) */
 
-/* Traverse all signatures, updating their hashes. */
-for (sig = ctx->sig; sig; sig = sig->next)
+if (sig->canon_body == PDKIM_CANON_RELAXED)
   {
-  /* Defaults to simple canon (no further treatment necessary) */
-  const uschar *canon_data = CUS data;
-  int           canon_len = len;
-
-  if (sig->canon_body == PDKIM_CANON_RELAXED)
+  /* Relax the line if not done already */
+  if (!relaxed_data)
     {
-    /* Relax the line if not done already */
-    if (!relaxed_data)
-      {
-      BOOL seen_wsp = FALSE;
-      const char *p;
-      int q = 0;
+    BOOL seen_wsp = FALSE;
+    const uschar * p;
+    int q = 0;
 
-      /* We want to be able to free this else we allocate
-      for the entire message which could be many MB. Since
-      we don't know what allocations the SHA routines might
-      do, not safe to use store_get()/store_reset(). */
+    /* We want to be able to free this else we allocate
+    for the entire message which could be many MB. Since
+    we don't know what allocations the SHA routines might
+    do, not safe to use store_get()/store_reset(). */
 
-      relaxed_data = store_malloc(len+1);
+    relaxed_data = store_malloc(sizeof(blob) + orig_data->len+1);
+    relaxed_data->data = US (relaxed_data+1);
 
-      for (p = data; *p; p++)
-        {
-       char c = *p;
-       if (c == '\r')
-         {
-         if (q > 0 && relaxed_data[q-1] == ' ')
-           q--;
-         }
-       else if (c == '\t' || c == ' ')
-         {
-         c = ' '; /* Turns WSP into SP */
-         if (seen_wsp)
-           continue;
-         seen_wsp = TRUE;
-         }
-       else
-         seen_wsp = FALSE;
-       relaxed_data[q++] = c;
+    for (p = orig_data->data; *p; p++)
+      {
+      char c = *p;
+      if (c == '\r')
+       {
+       if (q > 0 && relaxed_data->data[q-1] == ' ')
+         q--;
        }
-      relaxed_data[q] = '\0';
-      relaxed_len = q;
+      else if (c == '\t' || c == ' ')
+       {
+       c = ' '; /* Turns WSP into SP */
+       if (seen_wsp)
+         continue;
+       seen_wsp = TRUE;
+       }
+      else
+       seen_wsp = FALSE;
+      relaxed_data->data[q++] = c;
       }
-    canon_data = relaxed_data;
-    canon_len  = relaxed_len;
+    relaxed_data->data[q] = '\0';
+    relaxed_data->len = q;
     }
+  canon_data = relaxed_data;
+  }
 
-  /* Make sure we don't exceed the to-be-signed body length */
-  if (  sig->bodylength >= 0
-     && sig->signed_body_bytes + (unsigned long)canon_len > sig->bodylength
-     )
-    canon_len = sig->bodylength - sig->signed_body_bytes;
+/* Make sure we don't exceed the to-be-signed body length */
+if (  sig->bodylength >= 0
+   && sig->signed_body_bytes + (unsigned long)canon_data->len > sig->bodylength
+   )
+  canon_data->len = sig->bodylength - sig->signed_body_bytes;
 
-  if (canon_len > 0)
-    {
-    exim_sha_update(&sig->body_hash_ctx, CUS canon_data, canon_len);
-    sig->signed_body_bytes += canon_len;
-    DEBUG(D_acl) pdkim_quoteprint(canon_data, canon_len);
-    }
+if (canon_data->len > 0)
+  {
+  exim_sha_update(&sig->body_hash_ctx, CUS canon_data->data, canon_data->len);
+  sig->signed_body_bytes += canon_data->len;
+  DEBUG(D_acl) pdkim_quoteprint(canon_data->data, canon_data->len);
   }
 
-if (relaxed_data) store_free(relaxed_data);
-return PDKIM_OK;
+return relaxed_data;
 }
 
 
 /* -------------------------------------------------------------------------- */
 
 static void
-pdkim_finish_bodyhash(pdkim_ctx *ctx)
+pdkim_finish_bodyhash(pdkim_ctx * ctx)
 {
-pdkim_signature *sig;
+pdkim_signature * sig;
 
 /* Traverse all signatures */
 for (sig = ctx->sig; sig; sig = sig->next)
@@ -792,8 +769,9 @@ for (sig = ctx->sig; sig; sig = sig->next)
   DEBUG(D_acl)
     {
     debug_printf("PDKIM [%s] Body bytes hashed: %lu\n"
-                "PDKIM [%s] Body hash computed: ",
-               sig->domain, sig->signed_body_bytes, sig->domain);
+                "PDKIM [%s] Body %s computed: ",
+               sig->domain, sig->signed_body_bytes,
+               sig->domain, pdkim_hashes[sig->hashtype].dkim_hashname);
     pdkim_hexprint(CUS bh.data, bh.len);
     }
 
@@ -832,10 +810,10 @@ for (sig = ctx->sig; sig; sig = sig->next)
 
 
 
-static int
+static void
 pdkim_body_complete(pdkim_ctx * ctx)
 {
-pdkim_signature * sig = ctx->sig;      /*XXX assumes only one sig */
+pdkim_signature * sig;
 
 /* In simple body mode, if any empty lines were buffered,
 replace with one. rfc 4871 3.4.3 */
@@ -843,15 +821,15 @@ replace with one. rfc 4871 3.4.3 */
 it indicates that all linebreaks should be buffered, including
 the one terminating a text line */
 
-if (  sig && sig->canon_body == PDKIM_CANON_SIMPLE
-   && sig->signed_body_bytes == 0
-   && ctx->num_buffered_crlf > 0
-   )
-  pdkim_update_bodyhash(ctx, "\r\n", 2);
+for (sig = ctx->sig; sig; sig = sig->next)
+  if (  sig->canon_body == PDKIM_CANON_SIMPLE
+     && sig->signed_body_bytes == 0
+     && sig->num_buffered_blanklines > 0
+     )
+    (void) pdkim_update_sig_bodyhash(sig, &lineending, NULL);
 
 ctx->flags |= PDKIM_SEEN_EOD;
 ctx->linebuf_offset = 0;
-return PDKIM_OK;
 }
 
 
@@ -859,70 +837,78 @@ return PDKIM_OK;
 /* -------------------------------------------------------------------------- */
 /* Call from pdkim_feed below for processing complete body lines */
 
-static int
-pdkim_bodyline_complete(pdkim_ctx *ctx)
+static void
+pdkim_bodyline_complete(pdkim_ctx * ctx)
 {
-char *p = ctx->linebuf;
-int   n = ctx->linebuf_offset;
-pdkim_signature *sig = ctx->sig;       /*XXX assumes only one sig */
+blob line = {.data = ctx->linebuf, .len = ctx->linebuf_offset};
+pdkim_signature * sig;
+blob * rnl = NULL;
+blob * rline = NULL;
 
 /* Ignore extra data if we've seen the end-of-data marker */
-if (ctx->flags & PDKIM_SEEN_EOD) goto BAIL;
+if (ctx->flags & PDKIM_SEEN_EOD) goto all_skip;
 
 /* We've always got one extra byte to stuff a zero ... */
-ctx->linebuf[ctx->linebuf_offset] = '\0';
+ctx->linebuf[line.len] = '\0';
 
 /* Terminate on EOD marker */
 if (ctx->flags & PDKIM_DOT_TERM)
   {
-  if (memcmp(p, ".\r\n", 3) == 0)
-    return pdkim_body_complete(ctx);
+  if (memcmp(line.data, ".\r\n", 3) == 0)
+    { pdkim_body_complete(ctx); return; }
 
   /* Unstuff dots */
-  if (memcmp(p, "..", 2) == 0)
-    {
-    p++;
-    n--;
-    }
+  if (memcmp(line.data, "..", 2) == 0)
+    { line.data++; line.len--; }
   }
 
 /* Empty lines need to be buffered until we find a non-empty line */
-if (memcmp(p, "\r\n", 2) == 0)
+if (memcmp(line.data, "\r\n", 2) == 0)
   {
-  ctx->num_buffered_crlf++;
-  goto BAIL;
+  for (sig = ctx->sig; sig; sig = sig->next) sig->num_buffered_blanklines++;
+  goto all_skip;
   }
 
-if (sig && sig->canon_body == PDKIM_CANON_RELAXED)
+/* Process line for each sig separately */
+for (sig = ctx->sig; sig; sig = sig->next)
   {
-  /* Lines with just spaces need to be buffered too */
-  char *check = p;
-  while (memcmp(check, "\r\n", 2) != 0)
+  if (sig->canon_body == PDKIM_CANON_RELAXED)
     {
-    char c = *check;
+    /* Lines with just spaces need to be buffered too */
+    uschar * cp = line.data;
+    char c;
+
+    while ((c = *cp))
+      {
+      if (c == '\r' && cp[1] == '\n') break;
+      if (c != ' ' && c != '\t') goto sig_process;
+      cp++;
+      }
 
-    if (c != '\t' && c != ' ')
-      goto PROCESS;
-    check++;
+    sig->num_buffered_blanklines++;
+    goto sig_skip;
     }
 
-  ctx->num_buffered_crlf++;
-  goto BAIL;
-}
+sig_process:
+  /* At this point, we have a non-empty line, so release the buffered ones. */
 
-PROCESS:
-/* At this point, we have a non-empty line, so release the buffered ones. */
-while (ctx->num_buffered_crlf)
-  {
-  pdkim_update_bodyhash(ctx, "\r\n", 2);
-  ctx->num_buffered_crlf--;
+  while (sig->num_buffered_blanklines)
+    {
+    rnl = pdkim_update_sig_bodyhash(sig, &lineending, rnl);
+    sig->num_buffered_blanklines--;
+    }
+
+  rline = pdkim_update_sig_bodyhash(sig, &line, rline);
+sig_skip: ;
   }
 
-pdkim_update_bodyhash(ctx, p, n);
+if (rnl) store_free(rnl);
+if (rline) store_free(rline);
+
+all_skip:
 
-BAIL:
 ctx->linebuf_offset = 0;
-return PDKIM_OK;
+return;
 }
 
 
@@ -999,7 +985,7 @@ return PDKIM_OK;
 #define HEADER_BUFFER_FRAG_SIZE 256
 
 DLLEXPORT int
-pdkim_feed(pdkim_ctx *ctx, char *data, int len)
+pdkim_feed(pdkim_ctx * ctx, uschar * data, int len)
 {
 int p, rc;
 
@@ -1027,8 +1013,7 @@ else for (p = 0; p<len; p++)
     else if (c == '\n')
       {
       ctx->flags &= ~PDKIM_SEEN_CR;
-      if ((rc = pdkim_bodyline_complete(ctx)) != PDKIM_OK)
-       return rc;
+      pdkim_bodyline_complete(ctx);
       }
 
     if (ctx->linebuf_offset == PDKIM_MAX_BODY_LINE_LEN-1)
@@ -1208,7 +1193,7 @@ return str;
 /* -------------------------------------------------------------------------- */
 
 static uschar *
-pdkim_create_header(pdkim_signature *sig, BOOL final)
+pdkim_create_header(pdkim_signature * sig, BOOL final)
 {
 uschar * base64_bh;
 uschar * base64_b;
@@ -1229,7 +1214,7 @@ col = hdr_len;
 
 /* Required and static bits */
 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"a=",
-                   pdkim_algos[sig->algo]);
+                   dkim_sig_to_a_tag(sig));
 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"q=",
                    pdkim_querymethods[sig->querymethod]);
 hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"c=",
@@ -1297,11 +1282,23 @@ if (sig->bodylength >= 0)
   }
 
 /* Preliminary or final version? */
-base64_b = final ? pdkim_encode_base64(&sig->sighash) : US"";
-hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"b=", base64_b);
+if (final)
+  {
+  base64_b = pdkim_encode_base64(&sig->sighash);
+  hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"b=", base64_b);
 
-/* add trailing semicolon: I'm not sure if this is actually needed */
-hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, NULL, US";", US"");
+  /* add trailing semicolon: I'm not sure if this is actually needed */
+  hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, NULL, US";", US"");
+  }
+else
+  {
+  /* To satisfy the rule "all surrounding whitespace [...] deleted"
+  ( RFC 6376 section 3.7 ) we ensure there is no whitespace here.  Otherwise
+  the headcat routine could insert a linebreak which the relaxer would reduce
+  to a single space preceding the terminating semicolon, resulting in an
+  incorrect header-hash. */
+  hdr = pdkim_headcat(&col, hdr, &hdr_size, &hdr_len, US";", US"b=;", US"");
+  }
 
 hdr[hdr_len] = '\0';
 return hdr;
@@ -1337,7 +1334,9 @@ DEBUG(D_acl)
   {
   debug_printf(
     "PDKIM >> Parsing public key record >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"
-    " Raw record: ");
+    " %s\n"
+    " Raw record: ",
+    dns_txt_name);
   pdkim_quoteprint(CUS dns_txt_reply, Ustrlen(dns_txt_reply));
   }
 
@@ -1364,7 +1363,7 @@ DEBUG(D_acl) debug_printf(
       "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
 
 /* Import public key */
-if ((*errstr = exim_rsa_verify_init(&p->key, vctx)))
+if ((*errstr = exim_dkim_verify_init(&p->key, vctx)))
   {
   DEBUG(D_acl) debug_printf("verify_init: %s\n", *errstr);
   sig->verify_status =      PDKIM_VERIFY_INVALID;
@@ -1382,16 +1381,22 @@ DLLEXPORT int
 pdkim_feed_finish(pdkim_ctx * ctx, pdkim_signature ** return_signatures,
   const uschar ** err)
 {
-pdkim_signature *sig = ctx->sig;
+pdkim_signature * sig;
 
 /* Check if we must still flush a (partial) header. If that is the
    case, the message has no body, and we must compute a body hash
    out of '<CR><LF>' */
 if (ctx->cur_header && ctx->cur_header_len)
   {
-  int rc = pdkim_header_complete(ctx);
-  if (rc != PDKIM_OK) return rc;
-  pdkim_update_bodyhash(ctx, "\r\n", 2);
+  blob * rnl = NULL;
+  int rc;
+
+  if ((rc = pdkim_header_complete(ctx)) != PDKIM_OK)
+    return rc;
+
+  for (sig = ctx->sig; sig; sig = sig->next)
+    rnl = pdkim_update_sig_bodyhash(sig, &lineending, rnl);
+  if (rnl) store_free(rnl);
   }
 else
   DEBUG(D_acl) debug_printf(
@@ -1400,9 +1405,8 @@ else
 /* Build (and/or evaluate) body hash */
 pdkim_finish_bodyhash(ctx);
 
-while (sig)
+for (sig = ctx->sig; sig; sig = sig->next)
   {
-  BOOL is_sha1 = sig->algo == PDKIM_ALGO_RSA_SHA1;
   hctx hhash_ctx;
   uschar * sig_hdr = US"";
   blob hhash;
@@ -1412,14 +1416,22 @@ while (sig)
   hdata.data = NULL;
   hdata.len = 0;
 
-  if (!exim_sha_init(&hhash_ctx, is_sha1 ? HASH_SHA1 : HASH_SHA256))
+  if (!exim_sha_init(&hhash_ctx, pdkim_hashes[sig->hashtype].exim_hashmethod))
     {
-    DEBUG(D_acl) debug_printf("PDKIM: hask setup internal error\n");
+    DEBUG(D_acl)
+      debug_printf("PDKIM: hash setup error, possibly nonhandled hashtype\n");
     break;
     }
 
+  if (ctx->flags & PDKIM_MODE_SIGN)
+    DEBUG(D_acl) debug_printf(
+       "PDKIM >> Headers to be signed:                            >>>>>>>>>>>>\n"
+       " %s\n",
+       sig->sign_headers);
+
   DEBUG(D_acl) debug_printf(
-      "PDKIM >> Header data for hash, canonicalized, in sequence >>>>>>>>>>>>>>\n");
+      "PDKIM >> Header data for hash, canonicalized, in sequence >>>>>>>>>>>>\n");
+
 
   /* SIGNING ---------------------------------------------------------------- */
   /* When signing, walk through our header list and add them to the hash. As we
@@ -1429,49 +1441,43 @@ while (sig)
 
   if (ctx->flags & PDKIM_MODE_SIGN)
     {
-    uschar * headernames = NULL;       /* Collected signed header names */
     int hs = 0, hl = 0;
     pdkim_stringlist *p;
     const uschar * l;
     uschar * s;
     int sep = 0;
 
+    sig->headernames = NULL;           /* Collected signed header names */
+
     for (p = sig->headers; p; p = p->next)
-      if (header_name_match(p->value, sig->sign_headers) == PDKIM_OK)
+      {
+      uschar * rh = p->value;
+
+      if (header_name_match(rh, sig->sign_headers) == PDKIM_OK)
        {
-       uschar * rh;
        /* Collect header names (Note: colon presence is guaranteed here) */
-       uschar * q = Ustrchr(p->value, ':');
-
-       headernames = string_catn(headernames, &hs, &hl,
-                       p->value, (q - US p->value) + (p->next ? 1 : 0));
+       sig->headernames = string_append_listele_n(sig->headernames, &hs, &hl,
+                               ':', rh, Ustrchr(rh, ':') - rh);
 
-       rh = sig->canon_headers == PDKIM_CANON_RELAXED
-         ? pdkim_relax_header(p->value, 1) /* cook header for relaxed canon */
-         : string_copy(CUS p->value);      /* just copy it for simple canon */
+       if (sig->canon_headers == PDKIM_CANON_RELAXED)
+         rh = pdkim_relax_header(rh, TRUE);    /* cook header for relaxed canon */
 
        /* Feed header to the hash algorithm */
        exim_sha_update(&hhash_ctx, CUS rh, Ustrlen(rh));
 
        /* Remember headers block for signing (when the library cannot do incremental)  */
-       (void) exim_rsa_data_append(&hdata, &hdata_alloc, rh);
+       (void) exim_dkim_data_append(&hdata, &hdata_alloc, rh);
 
        DEBUG(D_acl) pdkim_quoteprint(rh, Ustrlen(rh));
        }
+      }
 
+    /* Any headers we wanted to sign but were not present must also be listed */
     l = sig->sign_headers;
     while((s = string_nextinlist(&l, &sep, NULL, 0)))
       if (*s != '_')
-       {                       /*SSS string_append_listele() */
-       if (hl > 0 && headernames[hl-1] != ':')
-         headernames = string_catn(headernames, &hs, &hl, US":", 1);
-
-       headernames = string_cat(headernames, &hs, &hl, s);
-       }
-    headernames[hl] = '\0';
-
-    /* Copy headernames to signature struct */
-    sig->headernames = headernames;
+       sig->headernames = string_append_listele(sig->headernames, &hs, &hl, ':', s);
+    sig->headernames[hl] = '\0';
 
     /* Create signature header with b= omitted */
     sig_hdr = pdkim_create_header(sig, FALSE);
@@ -1508,7 +1514,7 @@ while (sig)
            /* cook header for relaxed canon, or just copy it for simple  */
 
            uschar * rh = sig->canon_headers == PDKIM_CANON_RELAXED
-             ? pdkim_relax_header(hdrs->value, 1)
+             ? pdkim_relax_header(hdrs->value, TRUE)
              : string_copy(CUS hdrs->value);
 
            /* Feed header to the hash algorithm */
@@ -1530,9 +1536,18 @@ while (sig)
   DEBUG(D_acl) debug_printf(
            "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
 
+  DEBUG(D_acl)
+    {
+    debug_printf(
+           "PDKIM >> Signed DKIM-Signature header, pre-canonicalized >>>>>>>>>>>>>\n");
+    pdkim_quoteprint(CUS sig_hdr, Ustrlen(sig_hdr));
+    debug_printf(
+           "PDKIM <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
+    }
+
   /* Relax header if necessary */
   if (sig->canon_headers == PDKIM_CANON_RELAXED)
-    sig_hdr = pdkim_relax_header(sig_hdr, 0);
+    sig_hdr = pdkim_relax_header(sig_hdr, FALSE);
 
   DEBUG(D_acl)
     {
@@ -1549,21 +1564,24 @@ while (sig)
 
   DEBUG(D_acl)
     {
-    debug_printf("PDKIM [%s] Header hash computed: ", sig->domain);
+    debug_printf("PDKIM [%s] Header %s computed: ",
+      sig->domain, pdkim_hashes[sig->hashtype].dkim_hashname);
     pdkim_hexprint(hhash.data, hhash.len);
     }
 
-  /* Remember headers block for signing (when the library cannot do incremental)  */
+  /* Remember headers block for signing (when the signing library cannot do
+  incremental)  */
   if (ctx->flags & PDKIM_MODE_SIGN)
-    (void) exim_rsa_data_append(&hdata, &hdata_alloc, US sig_hdr);
+    (void) exim_dkim_data_append(&hdata, &hdata_alloc, US sig_hdr);
 
   /* SIGNING ---------------------------------------------------------------- */
   if (ctx->flags & PDKIM_MODE_SIGN)
     {
     es_ctx sctx;
 
-    /* Import private key */
-    if ((*err = exim_rsa_signing_init(US sig->rsa_privkey, &sctx)))
+    /* Import private key, including the keytype */
+/*XXX extend for non-RSA algos */
+    if ((*err = exim_dkim_signing_init(US sig->privkey, &sctx)))
       {
       DEBUG(D_acl) debug_printf("signing_init: %s\n", *err);
       return PDKIM_ERR_RSA_PRIVKEY;
@@ -1573,11 +1591,14 @@ while (sig)
     calculated, with GnuTLS we have to sign an entire block of headers
     (due to available interfaces) and it recalculates the hash internally. */
 
-#if defined(RSA_OPENSSL) || defined(RSA_GCRYPT)
+#if defined(SIGN_OPENSSL) || defined(SIGN_GCRYPT)
     hdata = hhash;
 #endif
 
-    if ((*err = exim_rsa_sign(&sctx, is_sha1, &hdata, &sig->sighash)))
+/*XXX extend for non-RSA algos */
+    if ((*err = exim_dkim_sign(&sctx,
+                 pdkim_hashes[sig->hashtype].exim_hashmethod,
+                 &hdata, &sig->sighash)))
       {
       DEBUG(D_acl) debug_printf("signing: %s\n", *err);
       return PDKIM_ERR_RSA_SIGNING;
@@ -1596,7 +1617,6 @@ while (sig)
   else
     {
     ev_ctx vctx;
-    pdkim_pubkey * p;
 
     /* Make sure we have all required signature tags */
     if (!(  sig->domain        && *sig->domain
@@ -1604,7 +1624,8 @@ while (sig)
         && sig->headernames   && *sig->headernames
         && sig->bodyhash.data
         && sig->sighash.data
-        && sig->algo > -1
+        && sig->keytype >= 0
+        && sig->hashtype >= 0
         && sig->version
        ) )
       {
@@ -1629,11 +1650,41 @@ while (sig)
       goto NEXT_VERIFY;
       }
 
+    DEBUG(D_acl)
+      {
+      debug_printf( "PDKIM [%s] b from mail: ", sig->domain);
+      pdkim_hexprint(sig->sighash.data, sig->sighash.len);
+      }
+
     if (!(sig->pubkey = pdkim_key_from_dns(ctx, sig, &vctx, err)))
       goto NEXT_VERIFY;
 
+    /* If the pubkey limits to a list of specific hashes, ignore sigs that
+    do not have the hash part of the sig algorithm matching */
+
+    if (sig->pubkey->hashes)
+      {
+      const uschar * list = sig->pubkey->hashes, * ele;
+      int sep = ':';
+      while ((ele = string_nextinlist(&list, &sep, NULL, 0)))
+       if (Ustrcmp(ele, pdkim_hashes[sig->hashtype].dkim_hashname) == 0) break;
+      if (!ele)
+       {
+       DEBUG(D_acl) debug_printf("pubkey h=%s vs. sig a=%s_%s\n",
+         sig->pubkey->hashes,
+         pdkim_keytypes[sig->keytype],
+         pdkim_hashes[sig->hashtype].dkim_hashname);
+       sig->verify_status =      PDKIM_VERIFY_FAIL;
+       sig->verify_ext_status =  PDKIM_VERIFY_FAIL_SIG_ALGO_MISMATCH;
+       goto NEXT_VERIFY;
+       }
+      }
+
     /* Check the signature */
-    if ((*err = exim_rsa_verify(&vctx, is_sha1, &hhash, &sig->sighash)))
+/*XXX needs extension for non-RSA */
+    if ((*err = exim_dkim_verify(&vctx,
+                 pdkim_hashes[sig->hashtype].exim_hashmethod,
+                 &hhash, &sig->sighash)))
       {
       DEBUG(D_acl) debug_printf("headers verify: %s\n", *err);
       sig->verify_status =      PDKIM_VERIFY_FAIL;
@@ -1659,8 +1710,6 @@ NEXT_VERIFY:
        debug_printf("\n");
       }
     }
-
-  sig = sig->next;
   }
 
 /* If requested, set return pointer to signature(s) */
@@ -1691,40 +1740,45 @@ return ctx;
 
 /* -------------------------------------------------------------------------- */
 
-DLLEXPORT pdkim_ctx *
-pdkim_init_sign(char * domain, char * selector, char * rsa_privkey, int algo,
-  BOOL dot_stuffed, int(*dns_txt_callback)(char *, char *),
-  const uschar ** errstr)
+/*XXX ? needs extension to cover non-RSA algo?  */
+
+DLLEXPORT pdkim_signature *
+pdkim_init_sign(pdkim_ctx * ctx,
+  uschar * domain, uschar * selector, uschar * privkey,
+  uschar * hashname, const uschar ** errstr)
 {
-pdkim_ctx * ctx;
+int hashtype;
 pdkim_signature * sig;
 
-if (!domain || !selector || !rsa_privkey)
+if (!domain || !selector || !privkey)
   return NULL;
 
-ctx = store_get(sizeof(pdkim_ctx) + PDKIM_MAX_BODY_LINE_LEN + sizeof(pdkim_signature));
-memset(ctx, 0, sizeof(pdkim_ctx));
-
-ctx->flags = dot_stuffed ? PDKIM_MODE_SIGN | PDKIM_DOT_TERM : PDKIM_MODE_SIGN;
-ctx->linebuf = CS (ctx+1);
-
-DEBUG(D_acl) ctx->dns_txt_callback = dns_txt_callback;
+/* Allocate & init one signature struct */
 
-sig = (pdkim_signature *)(ctx->linebuf + PDKIM_MAX_BODY_LINE_LEN);
+sig = store_get(sizeof(pdkim_signature));
 memset(sig, 0, sizeof(pdkim_signature));
 
 sig->bodylength = -1;
-ctx->sig = sig;
 
 sig->domain = string_copy(US domain);
 sig->selector = string_copy(US selector);
-sig->rsa_privkey = string_copy(US rsa_privkey);
-sig->algo = algo;
+sig->privkey = string_copy(US privkey);
+/*XXX no keytype yet; comes from privkey */
 
-if (!exim_sha_init(&sig->body_hash_ctx,
-              algo == PDKIM_ALGO_RSA_SHA1 ? HASH_SHA1 : HASH_SHA256))
+for (hashtype = 0; hashtype < nelem(pdkim_hashes); hashtype++)
+  if (Ustrcmp(hashname, pdkim_hashes[hashtype].dkim_hashname) == 0)
+  { sig->hashtype = hashtype; break; }
+if (hashtype >= nelem(pdkim_hashes))
+  {
+  DEBUG(D_acl)
+    debug_printf("PDKIM: unrecognised hashname '%s'\n", hashname);
+  return NULL;
+  }
+
+if (!exim_sha_init(&sig->body_hash_ctx, pdkim_hashes[hashtype].exim_hashmethod))
   {
-  DEBUG(D_acl) debug_printf("PDKIM: hash setup internal error\n");
+  DEBUG(D_acl)
+    debug_printf("PDKIM: hash setup error, possibly nonhandled hashtype\n");
   return NULL;
   }
 
@@ -1733,29 +1787,27 @@ DEBUG(D_acl)
   pdkim_signature s = *sig;
   ev_ctx vctx;
 
-  debug_printf("PDKIM (checking verify key)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
+  debug_printf("PDKIM (checking verify key)>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
   if (!pdkim_key_from_dns(ctx, &s, &vctx, errstr))
     debug_printf("WARNING: bad dkim key in dns\n");
-  debug_printf("PDKIM (finished checking verify key)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
+  debug_printf("PDKIM (finished checking verify key)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
   }
-return ctx;
+return sig;
 }
 
 
 /* -------------------------------------------------------------------------- */
 
-DLLEXPORT int
-pdkim_set_optional(pdkim_ctx *ctx,
-                       char *sign_headers,
-                       char *identity,
+DLLEXPORT void
+pdkim_set_optional(pdkim_signature * sig,
+                       char * sign_headers,
+                       char * identity,
                        int canon_headers,
                        int canon_body,
                        long bodylength,
                        unsigned long created,
                        unsigned long expires)
 {
-pdkim_signature * sig = ctx->sig;
-
 if (identity)
   sig->identity = string_copy(US identity);
 
@@ -1768,14 +1820,26 @@ sig->bodylength = bodylength;
 sig->created = created;
 sig->expires = expires;
 
-return PDKIM_OK;
+return;
+}
+
+
+
+void
+pdkim_init_context(pdkim_ctx * ctx, BOOL dot_stuffed,
+  int(*dns_txt_callback)(char *, char *))
+{
+memset(ctx, 0, sizeof(pdkim_ctx));
+ctx->flags = dot_stuffed ? PDKIM_MODE_SIGN | PDKIM_DOT_TERM : PDKIM_MODE_SIGN;
+ctx->linebuf = store_get(PDKIM_MAX_BODY_LINE_LEN);
+DEBUG(D_acl) ctx->dns_txt_callback = dns_txt_callback;
 }
 
 
 void
 pdkim_init(void)
 {
-exim_rsa_init();
+exim_dkim_init();
 }
 
 
index 8c477f744cbd3f49b6ba0a7b05af71c15d27ba0d..e82f26c05a40d9e376369e63a9a24807c8ee3fda 100644 (file)
 
 #define PDKIM_VERIFY_FAIL_BODY                    1
 #define PDKIM_VERIFY_FAIL_MESSAGE                 2
-#define PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE   3
-#define PDKIM_VERIFY_INVALID_BUFFER_SIZE          4
-#define PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD     5
-#define PDKIM_VERIFY_INVALID_PUBKEY_IMPORT        6
-#define PDKIM_VERIFY_INVALID_SIGNATURE_ERROR      7
-#define PDKIM_VERIFY_INVALID_DKIM_VERSION         8
+#define PDKIM_VERIFY_FAIL_SIG_ALGO_MISMATCH      3
+#define PDKIM_VERIFY_INVALID_PUBKEY_UNAVAILABLE   4
+#define PDKIM_VERIFY_INVALID_BUFFER_SIZE          5
+#define PDKIM_VERIFY_INVALID_PUBKEY_DNSRECORD     6
+#define PDKIM_VERIFY_INVALID_PUBKEY_IMPORT        7
+#define PDKIM_VERIFY_INVALID_SIGNATURE_ERROR      8
+#define PDKIM_VERIFY_INVALID_DKIM_VERSION         9
 
 /* -------------------------------------------------------------------------- */
 /* Some parameter values */
 #define PDKIM_QUERYMETHOD_DNS_TXT 0
 
-#define PDKIM_ALGO_RSA_SHA256     0
-#define PDKIM_ALGO_RSA_SHA1       1
-
 #define PDKIM_CANON_SIMPLE        0
 #define PDKIM_CANON_RELAXED       1
 
-#define PDKIM_HASH_SHA256         0
-#define PDKIM_HASH_SHA1           1
+/*XXX change to enums */
+#define PDKIM_HASH_SHA256         1
 
 #define PDKIM_KEYTYPE_RSA         0
 
@@ -97,14 +95,14 @@ typedef struct sha2_context sha2_context;
 /* -------------------------------------------------------------------------- */
 /* Public key as (usually) fetched from DNS */
 typedef struct pdkim_pubkey {
-  uschar *version;                /* v=  */
-  uschar *granularity;            /* g=  */
+  const uschar * version;         /* v=  */
+  const uschar *granularity;      /* g=  */
 
+  const uschar * hashes;          /* h=  */
 #ifdef notdef
-  uschar *hashes;                 /* h=  */
   uschar *keytype;                /* k=  */
 #endif
-  uschar *srvtype;                /* s=  */
+  const uschar *srvtype;          /* s=  */
   uschar *notes;                  /* n=  */
 
   blob  key;                      /* p=  */
@@ -115,15 +113,15 @@ typedef struct pdkim_pubkey {
 /* -------------------------------------------------------------------------- */
 /* Signature as it appears in a DKIM-Signature header */
 typedef struct pdkim_signature {
+  struct pdkim_signature * next;
 
   /* Bits stored in a DKIM signature header --------------------------- */
 
   /* (v=) The version, as an integer. Currently, always "1" */
   int version;
 
-  /* (a=) The signature algorithm. Either PDKIM_ALGO_RSA_SHA256
-     or PDKIM_ALGO_RSA_SHA1 */
-  int algo;
+  int keytype; /* PDKIM_KEYTYPE_RSA */
+  int hashtype;        /* pdkim_hashes index */
 
   /* (c=x/) Header canonicalization method. Either PDKIM_CANON_SIMPLE
      or PDKIM_CANON_RELAXED */
@@ -169,7 +167,7 @@ typedef struct pdkim_signature {
   /* (bh=) Raw body hash data, along with its length in bytes */
   blob bodyhash;
 
-  /* Folded DKIM-Signature: header. Singing only, NULL for verifying.
+  /* Folded DKIM-Signature: header. Signing only, NULL for verifying.
      Ready for insertion into the message. Note: Folded using CRLFTB,
      but final line terminator is NOT included. Note2: This buffer is
      free()d when you call pdkim_free_ctx(). */
@@ -226,19 +224,17 @@ typedef struct pdkim_signature {
      Caution: is NULL if signing or if no record was retrieved. */
   pdkim_pubkey *pubkey;
 
-  /* Pointer to the next pdkim_signature signature. NULL if signing or if
-     this is the last signature. */
-  void *next;
-
   /* Properties below this point are used internally only ------------- */
 
   /* Per-signature helper variables ----------------------------------- */
   hctx         body_hash_ctx;
 
   unsigned long signed_body_bytes; /* How many body bytes we hashed     */
+  int num_buffered_blanklines;
   pdkim_stringlist *headers; /* Raw headers included in the sig         */
+
   /* Signing specific ------------------------------------------------- */
-  uschar * rsa_privkey;     /* Private RSA key                             */
+  uschar * privkey;         /* Private key                                 */
   uschar * sign_headers;    /* To-be-signed header names                   */
   uschar * rawsig_no_b_val; /* Original signature header w/o b= tag value. */
 } pdkim_signature;
@@ -266,9 +262,8 @@ typedef struct pdkim_ctx {
   uschar    *cur_header;
   int        cur_header_size;
   int        cur_header_len;
-  char      *linebuf;
+  uschar    *linebuf;
   int        linebuf_offset;
-  int        num_buffered_crlf;
   int        num_headers;
   pdkim_stringlist *headers; /* Raw headers for verification         */
 } pdkim_ctx;
@@ -285,21 +280,24 @@ extern "C" {
 
 void      pdkim_init         (void);
 
+void      pdkim_init_context (pdkim_ctx *, BOOL, int(*)(char *, char *));
+
 DLLEXPORT
-pdkim_ctx *pdkim_init_sign    (char *, char *, char *, int,
-                             BOOL, int(*)(char *, char *), const uschar **);
+pdkim_signature *pdkim_init_sign    (pdkim_ctx *,
+                              uschar *, uschar *, uschar *, uschar *,
+                              const uschar **);
 
 DLLEXPORT
 pdkim_ctx *pdkim_init_verify  (int(*)(char *, char *), BOOL);
 
 DLLEXPORT
-int        pdkim_set_optional (pdkim_ctx *, char *, char *,int, int,
+void       pdkim_set_optional (pdkim_signature *, char *, char *,int, int,
                                long,
                                unsigned long,
                                unsigned long);
 
 DLLEXPORT
-int        pdkim_feed         (pdkim_ctx *, char *, int);
+int        pdkim_feed         (pdkim_ctx *, uschar *, int);
 DLLEXPORT
 int        pdkim_feed_finish  (pdkim_ctx *, pdkim_signature **, const uschar **);
 
@@ -309,6 +307,8 @@ void       pdkim_free_ctx     (pdkim_ctx *);
 
 const uschar * pdkim_errstr(int);
 
+uschar *       dkim_sig_to_a_tag(const pdkim_signature * sig);
+
 #ifdef __cplusplus
 }
 #endif
index 143cd19dfc192d4c3330333edf576e838978f757..008f277b3fd13020e9820d558481008539c8d771 100644 (file)
 #include "../blob.h"
 #include "../hash.h"
 
-#ifdef RSA_OPENSSL
+#ifdef SIGN_OPENSSL
 # include <openssl/rsa.h>
 # include <openssl/ssl.h>
 # include <openssl/err.h>
-#elif defined(RSA_GNUTLS)
+#elif defined(SIGN_GNUTLS)
 # include <gnutls/gnutls.h>
 # include <gnutls/x509.h>
 #endif
diff --git a/src/src/pdkim/rsa.c b/src/src/pdkim/rsa.c
deleted file mode 100644 (file)
index 950c617..0000000
+++ /dev/null
@@ -1,679 +0,0 @@
-/*
- *  PDKIM - a RFC4871 (DKIM) implementation
- *
- *  Copyright (C) 2016  Exim maintainers
- *
- *  RSA signing/verification interface
- */
-
-#include "../exim.h"
-
-#ifndef DISABLE_DKIM   /* entire file */
-
-#ifndef SUPPORT_TLS
-# error Need SUPPORT_TLS for DKIM
-#endif
-
-#include "crypt_ver.h"
-#include "rsa.h"
-
-
-/******************************************************************************/
-#ifdef RSA_GNUTLS
-
-void
-exim_rsa_init(void)
-{
-}
-
-
-/* accumulate data (gnutls-only).  String to be appended must be nul-terminated. */
-blob *
-exim_rsa_data_append(blob * b, int * alloc, uschar * s)
-{
-int len = b->len;
-b->data = string_append(b->data, alloc, &len, 1, s);
-b->len = len;
-return b;
-}
-
-
-
-/* import private key from PEM string in memory.
-Return: NULL for success, or an error string */
-
-const uschar *
-exim_rsa_signing_init(uschar * privkey_pem, es_ctx * sign_ctx)
-{
-gnutls_datum_t k;
-int rc;
-
-k.data = privkey_pem;
-k.size = strlen(privkey_pem);
-
-if (  (rc = gnutls_x509_privkey_init(&sign_ctx->rsa)) != GNUTLS_E_SUCCESS
-   /*|| (rc = gnutls_x509_privkey_import(sign_ctx->rsa, &k,
-         GNUTLS_X509_FMT_PEM)) != GNUTLS_E_SUCCESS */
-   )
-  return gnutls_strerror(rc);
-
-if (  /* (rc = gnutls_x509_privkey_init(&sign_ctx->rsa)) != GNUTLS_E_SUCCESS
-   ||*/ (rc = gnutls_x509_privkey_import(sign_ctx->rsa, &k,
-         GNUTLS_X509_FMT_PEM)) != GNUTLS_E_SUCCESS
-   )
-  return gnutls_strerror(rc);
-
-return NULL;
-}
-
-
-
-/* allocate mem for signature (when signing) */
-/* sign data (gnutls_only)
-OR
-sign hash.
-
-Return: NULL for success, or an error string */
-
-const uschar *
-exim_rsa_sign(es_ctx * sign_ctx, BOOL is_sha1, blob * data, blob * sig)
-{
-gnutls_datum_t k;
-size_t sigsize = 0;
-int rc;
-const uschar * ret = NULL;
-
-/* Allocate mem for signature */
-k.data = data->data;
-k.size = data->len;
-(void) gnutls_x509_privkey_sign_data(sign_ctx->rsa,
-  is_sha1 ? GNUTLS_DIG_SHA1 : GNUTLS_DIG_SHA256,
-  0, &k, NULL, &sigsize);
-
-sig->data = store_get(sigsize);
-sig->len = sigsize;
-
-/* Do signing */
-if ((rc = gnutls_x509_privkey_sign_data(sign_ctx->rsa,
-           is_sha1 ? GNUTLS_DIG_SHA1 : GNUTLS_DIG_SHA256,
-           0, &k, sig->data, &sigsize)) != GNUTLS_E_SUCCESS
-   )
-  ret = gnutls_strerror(rc);
-
-gnutls_x509_privkey_deinit(sign_ctx->rsa);
-return ret;
-}
-
-
-
-/* import public key (from DER in memory)
-Return: NULL for success, or an error string */
-
-const uschar *
-exim_rsa_verify_init(blob * pubkey_der, ev_ctx * verify_ctx)
-{
-gnutls_datum_t k;
-int rc;
-const uschar * ret = NULL;
-
-gnutls_pubkey_init(&verify_ctx->rsa);
-
-k.data = pubkey_der->data;
-k.size = pubkey_der->len;
-
-if ((rc = gnutls_pubkey_import(verify_ctx->rsa, &k, GNUTLS_X509_FMT_DER))
-       != GNUTLS_E_SUCCESS)
-  ret = gnutls_strerror(rc);
-return ret;
-}
-
-
-/* verify signature (of hash)  (given pubkey & alleged sig)
-Return: NULL for success, or an error string */
-
-const uschar *
-exim_rsa_verify(ev_ctx * verify_ctx, BOOL is_sha1, blob * data_hash, blob * sig)
-{
-gnutls_datum_t k, s;
-int rc;
-const uschar * ret = NULL;
-
-k.data = data_hash->data;
-k.size = data_hash->len;
-s.data = sig->data;
-s.size = sig->len;
-if ((rc = gnutls_pubkey_verify_hash2(verify_ctx->rsa,
-           is_sha1 ? GNUTLS_SIGN_RSA_SHA1 : GNUTLS_SIGN_RSA_SHA256,
-           0, &k, &s)) < 0)
-  ret = gnutls_strerror(rc);
-
-gnutls_pubkey_deinit(verify_ctx->rsa);
-return ret;
-}
-
-
-
-
-#elif defined(RSA_GCRYPT)
-/******************************************************************************/
-
-
-/* Internal service routine:
-Read and move past an asn.1 header, checking class & tag,
-optionally returning the data-length */
-
-static int
-as_tag(blob * der, uschar req_cls, long req_tag, long * alen)
-{
-int rc;
-uschar tag_class;
-int taglen;
-long tag, len;
-
-/* debug_printf_indent("as_tag: %02x %02x %02x %02x\n",
-       der->data[0], der->data[1], der->data[2], der->data[3]); */
-
-if ((rc = asn1_get_tag_der(der->data++, der->len--, &tag_class, &taglen, &tag))
-    != ASN1_SUCCESS)
-  return rc;
-
-if (tag_class != req_cls || tag != req_tag) return ASN1_ELEMENT_NOT_FOUND;
-
-if ((len = asn1_get_length_der(der->data, der->len, &taglen)) < 0)
-  return ASN1_DER_ERROR;
-if (alen) *alen = len;
-
-/* debug_printf_indent("as_tag:  tlen %d dlen %d\n", taglen, (int)len); */
-
-der->data += taglen;
-der->len -= taglen;
-return rc;
-}
-
-/* Internal service routine:
-Read and move over an asn.1 integer, setting an MPI to the value
-*/
-
-static uschar *
-as_mpi(blob * der, gcry_mpi_t * mpi)
-{
-long alen;
-int rc;
-gcry_error_t gerr;
-
-/* integer; move past the header */
-if ((rc = as_tag(der, 0, ASN1_TAG_INTEGER, &alen)) != ASN1_SUCCESS)
-  return US asn1_strerror(rc);
-
-/* read to an MPI */
-if ((gerr = gcry_mpi_scan(mpi, GCRYMPI_FMT_STD, der->data, alen, NULL)))
-  return US gcry_strerror(gerr);
-
-/* move over the data */
-der->data += alen; der->len -= alen;
-return NULL;
-}
-
-
-
-void
-exim_rsa_init(void)
-{
-/* Version check should be the very first call because it
-makes sure that important subsystems are initialized. */
-if (!gcry_check_version (GCRYPT_VERSION))
-  {
-  fputs ("libgcrypt version mismatch\n", stderr);
-  exit (2);
-  }
-
-/* We don't want to see any warnings, e.g. because we have not yet
-parsed program options which might be used to suppress such
-warnings. */
-gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
-
-/* ... If required, other initialization goes here.  Note that the
-process might still be running with increased privileges and that
-the secure memory has not been initialized.  */
-
-/* Allocate a pool of 16k secure memory.  This make the secure memory
-available and also drops privileges where needed.  */
-gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
-
-/* It is now okay to let Libgcrypt complain when there was/is
-a problem with the secure memory. */
-gcry_control (GCRYCTL_RESUME_SECMEM_WARN);
-
-/* ... If required, other initialization goes here.  */
-
-/* Tell Libgcrypt that initialization has completed. */
-gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
-
-return;
-}
-
-
-
-
-/* Accumulate data (gnutls-only).
-String to be appended must be nul-terminated. */
-
-blob *
-exim_rsa_data_append(blob * b, int * alloc, uschar * s)
-{
-return b;      /*dummy*/
-}
-
-
-
-/* import private key from PEM string in memory.
-Return: NULL for success, or an error string */
-
-const uschar *
-exim_rsa_signing_init(uschar * privkey_pem, es_ctx * sign_ctx)
-{
-uschar * s1, * s2;
-blob der;
-long alen;
-int rc;
-
-/*
- *  RSAPrivateKey ::= SEQUENCE
- *      version           Version,
- *      modulus           INTEGER,  -- n
- *      publicExponent    INTEGER,  -- e
- *      privateExponent   INTEGER,  -- d
- *      prime1            INTEGER,  -- p
- *      prime2            INTEGER,  -- q
- *      exponent1         INTEGER,  -- d mod (p-1)
- *      exponent2         INTEGER,  -- d mod (q-1)
- *      coefficient       INTEGER,  -- (inverse of q) mod p
- *      otherPrimeInfos   OtherPrimeInfos OPTIONAL
- */
-if (  !(s1 = Ustrstr(CS privkey_pem, "-----BEGIN RSA PRIVATE KEY-----"))
-   || !(s2 = Ustrstr(CS (s1+=31),    "-----END RSA PRIVATE KEY-----" ))
-   )
-  return US"Bad PEM wrapper";
-
-*s2 = '\0';
-
-if ((der.len = b64decode(s1, &der.data)) < 0)
-  return US"Bad PEM-DER b64 decode";
-
-/* untangle asn.1 */
-
-/* sequence; just move past the header */
-if ((rc = as_tag(&der, ASN1_CLASS_STRUCTURED, ASN1_TAG_SEQUENCE, NULL))
-   != ASN1_SUCCESS) goto asn_err;
-
-/* integer version; move past the header, check is zero */
-if ((rc = as_tag(&der, 0, ASN1_TAG_INTEGER, &alen)) != ASN1_SUCCESS)
-  goto asn_err;
-if (alen != 1 || *der.data != 0)
-  return US"Bad version number";
-der.data++; der.len--;
-
-if (  (s1 = as_mpi(&der, &sign_ctx->n))
-   || (s1 = as_mpi(&der, &sign_ctx->e))
-   || (s1 = as_mpi(&der, &sign_ctx->d))
-   || (s1 = as_mpi(&der, &sign_ctx->p))
-   || (s1 = as_mpi(&der, &sign_ctx->q))
-   || (s1 = as_mpi(&der, &sign_ctx->dp))
-   || (s1 = as_mpi(&der, &sign_ctx->dq))
-   || (s1 = as_mpi(&der, &sign_ctx->qp))
-   )
-  return s1;
-
-DEBUG(D_acl) debug_printf_indent("rsa_signing_init:\n");
-  {
-  uschar * s;
-  gcry_mpi_aprint (GCRYMPI_FMT_HEX, &s, NULL, sign_ctx->n);
-  debug_printf_indent(" N : %s\n", s);
-  gcry_mpi_aprint (GCRYMPI_FMT_HEX, &s, NULL, sign_ctx->e);
-  debug_printf_indent(" E : %s\n", s);
-  gcry_mpi_aprint (GCRYMPI_FMT_HEX, &s, NULL, sign_ctx->d);
-  debug_printf_indent(" D : %s\n", s);
-  gcry_mpi_aprint (GCRYMPI_FMT_HEX, &s, NULL, sign_ctx->p);
-  debug_printf_indent(" P : %s\n", s);
-  gcry_mpi_aprint (GCRYMPI_FMT_HEX, &s, NULL, sign_ctx->q);
-  debug_printf_indent(" Q : %s\n", s);
-  gcry_mpi_aprint (GCRYMPI_FMT_HEX, &s, NULL, sign_ctx->dp);
-  debug_printf_indent(" DP: %s\n", s);
-  gcry_mpi_aprint (GCRYMPI_FMT_HEX, &s, NULL, sign_ctx->dq);
-  debug_printf_indent(" DQ: %s\n", s);
-  gcry_mpi_aprint (GCRYMPI_FMT_HEX, &s, NULL, sign_ctx->qp);
-  debug_printf_indent(" QP: %s\n", s);
-  }
-return NULL;
-
-asn_err: return US asn1_strerror(rc);
-}
-
-
-
-/* allocate mem for signature (when signing) */
-/* sign data (gnutls_only)
-OR
-sign hash.
-
-Return: NULL for success, or an error string */
-
-const uschar *
-exim_rsa_sign(es_ctx * sign_ctx, BOOL is_sha1, blob * data, blob * sig)
-{
-gcry_sexp_t s_hash = NULL, s_key = NULL, s_sig = NULL;
-gcry_mpi_t m_sig;
-uschar * errstr;
-gcry_error_t gerr;
-
-#define SIGSPACE 128
-sig->data = store_get(SIGSPACE);
-
-if (gcry_mpi_cmp (sign_ctx->p, sign_ctx->q) > 0)
-  {
-  gcry_mpi_swap (sign_ctx->p, sign_ctx->q);
-  gcry_mpi_invm (sign_ctx->qp, sign_ctx->p, sign_ctx->q);
-  }
-
-if (  (gerr = gcry_sexp_build (&s_key, NULL,
-               "(private-key (rsa (n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
-               sign_ctx->n, sign_ctx->e,
-               sign_ctx->d, sign_ctx->p,
-               sign_ctx->q, sign_ctx->qp))
-   || (gerr = gcry_sexp_build (&s_hash, NULL,
-               is_sha1
-               ? "(data(flags pkcs1)(hash sha1 %b))"
-               : "(data(flags pkcs1)(hash sha256 %b))",
-               (int) data->len, CS data->data))
-   ||  (gerr = gcry_pk_sign (&s_sig, s_hash, s_key))
-   )
-  return US gcry_strerror(gerr);
-
-/* gcry_sexp_dump(s_sig); */
-
-if (  !(s_sig = gcry_sexp_find_token(s_sig, "s", 0))
-   )
-  return US"no sig result";
-
-m_sig = gcry_sexp_nth_mpi(s_sig, 1, GCRYMPI_FMT_USG);
-
-DEBUG(D_acl)
-  {
-  uschar * s;
-  gcry_mpi_aprint (GCRYMPI_FMT_HEX, &s, NULL, m_sig);
-  debug_printf_indent(" SG: %s\n", s);
-  }
-
-gerr = gcry_mpi_print(GCRYMPI_FMT_USG, sig->data, SIGSPACE, &sig->len, m_sig);
-if (gerr)
-  {
-  debug_printf_indent("signature conversion from MPI to buffer failed\n");
-  return US gcry_strerror(gerr);
-  }
-#undef SIGSPACE
-
-return NULL;
-}
-
-
-/* import public key (from DER in memory)
-Return: NULL for success, or an error string */
-
-const uschar *
-exim_rsa_verify_init(blob * pubkey_der, ev_ctx * verify_ctx)
-{
-/*
-in code sequence per b81207d2bfa92 rsa_parse_public_key() and asn1_get_mpi()
-*/
-uschar tag_class;
-int taglen;
-long alen;
-int rc;
-uschar * errstr;
-gcry_error_t gerr;
-uschar * stage = US"S1";
-
-/*
-sequence
- sequence
-  OBJECT:rsaEncryption
-  NULL
- BIT STRING:RSAPublicKey
-  sequence
-   INTEGER:Public modulus
-   INTEGER:Public exponent
-
-openssl rsa -in aux-fixed/dkim/dkim.private -pubout -outform DER | od -t x1 | head;
-openssl rsa -in aux-fixed/dkim/dkim.private -pubout | openssl asn1parse -dump;
-openssl rsa -in aux-fixed/dkim/dkim.private -pubout | openssl asn1parse -dump -offset 22;
-*/
-
-/* sequence; just move past the header */
-if ((rc = as_tag(pubkey_der, ASN1_CLASS_STRUCTURED, ASN1_TAG_SEQUENCE, NULL))
-   != ASN1_SUCCESS) goto asn_err;
-
-/* sequence; skip the entire thing */
-DEBUG(D_acl) stage = US"S2";
-if ((rc = as_tag(pubkey_der, ASN1_CLASS_STRUCTURED, ASN1_TAG_SEQUENCE, &alen))
-   != ASN1_SUCCESS) goto asn_err;
-pubkey_der->data += alen; pubkey_der->len -= alen;
-
-
-/* bitstring: limit range to size of bitstring;
-move over header + content wrapper */
-DEBUG(D_acl) stage = US"BS";
-if ((rc = as_tag(pubkey_der, 0, ASN1_TAG_BIT_STRING, &alen)) != ASN1_SUCCESS)
-  goto asn_err;
-pubkey_der->len = alen;
-pubkey_der->data++; pubkey_der->len--;
-
-/* sequence; just move past the header */
-DEBUG(D_acl) stage = US"S3";
-if ((rc = as_tag(pubkey_der, ASN1_CLASS_STRUCTURED, ASN1_TAG_SEQUENCE, NULL))
-   != ASN1_SUCCESS) goto asn_err;
-
-/* read two integers */
-DEBUG(D_acl) stage = US"MPI";
-if (  (errstr = as_mpi(pubkey_der, &verify_ctx->n))
-   || (errstr = as_mpi(pubkey_der, &verify_ctx->e))
-   )
-  return errstr;
-
-DEBUG(D_acl) debug_printf_indent("rsa_verify_init:\n");
-       {
-       uschar * s;
-       gcry_mpi_aprint (GCRYMPI_FMT_HEX, &s, NULL, verify_ctx->n);
-       debug_printf_indent(" N : %s\n", s);
-       gcry_mpi_aprint (GCRYMPI_FMT_HEX, &s, NULL, verify_ctx->e);
-       debug_printf_indent(" E : %s\n", s);
-       }
-
-return NULL;
-
-asn_err:
-DEBUG(D_acl) return string_sprintf("%s: %s", stage, asn1_strerror(rc));
-            return US asn1_strerror(rc);
-}
-
-
-/* verify signature (of hash)  (given pubkey & alleged sig)
-Return: NULL for success, or an error string */
-
-const uschar *
-exim_rsa_verify(ev_ctx * verify_ctx, BOOL is_sha1, blob * data_hash, blob * sig)
-{
-/*
-cf. libgnutls 2.8.5 _wrap_gcry_pk_verify()
-*/
-gcry_mpi_t m_sig;
-gcry_sexp_t s_sig = NULL, s_hash = NULL, s_pkey = NULL;
-gcry_error_t gerr;
-uschar * stage;
-
-if (  (stage = US"pkey sexp build",
-       gerr = gcry_sexp_build (&s_pkey, NULL, "(public-key(rsa(n%m)(e%m)))",
-                       verify_ctx->n, verify_ctx->e))
-   || (stage = US"data sexp build",
-       gerr = gcry_sexp_build (&s_hash, NULL,
-               is_sha1
-               ? "(data(flags pkcs1)(hash sha1 %b))"
-               : "(data(flags pkcs1)(hash sha256 %b))",
-               (int) data_hash->len, CS data_hash->data))
-   || (stage = US"sig mpi scan",
-       gerr = gcry_mpi_scan(&m_sig, GCRYMPI_FMT_USG, sig->data, sig->len, NULL))
-   || (stage = US"sig sexp build",
-       gerr = gcry_sexp_build (&s_sig, NULL, "(sig-val(rsa(s%m)))", m_sig))
-   || (stage = US"verify",
-       gerr = gcry_pk_verify (s_sig, s_hash, s_pkey))
-   )
-  {
-  DEBUG(D_acl) debug_printf_indent("verify: error in stage '%s'\n", stage);
-  return US gcry_strerror(gerr);
-  }
-
-if (s_sig) gcry_sexp_release (s_sig);
-if (s_hash) gcry_sexp_release (s_hash);
-if (s_pkey) gcry_sexp_release (s_pkey);
-gcry_mpi_release (m_sig);
-gcry_mpi_release (verify_ctx->n);
-gcry_mpi_release (verify_ctx->e);
-
-return NULL;
-}
-
-
-
-
-#elif defined(RSA_OPENSSL)
-/******************************************************************************/
-
-void
-exim_rsa_init(void)
-{
-}
-
-
-/* accumulate data (gnutls-only) */
-blob *
-exim_rsa_data_append(blob * b, int * alloc, uschar * s)
-{
-return b;      /*dummy*/
-}
-
-
-/* import private key from PEM string in memory.
-Return: NULL for success, or an error string */
-
-const uschar *
-exim_rsa_signing_init(uschar * privkey_pem, es_ctx * sign_ctx)
-{
-uschar * p, * q;
-int len;
-
-/* Convert PEM to DER */
-if (  !(p = Ustrstr(privkey_pem, "-----BEGIN RSA PRIVATE KEY-----"))
-   || !(q = Ustrstr(p+=31,       "-----END RSA PRIVATE KEY-----"))
-   )
-  return US"Bad PEM wrapping";
-
-*q = '\0';
-if ((len = b64decode(p, &p)) < 0)
-  return US"b64decode failed";
-
-if (!(sign_ctx->rsa = d2i_RSAPrivateKey(NULL, CUSS &p, len)))
-  {
-  char ssl_errstring[256];
-  ERR_load_crypto_strings();   /*XXX move to a startup routine */
-  ERR_error_string(ERR_get_error(), ssl_errstring);
-  return string_copy(US ssl_errstring);
-  }
-
-return NULL;
-}
-
-
-
-/* allocate mem for signature (when signing) */
-/* sign data (gnutls_only)
-OR
-sign hash.
-
-Return: NULL for success, or an error string */
-
-const uschar *
-exim_rsa_sign(es_ctx * sign_ctx, BOOL is_sha1, blob * data, blob * sig)
-{
-uint len;
-const uschar * ret = NULL;
-
-/* Allocate mem for signature */
-len = RSA_size(sign_ctx->rsa);
-sig->data = store_get(len);
-sig->len = len;
-
-/* Do signing */
-if (RSA_sign(is_sha1 ? NID_sha1 : NID_sha256,
-      CUS data->data, data->len,
-      US sig->data, &len, sign_ctx->rsa) != 1)
-  {
-  char ssl_errstring[256];
-  ERR_load_crypto_strings();   /*XXX move to a startup routine */
-  ERR_error_string(ERR_get_error(), ssl_errstring);
-  ret = string_copy(US ssl_errstring);
-  }
-
-RSA_free(sign_ctx->rsa);
-return ret;;
-}
-
-
-
-/* import public key (from DER in memory)
-Return: nULL for success, or an error string */
-
-const uschar *
-exim_rsa_verify_init(blob * pubkey_der, ev_ctx * verify_ctx)
-{
-const uschar * p = CUS pubkey_der->data;
-const uschar * ret = NULL;
-
-if (!(verify_ctx->rsa = d2i_RSA_PUBKEY(NULL, &p, (long) pubkey_der->len)))
-  {
-  char ssl_errstring[256];
-  ERR_load_crypto_strings();   /*XXX move to a startup routine */
-  ERR_error_string(ERR_get_error(), ssl_errstring);
-  ret = string_copy(CUS ssl_errstring);
-  }
-return ret;
-}
-
-
-
-
-/* verify signature (of hash)  (given pubkey & alleged sig)
-Return: NULL for success, or an error string */
-
-const uschar *
-exim_rsa_verify(ev_ctx * verify_ctx, BOOL is_sha1, blob * data_hash, blob * sig)
-{
-const uschar * ret = NULL;
-
-if (RSA_verify(is_sha1 ? NID_sha1 : NID_sha256,
-      CUS data_hash->data, data_hash->len,
-      US sig->data, (uint) sig->len, verify_ctx->rsa) != 1)
-  {
-  char ssl_errstring[256];
-  ERR_load_crypto_strings();   /*XXX move to a startup routine */
-  ERR_error_string(ERR_get_error(), ssl_errstring);
-  ret = string_copy(US ssl_errstring);
-  }
-return ret;
-}
-
-
-#endif
-/******************************************************************************/
-
-#endif /*DISABLE_DKIM*/
-/* End of File */
diff --git a/src/src/pdkim/rsa.h b/src/src/pdkim/rsa.h
deleted file mode 100644 (file)
index 6018eba..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- *  PDKIM - a RFC4871 (DKIM) implementation
- *
- *  Copyright (C) 2016  Exim maintainers
- *
- *  RSA signing/verification interface
- */
-
-#include "../exim.h"
-
-#ifndef DISABLE_DKIM   /* entire file */
-
-#include "crypt_ver.h"
-
-#ifdef RSA_OPENSSL
-# include <openssl/rsa.h>
-# include <openssl/ssl.h>
-# include <openssl/err.h>
-#elif defined(RSA_GNUTLS)
-# include <gnutls/gnutls.h>
-# include <gnutls/x509.h>
-#  include <gnutls/abstract.h>
-#elif defined(RSA_GCRYPT)
-#  include <gcrypt.h>
-#  include <libtasn1.h>
-#endif
-
-#include "../blob.h"
-
-
-#ifdef RSA_OPENSSL
-
-typedef struct {
-  RSA * rsa;
-} es_ctx;
-
-typedef struct {
-  RSA * rsa;
-} ev_ctx;
-
-#elif defined(RSA_GNUTLS)
-
-typedef struct {
-  gnutls_x509_privkey_t rsa;
-} es_ctx;
-
-typedef struct {
-  gnutls_pubkey_t rsa;
-} ev_ctx;
-
-#elif defined(RSA_GCRYPT)
-
-typedef struct {
-  gcry_mpi_t n;
-  gcry_mpi_t e;
-  gcry_mpi_t d;
-  gcry_mpi_t p;
-  gcry_mpi_t q;
-  gcry_mpi_t dp;
-  gcry_mpi_t dq;
-  gcry_mpi_t qp;
-} es_ctx;
-
-typedef struct {
-  gcry_mpi_t n;
-  gcry_mpi_t e;
-} ev_ctx;
-
-#endif
-
-
-extern void exim_rsa_init(void);
-extern blob * exim_rsa_data_append(blob *, int *, uschar *);
-
-extern const uschar * exim_rsa_signing_init(uschar *, es_ctx *);
-extern const uschar * exim_rsa_sign(es_ctx *, BOOL, blob *, blob *);
-extern const uschar * exim_rsa_verify_init(blob *, ev_ctx *);
-extern const uschar * exim_rsa_verify(ev_ctx *, BOOL, blob *, blob *);
-
-#endif /*DISABLE_DKIM*/
-/* End of File */
diff --git a/src/src/pdkim/signing.c b/src/src/pdkim/signing.c
new file mode 100644 (file)
index 0000000..e8cb297
--- /dev/null
@@ -0,0 +1,718 @@
+/*
+ *  PDKIM - a RFC4871 (DKIM) implementation
+ *
+ *  Copyright (C) 2016  Exim maintainers
+ *
+ *  signing/verification interface
+ */
+
+#include "../exim.h"
+
+#ifndef DISABLE_DKIM   /* entire file */
+
+#ifndef SUPPORT_TLS
+# error Need SUPPORT_TLS for DKIM
+#endif
+
+#include "crypt_ver.h"
+#include "signing.h"
+
+
+/******************************************************************************/
+#ifdef SIGN_GNUTLS
+
+void
+exim_dkim_init(void)
+{
+}
+
+
+/* accumulate data (gnutls-only).  String to be appended must be nul-terminated. */
+blob *
+exim_dkim_data_append(blob * b, int * alloc, uschar * s)
+{
+int len = b->len;
+b->data = string_append(b->data, alloc, &len, 1, s);
+b->len = len;
+return b;
+}
+
+
+
+/* import private key from PEM string in memory.
+Return: NULL for success, or an error string */
+
+const uschar *
+exim_dkim_signing_init(uschar * privkey_pem, es_ctx * sign_ctx)
+{
+gnutls_datum_t k;
+int rc;
+
+k.data = privkey_pem;
+k.size = strlen(privkey_pem);
+
+if (  (rc = gnutls_x509_privkey_init(&sign_ctx->key)) != GNUTLS_E_SUCCESS
+   || (rc = gnutls_x509_privkey_import(sign_ctx->key, &k,
+         GNUTLS_X509_FMT_PEM)) != GNUTLS_E_SUCCESS
+   )
+  return gnutls_strerror(rc);
+
+return NULL;
+}
+
+
+
+/* allocate mem for signature (when signing) */
+/* sign data (gnutls_only)
+OR
+sign hash.
+
+Return: NULL for success, or an error string */
+
+const uschar *
+exim_dkim_sign(es_ctx * sign_ctx, hashmethod hash, blob * data, blob * sig)
+{
+gnutls_digest_algorithm_t dig;
+gnutls_datum_t k;
+size_t sigsize = 0;
+int rc;
+const uschar * ret = NULL;
+
+switch (hash)
+  {
+  case HASH_SHA1:      dig = GNUTLS_DIG_SHA1; break;
+  case HASH_SHA2_256:  dig = GNUTLS_DIG_SHA256; break;
+  case HASH_SHA2_512:  dig = GNUTLS_DIG_SHA512; break;
+  default:             return US"nonhandled hash type";
+  }
+
+/* Allocate mem for signature */
+k.data = data->data;
+k.size = data->len;
+(void) gnutls_x509_privkey_sign_data(sign_ctx->key, dig,
+  0, &k, NULL, &sigsize);
+
+sig->data = store_get(sigsize);
+sig->len = sigsize;
+
+/* Do signing */
+if ((rc = gnutls_x509_privkey_sign_data(sign_ctx->key, dig,
+           0, &k, sig->data, &sigsize)) != GNUTLS_E_SUCCESS
+   )
+  ret = gnutls_strerror(rc);
+
+gnutls_x509_privkey_deinit(sign_ctx->key);
+return ret;
+}
+
+
+
+/* import public key (from DER in memory)
+Return: NULL for success, or an error string */
+
+const uschar *
+exim_dkim_verify_init(blob * pubkey_der, ev_ctx * verify_ctx)
+{
+gnutls_datum_t k;
+int rc;
+const uschar * ret = NULL;
+
+gnutls_pubkey_init(&verify_ctx->key);
+
+k.data = pubkey_der->data;
+k.size = pubkey_der->len;
+
+if ((rc = gnutls_pubkey_import(verify_ctx->key, &k, GNUTLS_X509_FMT_DER))
+       != GNUTLS_E_SUCCESS)
+  ret = gnutls_strerror(rc);
+return ret;
+}
+
+
+/* verify signature (of hash)  (given pubkey & alleged sig)
+Return: NULL for success, or an error string */
+
+const uschar *
+exim_dkim_verify(ev_ctx * verify_ctx, hashmethod hash, blob * data_hash, blob * sig)
+{
+gnutls_sign_algorithm_t algo;
+gnutls_datum_t k, s;
+int rc;
+const uschar * ret = NULL;
+
+/*XXX needs extension for non-rsa */
+switch (hash)
+  {
+  case HASH_SHA1:      algo = GNUTLS_SIGN_RSA_SHA1;   break;
+  case HASH_SHA2_256:  algo = GNUTLS_SIGN_RSA_SHA256; break;
+  case HASH_SHA2_512:  algo = GNUTLS_SIGN_RSA_SHA512; break;
+  default:             return US"nonhandled hash type";
+  }
+
+k.data = data_hash->data;
+k.size = data_hash->len;
+s.data = sig->data;
+s.size = sig->len;
+if ((rc = gnutls_pubkey_verify_hash2(verify_ctx->key, algo, 0, &k, &s)) < 0)
+  ret = gnutls_strerror(rc);
+
+gnutls_pubkey_deinit(verify_ctx->key);
+return ret;
+}
+
+
+
+
+#elif defined(SIGN_GCRYPT)
+/******************************************************************************/
+/* This variant is used under pre-3.0.0 GnuTLS.  Only rsa-sha1 and rsa-sha256 */
+
+
+/* Internal service routine:
+Read and move past an asn.1 header, checking class & tag,
+optionally returning the data-length */
+
+static int
+as_tag(blob * der, uschar req_cls, long req_tag, long * alen)
+{
+int rc;
+uschar tag_class;
+int taglen;
+long tag, len;
+
+/* debug_printf_indent("as_tag: %02x %02x %02x %02x\n",
+       der->data[0], der->data[1], der->data[2], der->data[3]); */
+
+if ((rc = asn1_get_tag_der(der->data++, der->len--, &tag_class, &taglen, &tag))
+    != ASN1_SUCCESS)
+  return rc;
+
+if (tag_class != req_cls || tag != req_tag) return ASN1_ELEMENT_NOT_FOUND;
+
+if ((len = asn1_get_length_der(der->data, der->len, &taglen)) < 0)
+  return ASN1_DER_ERROR;
+if (alen) *alen = len;
+
+/* debug_printf_indent("as_tag:  tlen %d dlen %d\n", taglen, (int)len); */
+
+der->data += taglen;
+der->len -= taglen;
+return rc;
+}
+
+/* Internal service routine:
+Read and move over an asn.1 integer, setting an MPI to the value
+*/
+
+static uschar *
+as_mpi(blob * der, gcry_mpi_t * mpi)
+{
+long alen;
+int rc;
+gcry_error_t gerr;
+
+/* integer; move past the header */
+if ((rc = as_tag(der, 0, ASN1_TAG_INTEGER, &alen)) != ASN1_SUCCESS)
+  return US asn1_strerror(rc);
+
+/* read to an MPI */
+if ((gerr = gcry_mpi_scan(mpi, GCRYMPI_FMT_STD, der->data, alen, NULL)))
+  return US gcry_strerror(gerr);
+
+/* move over the data */
+der->data += alen; der->len -= alen;
+return NULL;
+}
+
+
+
+void
+exim_dkim_init(void)
+{
+/* Version check should be the very first call because it
+makes sure that important subsystems are initialized. */
+if (!gcry_check_version (GCRYPT_VERSION))
+  {
+  fputs ("libgcrypt version mismatch\n", stderr);
+  exit (2);
+  }
+
+/* We don't want to see any warnings, e.g. because we have not yet
+parsed program options which might be used to suppress such
+warnings. */
+gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
+
+/* ... If required, other initialization goes here.  Note that the
+process might still be running with increased privileges and that
+the secure memory has not been initialized.  */
+
+/* Allocate a pool of 16k secure memory.  This make the secure memory
+available and also drops privileges where needed.  */
+gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
+
+/* It is now okay to let Libgcrypt complain when there was/is
+a problem with the secure memory. */
+gcry_control (GCRYCTL_RESUME_SECMEM_WARN);
+
+/* ... If required, other initialization goes here.  */
+
+/* Tell Libgcrypt that initialization has completed. */
+gcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
+
+return;
+}
+
+
+
+
+/* Accumulate data (gnutls-only).
+String to be appended must be nul-terminated. */
+
+blob *
+exim_dkim_data_append(blob * b, int * alloc, uschar * s)
+{
+return b;      /*dummy*/
+}
+
+
+
+/* import private key from PEM string in memory.
+Return: NULL for success, or an error string */
+
+const uschar *
+exim_dkim_signing_init(uschar * privkey_pem, es_ctx * sign_ctx)
+{
+uschar * s1, * s2;
+blob der;
+long alen;
+int rc;
+
+/*XXX will need extension to _spot_ as well as handle a
+non-RSA key?  I think... */
+
+/*
+ *  RSAPrivateKey ::= SEQUENCE
+ *      version           Version,
+ *      modulus           INTEGER,  -- n
+ *      publicExponent    INTEGER,  -- e
+ *      privateExponent   INTEGER,  -- d
+ *      prime1            INTEGER,  -- p
+ *      prime2            INTEGER,  -- q
+ *      exponent1         INTEGER,  -- d mod (p-1)
+ *      exponent2         INTEGER,  -- d mod (q-1)
+ *      coefficient       INTEGER,  -- (inverse of q) mod p
+ *      otherPrimeInfos   OtherPrimeInfos OPTIONAL
+ */
+if (  !(s1 = Ustrstr(CS privkey_pem, "-----BEGIN RSA PRIVATE KEY-----"))
+   || !(s2 = Ustrstr(CS (s1+=31),    "-----END RSA PRIVATE KEY-----" ))
+   )
+  return US"Bad PEM wrapper";
+
+*s2 = '\0';
+
+if ((der.len = b64decode(s1, &der.data)) < 0)
+  return US"Bad PEM-DER b64 decode";
+
+/* untangle asn.1 */
+
+/* sequence; just move past the header */
+if ((rc = as_tag(&der, ASN1_CLASS_STRUCTURED, ASN1_TAG_SEQUENCE, NULL))
+   != ASN1_SUCCESS) goto asn_err;
+
+/* integer version; move past the header, check is zero */
+if ((rc = as_tag(&der, 0, ASN1_TAG_INTEGER, &alen)) != ASN1_SUCCESS)
+  goto asn_err;
+if (alen != 1 || *der.data != 0)
+  return US"Bad version number";
+der.data++; der.len--;
+
+if (  (s1 = as_mpi(&der, &sign_ctx->n))
+   || (s1 = as_mpi(&der, &sign_ctx->e))
+   || (s1 = as_mpi(&der, &sign_ctx->d))
+   || (s1 = as_mpi(&der, &sign_ctx->p))
+   || (s1 = as_mpi(&der, &sign_ctx->q))
+   || (s1 = as_mpi(&der, &sign_ctx->dp))
+   || (s1 = as_mpi(&der, &sign_ctx->dq))
+   || (s1 = as_mpi(&der, &sign_ctx->qp))
+   )
+  return s1;
+
+#ifdef extreme_debug
+DEBUG(D_acl) debug_printf_indent("rsa_signing_init:\n");
+  {
+  uschar * s;
+  gcry_mpi_aprint (GCRYMPI_FMT_HEX, &s, NULL, sign_ctx->n);
+  debug_printf_indent(" N : %s\n", s);
+  gcry_mpi_aprint (GCRYMPI_FMT_HEX, &s, NULL, sign_ctx->e);
+  debug_printf_indent(" E : %s\n", s);
+  gcry_mpi_aprint (GCRYMPI_FMT_HEX, &s, NULL, sign_ctx->d);
+  debug_printf_indent(" D : %s\n", s);
+  gcry_mpi_aprint (GCRYMPI_FMT_HEX, &s, NULL, sign_ctx->p);
+  debug_printf_indent(" P : %s\n", s);
+  gcry_mpi_aprint (GCRYMPI_FMT_HEX, &s, NULL, sign_ctx->q);
+  debug_printf_indent(" Q : %s\n", s);
+  gcry_mpi_aprint (GCRYMPI_FMT_HEX, &s, NULL, sign_ctx->dp);
+  debug_printf_indent(" DP: %s\n", s);
+  gcry_mpi_aprint (GCRYMPI_FMT_HEX, &s, NULL, sign_ctx->dq);
+  debug_printf_indent(" DQ: %s\n", s);
+  gcry_mpi_aprint (GCRYMPI_FMT_HEX, &s, NULL, sign_ctx->qp);
+  debug_printf_indent(" QP: %s\n", s);
+  }
+#endif
+return NULL;
+
+asn_err: return US asn1_strerror(rc);
+}
+
+
+
+/* allocate mem for signature (when signing) */
+/* sign data (gnutls_only)
+OR
+sign hash.
+
+Return: NULL for success, or an error string */
+
+const uschar *
+exim_dkim_sign(es_ctx * sign_ctx, hashmethod hash, blob * data, blob * sig)
+{
+char * sexp_hash;
+gcry_sexp_t s_hash = NULL, s_key = NULL, s_sig = NULL;
+gcry_mpi_t m_sig;
+uschar * errstr;
+gcry_error_t gerr;
+
+/*XXX will need extension for hash types (though, possibly, should
+be re-specced to not rehash but take an already-hashed value? Actually
+current impl looks WRONG - it _is_ given a hash so should not be
+re-hashing.  Has this been tested?
+
+Will need extension for non-RSA sugning algos. */
+
+switch (hash)
+  {
+  case HASH_SHA1:      sexp_hash = "(data(flags pkcs1)(hash sha1 %b))"; break;
+  case HASH_SHA2_256:  sexp_hash = "(data(flags pkcs1)(hash sha256 %b))"; break;
+  default:             return US"nonhandled hash type";
+  }
+
+#define SIGSPACE 128
+sig->data = store_get(SIGSPACE);
+
+if (gcry_mpi_cmp (sign_ctx->p, sign_ctx->q) > 0)
+  {
+  gcry_mpi_swap (sign_ctx->p, sign_ctx->q);
+  gcry_mpi_invm (sign_ctx->qp, sign_ctx->p, sign_ctx->q);
+  }
+
+if (  (gerr = gcry_sexp_build (&s_key, NULL,
+               "(private-key (rsa (n%m)(e%m)(d%m)(p%m)(q%m)(u%m)))",
+               sign_ctx->n, sign_ctx->e,
+               sign_ctx->d, sign_ctx->p,
+               sign_ctx->q, sign_ctx->qp))
+   || (gerr = gcry_sexp_build (&s_hash, NULL, sexp_hash,
+               (int) data->len, CS data->data))
+   ||  (gerr = gcry_pk_sign (&s_sig, s_hash, s_key))
+   )
+  return US gcry_strerror(gerr);
+
+/* gcry_sexp_dump(s_sig); */
+
+if (  !(s_sig = gcry_sexp_find_token(s_sig, "s", 0))
+   )
+  return US"no sig result";
+
+m_sig = gcry_sexp_nth_mpi(s_sig, 1, GCRYMPI_FMT_USG);
+
+#ifdef extreme_debug
+DEBUG(D_acl)
+  {
+  uschar * s;
+  gcry_mpi_aprint (GCRYMPI_FMT_HEX, &s, NULL, m_sig);
+  debug_printf_indent(" SG: %s\n", s);
+  }
+#endif
+
+gerr = gcry_mpi_print(GCRYMPI_FMT_USG, sig->data, SIGSPACE, &sig->len, m_sig);
+if (gerr)
+  {
+  debug_printf_indent("signature conversion from MPI to buffer failed\n");
+  return US gcry_strerror(gerr);
+  }
+#undef SIGSPACE
+
+return NULL;
+}
+
+
+/* import public key (from DER in memory)
+Return: NULL for success, or an error string */
+
+const uschar *
+exim_dkim_verify_init(blob * pubkey_der, ev_ctx * verify_ctx)
+{
+/*
+in code sequence per b81207d2bfa92 rsa_parse_public_key() and asn1_get_mpi()
+*/
+uschar tag_class;
+int taglen;
+long alen;
+int rc;
+uschar * errstr;
+gcry_error_t gerr;
+uschar * stage = US"S1";
+
+/*
+sequence
+ sequence
+  OBJECT:rsaEncryption
+  NULL
+ BIT STRING:RSAPublicKey
+  sequence
+   INTEGER:Public modulus
+   INTEGER:Public exponent
+
+openssl rsa -in aux-fixed/dkim/dkim.private -pubout -outform DER | od -t x1 | head;
+openssl rsa -in aux-fixed/dkim/dkim.private -pubout | openssl asn1parse -dump;
+openssl rsa -in aux-fixed/dkim/dkim.private -pubout | openssl asn1parse -dump -offset 22;
+*/
+
+/* sequence; just move past the header */
+if ((rc = as_tag(pubkey_der, ASN1_CLASS_STRUCTURED, ASN1_TAG_SEQUENCE, NULL))
+   != ASN1_SUCCESS) goto asn_err;
+
+/* sequence; skip the entire thing */
+DEBUG(D_acl) stage = US"S2";
+if ((rc = as_tag(pubkey_der, ASN1_CLASS_STRUCTURED, ASN1_TAG_SEQUENCE, &alen))
+   != ASN1_SUCCESS) goto asn_err;
+pubkey_der->data += alen; pubkey_der->len -= alen;
+
+
+/* bitstring: limit range to size of bitstring;
+move over header + content wrapper */
+DEBUG(D_acl) stage = US"BS";
+if ((rc = as_tag(pubkey_der, 0, ASN1_TAG_BIT_STRING, &alen)) != ASN1_SUCCESS)
+  goto asn_err;
+pubkey_der->len = alen;
+pubkey_der->data++; pubkey_der->len--;
+
+/* sequence; just move past the header */
+DEBUG(D_acl) stage = US"S3";
+if ((rc = as_tag(pubkey_der, ASN1_CLASS_STRUCTURED, ASN1_TAG_SEQUENCE, NULL))
+   != ASN1_SUCCESS) goto asn_err;
+
+/* read two integers */
+DEBUG(D_acl) stage = US"MPI";
+if (  (errstr = as_mpi(pubkey_der, &verify_ctx->n))
+   || (errstr = as_mpi(pubkey_der, &verify_ctx->e))
+   )
+  return errstr;
+
+#ifdef extreme_debug
+DEBUG(D_acl) debug_printf_indent("rsa_verify_init:\n");
+       {
+       uschar * s;
+       gcry_mpi_aprint (GCRYMPI_FMT_HEX, &s, NULL, verify_ctx->n);
+       debug_printf_indent(" N : %s\n", s);
+       gcry_mpi_aprint (GCRYMPI_FMT_HEX, &s, NULL, verify_ctx->e);
+       debug_printf_indent(" E : %s\n", s);
+       }
+
+#endif
+return NULL;
+
+asn_err:
+DEBUG(D_acl) return string_sprintf("%s: %s", stage, asn1_strerror(rc));
+            return US asn1_strerror(rc);
+}
+
+
+/* verify signature (of hash)  (given pubkey & alleged sig)
+Return: NULL for success, or an error string */
+
+const uschar *
+exim_dkim_verify(ev_ctx * verify_ctx, hashmethod hash, blob * data_hash, blob * sig)
+{
+/*
+cf. libgnutls 2.8.5 _wrap_gcry_pk_verify()
+*/
+char * sexp_hash;
+gcry_mpi_t m_sig;
+gcry_sexp_t s_sig = NULL, s_hash = NULL, s_pkey = NULL;
+gcry_error_t gerr;
+uschar * stage;
+
+/*XXX needs extension for SHA512 */
+switch (hash)
+  {
+  case HASH_SHA1:     sexp_hash = "(data(flags pkcs1)(hash sha1 %b))"; break;
+  case HASH_SHA2_256: sexp_hash = "(data(flags pkcs1)(hash sha256 %b))"; break;
+  default:           return US"nonhandled hash type";
+  }
+
+if (  (stage = US"pkey sexp build",
+       gerr = gcry_sexp_build (&s_pkey, NULL, "(public-key(rsa(n%m)(e%m)))",
+                       verify_ctx->n, verify_ctx->e))
+   || (stage = US"data sexp build",
+       gerr = gcry_sexp_build (&s_hash, NULL, sexp_hash,
+               (int) data_hash->len, CS data_hash->data))
+   || (stage = US"sig mpi scan",
+       gerr = gcry_mpi_scan(&m_sig, GCRYMPI_FMT_USG, sig->data, sig->len, NULL))
+   || (stage = US"sig sexp build",
+       gerr = gcry_sexp_build (&s_sig, NULL, "(sig-val(rsa(s%m)))", m_sig))
+   || (stage = US"verify",
+       gerr = gcry_pk_verify (s_sig, s_hash, s_pkey))
+   )
+  {
+  DEBUG(D_acl) debug_printf_indent("verify: error in stage '%s'\n", stage);
+  return US gcry_strerror(gerr);
+  }
+
+if (s_sig) gcry_sexp_release (s_sig);
+if (s_hash) gcry_sexp_release (s_hash);
+if (s_pkey) gcry_sexp_release (s_pkey);
+gcry_mpi_release (m_sig);
+gcry_mpi_release (verify_ctx->n);
+gcry_mpi_release (verify_ctx->e);
+
+return NULL;
+}
+
+
+
+
+#elif defined(SIGN_OPENSSL)
+/******************************************************************************/
+
+void
+exim_dkim_init(void)
+{
+ERR_load_crypto_strings();
+}
+
+
+/* accumulate data (gnutls-only) */
+blob *
+exim_dkim_data_append(blob * b, int * alloc, uschar * s)
+{
+return b;      /*dummy*/
+}
+
+
+/* import private key from PEM string in memory.
+Return: NULL for success, or an error string */
+
+const uschar *
+exim_dkim_signing_init(uschar * privkey_pem, es_ctx * sign_ctx)
+{
+BIO * bp = BIO_new_mem_buf(privkey_pem, -1);
+
+if (!(sign_ctx->key = PEM_read_bio_PrivateKey(bp, NULL, NULL, NULL)))
+  return US ERR_error_string(ERR_get_error(), NULL);
+return NULL;
+}
+
+
+
+/* allocate mem for signature (when signing) */
+/* sign data (gnutls_only)
+OR
+sign hash.
+
+Return: NULL for success with the signaature in the sig blob, or an error string */
+
+const uschar *
+exim_dkim_sign(es_ctx * sign_ctx, hashmethod hash, blob * data, blob * sig)
+{
+const EVP_MD * md;
+EVP_PKEY_CTX * ctx;
+size_t siglen;
+
+switch (hash)
+  {
+  case HASH_SHA1:      md = EVP_sha1();   break;
+  case HASH_SHA2_256:  md = EVP_sha256(); break;
+  case HASH_SHA2_512:  md = EVP_sha512(); break;
+  default:             return US"nonhandled hash type";
+  }
+
+if (  (ctx = EVP_PKEY_CTX_new(sign_ctx->key, NULL))
+   && EVP_PKEY_sign_init(ctx) > 0
+   && EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) > 0
+   && EVP_PKEY_CTX_set_signature_md(ctx, md) > 0
+   && EVP_PKEY_sign(ctx, NULL, &siglen, data->data, data->len) > 0
+   )
+  {
+  /* Allocate mem for signature */
+  sig->data = store_get(siglen);
+
+  if (EVP_PKEY_sign(ctx, sig->data, &siglen, data->data, data->len) > 0)
+    {
+    EVP_PKEY_CTX_free(ctx);
+    sig->len = siglen;
+    return NULL;
+    }
+  }
+
+if (ctx) EVP_PKEY_CTX_free(ctx);
+return US ERR_error_string(ERR_get_error(), NULL);
+}
+
+
+
+/* import public key (from DER in memory)
+Return: NULL for success, or an error string */
+
+const uschar *
+exim_dkim_verify_init(blob * pubkey_der, ev_ctx * verify_ctx)
+{
+const uschar * s = pubkey_der->data;
+
+/*XXX hmm, we never free this */
+
+if ((verify_ctx->key = d2i_PUBKEY(NULL, &s, pubkey_der->len)))
+  return NULL;
+return US ERR_error_string(ERR_get_error(), NULL);
+}
+
+
+
+
+/* verify signature (of hash)  (given pubkey & alleged sig)
+Return: NULL for success, or an error string */
+
+const uschar *
+exim_dkim_verify(ev_ctx * verify_ctx, hashmethod hash, blob * data_hash, blob * sig)
+{
+const EVP_MD * md;
+EVP_PKEY_CTX * ctx;
+
+switch (hash)
+  {
+  case HASH_SHA1:      md = EVP_sha1();   break;
+  case HASH_SHA2_256:  md = EVP_sha256(); break;
+  case HASH_SHA2_512:  md = EVP_sha512(); break;
+  default:             return US"nonhandled hash type";
+  }
+
+if (  (ctx = EVP_PKEY_CTX_new(verify_ctx->key, NULL))
+   && EVP_PKEY_verify_init(ctx) > 0
+   && EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) > 0
+   && EVP_PKEY_CTX_set_signature_md(ctx, md) > 0
+   && EVP_PKEY_verify(ctx, sig->data, sig->len,
+       data_hash->data, data_hash->len) == 1
+   )
+  { EVP_PKEY_CTX_free(ctx); return NULL; }
+
+if (ctx) EVP_PKEY_CTX_free(ctx);
+return US ERR_error_string(ERR_get_error(), NULL);
+}
+
+
+
+#endif
+/******************************************************************************/
+
+#endif /*DISABLE_DKIM*/
+/* End of File */
diff --git a/src/src/pdkim/signing.h b/src/src/pdkim/signing.h
new file mode 100644 (file)
index 0000000..abf2559
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ *  PDKIM - a RFC4871 (DKIM) implementation
+ *
+ *  Copyright (C) 2016  Exim maintainers
+ *
+ *  RSA signing/verification interface
+ */
+
+#include "../exim.h"
+
+#ifndef DISABLE_DKIM   /* entire file */
+
+#include "crypt_ver.h"
+
+#ifdef SIGN_OPENSSL
+# include <openssl/rsa.h>
+# include <openssl/ssl.h>
+# include <openssl/err.h>
+#elif defined(SIGN_GNUTLS)
+# include <gnutls/gnutls.h>
+# include <gnutls/x509.h>
+#  include <gnutls/abstract.h>
+#elif defined(SIGN_GCRYPT)
+#  include <gcrypt.h>
+#  include <libtasn1.h>
+#endif
+
+#include "../blob.h"
+
+
+#ifdef SIGN_OPENSSL
+
+typedef struct {
+  EVP_PKEY * key;
+} es_ctx;
+
+typedef struct {
+  EVP_PKEY * key;
+} ev_ctx;
+
+#elif defined(SIGN_GNUTLS)
+
+typedef struct {
+  gnutls_x509_privkey_t key;
+} es_ctx;
+
+typedef struct {
+  gnutls_pubkey_t key;
+} ev_ctx;
+
+#elif defined(SIGN_GCRYPT)
+
+typedef struct {
+  int  keytype;
+  gcry_mpi_t n;
+  gcry_mpi_t e;
+  gcry_mpi_t d;
+  gcry_mpi_t p;
+  gcry_mpi_t q;
+  gcry_mpi_t dp;
+  gcry_mpi_t dq;
+  gcry_mpi_t qp;
+} es_ctx;
+
+typedef struct {
+  int  keytype;
+  gcry_mpi_t n;
+  gcry_mpi_t e;
+} ev_ctx;
+
+#endif
+
+
+extern void exim_dkim_init(void);
+extern blob * exim_dkim_data_append(blob *, int *, uschar *);
+
+extern const uschar * exim_dkim_signing_init(uschar *, es_ctx *);
+extern const uschar * exim_dkim_sign(es_ctx *, hashmethod, blob *, blob *);
+extern const uschar * exim_dkim_verify_init(blob *, ev_ctx *);
+extern const uschar * exim_dkim_verify(ev_ctx *, hashmethod, blob *, blob *);
+
+#endif /*DISABLE_DKIM*/
+/* End of File */
index 92218a6efb1e5d33ba9c5289dc53a9b7e9337a03..5f4f0d98dcad7699173bad27b5762d381047de77 100644 (file)
@@ -60,7 +60,7 @@ XS(xs_expand_string)
   str = expand_string(US SvPV(ST(0), len));
   ST(0) = sv_newmortal();
   if (str != NULL)
-    sv_setpv(ST(0), (const char *) str);
+    sv_setpv(ST(0), CCS  str);
   else if (!expand_string_forcedfail)
     croak("syntax error in Exim::expand_string argument: %s",
       expand_string_message);
index 50e4aaef34667e03f2cd4707058e6c1bfd0b3283..8b0494b269a7593c6f97c74446665fe3890e26b0 100644 (file)
@@ -405,28 +405,18 @@ if (!recurse)
   *p = 0;
 
   p = big_buffer;
-  sprintf(CS p, "pid=%d", (int)queue_run_pid);
-  while (*p != 0) p++;
+  p += sprintf(CS p, "pid=%d", (int)queue_run_pid);
 
   if (extras[0] != 0)
-    {
-    sprintf(CS p, " -q%s", extras);
-    while (*p != 0) p++;
-    }
+    p += sprintf(CS p, " -q%s", extras);
 
-  if (deliver_selectstring != NULL)
-    {
-    sprintf(CS p, " -R%s %s", deliver_selectstring_regex? "r" : "",
+  if (deliver_selectstring)
+    p += sprintf(CS p, " -R%s %s", deliver_selectstring_regex? "r" : "",
       deliver_selectstring);
-    while (*p != 0) p++;
-    }
 
-  if (deliver_selectstring_sender != NULL)
-    {
-    sprintf(CS p, " -S%s %s", deliver_selectstring_sender_regex? "r" : "",
+  if (deliver_selectstring_sender)
+    p += sprintf(CS p, " -S%s %s", deliver_selectstring_sender_regex? "r" : "",
       deliver_selectstring_sender);
-    while (*p != 0) p++;
-    }
 
   log_detail = string_copy(big_buffer);
   if (*queue_name)
@@ -438,10 +428,10 @@ if (!recurse)
 
 /* If deliver_selectstring is a regex, compile it. */
 
-if (deliver_selectstring != NULL && deliver_selectstring_regex)
+if (deliver_selectstring && deliver_selectstring_regex)
   selectstring_regex = regex_must_compile(deliver_selectstring, TRUE, FALSE);
 
-if (deliver_selectstring_sender != NULL && deliver_selectstring_sender_regex)
+if (deliver_selectstring_sender && deliver_selectstring_sender_regex)
   selectstring_regex_sender =
     regex_must_compile(deliver_selectstring_sender, TRUE, FALSE);
 
@@ -890,7 +880,7 @@ for (reset_point = store_get(0); f; f = f->next)
 
     if (Ustat(fname, &statbuf) == 0)
       size = message_size + statbuf.st_size - SPOOL_DATA_START_OFFSET + 1;
-    i = (now - received_time)/60;  /* minutes on queue */
+    i = (now - received_time.tv_sec)/60;  /* minutes on queue */
     if (i > 90)
       {
       i = (i + 30)/60;
@@ -1142,10 +1132,14 @@ if (action != MSG_SHOW_COPY) printf("Message %s ", id);
 switch(action)
   {
   case MSG_SHOW_COPY:
-  deliver_in_buffer = store_malloc(DELIVER_IN_BUFFER_SIZE);
-  deliver_out_buffer = store_malloc(DELIVER_OUT_BUFFER_SIZE);
-  transport_write_message(1, NULL, 0);
-  break;
+    {
+    transport_ctx tctx = {{0}};
+    deliver_in_buffer = store_malloc(DELIVER_IN_BUFFER_SIZE);
+    deliver_out_buffer = store_malloc(DELIVER_OUT_BUFFER_SIZE);
+    tctx.u.fd = 1;
+    transport_write_message(&tctx, 0);
+    break;
+    }
 
 
   case MSG_FREEZE:
index 995909b09258d053f2bc542d845da14d53a03c2c..fb3edac176f5a832bb0aa13924bb9fb0a72c2450 100644 (file)
@@ -715,30 +715,28 @@ if ((pid = fork()) == 0)
       yield == FF_FAIL || yield == FF_FREEZE)
     {
     address_item *addr;
-    for (addr = *generated; addr != NULL; addr = addr->next)
+    for (addr = *generated; addr; addr = addr->next)
       {
       int reply_options = 0;
 
       if (  rda_write_string(fd, addr->address) != 0
-         || write(fd, &(addr->mode), sizeof(addr->mode))
-           != sizeof(addr->mode)
-         || write(fd, &(addr->flags), sizeof(addr->flags))
-           != sizeof(addr->flags)
+         || write(fd, &addr->mode, sizeof(addr->mode)) != sizeof(addr->mode)
+         || write(fd, &addr->flags, sizeof(addr->flags)) != sizeof(addr->flags)
          || rda_write_string(fd, addr->prop.errors_address) != 0
         )
        goto bad;
 
-      if (addr->pipe_expandn != NULL)
+      if (addr->pipe_expandn)
         {
         uschar **pp;
-        for (pp = addr->pipe_expandn; *pp != NULL; pp++)
+        for (pp = addr->pipe_expandn; *pp; pp++)
           if (rda_write_string(fd, *pp) != 0)
            goto bad;
         }
       if (rda_write_string(fd, NULL) != 0)
         goto bad;
 
-      if (addr->reply == NULL)
+      if (!addr->reply)
        {
         if (write(fd, &reply_options, sizeof(int)) != sizeof(int))    /* 0 means no reply */
          goto bad;
@@ -889,9 +887,9 @@ if (yield == FF_DELIVERED || yield == FF_NOTDELIVERED ||
 
     /* Next comes the mode and the flags fields */
 
-    if (read(fd, &(addr->mode), sizeof(addr->mode)) != sizeof(addr->mode) ||
-        read(fd, &(addr->flags), sizeof(addr->flags)) != sizeof(addr->flags) ||
-        !rda_read_string(fd, &(addr->prop.errors_address))) goto DISASTER;
+    if (read(fd, &addr->mode, sizeof(addr->mode)) != sizeof(addr->mode) ||
+        read(fd, &addr->flags, sizeof(addr->flags)) != sizeof(addr->flags) ||
+        !rda_read_string(fd, &addr->prop.errors_address)) goto DISASTER;
 
     /* Next comes a possible setting for $thisaddress and any numerical
     variables for pipe expansion, terminated by a NULL string. The maximum
index 8b685c8fc6db142c12d9162597ded4d251719a94..f831f866a3ecd11ff667581aab7b4fa0bafc2e6b 100644 (file)
@@ -11,136 +11,12 @@ implementation of the conditional .ifdef etc. */
 
 #include "exim.h"
 
-extern char **environ;
-
-static void fn_smtp_receive_timeout(const uschar * name, const uschar * str);
-static void save_config_line(const uschar* line);
-static void save_config_position(const uschar *file, int line);
-static void print_config(BOOL admin, BOOL terse);
-static void readconf_options_auths(void);
-
-
-#define CSTATE_STACK_SIZE 10
-
-const uschar *config_directory = NULL;
-
-
-/* Structure for chain (stack) of .included files */
-
-typedef struct config_file_item {
-  struct config_file_item *next;
-  const uschar *filename;
-  const uschar *directory;
-  FILE *file;
-  int lineno;
-} config_file_item;
-
-/* Structure for chain of configuration lines (-bP config) */
-
-typedef struct config_line_item {
-  struct config_line_item *next;
-  uschar *line;
-} config_line_item;
-
-static config_line_item* config_lines;
-
-/* Structure of table of conditional words and their state transitions */
-
-typedef struct cond_item {
-  uschar *name;
-  int    namelen;
-  int    action1;
-  int    action2;
-  int    pushpop;
-} cond_item;
-
-/* Structure of table of syslog facility names and values */
-
-typedef struct syslog_fac_item {
-  uschar *name;
-  int    value;
-} syslog_fac_item;
-
-/* constants */
-static const char * const hidden = "<value not displayable>";
-
-/* Static variables */
-
-static config_file_item *config_file_stack = NULL;  /* For includes */
-
-static uschar *syslog_facility_str  = NULL;
-static uschar next_section[24];
-static uschar time_buffer[24];
-
-/* State variables for conditional loading (.ifdef / .else / .endif) */
-
-static int cstate = 0;
-static int cstate_stack_ptr = -1;
-static int cstate_stack[CSTATE_STACK_SIZE];
-
-/* Table of state transitions for handling conditional inclusions. There are
-four possible state transitions:
-
-  .ifdef true
-  .ifdef false
-  .elifdef true  (or .else)
-  .elifdef false
-
-.endif just causes the previous cstate to be popped off the stack */
-
-static int next_cstate[3][4] =
-  {
-  /* State 0: reading from file, or reading until next .else or .endif */
-  { 0, 1, 2, 2 },
-  /* State 1: condition failed, skipping until next .else or .endif */
-  { 2, 2, 0, 1 },
-  /* State 2: skipping until .endif */
-  { 2, 2, 2, 2 },
-  };
-
-/* Table of conditionals and the states to set. For each name, there are four
-values: the length of the name (to save computing it each time), the state to
-set if a macro was found in the line, the state to set if a macro was not found
-in the line, and a stack manipulation setting which is:
-
-  -1   pull state value off the stack
-   0   don't alter the stack
-  +1   push value onto stack, before setting new state
-*/
-
-static cond_item cond_list[] = {
-  { US"ifdef",    5, 0, 1,  1 },
-  { US"ifndef",   6, 1, 0,  1 },
-  { US"elifdef",  7, 2, 3,  0 },
-  { US"elifndef", 8, 3, 2,  0 },
-  { US"else",     4, 2, 2,  0 },
-  { US"endif",    5, 0, 0, -1 }
-};
-
-static int cond_list_size = sizeof(cond_list)/sizeof(cond_item);
-
-/* Table of syslog facility names and their values */
-
-static syslog_fac_item syslog_list[] = {
-  { US"mail",   LOG_MAIL },
-  { US"user",   LOG_USER },
-  { US"news",   LOG_NEWS },
-  { US"uucp",   LOG_UUCP },
-  { US"local0", LOG_LOCAL0 },
-  { US"local1", LOG_LOCAL1 },
-  { US"local2", LOG_LOCAL2 },
-  { US"local3", LOG_LOCAL3 },
-  { US"local4", LOG_LOCAL4 },
-  { US"local5", LOG_LOCAL5 },
-  { US"local6", LOG_LOCAL6 },
-  { US"local7", LOG_LOCAL7 },
-  { US"daemon", LOG_DAEMON }
-};
-
-static int syslog_list_size = sizeof(syslog_list)/sizeof(syslog_fac_item);
-
-
+#ifdef MACRO_PREDEF
+# include "macro_predef.h"
+#endif
 
+static uschar * syslog_facility_str;
+static void fn_smtp_receive_timeout(const uschar *, const uschar *);
 
 /*************************************************
 *           Main configuration options           *
@@ -217,6 +93,7 @@ static optionlist optionlist_config[] = {
   { "check_spool_inodes",       opt_int,         &check_spool_inodes },
   { "check_spool_space",        opt_Kint,        &check_spool_space },
   { "chunking_advertise_hosts", opt_stringptr,  &chunking_advertise_hosts },
+  { "commandline_checks_require_admin", opt_bool,&commandline_checks_require_admin },
   { "daemon_smtp_port",         opt_stringptr|opt_hidden, &daemon_smtp_port },
   { "daemon_smtp_ports",        opt_stringptr,   &daemon_smtp_port },
   { "daemon_startup_retries",   opt_int,         &daemon_startup_retries },
@@ -432,6 +309,7 @@ static optionlist optionlist_config[] = {
 #endif
   { "split_spool_directory",    opt_bool,        &split_spool_directory },
   { "spool_directory",          opt_stringptr,   &spool_directory },
+  { "spool_wireformat",         opt_bool,        &spool_wireformat },
 #ifdef LOOKUP_SQLITE
   { "sqlite_lock_timeout",      opt_int,         &sqlite_lock_timeout },
 #endif
@@ -494,7 +372,166 @@ static optionlist optionlist_config[] = {
   { "write_rejectlog",          opt_bool,        &write_rejectlog }
 };
 
+#ifndef MACRO_PREDEF
 static int optionlist_config_size = nelem(optionlist_config);
+#endif
+
+
+#ifdef MACRO_PREDEF
+
+static void fn_smtp_receive_timeout(const uschar * name, const uschar * str) {/*Dummy*/}
+
+void
+options_main(void)
+{
+options_from_list(optionlist_config, nelem(optionlist_config), US"MAIN", NULL);
+}
+
+void
+options_auths(void)
+{
+struct auth_info * ai;
+uschar buf[64];
+
+options_from_list(optionlist_auths, optionlist_auths_size, US"AUTHENTICATORS", NULL);
+
+for (ai = auths_available; ai->driver_name[0]; ai++)
+  {
+  spf(buf, sizeof(buf), US"_DRIVER_AUTHENTICATOR_%T", ai->driver_name);
+  builtin_macro_create(buf);
+  options_from_list(ai->options, (unsigned)*ai->options_count, US"AUTHENTICATOR", ai->driver_name);
+  }
+}
+
+
+#else  /*!MACRO_PREDEF*/
+
+extern char **environ;
+
+static void save_config_line(const uschar* line);
+static void save_config_position(const uschar *file, int line);
+static void print_config(BOOL admin, BOOL terse);
+
+
+#define CSTATE_STACK_SIZE 10
+
+const uschar *config_directory = NULL;
+
+
+/* Structure for chain (stack) of .included files */
+
+typedef struct config_file_item {
+  struct config_file_item *next;
+  const uschar *filename;
+  const uschar *directory;
+  FILE *file;
+  int lineno;
+} config_file_item;
+
+/* Structure for chain of configuration lines (-bP config) */
+
+typedef struct config_line_item {
+  struct config_line_item *next;
+  uschar *line;
+} config_line_item;
+
+static config_line_item* config_lines;
+
+/* Structure of table of conditional words and their state transitions */
+
+typedef struct cond_item {
+  uschar *name;
+  int    namelen;
+  int    action1;
+  int    action2;
+  int    pushpop;
+} cond_item;
+
+/* Structure of table of syslog facility names and values */
+
+typedef struct syslog_fac_item {
+  uschar *name;
+  int    value;
+} syslog_fac_item;
+
+/* constants */
+static const char * const hidden = "<value not displayable>";
+
+/* Static variables */
+
+static config_file_item *config_file_stack = NULL;  /* For includes */
+
+static uschar *syslog_facility_str  = NULL;
+static uschar next_section[24];
+static uschar time_buffer[24];
+
+/* State variables for conditional loading (.ifdef / .else / .endif) */
+
+static int cstate = 0;
+static int cstate_stack_ptr = -1;
+static int cstate_stack[CSTATE_STACK_SIZE];
+
+/* Table of state transitions for handling conditional inclusions. There are
+four possible state transitions:
+
+  .ifdef true
+  .ifdef false
+  .elifdef true  (or .else)
+  .elifdef false
+
+.endif just causes the previous cstate to be popped off the stack */
+
+static int next_cstate[3][4] =
+  {
+  /* State 0: reading from file, or reading until next .else or .endif */
+  { 0, 1, 2, 2 },
+  /* State 1: condition failed, skipping until next .else or .endif */
+  { 2, 2, 0, 1 },
+  /* State 2: skipping until .endif */
+  { 2, 2, 2, 2 },
+  };
+
+/* Table of conditionals and the states to set. For each name, there are four
+values: the length of the name (to save computing it each time), the state to
+set if a macro was found in the line, the state to set if a macro was not found
+in the line, and a stack manipulation setting which is:
+
+  -1   pull state value off the stack
+   0   don't alter the stack
+  +1   push value onto stack, before setting new state
+*/
+
+static cond_item cond_list[] = {
+  { US"ifdef",    5, 0, 1,  1 },
+  { US"ifndef",   6, 1, 0,  1 },
+  { US"elifdef",  7, 2, 3,  0 },
+  { US"elifndef", 8, 3, 2,  0 },
+  { US"else",     4, 2, 2,  0 },
+  { US"endif",    5, 0, 0, -1 }
+};
+
+static int cond_list_size = sizeof(cond_list)/sizeof(cond_item);
+
+/* Table of syslog facility names and their values */
+
+static syslog_fac_item syslog_list[] = {
+  { US"mail",   LOG_MAIL },
+  { US"user",   LOG_USER },
+  { US"news",   LOG_NEWS },
+  { US"uucp",   LOG_UUCP },
+  { US"local0", LOG_LOCAL0 },
+  { US"local1", LOG_LOCAL1 },
+  { US"local2", LOG_LOCAL2 },
+  { US"local3", LOG_LOCAL3 },
+  { US"local4", LOG_LOCAL4 },
+  { US"local5", LOG_LOCAL5 },
+  { US"local6", LOG_LOCAL6 },
+  { US"local7", LOG_LOCAL7 },
+  { US"daemon", LOG_DAEMON }
+};
+
+static int syslog_list_size = sizeof(syslog_list)/sizeof(syslog_fac_item);
+
 
 
 
@@ -528,7 +565,7 @@ for (r = routers; r; r = r->next)
   for (i = 0; i < *ri->options_count; i++)
     {
     if ((ri->options[i].type & opt_mask) != opt_stringptr) continue;
-    if (p == (char *)(r->options_block) + (long int)(ri->options[i].value))
+    if (p == CS (r->options_block) + (long int)(ri->options[i].value))
       return US ri->options[i].name;
     }
   }
@@ -541,8 +578,8 @@ for (t = transports; t; t = t->next)
     optionlist * op = &ti->options[i];
     if ((op->type & opt_mask) != opt_stringptr) continue;
     if (p == (  op->type & opt_public
-            ? (char *)t
-            : (char *)t->options_block
+            ? CS t
+            : CS t->options_block
             )
             + (long int)op->value)
        return US op->name;
@@ -559,41 +596,27 @@ return US"";
 *       Deal with an assignment to a macro       *
 *************************************************/
 
-/* We have a new definition. The macro_item structure includes a final vector
-called "name" which is one byte long. Thus, adding "namelen" gives us enough
-room to store the "name" string.
-If a builtin macro we place at head of list, else tail.  This lets us lazy-create
-builtins. */
+/* We have a new definition; append to the list.
+
+Args:
+ name  Name of the macro.  Must be in storage persistent past the call
+ val   Expansion result for the macro.  Ditto persistence.
+*/
 
 macro_item *
-macro_create(const uschar * name, const uschar * val,
-  BOOL command_line, BOOL builtin)
+macro_create(const uschar * name, const uschar * val, BOOL command_line)
 {
-unsigned namelen = Ustrlen(name);
-macro_item * m = store_get(sizeof(macro_item) + namelen);
+macro_item * m = store_get(sizeof(macro_item));
 
-/* fprintf(stderr, "%s: '%s' '%s'\n", __FUNCTION__, name, val) */
-if (!macros)
-  {
-  macros = m;
-  mlast = m;
-  m->next = NULL;
-  }
-else if (builtin)
-  {
-  m->next = macros;
-  macros = m;
-  }
-else
-  {
-  mlast->next = m;
-  mlast = m;
-  m->next = NULL;
-  }
+/* fprintf(stderr, "%s: '%s' '%s'\n", __FUNCTION__, name, val); */
+m->next = NULL;
 m->command_line = command_line;
-m->namelen = namelen;
-m->replacement = string_copy(val);
-Ustrcpy(m->name, name);
+m->namelen = Ustrlen(name);
+m->replen = Ustrlen(val);
+m->name = name;
+m->replacement = val;
+mlast->next = m;
+mlast = m;
 return m;
 }
 
@@ -680,230 +703,23 @@ if (m && m->command_line) return;
 
 if (redef)
   if (m)
+    {
+    m->replen = Ustrlen(s);
     m->replacement = string_copy(s);
+    }
   else
     log_write(0, LOG_CONFIG|LOG_PANIC_DIE, "can't redefine an undefined macro "
       "\"%s\"", name);
 
 /* We have a new definition. */
 else
-  (void) macro_create(name, s, FALSE, FALSE);
+  (void) macro_create(string_copy(name), string_copy(s), FALSE);
 }
 
 
 
 
 
-/*************************************************/
-/* Create compile-time feature macros */
-static void
-readconf_features(void)
-{
-/* Probably we could work out a static initialiser for wherever
-macros are stored, but this will do for now. Some names are awkward
-due to conflicts with other common macros. */
-
-#ifdef SUPPORT_CRYPTEQ
-  macro_create(US"_HAVE_CRYPTEQ", US"y", FALSE, TRUE);
-#endif
-#if HAVE_ICONV
-  macro_create(US"_HAVE_ICONV", US"y", FALSE, TRUE);
-#endif
-#if HAVE_IPV6
-  macro_create(US"_HAVE_IPV6", US"y", FALSE, TRUE);
-#endif
-#ifdef HAVE_SETCLASSRESOURCES
-  macro_create(US"_HAVE_SETCLASSRESOURCES", US"y", FALSE, TRUE);
-#endif
-#ifdef SUPPORT_PAM
-  macro_create(US"_HAVE_PAM", US"y", FALSE, TRUE);
-#endif
-#ifdef EXIM_PERL
-  macro_create(US"_HAVE_PERL", US"y", FALSE, TRUE);
-#endif
-#ifdef EXPAND_DLFUNC
-  macro_create(US"_HAVE_DLFUNC", US"y", FALSE, TRUE);
-#endif
-#ifdef USE_TCP_WRAPPERS
-  macro_create(US"_HAVE_TCPWRAPPERS", US"y", FALSE, TRUE);
-#endif
-#ifdef SUPPORT_TLS
-  macro_create(US"_HAVE_TLS", US"y", FALSE, TRUE);
-# ifdef USE_GNUTLS
-  macro_create(US"_HAVE_GNUTLS", US"y", FALSE, TRUE);
-# else
-  macro_create(US"_HAVE_OPENSSL", US"y", FALSE, TRUE);
-# endif
-#endif
-#ifdef SUPPORT_TRANSLATE_IP_ADDRESS
-  macro_create(US"_HAVE_TRANSLATE_IP_ADDRESS", US"y", FALSE, TRUE);
-#endif
-#ifdef SUPPORT_MOVE_FROZEN_MESSAGES
-  macro_create(US"_HAVE_MOVE_FROZEN_MESSAGES", US"y", FALSE, TRUE);
-#endif
-#ifdef WITH_CONTENT_SCAN
-  macro_create(US"_HAVE_CONTENT_SCANNING", US"y", FALSE, TRUE);
-#endif
-#ifndef DISABLE_DKIM
-  macro_create(US"_HAVE_DKIM", US"y", FALSE, TRUE);
-#endif
-#ifndef DISABLE_DNSSEC
-  macro_create(US"_HAVE_DNSSEC", US"y", FALSE, TRUE);
-#endif
-#ifndef DISABLE_EVENT
-  macro_create(US"_HAVE_EVENT", US"y", FALSE, TRUE);
-#endif
-#ifdef SUPPORT_I18N
-  macro_create(US"_HAVE_I18N", US"y", FALSE, TRUE);
-#endif
-#ifndef DISABLE_OCSP
-  macro_create(US"_HAVE_OCSP", US"y", FALSE, TRUE);
-#endif
-#ifndef DISABLE_PRDR
-  macro_create(US"_HAVE_PRDR", US"y", FALSE, TRUE);
-#endif
-#ifdef SUPPORT_PROXY
-  macro_create(US"_HAVE_PROXY", US"y", FALSE, TRUE);
-#endif
-#ifdef SUPPORT_SOCKS
-  macro_create(US"_HAVE_SOCKS", US"y", FALSE, TRUE);
-#endif
-#ifdef TCP_FASTOPEN
-  macro_create(US"_HAVE_TCP_FASTOPEN", US"y", FALSE, TRUE);
-#endif
-#ifdef EXPERIMENTAL_LMDB
-  macro_create(US"_HAVE_LMDB", US"y", FALSE, TRUE);
-#endif
-#ifdef EXPERIMENTAL_SPF
-  macro_create(US"_HAVE_SPF", US"y", FALSE, TRUE);
-#endif
-#ifdef EXPERIMENTAL_SRS
-  macro_create(US"_HAVE_SRS", US"y", FALSE, TRUE);
-#endif
-#ifdef EXPERIMENTAL_BRIGHTMAIL
-  macro_create(US"_HAVE_BRIGHTMAIL", US"y", FALSE, TRUE);
-#endif
-#ifdef EXPERIMENTAL_DANE
-  macro_create(US"_HAVE_DANE", US"y", FALSE, TRUE);
-#endif
-#ifdef EXPERIMENTAL_DCC
-  macro_create(US"_HAVE_DCC", US"y", FALSE, TRUE);
-#endif
-#ifdef EXPERIMENTAL_DMARC
-  macro_create(US"_HAVE_DMARC", US"y", FALSE, TRUE);
-#endif
-#ifdef EXPERIMENTAL_DSN_INFO
-  macro_create(US"_HAVE_DSN_INFO", US"y", FALSE, TRUE);
-#endif
-
-#ifdef LOOKUP_LSEARCH
-  macro_create(US"_HAVE_LOOKUP_LSEARCH", US"y", FALSE, TRUE);
-#endif
-#ifdef LOOKUP_CDB
-  macro_create(US"_HAVE_LOOKUP_CDB", US"y", FALSE, TRUE);
-#endif
-#ifdef LOOKUP_DBM
-  macro_create(US"_HAVE_LOOKUP_DBM", US"y", FALSE, TRUE);
-#endif
-#ifdef LOOKUP_DNSDB
-  macro_create(US"_HAVE_LOOKUP_DNSDB", US"y", FALSE, TRUE);
-#endif
-#ifdef LOOKUP_DSEARCH
-  macro_create(US"_HAVE_LOOKUP_DSEARCH", US"y", FALSE, TRUE);
-#endif
-#ifdef LOOKUP_IBASE
-  macro_create(US"_HAVE_LOOKUP_IBASE", US"y", FALSE, TRUE);
-#endif
-#ifdef LOOKUP_LDAP
-  macro_create(US"_HAVE_LOOKUP_LDAP", US"y", FALSE, TRUE);
-#endif
-#ifdef EXPERIMENTAL_LMDB
-  macro_create(US"_HAVE_LOOKUP_LMDB", US"y", FALSE, TRUE);
-#endif
-#ifdef LOOKUP_MYSQL
-  macro_create(US"_HAVE_LOOKUP_MYSQL", US"y", FALSE, TRUE);
-#endif
-#ifdef LOOKUP_NIS
-  macro_create(US"_HAVE_LOOKUP_NIS", US"y", FALSE, TRUE);
-#endif
-#ifdef LOOKUP_NISPLUS
-  macro_create(US"_HAVE_LOOKUP_NISPLUS", US"y", FALSE, TRUE);
-#endif
-#ifdef LOOKUP_ORACLE
-  macro_create(US"_HAVE_LOOKUP_ORACLE", US"y", FALSE, TRUE);
-#endif
-#ifdef LOOKUP_PASSWD
-  macro_create(US"_HAVE_LOOKUP_PASSWD", US"y", FALSE, TRUE);
-#endif
-#ifdef LOOKUP_PGSQL
-  macro_create(US"_HAVE_LOOKUP_PGSQL", US"y", FALSE, TRUE);
-#endif
-#ifdef LOOKUP_REDIS
-  macro_create(US"_HAVE_LOOKUP_REDIS", US"y", FALSE, TRUE);
-#endif
-#ifdef LOOKUP_SQLITE
-  macro_create(US"_HAVE_LOOKUP_SQLITE", US"y", FALSE, TRUE);
-#endif
-#ifdef LOOKUP_TESTDB
-  macro_create(US"_HAVE_LOOKUP_TESTDB", US"y", FALSE, TRUE);
-#endif
-#ifdef LOOKUP_WHOSON
-  macro_create(US"_HAVE_LOOKUP_WHOSON", US"y", FALSE, TRUE);
-#endif
-
-#ifdef TRANSPORT_APPENDFILE
-# ifdef SUPPORT_MAILDIR
-  macro_create(US"_HAVE_TRANSPORT_APPEND_MAILDIR", US"y", FALSE, TRUE);
-# endif
-# ifdef SUPPORT_MAILSTORE
-  macro_create(US"_HAVE_TRANSPORT_APPEND_MAILSTORE", US"y", FALSE, TRUE);
-# endif
-# ifdef SUPPORT_MBX
-  macro_create(US"_HAVE_TRANSPORT_APPEND_MBX", US"y", FALSE, TRUE);
-# endif
-#endif
-}
-
-
-void
-readconf_options_from_list(optionlist * opts, unsigned nopt, const uschar * section, uschar * group)
-{
-int i;
-const uschar * s;
-
-/* The 'previously-defined-substring' rule for macros in config file
-lines is done so for these builtin macros: we know that the table
-we source from is in strict alpha order, hence the builtins portion
-of the macros list is in reverse-alpha (we prepend them) - so longer
-macros that have substrings are always discovered first during
-expansion. */
-
-for (i = 0; i < nopt; i++)  if (*(s = US opts[i].name) && *s != '*')
-  if (group)
-    macro_create(string_sprintf("_OPT_%T_%T_%T", section, group, s), US"y", FALSE, TRUE);
-  else
-    macro_create(string_sprintf("_OPT_%T_%T", section, s), US"y", FALSE, TRUE);
-}
-
-
-static void
-readconf_options(void)
-{
-readconf_options_from_list(optionlist_config, nelem(optionlist_config), US"MAIN", NULL);
-readconf_options_routers();
-readconf_options_transports();
-readconf_options_auths();
-}
-
-static void
-macros_create_builtin(void)
-{
-readconf_features();
-readconf_options();
-macros_builtin_created = TRUE;
-}
-
-
 /*************************************************
 *            Read configuration line             *
 *************************************************/
@@ -1014,22 +830,10 @@ for (;;)
     if (*s != '=') s = ss;          /* Not a macro definition */
     }
 
-  /* If the builtin macros are not yet defined, and the line contains an
-  underscrore followed by an one of the three possible chars used by
-  builtins, create them. */
+  /* Skip leading chars which cannot start a macro name, to avoid multiple
+  pointless rescans in Ustrstr calls. */
 
-  if (!macros_builtin_created)
-    {
-    const uschar * t, * p;
-    uschar c;
-    for (t = s; (p = CUstrchr(t, '_')); t = p+1)
-      if (c = p[1], c == 'O' || c == 'D' || c == 'H')
-       {
-/* fprintf(stderr, "%s: builtins create triggered by '%s'\n", __FUNCTION__, s); */
-       macros_create_builtin();
-       break;
-       }
-    }
+  while (*s && !isupper(*s) && *s != '_') s++;
 
   /* For each defined macro, scan the line (from after XXX= if present),
   replacing all occurrences of the macro. */
@@ -1037,18 +841,17 @@ for (;;)
   macro_found = FALSE;
   for (m = macros; m; m = m->next)
     {
-    uschar *p, *pp;
-    uschar *t = s;
+    uschar * p, *pp;
+    uschar * t = s;
 
     while ((p = Ustrstr(t, m->name)) != NULL)
       {
       int moveby;
-      int replen = Ustrlen(m->replacement);
 
-/* fprintf(stderr, "%s: matched '%s' in '%s'\n", __FUNCTION__, m->name, t) */
+/* fprintf(stderr, "%s: matched '%s' in '%s'\n", __FUNCTION__, m->name, ss); */
       /* Expand the buffer if necessary */
 
-      while (newlen - m->namelen + replen + 1 > big_buffer_size)
+      while (newlen - m->namelen + m->replen + 1 > big_buffer_size)
         {
         int newsize = big_buffer_size + BIG_BUFFER_SIZE;
         uschar *newbuffer = store_malloc(newsize);
@@ -1067,13 +870,14 @@ for (;;)
       same macro. */
 
       pp = p + m->namelen;
-      if ((moveby = replen - m->namelen) != 0)
+      if ((moveby = m->replen - m->namelen) != 0)
         {
-        memmove(p + replen, pp, (big_buffer + newlen) - pp + 1);
+        memmove(p + m->replen, pp, (big_buffer + newlen) - pp + 1);
         newlen += moveby;
         }
-      Ustrncpy(p, m->replacement, replen);
-      t = p + replen;
+      Ustrncpy(p, m->replacement, m->replen);
+      t = p + m->replen;
+      while (*t && !isupper(*t) && *t != '_') t++;
       macro_found = TRUE;
       }
     }
@@ -1470,7 +1274,7 @@ ol = find_option(name2, oltop, last);
 if (ol == NULL) log_write(0, LOG_MAIN|LOG_PANIC_DIE,
   "Exim internal error: missing set flag for %s", name);
 return (data_block == NULL)? (BOOL *)(ol->value) :
-  (BOOL *)((uschar *)data_block + (long int)(ol->value));
+  (BOOL *)(US data_block + (long int)(ol->value));
 }
 
 
@@ -1896,9 +1700,13 @@ switch (type)
       const uschar * list = sptr;
       uschar * s;
       uschar * list_o = *str_target;
+      int size = 0, len = 0;
+
+      if (list_o)
+       size = (len = Ustrlen(list_o)) + 1;
 
       while ((s = string_nextinlist(&list, &sep_i, NULL, 0)))
-       list_o = string_append_listele(list_o, sep_o, s);
+       list_o = string_append_listele(list_o, &size, &len, sep_o, s);
       if (list_o)
        *str_target = string_copy_malloc(list_o);
       }
@@ -1939,8 +1747,8 @@ switch (type)
         }
       else
         {
-        chain = (rewrite_rule **)((uschar *)data_block + (long int)(ol2->value));
-        flagptr = (int *)((uschar *)data_block + (long int)(ol3->value));
+        chain = (rewrite_rule **)(US data_block + (long int)(ol2->value));
+        flagptr = (int *)(US data_block + (long int)(ol3->value));
         }
 
       while ((p = string_nextinlist(CUSS &sptr, &sep, big_buffer, BIG_BUFFER_SIZE)))
@@ -1972,7 +1780,7 @@ switch (type)
       if (data_block == NULL)
         *((uschar **)(ol2->value)) = ss;
       else
-        *((uschar **)((uschar *)data_block + (long int)(ol2->value))) = ss;
+        *((uschar **)(US data_block + (long int)(ol2->value))) = ss;
 
       if (ss != NULL)
         {
@@ -1991,7 +1799,7 @@ switch (type)
     if (data_block == NULL)
       *((uid_t *)(ol->value)) = uid;
     else
-      *((uid_t *)((uschar *)data_block + (long int)(ol->value))) = uid;
+      *((uid_t *)(US data_block + (long int)(ol->value))) = uid;
 
     /* Set the flag indicating a fixed value is set */
 
@@ -2013,7 +1821,7 @@ switch (type)
         if (data_block == NULL)
           *((gid_t *)(ol2->value)) = pw->pw_gid;
         else
-          *((gid_t *)((uschar *)data_block + (long int)(ol2->value))) = pw->pw_gid;
+          *((gid_t *)(US data_block + (long int)(ol2->value))) = pw->pw_gid;
         *set_flag = TRUE;
         }
       }
@@ -2035,7 +1843,7 @@ switch (type)
       if (data_block == NULL)
         *((uschar **)(ol2->value)) = ss;
       else
-        *((uschar **)((uschar *)data_block + (long int)(ol2->value))) = ss;
+        *((uschar **)(US data_block + (long int)(ol2->value))) = ss;
 
       if (ss != NULL)
         {
@@ -2053,7 +1861,7 @@ switch (type)
     if (data_block == NULL)
       *((gid_t *)(ol->value)) = gid;
     else
-      *((gid_t *)((uschar *)data_block + (long int)(ol->value))) = gid;
+      *((gid_t *)(US data_block + (long int)(ol->value))) = gid;
     *(get_set_flag(name, oltop, last, data_block)) = TRUE;
     break;
 
@@ -2083,7 +1891,7 @@ switch (type)
       if (data_block == NULL)
         *((uid_t **)(ol->value)) = list;
       else
-        *((uid_t **)((uschar *)data_block + (long int)(ol->value))) = list;
+        *((uid_t **)(US data_block + (long int)(ol->value))) = list;
 
       p = op;
       while (count-- > 1)
@@ -2124,7 +1932,7 @@ switch (type)
       if (data_block == NULL)
         *((gid_t **)(ol->value)) = list;
       else
-        *((gid_t **)((uschar *)data_block + (long int)(ol->value))) = list;
+        *((gid_t **)(US data_block + (long int)(ol->value))) = list;
 
       p = op;
       while (count-- > 1)
@@ -2160,7 +1968,7 @@ switch (type)
       if (data_block == NULL)
         *((uschar **)(ol2->value)) = sptr;
       else
-        *((uschar **)((uschar *)data_block + (long int)(ol2->value))) = sptr;
+        *((uschar **)(US data_block + (long int)(ol2->value))) = sptr;
       freesptr = FALSE;
       break;
       }
@@ -2198,7 +2006,7 @@ switch (type)
     int bit = 1 << ((ol->type >> 16) & 31);
     int *ptr = (data_block == NULL)?
       (int *)(ol->value) :
-      (int *)((uschar *)data_block + (long int)ol->value);
+      (int *)(US data_block + (long int)ol->value);
     if (boolvalue) *ptr |= bit; else *ptr &= ~bit;
     break;
     }
@@ -2208,7 +2016,7 @@ switch (type)
   if (data_block == NULL)
     *((BOOL *)(ol->value)) = boolvalue;
   else
-    *((BOOL *)((uschar *)data_block + (long int)(ol->value))) = boolvalue;
+    *((BOOL *)(US data_block + (long int)(ol->value))) = boolvalue;
 
   /* Verify fudge */
 
@@ -2221,7 +2029,7 @@ switch (type)
       if (data_block == NULL)
         *((BOOL *)(ol2->value)) = boolvalue;
       else
-        *((BOOL *)((uschar *)data_block + (long int)(ol2->value))) = boolvalue;
+        *((BOOL *)(US data_block + (long int)(ol2->value))) = boolvalue;
       }
     }
 
@@ -2236,7 +2044,7 @@ switch (type)
       if (data_block == NULL)
         *((BOOL *)(ol2->value)) = TRUE;
       else
-        *((BOOL *)((uschar *)data_block + (long int)(ol2->value))) = TRUE;
+        *((BOOL *)(US data_block + (long int)(ol2->value))) = TRUE;
       }
     }
   break;
@@ -2299,7 +2107,7 @@ switch (type)
   if (data_block == NULL)
     *((int *)(ol->value)) = value;
   else
-    *((int *)((uschar *)data_block + (long int)(ol->value))) = value;
+    *((int *)(US data_block + (long int)(ol->value))) = value;
   break;
 
   /*  Integer held in K: again, allow octal and hex formats, and suffixes K, M
@@ -2349,7 +2157,7 @@ switch (type)
   if (data_block == NULL)
     *((int *)(ol->value)) = value;
   else
-    *((int *)((uschar *)data_block + (long int)(ol->value))) = value;
+    *((int *)(US data_block + (long int)(ol->value))) = value;
   break;
 
   /*  Fixed-point number: held to 3 decimal places. */
@@ -2390,7 +2198,7 @@ switch (type)
   if (data_block == NULL)
     *((int *)(ol->value)) = value;
   else
-    *((int *)((uschar *)data_block + (long int)(ol->value))) = value;
+    *((int *)(US data_block + (long int)(ol->value))) = value;
   break;
 
   /* There's a special routine to read time values. */
@@ -2403,7 +2211,7 @@ switch (type)
   if (data_block == NULL)
     *((int *)(ol->value)) = value;
   else
-    *((int *)((uschar *)data_block + (long int)(ol->value))) = value;
+    *((int *)(US data_block + (long int)(ol->value))) = value;
   break;
 
   /* A time list is a list of colon-separated times, with the first
@@ -2415,7 +2223,7 @@ switch (type)
     int count = 0;
     int *list = (data_block == NULL)?
       (int *)(ol->value) :
-      (int *)((uschar *)data_block + (long int)(ol->value));
+      (int *)(US data_block + (long int)(ol->value));
 
     if (*s != 0) for (count = 1; count <= list[0] - 2; count++)
       {
@@ -2492,10 +2300,10 @@ t /= 24;
 d = t % 7;
 w = t/7;
 
-if (w > 0) { sprintf(CS p, "%dw", w); while (*p) p++; }
-if (d > 0) { sprintf(CS p, "%dd", d); while (*p) p++; }
-if (h > 0) { sprintf(CS p, "%dh", h); while (*p) p++; }
-if (m > 0) { sprintf(CS p, "%dm", m); while (*p) p++; }
+if (w > 0) p += sprintf(CS p, "%dw", w);
+if (d > 0) p += sprintf(CS p, "%dd", d);
+if (h > 0) p += sprintf(CS p, "%dh", h);
+if (m > 0) p += sprintf(CS p, "%dm", m);
 if (s > 0 || p == time_buffer) sprintf(CS p, "%ds", s);
 
 return time_buffer;
@@ -2565,7 +2373,7 @@ if (options_block != NULL)
   {
   if ((ol->type & opt_public) == 0)
     options_block = (void *)(((driver_instance *)options_block)->options_block);
-  value = (void *)((uschar *)options_block + (long int)value);
+  value = (void *)(US options_block + (long int)value);
   }
 
 switch(ol->type & opt_mask)
@@ -2654,7 +2462,7 @@ switch(ol->type & opt_mask)
       {
       void *value2 = ol2->value;
       if (options_block != NULL)
-        value2 = (void *)((uschar *)options_block + (long int)value2);
+        value2 = (void *)(US options_block + (long int)value2);
       s = *((uschar **)value2);
       if (!no_labels) printf("%s = ", name);
       printf("%s\n", (s == NULL)? US"" : string_printing(s));
@@ -2688,7 +2496,7 @@ switch(ol->type & opt_mask)
       {
       void *value2 = ol2->value;
       if (options_block != NULL)
-        value2 = (void *)((uschar *)options_block + (long int)value2);
+        value2 = (void *)(US options_block + (long int)value2);
       s = *((uschar **)value2);
       if (!no_labels) printf("%s = ", name);
       printf("%s\n", (s == NULL)? US"" : string_printing(s));
@@ -2783,7 +2591,7 @@ switch(ol->type & opt_mask)
     {
     void *value2 = ol2->value;
     if (options_block != NULL)
-      value2 = (void *)((uschar *)options_block + (long int)value2);
+      value2 = (void *)(US options_block + (long int)value2);
     s = *((uschar **)value2);
     if (s != NULL)
       {
@@ -3038,7 +2846,6 @@ else if (Ustrcmp(type, "macro") == 0)
     fprintf(stderr, "exim: permission denied\n");
     exit(EXIT_FAILURE);
     }
-  if (!macros_builtin_created) macros_create_builtin();
   for (m = macros; m; m = m->next)
     if (!name || Ustrcmp(name, m->name) == 0)
       {
@@ -3466,6 +3273,11 @@ a macro definition. */
 
 while ((s = get_config_line()) != NULL)
   {
+
+  if (config_lineno == 1 && Ustrstr(s, "\xef\xbb\xbf") == s)
+    log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
+      "found unexpected BOM (Byte Order Mark)");
+
   if (isupper(s[0])) read_macro_assignment(s);
 
   else if (Ustrncmp(s, "domainlist", 10) == 0)
@@ -3784,14 +3596,14 @@ if (tls_dh_max_bits < 1024)
       "tls_dh_max_bits is too small, must be at least 1024 for interop");
 
 /* If openssl_options is set, validate it */
-if (openssl_options != NULL)
+if (openssl_options)
   {
 # ifdef USE_GNUTLS
   log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
     "openssl_options is set but we're using GnuTLS");
 # else
   long dummy;
-  if (!(tls_openssl_options_parse(openssl_options, &dummy)))
+  if (!tls_openssl_options_parse(openssl_options, &dummy))
     log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
       "openssl_options parse error: %s", openssl_options);
 # endif
@@ -3832,7 +3644,7 @@ init_driver(driver_instance *d, driver_info *drivers_available,
 driver_info *dd;
 
 for (dd = drivers_available; dd->driver_name[0] != 0;
-     dd = (driver_info *)(((uschar *)dd) + size_of_info))
+     dd = (driver_info *)((US dd) + size_of_info))
   {
   if (Ustrcmp(d->driver_name, dd->driver_name) == 0)
     {
@@ -4045,7 +3857,7 @@ for (ol = d->info->options; ol < d->info->options + count; ol++)
   int type = ol->type & opt_mask;
   if (type != opt_stringptr) continue;
   options_block = ((ol->type & opt_public) == 0)? d->options_block : (void *)d;
-  value = *(uschar **)((uschar *)options_block + (long int)(ol->value));
+  value = *(uschar **)(US options_block + (long int)(ol->value));
   if (value != NULL && (ss = Ustrstr(value, s)) != NULL)
     {
     if (ss <= value || (ss[-1] != '$' && ss[-1] != '{') ||
@@ -4121,14 +3933,14 @@ else if (len == 7 && strncmpic(pp, US"timeout", len) == 0)
     static int values[] =
       { 'A',   'M',    RTEF_CTOUT,  RTEF_CTOUT|'A', RTEF_CTOUT|'M' };
 
-    for (i = 0; i < sizeof(extras)/sizeof(uschar *); i++)
+    for (i = 0; i < nelem(extras); i++)
       if (strncmpic(x, extras[i], xlen) == 0)
         {
         *more_errno = values[i];
         break;
         }
 
-    if (i >= sizeof(extras)/sizeof(uschar *))
+    if (i >= nelem(extras))
       if (strncmpic(x, US"DNS", xlen) == 0)
         log_write(0, LOG_MAIN|LOG_PANIC, "\"timeout_dns\" is no longer "
           "available in retry rules (it has never worked) - treated as "
@@ -4347,21 +4159,6 @@ while ((p = get_config_line()))
 *         Initialize authenticators              *
 *************************************************/
 
-static void
-readconf_options_auths(void)
-{
-struct auth_info * ai;
-
-readconf_options_from_list(optionlist_auths, optionlist_auths_size, US"AUTHENTICATORS", NULL);
-
-for (ai = auths_available; ai->driver_name[0]; ai++)
-  {
-  macro_create(string_sprintf("_DRIVER_AUTHENTICATOR_%T", ai->driver_name), US"y", FALSE, TRUE);
-  readconf_options_from_list(ai->options, (unsigned)*ai->options_count, US"AUTHENTICATOR", ai->driver_name);
-  }
-}
-
-
 /* Read the authenticators section of the configuration file.
 
 Arguments:   none
@@ -4539,7 +4336,7 @@ while(next_section[0] != 0)
   {
   int bit;
   int first = 0;
-  int last = sizeof(section_list) / sizeof(uschar *);
+  int last = nelem(section_list);
   int mid = last/2;
   int n = Ustrlen(next_section);
 
@@ -4595,6 +4392,7 @@ save_config_position(const uschar *file, int line)
 this operates on a global (static) list that holds all the pre-parsed
 config lines, we do no further processing here, output formatting and
 honouring of <hide> or macros will be done during output */
+
 static void
 save_config_line(const uschar* line)
 {
@@ -4693,6 +4491,7 @@ for (i = config_lines; i; i = i->next)
   }
 }
 
+#endif /*!MACRO_PREDEF*/
 /* vi: aw ai sw=2
 */
 /* End of readconf.c */
index 7980c324fc1d42c1bca0462928e4cecb89782d00..65e9fb415127f301e017c68e5d86b42132e382e9 100644 (file)
@@ -84,12 +84,10 @@ receive_check_set_sender(uschar *newsender)
 {
 uschar *qnewsender;
 if (trusted_caller) return TRUE;
-if (newsender == NULL || untrusted_set_sender == NULL) return FALSE;
-qnewsender = (Ustrchr(newsender, '@') != NULL)?
-  newsender : string_sprintf("%s@%s", newsender, qualify_domain_sender);
-return
-  match_address_list(qnewsender, TRUE, TRUE, CUSS &untrusted_set_sender, NULL, -1,
-    0, NULL) == OK;
+if (!newsender || !untrusted_set_sender) return FALSE;
+qnewsender = Ustrchr(newsender, '@')
+  ? newsender : string_sprintf("%s@%s", newsender, qualify_domain_sender);
+return match_address_list_basic(qnewsender, CUSS &untrusted_set_sender, 0) == OK;
 }
 
 
@@ -831,7 +829,7 @@ while ((ch = (receive_getc)(GETC_BUFFER_UNLIMITED)) != EOF)
       {
       message_size++;
       if (fout != NULL && fputc('\n', fout) == EOF) return END_WERROR;
-      (void) cutthrough_put_nl();
+      cutthrough_data_put_nl();
       if (ch != '\r') ch_state = 1; else continue;
       }
     break;
@@ -850,7 +848,7 @@ while ((ch = (receive_getc)(GETC_BUFFER_UNLIMITED)) != EOF)
     if (ch == '.')
       {
       uschar c= ch;
-      (void) cutthrough_puts(&c, 1);
+      cutthrough_data_puts(&c, 1);
       }
     ch_state = 1;
     break;
@@ -860,7 +858,7 @@ while ((ch = (receive_getc)(GETC_BUFFER_UNLIMITED)) != EOF)
     message_size++;
     body_linecount++;
     if (fout != NULL && fputc('\n', fout) == EOF) return END_WERROR;
-    (void) cutthrough_put_nl();
+    cutthrough_data_put_nl();
     if (ch == '\r')
       {
       ch_state = 2;
@@ -881,11 +879,11 @@ while ((ch = (receive_getc)(GETC_BUFFER_UNLIMITED)) != EOF)
     if (message_size > thismessage_size_limit) return END_SIZE;
     }
   if(ch == '\n')
-    (void) cutthrough_put_nl();
+    cutthrough_data_put_nl();
   else
     {
     uschar c = ch;
-    (void) cutthrough_puts(&c, 1);
+    cutthrough_data_puts(&c, 1);
     }
   }
 
@@ -921,7 +919,7 @@ BOOL fix_nl = FALSE;
 
 for(;;)
   {
-  switch ((ch = (bdat_getc)(GETC_BUFFER_UNLIMITED)))
+  switch ((ch = bdat_getc(GETC_BUFFER_UNLIMITED)))
     {
     case EOF:  return END_EOF;
     case ERR:  return END_PROTOCOL;
@@ -991,7 +989,7 @@ for(;;)
        {
        message_size++;
        if (fout && fputc('\n', fout) == EOF) return END_WERROR;
-       (void) cutthrough_put_nl();
+       cutthrough_data_put_nl();
        if (ch == '\r') continue;       /* don't write CR */
        ch_state = MID_LINE;
        }
@@ -1008,16 +1006,58 @@ for(;;)
     if (message_size > thismessage_size_limit) return END_SIZE;
     }
   if(ch == '\n')
-    (void) cutthrough_put_nl();
+    cutthrough_data_put_nl();
   else
     {
     uschar c = ch;
-    (void) cutthrough_puts(&c, 1);
+    cutthrough_data_puts(&c, 1);
     }
   }
 /*NOTREACHED*/
 }
 
+static int
+read_message_bdat_smtp_wire(FILE *fout)
+{
+int ch;
+
+/* Remember that this message uses wireformat. */
+
+DEBUG(D_receive) debug_printf("CHUNKING: writing spoolfile in wire format\n");
+spool_file_wireformat = TRUE;
+
+for (;;)
+  {
+  if (chunking_data_left > 0)
+    {
+    unsigned len = MAX(chunking_data_left, thismessage_size_limit - message_size + 1);
+    uschar * buf = bdat_getbuf(&len);
+
+    message_size += len;
+    if (fout && fwrite(buf, len, 1, fout) != 1) return END_WERROR;
+    }
+  else switch (ch = bdat_getc(GETC_BUFFER_UNLIMITED))
+    {
+    case EOF: return END_EOF;
+    case EOD: return END_DOT;
+    case ERR: return END_PROTOCOL;
+
+    default:
+      message_size++;
+  /*XXX not done:
+  linelength
+  max_received_linelength
+  body_linecount
+  body_zerocount
+  */
+      if (fout && fputc(ch, fout) == EOF) return END_WERROR;
+      break;
+    }
+  if (message_size > thismessage_size_limit) return END_SIZE;
+  }
+/*NOTREACHED*/
+}
+
 
 
 
@@ -1140,7 +1180,8 @@ switch(where)
   case ACL_WHERE_DKIM:
   case ACL_WHERE_MIME:
   case ACL_WHERE_DATA:
-    if (cutthrough.fd >= 0 && (acl_removed_headers || acl_added_headers))
+    if (  cutthrough.fd >= 0 && cutthrough.delivery
+       && (acl_removed_headers || acl_added_headers))
     {
     log_write(0, LOG_MAIN|LOG_PANIC, "Header modification in data ACLs"
                        " will not take effect on cutthrough deliveries");
@@ -1148,11 +1189,11 @@ switch(where)
     }
   }
 
-if (acl_removed_headers != NULL)
+if (acl_removed_headers)
   {
   DEBUG(D_receive|D_acl) debug_printf_indent(">>Headers removed by %s ACL:\n", acl_name);
 
-  for (h = header_list; h != NULL; h = h->next) if (h->type != htype_old)
+  for (h = header_list; h; h = h->next) if (h->type != htype_old)
     {
     const uschar * list = acl_removed_headers;
     int sep = ':';         /* This is specified as a colon-separated list */
@@ -1170,10 +1211,10 @@ if (acl_removed_headers != NULL)
   DEBUG(D_receive|D_acl) debug_printf_indent(">>\n");
   }
 
-if (acl_added_headers == NULL) return;
+if (!acl_added_headers) return;
 DEBUG(D_receive|D_acl) debug_printf_indent(">>Headers added by %s ACL:\n", acl_name);
 
-for (h = acl_added_headers; h != NULL; h = next)
+for (h = acl_added_headers; h; h = next)
   {
   next = h->next;
 
@@ -1262,7 +1303,7 @@ add_host_info_for_log(uschar * s, int * sizeptr, int * ptrptr)
 if (sender_fullhost)
   {
   if (LOGGING(dnssec) && sender_host_dnssec)   /*XXX sender_helo_dnssec? */
-    s = string_cat(s, sizeptr, ptrptr, US" DS");
+    s = string_catn(s, sizeptr, ptrptr, US" DS", 3);
   s = string_append(s, sizeptr, ptrptr, 2, US" H=", sender_fullhost);
   if (LOGGING(incoming_interface) && interface_address != NULL)
     {
@@ -1270,9 +1311,14 @@ if (sender_fullhost)
       string_sprintf(" I=[%s]:%d", interface_address, interface_port));
     }
   }
-if (sender_ident != NULL)
+if (tcp_in_fastopen && !tcp_in_fastopen_logged)
+  {
+  s = string_catn(s, sizeptr, ptrptr, US" TFO", 4);
+  tcp_in_fastopen_logged = TRUE;
+  }
+if (sender_ident)
   s = string_append(s, sizeptr, ptrptr, 2, US" U=", sender_ident);
-if (received_protocol != NULL)
+if (received_protocol)
   s = string_append(s, sizeptr, ptrptr, 2, US" P=", received_protocol);
 return s;
 }
@@ -1307,36 +1353,30 @@ unsigned long mbox_size;
 header_line *my_headerlist;
 uschar *user_msg, *log_msg;
 int mime_part_count_buffer = -1;
+uschar * mbox_filename;
 int rc = OK;
 
 memset(CS rfc822_file_path,0,2048);
 
 /* check if it is a MIME message */
-my_headerlist = header_list;
-while (my_headerlist != NULL)
-  {
-  /* skip deleted headers */
-  if (my_headerlist->type == '*')
-    {
-    my_headerlist = my_headerlist->next;
-    continue;
-    }
-  if (strncmpic(my_headerlist->text, US"Content-Type:", 13) == 0)
+
+for (my_headerlist = header_list; my_headerlist; my_headerlist = my_headerlist->next)
+  if (  my_headerlist->type != '*'                     /* skip deleted headers */
+     && strncmpic(my_headerlist->text, US"Content-Type:", 13) == 0
+     )
     {
     DEBUG(D_receive) debug_printf("Found Content-Type: header - executing acl_smtp_mime.\n");
     goto DO_MIME_ACL;
     }
-  my_headerlist = my_headerlist->next;
-  }
 
 DEBUG(D_receive) debug_printf("No Content-Type: header - presumably not a MIME message.\n");
 return TRUE;
 
 DO_MIME_ACL:
+
 /* make sure the eml mbox file is spooled up */
-mbox_file = spool_mbox(&mbox_size, NULL);
-if (mbox_file == NULL) {
-  /* error while spooling */
+if (!(mbox_file = spool_mbox(&mbox_size, NULL, &mbox_filename)))
+  {                                                            /* error while spooling */
   log_write(0, LOG_MAIN|LOG_PANIC,
          "acl_smtp_mime: error while creating mbox spool file, message temporarily rejected.");
   Uunlink(spool_name);
@@ -1348,7 +1388,7 @@ if (mbox_file == NULL) {
   message_id[0] = 0;            /* Indicate no message accepted */
   *smtp_reply_ptr = US"";       /* Indicate reply already sent */
   return FALSE;                 /* Indicate skip to end of receive function */
-};
+  }
 
 mime_is_rfc822 = 0;
 
@@ -1372,14 +1412,13 @@ if (Ustrlen(rfc822_file_path) > 0)
 /* check if we must check any message/rfc822 attachments */
 if (rc == OK)
   {
-  uschar temp_path[1024];
+  uschar * scandir;
   struct dirent * entry;
   DIR * tempdir;
 
-  (void) string_format(temp_path, sizeof(temp_path), "%s/scan/%s",
-    spool_directory, message_id);
+  scandir = string_copyn(mbox_filename, Ustrrchr(mbox_filename, '/') - mbox_filename);
 
-  tempdir = opendir(CS temp_path);
+  tempdir = opendir(CS scandir);
   for (;;)
     {
     if (!(entry = readdir(tempdir)))
@@ -1387,7 +1426,7 @@ if (rc == OK)
     if (strncmpic(US entry->d_name, US"__rfc822_", 9) == 0)
       {
       (void) string_format(rfc822_file_path, sizeof(rfc822_file_path),
-       "%s/scan/%s/%s", spool_directory, message_id, entry->d_name);
+       "%s/%s", scandir, entry->d_name);
       DEBUG(D_receive) debug_printf("RFC822 attachment detected: running MIME ACL for '%s'\n",
        rfc822_file_path);
       break;
@@ -1653,7 +1692,7 @@ search_tidyup();
 cutthrough delivery with the no-spool option.  It shouldn't be possible
 to set up the combination, but just in case kill any ongoing connection. */
 if (extract_recip || !smtp_input)
-  cancel_cutthrough_connection("not smtp input");
+  cancel_cutthrough_connection(TRUE, US"not smtp input");
 
 /* Initialize the chain of headers by setting up a place-holder for Received:
 header. Temporarily mark it as "old", i.e. not to be used. We keep header_last
@@ -1709,9 +1748,9 @@ message id creation below. */
 
 /* For other uses of the received time we can operate with granularity of one
 second, and for that we use the global variable received_time. This is for
-things like ultimate message timeouts. */
+things like ultimate message timeouts.XXX */
 
-received_time = message_id_tv.tv_sec;
+received_time = message_id_tv;
 
 /* If SMTP input, set the special handler for timeouts. The alarm() calls
 happen in the smtp_getc() function when it refills its buffer. */
@@ -2160,7 +2199,7 @@ for (;;)
       sender_address,
       sender_fullhost ? " H=" : "", sender_fullhost ? sender_fullhost : US"",
       sender_ident ? " U=" : "",    sender_ident ? sender_ident : US"");
-    smtp_printf("552 Message header not CRLF terminated\r\n");
+    smtp_printf("552 Message header not CRLF terminated\r\n", FALSE);
     bdat_flush_data();
     smtp_reply = US"";
     goto TIDYUP;                             /* Skip to end of function */
@@ -2988,26 +3027,24 @@ inbound is, but inbound chunking ought to be ok with outbound plain.
 Could we do onward CHUNKING given inbound CHUNKING?
 */
 if (chunking_state > CHUNKING_OFFERED)
-  cancel_cutthrough_connection("chunking active");
+  cancel_cutthrough_connection(FALSE, US"chunking active");
 
 /* Cutthrough delivery:
 We have to create the Received header now rather than at the end of reception,
 so the timestamp behaviour is a change to the normal case.
-XXX Ensure this gets documented XXX.
 Having created it, send the headers to the destination. */
-if (cutthrough.fd >= 0)
+
+if (cutthrough.fd >= 0 && cutthrough.delivery)
   {
   if (received_count > received_headers_max)
     {
-    cancel_cutthrough_connection("too many headers");
+    cancel_cutthrough_connection(TRUE, US"too many headers");
     if (smtp_input) receive_swallow_smtp();  /* Swallow incoming SMTP */
     log_write(0, LOG_MAIN|LOG_REJECT, "rejected from <%s>%s%s%s%s: "
       "Too many \"Received\" headers",
       sender_address,
-      (sender_fullhost == NULL)? "" : " H=",
-      (sender_fullhost == NULL)? US"" : sender_fullhost,
-      (sender_ident == NULL)? "" : " U=",
-      (sender_ident == NULL)? US"" : sender_ident);
+      sender_fullhost ? "H=" : "", sender_fullhost ? sender_fullhost : US"",
+      sender_ident ? "U=" : "", sender_ident ? sender_ident : US"");
     message_id[0] = 0;                       /* Indicate no message accepted */
     smtp_reply = US"550 Too many \"Received\" headers - suspected mail loop";
     goto TIDYUP;                             /* Skip to end of function */
@@ -3087,9 +3124,11 @@ if (!ferror(data_file) && !(receive_feof)() && message_ended != END_DOT)
   {
   if (smtp_input)
     {
-    message_ended = chunking_state > CHUNKING_OFFERED
-      ? read_message_bdat_smtp(data_file)
-      : read_message_data_smtp(data_file);
+    message_ended = chunking_state <= CHUNKING_OFFERED
+      ? read_message_data_smtp(data_file)
+      : spool_wireformat
+      ? read_message_bdat_smtp_wire(data_file)
+      : read_message_bdat_smtp(data_file);
     receive_linecount++;                /* The terminating "." line */
     }
   else message_ended = read_message_data(data_file);
@@ -3105,7 +3144,7 @@ if (!ferror(data_file) && !(receive_feof)() && message_ended != END_DOT)
       if (smtp_input)
        {
        Uunlink(spool_name);                 /* Lose data file when closed */
-       cancel_cutthrough_connection("sender closed connection");
+       cancel_cutthrough_connection(TRUE, US"sender closed connection");
        message_id[0] = 0;                   /* Indicate no message accepted */
        smtp_reply = handle_lost_connection(US"");
        smtp_yield = FALSE;
@@ -3118,7 +3157,7 @@ if (!ferror(data_file) && !(receive_feof)() && message_ended != END_DOT)
 
     case END_SIZE:
       Uunlink(spool_name);                /* Lose the data file when closed */
-      cancel_cutthrough_connection("mail too big");
+      cancel_cutthrough_connection(TRUE, US"mail too big");
       if (smtp_input) receive_swallow_smtp();  /* Swallow incoming SMTP */
 
       log_write(L_size_reject, LOG_MAIN|LOG_REJECT, "rejected from <%s>%s%s%s%s: "
@@ -3151,7 +3190,7 @@ if (!ferror(data_file) && !(receive_feof)() && message_ended != END_DOT)
 
     case END_PROTOCOL:
       Uunlink(spool_name);             /* Lose the data file when closed */
-      cancel_cutthrough_connection("sender protocol error");
+      cancel_cutthrough_connection(TRUE, US"sender protocol error");
       smtp_reply = US"";               /* Response already sent */
       message_id[0] = 0;               /* Indicate no message accepted */
       goto TIDYUP;                     /* Skip to end of function */
@@ -3184,7 +3223,7 @@ if (fflush(data_file) == EOF || ferror(data_file) ||
 
   log_write(0, LOG_MAIN, "Message abandoned: %s", msg);
   Uunlink(spool_name);                /* Lose the data file */
-  cancel_cutthrough_connection("error writing spoolfile");
+  cancel_cutthrough_connection(TRUE, US"error writing spoolfile");
 
   if (smtp_input)
     {
@@ -3423,7 +3462,7 @@ else
              DEBUG(D_receive)
                debug_printf("acl_smtp_dkim: acl_check returned %d on %s, "
                  "skipping remaining items\n", rc, item);
-             cancel_cutthrough_connection("dkim acl not ok");
+             cancel_cutthrough_connection(TRUE, US"dkim acl not ok");
              break;
              }
             }
@@ -3467,7 +3506,7 @@ else
       int all_pass = OK;
       int all_fail = FAIL;
 
-      smtp_printf("353 PRDR content analysis beginning\r\n");
+      smtp_printf("353 PRDR content analysis beginning\r\n", TRUE);
       /* Loop through recipients, responses must be in same order received */
       for (c = 0; recipients_count > c; c++)
         {
@@ -3542,14 +3581,14 @@ else
         {
         recipients_count = 0;
         blackholed_by = US"DATA ACL";
-        if (log_msg != NULL)
+        if (log_msg)
           blackhole_log_msg = string_sprintf(": %s", log_msg);
-       cancel_cutthrough_connection("data acl discard");
+       cancel_cutthrough_connection(TRUE, US"data acl discard");
         }
       else if (rc != OK)
         {
         Uunlink(spool_name);
-       cancel_cutthrough_connection("data acl not ok");
+       cancel_cutthrough_connection(TRUE, US"data acl not ok");
 #ifdef WITH_CONTENT_SCAN
         unspool_mbox();
 #endif
@@ -3643,6 +3682,7 @@ dcc_ok = 0;
 version supplied with Exim always accepts, but this is a hook for sysadmins to
 supply their own checking code. The local_scan() function is run even when all
 the recipients have been discarded. */
+/*XXS could we avoid this for the standard case, given that few people will use it? */
 
 lseek(data_fd, (long int)SPOOL_DATA_START_OFFSET, SEEK_SET);
 
@@ -4148,9 +4188,9 @@ for this message. */
 
    XXX We do not handle queue-only, freezing, or blackholes.
 */
-if(cutthrough.fd >= 0)
+if(cutthrough.fd >= 0 && cutthrough.delivery)
   {
-  uschar * msg= cutthrough_finaldot(); /* Ask the target system to accept the message */
+  uschar * msg = cutthrough_finaldot();        /* Ask the target system to accept the message */
                                        /* Logging was done in finaldot() */
   switch(msg[0])
     {
@@ -4267,12 +4307,12 @@ if (smtp_input)
 
       else if (chunking_state > CHUNKING_OFFERED)
        {
-        smtp_printf("250- %u byte chunk, total %d\r\n250 OK id=%s\r\n",
+        smtp_printf("250- %u byte chunk, total %d\r\n250 OK id=%s\r\n", FALSE,
            chunking_datasize, message_size+message_linecount, message_id);
        chunking_state = CHUNKING_OFFERED;
        }
       else
-        smtp_printf("250 OK id=%s\r\n", message_id);
+        smtp_printf("250 OK id=%s\r\n", FALSE, message_id);
 
       if (host_checking)
         fprintf(stdout,
@@ -4286,7 +4326,7 @@ if (smtp_input)
         smtp_respond((fake_response == DEFER)? US"450" : US"550", 3, TRUE,
           fake_response_text);
       else
-        smtp_printf("%.1024s\r\n", smtp_reply);
+        smtp_printf("%.1024s\r\n", FALSE, smtp_reply);
 
     switch (cutthrough_done)
       {
@@ -4297,7 +4337,6 @@ if (smtp_input)
        Uunlink(spool_fname(US"input", message_subdir, message_id, US"-D"));
        Uunlink(spool_fname(US"input", message_subdir, message_id, US"-H"));
        Uunlink(spool_fname(US"msglog", message_subdir, message_id, US""));
-       message_id[0] = 0;        /* Prevent a delivery from starting */
        break;
 
       case TMP_REJ:
@@ -4307,12 +4346,15 @@ if (smtp_input)
          Uunlink(spool_fname(US"input", message_subdir, message_id, US"-H"));
          Uunlink(spool_fname(US"msglog", message_subdir, message_id, US""));
          }
-       message_id[0] = 0;        /* Prevent a delivery from starting */
       default:
        break;
       }
-    cutthrough.delivery = FALSE;
-    cutthrough.defer_pass = FALSE;
+    if (cutthrough_done != NOT_TRIED)
+      {
+      message_id[0] = 0;         /* Prevent a delivery from starting */
+      cutthrough.delivery = cutthrough.callout_hold_only = FALSE;
+      cutthrough.defer_pass = FALSE;
+      }
     }
 
   /* For batched SMTP, generate an error message on failure, and do
index 9274f9095bb83bd027129baa8872512d9699369b..3560bef529a813158ab690991fd650832da394de 100644 (file)
@@ -105,7 +105,7 @@ regex_match_string = NULL;
 
 if (!mime_stream)                              /* We are in the DATA ACL */
   {
-  if (!(mbox_file = spool_mbox(&mbox_size, NULL)))
+  if (!(mbox_file = spool_mbox(&mbox_size, NULL, NULL)))
     {                                          /* error while spooling */
     log_write(0, LOG_MAIN|LOG_PANIC,
           "regex acl condition: error while creating mbox spool file");
index 364591bd09214a617794d557fde67d7471cb0dca..91c27104a82b950f35db48b5756ded0c6059e8bb 100644 (file)
@@ -54,8 +54,8 @@ if (retry != NULL && retry->rules != NULL)
        last_rule = last_rule->next);
   DEBUG(D_retry)
     debug_printf("  received_time=%d diff=%d timeout=%d\n",
-      received_time, (int)(now - received_time), last_rule->timeout);
-  address_timeout = (now - received_time > last_rule->timeout);
+      (int)received_time.tv_sec, (int)(now - received_time.tv_sec), last_rule->timeout);
+  address_timeout = (now - received_time.tv_sec > last_rule->timeout);
   }
 else
   {
@@ -159,8 +159,7 @@ deliveries (so as to do it all in one go). The tree records addresses that have
 become unusable during this delivery process (i.e. those that will get put into
 the retry database when it is updated). */
 
-node = tree_search(tree_unusable, host_key);
-if (node != NULL)
+if ((node = tree_search(tree_unusable, host_key)))
   {
   DEBUG(D_transport|D_retry) debug_printf("found in tree of unusables\n");
   host->status = (node->data.val > 255)?
@@ -172,7 +171,7 @@ if (node != NULL)
 /* Open the retry database, giving up if there isn't one. Otherwise, search for
 the retry records, and then close the database again. */
 
-if ((dbm_file = dbfn_open(US"retry", O_RDONLY, &dbblock, FALSE)) == NULL)
+if (!(dbm_file = dbfn_open(US"retry", O_RDONLY, &dbblock, FALSE)))
   {
   DEBUG(D_deliver|D_retry|D_hints_lookup)
     debug_printf("no retry data available\n");
@@ -184,7 +183,7 @@ dbfn_close(dbm_file);
 
 /* Ignore the data if it is too old - too long since it was written */
 
-if (host_retry_record == NULL)
+if (!host_retry_record)
   {
   DEBUG(D_transport|D_retry) debug_printf("no host retry record\n");
   }
@@ -194,7 +193,7 @@ else if (now - host_retry_record->time_stamp > retry_data_expire)
   DEBUG(D_transport|D_retry) debug_printf("host retry record too old\n");
   }
 
-if (message_retry_record == NULL)
+if (!message_retry_record)
   {
   DEBUG(D_transport|D_retry) debug_printf("no message retry record\n");
   }
@@ -211,7 +210,7 @@ address. Allow the delivery if it has. Otherwise set the appropriate unusable
 flag and return FALSE. Otherwise arrange to return TRUE if this is an expired
 host. */
 
-if (host_retry_record != NULL)
+if (host_retry_record)
   {
   *retry_host_key = host_key;
 
@@ -243,7 +242,7 @@ if (host_retry_record != NULL)
 for reaching its retry time (or forcing). If not, mark the host unusable,
 unless the ultimate address timeout has been reached. */
 
-if (message_retry_record != NULL)
+if (message_retry_record)
   {
   *retry_message_key = message_key;
   if (now < message_retry_record->next_try && !deliver_force)
@@ -295,6 +294,7 @@ retry_add_item(address_item *addr, uschar *key, int flags)
 {
 retry_item *rti = store_get(sizeof(retry_item));
 host_item * host = addr->host_used;
+
 rti->next = addr->retries;
 addr->retries = rti;
 rti->key = key;
@@ -378,7 +378,7 @@ if (alternate)    alternate = string_sprintf("*@%s", alternate);
 
 /* Scan the configured retry items. */
 
-for (yield = retries; yield != NULL; yield = yield->next)
+for (yield = retries; yield; yield = yield->next)
   {
   const uschar *plist = yield->pattern;
   const uschar *slist = yield->senders;
@@ -472,19 +472,19 @@ for (yield = retries; yield != NULL; yield = yield->next)
   /* If the "senders" condition is set, check it. Note that sender_address may
   be null during -brt checking, in which case we do not use this rule. */
 
-  if (slist != NULL && (sender_address == NULL ||
-      match_address_list(sender_address, TRUE, TRUE, &slist, NULL, -1, 0,
-        NULL) != OK))
+  if (  slist
+     && (  !sender_address
+               || match_address_list_basic(sender_address, &slist, 0) != OK
+     )  )
     continue;
 
   /* Check for a match between the address list item at the start of this retry
   rule and either the main or alternate keys. */
 
-  if (match_address_list(key, TRUE, TRUE, &plist, NULL, -1, UCHAR_MAX+1,
-        NULL) == OK ||
-     (alternate != NULL &&
-      match_address_list(alternate, TRUE, TRUE, &plist, NULL, -1,
-        UCHAR_MAX+1, NULL) == OK))
+  if (  match_address_list_basic(key, &plist, UCHAR_MAX+1) == OK
+     || (  alternate
+       && match_address_list_basic(alternate, &plist, UCHAR_MAX+1) == OK
+     )  )
     break;
   }
 
@@ -639,7 +639,6 @@ for (i = 0; i < 3; i++)
           }
 
         DEBUG(D_retry)
-          {
           if (rti->flags & rf_host)
             debug_printf("retry for %s (%s) = %s %d %d\n", rti->key,
               addr->domain, retry->pattern, retry->basic_errno,
@@ -647,7 +646,6 @@ for (i = 0; i < 3; i++)
           else
             debug_printf("retry for %s = %s %d %d\n", rti->key, retry->pattern,
               retry->basic_errno, retry->more_errno);
-          }
 
         /* Set up the message for the database retry record. Because DBM
         records have a maximum data length, we enforce a limit. There isn't
@@ -756,7 +754,7 @@ for (i = 0; i < 3; i++)
         this is a small bit of code, and it does no harm to leave it in place,
         just in case. */
 
-        if (  received_time <= retry_record->first_failed
+        if (  received_time.tv_sec <= retry_record->first_failed
           && addr == endaddr
           && !retry_record->expired
           && rule)
@@ -764,7 +762,7 @@ for (i = 0; i < 3; i++)
           retry_rule *last_rule;
           for (last_rule = rule; last_rule->next; last_rule = last_rule->next)
            ;
-          if (now - received_time > last_rule->timeout)
+          if (now - received_time.tv_sec > last_rule->timeout)
             {
             DEBUG(D_retry) debug_printf("on queue longer than maximum retry\n");
             timedout_count++;
@@ -861,10 +859,8 @@ for (i = 0; i < 3; i++)
           timed_out = TRUE;
           }
         else
-          {
           DEBUG(D_retry)
             debug_printf("timed out but some hosts were skipped\n");
-          }
       }     /* Loop for an address and its parents */
 
     /* If this is a deferred address, and retry processing was requested by
index 5c987e292f2f53f50bc8e06015eac4e9a73631d3..041a18858768ace59de0f89b6c38c433ffe8fbdd 100644 (file)
@@ -50,7 +50,7 @@ ptr = *ptrptr = store_get(Ustrlen(string) + 1);  /* No longer than this */
 
 while (*string != 0)
   {
-  register int ch = *string++;
+  int ch = *string++;
 
   if (ch == '_') *ptr++ = ' ';
   else if (ch == '=')
@@ -197,9 +197,9 @@ uschar *mimeword, *q1, *q2, *endword;
 *error = NULL;
 mimeword = decode_mimeword(string, lencheck, &q1, &q2, &endword, &dlen, &dptr);
 
-if (mimeword == NULL)
+if (!mimeword)
   {
-  if (lenptr != NULL) *lenptr = size;
+  if (lenptr) *lenptr = size;
   return string;
   }
 
@@ -210,7 +210,7 @@ string building code. */
 
 yield = store_get(++size);
 
-while (mimeword != NULL)
+while (mimeword)
   {
 
   #if HAVE_ICONV
@@ -317,7 +317,7 @@ while (mimeword != NULL)
 
   string = endword + 2;
   mimeword = decode_mimeword(string, lencheck, &q1, &q2, &endword, &dlen, &dptr);
-  if (mimeword != NULL)
+  if (mimeword)
     {
     uschar *s = string;
     while (isspace(*s)) s++;
@@ -330,8 +330,8 @@ the length as well if requested. */
 
 yield = string_cat(yield, &size, &ptr, string);
 yield[ptr] = 0;
-if (lenptr != NULL) *lenptr = ptr;
-if (sizeptr != NULL) *sizeptr = size;
+if (lenptr) *lenptr = ptr;
+if (sizeptr) *sizeptr = size;
 return yield;
 }
 
index 08b3e055dd6e9ea76cf614269b57ba1e393d4954..bbaa5285d37f9decffcfb9e81f77d851602d9b29 100644 (file)
@@ -143,20 +143,28 @@ optionlist optionlist_routers[] = {
 int optionlist_routers_size = sizeof(optionlist_routers)/sizeof(optionlist);
 
 
+#ifdef MACRO_PREDEF
+
+# include "macro_predef.h"
+
 void
-readconf_options_routers(void)
+options_routers(void)
 {
 struct router_info * ri;
+uschar buf[64];
 
-readconf_options_from_list(optionlist_routers, nelem(optionlist_routers), US"ROUTERS", NULL);
+options_from_list(optionlist_routers, nelem(optionlist_routers), US"ROUTERS", NULL);
 
 for (ri = routers_available; ri->driver_name[0]; ri++)
   {
-  macro_create(string_sprintf("_DRIVER_ROUTER_%T", ri->driver_name), US"y", FALSE, TRUE);
-  readconf_options_from_list(ri->options, (unsigned)*ri->options_count, US"ROUTER", ri->driver_name);
+  spf(buf, sizeof(buf), US"_DRIVER_ROUTER_%T", ri->driver_name);
+  builtin_macro_create(buf);
+  options_from_list(ri->options, (unsigned)*ri->options_count, US"ROUTER", ri->driver_name);
   }
 }
 
+#else  /*!MACRO_PREDEF*/
+
 /*************************************************
 *          Set router pointer from name          *
 *************************************************/
@@ -1357,7 +1365,7 @@ new->prop.errors_address = parent->prop.errors_address;
 
 /* Copy the propagated flags and address_data from the original. */
 
-copyflag(new, addr, af_propagate);
+new->prop.ignore_error = addr->prop.ignore_error;
 new->prop.address_data = addr->prop.address_data;
 new->dsn_flags = addr->dsn_flags;
 new->dsn_orcpt = addr->dsn_orcpt;
@@ -1919,4 +1927,5 @@ disable_logging = FALSE;
 return yield;
 }
 
+#endif /*!MACRO_PREDEF*/
 /* End of route.c */
index 6c76c7119b0bc30d217e839eba2271b2f6650c04..b3a54e7cb83864be2f3bc779ecd200b30a667acc 100644 (file)
@@ -32,6 +32,18 @@ accept_router_options_block accept_router_option_defaults = {
 };
 
 
+#ifdef MACRO_PREDEF
+
+/* Dummy entries */
+void accept_router_init(router_instance *rblock) {}
+int accept_router_entry(router_instance *rblock, address_item *addr,
+  struct passwd *pw, int verify, address_item **addr_local,
+  address_item **addr_remote, address_item **addr_new,
+  address_item **addr_succeed) {return 0;}
+
+#else  /*!MACRO_PREDEF*/
+
+
 
 /*************************************************
 *          Initialization entry point            *
@@ -125,4 +137,5 @@ addr->prop.remove_headers = remove_headers;
 return rf_queue_add(addr, addr_local, addr_remote, rblock, pw)? OK : DEFER;
 }
 
+#endif /*!MACRO_PREDEF*/
 /* End of routers/accept.c */
index e4f7a2539335764ed1df37ebe0c75830ca07c657..9e230b1be492512ba6fe70bc35fdd5d2e2e92b38 100644 (file)
@@ -44,6 +44,22 @@ address can appear in the tables drtables.c. */
 int dnslookup_router_options_count =
   sizeof(dnslookup_router_options)/sizeof(optionlist);
 
+
+#ifdef MACRO_PREDEF
+
+/* Dummy entries */
+dnslookup_router_options_block dnslookup_router_option_defaults = {0};
+void dnslookup_router_init(router_instance *rblock) {}
+int dnslookup_router_entry(router_instance *rblock, address_item *addr,
+  struct passwd *pw, int verify, address_item **addr_local,
+  address_item **addr_remote, address_item **addr_new,
+  address_item **addr_succeed) {return 0;}
+
+#else   /*!MACRO_PREDEF*/
+
+
+
+
 /* Default private options block for the dnslookup router. */
 
 dnslookup_router_options_block dnslookup_router_option_defaults = {
@@ -446,6 +462,7 @@ return rf_queue_add(addr, addr_local, addr_remote, rblock, pw)?
   OK : DEFER;
 }
 
+#endif   /*!MACRO_PREDEF*/
 /* End of routers/dnslookup.c */
 /* vi: aw ai sw=2
 */
index 22d292d881e3c9b1f9a6856d3489ebbf1be9cb1f..5cd6da52afe586faff9d94c7fcfa84f43068f730 100644 (file)
@@ -30,6 +30,17 @@ value is present to keep some compilers happy. */
 ipliteral_router_options_block ipliteral_router_option_defaults = { 0 };
 
 
+#ifdef MACRO_PREDEF
+
+/* Dummy entries */
+void ipliteral_router_init(router_instance *rblock) {}
+int ipliteral_router_entry(router_instance *rblock, address_item *addr,
+  struct passwd *pw, int verify, address_item **addr_local,
+  address_item **addr_remote, address_item **addr_new,
+  address_item **addr_succeed) {return 0;}
+
+#else   /*!MACRO_PREDEF*/
+
 
 /*************************************************
 *          Initialization entry point            *
@@ -190,4 +201,5 @@ return rf_queue_add(addr, addr_local, addr_remote, rblock, pw)?
   OK : DEFER;
 }
 
+#endif   /*!MACRO_PREDEF*/
 /* End of routers/ipliteral.c */
index 96e9626df63236d37e80deddfcad1dfd7c826fd5..3592809ea67e6a54cfb2f682aa998b7de3ac6a7f 100644 (file)
@@ -44,6 +44,20 @@ address can appear in the tables drtables.c. */
 int iplookup_router_options_count =
   sizeof(iplookup_router_options)/sizeof(optionlist);
 
+
+#ifdef MACRO_PREDEF
+
+/* Dummy entries */
+iplookup_router_options_block iplookup_router_option_defaults = {0};
+void iplookup_router_init(router_instance *rblock) {}
+int iplookup_router_entry(router_instance *rblock, address_item *addr,
+  struct passwd *pw, int verify, address_item **addr_local,
+  address_item **addr_remote, address_item **addr_new,
+  address_item **addr_succeed) {return 0;}
+
+#else   /*!MACRO_PREDEF*/
+
+
 /* Default private options block for the iplookup router. */
 
 iplookup_router_options_block iplookup_router_option_defaults = {
@@ -240,9 +254,10 @@ while ((hostname = string_nextinlist(&listptr, &sep, host_buffer,
     /* Connect to the remote host, under a timeout. In fact, timeouts can occur
     here only for TCP calls; for a UDP socket, "connect" always works (the
     router will timeout later on the read call). */
+/*XXX could take advantage of TFO */
 
     if (ip_connect(query_socket, host_af, h->address,ob->port, ob->timeout,
-                       ob->protocol != ip_udp) < 0)
+               ob->protocol == ip_udp ? NULL : &tcp_fastopen_nodata) < 0)
       {
       close(query_socket);
       DEBUG(D_route)
@@ -379,7 +394,6 @@ the chain of new addressess. */
 new_addr = deliver_make_addr(reroute, TRUE);
 new_addr->parent = addr;
 
-copyflag(new_addr, addr, af_propagate);
 new_addr->prop = addr->prop;
 
 if (addr->child_count == USHRT_MAX)
@@ -402,4 +416,5 @@ if (rc != OK) return rc;
 return OK;
 }
 
+#endif   /*!MACRO_PREDEF*/
 /* End of routers/iplookup.c */
index 95c69328d664cc8e4f1166e28429536d344d3bd0..a695a9b6a96d40d88629d18a09bef887835e1d1c 100644 (file)
@@ -34,6 +34,21 @@ address can appear in the tables drtables.c. */
 int manualroute_router_options_count =
   sizeof(manualroute_router_options)/sizeof(optionlist);
 
+
+#ifdef MACRO_PREDEF
+
+/* Dummy entries */
+manualroute_router_options_block manualroute_router_option_defaults = {0};
+void manualroute_router_init(router_instance *rblock) {}
+int manualroute_router_entry(router_instance *rblock, address_item *addr,
+  struct passwd *pw, int verify, address_item **addr_local,
+  address_item **addr_remote, address_item **addr_new,
+  address_item **addr_succeed) {return 0;}
+
+#else   /*!MACRO_PREDEF*/
+
+
+
 /* Default private options block for the manualroute router. */
 
 manualroute_router_options_block manualroute_router_option_defaults = {
@@ -333,7 +348,7 @@ while (*options != 0)
     {
     transport_instance *t;
     for (t = transports; t != NULL; t = t->next)
-      if (Ustrcmp(t->name, s) == 0)
+      if (Ustrncmp(t->name, s, n) == 0)
         {
         transport = t;
         individual_transport_set = TRUE;
@@ -474,4 +489,5 @@ addr->transport = transport;
 return OK;
 }
 
+#endif   /*!MACRO_PREDEF*/
 /* End of routers/manualroute.c */
index cd02f366f1ab3d697094204fba521d1f9374c65c..abba024dbe9bfcba6f3d962ef06d12299db11bc4 100644 (file)
@@ -40,6 +40,20 @@ address can appear in the tables drtables.c. */
 int queryprogram_router_options_count =
   sizeof(queryprogram_router_options)/sizeof(optionlist);
 
+
+#ifdef MACRO_PREDEF
+
+/* Dummy entries */
+queryprogram_router_options_block queryprogram_router_option_defaults = {0};
+void queryprogram_router_init(router_instance *rblock) {}
+int queryprogram_router_entry(router_instance *rblock, address_item *addr,
+  struct passwd *pw, int verify, address_item **addr_local,
+  address_item **addr_remote, address_item **addr_new,
+  address_item **addr_succeed) {return 0;}
+
+#else   /*!MACRO_PREDEF*/
+
+
 /* Default private options block for the queryprogram router. */
 
 queryprogram_router_options_block queryprogram_router_option_defaults = {
@@ -109,12 +123,14 @@ add_generated(router_instance *rblock, address_item **addr_new,
 {
 while (generated != NULL)
   {
+  BOOL ignore_error = addr->prop.ignore_error;
   address_item *next = generated;
+
   generated = next->next;
 
   next->parent = addr;
-  orflag(next, addr, af_propagate);
   next->prop = *addr_prop;
+  next->prop.ignore_error = next->prop.ignore_error || ignore_error;
   next->start_router = rblock->redirect_router;
 
   next->next = *addr_new;
@@ -539,4 +555,5 @@ return rf_queue_add(addr, addr_local, addr_remote, rblock, pw)?
   OK : DEFER;
 }
 
+#endif   /*!MACRO_PREDEF*/
 /* End of routers/queryprogram.c */
index 29537baaee5bc46359a782f1fa4c913055be8e8e..9923af58514af31cbc369b69fc412c99ee4d4b19 100644 (file)
@@ -133,6 +133,21 @@ address can appear in the tables drtables.c. */
 int redirect_router_options_count =
   sizeof(redirect_router_options)/sizeof(optionlist);
 
+
+#ifdef MACRO_PREDEF
+
+/* Dummy entries */
+redirect_router_options_block redirect_router_option_defaults = {0};
+void redirect_router_init(router_instance *rblock) {}
+int redirect_router_entry(router_instance *rblock, address_item *addr,
+  struct passwd *pw, int verify, address_item **addr_local,
+  address_item **addr_remote, address_item **addr_new,
+  address_item **addr_succeed) {return 0;}
+
+#else   /*!MACRO_PREDEF*/
+
+
+
 /* Default private options block for the redirect router. */
 
 redirect_router_options_block redirect_router_option_defaults = {
@@ -333,7 +348,6 @@ while (generated)
 
   generated = next->next;
   next->parent = addr;
-  orflag(next, addr, af_ignore_error);
   next->start_router = rblock->redirect_router;
   if (addr->child_count == USHRT_MAX)
     log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s router generated more than %d "
@@ -373,8 +387,12 @@ while (generated)
   If so, we must take care to re-instate it when we copy in the propagated
   data so that it overrides any errors_to setting on the router. */
 
-  next->prop = *addr_prop;
-  if (errors_address != NULL) next->prop.errors_address = errors_address;
+    {
+    BOOL ignore_error = next->prop.ignore_error;
+    next->prop = *addr_prop;
+    next->prop.ignore_error = ignore_error || addr->prop.ignore_error;
+    }
+  if (errors_address) next->prop.errors_address = errors_address;
 
   /* For pipes, files, and autoreplies, record this router as handling them,
   because they don't go through the routing process again. Then set up uid,
@@ -897,10 +915,8 @@ else
   next->next = *addr_new;
   *addr_new = next;
 
-  /* Copy relevant flags (af_propagate is a name for the set), and set the
-  data that propagates. */
+  /* Set the data that propagates. */
 
-  copyflag(next, addr, af_propagate);
   next->prop = addr_prop;
 
   DEBUG(D_route) debug_printf("%s router autogenerated %s\n%s%s%s",
@@ -921,4 +937,5 @@ addr->next = *addr_succeed;
 return yield;
 }
 
+#endif   /*!MACRO_PREDEF*/
 /* End of routers/redirect.c */
index d7172d7ac3478b1acfed76b2bc0e11009392d0eb..d81f0e90727f2a74bf4fe5927dc0ea07690f488b 100644 (file)
@@ -60,7 +60,7 @@ if (s == NULL)
 
 if (*s == 0)
   {
-  setflag(addr, af_ignore_error);      /* For locally detected errors */
+  addr->prop.ignore_error = TRUE;   /* For locally detected errors */
   *errors_to = US"";                   /* Return path for SMTP */
   return OK;
   }
index ecb4ee097de69680e2ec4b89e6d878305716d1f8..745704f6241ddb112a4af50957dca8f5cc8d481c 100644 (file)
@@ -91,6 +91,10 @@ if (rblock->remove_headers)
   const uschar * list = rblock->remove_headers;
   int sep = ':';
   uschar * s;
+  int size = 0, len = 0;
+
+  if (*remove_headers)
+    size = (len = Ustrlen(*remove_headers)) + 1;
 
   while ((s = string_nextinlist(&list, &sep, NULL, 0)))
     if (!(s = expand_string(s)))
@@ -104,7 +108,7 @@ if (rblock->remove_headers)
        }
       }
     else if (*s)
-      *remove_headers = string_append_listele(*remove_headers, ':', s);
+      *remove_headers = string_append_listele(*remove_headers, &size, &len, ':', s);
   }
 
 return OK;
index 784a5477fca25d2c98e8da40ab22dc101db2bb86..1eb109c89e3e531c4b17351124bc3c5632910aee 100644 (file)
@@ -41,7 +41,7 @@ addr->prop.localpart_data = deliver_localpart_data;   /* use in the transport */
 
 /* Handle a local transport */
 
-if (addr->transport != NULL && addr->transport->info->local)
+if (addr->transport && addr->transport->info->local)
   {
   ugid_block ugid;
 
@@ -50,11 +50,13 @@ if (addr->transport != NULL && addr->transport->info->local)
   When getting the home directory out of the password information, set the
   flag that prevents expansion later. */
 
-  if (pw != NULL)
+  if (pw)
     {
     addr->uid = pw->pw_uid;
     addr->gid = pw->pw_gid;
-    setflag(addr, af_uid_set|af_gid_set|af_home_expanded);
+    setflag(addr, af_uid_set);
+    setflag(addr, af_gid_set);
+    setflag(addr, af_home_expanded);
     addr->home_dir = string_copy(US pw->pw_dir);
     }
 
@@ -65,12 +67,12 @@ if (addr->transport != NULL && addr->transport->info->local)
   otherwise use the expanded value of router_home_directory. The flag also
   tells the transport not to re-expand it. */
 
-  if (rblock->home_directory != NULL)
+  if (rblock->home_directory)
     {
     addr->home_dir = rblock->home_directory;
     clearflag(addr, af_home_expanded);
     }
-  else if (addr->home_dir == NULL && testflag(addr, af_home_expanded))
+  else if (!addr->home_dir && testflag(addr, af_home_expanded))
     addr->home_dir = deliver_home;
 
   addr->current_dir = rblock->current_directory;
index 96344c416d33fa2dc1f46eebad5a514b6e9beeb5..32d9279eaba612ce4d52ecced3394a551925b48e 100644 (file)
@@ -291,7 +291,6 @@ for (pass=0; pass<=1; ++pass)
       else
         {              /* encoded char */
         new += sprintf(CS new,"=%02X",ch);
-        new+=3;
         }
       line+=3;
       }
@@ -414,7 +413,7 @@ static int parse_mailto_uri(struct Sieve *filter, const uschar *uri, string_item
 {
 const uschar *start;
 struct String to, hname;
-struct String hvalue = {NULL, 0};
+struct String hvalue = {.character = NULL, .length = 0};
 int capacity;
 string_item *new;
 
@@ -1046,30 +1045,33 @@ Arguments:
 Returns:      nothing
 */
 
-static void add_addr(address_item **generated, uschar *addr, int file, int maxage, int maxmessages, int maxstorage)
+static void
+add_addr(address_item **generated, uschar *addr, int file, int maxage, int maxmessages, int maxstorage)
 {
 address_item *new_addr;
 
 for (new_addr=*generated; new_addr; new_addr=new_addr->next)
-  {
-  if (Ustrcmp(new_addr->address,addr)==0 && (file ? testflag(new_addr, af_pfr|af_file) : 1))
+  if (  Ustrcmp(new_addr->address,addr) == 0
+     && (  !file
+       || testflag(new_addr, af_pfr)
+       || testflag(new_addr, af_file)
+       )
+     )
     {
     if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
-      {
       debug_printf("Repeated %s `%s' ignored.\n",file ? "fileinto" : "redirect", addr);
-      }
+
     return;
     }
-  }
 
 if ((filter_test != FTEST_NONE && debug_selector != 0) || (debug_selector & D_filter) != 0)
-  {
   debug_printf("%s `%s'\n",file ? "fileinto" : "redirect", addr);
-  }
-new_addr=deliver_make_addr(addr,TRUE);
+
+new_addr = deliver_make_addr(addr,TRUE);
 if (file)
   {
-  setflag(new_addr, af_pfr|af_file);
+  setflag(new_addr, af_pfr);
+  setflag(new_addr, af_file);
   new_addr->mode = 0;
   }
 new_addr->prop.errors_address = NULL;
@@ -3346,7 +3348,7 @@ while (*filter->pc)
 
           addr = deliver_make_addr(string_sprintf(">%.256s", sender_address), FALSE);
           setflag(addr, af_pfr);
-          setflag(addr, af_ignore_error);
+          addr->prop.ignore_error = TRUE;
           addr->next = *generated;
           *generated = addr;
           addr->reply = store_get(sizeof(reply_item));
@@ -3390,7 +3392,7 @@ while (*filter->pc)
             }
           else
             {
-            struct String qp = { NULL, 0 };  /* Keep compiler happy (PH) */
+            struct String qp = { .character = NULL, .length = 0 };  /* Keep compiler happy (PH) */
 
             capacity = 0;
             start = reason.length;
index f0885b3a13b1ca6c65a3effe44f97d1ea9ef2e6c..36f6856772d0b02f74e2041c6e8b8986b3732fa8 100644 (file)
@@ -314,10 +314,10 @@ static void smtp_rset_handler(void);
 *************************************************/
 
 /* Synchronization checks can never be perfect because a packet may be on its
-way but not arrived when the check is done. Such checks can in any case only be
-done when TLS is not in use. Normally, the checks happen when commands are
-read: Exim ensures that there is no more input in the input buffer. In normal
-cases, the response to the command will be fast, and there is no further check.
+way but not arrived when the check is done.  Normally, the checks happen when
+commands are read: Exim ensures that there is no more input in the input buffer.
+In normal cases, the response to the command will be fast, and there is no
+further check.
 
 However, for some commands an ACL is run, and that can include delays. In those
 cases, it is useful to do another check on the input just before sending the
@@ -333,15 +333,19 @@ Returns:   TRUE if all is well; FALSE if there is input pending
 */
 
 static BOOL
-check_sync(void)
+wouldblock_reading(void)
 {
 int fd, rc;
 fd_set fds;
 struct timeval tzero;
 
-if (!smtp_enforce_sync || sender_host_address == NULL ||
-    sender_host_notsocket || tls_in.active >= 0)
-  return TRUE;
+#ifdef SUPPORT_TLS
+if (tls_in.active >= 0)
+ return !tls_could_read();
+#endif
+
+if (smtp_inptr < smtp_inend)
+  return FALSE;
 
 fd = fileno(smtp_in);
 FD_ZERO(&fds);
@@ -361,6 +365,29 @@ smtp_inptr[rc] = 0;
 return FALSE;
 }
 
+static BOOL
+check_sync(void)
+{
+if (!smtp_enforce_sync || sender_host_address == NULL || sender_host_notsocket)
+  return TRUE;
+
+return wouldblock_reading();
+}
+
+
+/* If there's input waiting (and we're doing pipelineing) then we can pipeline
+a reponse with the one following. */
+
+static BOOL
+pipeline_response(void)
+{
+if (  !smtp_enforce_sync || !sender_host_address
+   || sender_host_notsocket || !pipelining_advertised)
+  return FALSE;
+
+return !wouldblock_reading();
+}
+
 
 
 /*************************************************
@@ -400,6 +427,44 @@ log_write(L_smtp_incomplete_transaction, LOG_MAIN|LOG_SENDER|LOG_RECIPIENTS,
 
 
 
+/* Refill the buffer, and notify DKIM verification code.
+Return false for error or EOF.
+*/
+
+static BOOL
+smtp_refill(unsigned lim)
+{
+int rc, save_errno;
+if (!smtp_out) return FALSE;
+fflush(smtp_out);
+if (smtp_receive_timeout > 0) alarm(smtp_receive_timeout);
+
+/* Limit amount read, so non-message data is not fed to DKIM */
+
+rc = read(fileno(smtp_in), smtp_inbuffer, MIN(IN_BUFFER_SIZE, lim));
+save_errno = errno;
+alarm(0);
+if (rc <= 0)
+  {
+  /* Must put the error text in fixed store, because this might be during
+  header reading, where it releases unused store above the header. */
+  if (rc < 0)
+    {
+    smtp_had_error = save_errno;
+    smtp_read_error = string_copy_malloc(
+      string_sprintf(" (error: %s)", strerror(save_errno)));
+    }
+  else smtp_had_eof = 1;
+  return FALSE;
+  }
+#ifndef DISABLE_DKIM
+dkim_exim_verify_feed(smtp_inbuffer, rc);
+#endif
+smtp_inend = smtp_inbuffer + rc;
+smtp_inptr = smtp_inbuffer;
+return TRUE;
+}
+
 /*************************************************
 *          SMTP version of getc()                *
 *************************************************/
@@ -417,39 +482,28 @@ int
 smtp_getc(unsigned lim)
 {
 if (smtp_inptr >= smtp_inend)
-  {
-  int rc, save_errno;
-  if (!smtp_out) return EOF;
-  fflush(smtp_out);
-  if (smtp_receive_timeout > 0) alarm(smtp_receive_timeout);
-
-  /* Limit amount read, so non-message data is not fed to DKIM */
-
-  rc = read(fileno(smtp_in), smtp_inbuffer, MIN(IN_BUFFER_SIZE, lim));
-  save_errno = errno;
-  alarm(0);
-  if (rc <= 0)
-    {
-    /* Must put the error text in fixed store, because this might be during
-    header reading, where it releases unused store above the header. */
-    if (rc < 0)
-      {
-      smtp_had_error = save_errno;
-      smtp_read_error = string_copy_malloc(
-        string_sprintf(" (error: %s)", strerror(save_errno)));
-      }
-    else smtp_had_eof = 1;
+  if (!smtp_refill(lim))
     return EOF;
-    }
-#ifndef DISABLE_DKIM
-  dkim_exim_verify_feed(smtp_inbuffer, rc);
-#endif
-  smtp_inend = smtp_inbuffer + rc;
-  smtp_inptr = smtp_inbuffer;
-  }
 return *smtp_inptr++;
 }
 
+uschar *
+smtp_getbuf(unsigned * len)
+{
+unsigned size;
+uschar * buf;
+
+if (smtp_inptr >= smtp_inend)
+  if (!smtp_refill(*len))
+    { *len = 0; return NULL; }
+
+if ((size = smtp_inend - smtp_inptr) > *len) size = *len;
+buf = smtp_inptr;
+smtp_inptr += size;
+*len = size;
+return buf;
+}
+
 void
 smtp_get_cache(void)
 {
@@ -493,6 +547,7 @@ for(;;)
     return lwr_receive_getc(chunking_data_left--);
 
   receive_getc = lwr_receive_getc;
+  receive_getbuf = lwr_receive_getbuf;
   receive_ungetc = lwr_receive_ungetc;
 #ifndef DISABLE_DKIM
   dkim_save = dkim_collect_input;
@@ -504,12 +559,15 @@ for(;;)
 
   if (!pipelining_advertised && !check_sync())
     {
+    unsigned n = smtp_inend - smtp_inptr;
+    if (n > 32) n = 32;
+
     incomplete_transaction_log(US"sync failure");
     log_write(0, LOG_MAIN|LOG_REJECT, "SMTP protocol synchronization error "
       "(next input sent too soon: pipelining was not advertised): "
       "rejected \"%s\" %s next input=\"%s\"",
       smtp_cmd_buffer, host_and_ident(TRUE),
-      string_printing(smtp_inptr));
+      string_printing(string_copyn(smtp_inptr, n)));
       (void) synprot_error(L_smtp_protocol_error, 554, NULL,
        US"SMTP synchronization error");
     goto repeat_until_rset;
@@ -526,7 +584,7 @@ for(;;)
     return EOD;
     }
 
-  smtp_printf("250 %u byte chunk received\r\n", chunking_datasize);
+  smtp_printf("250 %u byte chunk received\r\n", FALSE, chunking_datasize);
   chunking_state = CHUNKING_OFFERED;
   DEBUG(D_receive) debug_printf("chunking state %d\n", (int)chunking_state);
 
@@ -564,7 +622,7 @@ next_cmd:
 
     case NOOP_CMD:
       HAD(SCH_NOOP);
-      smtp_printf("250 OK\r\n");
+      smtp_printf("250 OK\r\n", FALSE);
       goto next_cmd;
 
     case BDAT_CMD:
@@ -594,6 +652,7 @@ next_cmd:
          }
 
       receive_getc = bdat_getc;
+      receive_getbuf = bdat_getbuf;
       receive_ungetc = bdat_ungetc;
 #ifndef DISABLE_DKIM
       dkim_collect_input = dkim_save;
@@ -604,14 +663,28 @@ next_cmd:
   }
 }
 
+uschar *
+bdat_getbuf(unsigned * len)
+{
+uschar * buf;
+
+if (chunking_data_left <= 0)
+  { *len = 0; return NULL; }
+
+if (*len > chunking_data_left) *len = chunking_data_left;
+buf = lwr_receive_getbuf(len); /* Either smtp_getbuf or tls_getbuf */
+chunking_data_left -= *len;
+return buf;
+}
+
 void
 bdat_flush_data(void)
 {
-while (chunking_data_left > 0)
-  if (lwr_receive_getc(chunking_data_left--) < 0)
-    break;
+unsigned n = chunking_data_left;
+(void) bdat_getbuf(&n);
 
 receive_getc = lwr_receive_getc;
+receive_getbuf = lwr_receive_getbuf;
 receive_ungetc = lwr_receive_ungetc;
 
 if (chunking_state != CHUNKING_LAST)
@@ -725,18 +798,19 @@ they are also picked up later by smtp_fflush().
 
 Arguments:
   format      format string
+  more       further data expected
   ...         optional arguments
 
 Returns:      nothing
 */
 
 void
-smtp_printf(const char *format, ...)
+smtp_printf(const char *format, BOOL more, ...)
 {
 va_list ap;
 
-va_start(ap, format);
-smtp_vprintf(format, ap);
+va_start(ap, more);
+smtp_vprintf(format, more, ap);
 va_end(ap);
 }
 
@@ -745,7 +819,7 @@ smtp_printf(), bearing in mind that in C a vararg function can't directly
 call another vararg function, only a function which accepts a va_list. */
 
 void
-smtp_vprintf(const char *format, va_list ap)
+smtp_vprintf(const char *format, BOOL more, va_list ap)
 {
 BOOL yield;
 
@@ -791,7 +865,7 @@ if (rcpt_in_progress)
 #ifdef SUPPORT_TLS
 if (tls_in.active >= 0)
   {
-  if (tls_write(TRUE, big_buffer, Ustrlen(big_buffer)) < 0)
+  if (tls_write(TRUE, big_buffer, Ustrlen(big_buffer), more) < 0)
     smtp_write_error = -1;
   }
 else
@@ -1570,7 +1644,7 @@ smtp_closedown(uschar *message)
 {
 if (smtp_in == NULL || smtp_batched_input) return;
 receive_swallow_smtp();
-smtp_printf("421 %s\r\n", message);
+smtp_printf("421 %s\r\n", FALSE, message);
 
 for (;;) switch(smtp_read_command(FALSE, GETC_BUFFER_UNLIMITED))
   {
@@ -1578,16 +1652,16 @@ for (;;) switch(smtp_read_command(FALSE, GETC_BUFFER_UNLIMITED))
   return;
 
   case QUIT_CMD:
-  smtp_printf("221 %s closing connection\r\n", smtp_active_hostname);
+  smtp_printf("221 %s closing connection\r\n", FALSE, smtp_active_hostname);
   mac_smtp_fflush();
   return;
 
   case RSET_CMD:
-  smtp_printf("250 Reset OK\r\n");
+  smtp_printf("250 Reset OK\r\n", FALSE);
   break;
 
   default:
-  smtp_printf("421 %s\r\n", message);
+  smtp_printf("421 %s\r\n", FALSE, message);
   break;
   }
 }
@@ -1723,14 +1797,33 @@ for (i = 0; i < smtp_ch_index; i++)
   sep = US",";
   }
 
-if (s != NULL) s[ptr] = 0; else s = US"";
-log_write(0, LOG_MAIN, "no MAIL in SMTP connection from %s D=%s%s",
-  host_and_ident(FALSE),
-  readconf_printtime( (int) ((long)time(NULL) - (long)smtp_connection_start)),
-  s);
+if (s) s[ptr] = 0; else s = US"";
+log_write(0, LOG_MAIN, "no MAIL in %sSMTP connection from %s D=%s%s",
+  tcp_in_fastopen ? US"TFO " : US"",
+  host_and_ident(FALSE), string_timesince(&smtp_connection_start), s);
 }
 
 
+/* Return list of recent smtp commands */
+
+uschar *
+smtp_cmd_hist(void)
+{
+uschar * list = NULL;
+int size = 0, len = 0, i;
+
+for (i = smtp_ch_index; i < SMTP_HBUFF_SIZE; i++)
+  if (smtp_connection_had[i] != SCH_NONE)
+    list = string_append_listele(list, &size, &len, ',',
+      smtp_names[smtp_connection_had[i]]);
+for (i = 0; i < smtp_ch_index; i++)
+  list = string_append_listele(list, &size, &len, ',',
+    smtp_names[smtp_connection_had[i]]);
+return list ? list : US"";
+}
+
+
+
 
 /*************************************************
 *   Check HELO line and set sender_helo_name     *
@@ -1849,17 +1942,17 @@ while (v > smtp_cmd_data && *v != '=' && !isspace(*v))
 
 n = v;
 if (*v == '=')
-{
+  {
   while(isalpha(n[-1])) n--;
   /* RFC says SP, but TAB seen in wild and other major MTAs accept it */
   if (!isspace(n[-1])) return FALSE;
   n[-1] = 0;
-}
+  }
 else
-{
+  {
   n++;
   if (v == smtp_cmd_data) return FALSE;
-}
+  }
 *v++ = 0;
 *name = n;
 *value = v;
@@ -1887,7 +1980,6 @@ smtp_reset(void *reset_point)
 recipients_list = NULL;
 rcpt_count = rcpt_defer_count = rcpt_fail_count =
   raw_recipients_count = recipients_count = recipients_list_max = 0;
-cancel_cutthrough_connection("smtp reset");
 message_linecount = 0;
 message_size = -1;
 acl_added_headers = NULL;
@@ -2018,6 +2110,7 @@ bsmtp_transaction_linecount = receive_linecount;
 
 if ((receive_feof)()) return 0;   /* Treat EOF as QUIT */
 
+cancel_cutthrough_connection(TRUE, US"smtp_setup_batch_msg");
 smtp_reset(reset_point);                /* Reset for start of message */
 
 /* Deal with SMTP commands. This loop is exited by setting done to a POSITIVE
@@ -2042,6 +2135,7 @@ while (done <= 0)
     /* Fall through */
 
     case RSET_CMD:
+    cancel_cutthrough_connection(TRUE, US"RSET received");
     smtp_reset(reset_point);
     bsmtp_transaction_linecount = receive_linecount;
     break;
@@ -2065,6 +2159,7 @@ while (done <= 0)
 
     /* Reset to start of message */
 
+    cancel_cutthrough_connection(TRUE, US"MAIL received");
     smtp_reset(reset_point);
 
     /* Apply SMTP rewrite */
@@ -2237,6 +2332,28 @@ return FALSE;
 }
 
 
+
+
+#ifdef TCP_FASTOPEN
+static void
+tfo_in_check(void)
+{
+# ifdef TCP_INFO
+struct tcp_info tinfo;
+socklen_t len = sizeof(tinfo);
+
+if (  getsockopt(fileno(smtp_out), IPPROTO_TCP, TCP_INFO, &tinfo, &len) == 0
+   && tinfo.tcpi_state == TCP_SYN_RECV
+   )
+  {
+  DEBUG(D_receive) debug_printf("TCP_FASTOPEN mode connection\n");
+  tcp_in_fastopen = TRUE;
+  }
+# endif
+}
+#endif
+
+
 /*************************************************
 *          Start an SMTP session                 *
 *************************************************/
@@ -2259,7 +2376,7 @@ uschar *user_msg, *log_msg;
 uschar *code, *esc;
 uschar *p, *s, *ss;
 
-smtp_connection_start = time(NULL);
+gettimeofday(&smtp_connection_start, NULL);
 for (smtp_ch_index = 0; smtp_ch_index < SMTP_HBUFF_SIZE; smtp_ch_index++)
   smtp_connection_had[smtp_ch_index] = SCH_NONE;
 smtp_ch_index = 0;
@@ -2326,10 +2443,11 @@ else
 /* Set up the buffer for inputting using direct read() calls, and arrange to
 call the local functions instead of the standard C ones. */
 
-if (!(smtp_inbuffer = (uschar *)malloc(IN_BUFFER_SIZE)))
+if (!(smtp_inbuffer = US malloc(IN_BUFFER_SIZE)))
   log_write(0, LOG_MAIN|LOG_PANIC_DIE, "malloc() failed for SMTP input buffer");
 
 receive_getc = smtp_getc;
+receive_getbuf = smtp_getbuf;
 receive_get_cache = smtp_get_cache;
 receive_ungetc = smtp_ungetc;
 receive_feof = smtp_feof;
@@ -2431,14 +2549,14 @@ if (!sender_host_unknown)
 
     DEBUG(D_receive) debug_printf("checking for IP options\n");
 
-    if (getsockopt(fileno(smtp_out), IPPROTO_IP, IP_OPTIONS, (uschar *)(ipopt),
+    if (getsockopt(fileno(smtp_out), IPPROTO_IP, IP_OPTIONS, US (ipopt),
           &optlen) < 0)
       {
       if (errno != ENOPROTOOPT)
         {
         log_write(0, LOG_MAIN, "getsockopt() failed from %s: %s",
           host_and_ident(FALSE), strerror(errno));
-        smtp_printf("451 SMTP service not available\r\n");
+        smtp_printf("451 SMTP service not available\r\n", FALSE);
         return FALSE;
         }
       }
@@ -2457,11 +2575,11 @@ if (!sender_host_unknown)
       struct in_addr addr;
 
       #if OPTSTYLE == 1
-      uschar *optstart = (uschar *)(ipopt->__data);
+      uschar *optstart = US (ipopt->__data);
       #elif OPTSTYLE == 2
-      uschar *optstart = (uschar *)(ipopt->ip_opts);
+      uschar *optstart = US (ipopt->ip_opts);
       #else
-      uschar *optstart = (uschar *)(ipopt->ipopt_list);
+      uschar *optstart = US (ipopt->ipopt_list);
       #endif
 
       DEBUG(D_receive) debug_printf("IP options exist\n");
@@ -2470,7 +2588,7 @@ if (!sender_host_unknown)
       p += Ustrlen(p);
 
       for (opt = optstart; opt != NULL &&
-           opt < (uschar *)(ipopt) + optlen;)
+           opt < US (ipopt) + optlen;)
         {
         switch (*opt)
           {
@@ -2524,10 +2642,7 @@ if (!sender_host_unknown)
             Ustrcat(p, "[ ");
             p += 2;
             for (i = 0; i < opt[1]; i++)
-              {
-              sprintf(CS p, "%2.2x ", opt[i]);
-              p += 3;
-              }
+              p += sprintf(CS p, "%2.2x ", opt[i]);
             *p++ = ']';
             }
           opt += opt[1];
@@ -2543,7 +2658,7 @@ if (!sender_host_unknown)
       log_write(0, LOG_MAIN|LOG_REJECT,
         "connection from %s refused (IP options)", host_and_ident(FALSE));
 
-      smtp_printf("554 SMTP service not available\r\n");
+      smtp_printf("554 SMTP service not available\r\n", FALSE);
       return FALSE;
       }
 
@@ -2595,7 +2710,7 @@ if (!sender_host_unknown)
     {
     log_write(L_connection_reject, LOG_MAIN|LOG_REJECT, "refused connection "
       "from %s (host_reject_connection)", host_and_ident(FALSE));
-    smtp_printf("554 SMTP service not available\r\n");
+    smtp_printf("554 SMTP service not available\r\n", FALSE);
     return FALSE;
     }
 
@@ -2626,7 +2741,7 @@ if (!sender_host_unknown)
       log_write(L_connection_reject,
                 LOG_MAIN|LOG_REJECT, "refused connection from %s "
                 "(tcp wrappers)", host_and_ident(FALSE));
-      smtp_printf("554 SMTP service not available\r\n");
+      smtp_printf("554 SMTP service not available\r\n", FALSE);
       }
     else
       {
@@ -2636,7 +2751,7 @@ if (!sender_host_unknown)
       log_write(L_connection_reject,
                 LOG_MAIN|LOG_REJECT, "temporarily refused connection from %s "
                 "(tcp wrappers errno=%d)", host_and_ident(FALSE), save_errno);
-      smtp_printf("451 Temporary local problem - please try later\r\n");
+      smtp_printf("451 Temporary local problem - please try later\r\n", FALSE);
       }
     return FALSE;
     }
@@ -2656,7 +2771,7 @@ if (!sender_host_unknown)
         host_and_ident(FALSE), smtp_accept_count - 1, smtp_accept_max,
         smtp_accept_reserve, (rc == DEFER)? " (lookup deferred)" : "");
       smtp_printf("421 %s: Too many concurrent SMTP connections; "
-        "please try again later\r\n", smtp_active_hostname);
+        "please try again later\r\n", FALSE, smtp_active_hostname);
       return FALSE;
       }
     reserved_host = TRUE;
@@ -2677,7 +2792,7 @@ if (!sender_host_unknown)
       LOG_MAIN, "temporarily refused connection from %s: not in "
       "reserve list and load average = %.2f", host_and_ident(FALSE),
       (double)load_average/1000.0);
-    smtp_printf("421 %s: Too much load; please try again later\r\n",
+    smtp_printf("421 %s: Too much load; please try again later\r\n", FALSE,
       smtp_active_hostname);
     return FALSE;
     }
@@ -2817,17 +2932,28 @@ this synchronisation check is disabled. */
 
 if (!check_sync())
   {
+  unsigned n = smtp_inend - smtp_inptr;
+  if (n > 32) n = 32;
+
   log_write(0, LOG_MAIN|LOG_REJECT, "SMTP protocol "
     "synchronization error (input sent without waiting for greeting): "
     "rejected connection from %s input=\"%s\"", host_and_ident(TRUE),
-    string_printing(smtp_inptr));
-  smtp_printf("554 SMTP synchronization error\r\n");
+    string_printing(string_copyn(smtp_inptr, n)));
+  smtp_printf("554 SMTP synchronization error\r\n", FALSE);
   return FALSE;
   }
 
 /* Now output the banner */
 
-smtp_printf("%s", ss);
+smtp_printf("%s", FALSE, ss);
+
+/* Attempt to see if we sent the banner before the last ACK of the 3-way
+handshake arrived.  If so we must have managed a TFO. */
+
+#ifdef TCP_FASTOPEN
+tfo_in_check();
+#endif
+
 return TRUE;
 }
 
@@ -2874,10 +3000,10 @@ if (++synprot_error_count > smtp_max_synprot_errors)
 
 if (code > 0)
   {
-  smtp_printf("%d%c%s%s%s\r\n", code, (yield == 1)? '-' : ' ',
-    (data == NULL)? US"" : data, (data == NULL)? US"" : US": ", errmess);
+  smtp_printf("%d%c%s%s%s\r\n", FALSE, code, yield == 1 ? '-' : ' ',
+    data ? data : US"", data ? US": " : US"", errmess);
   if (yield == 1)
-    smtp_printf("%d Too many syntax or protocol errors\r\n", code);
+    smtp_printf("%d Too many syntax or protocol errors\r\n", FALSE, code);
   }
 
 return yield;
@@ -2933,25 +3059,27 @@ if (rcpt_in_progress)
   rcpt_in_progress = FALSE;
   }
 
-/* Not output the message, splitting it up into multiple lines if necessary. */
+/* Now output the message, splitting it up into multiple lines if necessary.
+We only handle pipelining these responses as far as nonfinal/final groups,
+not the whole MAIL/RCPT/DATA response set. */
 
 for (;;)
   {
   uschar *nl = Ustrchr(msg, '\n');
   if (nl == NULL)
     {
-    smtp_printf("%.3s%c%.*s%s\r\n", code, final? ' ':'-', esclen, esc, msg);
+    smtp_printf("%.3s%c%.*s%s\r\n", !final, code, final ? ' ':'-', esclen, esc, msg);
     return;
     }
   else if (nl[1] == 0 || no_multiline_responses)
     {
-    smtp_printf("%.3s%c%.*s%.*s\r\n", code, final? ' ':'-', esclen, esc,
+    smtp_printf("%.3s%c%.*s%.*s\r\n", !final, code, final ? ' ':'-', esclen, esc,
       (int)(nl - msg), msg);
     return;
     }
   else
     {
-    smtp_printf("%.3s-%.*s%.*s\r\n", code, esclen, esc, (int)(nl - msg), msg);
+    smtp_printf("%.3s-%.*s%.*s\r\n", TRUE, code, esclen, esc, (int)(nl - msg), msg);
     msg = nl + 1;
     while (isspace(*msg)) msg++;
     }
@@ -3295,7 +3423,7 @@ if (code && defaultrespond)
     va_start(ap, defaultrespond);
     if (!string_vformat(buffer, sizeof(buffer), CS defaultrespond, ap))
       log_write(0, LOG_MAIN|LOG_PANIC, "string too large in smtp_notquit_exit()");
-    smtp_printf("%s %s\r\n", code, buffer);
+    smtp_printf("%s %s\r\n", FALSE, code, buffer);
     va_end(ap);
     }
   mac_smtp_fflush();
@@ -3587,7 +3715,7 @@ if (allow_unqualified_recipient || strcmpic(*recipient, US"postmaster") == 0)
   *recipient = rewrite_address_qualify(*recipient, TRUE);
   return rd;
   }
-smtp_printf("501 %s: recipient address must contain a domain\r\n",
+smtp_printf("501 %s: recipient address must contain a domain\r\n", FALSE,
   smtp_cmd_data);
 log_write(L_smtp_syntax_error,
   LOG_MAIN|LOG_REJECT, "unqualified %s rejected: <%s> %s%s",
@@ -3613,7 +3741,7 @@ if (acl_smtp_quit)
 if (*user_msgp)
   smtp_respond(US"221", 3, TRUE, *user_msgp);
 else
-  smtp_printf("221 %s closing connection\r\n", smtp_active_hostname);
+  smtp_printf("221 %s closing connection\r\n", FALSE, smtp_active_hostname);
 
 #ifdef SUPPORT_TLS
 tls_close(TRUE, TRUE);
@@ -3629,7 +3757,7 @@ smtp_rset_handler(void)
 {
 HAD(SCH_RSET);
 incomplete_transaction_log(US"RSET");
-smtp_printf("250 Reset OK\r\n");
+smtp_printf("250 Reset OK\r\n", FALSE);
 cmd_list[CMD_LIST_RSET].is_mail_cmd = FALSE;
 }
 
@@ -3849,7 +3977,7 @@ while (done <= 0)
       {
       c = smtp_in_auth(au, &s, &ss);
 
-      smtp_printf("%s\r\n", s);
+      smtp_printf("%s\r\n", FALSE, s);
       if (c != OK)
        log_write(0, LOG_MAIN|LOG_REJECT, "%s authenticator failed for %s: %s",
          au->name, host_and_ident(FALSE), ss);
@@ -3896,7 +4024,7 @@ while (done <= 0)
 
     if (!check_helo(smtp_cmd_data))
       {
-      smtp_printf("501 Syntactically invalid %s argument(s)\r\n", hello);
+      smtp_printf("501 Syntactically invalid %s argument(s)\r\n", FALSE, hello);
 
       log_write(0, LOG_MAIN|LOG_REJECT, "rejected %s from %s: syntactically "
         "invalid argument(s): %s", hello, host_and_ident(FALSE),
@@ -3960,7 +4088,7 @@ while (done <= 0)
           {
           if (helo_required)
             {
-            smtp_printf("%d %s argument does not match calling host\r\n",
+            smtp_printf("%d %s argument does not match calling host\r\n", FALSE,
               tempfail? 451 : 550, hello);
             log_write(0, LOG_MAIN|LOG_REJECT, "%srejected \"%s %s\" from %s",
               tempfail? "temporarily " : "",
@@ -4010,19 +4138,19 @@ while (done <= 0)
 #endif
 
     smtp_code = US"250 ";        /* Default response code plus space*/
-    if (user_msg == NULL)
+    if (!user_msg)
       {
       s = string_sprintf("%.3s %s Hello %s%s%s",
         smtp_code,
         smtp_active_hostname,
-        (sender_ident == NULL)?  US"" : sender_ident,
-        (sender_ident == NULL)?  US"" : US" at ",
-        (sender_host_name == NULL)? sender_helo_name : sender_host_name);
+        sender_ident ? sender_ident : US"",
+        sender_ident ? US" at " : US"",
+        sender_host_name ? sender_host_name : sender_helo_name);
 
       ptr = Ustrlen(s);
       size = ptr + 1;
 
-      if (sender_host_address != NULL)
+      if (sender_host_address)
         {
         s = string_catn(s, &size, &ptr, US" [", 2);
         s = string_cat (s, &size, &ptr, sender_host_address);
@@ -4150,26 +4278,34 @@ while (done <= 0)
        auth_instance *au;
        BOOL first = TRUE;
        for (au = auths; au; au = au->next)
-         if (au->server && (au->advertise_condition == NULL ||
-             expand_check_condition(au->advertise_condition, au->name,
-             US"authenticator")))
+         {
+         au->advertised = FALSE;
+         if (au->server)
            {
-           int saveptr;
-           if (first)
+           DEBUG(D_auth+D_expand) debug_printf_indent(
+             "Evaluating advertise_condition for %s athenticator\n",
+             au->public_name);
+           if (  !au->advertise_condition
+              || expand_check_condition(au->advertise_condition, au->name,
+                     US"authenticator")
+              )
              {
-             s = string_catn(s, &size, &ptr, smtp_code, 3);
-             s = string_catn(s, &size, &ptr, US"-AUTH", 5);
-             first = FALSE;
-             auth_advertised = TRUE;
+             int saveptr;
+             if (first)
+               {
+               s = string_catn(s, &size, &ptr, smtp_code, 3);
+               s = string_catn(s, &size, &ptr, US"-AUTH", 5);
+               first = FALSE;
+               auth_advertised = TRUE;
+               }
+             saveptr = ptr;
+             s = string_catn(s, &size, &ptr, US" ", 1);
+             s = string_cat (s, &size, &ptr, au->public_name);
+             while (++saveptr < ptr) s[saveptr] = toupper(s[saveptr]);
+             au->advertised = TRUE;
              }
-           saveptr = ptr;
-           s = string_catn(s, &size, &ptr, US" ", 1);
-           s = string_cat (s, &size, &ptr, au->public_name);
-           while (++saveptr < ptr) s[saveptr] = toupper(s[saveptr]);
-           au->advertised = TRUE;
            }
-         else
-           au->advertised = FALSE;
+         }
 
        if (!first) s = string_catn(s, &size, &ptr, US"\r\n", 2);
        }
@@ -4230,7 +4366,7 @@ while (done <= 0)
     s[ptr] = 0;
 
 #ifdef SUPPORT_TLS
-    if (tls_in.active >= 0) (void)tls_write(TRUE, s, ptr); else
+    if (tls_in.active >= 0) (void)tls_write(TRUE, s, ptr, FALSE); else
 #endif
 
       {
@@ -4253,6 +4389,7 @@ while (done <= 0)
          : pnormal)
        + (tls_in.active >= 0 ? pcrpted : 0)
        ];
+    cancel_cutthrough_connection(TRUE, US"sent EHLO response");
     smtp_reset(reset_point);
     toomany = FALSE;
     break;   /* HELO/EHLO */
@@ -4272,7 +4409,7 @@ while (done <= 0)
 
     if (helo_required && !helo_seen)
       {
-      smtp_printf("503 HELO or EHLO required\r\n");
+      smtp_printf("503 HELO or EHLO required\r\n", FALSE);
       log_write(0, LOG_MAIN|LOG_REJECT, "rejected MAIL from %s: no "
         "HELO/EHLO given", host_and_ident(FALSE));
       break;
@@ -4298,7 +4435,7 @@ while (done <= 0)
     if (smtp_accept_max_per_connection > 0 &&
         smtp_mailcmd_count > smtp_accept_max_per_connection)
       {
-      smtp_printf("421 too many messages in this connection\r\n");
+      smtp_printf("421 too many messages in this connection\r\n", FALSE);
       log_write(0, LOG_MAIN|LOG_REJECT, "rejected MAIL command %s: too many "
         "messages in one connection", host_and_ident(TRUE));
       break;
@@ -4307,6 +4444,7 @@ while (done <= 0)
     /* Reset for start of message - even if this is going to fail, we
     obviously need to throw away any previous data. */
 
+    cancel_cutthrough_connection(TRUE, US"MAIL received");
     smtp_reset(reset_point);
     toomany = FALSE;
     sender_data = recipient_data = NULL;
@@ -4562,7 +4700,7 @@ while (done <= 0)
 
     if (thismessage_size_limit > 0 && message_size > thismessage_size_limit)
       {
-      smtp_printf("552 Message size exceeds maximum permitted\r\n");
+      smtp_printf("552 Message size exceeds maximum permitted\r\n", FALSE);
       log_write(L_size_reject,
           LOG_MAIN|LOG_REJECT, "rejected MAIL FROM:<%s> %s: "
           "message too big: size%s=%d max=%d",
@@ -4587,7 +4725,7 @@ while (done <= 0)
          (smtp_check_spool_space && message_size >= 0)?
             message_size + 5000 : 0))
       {
-      smtp_printf("452 Space shortage, please try later\r\n");
+      smtp_printf("452 Space shortage, please try later\r\n", FALSE);
       sender_address = NULL;
       break;
       }
@@ -4609,7 +4747,7 @@ while (done <= 0)
         }
       else
         {
-        smtp_printf("501 %s: sender address must contain a domain\r\n",
+        smtp_printf("501 %s: sender address must contain a domain\r\n", FALSE,
           smtp_cmd_data);
         log_write(L_smtp_syntax_error,
           LOG_MAIN|LOG_REJECT,
@@ -4637,8 +4775,10 @@ while (done <= 0)
 
     if (rc == OK || rc == DISCARD)
       {
+      BOOL more = pipeline_response();
+
       if (!user_msg)
-        smtp_printf("%s%s%s", US"250 OK",
+        smtp_printf("%s%s%s", more, US"250 OK",
                   #ifndef DISABLE_PRDR
                     prdr_requested ? US", PRDR Requested" : US"",
                  #else
@@ -4684,7 +4824,7 @@ while (done <= 0)
       {
       if (pipelining_advertised && last_was_rej_mail)
         {
-        smtp_printf("503 sender not yet given\r\n");
+        smtp_printf("503 sender not yet given\r\n", FALSE);
         was_rej_mail = TRUE;
         }
       else
@@ -4832,7 +4972,7 @@ while (done <= 0)
       if (recipients_max_reject)
         {
         rcpt_fail_count++;
-        smtp_printf("552 too many recipients\r\n");
+        smtp_printf("552 too many recipients\r\n", FALSE);
         if (!toomany)
           log_write(0, LOG_MAIN|LOG_REJECT, "too many recipients: message "
             "rejected: sender=<%s> %s", sender_address, host_and_ident(TRUE));
@@ -4840,7 +4980,7 @@ while (done <= 0)
       else
         {
         rcpt_defer_count++;
-        smtp_printf("452 too many recipients\r\n");
+        smtp_printf("452 too many recipients\r\n", FALSE);
         if (!toomany)
           log_write(0, LOG_MAIN|LOG_REJECT, "too many recipients: excess "
             "temporarily rejected: sender=<%s> %s", sender_address,
@@ -4882,10 +5022,12 @@ while (done <= 0)
 
     if (rc == OK)
       {
+      BOOL more = pipeline_response();
+
       if (user_msg)
         smtp_user_msg(US"250", user_msg);
       else
-        smtp_printf("250 Accepted\r\n");
+        smtp_printf("250 Accepted\r\n", more);
       receive_add_recipient(recipient, -1);
 
       /* Set the dsn flags in the recipients_list */
@@ -4904,7 +5046,7 @@ while (done <= 0)
       if (user_msg)
         smtp_user_msg(US"250", user_msg);
       else
-        smtp_printf("250 Accepted\r\n");
+        smtp_printf("250 Accepted\r\n", FALSE);
       rcpt_fail_count++;
       discarded = TRUE;
       log_write(0, LOG_MAIN|LOG_REJECT, "%s F=<%s> RCPT %s: "
@@ -4971,6 +5113,7 @@ while (done <= 0)
                                    (int)chunking_state, chunking_data_left);
 
       lwr_receive_getc = receive_getc;
+      lwr_receive_getbuf = receive_getbuf;
       lwr_receive_ungetc = receive_ungetc;
       receive_getc = bdat_getc;
       receive_ungetc = bdat_ungetc;
@@ -4996,7 +5139,7 @@ while (done <= 0)
         smtp_respond(code, 3, FALSE, rcpt_smtp_response);
         }
       if (pipelining_advertised && last_was_rcpt)
-        smtp_printf("503 Valid RCPT command must precede %s\r\n",
+        smtp_printf("503 Valid RCPT command must precede %s\r\n", FALSE,
          smtp_names[smtp_connection_had[smtp_ch_index-1]]);
       else
         done = synprot_error(L_smtp_protocol_error, 503, NULL,
@@ -5013,7 +5156,7 @@ while (done <= 0)
       {
       sender_address = NULL;  /* This will allow a new MAIL without RSET */
       sender_address_unrewritten = NULL;
-      smtp_printf("554 Too many recipients\r\n");
+      smtp_printf("554 Too many recipients\r\n", FALSE);
       break;
       }
 
@@ -5048,7 +5191,7 @@ while (done <= 0)
        smtp_user_msg(US"354", user_msg);
       else
        smtp_printf(
-         "354 Enter message, ending with \".\" on a line by itself\r\n");
+         "354 Enter message, ending with \".\" on a line by itself\r\n", FALSE);
       }
 
 #ifdef TCP_QUICKACK
@@ -5071,7 +5214,7 @@ while (done <= 0)
       if (!(address = parse_extract_address(smtp_cmd_data, &errmess,
             &start, &end, &recipient_domain, FALSE)))
        {
-       smtp_printf("501 %s\r\n", errmess);
+       smtp_printf("501 %s\r\n", FALSE, errmess);
        break;
        }
 
@@ -5110,7 +5253,7 @@ while (done <= 0)
            break;
          }
 
-       smtp_printf("%s\r\n", s);
+       smtp_printf("%s\r\n", FALSE, s);
        }
       break;
       }
@@ -5162,6 +5305,7 @@ while (done <= 0)
     do an implied RSET when STARTTLS is received. */
 
     incomplete_transaction_log(US"STARTTLS");
+    cancel_cutthrough_connection(TRUE, US"STARTTLS received");
     smtp_reset(reset_point);
     toomany = FALSE;
     cmd_list[CMD_LIST_STARTTLS].is_mail_cmd = FALSE;
@@ -5238,7 +5382,7 @@ while (done <= 0)
 
     if (rc == DEFER)
       {
-      smtp_printf("454 TLS currently unavailable\r\n");
+      smtp_printf("454 TLS currently unavailable\r\n", FALSE);
       break;
       }
 
@@ -5271,14 +5415,14 @@ while (done <= 0)
        if (user_msg)
          smtp_respond(US"221", 3, TRUE, user_msg);
        else
-         smtp_printf("221 %s closing connection\r\n", smtp_active_hostname);
+         smtp_printf("221 %s closing connection\r\n", FALSE, smtp_active_hostname);
        log_write(L_smtp_connection, LOG_MAIN, "%s closed by QUIT",
          smtp_get_connection_info());
        done = 2;
        break;
 
       default:
-       smtp_printf("554 Security failure\r\n");
+       smtp_printf("554 Security failure\r\n", FALSE);
        break;
       }
     tls_close(TRUE, TRUE);
@@ -5298,6 +5442,7 @@ while (done <= 0)
 
     case RSET_CMD:
     smtp_rset_handler();
+    cancel_cutthrough_connection(TRUE, US"RSET received");
     smtp_reset(reset_point);
     toomany = FALSE;
     break;
@@ -5305,7 +5450,7 @@ while (done <= 0)
 
     case NOOP_CMD:
     HAD(SCH_NOOP);
-    smtp_printf("250 OK\r\n");
+    smtp_printf("250 OK\r\n", FALSE);
     break;
 
 
@@ -5316,7 +5461,7 @@ while (done <= 0)
 
     case HELP_CMD:
     HAD(SCH_HELP);
-    smtp_printf("214-Commands supported:\r\n");
+    smtp_printf("214-Commands supported:\r\n", TRUE);
       {
       uschar buffer[256];
       buffer[0] = 0;
@@ -5331,7 +5476,7 @@ while (done <= 0)
       if (acl_smtp_etrn != NULL) Ustrcat(buffer, " ETRN");
       if (acl_smtp_expn != NULL) Ustrcat(buffer, " EXPN");
       if (acl_smtp_vrfy != NULL) Ustrcat(buffer, " VRFY");
-      smtp_printf("214%s\r\n", buffer);
+      smtp_printf("214%s\r\n", FALSE, buffer);
       }
     break;
 
@@ -5345,15 +5490,22 @@ while (done <= 0)
     just drop the call rather than sending QUIT, and it clutters up the logs.
     */
 
-    if (sender_address != NULL || recipients_count > 0)
-      log_write(L_lost_incoming_connection,
-          LOG_MAIN,
-          "unexpected %s while reading SMTP command from %s%s",
-          sender_host_unknown? "EOF" : "disconnection",
-          host_and_ident(FALSE), smtp_read_error);
+    if (sender_address || recipients_count > 0)
+      log_write(L_lost_incoming_connection, LOG_MAIN,
+       "unexpected %s while reading SMTP command from %s%s%s D=%s",
+       sender_host_unknown ? "EOF" : "disconnection",
+       tcp_in_fastopen && !tcp_in_fastopen_logged ? US"TFO " : US"",
+       host_and_ident(FALSE), smtp_read_error,
+       string_timesince(&smtp_connection_start)
+       );
 
-    else log_write(L_smtp_connection, LOG_MAIN, "%s lost%s",
-      smtp_get_connection_info(), smtp_read_error);
+    else
+      log_write(L_smtp_connection, LOG_MAIN, "%s %slost%s D=%s",
+        smtp_get_connection_info(),
+       tcp_in_fastopen && !tcp_in_fastopen_logged ? US"TFO " : US"",
+       smtp_read_error,
+       string_timesince(&smtp_connection_start)
+       );
 
     done = 1;
     break;
@@ -5400,7 +5552,7 @@ while (done <= 0)
         {
         log_write(0, LOG_MAIN|LOG_PANIC, "failed to set up ETRN command: %s",
           error);
-        smtp_printf("458 Internal failure\r\n");
+        smtp_printf("458 Internal failure\r\n", FALSE);
         break;
         }
       }
@@ -5431,7 +5583,7 @@ while (done <= 0)
         debug_printf("ETRN command is: %s\n", etrn_command);
         debug_printf("ETRN command execution skipped\n");
         }
-      if (user_msg == NULL) smtp_printf("250 OK\r\n");
+      if (user_msg == NULL) smtp_printf("250 OK\r\n", FALSE);
         else smtp_user_msg(US"250", user_msg);
       break;
       }
@@ -5442,7 +5594,7 @@ while (done <= 0)
 
     if (smtp_etrn_serialize && !enq_start(etrn_serialize_key, 1))
       {
-      smtp_printf("458 Already processing %s\r\n", smtp_cmd_data);
+      smtp_printf("458 Already processing %s\r\n", FALSE, smtp_cmd_data);
       break;
       }
 
@@ -5505,12 +5657,12 @@ while (done <= 0)
       {
       log_write(0, LOG_MAIN|LOG_PANIC, "fork of process for ETRN failed: %s",
         strerror(errno));
-      smtp_printf("458 Unable to fork process\r\n");
+      smtp_printf("458 Unable to fork process\r\n", FALSE);
       if (smtp_etrn_serialize) enq_end(etrn_serialize_key);
       }
     else
       {
-      if (user_msg == NULL) smtp_printf("250 OK\r\n");
+      if (user_msg == NULL) smtp_printf("250 OK\r\n", FALSE);
         else smtp_user_msg(US"250", user_msg);
       }
 
@@ -5529,7 +5681,7 @@ while (done <= 0)
     case BADCHAR_CMD:
     done = synprot_error(L_smtp_syntax_error, 0, NULL,       /* Just logs */
       US"NULL character(s) present (shown as '?')");
-    smtp_printf("501 NULL characters are not allowed in SMTP commands\r\n");
+    smtp_printf("501 NULL characters are not allowed in SMTP commands\r\n", FALSE);
     break;
 
 
@@ -5566,7 +5718,7 @@ while (done <= 0)
 
 #ifdef SUPPORT_PROXY
     case PROXY_FAIL_IGNORE_CMD:
-    smtp_printf("503 Command refused, required Proxy negotiation failed\r\n");
+    smtp_printf("503 Command refused, required Proxy negotiation failed\r\n", FALSE);
     break;
 #endif
 
index ba6153ea9b9316a1d54a74b889ae3aace7aefb64..db33ac66e26990c7ba0be6222ff0dd58106ee604 100644 (file)
@@ -100,7 +100,7 @@ smtp_get_port(uschar *rstring, address_item *addr, int *port, uschar *msg)
 {
 uschar *pstring = expand_string(rstring);
 
-if (pstring == NULL)
+if (!pstring)
   {
   addr->transport_return = PANIC;
   addr->message = string_sprintf("failed to expand \"%s\" (\"port\" option) "
@@ -124,7 +124,7 @@ if (isdigit(*pstring))
 else
   {
   struct servent *smtp_service = getservbyname(CS pstring, "tcp");
-  if (smtp_service == NULL)
+  if (!smtp_service)
     {
     addr->transport_return = PANIC;
     addr->message = string_sprintf("TCP port \"%s\" is not defined for %s",
@@ -140,9 +140,15 @@ return TRUE;
 
 
 
+/* Arguments as for smtp_connect(), plus
+  early_data   if non-NULL, data to be sent - preferably in the TCP SYN segment
+
+Returns:      connected socket number, or -1 with errno set
+*/
+
 int
 smtp_sock_connect(host_item * host, int host_af, int port, uschar * interface,
-  transport_instance * tb, int timeout)
+  transport_instance * tb, int timeout, const blob * early_data)
 {
 smtp_transport_options_block * ob =
   (smtp_transport_options_block *)tb->options_block;
@@ -152,7 +158,6 @@ int dscp_level;
 int dscp_option;
 int sock;
 int save_errno = 0;
-BOOL fastopen = FALSE;
 
 #ifndef DISABLE_EVENT
 deliver_host_address = host->address;
@@ -185,10 +190,6 @@ if (dscp && dscp_lookup(dscp, host_af, &dscp_level, &dscp_option, &dscp_value))
     (void) setsockopt(sock, dscp_level, dscp_option, &dscp_value, sizeof(dscp_value));
   }
 
-#ifdef TCP_FASTOPEN
-if (verify_check_given_host (&ob->hosts_try_fastopen, host) == OK) fastopen = TRUE;
-#endif
-
 /* Bind to a specific interface if requested. Caller must ensure the interface
 is the same type (IPv4 or IPv6) as the outgoing address. */
 
@@ -201,10 +202,24 @@ if (interface && ip_bind(sock, host_af, interface, 0) < 0)
   }
 
 /* Connect to the remote host, and add keepalive to the socket before returning
-it, if requested. */
+it, if requested.  If the build supports TFO, request it - and if the caller
+requested some early-data then include that in the TFO request. */
 
-else if (ip_connect(sock, host_af, host->address, port, timeout, fastopen) < 0)
-  save_errno = errno;
+else
+  {
+  const blob * fastopen = NULL;
+
+#ifdef TCP_FASTOPEN
+  if (verify_check_given_host(&ob->hosts_try_fastopen, host) == OK)
+    fastopen = early_data ? early_data : &tcp_fastopen_nodata;
+#endif
+
+  if (ip_connect(sock, host_af, host->address, port, timeout, fastopen) < 0)
+    save_errno = errno;
+  else if (early_data && !fastopen && early_data->data && early_data->len)
+    if (send(sock, early_data->data, early_data->len, 0) < 0)
+      save_errno = errno;
+  }
 
 /* Either bind() or connect() failed */
 
@@ -243,6 +258,24 @@ else
   }
 }
 
+
+
+
+
+void
+smtp_port_for_connect(host_item * host, int port)
+{
+if (host->port != PORT_NONE)
+  {
+  HDEBUG(D_transport|D_acl|D_v)
+    debug_printf_indent("Transport port=%d replaced by host-specific port=%d\n", port,
+      host->port);
+  port = host->port;
+  }
+else host->port = port;    /* Set the port actually used */
+}
+
+
 /*************************************************
 *           Connect to remote host               *
 *************************************************/
@@ -252,15 +285,9 @@ detected by checking for a colon in the address. AF_INET6 is defined even on
 non-IPv6 systems, to enable the code to be less messy. However, on such systems
 host->address will always be an IPv4 address.
 
-The port field in the host item is used if it is set (usually router from SRV
-records or elsewhere). In other cases, the default passed as an argument is
-used, and the host item is updated with its value.
-
 Arguments:
-  host        host item containing name and address (and sometimes port)
+  host        host item containing name and address and port
   host_af     AF_INET or AF_INET6
-  port        default remote port to connect to, in host byte order, for those
-                hosts whose port setting is PORT_NONE
   interface   outgoing interface address or NULL
   timeout     timeout value or 0
   tb          transport
@@ -269,23 +296,15 @@ Returns:      connected socket number, or -1 with errno set
 */
 
 int
-smtp_connect(host_item *host, int host_af, int port, uschar *interface,
+smtp_connect(host_item *host, int host_af, uschar *interface,
   int timeout, transport_instance * tb)
 {
+int port = host->port;
 #ifdef SUPPORT_SOCKS
 smtp_transport_options_block * ob =
   (smtp_transport_options_block *)tb->options_block;
 #endif
 
-if (host->port != PORT_NONE)
-  {
-  HDEBUG(D_transport|D_acl|D_v)
-    debug_printf_indent("Transport port=%d replaced by host-specific port=%d\n", port,
-      host->port);
-  port = host->port;
-  }
-else host->port = port;    /* Set the port actually used */
-
 callout_address = string_sprintf("[%s]:%d", host->address, port);
 
 HDEBUG(D_transport|D_acl|D_v)
@@ -305,7 +324,7 @@ if (ob->socks_proxy)
   return socks_sock_connect(host, host_af, port, interface, tb, timeout);
 #endif
 
-return smtp_sock_connect(host, host_af, port, interface, tb, timeout);
+return smtp_sock_connect(host, host_af, port, interface, tb, timeout, NULL);
 }
 
 
@@ -319,23 +338,33 @@ pipelining.
 
 Argument:
   outblock   the SMTP output block
+  mode      further data expected, or plain
 
 Returns:     TRUE if OK, FALSE on error, with errno set
 */
 
 static BOOL
-flush_buffer(smtp_outblock *outblock)
+flush_buffer(smtp_outblock * outblock, int mode)
 {
 int rc;
 int n = outblock->ptr - outblock->buffer;
+BOOL more = mode == SCMD_MORE;
+
+HDEBUG(D_transport|D_acl) debug_printf_indent("cmd buf flush %d bytes%s\n", n,
+  more ? " (more expected)" : "");
 
-HDEBUG(D_transport|D_acl) debug_printf_indent("cmd buf flush %d bytes\n", n);
 #ifdef SUPPORT_TLS
 if (tls_out.active == outblock->sock)
-  rc = tls_write(FALSE, outblock->buffer, n);
+  rc = tls_write(FALSE, outblock->buffer, n, more);
 else
 #endif
-  rc = send(outblock->sock, outblock->buffer, n, 0);
+  rc = send(outblock->sock, outblock->buffer, n,
+#ifdef MSG_MORE
+           more ? MSG_MORE : 0
+#else
+           0
+#endif
+          );
 
 if (rc <= 0)
   {
@@ -359,7 +388,7 @@ any error message.
 
 Arguments:
   outblock   contains buffer for pipelining, and socket
-  noflush    if TRUE, save the command in the output buffer, for pipelining
+  mode       buffer, write-with-more-likely, write
   format     a format, starting with one of
              of HELO, MAIL FROM, RCPT TO, DATA, ".", or QUIT.
             If NULL, flush pipeline buffer only.
@@ -371,7 +400,7 @@ Returns:     0 if command added to pipelining buffer, with nothing transmitted
 */
 
 int
-smtp_write_command(smtp_outblock *outblock, BOOL noflush, const char *format, ...)
+smtp_write_command(smtp_outblock * outblock, int mode, const char *format, ...)
 {
 int count;
 int rc = 0;
@@ -393,7 +422,7 @@ if (format)
   if (count > outblock->buffersize - (outblock->ptr - outblock->buffer))
     {
     rc = outblock->cmd_count;                 /* flush resets */
-    if (!flush_buffer(outblock)) return -1;
+    if (!flush_buffer(outblock, SCMD_FLUSH)) return -1;
     }
 
   Ustrncpy(CS outblock->ptr, big_buffer, count);
@@ -423,10 +452,10 @@ if (format)
   HDEBUG(D_transport|D_acl|D_v) debug_printf_indent("  SMTP>> %s\n", big_buffer);
   }
 
-if (!noflush)
+if (mode != SCMD_BUFFER)
   {
   rc += outblock->cmd_count;                /* flush resets */
-  if (!flush_buffer(outblock)) return -1;
+  if (!flush_buffer(outblock, mode)) return -1;
   }
 
 return rc;
@@ -500,8 +529,9 @@ for (;;)
 
   if((rc = ip_recv(sock, inblock->buffer, inblock->buffersize, timeout)) <= 0)
     {
-    if (!errno)
-      DEBUG(D_deliver|D_transport|D_acl) debug_printf_indent("  SMTP(closed)<<\n");
+    DEBUG(D_deliver|D_transport|D_acl)
+      debug_printf_indent(errno ? "  SMTP(%s)<<\n" : "  SMTP(closed)<<\n",
+       strerror(errno));
     break;
     }
 
index d4b95b2f929e8235865821c5bbe7f7d89927b9f4..20154da4f40f310d5885daa13592ce40348e9883 100644 (file)
@@ -265,11 +265,9 @@ if (spam_ok && Ustrcmp(prev_user_name, user_name) == 0)
   return override ? OK : spam_rc;
 
 /* make sure the eml mbox file is spooled up */
-mbox_file = spool_mbox(&mbox_size, NULL);
 
-if (mbox_file == NULL)
-  {
-  /* error while spooling */
+if (!(mbox_file = spool_mbox(&mbox_size, NULL, NULL)))
+  {                                                            /* error while spooling */
   log_write(0, LOG_MAIN|LOG_PANIC,
         "%s error while creating mbox spool file", loglabel);
   return DEFER;
@@ -287,8 +285,7 @@ start = time(NULL);
   /* Check how many spamd servers we have
      and register their addresses */
   sep = 0;                             /* default colon-sep */
-  while ((address = string_nextinlist(&spamd_address_list_ptr, &sep,
-                                     NULL, 0)) != NULL)
+  while ((address = string_nextinlist(&spamd_address_list_ptr, &sep, NULL, 0)))
     {
     const uschar * sublist;
     int sublist_sep = -(int)' ';       /* default space-sep */
@@ -346,6 +343,7 @@ start = time(NULL);
 
     for (;;)
       {
+      /*XXX could potentially use TFO early-data here */
       if (  (spamd_sock = ip_streamsocket(sd->hostspec, &errstr, 5)) >= 0
          || sd->retry <= 0
         )
@@ -372,27 +370,30 @@ start = time(NULL);
 (void)fcntl(spamd_sock, F_SETFL, O_NONBLOCK);
 /* now we are connected to spamd on spamd_sock */
 if (sd->is_rspamd)
-  {                            /* rspamd variant */
-  uschar *req_str;
-  const uschar * helo;
-  const uschar * fcrdns;
-  const uschar * authid;
-
-  req_str = string_sprintf("CHECK RSPAMC/1.3\r\nContent-length: %lu\r\n"
-    "Queue-Id: %s\r\nFrom: <%s>\r\nRecipient-Number: %d\r\n",
-    mbox_size, message_id, sender_address, recipients_count);
+  {
+  uschar * req_str = NULL;
+  int size = 0, len = 0;
+  const uschar * s;
+
+  req_str = string_append(req_str, &size, &len, 8,
+    "CHECK RSPAMC/1.3\r\nContent-length: ", string_sprintf("%lu\r\n", mbox_size),
+    "Queue-Id: ", message_id,
+    "\r\nFrom: <", sender_address,
+    ">\r\nRecipient-Number: ", string_sprintf("%d\r\n", recipients_count));
+
   for (i = 0; i < recipients_count; i ++)
-    req_str = string_sprintf("%sRcpt: <%s>\r\n", req_str, recipients_list[i].address);
-  if ((helo = expand_string(US"$sender_helo_name")) != NULL && *helo != '\0')
-    req_str = string_sprintf("%sHelo: %s\r\n", req_str, helo);
-  if ((fcrdns = expand_string(US"$sender_host_name")) != NULL && *fcrdns != '\0')
-    req_str = string_sprintf("%sHostname: %s\r\n", req_str, fcrdns);
-  if (sender_host_address != NULL)
-    req_str = string_sprintf("%sIP: %s\r\n", req_str, sender_host_address);
-  if ((authid = expand_string(US"$authenticated_id")) != NULL && *authid != '\0')
-    req_str = string_sprintf("%sUser: %s\r\n", req_str, authid);
-  req_str = string_sprintf("%s\r\n", req_str);
-  wrote = send(spamd_sock, req_str, Ustrlen(req_str), 0);
+    req_str = string_append(req_str, &size, &len, 3,
+      "Rcpt: <", recipients_list[i].address, ">\r\n");
+  if ((s = expand_string(US"$sender_helo_name")) && *s)
+    req_str = string_append(req_str, &size, &len, 3, "Helo: ", s, "\r\n");
+  if ((s = expand_string(US"$sender_host_name")) && *s)
+    req_str = string_append(req_str, &size, &len, 3, "Hostname: ", s, "\r\n");
+  if (sender_host_address)
+    req_str = string_append(req_str, &size, &len, 3, "IP: ", sender_host_address, "\r\n");
+  if ((s = expand_string(US"$authenticated_id")) && *s)
+    req_str = string_append(req_str, &size, &len, 3, "User: ", s, "\r\n");
+  req_str = string_catn(req_str, &size, &len, "\r\n", 2);
+  wrote = send(spamd_sock, req_str, len, 0);
   }
 else
   {                            /* spamassassin variant */
index 9ab56af23516ee6f75ccd56a05061ed7dc32ce87..2741c7bafe20d409d42ae2a6ee92b47abced58bf 100644 (file)
 
 /* must be kept in numeric order */
 static spf_result_id spf_result_id_list[] = {
-  { US"invalid", 0},
-  { US"neutral", 1 },
-  { US"pass", 2 },
-  { US"fail", 3 },
-  { US"softfail", 4 },
-  { US"none", 5 },
-  { US"err_temp", 6 },  /* Deprecated Apr 2014 */
-  { US"err_perm", 7 },  /* Deprecated Apr 2014 */
-  { US"temperror", 6 }, /* RFC 4408 defined */
-  { US"permerror", 7 }  /* RFC 4408 defined */
+  /* name              value */
+  { US"invalid",       0},
+  { US"neutral",       1 },
+  { US"pass",          2 },
+  { US"fail",          3 },
+  { US"softfail",      4 },
+  { US"none",          5 },
+  { US"err_temp",      6 },  /* Deprecated Apr 2014 */
+  { US"err_perm",      7 },  /* Deprecated Apr 2014 */
+  { US"temperror",     6 }, /* RFC 4408 defined */
+  { US"permerror",     7 }  /* RFC 4408 defined */
 };
 
 SPF_server_t    *spf_server = NULL;
@@ -102,10 +103,10 @@ int spf_process(const uschar **listptr, uschar *spf_envelope_sender, int action)
     SPF_request_query_mailfrom(spf_request, &spf_response);
 
   /* set up expansion items */
-  spf_header_comment     = (uschar *)SPF_response_get_header_comment(spf_response);
-  spf_received           = (uschar *)SPF_response_get_received_spf(spf_response);
-  spf_result             = (uschar *)SPF_strresult(SPF_response_result(spf_response));
-  spf_smtp_comment       = (uschar *)SPF_response_get_smtp_comment(spf_response);
+  spf_header_comment     = US SPF_response_get_header_comment(spf_response);
+  spf_received           = US SPF_response_get_received_spf(spf_response);
+  spf_result             = US SPF_strresult(SPF_response_result(spf_response));
+  spf_smtp_comment       = US SPF_response_get_smtp_comment(spf_response);
 
   rc = SPF_response_result(spf_response);
 
index 6ed5664118f6206d19f5da17c63ca6581ae5acc2..a5b14959fa4c2fcc347125bcc0f58994100f9c3d 100644 (file)
@@ -284,6 +284,9 @@ sender_ident = NULL;
 sender_local = FALSE;
 sender_set_untrusted = FALSE;
 smtp_active_hostname = primary_hostname;
+#ifndef COMPILE_UTILITY
+spool_file_wireformat = FALSE;
+#endif
 tree_nonrecipients = NULL;
 
 #ifdef EXPERIMENTAL_BRIGHTMAIL
@@ -394,10 +397,11 @@ sender_address[n-3] = 0;
 
 /* time */
 if (Ufgets(big_buffer, big_buffer_size, f) == NULL) goto SPOOL_READ_ERROR;
-if (sscanf(CS big_buffer, "%d %d", &received_time, &warning_count) != 2)
+if (sscanf(CS big_buffer, TIME_T_FMT " %d", &received_time.tv_sec, &warning_count) != 2)
   goto SPOOL_FORMAT_ERROR;
+received_time.tv_usec = 0;
 
-message_age = time(NULL) - received_time;
+message_age = time(NULL) - received_time.tv_sec;
 
 #ifndef COMPILE_UTILITY
 DEBUG(D_deliver) debug_printf("user=%s uid=%ld gid=%ld sender=%s\n",
@@ -570,7 +574,8 @@ for (;;)
     break;
 
     case 'l':
-    if (Ustrcmp(p, "ocal") == 0) sender_local = TRUE;
+    if (Ustrcmp(p, "ocal") == 0)
+      sender_local = TRUE;
     else if (Ustrcmp(big_buffer, "-localerror") == 0)
       local_error_message = TRUE;
     else if (Ustrncmp(p, "ocal_scan ", 10) == 0)
@@ -590,6 +595,12 @@ for (;;)
     case 'r':
     if (Ustrncmp(p, "eceived_protocol", 16) == 0)
       received_protocol = string_copy(big_buffer + 19);
+    else if (Ustrncmp(p, "eceived_time_usec", 17) == 0)
+      {
+      unsigned usec;
+      if (sscanf(CS big_buffer + 21, "%u", &usec) == 1)
+       received_time.tv_usec = usec;
+      }
     break;
 
     case 's':
@@ -603,6 +614,10 @@ for (;;)
     else if (Ustrncmp(p, "pam_score_int ", 14) == 0)
       spam_score_int = string_copy(big_buffer + 16);
 #endif
+#ifndef COMPILE_UTILITY
+    else if (Ustrncmp(p, "pool_file_wireformat", 20) == 0)
+      spool_file_wireformat = TRUE;
+#endif
 #if defined(SUPPORT_I18N) && !defined(COMPILE_UTILITY)
     else if (Ustrncmp(p, "mtputf8", 7) == 0)
       message_smtputf8 = TRUE;
index b1de39e7dee3a687fa04f5019799d4bcb094a128..4326340948f59904457e77eff8f2fdae083ac70c 100644 (file)
@@ -19,11 +19,17 @@ extern int spam_ok;
 int spool_mbox_ok = 0;
 uschar spooled_message_id[MESSAGE_ID_LENGTH+1];
 
-/* returns a pointer to the FILE, and puts the size in bytes into mbox_file_size
- * normally, source_file_override is NULL */
+/*
+Create an MBOX-style message file from the spooled files.
+
+Returns a pointer to the FILE, and puts the size in bytes into mbox_file_size.
+If mbox_fname is non-null, fill in a pointer to the name.
+Normally, source_file_override is NULL
+*/
 
 FILE *
-spool_mbox(unsigned long *mbox_file_size, const uschar *source_file_override)
+spool_mbox(unsigned long *mbox_file_size, const uschar *source_file_override,
+  uschar ** mbox_fname)
 {
 uschar message_subdir[2];
 uschar buffer[16384];
@@ -35,10 +41,13 @@ FILE *yield = NULL;
 header_line *my_headerlist;
 struct stat statbuf;
 int i, j;
-void *reset_point = store_get(0);
+void *reset_point;
+
+mbox_path = string_sprintf("%s/scan/%s/%s.eml",
+  spool_directory, message_id, message_id);
+if (mbox_fname) *mbox_fname = mbox_path;
 
-mbox_path = string_sprintf("%s/scan/%s/%s.eml", spool_directory, message_id,
-  message_id);
+reset_point = store_get(0);
 
 /* Skip creation if already spooled out as mbox file */
 if (!spool_mbox_ok)
@@ -53,8 +62,8 @@ if (!spool_mbox_ok)
     }
 
   /* open [message_id].eml file for writing */
-  mbox_file = modefopen(mbox_path, "wb", SPOOL_MODE);
-  if (mbox_file == NULL)
+
+  if (!(mbox_file = modefopen(mbox_path, "wb", SPOOL_MODE)))
     {
     log_write(0, LOG_MAIN|LOG_PANIC, "%s", string_open_failed(errno,
       "scan file %s", mbox_path));
@@ -71,33 +80,25 @@ if (!spool_mbox_ok)
     "${if def:sender_address{X-Envelope-From: <${sender_address}>\n}}"
     "${if def:recipients{X-Envelope-To: ${recipients}\n}}");
 
-  if (temp_string != NULL)
-    {
-    i = fwrite(temp_string, Ustrlen(temp_string), 1, mbox_file);
-    if (i != 1)
+  if (temp_string)
+    if (fwrite(temp_string, Ustrlen(temp_string), 1, mbox_file) != 1)
       {
       log_write(0, LOG_MAIN|LOG_PANIC, "Error/short write while writing \
          mailbox headers to %s", mbox_path);
       goto OUT;
       }
-    }
 
-  /* write all header lines to mbox file */
-  my_headerlist = header_list;
-  for (my_headerlist = header_list; my_headerlist != NULL;
-    my_headerlist = my_headerlist->next)
-    {
-    /* skip deleted headers */
-    if (my_headerlist->type == '*') continue;
+  /* write all non-deleted header lines to mbox file */
 
-    i = fwrite(my_headerlist->text, my_headerlist->slen, 1, mbox_file);
-    if (i != 1)
-      {
-      log_write(0, LOG_MAIN|LOG_PANIC, "Error/short write while writing \
-         message headers to %s", mbox_path);
-      goto OUT;
-      }
-    }
+  for (my_headerlist = header_list; my_headerlist;
+      my_headerlist = my_headerlist->next)
+    if (my_headerlist->type != '*')
+      if (fwrite(my_headerlist->text, my_headerlist->slen, 1, mbox_file) != 1)
+       {
+       log_write(0, LOG_MAIN|LOG_PANIC, "Error/short write while writing \
+           message headers to %s", mbox_path);
+       goto OUT;
+       }
 
   /* End headers */
   if (fwrite("\n", 1, 1, mbox_file) != 1)
@@ -108,7 +109,7 @@ if (!spool_mbox_ok)
     }
 
   /* copy body file */
-  if (source_file_override == NULL)
+  if (!source_file_override)
     {
     message_subdir[1] = '\0';
     for (i = 0; i < 2; i++)
@@ -142,18 +143,32 @@ if (!spool_mbox_ok)
 
   do
     {
-    j = fread(buffer, 1, sizeof(buffer), data_file);
+    uschar * s;
+
+    if (!spool_file_wireformat || source_file_override)
+      j = fread(buffer, 1, sizeof(buffer), data_file);
+    else                                               /* needs CRLF -> NL */
+      if ((s = US fgets(CS buffer, sizeof(buffer), data_file)))
+       {
+       uschar * p = s + Ustrlen(s) - 1;
+
+       if (*p == '\n' && p[-1] == '\r')
+         *--p = '\n';
+       else if (*p == '\r')
+         ungetc(*p--, data_file);
+
+       j = p - buffer;
+       }
+      else
+       j = 0;
 
     if (j > 0)
-      {
-      i = fwrite(buffer, j, 1, mbox_file);
-      if (i != 1)
+      if (fwrite(buffer, j, 1, mbox_file) != 1)
         {
        log_write(0, LOG_MAIN|LOG_PANIC, "Error/short write while writing \
            message body to %s", mbox_path);
        goto OUT;
        }
-      }
     } while (j > 0);
 
   (void)fclose(mbox_file);
@@ -201,8 +216,7 @@ if (spool_mbox_ok && !no_mbox_unspool)
 
   mbox_path = string_sprintf("%s/scan/%s", spool_directory, spooled_message_id);
 
-  tempdir = opendir(CS mbox_path);
-  if (!tempdir)
+  if (!(tempdir = opendir(CS mbox_path)))
     {
     debug_printf("Unable to opendir(%s): %s\n", mbox_path, strerror(errno));
     /* Just in case we still can: */
@@ -210,7 +224,7 @@ if (spool_mbox_ok && !no_mbox_unspool)
     return;
     }
   /* loop thru dir & delete entries */
-  while((entry = readdir(tempdir)) != NULL)
+  while((entry = readdir(tempdir)))
     {
     uschar *name = US entry->d_name;
     int dummy;
@@ -218,7 +232,7 @@ if (spool_mbox_ok && !no_mbox_unspool)
 
     file_path = string_sprintf("%s/%s", mbox_path, name);
     debug_printf("unspool_mbox(): unlinking '%s'\n", file_path);
-    dummy = unlink(CS file_path);
+    dummy = unlink(CS file_path); dummy = dummy;       /* compiler quietening */
     }
 
   closedir(tempdir);
index 652506fb359c9d7b84df1b1f2ace9b03d0ab64fb..449662253332e30d18b4f421ea713ad39b35ff67 100644 (file)
@@ -154,26 +154,28 @@ fprintf(f, "%s-H\n", message_id);
 fprintf(f, "%.63s %ld %ld\n", originator_login, (long int)originator_uid,
   (long int)originator_gid);
 fprintf(f, "<%s>\n", sender_address);
-fprintf(f, "%d %d\n", received_time, warning_count);
+fprintf(f, "%d %d\n", (int)received_time.tv_sec, warning_count);
+
+fprintf(f, "-received_time_usec .%06d\n", (int)received_time.tv_usec);
 
 /* If there is information about a sending host, remember it. The HELO
 data can be set for local SMTP as well as remote. */
 
-if (sender_helo_name != NULL)
+if (sender_helo_name)
   fprintf(f, "-helo_name %s\n", sender_helo_name);
 
-if (sender_host_address != NULL)
+if (sender_host_address)
   {
   fprintf(f, "-host_address %s.%d\n", sender_host_address, sender_host_port);
-  if (sender_host_name != NULL)
+  if (sender_host_name)
     fprintf(f, "-host_name %s\n", sender_host_name);
-  if (sender_host_authenticated != NULL)
+  if (sender_host_authenticated)
     fprintf(f, "-host_auth %s\n", sender_host_authenticated);
   }
 
 /* Also about the interface a message came in on */
 
-if (interface_address != NULL)
+if (interface_address)
   fprintf(f, "-interface_address %s.%d\n", interface_address, interface_port);
 
 if (smtp_active_hostname != primary_hostname)
@@ -183,11 +185,11 @@ if (smtp_active_hostname != primary_hostname)
 likely to be the same as originator_login, but will be different if
 the originator was root, forcing a different ident. */
 
-if (sender_ident != NULL) fprintf(f, "-ident %s\n", sender_ident);
+if (sender_ident) fprintf(f, "-ident %s\n", sender_ident);
 
 /* Ditto for the received protocol */
 
-if (received_protocol != NULL)
+if (received_protocol)
   fprintf(f, "-received_protocol %s\n", received_protocol);
 
 /* Preserve any ACL variables that are set. */
@@ -197,14 +199,17 @@ tree_walk(acl_var_m, &acl_var_write, f);
 
 /* Now any other data that needs to be remembered. */
 
-fprintf(f, "-body_linecount %d\n", body_linecount);
+if (spool_file_wireformat)
+  fprintf(f, "-spool_file_wireformat\n");
+else
+  fprintf(f, "-body_linecount %d\n", body_linecount);
 fprintf(f, "-max_received_linelength %d\n", max_received_linelength);
 
 if (body_zerocount > 0) fprintf(f, "-body_zerocount %d\n", body_zerocount);
 
-if (authenticated_id != NULL)
+if (authenticated_id)
   fprintf(f, "-auth_id %s\n", authenticated_id);
-if (authenticated_sender != NULL)
+if (authenticated_sender)
   fprintf(f, "-auth_sender %s\n", authenticated_sender);
 
 if (allow_unqualified_recipient) fprintf(f, "-allow_unqualified_recipient\n");
@@ -258,7 +263,7 @@ if (message_smtputf8)
 
 /* Write the dsn flags to the spool header file */
 DEBUG(D_deliver) debug_printf("DSN: Write SPOOL :-dsn_envid %s\n", dsn_envid);
-if (dsn_envid != NULL) fprintf(f, "-dsn_envid %s\n", dsn_envid);
+if (dsn_envid) fprintf(f, "-dsn_envid %s\n", dsn_envid);
 DEBUG(D_deliver) debug_printf("DSN: Write SPOOL :-dsn_ret %d\n", dsn_ret);
 if (dsn_ret != 0) fprintf(f, "-dsn_ret %d\n", dsn_ret);
 
@@ -313,7 +318,7 @@ various other headers, or an asterisk for old headers that have been rewritten.
 These are saved as a record for debugging. Don't included them in the message's
 size. */
 
-for (h = header_list; h != NULL; h = h->next)
+for (h = header_list; h; h = h->next)
   {
   fprintf(f, "%03d%c %s", h->slen, h->type, h->text);
   size_correction += 5;
index 8ccef122b14a97b3ff2da68c132146279e91936c..d41e2a195141ec02602ec2f64bfec842bea24340 100644 (file)
@@ -961,26 +961,27 @@ struct dh_constant {
 /* KEEP SORTED ALPHABETICALLY;
  * duplicate PEM are okay, if we want aliases, but names must be alphabetical */
 static struct dh_constant dh_constants[] = {
-    { "default", dh_exim_20160529_3 },
-    { "exim.dev.20160529.1", dh_exim_20160529_1 },
-    { "exim.dev.20160529.2", dh_exim_20160529_2 },
-    { "exim.dev.20160529.3", dh_exim_20160529_3 },
-    { "ffdhe2048", dh_ffdhe2048_pem },
-    { "ffdhe3072", dh_ffdhe3072_pem },
-    { "ffdhe4096", dh_ffdhe4096_pem },
-    { "ffdhe6144", dh_ffdhe6144_pem },
-    { "ffdhe8192", dh_ffdhe8192_pem },
-    { "ike1", dh_ike_1_pem },
-    { "ike14", dh_ike_14_pem },
-    { "ike15", dh_ike_15_pem },
-    { "ike16", dh_ike_16_pem },
-    { "ike17", dh_ike_17_pem },
-    { "ike18", dh_ike_18_pem },
-    { "ike2", dh_ike_2_pem },
-    { "ike22", dh_ike_22_pem },
-    { "ike23", dh_ike_23_pem },
-    { "ike24", dh_ike_24_pem },
-    { "ike5", dh_ike_5_pem },
+    /*  label                  pem */
+    { "default",               dh_exim_20160529_3 },
+    { "exim.dev.20160529.1",   dh_exim_20160529_1 },
+    { "exim.dev.20160529.2",   dh_exim_20160529_2 },
+    { "exim.dev.20160529.3",   dh_exim_20160529_3 },
+    { "ffdhe2048",             dh_ffdhe2048_pem },
+    { "ffdhe3072",             dh_ffdhe3072_pem },
+    { "ffdhe4096",             dh_ffdhe4096_pem },
+    { "ffdhe6144",             dh_ffdhe6144_pem },
+    { "ffdhe8192",             dh_ffdhe8192_pem },
+    { "ike1",                  dh_ike_1_pem },
+    { "ike14",                 dh_ike_14_pem },
+    { "ike15",                 dh_ike_15_pem },
+    { "ike16",                 dh_ike_16_pem },
+    { "ike17",                 dh_ike_17_pem },
+    { "ike18",                 dh_ike_18_pem },
+    { "ike2",                  dh_ike_2_pem },
+    { "ike22",                 dh_ike_22_pem },
+    { "ike23",                 dh_ike_23_pem },
+    { "ike24",                 dh_ike_24_pem },
+    { "ike5",                  dh_ike_5_pem },
 };
 static const int dh_constants_count =
   sizeof(dh_constants) / sizeof(struct dh_constant);
index 8628954b5b2eec784aea7ddbb2456e04b8e3ca87..12db584ce71a1226da76ae00f12d9a08c9acf9ae 100644 (file)
@@ -205,7 +205,7 @@ DEBUG(D_memory)
 (void) VALGRIND_MAKE_MEM_UNDEFINED(store_last_get[store_pool], size);
 /* Update next pointer and number of bytes left in the current block. */
 
-next_yield[store_pool] = (void *)((char *)next_yield[store_pool] + size);
+next_yield[store_pool] = (void *)(CS next_yield[store_pool] + size);
 yield_length[store_pool] -= size;
 
 return store_last_get[store_pool];
@@ -273,7 +273,7 @@ int rounded_oldsize = oldsize;
 if (rounded_oldsize % alignment != 0)
   rounded_oldsize += alignment - (rounded_oldsize % alignment);
 
-if ((char *)ptr + rounded_oldsize != (char *)(next_yield[store_pool]) ||
+if (CS ptr + rounded_oldsize != CS (next_yield[store_pool]) ||
     inc > yield_length[store_pool] + rounded_oldsize - oldsize)
   return FALSE;
 
@@ -295,7 +295,7 @@ DEBUG(D_memory)
 #endif  /* COMPILE_UTILITY */
 
 if (newsize % alignment != 0) newsize += alignment - (newsize % alignment);
-next_yield[store_pool] = (char *)ptr + newsize;
+next_yield[store_pool] = CS ptr + newsize;
 yield_length[store_pool] -= newsize - rounded_oldsize;
 (void) VALGRIND_MAKE_MEM_UNDEFINED(ptr + oldsize, inc);
 return TRUE;
@@ -455,7 +455,7 @@ storeblock *b;
 for (b = chainbase[store_pool]; b != NULL; b = b->next)
   {
   storeblock *bb = b->next;
-  if (bb != NULL && (char *)block == (char *)bb + ALIGNED_SIZEOF_STOREBLOCK)
+  if (bb != NULL && CS block == CS bb + ALIGNED_SIZEOF_STOREBLOCK)
     {
     b->next = bb->next;
     pool_malloc -= bb->length + ALIGNED_SIZEOF_STOREBLOCK;
index cec59506dbe46420e3a620dfd3f3198169bf7efa..2de595afb664d3602bc40fc3c50ff728ca7118ab 100644 (file)
@@ -42,7 +42,7 @@ int yield = 4;
 /* If an optional mask is permitted, check for it. If found, pass back the
 offset. */
 
-if (maskptr != NULL)
+if (maskptr)
   {
   const uschar *ss = s + Ustrlen(s);
   *maskptr = 0;
@@ -79,7 +79,7 @@ if (Ustrchr(s, ':') != NULL)
     if we hit the / that introduces a mask or the % that introduces the
     interface specifier (scope id) of a link-local address. */
 
-    if (*s == 0 || *s == '%' || *s == '/') return had_double_colon? yield : 0;
+    if (*s == 0 || *s == '%' || *s == '/') return had_double_colon ? yield : 0;
 
     /* If a component starts with an additional colon, we have hit a double
     colon. This is permitted to appear once only, and counts as at least
@@ -135,13 +135,16 @@ if (Ustrchr(s, ':') != NULL)
 
 for (i = 0; i < 4; i++)
   {
+  long n;
+  uschar * end;
+
   if (i != 0 && *s++ != '.') return 0;
-  if (!isdigit(*s++)) return 0;
-  if (isdigit(*s) && isdigit(*(++s))) s++;
+  n = strtol(CCS s, CSS &end, 10);
+  if (n > 255 || n < 0 || end <= s || end > s+3) return 0;
+  s = end;
   }
 
-return (*s == 0 || (*s == '/' && maskptr != NULL && *maskptr != 0))?
-  yield : 0;
+return !*s || (*s == '/' && maskptr && *maskptr != 0) ? yield : 0;
 }
 #endif  /* COMPILE_UTILITY */
 
@@ -965,21 +968,43 @@ else
 *listptr = s;
 return buffer;
 }
-#endif  /* COMPILE_UTILITY */
 
 
-#ifndef COMPILE_UTILITY
+static const uschar *
+Ustrnchr(const uschar * s, int c, unsigned * len)
+{
+unsigned siz = *len;
+while (siz)
+  {
+  if (!*s) return NULL;
+  if (*s == c)
+    {
+    *len = siz;
+    return s;
+    }
+  s++;
+  siz--;
+  }
+return NULL;
+}
+
+
 /************************************************
 *      Add element to separated list           *
 ************************************************/
-/* This function is used to build a list, returning
-an allocated null-terminated growable string. The
-given element has any embedded separator characters
+/* This function is used to build a list, returning an allocated null-terminated
+growable string. The given element has any embedded separator characters
 doubled.
 
+Despite having the same growable-string interface as string_cat() the list is
+always returned null-terminated.
+
 Arguments:
   list points to the start of the list that is being built, or NULL
        if this is a new list that has no contents yet
+  sz    (ptr to) amount of memory allocated for list; zero for a new list
+  off   (ptr to) current list length in chars (insert point for next addition),
+        zero for a new list
   sep  list separator character
   ele  new element to be appended to the list
 
@@ -987,78 +1012,49 @@ Returns:  pointer to the start of the list, changed if copied for expansion.
 */
 
 uschar *
-string_append_listele(uschar * list, uschar sep, const uschar * ele)
+string_append_listele(uschar * list, int * sz, int * off,
+  uschar sep, const uschar * ele)
 {
-uschar * new = NULL;
-int sz = 0, off = 0;
 uschar * sp;
 
 if (list)
-  {
-  new = string_cat (new, &sz, &off, list);
-  new = string_catn(new, &sz, &off, &sep, 1);
-  }
+  list = string_catn(list, sz, off, &sep, 1);
 
 while((sp = Ustrchr(ele, sep)))
   {
-  new = string_catn(new, &sz, &off, ele, sp-ele+1);
-  new = string_catn(new, &sz, &off, &sep, 1);
+  list = string_catn(list, sz, off, ele, sp-ele+1);
+  list = string_catn(list, sz, off, &sep, 1);
   ele = sp+1;
   }
-new = string_cat(new, &sz, &off, ele);
-new[off] = '\0';
-return new;
+list = string_cat(list, sz, off, ele);
+list[*off] = '\0';
+return list;
 }
 
 
-static const uschar *
-Ustrnchr(const uschar * s, int c, unsigned * len)
-{
-unsigned siz = *len;
-while (siz)
-  {
-  if (!*s) return NULL;
-  if (*s == c)
-    {
-    *len = siz;
-    return s;
-    }
-  s++;
-  siz--;
-  }
-return NULL;
-}
-
 uschar *
-string_append_listele_n(uschar * list, uschar sep, const uschar * ele,
-  unsigned len)
+string_append_listele_n(uschar * list, int * sz, int * off,
+  uschar sep, const uschar * ele, unsigned len)
 {
-uschar * new = NULL;
-int sz = 0, off = 0;
 const uschar * sp;
 
 if (list)
-  {
-  new = string_cat (new, &sz, &off, list);
-  new = string_catn(new, &sz, &off, &sep, 1);
-  }
+  list = string_catn(list, sz, off, &sep, 1);
 
 while((sp = Ustrnchr(ele, sep, &len)))
   {
-  new = string_catn(new, &sz, &off, ele, sp-ele+1);
-  new = string_catn(new, &sz, &off, &sep, 1);
+  list = string_catn(list, sz, off, ele, sp-ele+1);
+  list = string_catn(list, sz, off, &sep, 1);
   ele = sp+1;
   len--;
   }
-new = string_catn(new, &sz, &off, ele, len);
-new[off] = '\0';
-return new;
+list = string_catn(list, sz, off, ele, len);
+list[*off] = '\0';
+return list;
 }
-#endif  /* COMPILE_UTILITY */
 
 
 
-#ifndef COMPILE_UTILITY
 /*************************************************
 *             Add chars to string                *
 *************************************************/
@@ -1078,7 +1074,7 @@ Arguments:
              characters, updated to the new offset
   s        points to characters to add
   count    count of characters to add; must not exceed the length of s, if s
-             is a C string.  If -1 given, strlen(s) is used.
+             is a C string.
 
 If string is given as NULL, *size and *ptr should both be zero.
 
@@ -1359,20 +1355,18 @@ while (*fp != 0)
     switch(length)
       {
       case L_SHORT:
-      case L_NORMAL:   sprintf(CS p, newformat, va_arg(ap, int)); break;
-      case L_LONG:     sprintf(CS p, newformat, va_arg(ap, long int)); break;
-      case L_LONGLONG: sprintf(CS p, newformat, va_arg(ap, LONGLONG_T)); break;
-      case L_SIZE:     sprintf(CS p, newformat, va_arg(ap, size_t)); break;
+      case L_NORMAL:   p += sprintf(CS p, newformat, va_arg(ap, int)); break;
+      case L_LONG:     p += sprintf(CS p, newformat, va_arg(ap, long int)); break;
+      case L_LONGLONG: p += sprintf(CS p, newformat, va_arg(ap, LONGLONG_T)); break;
+      case L_SIZE:     p += sprintf(CS p, newformat, va_arg(ap, size_t)); break;
       }
-    while (*p) p++;
     break;
 
     case 'p':
     if (p >= last - 24) { yield = FALSE; goto END_FORMAT; }
     strncpy(newformat, item_start, fp - item_start);
     newformat[fp - item_start] = 0;
-    sprintf(CS p, newformat, va_arg(ap, void *));
-    while (*p) p++;
+    p += sprintf(CS p, newformat, va_arg(ap, void *));
     break;
 
     /* %f format is inherently insecure if the numbers that it may be
@@ -1392,10 +1386,9 @@ while (*fp != 0)
     strncpy(newformat, item_start, fp - item_start);
     newformat[fp-item_start] = 0;
     if (length == L_LONGDOUBLE)
-      sprintf(CS p, newformat, va_arg(ap, long double));
+      p += sprintf(CS p, newformat, va_arg(ap, long double));
     else
-      sprintf(CS p, newformat, va_arg(ap, double));
-    while (*p) p++;
+      p += sprintf(CS p, newformat, va_arg(ap, double));
     break;
 
     /* String types */
index 38b095f06a584e185f5d0ba1e072763f107dc8e2..d8ac19ab8c8eaf3671a88f082da0ddb6b2f1424f 100644 (file)
@@ -28,11 +28,12 @@ struct router_info;
 /* Structure for remembering macros for the configuration file */
 
 typedef struct macro_item {
-  struct   macro_item *next;
-  BOOL     command_line;
-  unsigned namelen;
-  uschar * replacement;
-  uschar   name[1];
+  struct  macro_item * next;
+  BOOL         command_line;
+  unsigned     namelen;
+  unsigned     replen;
+  const uschar * name;
+  const uschar * replacement;
 } macro_item;
 
 /* Structure for bit tables for debugging and logging */
@@ -230,12 +231,15 @@ typedef struct transport_info {
 #define tc_chunk_last  BIT(1)  /* annotate chunk SMTP cmd as LAST */
 
 struct transport_context;
-typedef int (*tpt_chunk_cmd_cb)(int fd, struct transport_context * tctx,
-                               unsigned len, unsigned flags);
+typedef int (*tpt_chunk_cmd_cb)(struct transport_context *, unsigned, unsigned);
 
 /* Structure for information about a delivery-in-progress */
 
 typedef struct transport_context {
+  union {                      /* discriminated by option topt_output_string */
+    int                          fd;   /* file descriptor to write message to */
+    uschar *             msg;  /* allocated string with written message */
+  } u;
   transport_instance   * tblock;               /* transport */
   struct address_item  * addr;
   uschar               * check_string;         /* string replacement */
@@ -245,6 +249,10 @@ typedef struct transport_context {
   /* items below only used with option topt_use_bdat */
   tpt_chunk_cmd_cb       chunk_cb;             /* per-datachunk callback */
   void                 * smtp_context;
+
+  /* items below only used with option topt_output_string */
+  int                    msg_size;
+  int                    msg_ptr;
 } transport_ctx;
 
 
@@ -497,6 +505,7 @@ typedef struct address_item_propagated {
   #ifdef EXPERIMENTAL_SRS
   uschar *srs_sender;             /* Change return path when delivering */
   #endif
+  BOOL    ignore_error:1;        /* ignore delivery error */
   #ifdef SUPPORT_I18N
   BOOL    utf8_msg:1;            /* requires SMTPUTF8 processing */
   BOOL   utf8_downcvt:1;         /* mandatory downconvert on delivery */
@@ -504,50 +513,6 @@ typedef struct address_item_propagated {
   #endif
 } address_item_propagated;
 
-/* Bits for the flags field below */
-
-#define af_allow_file          0x00000001 /* allow file in generated address */
-#define af_allow_pipe          0x00000002 /* allow pipe in generated address */
-#define af_allow_reply         0x00000004 /* allow autoreply in generated address */
-#define af_dr_retry_exists     0x00000008 /* router retry record exists */
-#define af_expand_pipe         0x00000010 /* expand pipe arguments */
-#define af_file                0x00000020 /* file delivery; always with pfr */
-#define af_gid_set             0x00000040 /* gid field is set */
-#define af_home_expanded       0x00000080 /* home_dir is already expanded */
-#define af_ignore_error        0x00000100 /* ignore delivery error */
-#define af_initgroups          0x00000200 /* use initgroups() for local transporting */
-#define af_local_host_removed  0x00000400 /* local host was backup */
-#define af_lt_retry_exists     0x00000800 /* local transport retry exists */
-#define af_pfr                 0x00001000 /* pipe or file or reply delivery */
-#define af_retry_skipped       0x00002000 /* true if retry caused some skipping */
-#define af_retry_timedout      0x00004000 /* true if retry timed out */
-#define af_uid_set             0x00008000 /* uid field is set */
-#define af_hide_child          0x00010000 /* hide child in bounce/defer msgs */
-#define af_sverify_told        0x00020000 /* sender verify failure notified */
-#define af_verify_pmfail       0x00040000 /* verify failure was postmaster callout */
-#define af_verify_nsfail       0x00080000 /* verify failure was null sender callout */
-#define af_homonym             0x00100000 /* an ancestor has same address */
-#define af_verify_routed       0x00200000 /* for cached sender verify: routed OK */
-#define af_verify_callout      0x00400000 /* for cached sender verify: callout was specified */
-#define af_include_affixes     0x00800000 /* delivered with affixes in RCPT */
-#define af_cert_verified       0x01000000 /* delivered with verified TLS cert */
-#define af_pass_message        0x02000000 /* pass message in bounces */
-#define af_bad_reply           0x04000000 /* filter could not generate autoreply */
-#ifndef DISABLE_PRDR
-# define af_prdr_used          0x08000000 /* delivery used SMTP PRDR */
-#endif
-#define af_chunking_used       0x10000000 /* delivery used SMTP CHUNKING */
-#define af_force_command       0x20000000 /* force_command in pipe transport */
-#ifdef EXPERIMENTAL_DANE
-# define af_dane_verified      0x40000000 /* TLS cert verify done with DANE */
-#endif
-#ifdef SUPPORT_I18N
-# define af_utf8_downcvt       0x80000000 /* downconvert was done for delivery */
-#endif
-
-/* These flags must be propagated when a child is created */
-
-#define af_propagate           (af_ignore_error)
 
 /* The main address structure. Note that fields that are to be copied to
 generated addresses should be put in the address_item_propagated structure (see
@@ -617,12 +582,54 @@ typedef struct address_item {
   uid_t   uid;                    /* uid for transporting */
   gid_t   gid;                    /* gid for transporting */
 
-  unsigned int flags;             /* a row of bits, defined above */
+                                 /* flags */
+  struct {
+    BOOL af_allow_file:1;              /* allow file in generated address */
+    BOOL af_allow_pipe:1;              /* allow pipe in generated address */
+    BOOL af_allow_reply:1;             /* allow autoreply in generated address */
+    BOOL af_dr_retry_exists:1;         /* router retry record exists */
+    BOOL af_expand_pipe:1;             /* expand pipe arguments */
+    BOOL af_file:1;                    /* file delivery; always with pfr */
+    BOOL af_gid_set:1;                 /* gid field is set */
+    BOOL af_home_expanded:1;           /* home_dir is already expanded */
+    BOOL af_initgroups:1;              /* use initgroups() for local transporting */
+    BOOL af_local_host_removed:1;      /* local host was backup */
+    BOOL af_lt_retry_exists:1;         /* local transport retry exists */
+    BOOL af_pfr:1;                     /* pipe or file or reply delivery */
+    BOOL af_retry_skipped:1;           /* true if retry caused some skipping */
+    BOOL af_retry_timedout:1;          /* true if retry timed out */
+    BOOL af_uid_set:1;                 /* uid field is set */
+    BOOL af_hide_child:1;              /* hide child in bounce/defer msgs */
+    BOOL af_sverify_told:1;            /* sender verify failure notified */
+    BOOL af_verify_pmfail:1;           /* verify failure was postmaster callout */
+    BOOL af_verify_nsfail:1;           /* verify failure was null sender callout */
+    BOOL af_homonym:1;                 /* an ancestor has same address */
+    BOOL af_verify_routed:1;           /* for cached sender verify: routed OK */
+    BOOL af_verify_callout:1;          /* for cached sender verify: callout was specified */
+    BOOL af_include_affixes:1;         /* delivered with affixes in RCPT */
+    BOOL af_cert_verified:1;           /* delivered with verified TLS cert */
+    BOOL af_pass_message:1;            /* pass message in bounces */
+    BOOL af_bad_reply:1;               /* filter could not generate autoreply */
+    BOOL af_tcp_fastopen:1;            /* delivery used TCP Fast Open */
+#ifndef DISABLE_PRDR
+    BOOL af_prdr_used:1;               /* delivery used SMTP PRDR */
+#endif
+    BOOL af_chunking_used:1;           /* delivery used SMTP CHUNKING */
+    BOOL af_force_command:1;           /* force_command in pipe transport */
+#ifdef EXPERIMENTAL_DANE
+    BOOL af_dane_verified:1;           /* TLS cert verify done with DANE */
+#endif
+#ifdef SUPPORT_I18N
+    BOOL af_utf8_downcvt:1;            /* downconvert was done for delivery */
+#endif
+  } flags;
+
   unsigned int domain_cache[(MAX_NAMED_LIST * 2)/32];
   unsigned int localpart_cache[(MAX_NAMED_LIST * 2)/32];
   int     mode;                   /* mode for local transporting to a file */
   int     more_errno;             /* additional error information */
                                   /* (may need to hold a timestamp) */
+  unsigned int delivery_usec;    /* subsecond part of delivery time */
 
   short int basic_errno;          /* status after failure */
   unsigned short child_count;     /* number of child addresses */
@@ -860,11 +867,13 @@ typedef BOOL (*oicf) (uschar *message_id, void *data);
 /* DKIM information for transport */
 struct ob_dkim {
   uschar *dkim_domain;
+  uschar *dkim_identity;
   uschar *dkim_private_key;
   uschar *dkim_selector;
   uschar *dkim_canon;
   uschar *dkim_sign_headers;
   uschar *dkim_strict;
+  uschar *dkim_hash;
   BOOL    dot_stuffed;
 };
 
index 8836bb259edbbb1b7fcbd7ca69284113d7eb344b..d54c560f708ee9d4d6fd0458a9ee10c2c71a52a3 100644 (file)
@@ -60,6 +60,9 @@ require current GnuTLS, then we'll drop support for the ancient libraries).
 #if GNUTLS_VERSION_NUMBER >= 0x030014
 # define SUPPORT_SYSDEFAULT_CABUNDLE
 #endif
+#if GNUTLS_VERSION_NUMBER >= 0x030109
+# define SUPPORT_CORK
+#endif
 
 #ifndef DISABLE_OCSP
 # include <gnutls/ocsp.h>
@@ -136,16 +139,45 @@ typedef struct exim_gnutls_state {
 } exim_gnutls_state_st;
 
 static const exim_gnutls_state_st exim_gnutls_state_init = {
-  NULL, NULL, NULL, VERIFY_NONE, -1, -1, FALSE, FALSE, FALSE,
-  NULL, NULL, NULL, NULL,
-  NULL, NULL, NULL, NULL, NULL, NULL,
-  NULL, NULL, NULL, NULL, NULL, NULL, NULL,
-  NULL,
+  .session =           NULL,
+  .x509_cred =         NULL,
+  .priority_cache =    NULL,
+  .verify_requirement =        VERIFY_NONE,
+  .fd_in =             -1,
+  .fd_out =            -1,
+  .peer_cert_verified =        FALSE,
+  .trigger_sni_changes =FALSE,
+  .have_set_peerdn =   FALSE,
+  .host =              NULL,
+  .peercert =          NULL,
+  .peerdn =            NULL,
+  .ciphersuite =       NULL,
+  .received_sni =      NULL,
+
+  .tls_certificate =   NULL,
+  .tls_privatekey =    NULL,
+  .tls_sni =           NULL,
+  .tls_verify_certificates = NULL,
+  .tls_crl =           NULL,
+  .tls_require_ciphers =NULL,
+
+  .exp_tls_certificate = NULL,
+  .exp_tls_privatekey =        NULL,
+  .exp_tls_verify_certificates = NULL,
+  .exp_tls_crl =       NULL,
+  .exp_tls_require_ciphers = NULL,
+  .exp_tls_ocsp_file = NULL,
+  .exp_tls_verify_cert_hostnames = NULL,
 #ifndef DISABLE_EVENT
-                                            NULL,
+  .event_action =      NULL,
 #endif
-  NULL,
-  NULL, 0, 0, 0, 0,
+  .tlsp =              NULL,
+
+  .xfer_buffer =       NULL,
+  .xfer_buffer_lwm =   0,
+  .xfer_buffer_hwm =   0,
+  .xfer_eof =          0,
+  .xfer_error =                0,
 };
 
 /* Not only do we have our own APIs which don't pass around state, assuming
@@ -1648,7 +1680,7 @@ int ret;
 if ((ret = gnutls_load_file(ptr, ocsp_response)) < 0)
   {
   DEBUG(D_tls) debug_printf("Failed to load ocsp stapling file %s\n",
-                             (char *)ptr);
+                             CS ptr);
   tls_in.ocsp = OCSP_NOT_RESP;
   return GNUTLS_E_NO_CERTIFICATE_STATUS;
   }
@@ -1745,7 +1777,7 @@ exim_gnutls_state_st * state = NULL;
 if (tls_in.active >= 0)
   {
   tls_error(US"STARTTLS received after TLS started", "", NULL, errstr);
-  smtp_printf("554 Already in TLS\r\n");
+  smtp_printf("554 Already in TLS\r\n", FALSE);
   return FAIL;
   }
 
@@ -1806,7 +1838,7 @@ mode, the fflush() happens when smtp_getc() is called. */
 
 if (!state->tlsp->on_connect)
   {
-  smtp_printf("220 TLS go ahead\r\n");
+  smtp_printf("220 TLS go ahead\r\n", FALSE);
   fflush(smtp_out);
   }
 
@@ -1885,6 +1917,7 @@ and initialize appropriately. */
 state->xfer_buffer = store_malloc(ssl_xfer_buffer_size);
 
 receive_getc = tls_getc;
+receive_getbuf = tls_getbuf;
 receive_get_cache = tls_get_cache;
 receive_ungetc = tls_ungetc;
 receive_feof = tls_feof;
@@ -2154,6 +2187,75 @@ if ((state_server.session == NULL) && (state_client.session == NULL))
 
 
 
+static BOOL
+tls_refill(unsigned lim)
+{
+exim_gnutls_state_st * state = &state_server;
+ssize_t inbytes;
+
+DEBUG(D_tls) debug_printf("Calling gnutls_record_recv(%p, %p, %u)\n",
+  state->session, state->xfer_buffer, ssl_xfer_buffer_size);
+
+if (smtp_receive_timeout > 0) alarm(smtp_receive_timeout);
+inbytes = gnutls_record_recv(state->session, state->xfer_buffer,
+  MIN(ssl_xfer_buffer_size, lim));
+alarm(0);
+
+/* Timeouts do not get this far; see command_timeout_handler().
+   A zero-byte return appears to mean that the TLS session has been
+   closed down, not that the socket itself has been closed down. Revert to
+   non-TLS handling. */
+
+if (sigalrm_seen)
+  {
+  DEBUG(D_tls) debug_printf("Got tls read timeout\n");
+  state->xfer_error = 1;
+  return FALSE;
+  }
+
+else if (inbytes == 0)
+  {
+  DEBUG(D_tls) debug_printf("Got TLS_EOF\n");
+
+  receive_getc = smtp_getc;
+  receive_getbuf = smtp_getbuf;
+  receive_get_cache = smtp_get_cache;
+  receive_ungetc = smtp_ungetc;
+  receive_feof = smtp_feof;
+  receive_ferror = smtp_ferror;
+  receive_smtp_buffered = smtp_buffered;
+
+  gnutls_deinit(state->session);
+  gnutls_certificate_free_credentials(state->x509_cred);
+
+  state->session = NULL;
+  state->tlsp->active = -1;
+  state->tlsp->bits = 0;
+  state->tlsp->certificate_verified = FALSE;
+  tls_channelbinding_b64 = NULL;
+  state->tlsp->cipher = NULL;
+  state->tlsp->peercert = NULL;
+  state->tlsp->peerdn = NULL;
+
+  return FALSE;
+  }
+
+/* Handle genuine errors */
+
+else if (inbytes < 0)
+  {
+  record_io_error(state, (int) inbytes, US"recv", NULL);
+  state->xfer_error = 1;
+  return FALSE;
+  }
+#ifndef DISABLE_DKIM
+dkim_exim_verify_feed(state->xfer_buffer, inbytes);
+#endif
+state->xfer_buffer_hwm = (int) inbytes;
+state->xfer_buffer_lwm = 0;
+return TRUE;
+}
+
 /*************************************************
 *            TLS version of getc                 *
 *************************************************/
@@ -2171,77 +2273,41 @@ Returns:    the next character or EOF
 int
 tls_getc(unsigned lim)
 {
-exim_gnutls_state_st *state = &state_server;
-if (state->xfer_buffer_lwm >= state->xfer_buffer_hwm)
-  {
-  ssize_t inbytes;
-
-  DEBUG(D_tls) debug_printf("Calling gnutls_record_recv(%p, %p, %u)\n",
-    state->session, state->xfer_buffer, ssl_xfer_buffer_size);
-
-  if (smtp_receive_timeout > 0) alarm(smtp_receive_timeout);
-  inbytes = gnutls_record_recv(state->session, state->xfer_buffer,
-    MIN(ssl_xfer_buffer_size, lim));
-  alarm(0);
-
-  /* Timeouts do not get this far; see command_timeout_handler().
-     A zero-byte return appears to mean that the TLS session has been
-     closed down, not that the socket itself has been closed down. Revert to
-     non-TLS handling. */
-
-  if (sigalrm_seen)
-    {
-    DEBUG(D_tls) debug_printf("Got tls read timeout\n");
-    state->xfer_error = 1;
-    return EOF;
-    }
-
-  else if (inbytes == 0)
-    {
-    DEBUG(D_tls) debug_printf("Got TLS_EOF\n");
-
-    receive_getc = smtp_getc;
-    receive_get_cache = smtp_get_cache;
-    receive_ungetc = smtp_ungetc;
-    receive_feof = smtp_feof;
-    receive_ferror = smtp_ferror;
-    receive_smtp_buffered = smtp_buffered;
+exim_gnutls_state_st * state = &state_server;
 
-    gnutls_deinit(state->session);
-    gnutls_certificate_free_credentials(state->x509_cred);
+if (state->xfer_buffer_lwm >= state->xfer_buffer_hwm)
+  if (!tls_refill(lim))
+    return state->xfer_error ? EOF : smtp_getc(lim);
 
-    state->session = NULL;
-    state->tlsp->active = -1;
-    state->tlsp->bits = 0;
-    state->tlsp->certificate_verified = FALSE;
-    tls_channelbinding_b64 = NULL;
-    state->tlsp->cipher = NULL;
-    state->tlsp->peercert = NULL;
-    state->tlsp->peerdn = NULL;
+/* Something in the buffer; return next uschar */
 
-    return smtp_getc(lim);
-    }
+return state->xfer_buffer[state->xfer_buffer_lwm++];
+}
 
-  /* Handle genuine errors */
+uschar *
+tls_getbuf(unsigned * len)
+{
+exim_gnutls_state_st * state = &state_server;
+unsigned size;
+uschar * buf;
 
-  else if (inbytes < 0)
+if (state->xfer_buffer_lwm >= state->xfer_buffer_hwm)
+  if (!tls_refill(*len))
     {
-    record_io_error(state, (int) inbytes, US"recv", NULL);
-    state->xfer_error = 1;
-    return EOF;
+    if (!state->xfer_error) return smtp_getbuf(len);
+    *len = 0;
+    return NULL;
     }
-#ifndef DISABLE_DKIM
-  dkim_exim_verify_feed(state->xfer_buffer, inbytes);
-#endif
-  state->xfer_buffer_hwm = (int) inbytes;
-  state->xfer_buffer_lwm = 0;
-  }
-
-/* Something in the buffer; return next uschar */
 
-return state->xfer_buffer[state->xfer_buffer_lwm++];
+if ((size = state->xfer_buffer_hwm - state->xfer_buffer_lwm) > *len)
+  size = *len;
+buf = &state->xfer_buffer[state->xfer_buffer_lwm];
+state->xfer_buffer_lwm += size;
+*len = size;
+return buf;
 }
 
+
 void
 tls_get_cache()
 {
@@ -2254,6 +2320,14 @@ if (n > 0)
 }
 
 
+BOOL
+tls_could_read(void)
+{
+return state_server.xfer_buffer_lwm < state_server.xfer_buffer_hwm
+ || gnutls_record_check_pending(state_server.session) > 0;
+}
+
+
 
 
 /*************************************************
@@ -2313,19 +2387,27 @@ Arguments:
   is_server channel specifier
   buff      buffer of data
   len       number of bytes
+  more     more data expected soon
 
 Returns:    the number of bytes after a successful write,
             -1 after a failed write
 */
 
 int
-tls_write(BOOL is_server, const uschar *buff, size_t len)
+tls_write(BOOL is_server, const uschar *buff, size_t len, BOOL more)
 {
 ssize_t outbytes;
 size_t left = len;
 exim_gnutls_state_st *state = is_server ? &state_server : &state_client;
+#ifdef SUPPORT_CORK
+static BOOL corked = FALSE;
+
+if (more && !corked) gnutls_record_cork(state->session);
+#endif
+
+DEBUG(D_tls) debug_printf("%s(%p, " SIZE_T_FMT "%s)\n", __FUNCTION__,
+  buff, left, more ? ", more" : "");
 
-DEBUG(D_tls) debug_printf("tls_do_write(%p, " SIZE_T_FMT ")\n", buff, left);
 while (left > 0)
   {
   DEBUG(D_tls) debug_printf("gnutls_record_send(SSL, %p, " SIZE_T_FMT ")\n",
@@ -2356,6 +2438,14 @@ if (len > INT_MAX)
   len = INT_MAX;
   }
 
+#ifdef SUPPORT_CORK
+if (more != corked)
+  {
+  if (!more) (void) gnutls_record_uncork(state->session, 0);
+  corked = more;
+  }
+#endif
+
 return (int) len;
 }
 
index 4a41ba192fde32f18dd248f575f78733e74b176c..c0ed6f992c3a976dbcf49cb77ee8b948c77c6770 100644 (file)
@@ -69,6 +69,7 @@ functions from the OpenSSL library. */
 #ifndef LIBRESSL_VERSION_NUMBER
 # if OPENSSL_VERSION_NUMBER >= 0x010100000L
 #  define EXIM_HAVE_OPENSSL_CHECKHOST
+#  define EXIM_HAVE_OPENSSL_DH_BITS
 # endif
 # if OPENSSL_VERSION_NUMBER >= 0x010000000L \
     && (OPENSSL_VERSION_NUMBER & 0x0000ff000L) >= 0x000002000L
@@ -383,11 +384,13 @@ dn[sizeof(dn)-1] = '\0';
 
 if (preverify_ok == 0)
   {
-  log_write(0, LOG_MAIN, "[%s] SSL verify error: depth=%d error=%s cert=%s",
-       tlsp == &tls_out ? deliver_host_address : sender_host_address,
-    depth,
-    X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509ctx)),
-    dn);
+  uschar * extra = verify_mode ? string_sprintf(" (during %c-verify for [%s])",
+      *verify_mode, sender_host_address)
+    : US"";
+  log_write(0, LOG_MAIN, "[%s] SSL verify error%s: depth=%d error=%s cert=%s",
+    tlsp == &tls_out ? deliver_host_address : sender_host_address,
+    extra, depth,
+    X509_verify_cert_error_string(X509_STORE_CTX_get_error(x509ctx)), dn);
   *calledp = TRUE;
   if (!*optionalp)
     {
@@ -448,7 +451,7 @@ else
        if (rc < 0)
          {
          log_write(0, LOG_MAIN, "[%s] SSL verify error: internal error",
-               deliver_host_address);
+           tlsp == &tls_out ? deliver_host_address : sender_host_address);
          name = NULL;
          }
        break;
@@ -458,10 +461,14 @@ else
     if (!tls_is_name_for_cert(verify_cert_hostnames, cert))
 #endif
       {
+      uschar * extra = verify_mode
+        ? string_sprintf(" (during %c-verify for [%s])",
+         *verify_mode, sender_host_address)
+       : US"";
       log_write(0, LOG_MAIN,
-               "[%s] SSL verify error: certificate name mismatch: "
-               "DN=\"%s\" H=\"%s\"",
-               deliver_host_address, dn, verify_cert_hostnames);
+       "[%s] SSL verify error%s: certificate name mismatch: DN=\"%s\" H=\"%s\"",
+       tlsp == &tls_out ? deliver_host_address : sender_host_address,
+       extra, dn, verify_cert_hostnames);
       *calledp = TRUE;
       if (!*optionalp)
        {
@@ -595,6 +602,7 @@ BIO *bio;
 DH *dh;
 uschar *dhexpanded;
 const char *pem;
+int dh_bitsize;
 
 if (!expand_check(dhparam, US"tls_dhparam", &dhexpanded, errstr))
   return FALSE;
@@ -635,21 +643,34 @@ if (!(dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL)))
   return FALSE;
   }
 
+/* note: our default limit of 2236 is not a multiple of 8; the limit comes from
+ * an NSS limit, and the GnuTLS APIs handle bit-sizes fine, so we went with
+ * 2236.  But older OpenSSL can only report in bytes (octets), not bits.
+ * If someone wants to dance at the edge, then they can raise the limit or use
+ * current libraries. */
+#ifdef EXIM_HAVE_OPENSSL_DH_BITS
+/* Added in commit 26c79d5641d; `git describe --contains` says OpenSSL_1_1_0-pre1~1022
+ * This predates OpenSSL_1_1_0 (before a, b, ...) so is in all 1.1.0 */
+dh_bitsize = DH_bits(dh);
+#else
+dh_bitsize = 8 * DH_size(dh);
+#endif
+
 /* Even if it is larger, we silently return success rather than cause things
  * to fail out, so that a too-large DH will not knock out all TLS; it's a
  * debatable choice. */
-if ((8*DH_size(dh)) > tls_dh_max_bits)
+if (dh_bitsize > tls_dh_max_bits)
   {
   DEBUG(D_tls)
-    debug_printf("dhparams file %d bits, is > tls_dh_max_bits limit of %d",
-        8*DH_size(dh), tls_dh_max_bits);
+    debug_printf("dhparams file %d bits, is > tls_dh_max_bits limit of %d\n",
+        dh_bitsize, tls_dh_max_bits);
   }
 else
   {
   SSL_CTX_set_tmp_dh(sctx, dh);
   DEBUG(D_tls)
     debug_printf("Diffie-Hellman initialized from %s with %d-bit prime\n",
-      dhexpanded ? dhexpanded : US"default", 8*DH_size(dh));
+      dhexpanded ? dhexpanded : US"default", dh_bitsize);
   }
 
 DH_free(dh);
@@ -727,7 +748,7 @@ if (Ustrcmp(exp_curve, "auto") == 0)
 #if OPENSSL_VERSION_NUMBER < 0x10002000L
   DEBUG(D_tls) debug_printf(
     "ECDH OpenSSL < 1.0.2: temp key parameter settings: overriding \"auto\" with \"prime256v1\"\n");
-  exp_curve = "prime256v1";
+  exp_curve = US"prime256v1";
 #else
 # if defined SSL_CTRL_SET_ECDH_AUTO
   DEBUG(D_tls) debug_printf(
@@ -1418,9 +1439,9 @@ tls_init(SSL_CTX **ctxp, host_item *host, uschar *dhparam, uschar *certificate,
 #endif
   address_item *addr, tls_ext_ctx_cb ** cbp, uschar ** errstr)
 {
+SSL_CTX * ctx;
 long init_options;
 int rc;
-BOOL okay;
 tls_ext_ctx_cb * cbinfo;
 
 cbinfo = store_malloc(sizeof(tls_ext_ctx_cb));
@@ -1461,9 +1482,8 @@ when OpenSSL is built without SSLv2 support.
 By disabling with openssl_options, we can let admins re-enable with the
 existing knob. */
 
-*ctxp = SSL_CTX_new(host ? SSLv23_client_method() : SSLv23_server_method());
-
-if (!*ctxp) return tls_error(US"SSL_CTX_new", host, NULL, errstr);
+if (!(ctx = SSL_CTX_new(host ? SSLv23_client_method() : SSLv23_server_method())))
+  return tls_error(US"SSL_CTX_new", host, NULL, errstr);
 
 /* It turns out that we need to seed the random number generator this early in
 order to get the full complement of ciphers to work. It took me roughly a day
@@ -1479,9 +1499,9 @@ if (!RAND_status())
   gettimeofday(&r.tv, NULL);
   r.p = getpid();
 
-  RAND_seed((uschar *)(&r), sizeof(r));
-  RAND_seed((uschar *)big_buffer, big_buffer_size);
-  if (addr != NULL) RAND_seed((uschar *)addr, sizeof(addr));
+  RAND_seed(US (&r), sizeof(r));
+  RAND_seed(US big_buffer, big_buffer_size);
+  if (addr != NULL) RAND_seed(US addr, sizeof(addr));
 
   if (!RAND_status())
     return tls_error(US"RAND_status", host,
@@ -1491,10 +1511,10 @@ if (!RAND_status())
 /* Set up the information callback, which outputs if debugging is at a suitable
 level. */
 
-DEBUG(D_tls) SSL_CTX_set_info_callback(*ctxp, (void (*)())info_callback);
+DEBUG(D_tls) SSL_CTX_set_info_callback(ctx, (void (*)())info_callback);
 
 /* Automatically re-try reads/writes after renegotiation. */
-(void) SSL_CTX_set_mode(*ctxp, SSL_MODE_AUTO_RETRY);
+(void) SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
 
 /* Apply administrator-supplied work-arounds.
 Historically we applied just one requested option,
@@ -1505,31 +1525,34 @@ grandfathered in the first one as the default value for "openssl_options".
 No OpenSSL version number checks: the options we accept depend upon the
 availability of the option value macros from OpenSSL.  */
 
-okay = tls_openssl_options_parse(openssl_options, &init_options);
-if (!okay)
+if (!tls_openssl_options_parse(openssl_options, &init_options))
   return tls_error(US"openssl_options parsing failed", host, NULL, errstr);
 
 if (init_options)
   {
   DEBUG(D_tls) debug_printf("setting SSL CTX options: %#lx\n", init_options);
-  if (!(SSL_CTX_set_options(*ctxp, init_options)))
+  if (!(SSL_CTX_set_options(ctx, init_options)))
     return tls_error(string_sprintf(
           "SSL_CTX_set_option(%#lx)", init_options), host, NULL, errstr);
   }
 else
   DEBUG(D_tls) debug_printf("no SSL CTX options to set\n");
 
+/* Disable session cache unconditionally */
+
+(void) SSL_CTX_set_session_cache_mode(ctx, SSL_SESS_CACHE_OFF);
+
 /* Initialize with DH parameters if supplied */
 /* Initialize ECDH temp key parameter selection */
 
-if (  !init_dh(*ctxp, dhparam, host, errstr)
-   || !init_ecdh(*ctxp, host, errstr)
+if (  !init_dh(ctx, dhparam, host, errstr)
+   || !init_ecdh(ctx, host, errstr)
    )
   return DEFER;
 
 /* Set up certificate and key (and perhaps OCSP info) */
 
-if ((rc = tls_expand_session_files(*ctxp, cbinfo, errstr)) != OK)
+if ((rc = tls_expand_session_files(ctx, cbinfo, errstr)) != OK)
   return rc;
 
 /* If we need to handle SNI or OCSP, do so */
@@ -1552,14 +1575,14 @@ if (host == NULL)               /* server */
   callback is invoked. */
   if (cbinfo->u_ocsp.server.file)
     {
-    SSL_CTX_set_tlsext_status_cb(server_ctx, tls_server_stapling_cb);
-    SSL_CTX_set_tlsext_status_arg(server_ctx, cbinfo);
+    SSL_CTX_set_tlsext_status_cb(ctx, tls_server_stapling_cb);
+    SSL_CTX_set_tlsext_status_arg(ctx, cbinfo);
     }
 # endif
   /* We always do this, so that $tls_sni is available even if not used in
   tls_certificate */
-  SSL_CTX_set_tlsext_servername_callback(*ctxp, tls_servername_cb);
-  SSL_CTX_set_tlsext_servername_arg(*ctxp, cbinfo);
+  SSL_CTX_set_tlsext_servername_callback(ctx, tls_servername_cb);
+  SSL_CTX_set_tlsext_servername_arg(ctx, cbinfo);
   }
 # ifndef DISABLE_OCSP
 else                   /* client */
@@ -1570,8 +1593,8 @@ else                      /* client */
       DEBUG(D_tls) debug_printf("failed to create store for stapling verify\n");
       return FAIL;
       }
-    SSL_CTX_set_tlsext_status_cb(*ctxp, tls_client_stapling_cb);
-    SSL_CTX_set_tlsext_status_arg(*ctxp, cbinfo);
+    SSL_CTX_set_tlsext_status_cb(ctx, tls_client_stapling_cb);
+    SSL_CTX_set_tlsext_status_arg(ctx, cbinfo);
     }
 # endif
 #endif
@@ -1580,15 +1603,16 @@ cbinfo->verify_cert_hostnames = NULL;
 
 #ifdef EXIM_HAVE_EPHEM_RSA_KEX
 /* Set up the RSA callback */
-SSL_CTX_set_tmp_rsa_callback(*ctxp, rsa_callback);
+SSL_CTX_set_tmp_rsa_callback(ctx, rsa_callback);
 #endif
 
 /* Finally, set the timeout, and we are done */
 
-SSL_CTX_set_timeout(*ctxp, ssl_session_timeout);
+SSL_CTX_set_timeout(ctx, ssl_session_timeout);
 DEBUG(D_tls) debug_printf("Initialized TLS\n");
 
 *cbp = cbinfo;
+*ctxp = ctx;
 
 return OK;
 }
@@ -1699,6 +1723,7 @@ uschar *expcerts, *expcrl;
 
 if (!expand_check(certs, US"tls_verify_certificates", &expcerts, errstr))
   return DEFER;
+DEBUG(D_tls) debug_printf("tls_verify_certificates: %s\n", expcerts);
 
 if (expcerts && *expcerts)
   {
@@ -1871,7 +1896,7 @@ static uschar cipherbuf[256];
 if (tls_in.active >= 0)
   {
   tls_error(US"STARTTLS received after TLS started", NULL, US"", errstr);
-  smtp_printf("554 Already in TLS\r\n");
+  smtp_printf("554 Already in TLS\r\n", FALSE);
   return FAIL;
   }
 
@@ -1955,7 +1980,7 @@ mode, the fflush() happens when smtp_getc() is called. */
 SSL_set_session_id_context(server_ssl, sid_ctx, Ustrlen(sid_ctx));
 if (!tls_in.on_connect)
   {
-  smtp_printf("220 TLS go ahead\r\n");
+  smtp_printf("220 TLS go ahead\r\n", FALSE);
   fflush(smtp_out);
   }
 
@@ -2012,6 +2037,7 @@ ssl_xfer_buffer_lwm = ssl_xfer_buffer_hwm = 0;
 ssl_xfer_eof = ssl_xfer_error = 0;
 
 receive_getc = tls_getc;
+receive_getbuf = tls_getbuf;
 receive_get_cache = tls_get_cache;
 receive_ungetc = tls_ungetc;
 receive_feof = tls_feof;
@@ -2348,6 +2374,74 @@ return OK;
 
 
 
+static BOOL
+tls_refill(unsigned lim)
+{
+int error;
+int inbytes;
+
+DEBUG(D_tls) debug_printf("Calling SSL_read(%p, %p, %u)\n", server_ssl,
+  ssl_xfer_buffer, ssl_xfer_buffer_size);
+
+if (smtp_receive_timeout > 0) alarm(smtp_receive_timeout);
+inbytes = SSL_read(server_ssl, CS ssl_xfer_buffer,
+                 MIN(ssl_xfer_buffer_size, lim));
+error = SSL_get_error(server_ssl, inbytes);
+alarm(0);
+
+/* SSL_ERROR_ZERO_RETURN appears to mean that the SSL session has been
+closed down, not that the socket itself has been closed down. Revert to
+non-SSL handling. */
+
+if (error == SSL_ERROR_ZERO_RETURN)
+  {
+  DEBUG(D_tls) debug_printf("Got SSL_ERROR_ZERO_RETURN\n");
+
+  receive_getc = smtp_getc;
+  receive_getbuf = smtp_getbuf;
+  receive_get_cache = smtp_get_cache;
+  receive_ungetc = smtp_ungetc;
+  receive_feof = smtp_feof;
+  receive_ferror = smtp_ferror;
+  receive_smtp_buffered = smtp_buffered;
+
+  SSL_free(server_ssl);
+  server_ssl = NULL;
+  tls_in.active = -1;
+  tls_in.bits = 0;
+  tls_in.cipher = NULL;
+  tls_in.peerdn = NULL;
+  tls_in.sni = NULL;
+
+  return FALSE;
+  }
+
+/* Handle genuine errors */
+
+else if (error == SSL_ERROR_SSL)
+  {
+  ERR_error_string(ERR_get_error(), ssl_errstring);
+  log_write(0, LOG_MAIN, "TLS error (SSL_read): %s", ssl_errstring);
+  ssl_xfer_error = 1;
+  return FALSE;
+  }
+
+else if (error != SSL_ERROR_NONE)
+  {
+  DEBUG(D_tls) debug_printf("Got SSL error %d\n", error);
+  ssl_xfer_error = 1;
+  return FALSE;
+  }
+
+#ifndef DISABLE_DKIM
+dkim_exim_verify_feed(ssl_xfer_buffer, inbytes);
+#endif
+ssl_xfer_buffer_hwm = inbytes;
+ssl_xfer_buffer_lwm = 0;
+return TRUE;
+}
+
+
 /*************************************************
 *            TLS version of getc                 *
 *************************************************/
@@ -2365,74 +2459,37 @@ int
 tls_getc(unsigned lim)
 {
 if (ssl_xfer_buffer_lwm >= ssl_xfer_buffer_hwm)
-  {
-  int error;
-  int inbytes;
-
-  DEBUG(D_tls) debug_printf("Calling SSL_read(%p, %p, %u)\n", server_ssl,
-    ssl_xfer_buffer, ssl_xfer_buffer_size);
-
-  if (smtp_receive_timeout > 0) alarm(smtp_receive_timeout);
-  inbytes = SSL_read(server_ssl, CS ssl_xfer_buffer,
-                   MIN(ssl_xfer_buffer_size, lim));
-  error = SSL_get_error(server_ssl, inbytes);
-  alarm(0);
+  if (!tls_refill(lim))
+    return ssl_xfer_error ? EOF : smtp_getc(lim);
 
-  /* SSL_ERROR_ZERO_RETURN appears to mean that the SSL session has been
-  closed down, not that the socket itself has been closed down. Revert to
-  non-SSL handling. */
-
-  if (error == SSL_ERROR_ZERO_RETURN)
-    {
-    DEBUG(D_tls) debug_printf("Got SSL_ERROR_ZERO_RETURN\n");
-
-    receive_getc = smtp_getc;
-    receive_get_cache = smtp_get_cache;
-    receive_ungetc = smtp_ungetc;
-    receive_feof = smtp_feof;
-    receive_ferror = smtp_ferror;
-    receive_smtp_buffered = smtp_buffered;
-
-    SSL_free(server_ssl);
-    server_ssl = NULL;
-    tls_in.active = -1;
-    tls_in.bits = 0;
-    tls_in.cipher = NULL;
-    tls_in.peerdn = NULL;
-    tls_in.sni = NULL;
-
-    return smtp_getc(lim);
-    }
+/* Something in the buffer; return next uschar */
 
-  /* Handle genuine errors */
+return ssl_xfer_buffer[ssl_xfer_buffer_lwm++];
+}
 
-  else if (error == SSL_ERROR_SSL)
-    {
-    ERR_error_string(ERR_get_error(), ssl_errstring);
-    log_write(0, LOG_MAIN, "TLS error (SSL_read): %s", ssl_errstring);
-    ssl_xfer_error = 1;
-    return EOF;
-    }
+uschar *
+tls_getbuf(unsigned * len)
+{
+unsigned size;
+uschar * buf;
 
-  else if (error != SSL_ERROR_NONE)
+if (ssl_xfer_buffer_lwm >= ssl_xfer_buffer_hwm)
+  if (!tls_refill(*len))
     {
-    DEBUG(D_tls) debug_printf("Got SSL error %d\n", error);
-    ssl_xfer_error = 1;
-    return EOF;
+    if (!ssl_xfer_error) return smtp_getbuf(len);
+    *len = 0;
+    return NULL;
     }
 
-#ifndef DISABLE_DKIM
-  dkim_exim_verify_feed(ssl_xfer_buffer, inbytes);
-#endif
-  ssl_xfer_buffer_hwm = inbytes;
-  ssl_xfer_buffer_lwm = 0;
-  }
-
-/* Something in the buffer; return next uschar */
-
-return ssl_xfer_buffer[ssl_xfer_buffer_lwm++];
+if ((size = ssl_xfer_buffer_hwm - ssl_xfer_buffer_lwm) > *len)
+  size = *len;
+buf = &ssl_xfer_buffer[ssl_xfer_buffer_lwm];
+ssl_xfer_buffer_lwm += size;
+*len = size;
+return buf;
 }
 
+
 void
 tls_get_cache()
 {
@@ -2444,6 +2501,12 @@ if (n > 0)
 }
 
 
+BOOL
+tls_could_read(void)
+{
+return ssl_xfer_buffer_lwm < ssl_xfer_buffer_hwm || SSL_pending(server_ssl) > 0;
+}
+
 
 /*************************************************
 *          Read bytes from TLS channel           *
@@ -2497,6 +2560,7 @@ Arguments:
   is_server channel specifier
   buff      buffer of data
   len       number of bytes
+  more     further data expected soon
 
 Returns:    the number of bytes after a successful write,
             -1 after a failed write
@@ -2505,15 +2569,32 @@ Used by both server-side and client-side TLS.
 */
 
 int
-tls_write(BOOL is_server, const uschar *buff, size_t len)
+tls_write(BOOL is_server, const uschar *buff, size_t len, BOOL more)
 {
-int outbytes;
-int error;
-int left = len;
+int outbytes, error, left;
 SSL *ssl = is_server ? server_ssl : client_ssl;
+static uschar * corked = NULL;
+static int c_size = 0, c_len = 0;
+
+DEBUG(D_tls) debug_printf("%s(%p, %lu%s)\n", __FUNCTION__,
+  buff, (unsigned long)len, more ? ", more" : "");
+
+/* Lacking a CORK or MSG_MORE facility (such as GnuTLS has) we copy data when
+"more" is notified.  This hack is only ok if small amounts are involved AND only
+one stream does it, in one context (i.e. no store reset).  Currently it is used
+for the responses to the received SMTP MAIL , RCPT, DATA sequence, only. */
+
+if (is_server && (more || corked))
+  {
+  corked = string_catn(corked, &c_size, &c_len, buff, len);
+  if (more)
+    return len;
+  buff = CUS corked;
+  len = c_len;
+  corked = NULL; c_size = c_len = 0;
+  }
 
-DEBUG(D_tls) debug_printf("tls_do_write(%p, %d)\n", buff, left);
-while (left > 0)
+for (left = len; left > 0;)
   {
   DEBUG(D_tls) debug_printf("SSL_write(SSL, %p, %d)\n", buff, left);
   outbytes = SSL_write(ssl, CS buff, left);
@@ -2738,7 +2819,7 @@ if (!RAND_status())
   gettimeofday(&r.tv, NULL);
   r.p = getpid();
 
-  RAND_seed((uschar *)(&r), sizeof(r));
+  RAND_seed(US (&r), sizeof(r));
   }
 /* We're after pseudo-random, not random; if we still don't have enough data
 in the internal PRNG then our options are limited.  We could sleep and hope
@@ -2950,7 +3031,7 @@ uschar *s, *end;
 uschar keep_c;
 BOOL adding, item_parsed;
 
-result = 0L;
+result = SSL_OP_NO_TICKET;
 /* Prior to 4.80 we or'd in SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; removed
  * from default because it increases BEAST susceptibility. */
 #ifdef SSL_OP_NO_SSLv2
@@ -2960,7 +3041,7 @@ result |= SSL_OP_NO_SSLv2;
 result |= SSL_OP_SINGLE_DH_USE;
 #endif
 
-if (option_spec == NULL)
+if (!option_spec)
   {
   *results = result;
   return TRUE;
index a5cb35bd9bba039f03478edf4fb1b2634dc192a5..c93eb4579069e36365aba99a222aa3e12bf038b0 100644 (file)
@@ -264,6 +264,7 @@ uschar * ele;
 uschar * match = NULL;
 int len;
 uschar * list = NULL;
+int size = 0, pos = 0;
 
 while ((ele = string_nextinlist(&mod, &insep, NULL, 0)))
   if (ele[0] != '>')
@@ -278,7 +279,7 @@ while ((ele = string_nextinlist(CUSS &dn, &insep, NULL, 0)))
   if (  !match
      || Ustrncmp(ele, match, len) == 0 && ele[len] == '='
      )
-    list = string_append_listele(list, outsep, ele+len+1);
+    list = string_append_listele(list, &size, &pos, outsep, ele+len+1);
 return list;
 }
 
index 296398ae9af2c878bdd6cf8badd322bbbab0c896..65d01214ab41f00d8590e5b2c4d16fcda2a8eb81 100644 (file)
@@ -182,8 +182,8 @@ if ((ret = gnutls_x509_crt_get_serial((gnutls_x509_crt_t)cert,
     bin, &sz)))
   return g_err("gs0", __FUNCTION__, ret);
 
-for(dp = txt, sp = bin; sz; dp += 2, sp++, sz--)
-  sprintf(CS dp, "%.2x", *sp);
+for(dp = txt, sp = bin; sz; sz--)
+  dp += sprintf(CS dp, "%.2x", *sp++);
 for(sp = txt; sp[0]=='0' && sp[1]; ) sp++;     /* leading zeroes */
 return string_copy(sp);
 }
@@ -205,8 +205,8 @@ cp1 = store_get(len*4+1);
 if (gnutls_x509_crt_get_signature((gnutls_x509_crt_t)cert, CS cp1, &len) != 0)
   return g_err("gs1", __FUNCTION__, ret);
 
-for(cp3 = cp2 = cp1+len; cp1 < cp2; cp3 += 3, cp1++)
-  sprintf(CS cp3, "%.2x ", *cp1);
+for(cp3 = cp2 = cp1+len; cp1 < cp2; cp1++)
+  cp3 += sprintf(CS cp3, "%.2x ", *cp1);
 cp3[-1]= '\0';
 
 return cp2;
@@ -269,8 +269,8 @@ if (ret < 0)
 /* binary data, DER encoded */
 
 /* just dump for now */
-for(cp3 = cp2 = cp1+siz; cp1 < cp2; cp3 += 3, cp1++)
-  sprintf(CS cp3, "%.2x ", *cp1);
+for(cp3 = cp2 = cp1+siz; cp1 < cp2; cp1++)
+  cp3 += sprintf(CS cp3, "%.2x ", *cp1);
 cp3[-1]= '\0';
 
 return cp2;
@@ -280,6 +280,7 @@ uschar *
 tls_cert_subject_altname(void * cert, uschar * mod)
 {
 uschar * list = NULL;
+int lsize = 0, llen = 0;
 int index;
 size_t siz;
 int ret;
@@ -332,7 +333,7 @@ for(index = 0;; index++)
     case GNUTLS_SAN_RFC822NAME: tag = US"MAIL"; break;
     default: continue;        /* ignore unrecognised types */
     }
-  list = string_append_listele(list, sep,
+  list = string_append_listele(list, &lsize, &llen, sep,
           match == -1 ? string_sprintf("%s=%s", tag, ele) : ele);
   }
 /*NOTREACHED*/
@@ -347,6 +348,7 @@ int ret;
 uschar sep = '\n';
 int index;
 uschar * list = NULL;
+int lsize = 0, llen = 0;
 
 if (mod)
   if (*mod == '>' && *++mod) sep = *mod++;
@@ -361,8 +363,8 @@ for(index = 0;; index++)
   if (ret < 0)
     return g_err("gai", __FUNCTION__, ret);
 
-  list = string_append_listele(list, sep,
-           string_copyn(uri.data, uri.size));
+  list = string_append_listele_n(list, &lsize, &llen, sep,
+           uri.data, uri.size);
   }
 /*NOTREACHED*/
 
@@ -384,6 +386,7 @@ size_t siz;
 uschar sep = '\n';
 int index;
 uschar * list = NULL;
+int lsize = 0, llen = 0;
 uschar * ele;
 
 if (mod)
@@ -403,13 +406,12 @@ for(index = 0;; index++)
       return g_err("gc0", __FUNCTION__, ret);
     }
 
-  ele = store_get(siz+1);
+  ele = store_get(siz);
   if ((ret = gnutls_x509_crt_get_crl_dist_points(
       (gnutls_x509_crt_t)cert, index, ele, &siz, NULL, NULL)) < 0)
     return g_err("gc1", __FUNCTION__, ret);
 
-  ele[siz] = '\0';
-  list = string_append_listele(list, sep, ele);
+  list = string_append_listele_n(list, &lsize, &llen, sep, ele, siz);
   }
 /*NOTREACHED*/
 }
@@ -457,8 +459,8 @@ cp = store_get(siz*3+1);
 if ((ret = gnutls_x509_crt_get_fingerprint(cert, algo, cp, &siz)) < 0)
   return g_err("gf1", __FUNCTION__, ret);
 
-for (cp3 = cp2 = cp+siz; cp < cp2; cp++, cp3+=2)
-  sprintf(CS cp3, "%02X",*cp);
+for (cp3 = cp2 = cp+siz; cp < cp2; cp++)
+  cp3 += sprintf(CS cp3, "%02X", *cp);
 return cp2;
 }
 
index 690f9508148609b4572c587c02388c9ca4509215..87623a8794be6f24ee4df83fa7eb2f14620454b6 100644 (file)
@@ -331,8 +331,7 @@ cp3 = cp2 = store_get(len*3+1);
 
 while(len)
   {
-  sprintf(CS cp2, "%.2x ", *cp1++);
-  cp2 += 3;
+  cp2 += sprintf(CS cp2, "%.2x ", *cp1++);
   len--;
   }
 cp2[-1] = '\0';
@@ -344,6 +343,7 @@ uschar *
 tls_cert_subject_altname(void * cert, uschar * mod)
 {
 uschar * list = NULL;
+int lsize = 0, llen = 0;
 STACK_OF(GENERAL_NAME) * san = (STACK_OF(GENERAL_NAME) *)
   X509_get_ext_d2i((X509 *)cert, NID_subject_alt_name, NULL, NULL);
 uschar osep = '\n';
@@ -394,7 +394,7 @@ while (sk_GENERAL_NAME_num(san) > 0)
     ele = string_copyn(ele, len);
 
   if (Ustrlen(ele) == len)     /* ignore any with embedded nul */
-    list = string_append_listele(list, osep,
+    list = string_append_listele(list, &lsize, &llen, osep,
          match == -1 ? string_sprintf("%s=%s", tag, ele) : ele);
   }
 
@@ -411,6 +411,7 @@ int adsnum = sk_ACCESS_DESCRIPTION_num(ads);
 int i;
 uschar sep = '\n';
 uschar * list = NULL;
+int size = 0, len = 0;
 
 if (mod)
   if (*mod == '>' && *++mod) sep = *mod++;
@@ -420,11 +421,9 @@ for (i = 0; i < adsnum; i++)
   ACCESS_DESCRIPTION * ad = sk_ACCESS_DESCRIPTION_value(ads, i);
 
   if (ad && OBJ_obj2nid(ad->method) == NID_ad_OCSP)
-    {
-    uschar * ele = ASN1_STRING_data(ad->location->d.ia5);
-    int len =  ASN1_STRING_length(ad->location->d.ia5);
-    list = string_append_listele_n(list, sep, ele, len);
-    }
+    list = string_append_listele_n(list, &size, &len, sep,
+      ASN1_STRING_data(ad->location->d.ia5),
+      ASN1_STRING_length(ad->location->d.ia5));
   }
 sk_ACCESS_DESCRIPTION_free(ads);
 return list;
@@ -441,6 +440,7 @@ int dpsnum = sk_DIST_POINT_num(dps);
 int i;
 uschar sep = '\n';
 uschar * list = NULL;
+int size = 0, len = 0;
 
 if (mod)
   if (*mod == '>' && *++mod) sep = *mod++;
@@ -457,11 +457,9 @@ if (dps) for (i = 0; i < dpsnum; i++)
       if (  (np = sk_GENERAL_NAME_value(names, j))
         && np->type == GEN_URI
         )
-       {
-       uschar * ele = ASN1_STRING_data(np->d.uniformResourceIdentifier);
-       int len =  ASN1_STRING_length(np->d.uniformResourceIdentifier);
-       list = string_append_listele_n(list, sep, ele, len);
-       }
+       list = string_append_listele_n(list, &size, &len,  sep,
+         ASN1_STRING_data(np->d.uniformResourceIdentifier),
+         ASN1_STRING_length(np->d.uniformResourceIdentifier));
     }
 sk_DIST_POINT_free(dps);
 return list;
index 5f451ba96de445e6b52a60b01f5a04a9ed4bc8dd..76b6d2da993bc94268482bc13c0c863011e9e4ef 100644 (file)
@@ -13,7 +13,7 @@
 /* #define TESTING_LOG_DATESTAMP */
 
 
-static uschar timebuf[sizeof("www, dd-mmm-yyyy hh:mm:ss +zzzz")];
+static uschar timebuf[sizeof("www, dd-mmm-yyyy hh:mm:ss.ddd +zzzz")];
 
 
 /*************************************************
@@ -52,159 +52,173 @@ Returns:   pointer to fixed buffer containing the timestamp
 uschar *
 tod_stamp(int type)
 {
-time_t now;
-struct tm *t;
+struct timeval now;
+struct tm * t;
+int off = 0;
 
-if (type == tod_epoch_l)
-  {
-  struct timeval tv;
-  gettimeofday(&tv, NULL);
-  /* Unix epoch/usec format */
-  (void) sprintf(CS timebuf, TIME_T_FMT "%06ld", tv.tv_sec, (long) tv.tv_usec );
-  return timebuf;
-  }
-
-now = time(NULL);
-
-/* Vary log type according to timezone requirement */
-
-if (type == tod_log) type = log_timezone? tod_log_zone : tod_log_bare;
+gettimeofday(&now, NULL);
 
 /* Styles that don't need local time */
 
-else if (type == tod_epoch)
+switch(type)
   {
-  (void) sprintf(CS timebuf, TIME_T_FMT, now);  /* Unix epoch format */
-  return timebuf;      /* NB the above will be wrong if time_t is FP */
+  case tod_epoch:
+    (void) sprintf(CS timebuf, TIME_T_FMT, now.tv_sec);  /* Unix epoch format */
+    return timebuf;    /* NB the above will be wrong if time_t is FP */
+
+  case tod_epoch_l:
+    /* Unix epoch/usec format */
+    (void) sprintf(CS timebuf, TIME_T_FMT "%06ld", now.tv_sec, (long) now.tv_usec );
+    return timebuf;
+
+  case tod_zulu:
+    t = gmtime(&now.tv_sec);
+    (void) sprintf(CS timebuf, "%04d%02d%02d%02d%02d%02dZ",
+      1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min,
+      t->tm_sec);
+    return timebuf;
   }
 
-else if (type == tod_zulu)
-  {
-  t = gmtime(&now);
-  (void) sprintf(CS timebuf, "%04d%02d%02d%02d%02d%02dZ",
-    1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min,
-    t->tm_sec);
-  return timebuf;
-  }
+/* Vary log type according to timezone requirement */
+
+if (type == tod_log) type = log_timezone ? tod_log_zone : tod_log_bare;
 
 /* Convert to local time or UTC */
 
-t = timestamps_utc? gmtime(&now) : localtime(&now);
+t = timestamps_utc ? gmtime(&now.tv_sec) : localtime(&now.tv_sec);
 
 switch(type)
   {
   case tod_log_bare:          /* Format used in logging without timezone */
-  (void) sprintf(CS timebuf, "%04d-%02d-%02d %02d:%02d:%02d",
-    1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday,
-    t->tm_hour, t->tm_min, t->tm_sec);
-  break;
+    off = sprintf(CS timebuf, "%04d-%02d-%02d %02d:%02d:%02d",
+      1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday,
+      t->tm_hour, t->tm_min, t->tm_sec);
+    break;
 
-  /* Format used as suffix of log file name when 'log_datestamp' is active. For
-  testing purposes, it changes the file every second. */
+    /* Format used as suffix of log file name when 'log_datestamp' is active. For
+    testing purposes, it changes the file every second. */
 
-  #ifdef TESTING_LOG_DATESTAMP
+#ifdef TESTING_LOG_DATESTAMP
   case tod_log_datestamp_daily:
   case tod_log_datestamp_monthly:
-  (void) sprintf(CS timebuf, "%04d%02d%02d%02d%02d",
-    1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min);
-  break;
+    off = sprintf(CS timebuf, "%04d%02d%02d%02d%02d",
+      1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min);
+    break;
 
-  #else
+#else
   case tod_log_datestamp_daily:
-  (void) sprintf(CS timebuf, "%04d%02d%02d",
-    1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday);
-  break;
+    off = sprintf(CS timebuf, "%04d%02d%02d",
+      1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday);
+    break;
 
   case tod_log_datestamp_monthly:
-  (void) sprintf(CS timebuf, "%04d%02d",
-    1900 + t->tm_year, 1 + t->tm_mon);
-  break;
-  #endif
-
-  /* Format used in BSD inbox separator lines. Sort-of documented in RFC 976
-  ("UUCP Mail Interchange Format Standard") but only by example, not by
-  explicit definition. The examples show no timezone offsets, and some MUAs
-  appear to be sensitive to this, so Exim has been changed to remove the
-  timezone offsets that originally appeared. */
+#ifndef COMPILE_UTILITY
+    off = sprintf(CS timebuf, "%04d%02d",
+      1900 + t->tm_year, 1 + t->tm_mon);
+#endif
+    break;
+#endif
+
+    /* Format used in BSD inbox separator lines. Sort-of documented in RFC 976
+    ("UUCP Mail Interchange Format Standard") but only by example, not by
+    explicit definition. The examples show no timezone offsets, and some MUAs
+    appear to be sensitive to this, so Exim has been changed to remove the
+    timezone offsets that originally appeared. */
 
   case tod_bsdin:
-    {
-    int len = Ustrftime(timebuf, sizeof(timebuf), "%a %b %d %H:%M:%S", t);
-    Ustrftime(timebuf + len, sizeof(timebuf) - len, " %Y", t);
-    }
-  break;
-
-  /* Other types require the GMT offset to be calculated, or just set up in the
-  case of UTC timestamping. We need to take a copy of the local time first. */
-
-  default:
-    {
-    int diff_hour, diff_min;
-    struct tm local;
-    memcpy(&local, t, sizeof(struct tm));
-
-    if (timestamps_utc)
       {
-      diff_hour = diff_min = 0;
-      }
-    else
-      {
-      struct tm *gmt = gmtime(&now);
-      diff_min = 60*(local.tm_hour - gmt->tm_hour) + local.tm_min - gmt->tm_min;
-      if (local.tm_year != gmt->tm_year)
-        diff_min += (local.tm_year > gmt->tm_year)? 1440 : -1440;
-      else if (local.tm_yday != gmt->tm_yday)
-        diff_min += (local.tm_yday > gmt->tm_yday)? 1440 : -1440;
-      diff_hour = diff_min/60;
-      diff_min  = abs(diff_min - diff_hour*60);
+      int len = Ustrftime(timebuf, sizeof(timebuf), "%a %b %d %H:%M:%S", t);
+      Ustrftime(timebuf + len, sizeof(timebuf) - len, " %Y", t);
       }
+    break;
+
+    /* Other types require the GMT offset to be calculated, or just set up in the
+    case of UTC timestamping. We need to take a copy of the local time first. */
 
-    switch(type)
+  default:
       {
-      case tod_log_zone:          /* Format used in logging with timezone */
-      (void) sprintf(CS timebuf, "%04d-%02d-%02d %02d:%02d:%02d %+03d%02d",
-        1900 + local.tm_year, 1 + local.tm_mon, local.tm_mday,
-        local.tm_hour, local.tm_min, local.tm_sec,
-        diff_hour, diff_min);
-      break;
-
-      case tod_zone:              /* Just the timezone offset */
-      (void) sprintf(CS timebuf, "%+03d%02d", diff_hour, diff_min);
-      break;
-
-      /* tod_mbx: format used in MBX mailboxes - subtly different to tod_full */
-
-      #ifdef SUPPORT_MBX
-      case tod_mbx:
-        {
-        int len;
-        (void) sprintf(CS timebuf, "%02d-", local.tm_mday);
-        len = Ustrlen(timebuf);
-        len += Ustrftime(timebuf + len, sizeof(timebuf) - len, "%b-%Y %H:%M:%S",
-          &local);
-        (void) sprintf(CS timebuf + len, " %+03d%02d", diff_hour, diff_min);
-        }
-      break;
-      #endif
-
-      /* tod_full: format used in Received: headers (use as default just in case
-      called with a junk type value) */
-
-      default:
-        {
-        int len = Ustrftime(timebuf, sizeof(timebuf), "%a, ", &local);
-        (void) sprintf(CS timebuf + len, "%02d ", local.tm_mday);
-        len += Ustrlen(timebuf + len);
-        len += Ustrftime(timebuf + len, sizeof(timebuf) - len, "%b %Y %H:%M:%S",
-          &local);
-        (void) sprintf(CS timebuf + len, " %+03d%02d", diff_hour, diff_min);
-        }
-      break;
+      int diff_hour, diff_min;
+      struct tm local;
+      memcpy(&local, t, sizeof(struct tm));
+
+      if (timestamps_utc)
+       diff_hour = diff_min = 0;
+      else
+       {
+       struct tm * gmt = gmtime(&now.tv_sec);
+
+       diff_min = 60*(local.tm_hour - gmt->tm_hour) + local.tm_min - gmt->tm_min;
+       if (local.tm_year != gmt->tm_year)
+         diff_min += (local.tm_year > gmt->tm_year)? 1440 : -1440;
+       else if (local.tm_yday != gmt->tm_yday)
+         diff_min += (local.tm_yday > gmt->tm_yday)? 1440 : -1440;
+       diff_hour = diff_min/60;
+       diff_min  = abs(diff_min - diff_hour*60);
+       }
+
+      switch(type)
+       {
+       case tod_log_zone:          /* Format used in logging with timezone */
+#ifndef COMPILE_UTILITY
+         if (LOGGING(millisec))
+           (void) sprintf(CS timebuf,
+             "%04d-%02d-%02d %02d:%02d:%02d.%03d %+03d%02d",
+             1900 + local.tm_year, 1 + local.tm_mon, local.tm_mday,
+             local.tm_hour, local.tm_min, local.tm_sec, (int)(now.tv_usec/1000),
+             diff_hour, diff_min);
+         else
+#endif
+           (void) sprintf(CS timebuf,
+             "%04d-%02d-%02d %02d:%02d:%02d %+03d%02d",
+             1900 + local.tm_year, 1 + local.tm_mon, local.tm_mday,
+             local.tm_hour, local.tm_min, local.tm_sec,
+             diff_hour, diff_min);
+         break;
+
+       case tod_zone:              /* Just the timezone offset */
+         (void) sprintf(CS timebuf, "%+03d%02d", diff_hour, diff_min);
+         break;
+
+       /* tod_mbx: format used in MBX mailboxes - subtly different to tod_full */
+
+         #ifdef SUPPORT_MBX
+       case tod_mbx:
+           {
+           int len;
+           (void) sprintf(CS timebuf, "%02d-", local.tm_mday);
+           len = Ustrlen(timebuf);
+           len += Ustrftime(timebuf + len, sizeof(timebuf) - len, "%b-%Y %H:%M:%S",
+             &local);
+           (void) sprintf(CS timebuf + len, " %+03d%02d", diff_hour, diff_min);
+           }
+         break;
+         #endif
+
+       /* tod_full: format used in Received: headers (use as default just in case
+       called with a junk type value) */
+
+       default:
+           {
+           int len = Ustrftime(timebuf, sizeof(timebuf), "%a, ", &local);
+           (void) sprintf(CS timebuf + len, "%02d ", local.tm_mday);
+           len += Ustrlen(timebuf + len);
+           len += Ustrftime(timebuf + len, sizeof(timebuf) - len, "%b %Y %H:%M:%S",
+             &local);
+           (void) sprintf(CS timebuf + len, " %+03d%02d", diff_hour, diff_min);
+           }
+         break;
+       }
       }
-    }
-  break;
+    break;
   }
 
+#ifndef COMPILE_UTILITY
+if (LOGGING(millisec) && off > 0)
+  (void) sprintf(CS timebuf + off, ".%03d", (int)(now.tv_usec/1000));
+#else
+off = off;     /* Compiler quietening */
+#endif
+
 return timebuf;
 }
 
index aca33762b12c10036da01ac4a3c7567ebe8632b5..5d4102ef8781b21279ae7ab5e38784349423967a 100644 (file)
@@ -11,35 +11,13 @@ transports. */
 
 #include "exim.h"
 
-#ifdef HAVE_LINUX_SENDFILE
-#include <sys/sendfile.h>
-#endif
-
-/* Structure for keeping list of addresses that have been added to
-Envelope-To:, in order to avoid duplication. */
-
-struct aci {
-  struct aci *next;
-  address_item *ptr;
-  };
-
-
-/* Static data for write_chunk() */
-
-static uschar *chunk_ptr;           /* chunk pointer */
-static uschar *nl_check;            /* string to look for at line start */
-static int     nl_check_length;     /* length of same */
-static uschar *nl_escape;           /* string to insert */
-static int     nl_escape_length;    /* length of same */
-static int     nl_partial_match;    /* length matched at chunk end */
-
-
 /* Generic options for transports, all of which live inside transport_instance
 data blocks and which therefore have the opt_public flag set. Note that there
 are other options living inside this structure which can be set only from
 certain transports. */
 
 optionlist optionlist_transports[] = {
+  /*   name            type                                    value */
   { "*expand_group",    opt_stringptr|opt_hidden|opt_public,
                  (void *)offsetof(transport_instance, expand_gid) },
   { "*expand_user",     opt_stringptr|opt_hidden|opt_public,
@@ -110,21 +88,47 @@ optionlist optionlist_transports[] = {
 
 int optionlist_transports_size = nelem(optionlist_transports);
 
+#ifdef MACRO_PREDEF
+
+# include "macro_predef.h"
 
 void
-readconf_options_transports(void)
+options_transports(void)
 {
 struct transport_info * ti;
+uschar buf[64];
 
-readconf_options_from_list(optionlist_transports, nelem(optionlist_transports), US"TRANSPORTS", NULL);
+options_from_list(optionlist_transports, nelem(optionlist_transports), US"TRANSPORTS", NULL);
 
 for (ti = transports_available; ti->driver_name[0]; ti++)
   {
-  macro_create(string_sprintf("_DRIVER_TRANSPORT_%T", ti->driver_name), US"y", FALSE, TRUE);
-  readconf_options_from_list(ti->options, (unsigned)*ti->options_count, US"TRANSPORT", ti->driver_name);
+  spf(buf, sizeof(buf), US"_DRIVER_TRANSPORT_%T", ti->driver_name);
+  builtin_macro_create(buf);
+  options_from_list(ti->options, (unsigned)*ti->options_count, US"TRANSPORT", ti->driver_name);
   }
 }
 
+#else  /*!MACRO_PREDEF*/
+
+/* Structure for keeping list of addresses that have been added to
+Envelope-To:, in order to avoid duplication. */
+
+struct aci {
+  struct aci *next;
+  address_item *ptr;
+  };
+
+
+/* Static data for write_chunk() */
+
+static uschar *chunk_ptr;           /* chunk pointer */
+static uschar *nl_check;            /* string to look for at line start */
+static int     nl_check_length;     /* length of same */
+static uschar *nl_escape;           /* string to insert */
+static int     nl_escape_length;    /* length of same */
+static int     nl_partial_match;    /* length matched at chunk end */
+
+
 /*************************************************
 *             Initialize transport list           *
 *************************************************/
@@ -204,19 +208,21 @@ evermore, so stick a maximum repetition count on the loop to act as a
 longstop.
 
 Arguments:
-  fd        file descriptor to write to
+  tctx      transport context: file descriptor or string to write to
   block     block of bytes to write
   len       number of bytes to write
+  more     further data expected soon
 
 Returns:    TRUE on success, FALSE on failure (with errno preserved);
               transport_count is incremented by the number of bytes written
 */
 
-BOOL
-transport_write_block(int fd, uschar *block, int len)
+static BOOL
+transport_write_block_fd(transport_ctx * tctx, uschar *block, int len, BOOL more)
 {
 int i, rc, save_errno;
 int local_timeout = transport_write_timeout;
+int fd = tctx->u.fd;
 
 /* This loop is for handling incomplete writes and other retries. In most
 normal cases, it is only ever executed once. */
@@ -224,8 +230,8 @@ normal cases, it is only ever executed once. */
 for (i = 0; i < 100; i++)
   {
   DEBUG(D_transport)
-    debug_printf("writing data block fd=%d size=%d timeout=%d\n",
-      fd, len, local_timeout);
+    debug_printf("writing data block fd=%d size=%d timeout=%d%s\n",
+      fd, len, local_timeout, more ? " (more expected)" : "");
 
   /* This code makes use of alarm() in order to implement the timeout. This
   isn't a very tidy way of doing things. Using non-blocking I/O with select()
@@ -234,10 +240,14 @@ for (i = 0; i < 100; i++)
 
   if (transport_write_timeout <= 0)   /* No timeout wanted */
     {
-    #ifdef SUPPORT_TLS
-    if (tls_out.active == fd) rc = tls_write(FALSE, block, len); else
-    #endif
-    rc = write(fd, block, len);
+    rc =
+#ifdef SUPPORT_TLS
+       tls_out.active == fd ? tls_write(FALSE, block, len, more) :
+#endif
+#ifdef MSG_MORE
+       more ? send(fd, block, len, MSG_MORE) :
+#endif
+       write(fd, block, len);
     save_errno = errno;
     }
 
@@ -246,12 +256,16 @@ for (i = 0; i < 100; i++)
   else
     {
     alarm(local_timeout);
+
+    rc =
 #ifdef SUPPORT_TLS
-    if (tls_out.active == fd)
-      rc = tls_write(FALSE, block, len);
-    else
+       tls_out.active == fd ? tls_write(FALSE, block, len, more) :
 #endif
-      rc = write(fd, block, len);
+#ifdef MSG_MORE
+       more ? send(fd, block, len, MSG_MORE) :
+#endif
+       write(fd, block, len);
+
     save_errno = errno;
     local_timeout = alarm(0);
     if (sigalrm_seen)
@@ -323,6 +337,25 @@ return FALSE;
 }
 
 
+BOOL
+transport_write_block(transport_ctx * tctx, uschar *block, int len, BOOL more)
+{
+if (!(tctx->options & topt_output_string))
+  return transport_write_block_fd(tctx, block, len, more);
+
+/* Write to expanding-string.  NOTE: not NUL-terminated */
+
+if (!tctx->u.msg)
+  {
+  tctx->u.msg = store_get(tctx->msg_size = 1024);
+  tctx->msg_ptr = 0;
+  }
+
+tctx->u.msg = string_catn(tctx->u.msg, &tctx->msg_size, &tctx->msg_ptr, block, len);
+return TRUE;
+}
+
+
 
 
 /*************************************************
@@ -342,17 +375,29 @@ Returns:      the yield of transport_write_block()
 BOOL
 transport_write_string(int fd, const char *format, ...)
 {
+transport_ctx tctx = {{0}};
 va_list ap;
 va_start(ap, format);
 if (!string_vformat(big_buffer, big_buffer_size, format, ap))
   log_write(0, LOG_MAIN|LOG_PANIC_DIE, "overlong formatted string in transport");
 va_end(ap);
-return transport_write_block(fd, big_buffer, Ustrlen(big_buffer));
+tctx.u.fd = fd;
+return transport_write_block(&tctx, big_buffer, Ustrlen(big_buffer), FALSE);
 }
 
 
 
 
+void
+transport_write_reset(int options)
+{
+if (!(options & topt_continuation)) chunk_ptr = deliver_out_buffer;
+nl_partial_match = -1;
+nl_check_length = nl_escape_length = 0;
+}
+
+
+
 /*************************************************
 *              Write character chunk             *
 *************************************************/
@@ -366,18 +411,18 @@ Static data is used to handle the case when the last character of the previous
 chunk was NL, or matched part of the data that has to be escaped.
 
 Arguments:
-  fd         file descript to write to
+  tctx       transport context - processing to be done during output,
+               and file descriptor to write to
   chunk      pointer to data to write
   len        length of data to write
-  tctx       transport context - processing to be done during output
 
 In addition, the static nl_xxx variables must be set as required.
 
 Returns:     TRUE on success, FALSE on failure (with errno preserved)
 */
 
-static BOOL
-write_chunk(int fd, transport_ctx * tctx, uschar *chunk, int len)
+BOOL
+write_chunk(transport_ctx * tctx, uschar *chunk, int len)
 {
 uschar *start = chunk;
 uschar *end = chunk + len;
@@ -433,27 +478,36 @@ for (ptr = start; ptr < end; ptr++)
     /* If CHUNKING, prefix with BDAT (size) NON-LAST.  Also, reap responses
     from previous SMTP commands. */
 
-    if (tctx &&  tctx->options & topt_use_bdat  &&  tctx->chunk_cb)
+    if (tctx->options & topt_use_bdat  &&  tctx->chunk_cb)
       {
-      if (  tctx->chunk_cb(fd, tctx, (unsigned)len, 0) != OK
-        || !transport_write_block(fd, deliver_out_buffer, len)
-        || tctx->chunk_cb(fd, tctx, 0, tc_reap_prev) != OK
+      if (  tctx->chunk_cb(tctx, (unsigned)len, 0) != OK
+        || !transport_write_block(tctx, deliver_out_buffer, len, FALSE)
+        || tctx->chunk_cb(tctx, 0, tc_reap_prev) != OK
         )
        return FALSE;
       }
     else
-      if (!transport_write_block(fd, deliver_out_buffer, len))
+      if (!transport_write_block(tctx, deliver_out_buffer, len, FALSE))
        return FALSE;
     chunk_ptr = deliver_out_buffer;
     }
 
+  /* Remove CR before NL if required */
+
+  if (  *ptr == '\r' && ptr[1] == '\n'
+     && !(tctx->options & topt_use_crlf)
+     && spool_file_wireformat
+     )
+    ptr++;
+
   if ((ch = *ptr) == '\n')
     {
     int left = end - ptr - 1;  /* count of chars left after NL */
 
     /* Insert CR before NL if required */
 
-    if (tctx  &&  tctx->options & topt_use_crlf) *chunk_ptr++ = '\r';
+    if (tctx->options & topt_use_crlf && !spool_file_wireformat)
+      *chunk_ptr++ = '\r';
     *chunk_ptr++ = '\n';
     transport_newlines++;
 
@@ -569,15 +623,15 @@ Arguments:
   pplist    address of anchor of the list of addresses not to output
   pdlist    address of anchor of the list of processed addresses
   first     TRUE if this is the first address; set it FALSE afterwards
-  fd        the file descriptor to write to
   tctx      transport context - processing to be done during output
+             and the file descriptor to write to
 
 Returns:    FALSE if writing failed
 */
 
 static BOOL
 write_env_to(address_item *p, struct aci **pplist, struct aci **pdlist,
-  BOOL *first, int fd, transport_ctx * tctx)
+  BOOL *first, transport_ctx * tctx)
 {
 address_item *pp;
 struct aci *ppp;
@@ -599,7 +653,7 @@ for (pp = p;; pp = pp->parent)
   address_item *dup;
   for (dup = addr_duplicate; dup; dup = dup->next)
     if (dup->dupof == pp)   /* a dup of our address */
-      if (!write_env_to(dup, pplist, pdlist, first, fd, tctx))
+      if (!write_env_to(dup, pplist, pdlist, first, tctx))
        return FALSE;
   if (!pp->parent) break;
   }
@@ -616,9 +670,9 @@ ppp->next = *pplist;
 *pplist = ppp;
 ppp->ptr = pp;
 
-if (!*first && !write_chunk(fd, tctx, US",\n ", 3)) return FALSE;
+if (!*first && !write_chunk(tctx, US",\n ", 3)) return FALSE;
 *first = FALSE;
-return write_chunk(fd, tctx, pp->address, Ustrlen(pp->address));
+return write_chunk(tctx, pp->address, Ustrlen(pp->address));
 }
 
 
@@ -632,15 +686,14 @@ Globals:
 Arguments:
   addr                  (chain of) addresses (for extra headers), or NULL;
                           only the first address is used
-  fd                    file descriptor to write the message to
   tctx                  transport context
   sendfn               function for output (transport or verify)
 
 Returns:                TRUE on success; FALSE on failure.
 */
 BOOL
-transport_headers_send(int fd, transport_ctx * tctx,
-  BOOL (*sendfn)(int fd, transport_ctx * tctx, uschar * s, int len))
+transport_headers_send(transport_ctx * tctx,
+  BOOL (*sendfn)(transport_ctx * tctx, uschar * s, int len))
 {
 header_line *h;
 const uschar *list;
@@ -700,7 +753,7 @@ for (h = header_list; h; h = h->next) if (h->type != htype_old)
       if ((hh = rewrite_header(h, NULL, NULL, tblock->rewrite_rules,
                  tblock->rewrite_existflags, FALSE)))
        {
-       if (!sendfn(fd, tctx, hh->text, hh->slen)) return FALSE;
+       if (!sendfn(tctx, hh->text, hh->slen)) return FALSE;
        store_reset(reset_point);
        continue;     /* With the next header line */
        }
@@ -708,15 +761,13 @@ for (h = header_list; h; h = h->next) if (h->type != htype_old)
 
     /* Either no rewriting rules, or it didn't get rewritten */
 
-    if (!sendfn(fd, tctx, h->text, h->slen)) return FALSE;
+    if (!sendfn(tctx, h->text, h->slen)) return FALSE;
     }
 
   /* Header removed */
 
   else
-    {
     DEBUG(D_transport) debug_printf("removed header line:\n%s---\n", h->text);
-    }
   }
 
 /* Add on any address-specific headers. If there are multiple addresses,
@@ -743,7 +794,7 @@ if (addr)
       hprev = h;
       if (i == 1)
        {
-       if (!sendfn(fd, tctx, h->text, h->slen)) return FALSE;
+       if (!sendfn(tctx, h->text, h->slen)) return FALSE;
        DEBUG(D_transport)
          debug_printf("added header line(s):\n%s---\n", h->text);
        }
@@ -768,8 +819,8 @@ if (tblock && (list = CUS tblock->add_headers))
       int len = Ustrlen(s);
       if (len > 0)
        {
-       if (!sendfn(fd, tctx, s, len)) return FALSE;
-       if (s[len-1] != '\n' && !sendfn(fd, tctx, US"\n", 1))
+       if (!sendfn(tctx, s, len)) return FALSE;
+       if (s[len-1] != '\n' && !sendfn(tctx, US"\n", 1))
          return FALSE;
        DEBUG(D_transport)
          {
@@ -785,7 +836,7 @@ if (tblock && (list = CUS tblock->add_headers))
 
 /* Separate headers from body with a blank line */
 
-return sendfn(fd, tctx, US"\n", 1);
+return sendfn(tctx, US"\n", 1);
 }
 
 
@@ -818,8 +869,10 @@ can include timeouts for certain transports, which are requested by setting
 transport_write_timeout non-zero.
 
 Arguments:
-  fd                    file descriptor to write the message to
   tctx
+    (fd, msg)          Either and fd, to write the message to,
+                       or a string: if null write message to allocated space
+                       otherwire take content as headers.
     addr                (chain of) addresses (for extra headers), or NULL;
                           only the first address is used
     tblock             optional transport instance block (NULL signifies NULL/0):
@@ -851,17 +904,16 @@ Returns:                TRUE on success; FALSE (with errno) on failure.
 */
 
 static BOOL
-internal_transport_write_message(int fd, transport_ctx * tctx, int size_limit)
+internal_transport_write_message(transport_ctx * tctx, int size_limit)
 {
-int len;
+int len, size = 0;
 
 /* Initialize pointer in output buffer. */
 
-chunk_ptr = deliver_out_buffer;
+transport_write_reset(tctx->options);
 
 /* Set up the data for start-of-line data checking and escaping */
 
-nl_partial_match = -1;
 if (tctx->check_string && tctx->escape_string)
   {
   nl_check = tctx->check_string;
@@ -869,8 +921,6 @@ if (tctx->check_string && tctx->escape_string)
   nl_escape = tctx->escape_string;
   nl_escape_length = Ustrlen(nl_escape);
   }
-else
-  nl_check_length = nl_escape_length = 0;
 
 /* Whether the escaping mechanism is applied to headers or not is controlled by
 an option (set for SMTP, not otherwise). Negate the length if not wanted till
@@ -880,10 +930,14 @@ if (!(tctx->options & topt_escape_headers))
   nl_check_length = -nl_check_length;
 
 /* Write the headers if required, including any that have to be added. If there
-are header rewriting rules, apply them. */
+are header rewriting rules, apply them.  The datasource is not the -D spoolfile
+so temporarily hide the global that adjusts for its format. */
 
 if (!(tctx->options & topt_no_headers))
   {
+  BOOL save_wireformat = spool_file_wireformat;
+  spool_file_wireformat = FALSE;
+
   /* Add return-path: if requested. */
 
   if (tctx->options & topt_add_return_path)
@@ -891,7 +945,7 @@ if (!(tctx->options & topt_no_headers))
     uschar buffer[ADDRESS_MAXLENGTH + 20];
     int n = sprintf(CS buffer, "Return-path: <%.*s>\n", ADDRESS_MAXLENGTH,
       return_path);
-    if (!write_chunk(fd, tctx, buffer, n)) return FALSE;
+    if (!write_chunk(tctx, buffer, n)) goto bad;
     }
 
   /* Add envelope-to: if requested */
@@ -904,19 +958,18 @@ if (!(tctx->options & topt_no_headers))
     struct aci *dlist = NULL;
     void *reset_point = store_get(0);
 
-    if (!write_chunk(fd, tctx, US"Envelope-to: ", 13)) return FALSE;
+    if (!write_chunk(tctx, US"Envelope-to: ", 13)) goto bad;
 
     /* Pick up from all the addresses. The plist and dlist variables are
     anchors for lists of addresses already handled; they have to be defined at
     this level because write_env_to() calls itself recursively. */
 
     for (p = tctx->addr; p; p = p->next)
-      if (!write_env_to(p, &plist, &dlist, &first, fd, tctx))
-       return FALSE;
+      if (!write_env_to(p, &plist, &dlist, &first, tctx)) goto bad;
 
     /* Add a final newline and reset the store used for tracking duplicates */
 
-    if (!write_chunk(fd, tctx, US"\n", 1)) return FALSE;
+    if (!write_chunk(tctx, US"\n", 1)) goto bad;
     store_reset(reset_point);
     }
 
@@ -924,9 +977,11 @@ if (!(tctx->options & topt_no_headers))
 
   if (tctx->options & topt_add_delivery_date)
     {
-    uschar buffer[100];
-    int n = sprintf(CS buffer, "Delivery-date: %s\n", tod_stamp(tod_full));
-    if (!write_chunk(fd, tctx, buffer, n)) return FALSE;
+    uschar * s = tod_stamp(tod_full);
+
+    if (  !write_chunk(tctx, US"Delivery-date: ", 15)
+       || !write_chunk(tctx, s, Ustrlen(s))
+       || !write_chunk(tctx, US"\n", 1)) goto bad;
     }
 
   /* Then the message's headers. Don't write any that are flagged as "old";
@@ -935,8 +990,14 @@ if (!(tctx->options & topt_no_headers))
   match any entries therein. Then check addr->prop.remove_headers too, provided that
   addr is not NULL. */
 
-  if (!transport_headers_send(fd, tctx, &write_chunk))
+  if (!transport_headers_send(tctx, &write_chunk))
+    {
+bad:
+    spool_file_wireformat = save_wireformat;
     return FALSE;
+    }
+
+  spool_file_wireformat = save_wireformat;
   }
 
 /* When doing RFC3030 CHUNKING output, work out how much data would be in a
@@ -954,7 +1015,7 @@ suboptimal. */
 if (tctx->options & topt_use_bdat)
   {
   off_t fsize;
-  int hsize, size = 0;
+  int hsize;
 
   if ((hsize = chunk_ptr - deliver_out_buffer) < 0)
     hsize = 0;
@@ -965,8 +1026,11 @@ if (tctx->options & topt_use_bdat)
     if (size_limit > 0  &&  fsize > size_limit)
       fsize = size_limit;
     size = hsize + fsize;
-    if (tctx->options & topt_use_crlf)
+    if (tctx->options & topt_use_crlf  &&  !spool_file_wireformat)
       size += body_linecount;  /* account for CRLF-expansion */
+
+    /* With topt_use_bdat we never do dot-stuffing; no need to
+    account for any expansion due to that. */
     }
 
   /* If the message is large, emit first a non-LAST chunk with just the
@@ -979,20 +1043,20 @@ if (tctx->options & topt_use_bdat)
     {
     DEBUG(D_transport)
       debug_printf("sending small initial BDAT; hsize=%d\n", hsize);
-    if (  tctx->chunk_cb(fd, tctx, hsize, 0) != OK
-       || !transport_write_block(fd, deliver_out_buffer, hsize)
-       || tctx->chunk_cb(fd, tctx, 0, tc_reap_prev) != OK
+    if (  tctx->chunk_cb(tctx, hsize, 0) != OK
+       || !transport_write_block(tctx, deliver_out_buffer, hsize, FALSE)
+       || tctx->chunk_cb(tctx, 0, tc_reap_prev) != OK
        )
       return FALSE;
     chunk_ptr = deliver_out_buffer;
     size -= hsize;
     }
 
-  /* Emit a LAST datachunk command. */
+  /* Emit a LAST datachunk command, and unmark the context for further
+  BDAT commands. */
 
-  if (tctx->chunk_cb(fd, tctx, size, tc_chunk_last) != OK)
+  if (tctx->chunk_cb(tctx, size, tc_chunk_last) != OK)
     return FALSE;
-
   tctx->options &= ~topt_use_bdat;
   }
 
@@ -1002,6 +1066,52 @@ negative in cases where it isn't to apply to the headers). Then ensure the body
 is positioned at the start of its file (following the message id), then write
 it, applying the size limit if required. */
 
+/* If we have a wireformat -D file (CRNL lines, non-dotstuffed, no ending dot)
+and we want to send a body without dotstuffing or ending-dot, in-clear,
+then we can just dump it using sendfile.
+This should get used for CHUNKING output and also for writing the -K file for
+dkim signing,  when we had CHUNKING input.  */
+
+#ifdef OS_SENDFILE
+if (  spool_file_wireformat
+   && !(tctx->options & (topt_no_body | topt_end_dot))
+   && !nl_check_length
+   && tls_out.active != tctx->u.fd
+   )
+  {
+  ssize_t copied = 0;
+  off_t offset = SPOOL_DATA_START_OFFSET;
+
+  /* Write out any header data in the buffer */
+
+  if ((len = chunk_ptr - deliver_out_buffer) > 0)
+    {
+    if (!transport_write_block(tctx, deliver_out_buffer, len, TRUE))
+      return FALSE;
+    size -= len;
+    }
+
+  DEBUG(D_transport) debug_printf("using sendfile for body\n");
+
+  while(size > 0)
+    {
+    if ((copied = os_sendfile(tctx->u.fd, deliver_datafile, &offset, size)) <= 0) break;
+    size -= copied;
+    }
+  return copied >= 0;
+  }
+#else
+DEBUG(D_transport) debug_printf("cannot use sendfile for body: no support\n");
+#endif
+
+DEBUG(D_transport)
+  if (!(tctx->options & topt_no_body))
+    debug_printf("cannot use sendfile for body: %s\n",
+      !spool_file_wireformat ? "spoolfile not wireformat"
+      : tctx->options & topt_end_dot ? "terminating dot wanted"
+      : nl_check_length ? "dot- or From-stuffing wanted"
+      : "TLS output wanted");
+
 if (!(tctx->options & topt_no_body))
   {
   int size = size_limit;
@@ -1013,7 +1123,7 @@ if (!(tctx->options & topt_no_body))
   while (  (len = MAX(DELIVER_IN_BUFFER_SIZE, size)) > 0
        && (len = read(deliver_datafile, deliver_in_buffer, len)) > 0)
     {
-    if (!write_chunk(fd, tctx, deliver_in_buffer, len))
+    if (!write_chunk(tctx, deliver_in_buffer, len))
       return FALSE;
     size -= len;
     }
@@ -1029,202 +1139,15 @@ nl_check_length = nl_escape_length = 0;
 
 /* If requested, add a terminating "." line (SMTP output). */
 
-if (tctx->options & topt_end_dot && !write_chunk(fd, tctx, US".\n", 2))
+if (tctx->options & topt_end_dot && !write_chunk(tctx, US".\n", 2))
   return FALSE;
 
 /* Write out any remaining data in the buffer before returning. */
 
 return (len = chunk_ptr - deliver_out_buffer) <= 0 ||
-  transport_write_block(fd, deliver_out_buffer, len);
-}
-
-
-#ifndef DISABLE_DKIM
-
-/***************************************************************************************************
-*    External interface to write the message, while signing it with DKIM and/or Domainkeys         *
-***************************************************************************************************/
-
-/* This function is a wrapper around transport_write_message().
-   It is only called from the smtp transport if DKIM or Domainkeys support
-   is compiled in.  The function sets up a replacement fd into a -K file,
-   then calls the normal function. This way, the exact bits that exim would
-   have put "on the wire" will end up in the file (except for TLS
-   encapsulation, which is the very very last thing). When we are done
-   signing the file, send the signed message down the original fd (or TLS fd).
-
-Arguments:
-  as for internal_transport_write_message() above, with additional arguments
-  for DKIM.
-
-Returns:       TRUE on success; FALSE (with errno) for any failure
-*/
-
-BOOL
-dkim_transport_write_message(int out_fd, transport_ctx * tctx,
-  struct ob_dkim * dkim, const uschar ** err)
-{
-int dkim_fd;
-int save_errno = 0;
-BOOL rc;
-uschar * dkim_spool_name;
-uschar * dkim_signature = NULL;
-int sread = 0, wwritten = 0, siglen = 0, options;
-off_t k_file_size;
-const uschar * errstr;
-
-/* If we can't sign, just call the original function. */
-
-if (!(dkim->dkim_private_key && dkim->dkim_domain && dkim->dkim_selector))
-  return transport_write_message(out_fd, tctx, 0);
-
-dkim_spool_name = spool_fname(US"input", message_subdir, message_id,
-                   string_sprintf("-%d-K", (int)getpid()));
-
-if ((dkim_fd = Uopen(dkim_spool_name, O_RDWR|O_CREAT|O_TRUNC, SPOOL_MODE)) < 0)
-  {
-  /* Can't create spool file. Ugh. */
-  rc = FALSE;
-  save_errno = errno;
-  *err = string_sprintf("dkim spoolfile create: %s", strerror(errno));
-  goto CLEANUP;
-  }
-
-/* Call original function to write the -K file; does the CRLF expansion
-(but, in the CHUNKING case, not dot-stuffing and dot-termination). */
-
-options = tctx->options;
-tctx->options &= ~topt_use_bdat;
-rc = transport_write_message(dkim_fd, tctx, 0);
-tctx->options = options;
-
-/* Save error state. We must clean up before returning. */
-if (!rc)
-  {
-  save_errno = errno;
-  goto CLEANUP;
-  }
-
-/* Rewind file and feed it to the goats^W DKIM lib */
-dkim->dot_stuffed = !!(options & topt_end_dot);
-lseek(dkim_fd, 0, SEEK_SET);
-if ((dkim_signature = dkim_exim_sign(dkim_fd, dkim, &errstr)))
-  siglen = Ustrlen(dkim_signature);
-else if (dkim->dkim_strict)
-  {
-  uschar *dkim_strict_result = expand_string(dkim->dkim_strict);
-  if (dkim_strict_result)
-    if ( (strcmpic(dkim->dkim_strict,US"1") == 0) ||
-        (strcmpic(dkim->dkim_strict,US"true") == 0) )
-      {
-      /* Set errno to something halfway meaningful */
-      save_errno = EACCES;
-      log_write(0, LOG_MAIN, "DKIM: message could not be signed,"
-       " and dkim_strict is set. Deferring message delivery.");
-      *err = errstr;
-      rc = FALSE;
-      goto CLEANUP;
-      }
-  }
-
-#ifndef HAVE_LINUX_SENDFILE
-if (options & topt_use_bdat)
-#endif
-  k_file_size = lseek(dkim_fd, 0, SEEK_END); /* Fetch file size */
-
-if (options & topt_use_bdat)
-  {
-
-  /* On big messages output a precursor chunk to get any pipelined
-  MAIL & RCPT commands flushed, then reap the responses so we can
-  error out on RCPT rejects before sending megabytes. */
-
-  if (siglen + k_file_size > DELIVER_OUT_BUFFER_SIZE && siglen > 0)
-    {
-    if (  tctx->chunk_cb(out_fd, tctx, siglen, 0) != OK
-       || !transport_write_block(out_fd, dkim_signature, siglen)
-       || tctx->chunk_cb(out_fd, tctx, 0, tc_reap_prev) != OK
-       )
-      goto err;
-    siglen = 0;
-    }
-
-  if (tctx->chunk_cb(out_fd, tctx, siglen + k_file_size, tc_chunk_last) != OK)
-    goto err;
-  }
-
-if(siglen > 0 && !transport_write_block(out_fd, dkim_signature, siglen))
-  goto err;
-
-#ifdef HAVE_LINUX_SENDFILE
-/* We can use sendfile() to shove the file contents
-   to the socket. However only if we don't use TLS,
-   as then there's another layer of indirection
-   before the data finally hits the socket. */
-if (tls_out.active != out_fd)
-  {
-  ssize_t copied = 0;
-  off_t offset = 0;
-
-  /* Rewind file */
-  lseek(dkim_fd, 0, SEEK_SET);
-
-  while(copied >= 0 && offset < k_file_size)
-    copied = sendfile(out_fd, dkim_fd, &offset, k_file_size - offset);
-  if (copied < 0)
-    goto err;
-  }
-else
-
-#endif
-
-  {
-  /* Rewind file */
-  lseek(dkim_fd, 0, SEEK_SET);
-
-  /* Send file down the original fd */
-  while((sread = read(dkim_fd, deliver_out_buffer, DELIVER_OUT_BUFFER_SIZE)) >0)
-    {
-    uschar * p = deliver_out_buffer;
-    /* write the chunk */
-
-    while (sread)
-      {
-#ifdef SUPPORT_TLS
-      wwritten = tls_out.active == out_fd
-       ? tls_write(FALSE, p, sread)
-       : write(out_fd, CS p, sread);
-#else
-      wwritten = write(out_fd, CS p, sread);
-#endif
-      if (wwritten == -1)
-       goto err;
-      p += wwritten;
-      sread -= wwritten;
-      }
-    }
-
-  if (sread == -1)
-    {
-    save_errno = errno;
-    rc = FALSE;
-    }
-  }
-
-CLEANUP:
-  /* unlink -K file */
-  (void)close(dkim_fd);
-  Uunlink(dkim_spool_name);
-  errno = save_errno;
-  return rc;
-
-err:
-  save_errno = errno;
-  rc = FALSE;
-  goto CLEANUP;
+  transport_write_block(tctx, deliver_out_buffer, len, FALSE);
 }
 
-#endif
 
 
 
@@ -1236,9 +1159,9 @@ err:
 the real work, passing over all the arguments from this function. Otherwise,
 set up a filtering process, fork another process to call the internal function
 to write to the filter, and in this process just suck from the filter and write
-down the given fd. At the end, tidy up the pipes and the processes.
+down the fd in the transport context. At the end, tidy up the pipes and the
+processes.
 
-XXX
 Arguments:     as for internal_transport_write_message() above
 
 Returns:       TRUE on success; FALSE (with errno) for any failure
@@ -1246,15 +1169,13 @@ Returns:       TRUE on success; FALSE (with errno) for any failure
 */
 
 BOOL
-transport_write_message(int fd, transport_ctx * tctx, int size_limit)
+transport_write_message(transport_ctx * tctx, int size_limit)
 {
 BOOL last_filter_was_NL = TRUE;
+BOOL save_spool_file_wireformat = spool_file_wireformat;
 int rc, len, yield, fd_read, fd_write, save_errno;
 int pfd[2] = {-1, -1};
 pid_t filter_pid, write_pid;
-static transport_ctx dummy_tctx = {0};
-
-if (!tctx) tctx = &dummy_tctx;
 
 transport_filter_timed_out = FALSE;
 
@@ -1265,7 +1186,7 @@ if (  !transport_filter_argv
    || !*transport_filter_argv
    || !**transport_filter_argv
    )
-  return internal_transport_write_message(fd, tctx, size_limit);
+  return internal_transport_write_message(tctx, size_limit);
 
 /* Otherwise the message must be written to a filter process and read back
 before being written to the incoming fd. First set up the special processing to
@@ -1295,11 +1216,11 @@ yield = FALSE;
 write_pid = (pid_t)(-1);
 
   {
-  int bits = fcntl(fd, F_GETFD);
-  (void)fcntl(fd, F_SETFD, bits | FD_CLOEXEC);
+  int bits = fcntl(tctx->u.fd, F_GETFD);
+  (void)fcntl(tctx->u.fd, F_SETFD, bits | FD_CLOEXEC);
   filter_pid = child_open(USS transport_filter_argv, NULL, 077,
    &fd_write, &fd_read, FALSE);
-  (void)fcntl(fd, F_SETFD, bits & ~FD_CLOEXEC);
+  (void)fcntl(tctx->u.fd, F_SETFD, bits & ~FD_CLOEXEC);
   }
 if (filter_pid < 0) goto TIDY_UP;      /* errno set */
 
@@ -1319,10 +1240,11 @@ if ((write_pid = fork()) == 0)
   (void)close(pfd[pipe_read]);
   nl_check_length = nl_escape_length = 0;
 
+  tctx->u.fd = fd_write;
   tctx->check_string = tctx->escape_string = NULL;
   tctx->options &= ~(topt_use_crlf | topt_end_dot | topt_use_bdat);
 
-  rc = internal_transport_write_message(fd_write, tctx, size_limit);
+  rc = internal_transport_write_message(tctx, size_limit);
 
   save_errno = errno;
   if (  write(pfd[pipe_write], (void *)&rc, sizeof(BOOL))
@@ -1331,6 +1253,8 @@ if ((write_pid = fork()) == 0)
         != sizeof(int)
      || write(pfd[pipe_write], (void *)&tctx->addr->more_errno, sizeof(int))
         != sizeof(int)
+     || write(pfd[pipe_write], (void *)&tctx->addr->delivery_usec, sizeof(int))
+        != sizeof(int)
      )
     rc = FALSE;        /* compiler quietening */
   _exit(0);
@@ -1367,8 +1291,10 @@ DEBUG(D_transport) debug_printf("copying from the filter\n");
 
 /* Copy the output of the filter, remembering if the last character was NL. If
 no data is returned, that counts as "ended with NL" (default setting of the
-variable is TRUE). */
+variable is TRUE).  The output should always be unix-format as we converted
+any wireformat source on writing input to the filter. */
 
+spool_file_wireformat = FALSE;
 chunk_ptr = deliver_out_buffer;
 
 for (;;)
@@ -1389,7 +1315,7 @@ for (;;)
 
   if (len > 0)
     {
-    if (!write_chunk(fd, tctx, deliver_in_buffer, len)) goto TIDY_UP;
+    if (!write_chunk(tctx, deliver_in_buffer, len)) goto TIDY_UP;
     last_filter_was_NL = (deliver_in_buffer[len-1] == '\n');
     }
 
@@ -1408,6 +1334,7 @@ there has been an error, kill the processes before waiting for them, just to be
 sure. Also apply a paranoia timeout. */
 
 TIDY_UP:
+spool_file_wireformat = save_spool_file_wireformat;
 save_errno = errno;
 
 (void)close(fd_read);
@@ -1452,7 +1379,9 @@ if (write_pid > 0)
       else if (!ok)
         {
        int dummy = read(pfd[pipe_read], (void *)&save_errno, sizeof(int));
-        dummy = read(pfd[pipe_read], (void *)&(tctx->addr->more_errno), sizeof(int));
+        dummy = read(pfd[pipe_read], (void *)&tctx->addr->more_errno, sizeof(int));
+        dummy = read(pfd[pipe_read], (void *)&tctx->addr->delivery_usec, sizeof(int));
+       dummy = dummy;          /* compiler quietening */
         yield = FALSE;
         }
       }
@@ -1475,8 +1404,8 @@ if (yield)
   nl_check_length = nl_escape_length = 0;
   if (  tctx->options & topt_end_dot
      && ( last_filter_was_NL
-        ? !write_chunk(fd, tctx, US".\n", 2)
-       : !write_chunk(fd, tctx, US"\n.\n", 3)
+        ? !write_chunk(tctx, US".\n", 2)
+       : !write_chunk(tctx, US"\n.\n", 3)
      )  )
     yield = FALSE;
 
@@ -1484,7 +1413,7 @@ if (yield)
 
   else
     yield = (len = chunk_ptr - deliver_out_buffer) <= 0
-         || transport_write_block(fd, deliver_out_buffer, len);
+         || transport_write_block(tctx, deliver_out_buffer, len, FALSE);
   }
 else
   errno = save_errno;      /* From some earlier error */
@@ -1541,7 +1470,6 @@ Returns:    nothing
 void
 transport_update_waiting(host_item *hostlist, uschar *tpname)
 {
-uschar buffer[256];
 const uschar *prevname = US"";
 host_item *host;
 open_db dbblock;
@@ -1551,19 +1479,20 @@ DEBUG(D_transport) debug_printf("updating wait-%s database\n", tpname);
 
 /* Open the database for this transport */
 
-sprintf(CS buffer, "wait-%.200s", tpname);
-dbm_file = dbfn_open(buffer, O_RDWR, &dbblock, TRUE);
-if (dbm_file == NULL) return;
+if (!(dbm_file = dbfn_open(string_sprintf("wait-%.200s", tpname),
+                     O_RDWR, &dbblock, TRUE)))
+  return;
 
 /* Scan the list of hosts for which this message is waiting, and ensure
 that the message id is in each host record. */
 
-for (host = hostlist; host!= NULL; host = host->next)
+for (host = hostlist; host; host = host->next)
   {
   BOOL already = FALSE;
   dbdata_wait *host_record;
   uschar *s;
   int i, host_length;
+  uschar buffer[256];
 
   /* Skip if this is the same host as we just processed; otherwise remember
   the name for next time. */
@@ -1573,8 +1502,7 @@ for (host = hostlist; host!= NULL; host = host->next)
 
   /* Look up the host record; if there isn't one, make an empty one. */
 
-  host_record = dbfn_read(dbm_file, host->name);
-  if (host_record == NULL)
+  if (!(host_record = dbfn_read(dbm_file, host->name)))
     {
     host_record = store_get(sizeof(dbdata_wait) + MESSAGE_ID_LENGTH);
     host_record->count = host_record->sequence = 0;
@@ -1588,10 +1516,8 @@ for (host = hostlist; host!= NULL; host = host->next)
 
   for (s = host_record->text; s < host_record->text + host_length;
        s += MESSAGE_ID_LENGTH)
-    {
     if (Ustrncmp(s, message_id, MESSAGE_ID_LENGTH) == 0)
       { already = TRUE; break; }
-    }
 
   /* If we haven't found this message in the main record, search any
   continuation records that exist. */
@@ -1600,15 +1526,12 @@ for (host = hostlist; host!= NULL; host = host->next)
     {
     dbdata_wait *cont;
     sprintf(CS buffer, "%.200s:%d", host->name, i);
-    cont = dbfn_read(dbm_file, buffer);
-    if (cont != NULL)
+    if ((cont = dbfn_read(dbm_file, buffer)))
       {
       int clen = cont->count * MESSAGE_ID_LENGTH;
       for (s = cont->text; s < cont->text + clen; s += MESSAGE_ID_LENGTH)
-        {
         if (Ustrncmp(s, message_id, MESSAGE_ID_LENGTH) == 0)
           { already = TRUE; break; }
-        }
       }
     }
 
@@ -1704,7 +1627,6 @@ dbdata_wait *host_record;
 int host_length;
 open_db dbblock;
 open_db *dbm_file;
-uschar buffer[256];
 
 int         i;
 struct stat statbuf;
@@ -1731,9 +1653,9 @@ if (local_message_max > 0 && continue_sequence >= local_message_max)
 
 /* Open the waiting information database. */
 
-sprintf(CS buffer, "wait-%.200s", transport_name);
-dbm_file = dbfn_open(buffer, O_RDWR, &dbblock, TRUE);
-if (dbm_file == NULL) return FALSE;
+if (!(dbm_file = dbfn_open(string_sprintf("wait-%.200s", transport_name),
+                         O_RDWR, &dbblock, TRUE)))
+  return FALSE;
 
 /* See if there is a record for this host; if not, there's nothing to do. */
 
@@ -1849,13 +1771,13 @@ while (1)
       }
     }
 
-/* Jeremy: check for a continuation record, this code I do not know how to
-test but the code should work */
+  /* Check for a continuation record. */
 
   while (host_length <= 0)
     {
     int i;
     dbdata_wait * newr = NULL;
+    uschar buffer[256];
 
     /* Search for a continuation */
 
@@ -1934,6 +1856,70 @@ return TRUE;
 *    Deliver waiting message down same socket    *
 *************************************************/
 
+/* Just the regain-root-privilege exec portion */
+void
+transport_do_pass_socket(const uschar *transport_name, const uschar *hostname,
+  const uschar *hostaddress, uschar *id, int socket_fd)
+{
+int i = 20;
+const uschar **argv;
+
+/* Set up the calling arguments; use the standard function for the basics,
+but we have a number of extras that may be added. */
+
+argv = CUSS child_exec_exim(CEE_RETURN_ARGV, TRUE, &i, FALSE, 0);
+
+if (smtp_authenticated)                                argv[i++] = US"-MCA";
+if (smtp_peer_options & OPTION_CHUNKING)       argv[i++] = US"-MCK";
+if (smtp_peer_options & OPTION_DSN)            argv[i++] = US"-MCD";
+if (smtp_peer_options & OPTION_PIPE)           argv[i++] = US"-MCP";
+if (smtp_peer_options & OPTION_SIZE)           argv[i++] = US"-MCS";
+#ifdef SUPPORT_TLS
+if (smtp_peer_options & OPTION_TLS)
+  if (tls_out.active >= 0 || continue_proxy_cipher)
+    {
+    argv[i++] = US"-MCt";
+    argv[i++] = sending_ip_address;
+    argv[i++] = string_sprintf("%d", sending_port);
+    argv[i++] = tls_out.active >= 0 ? tls_out.cipher : continue_proxy_cipher;
+    }
+  else
+    argv[i++] = US"-MCT";
+#endif
+
+if (queue_run_pid != (pid_t)0)
+  {
+  argv[i++] = US"-MCQ";
+  argv[i++] = string_sprintf("%d", queue_run_pid);
+  argv[i++] = string_sprintf("%d", queue_run_pipe);
+  }
+
+argv[i++] = US"-MC";
+argv[i++] = US transport_name;
+argv[i++] = US hostname;
+argv[i++] = US hostaddress;
+argv[i++] = string_sprintf("%d", continue_sequence + 1);
+argv[i++] = id;
+argv[i++] = NULL;
+
+/* Arrange for the channel to be on stdin. */
+
+if (socket_fd != 0)
+  {
+  (void)dup2(socket_fd, 0);
+  (void)close(socket_fd);
+  }
+
+DEBUG(D_exec) debug_print_argv(argv);
+exim_nullstd();                          /* Ensure std{out,err} exist */
+execv(CS argv[0], (char *const *)argv);
+
+DEBUG(D_any) debug_printf("execv failed: %s\n", strerror(errno));
+_exit(errno);         /* Note: must be _exit(), NOT exit() */
+}
+
+
+
 /* Fork a new exim process to deliver the message, and do a re-exec, both to
 get a clean delivery process, and to regain root privilege in cases where it
 has been given away.
@@ -1959,69 +1945,20 @@ DEBUG(D_transport) debug_printf("transport_pass_socket entered\n");
 
 if ((pid = fork()) == 0)
   {
-  int i = 19;
-  const uschar **argv;
-
   /* Disconnect entirely from the parent process. If we are running in the
   test harness, wait for a bit to allow the previous process time to finish,
   write the log, etc., so that the output is always in the same order for
   automatic comparison. */
 
-  if ((pid = fork()) != 0) _exit(EXIT_SUCCESS);
-  if (running_in_test_harness) sleep(1);
-
-  /* Set up the calling arguments; use the standard function for the basics,
-  but we have a number of extras that may be added. */
-
-  argv = CUSS child_exec_exim(CEE_RETURN_ARGV, TRUE, &i, FALSE, 0);
-
-  if (smtp_authenticated) argv[i++] = US"-MCA";
-
-  if (smtp_peer_options & PEER_OFFERED_CHUNKING) argv[i++] = US"-MCK";
-  if (smtp_peer_options & PEER_OFFERED_DSN) argv[i++] = US"-MCD";
-  if (smtp_peer_options & PEER_OFFERED_PIPE) argv[i++] = US"-MCP";
-  if (smtp_peer_options & PEER_OFFERED_SIZE) argv[i++] = US"-MCS";
-#ifdef SUPPORT_TLS
-  if (smtp_peer_options & PEER_OFFERED_TLS)
-    if (tls_out.active >= 0 || continue_proxy)
-      {
-      argv[i++] = US"-MCt";
-      argv[i++] = sending_ip_address;
-      argv[i++] = string_sprintf("%d", sending_port);
-      }
-    else
-      argv[i++] = US"-MCT";
-#endif
-
-  if (queue_run_pid != (pid_t)0)
+  if ((pid = fork()) != 0)
     {
-    argv[i++] = US"-MCQ";
-    argv[i++] = string_sprintf("%d", queue_run_pid);
-    argv[i++] = string_sprintf("%d", queue_run_pipe);
+    DEBUG(D_transport) debug_printf("transport_pass_socket succeeded (final-pid %d)\n", pid);
+    _exit(EXIT_SUCCESS);
     }
+  if (running_in_test_harness) sleep(1);
 
-  argv[i++] = US"-MC";
-  argv[i++] = US transport_name;
-  argv[i++] = US hostname;
-  argv[i++] = US hostaddress;
-  argv[i++] = string_sprintf("%d", continue_sequence + 1);
-  argv[i++] = id;
-  argv[i++] = NULL;
-
-  /* Arrange for the channel to be on stdin. */
-
-  if (socket_fd != 0)
-    {
-    (void)dup2(socket_fd, 0);
-    (void)close(socket_fd);
-    }
-
-  DEBUG(D_exec) debug_print_argv(argv);
-  exim_nullstd();                          /* Ensure std{out,err} exist */
-  execv(CS argv[0], (char *const *)argv);
-
-  DEBUG(D_any) debug_printf("execv failed: %s\n", strerror(errno));
-  _exit(errno);         /* Note: must be _exit(), NOT exit() */
+  transport_do_pass_socket(transport_name, hostname, hostaddress,
+    id, socket_fd);
   }
 
 /* If the process creation succeeded, wait for the first-level child, which
@@ -2032,7 +1969,7 @@ if (pid > 0)
   {
   int rc;
   while ((rc = wait(&status)) != pid && (rc >= 0 || errno != ECHILD));
-  DEBUG(D_transport) debug_printf("transport_pass_socket succeeded\n");
+  DEBUG(D_transport) debug_printf("transport_pass_socket succeeded (inter-pid %d)\n", pid);
   return TRUE;
   }
 else
@@ -2114,7 +2051,7 @@ while (*s != 0 && argcount < max_args)
   while (isspace(*s)) s++;
   }
 
-argv[argcount] = (uschar *)0;
+argv[argcount] = US 0;
 
 /* If *s != 0 we have run out of argument slots. */
 
@@ -2150,7 +2087,7 @@ $recipients. */
 DEBUG(D_transport)
   {
   debug_printf("direct command:\n");
-  for (i = 0; argv[i] != (uschar *)0; i++)
+  for (i = 0; argv[i] != US 0; i++)
     debug_printf("  argv[%d] = %s\n", i, string_printing(argv[i]));
   }
 
@@ -2160,7 +2097,7 @@ if (expand_arguments)
     addr->parent != NULL &&
     Ustrcmp(addr->parent->address, "system-filter") == 0;
 
-  for (i = 0; argv[i] != (uschar *)0; i++)
+  for (i = 0; argv[i] != US 0; i++)
     {
 
     /* Handle special fudge for passing an address list */
@@ -2244,7 +2181,7 @@ if (expand_arguments)
         while (isspace(*s)) s++; /* strip space after arg */
         }
 
-      address_pipe_argv[address_pipe_argcount] = (uschar *)0;
+      address_pipe_argv[address_pipe_argcount] = US 0;
 
       /* If *s != 0 we have run out of argument slots. */
       if (*s != 0)
@@ -2292,7 +2229,7 @@ if (expand_arguments)
        * [argv 0][argv 1][argv 2=pipeargv[0]][argv 3=pipeargv[1]][old argv 3][0]
        */
       for (address_pipe_i = 0;
-           address_pipe_argv[address_pipe_i] != (uschar *)0;
+           address_pipe_argv[address_pipe_i] != US 0;
            address_pipe_i++)
         {
         argv[i++] = address_pipe_argv[address_pipe_i];
@@ -2333,7 +2270,7 @@ if (expand_arguments)
   DEBUG(D_transport)
     {
     debug_printf("direct command after expansion:\n");
-    for (i = 0; argv[i] != (uschar *)0; i++)
+    for (i = 0; argv[i] != US 0; i++)
       debug_printf("  argv[%d] = %s\n", i, string_printing(argv[i]));
     }
   }
@@ -2341,6 +2278,7 @@ if (expand_arguments)
 return TRUE;
 }
 
+#endif /*!MACRO_PREDEF*/
 /* vi: aw ai sw=2
 */
 /* End of transport.c */
index 9b3379be2dbe0412dafa2ce16f167c97f6570eeb..3b463c644bf326551f1c009ac43863c029c8d000 100644 (file)
 #endif
 
 
-/* Encodings for mailbox formats, and their names. MBX format is actually
-supported only if SUPPORT_MBX is set. */
-
-enum { mbf_unix, mbf_mbx, mbf_smail, mbf_maildir, mbf_mailstore };
-
-static const char *mailbox_formats[] = {
-  "unix", "mbx", "smail", "maildir", "mailstore" };
-
-
-/* Check warn threshold only if quota size set or not a percentage threshold
-   percentage check should only be done if quota > 0 */
-
-#define THRESHOLD_CHECK  (ob->quota_warn_threshold_value > 0 && \
-  (!ob->quota_warn_threshold_is_percent || ob->quota_value > 0))
-
-
 /* Options specific to the appendfile transport. They must be in alphabetic
 order (note that "_" comes before the lower case letters). Some of them are
 stored in the publicly visible instance block - these are flagged with the
@@ -170,6 +154,16 @@ address can appear in the tables drtables.c. */
 int appendfile_transport_options_count =
   sizeof(appendfile_transport_options)/sizeof(optionlist);
 
+
+#ifdef MACRO_PREDEF
+
+/* Dummy values */
+appendfile_transport_options_block appendfile_transport_option_defaults = {0};
+void appendfile_transport_init(transport_instance *tblock) {}
+BOOL appendfile_transport_entry(transport_instance *tblock, address_item *addr) {return FALSE;}
+
+#else  /*!MACRO_PREDEF*/
+
 /* Default private options block for the appendfile transport. */
 
 appendfile_transport_options_block appendfile_transport_option_defaults = {
@@ -234,10 +228,28 @@ appendfile_transport_options_block appendfile_transport_option_defaults = {
   FALSE,          /* mailstore_format */
   FALSE,          /* mbx_format */
   FALSE,          /* quota_warn_threshold_is_percent */
-  TRUE            /* quota_is_inclusive */
+  TRUE,           /* quota_is_inclusive */
+  FALSE,          /* quota_no_check */
+  FALSE           /* quota_filecount_no_check */
 };
 
 
+/* Encodings for mailbox formats, and their names. MBX format is actually
+supported only if SUPPORT_MBX is set. */
+
+enum { mbf_unix, mbf_mbx, mbf_smail, mbf_maildir, mbf_mailstore };
+
+static const char *mailbox_formats[] = {
+  "unix", "mbx", "smail", "maildir", "mailstore" };
+
+
+/* Check warn threshold only if quota size set or not a percentage threshold
+   percentage check should only be done if quota > 0 */
+
+#define THRESHOLD_CHECK  (ob->quota_warn_threshold_value > 0 && \
+  (!ob->quota_warn_threshold_is_percent || ob->quota_value > 0))
+
+
 
 /*************************************************
 *              Setup entry point                 *
@@ -285,9 +297,11 @@ mailbox_filecount */
 for (i = 0; i < 5; i++)
   {
   double d;
+  int no_check = 0;
   uschar *which = NULL;
 
-  if (q == NULL) d = default_value; else
+  if (q == NULL) d = default_value;
+  else
     {
     uschar *rest;
     uschar *s = expand_string(q);
@@ -321,6 +335,15 @@ for (i = 0; i < 5; i++)
       rest++;
       }
 
+
+    /* For quota and quota_filecount there may be options
+    appended. Currently only "no_check", so we can be lazy parsing it */
+    if (i < 2 && Ustrstr(rest, "/no_check") == rest)
+      {
+        no_check = 1;
+        rest += sizeof("/no_check") - 1;
+      }
+
     while (isspace(*rest)) rest++;
 
     if (*rest != 0)
@@ -338,12 +361,14 @@ for (i = 0; i < 5; i++)
     case 0:
     if (d >= 2.0*1024.0*1024.0*1024.0 && sizeof(off_t) <= 4) which = US"quota";
     ob->quota_value = (off_t)d;
+    ob->quota_no_check = no_check;
     q = ob->quota_filecount;
     break;
 
     case 1:
     if (d >= 2.0*1024.0*1024.0*1024.0) which = US"quota_filecount";
     ob->quota_filecount_value = (int)d;
+    ob->quota_filecount_no_check = no_check;
     q = ob->quota_warn_threshold;
     break;
 
@@ -630,7 +655,7 @@ for (h = &host; h; h = h->next)
 
   /* Connect never fails for a UDP socket, so don't set a timeout. */
 
-  (void)ip_connect(sock, host_af, h->address, ntohs(sp->s_port), 0, FALSE);
+  (void)ip_connect(sock, host_af, h->address, ntohs(sp->s_port), 0, NULL);
   rc = send(sock, buffer, Ustrlen(buffer) + 1, 0);
   (void)close(sock);
 
@@ -916,6 +941,9 @@ copy_mbx_message(int to_fd, int from_fd, off_t saved_size)
 int used;
 off_t size;
 struct stat statbuf;
+transport_ctx tctx = {{0}};
+
+tctx.u.fd = to_fd;
 
 /* If the current mailbox size is zero, write a header block */
 
@@ -928,7 +956,7 @@ if (saved_size == 0)
     (long int)time(NULL));
   for (i = 0; i < MBX_NUSERFLAGS; i++)
     sprintf (CS(s += Ustrlen(s)), "\015\012");
-  if (!transport_write_block (to_fd, deliver_out_buffer, MBX_HDRSIZE))
+  if (!transport_write_block (&tctx, deliver_out_buffer, MBX_HDRSIZE, FALSE))
     return DEFER;
   }
 
@@ -946,7 +974,7 @@ used = Ustrlen(deliver_out_buffer);
 
 /* Rewind the temporary file, and copy it over in chunks. */
 
-lseek(from_fd, 0 , SEEK_SET);
+if (lseek(from_fd, 0 , SEEK_SET) < 0) return DEFER;
 
 while (size > 0)
   {
@@ -957,7 +985,7 @@ while (size > 0)
     if (len == 0) errno = ERRNO_MBXLENGTH;
     return DEFER;
     }
-  if (!transport_write_block(to_fd, deliver_out_buffer, used + len))
+  if (!transport_write_block(&tctx, deliver_out_buffer, used + len, FALSE))
     return DEFER;
   size -= len;
   used = 0;
@@ -1380,10 +1408,13 @@ else
 DEBUG(D_transport)
   {
   debug_printf("appendfile: mode=%o notify_comsat=%d quota=" OFF_T_FMT
+    "%s%s"
     " warning=" OFF_T_FMT "%s\n"
     "  %s=%s format=%s\n  message_prefix=%s\n  message_suffix=%s\n  "
     "maildir_use_size_file=%s\n",
     mode, ob->notify_comsat, ob->quota_value,
+    ob->quota_no_check? " (no_check)" : "",
+    ob->quota_filecount_no_check? " (no_check_filecount)" : "",
     ob->quota_warn_threshold_value,
     ob->quota_warn_threshold_is_percent? "%" : "",
     isdirectory? "directory" : "file",
@@ -2774,21 +2805,33 @@ if (!disable_quota && ob->quota_value > 0)
     debug_printf("  file count quota = %d count = %d\n",
       ob->quota_filecount_value, mailbox_filecount);
     }
+
   if (mailbox_size + (ob->quota_is_inclusive? message_size:0) > ob->quota_value)
     {
-    DEBUG(D_transport) debug_printf("mailbox quota exceeded\n");
-    yield = DEFER;
-    errno = ERRNO_EXIMQUOTA;
-    }
-  else if (ob->quota_filecount_value > 0 &&
-           mailbox_filecount + (ob->quota_is_inclusive ? 1:0) >
-             ob->quota_filecount_value)
-    {
-    DEBUG(D_transport) debug_printf("mailbox file count quota exceeded\n");
-    yield = DEFER;
-    errno = ERRNO_EXIMQUOTA;
-    filecount_msg = US" filecount";
+
+      if (!ob->quota_no_check)
+        {
+        DEBUG(D_transport) debug_printf("mailbox quota exceeded\n");
+        yield = DEFER;
+        errno = ERRNO_EXIMQUOTA;
+        }
+      else DEBUG(D_transport) debug_printf("mailbox quota exceeded but ignored\n");
+
     }
+
+  if (ob->quota_filecount_value > 0
+           && mailbox_filecount + (ob->quota_is_inclusive ? 1:0) >
+              ob->quota_filecount_value)
+    if(!ob->quota_filecount_no_check)
+      {
+      DEBUG(D_transport) debug_printf("mailbox file count quota exceeded\n");
+      yield = DEFER;
+      errno = ERRNO_EXIMQUOTA;
+      filecount_msg = US" filecount";
+      }
+    else DEBUG(D_transport) if (ob->quota_filecount_no_check)
+      debug_printf("mailbox file count quota exceeded but ignored\n");
+
   }
 
 /* If we are writing in MBX format, what we actually do is to write the message
@@ -2874,13 +2917,14 @@ at initialization time. */
 if (yield == OK)
   {
   transport_ctx tctx = {
+    {fd},
     tblock,
     addr,
     ob->check_string,
     ob->escape_string,
     ob->options
   };
-  if (!transport_write_message(fd, &tctx, 0))
+  if (!transport_write_message(&tctx, 0))
     yield = DEFER;
   }
 
@@ -3373,4 +3417,5 @@ put in the first address of a batch. */
 return FALSE;
 }
 
+#endif /*!MACRO_PREDEF*/
 /* End of transport/appendfile.c */
index 52dc3bacadfda7cb120723054d0f557bfee17d7d..70330857d56834a1c37184009f7f7914b92c9098 100644 (file)
@@ -70,6 +70,8 @@ typedef struct {
   BOOL  mbx_format;
   BOOL  quota_warn_threshold_is_percent;
   BOOL  quota_is_inclusive;
+  BOOL  quota_no_check;
+  BOOL  quota_filecount_no_check;
 } appendfile_transport_options_block;
 
 /* Restricted creation options */
index f07cd83cf7e63ae63c9f34ae8090d348faa601f8..9f6e2acaf5501848e48af72c6106447b21bfb3ce 100644 (file)
@@ -62,6 +62,17 @@ address can appear in the tables drtables.c. */
 int autoreply_transport_options_count =
   sizeof(autoreply_transport_options)/sizeof(optionlist);
 
+
+#ifdef MACRO_PREDEF
+
+/* Dummy values */
+autoreply_transport_options_block autoreply_transport_option_defaults = {0};
+void autoreply_transport_init(transport_instance *tblock) {}
+BOOL autoreply_transport_entry(transport_instance *tblock, address_item *addr) {return FALSE;}
+
+#else   /*!MACRO_PREDEF*/
+
+
 /* Default private options block for the autoreply transport. */
 
 autoreply_transport_options_block autoreply_transport_option_defaults = {
@@ -335,33 +346,22 @@ else
   file_expand = ob->file_expand;
   return_message = ob->return_message;
 
-  if ((from  != NULL &&
-        (from = checkexpand(from, addr, tblock->name, cke_hdr)) == NULL) ||
-      (reply_to    != NULL &&
-        (reply_to = checkexpand(reply_to, addr, tblock->name, cke_hdr)) == NULL) ||
-      (to    != NULL &&
-        (to = checkexpand(to, addr, tblock->name, cke_hdr)) == NULL) ||
-      (cc    != NULL &&
-        (cc = checkexpand(cc, addr, tblock->name, cke_hdr)) == NULL) ||
-      (bcc   != NULL &&
-        (bcc = checkexpand(bcc, addr, tblock->name, cke_hdr)) == NULL) ||
-      (subject   != NULL &&
-        (subject = checkexpand(subject, addr, tblock->name, cke_hdr)) == NULL) ||
-      (headers != NULL &&
-        (headers = checkexpand(headers, addr, tblock->name, cke_text)) == NULL) ||
-      (text  != NULL &&
-        (text = checkexpand(text, addr, tblock->name, cke_text)) == NULL) ||
-      (file  != NULL &&
-        (file = checkexpand(file, addr, tblock->name, cke_file)) == NULL) ||
-      (logfile != NULL &&
-        (logfile = checkexpand(logfile, addr, tblock->name, cke_file)) == NULL) ||
-      (oncelog != NULL &&
-        (oncelog = checkexpand(oncelog, addr, tblock->name, cke_file)) == NULL) ||
-      (oncerepeat != NULL &&
-        (oncerepeat = checkexpand(oncerepeat, addr, tblock->name, cke_file)) == NULL))
+  if (  from && !(from = checkexpand(from, addr, tblock->name, cke_hdr))
+     || reply_to && !(reply_to = checkexpand(reply_to, addr, tblock->name, cke_hdr))
+     || to && !(to = checkexpand(to, addr, tblock->name, cke_hdr))
+     || cc && !(cc = checkexpand(cc, addr, tblock->name, cke_hdr))
+     || bcc && !(bcc = checkexpand(bcc, addr, tblock->name, cke_hdr))
+     || subject && !(subject = checkexpand(subject, addr, tblock->name, cke_hdr))
+     || headers && !(headers = checkexpand(headers, addr, tblock->name, cke_text))
+     || text && !(text = checkexpand(text, addr, tblock->name, cke_text))
+     || file && !(file = checkexpand(file, addr, tblock->name, cke_file))
+     || logfile && !(logfile = checkexpand(logfile, addr, tblock->name, cke_file))
+     || oncelog && !(oncelog = checkexpand(oncelog, addr, tblock->name, cke_file))
+     || oncerepeat && !(oncerepeat = checkexpand(oncerepeat, addr, tblock->name, cke_file))
+     )
     return FALSE;
 
-  if (oncerepeat != NULL)
+  if (oncerepeat)
     {
     once_repeat_sec = readconf_readtime(oncerepeat, 0, FALSE);
     if (once_repeat_sec < 0)
@@ -377,11 +377,11 @@ else
 /* If the never_mail option is set, we have to scan all the recipients and
 remove those that match. */
 
-if (ob->never_mail != NULL)
+if (ob->never_mail)
   {
   const uschar *never_mail = expand_string(ob->never_mail);
 
-  if (never_mail == NULL)
+  if (!never_mail)
     {
     addr->transport_return = FAIL;
     addr->message = string_sprintf("Failed to expand \"%s\" for "
@@ -389,11 +389,11 @@ if (ob->never_mail != NULL)
     return FALSE;
     }
 
-  if (to != NULL) check_never_mail(&to, never_mail);
-  if (cc != NULL) check_never_mail(&cc, never_mail);
-  if (bcc != NULL) check_never_mail(&bcc, never_mail);
+  if (to) check_never_mail(&to, never_mail);
+  if (cc) check_never_mail(&cc, never_mail);
+  if (bcc) check_never_mail(&bcc, never_mail);
 
-  if (to == NULL && cc == NULL && bcc == NULL)
+  if (!to && !cc && !bcc)
     {
     DEBUG(D_transport)
       debug_printf("*** all recipients removed by never_mail\n");
@@ -419,7 +419,7 @@ recipient, the effect might not be quite as envisaged. If once_file_size is
 set, instead of a dbm file, we use a regular file containing a circular buffer
 recipient cache. */
 
-if (oncelog != NULL && *oncelog != 0 && to != NULL)
+if (oncelog && *oncelog != 0 && to)
   {
   time_t then = 0;
 
@@ -427,7 +427,7 @@ if (oncelog != NULL && *oncelog != 0 && to != NULL)
 
   if (ob->once_file_size > 0)
     {
-    uschar *p;
+    uschar * p, * nextp;
     struct stat statbuf;
     cache_fd = Uopen(oncelog, O_CREAT|O_RDWR, ob->mode);
 
@@ -464,18 +464,16 @@ if (oncelog != NULL && *oncelog != 0 && to != NULL)
     zero. If we find a match, put the time into "then", and the place where it
     was found into "cache_time". Otherwise, "then" is left at zero. */
 
-    p = cache_buff;
-    while (p < cache_buff + cache_size)
+    for (p = cache_buff; p < cache_buff + cache_size; p = nextp)
       {
       uschar *s = p + sizeof(time_t);
-      uschar *nextp = s + Ustrlen(s) + 1;
+      nextp = s + Ustrlen(s) + 1;
       if (Ustrcmp(to, s) == 0)
         {
         memcpy(&then, p, sizeof(time_t));
         cache_time = p;
         break;
         }
-      p = nextp;
       }
     }
 
@@ -484,8 +482,12 @@ if (oncelog != NULL && *oncelog != 0 && to != NULL)
   else
     {
     EXIM_DATUM key_datum, result_datum;
-    EXIM_DBOPEN(oncelog, O_RDWR|O_CREAT, ob->mode, &dbm_file);
-    if (dbm_file == NULL)
+    uschar * dirname = string_copy(oncelog);
+    uschar * s;
+
+    if ((s = Ustrrchr(dirname, '/'))) *s = '\0';
+    EXIM_DBOPEN(oncelog, dirname, O_RDWR|O_CREAT, ob->mode, &dbm_file);
+    if (!dbm_file)
       {
       addr->transport_return = DEFER;
       addr->message = string_sprintf("Failed to open %s file %s when sending "
@@ -509,10 +511,9 @@ if (oncelog != NULL && *oncelog != 0 && to != NULL)
       can be abolished. */
 
       if (EXIM_DATUM_SIZE(result_datum) == sizeof(time_t))
-        {
         memcpy(&then, EXIM_DATUM_DATA(result_datum), sizeof(time_t));
-        }
-      else then = now;
+      else
+        then = now;
       }
     }
 
@@ -544,10 +545,10 @@ if (oncelog != NULL && *oncelog != 0 && to != NULL)
 
 /* We are going to send a message. Ensure any requested file is available. */
 
-if (file != NULL)
+if (file)
   {
   ff = Ufopen(file, "rb");
-  if (ff == NULL && !ob->file_optional)
+  if (!ff && !ob->file_optional)
     {
     addr->transport_return = DEFER;
     addr->message = string_sprintf("Failed to open file %s when sending "
@@ -568,6 +569,7 @@ if (pid < 0)
   addr->message = string_sprintf("Failed to create child process to send "
     "message from %s transport: %s", tblock->name, strerror(errno));
   DEBUG(D_transport) debug_printf("%s\n", addr->message);
+  if (dbm_file) EXIM_DBCLOSE(dbm_file);
   return FALSE;
   }
 
@@ -577,20 +579,20 @@ are newlines in it which might, if placed earlier, screw up other headers. */
 
 f = fdopen(fd, "wb");
 
-if (from != NULL) fprintf(f, "From: %s\n", from);
-if (reply_to != NULL) fprintf(f, "Reply-To: %s\n", reply_to);
-if (to != NULL) fprintf(f, "To: %s\n", to);
-if (cc != NULL) fprintf(f, "Cc: %s\n", cc);
-if (bcc != NULL) fprintf(f, "Bcc: %s\n", bcc);
-if (subject != NULL) fprintf(f, "Subject: %s\n", subject);
+if (from) fprintf(f, "From: %s\n", from);
+if (reply_to) fprintf(f, "Reply-To: %s\n", reply_to);
+if (to) fprintf(f, "To: %s\n", to);
+if (cc) fprintf(f, "Cc: %s\n", cc);
+if (bcc) fprintf(f, "Bcc: %s\n", bcc);
+if (subject) fprintf(f, "Subject: %s\n", subject);
 
 /* Generate In-Reply-To from the message_id header; there should
 always be one, but code defensively. */
 
-for (h = header_list; h != NULL; h = h->next)
+for (h = header_list; h; h = h->next)
   if (h->type == htype_id) break;
 
-if (h != NULL)
+if (h)
   {
   message_id = Ustrchr(h->text, ':') + 1;
   while (isspace(*message_id)) message_id++;
@@ -600,12 +602,12 @@ if (h != NULL)
 /* Generate a References header if there is at least one of Message-ID:,
 References:, or In-Reply-To: (see RFC 2822). */
 
-for (h = header_list; h != NULL; h = h->next)
+for (h = header_list; h; h = h->next)
   if (h->type != htype_old && strncmpic(US"References:", h->text, 11) == 0)
     break;
 
-if (h == NULL)
-  for (h = header_list; h != NULL; h = h->next)
+if (!h)
+  for (h = header_list; h; h = h->next)
     if (h->type != htype_old && strncmpic(US"In-Reply-To:", h->text, 12) == 0)
       break;
 
@@ -614,10 +616,10 @@ limit, some systems do not like headers growing beyond recognition.
 Keep the first message ID for the thread root and the last few for
 the position inside the thread, up to a maximum of 12 altogether. */
 
-if (h != NULL || message_id != NULL)
+if (h || message_id)
   {
   fprintf(f, "References:");
-  if (h != NULL)
+  if (h)
     {
     uschar *s, *id, *error;
     uschar *referenced_ids[12];
@@ -628,7 +630,7 @@ if (h != NULL || message_id != NULL)
     parse_allow_group = FALSE;
     while (*s != 0 && (s = parse_message_id(s, &id, &error)) != NULL)
       {
-      if (reference_count == sizeof(referenced_ids)/sizeof(uschar *))
+      if (reference_count == nelem(referenced_ids))
         {
         memmove(referenced_ids + 1, referenced_ids + 2,
            sizeof(referenced_ids) - 2*sizeof(uschar *));
@@ -641,8 +643,8 @@ if (h != NULL || message_id != NULL)
 
   /* The message id will have a newline on the end of it. */
 
-  if (message_id != NULL) fprintf(f, " %s", message_id);
-    else fprintf(f, "\n");
+  if (message_id) fprintf(f, " %s", message_id);
+  else fprintf(f, "\n");
   }
 
 /* Add an Auto-Submitted: header */
@@ -651,16 +653,16 @@ fprintf(f, "Auto-Submitted: auto-replied\n");
 
 /* Add any specially requested headers */
 
-if (headers != NULL) fprintf(f, "%s\n", headers);
+if (headers) fprintf(f, "%s\n", headers);
 fprintf(f, "\n");
 
-if (text != NULL)
+if (text)
   {
   fprintf(f, "%s", CS text);
   if (text[Ustrlen(text)-1] != '\n') fprintf(f, "\n");
   }
 
-if (ff != NULL)
+if (ff)
   {
   while (Ufgets(big_buffer, big_buffer_size, ff) != NULL)
     {
@@ -669,11 +671,11 @@ if (ff != NULL)
       uschar *s = expand_string(big_buffer);
       DEBUG(D_transport)
         {
-        if (s == NULL)
+        if (!s)
           debug_printf("error while expanding line from file:\n  %s\n  %s\n",
             big_buffer, expand_string_message);
         }
-      fprintf(f, "%s", (s == NULL)? CS big_buffer : CS s);
+      fprintf(f, "%s", s ? CS s : CS big_buffer);
       }
     else fprintf(f, "%s", CS big_buffer);
     }
@@ -692,6 +694,7 @@ if (return_message)
     :
     US"------ This is a copy of the message, including all the headers.\n";
   transport_ctx tctx = {
+    {fileno(f)},
     tblock,
     addr,
     NULL, NULL,
@@ -720,7 +723,7 @@ if (return_message)
 
   fflush(f);
   transport_count = 0;
-  transport_write_message(fileno(f), &tctx, bounce_return_size_limit);
+  transport_write_message(&tctx, bounce_return_size_limit);
   }
 
 /* End the message and wait for the child process to end; no timeout. */
@@ -744,30 +747,32 @@ if (cache_fd >= 0)
   {
   uschar *from = cache_buff;
   int size = cache_size;
-  (void)lseek(cache_fd, 0, SEEK_SET);
 
-  if (cache_time == NULL)
+  if (lseek(cache_fd, 0, SEEK_SET) == 0)
     {
-    cache_time = from + size;
-    memcpy(cache_time + sizeof(time_t), to, add_size - sizeof(time_t));
-    size += add_size;
-
-    if (cache_size > 0 && size > ob->once_file_size)
+    if (!cache_time)
       {
-      from += sizeof(time_t) + Ustrlen(from + sizeof(time_t)) + 1;
-      size -= (from - cache_buff);
+      cache_time = from + size;
+      memcpy(cache_time + sizeof(time_t), to, add_size - sizeof(time_t));
+      size += add_size;
+
+      if (cache_size > 0 && size > ob->once_file_size)
+       {
+       from += sizeof(time_t) + Ustrlen(from + sizeof(time_t)) + 1;
+       size -= (from - cache_buff);
+       }
       }
-    }
 
-  memcpy(cache_time, &now, sizeof(time_t));
-  if(write(cache_fd, from, size) != size)
-    DEBUG(D_transport) debug_printf("Problem writing cache file %s for %s "
-      "transport\n", oncelog, tblock->name);
+    memcpy(cache_time, &now, sizeof(time_t));
+    if(write(cache_fd, from, size) != size)
+      DEBUG(D_transport) debug_printf("Problem writing cache file %s for %s "
+       "transport\n", oncelog, tblock->name);
+    }
   }
 
 /* Update DBM file */
 
-else if (dbm_file != NULL)
+else if (dbm_file)
   {
   EXIM_DATUM key_datum, value_datum;
   EXIM_DATUM_INIT(key_datum);          /* Some DBM libraries need to have */
@@ -789,7 +794,6 @@ try will skip, of course. However, if there were no recipients in the
 message, we do not fail. */
 
 if (rc != 0)
-  {
   if (rc == EXIT_NORECIPIENTS)
     {
     DEBUG(D_any) debug_printf("%s transport: message contained no recipients\n",
@@ -802,7 +806,6 @@ if (rc != 0)
       "transport (%d)", tblock->name, rc);
     goto END_OFF;
     }
-  }
 
 /* Log the sending of the message if successful and required. If the file
 fails to open, it's hard to know what to do. We cannot write to the Exim
@@ -813,7 +816,7 @@ file opened for appending, in order to avoid interleaving of output from
 different processes. The log_buffer can be used exactly as for main log
 writing. */
 
-if (logfile != NULL)
+if (logfile)
   {
   int log_fd = Uopen(logfile, O_WRONLY|O_APPEND|O_CREAT, ob->mode);
   if (log_fd >= 0)
@@ -822,37 +825,37 @@ if (logfile != NULL)
     DEBUG(D_transport) debug_printf("logging message details\n");
     sprintf(CS ptr, "%s\n", tod_stamp(tod_log));
     while(*ptr) ptr++;
-    if (from != NULL)
+    if (from)
       {
       (void)string_format(ptr, LOG_BUFFER_SIZE - (ptr-log_buffer),
         "  From: %s\n", from);
       while(*ptr) ptr++;
       }
-    if (to != NULL)
+    if (to)
       {
       (void)string_format(ptr, LOG_BUFFER_SIZE - (ptr-log_buffer),
         "  To: %s\n", to);
       while(*ptr) ptr++;
       }
-    if (cc != NULL)
+    if (cc)
       {
       (void)string_format(ptr, LOG_BUFFER_SIZE - (ptr-log_buffer),
         "  Cc: %s\n", cc);
       while(*ptr) ptr++;
       }
-    if (bcc != NULL)
+    if (bcc)
       {
       (void)string_format(ptr, LOG_BUFFER_SIZE - (ptr-log_buffer),
         "  Bcc: %s\n", bcc);
       while(*ptr) ptr++;
       }
-    if (subject != NULL)
+    if (subject)
       {
       (void)string_format(ptr, LOG_BUFFER_SIZE - (ptr-log_buffer),
         "  Subject: %s\n", subject);
       while(*ptr) ptr++;
       }
-    if (headers != NULL)
+    if (headers)
       {
       (void)string_format(ptr, LOG_BUFFER_SIZE - (ptr-log_buffer),
         "  %s\n", headers);
@@ -868,7 +871,7 @@ if (logfile != NULL)
   }
 
 END_OFF:
-if (dbm_file != NULL) EXIM_DBCLOSE(dbm_file);
+if (dbm_file) EXIM_DBCLOSE(dbm_file);
 if (cache_fd > 0) (void)close(cache_fd);
 
 DEBUG(D_transport) debug_printf("%s transport succeeded\n", tblock->name);
@@ -876,4 +879,5 @@ DEBUG(D_transport) debug_printf("%s transport succeeded\n", tblock->name);
 return FALSE;
 }
 
+#endif /*!MACRO_PREDEF*/
 /* End of transport/autoreply.c */
index c4606ef8b8c647bd096829e2ea2660f007ed589b..f26050fdce292adfadb068a083712fa1037b0638 100644 (file)
@@ -40,6 +40,17 @@ address can appear in the tables drtables.c. */
 int lmtp_transport_options_count =
   sizeof(lmtp_transport_options)/sizeof(optionlist);
 
+
+#ifdef MACRO_PREDEF
+
+/* Dummy values */
+lmtp_transport_options_block lmtp_transport_option_defaults = {0};
+void lmtp_transport_init(transport_instance *tblock) {}
+BOOL lmtp_transport_entry(transport_instance *tblock, address_item *addr) {return FALSE;}
+
+#else   /*!MACRO_PREDEF*/
+
+
 /* Default private options block for the lmtp transport. */
 
 lmtp_transport_options_block lmtp_transport_option_defaults = {
@@ -610,6 +621,7 @@ if (send_data)
   {
   BOOL ok;
   transport_ctx tctx = {
+    {fd_in},
     tblock,
     addrlist,
     US".", US"..",
@@ -634,7 +646,7 @@ if (send_data)
     debug_printf("  LMTP>> writing message and terminating \".\"\n");
 
   transport_count = 0;
-  ok = transport_write_message(fd_in, &tctx, 0);
+  ok = transport_write_message(&tctx, 0);
 
   /* Failure can either be some kind of I/O disaster (including timeout),
   or the failure of a transport filter or the expansion of added headers. */
@@ -663,7 +675,7 @@ if (send_data)
         {
         const uschar *s = string_printing(buffer);
        /* de-const safe here as string_printing known to have alloc'n'copied */
-        addr->message = (s == buffer)? (uschar *)string_copy(s) : US s;
+        addr->message = (s == buffer)? US string_copy(s) : US s;
         }
       }
     /* If the response has failed badly, use it for all the remaining pending
@@ -790,4 +802,5 @@ MINUS_N:
   return FALSE;
 }
 
+#endif /*!MACRO_PREDEF*/
 /* End of transport/lmtp.c */
index 8b87e4a95909c57ed6fd74877b9f9c111c243bcc..be02560611b7a5bdef4c3fbfc55e6dcf3da048d1 100644 (file)
@@ -95,6 +95,17 @@ address can appear in the tables drtables.c. */
 int pipe_transport_options_count =
   sizeof(pipe_transport_options)/sizeof(optionlist);
 
+
+#ifdef MACRO_PREDEF
+
+/* Dummy values */
+pipe_transport_options_block pipe_transport_option_defaults = {0};
+void pipe_transport_init(transport_instance *tblock) {}
+BOOL pipe_transport_entry(transport_instance *tblock, address_item *addr) {return FALSE;}
+
+#else   /*!MACRO_PREDEF*/
+
+
 /* Default private options block for the pipe transport. */
 
 pipe_transport_options_block pipe_transport_option_defaults = {
@@ -516,7 +527,7 @@ if (expand_arguments)
   }
 else argv[2] = cmd;
 
-argv[3] = (uschar *)0;
+argv[3] = US 0;
 return TRUE;
 }
 
@@ -552,6 +563,7 @@ const uschar *envlist = ob->environment;
 uschar *cmd, *ss;
 uschar *eol = ob->use_crlf ? US"\r\n" : US"\n";
 transport_ctx tctx = {
+  {0},
   tblock,
   addr,
   ob->check_string,
@@ -684,10 +696,9 @@ if (envlist)
     }
   }
 
-while ((ss = string_nextinlist(&envlist, &envsep, big_buffer, big_buffer_size))
-       != NULL)
+while ((ss = string_nextinlist(&envlist, &envsep, big_buffer, big_buffer_size)))
    {
-   if (envcount > sizeof(envp)/sizeof(uschar *) - 2)
+   if (envcount > nelem(envp) - 2)
      {
      addr->transport_return = DEFER;
      addr->message = string_sprintf("too many environment settings for "
@@ -739,6 +750,7 @@ if ((pid = child_open(USS argv, envp, ob->umask, &fd_in, &fd_out, TRUE)) < 0)
       strerror(errno));
   return FALSE;
   }
+tctx.u.fd = fd_in;
 
 /* Now fork a process to handle the output that comes down the pipe. */
 
@@ -829,7 +841,7 @@ if (ob->message_prefix != NULL)
       expand_string_message);
     return FALSE;
     }
-  if (!transport_write_block(fd_in, prefix, Ustrlen(prefix)))
+  if (!transport_write_block(&tctx, prefix, Ustrlen(prefix), FALSE))
     goto END_WRITE;
   }
 
@@ -857,7 +869,7 @@ if (ob->use_bsmtp)
 
 /* Now the actual message */
 
-if (!transport_write_message(fd_in, &tctx, 0))
+if (!transport_write_message(&tctx, 0))
     goto END_WRITE;
 
 /* Now any configured suffix */
@@ -873,7 +885,7 @@ if (ob->message_suffix)
       expand_string_message);
     return FALSE;
     }
-  if (!transport_write_block(fd_in, suffix, Ustrlen(suffix)))
+  if (!transport_write_block(&tctx, suffix, Ustrlen(suffix), FALSE))
     goto END_WRITE;
   }
 
@@ -1150,4 +1162,5 @@ if (addr->transport_return != OK)
 return FALSE;
 }
 
+#endif /*!MACRO_PREDEF*/
 /* End of transport/pipe.c */
index 7f10706c1dc34b34966fd3e473deff724a2ead9d..bc4ed3f4096d1665619ec6c5e233ae3cc0374a25 100644 (file)
@@ -20,12 +20,25 @@ optionlist queuefile_transport_options[] = {
     (void *)offsetof(queuefile_transport_options_block, dirname) },
 };
 
+
 /* Size of the options list. An extern variable has to be used so that its
 address can appear in the tables drtables.c. */
 
 int queuefile_transport_options_count =
   sizeof(queuefile_transport_options) / sizeof(optionlist);
 
+
+#ifdef MACRO_PREDEF
+
+/* Dummy values */
+queuefile_transport_options_block queuefile_transport_option_defaults = {0};
+void queuefile_transport_init(transport_instance *tblock) {}
+BOOL queuefile_transport_entry(transport_instance *tblock, address_item *addr) {return FALSE;}
+
+#else   /*!MACRO_PREDEF*/
+
+
+
 /* Default private options block for the appendfile transport. */
 
 queuefile_transport_options_block queuefile_transport_option_defaults = {
@@ -254,3 +267,5 @@ if (sdfd >= 0) (void) close(sdfd);
 put in the first address of a batch. */
 return FALSE;
 }
+
+#endif /*!MACRO_PREDEF*/
index 52e04b8a57a032082679a7a5929796b2903439e5..461b26c4a2b3817692bad84a99ec088b9520a731 100644 (file)
@@ -43,6 +43,10 @@ optionlist smtp_transport_options[] = {
       (void *)offsetof(smtp_transport_options_block, dkim.dkim_canon) },
   { "dkim_domain", opt_stringptr,
       (void *)offsetof(smtp_transport_options_block, dkim.dkim_domain) },
+  { "dkim_hash", opt_stringptr,
+      (void *)offsetof(smtp_transport_options_block, dkim.dkim_hash) },
+  { "dkim_identity", opt_stringptr,
+      (void *)offsetof(smtp_transport_options_block, dkim.dkim_identity) },
   { "dkim_private_key", opt_stringptr,
       (void *)offsetof(smtp_transport_options_block, dkim.dkim_private_key) },
   { "dkim_selector", opt_stringptr,
@@ -186,88 +190,104 @@ address can appear in the tables drtables.c. */
 int smtp_transport_options_count =
   sizeof(smtp_transport_options)/sizeof(optionlist);
 
+
+#ifdef MACRO_PREDEF
+
+/* Dummy values */
+smtp_transport_options_block smtp_transport_option_defaults = {0};
+void smtp_transport_init(transport_instance *tblock) {}
+BOOL smtp_transport_entry(transport_instance *tblock, address_item *addr) {return FALSE;}
+void smtp_transport_closedown(transport_instance *tblock) {}
+
+#else   /*!MACRO_PREDEF*/
+
+
 /* Default private options block for the smtp transport. */
 
 smtp_transport_options_block smtp_transport_option_defaults = {
-  NULL,                /* hosts */
-  NULL,                /* fallback_hosts */
-  NULL,                /* hostlist */
-  NULL,                /* fallback_hostlist */
-  NULL,                /* authenticated_sender */
-  US"$primary_hostname", /* helo_data */
-  NULL,                /* interface */
-  NULL,                /* port */
-  US"smtp",            /* protocol */
-  NULL,                /* DSCP */
-  NULL,                /* serialize_hosts */
-  NULL,                /* hosts_try_auth */
-  NULL,                /* hosts_require_auth */
-  US"*",               /* hosts_try_chunking */
+  .hosts =                     NULL,
+  .hosts =                     NULL,
+  .hostlist =                  NULL,
+  .fallback_hostlist =         NULL,
+  .authenticated_sender =      NULL,
+  .helo_data =                 US"$primary_hostname",
+  .interface =                 NULL,
+  .port =                      NULL,
+  .protocol =                  US"smtp",
+  .dscp =                      NULL,
+  .serialize_hosts =           NULL,
+  .hosts_try_auth =            NULL,
+  .hosts_require_auth =                NULL,
+  .hosts_try_chunking =                US"*",
 #ifdef EXPERIMENTAL_DANE
-  NULL,                /* hosts_try_dane */
-  NULL,                /* hosts_require_dane */
+  .hosts_try_dane =            NULL,
+  .hosts_require_dane =                NULL,
 #endif
-  NULL,                /* hosts_try_fastopen */
+  .hosts_try_fastopen =                NULL,
 #ifndef DISABLE_PRDR
-  US"*",               /* hosts_try_prdr */
+  .hosts_try_prdr =            US"*",
 #endif
 #ifndef DISABLE_OCSP
-  US"*",               /* hosts_request_ocsp (except under DANE; tls_client_start()) */
-  NULL,                /* hosts_require_ocsp */
+  .hosts_request_ocsp =                US"*",               /* hosts_request_ocsp (except under DANE; tls_client_start()) */
+  .hosts_require_ocsp =                NULL,
+#endif
+  .hosts_require_tls =         NULL,
+  .hosts_avoid_tls =           NULL,
+  .hosts_verify_avoid_tls =    NULL,
+  .hosts_avoid_pipelining =    NULL,
+  .hosts_avoid_esmtp =         NULL,
+#ifdef SUPPORT_TLS
+  .hosts_nopass_tls =          NULL,
+  .hosts_noproxy_tls =         US"*",
 #endif
-  NULL,                /* hosts_require_tls */
-  NULL,                /* hosts_avoid_tls */
-  NULL,                /* hosts_verify_avoid_tls */
-  NULL,                /* hosts_avoid_pipelining */
-  NULL,                /* hosts_avoid_esmtp */
-  NULL,                /* hosts_nopass_tls */
-  US"*",              /* hosts_noproxy_tls */
-  5*60,                /* command_timeout */
-  5*60,                /* connect_timeout; shorter system default overrides */
-  5*60,                /* data timeout */
-  10*60,               /* final timeout */
-  1024,                /* size_addition */
-  5,                   /* hosts_max_try */
-  50,                  /* hosts_max_try_hardlimit */
-  TRUE,                /* address_retry_include_sender */
-  FALSE,               /* allow_localhost */
-  FALSE,               /* authenticated_sender_force */
-  FALSE,               /* gethostbyname */
-  TRUE,                /* dns_qualify_single */
-  FALSE,               /* dns_search_parents */
-  { NULL, NULL },      /* dnssec_domains {request,require} */
-  TRUE,                /* delay_after_cutoff */
-  FALSE,               /* hosts_override */
-  FALSE,               /* hosts_randomize */
-  TRUE,                /* keepalive */
-  FALSE,               /* lmtp_ignore_quota */
-  NULL,                       /* expand_retry_include_ip_address */
-  TRUE                 /* retry_include_ip_address */
+  .command_timeout =           5*60,
+  .connect_timeout =           5*60,
+  .data_timeout =              5*60,
+  .final_timeout =             10*60,
+  .size_addition =             1024,
+  .hosts_max_try =             5,
+  .hosts_max_try_hardlimit =   50,
+  .address_retry_include_sender = TRUE,
+  .allow_localhost =           FALSE,
+  .authenticated_sender_force =        FALSE,
+  .gethostbyname =             FALSE,
+  .dns_qualify_single =                TRUE,
+  .dns_search_parents =                FALSE,
+  .dnssec = { .request=NULL, .require=NULL },
+  .delay_after_cutoff =                TRUE,
+  .hosts_override =            FALSE,
+  .hosts_randomize =           FALSE,
+  .keepalive =                 TRUE,
+  .lmtp_ignore_quota =         FALSE,
+  .expand_retry_include_ip_address =   NULL,
+  .retry_include_ip_address =  TRUE,
 #ifdef SUPPORT_SOCKS
- ,NULL                 /* socks_proxy */
+  .socks_proxy =               NULL,
 #endif
 #ifdef SUPPORT_TLS
- ,NULL,                /* tls_certificate */
-  NULL,                /* tls_crl */
-  NULL,                /* tls_privatekey */
-  NULL,                /* tls_require_ciphers */
-  NULL,                /* tls_sni */
-  US"system",          /* tls_verify_certificates */
-  EXIM_CLIENT_DH_DEFAULT_MIN_BITS,
-                       /* tls_dh_min_bits */
-  TRUE,                /* tls_tempfail_tryclear */
-  NULL,                /* tls_verify_hosts */
-  US"*",               /* tls_try_verify_hosts */
-  US"*"                /* tls_verify_cert_hostnames */
+  .tls_certificate =           NULL,
+  .tls_crl =                   NULL,
+  .tls_privatekey =            NULL,
+  .tls_require_ciphers =       NULL,
+  .tls_sni =                   NULL,
+  .tls_verify_certificates =   US"system",
+  .tls_dh_min_bits =           EXIM_CLIENT_DH_DEFAULT_MIN_BITS,
+  .tls_tempfail_tryclear =     TRUE,
+  .tls_verify_hosts =          NULL,
+  .tls_try_verify_hosts =      US"*",
+  .tls_verify_cert_hostnames = US"*",
 #endif
 #ifndef DISABLE_DKIM
- , {NULL,              /* dkim_canon */
-    NULL,              /* dkim_domain */
-    NULL,              /* dkim_private_key */
-    NULL,              /* dkim_selector */
-    NULL,              /* dkim_sign_headers */
-    NULL,              /* dkim_strict */
-    FALSE}            /* dot_stuffed */
+ .dkim =
+   {.dkim_domain =             NULL,
+    .dkim_identity =           NULL,
+    .dkim_private_key =                NULL,
+    .dkim_selector =           NULL,
+    .dkim_canon =              NULL,
+    .dkim_sign_headers =       NULL,
+    .dkim_strict =             NULL,
+    .dkim_hash =               US"sha256",
+    .dot_stuffed =             FALSE},
 #endif
 };
 
@@ -794,7 +814,9 @@ with an address by scanning for the next address whose status is PENDING_DEFER.
 
 while (count-- > 0)
   {
-  while (addr->transport_return != PENDING_DEFER) addr = addr->next;
+  while (addr->transport_return != PENDING_DEFER)
+    if (!(addr = addr->next))
+      return -2;
 
   /* The address was accepted */
   addr->host_used = sx->host;
@@ -1002,7 +1024,7 @@ if (is_esmtp && regex_match_and_setup(regex_AUTH, buffer, 0, -1))
     If one is found, attempt to authenticate by calling its client function.
     */
 
-    for (au = auths; !smtp_authenticated && au != NULL; au = au->next)
+    for (au = auths; !smtp_authenticated && au; au = au->next)
       {
       uschar *p = names;
       if (!au->client ||
@@ -1019,7 +1041,7 @@ if (is_esmtp && regex_match_and_setup(regex_AUTH, buffer, 0, -1))
 
       /* Loop to scan supported server mechanisms */
 
-      while (*p != 0)
+      while (*p)
        {
        int rc;
        int len = Ustrlen(au->public_name);
@@ -1182,20 +1204,24 @@ tlsa_lookup(const host_item * host, dns_answer * dnsa, BOOL dane_required)
 /* move this out to host.c given the similarity to dns_lookup() ? */
 uschar buffer[300];
 const uschar * fullname = buffer;
+int rc;
+BOOL sec;
 
 /* TLSA lookup string */
 (void)sprintf(CS buffer, "_%d._tcp.%.256s", host->port, host->name);
 
-switch (dns_lookup(dnsa, buffer, T_TLSA, &fullname))
+rc = dns_lookup(dnsa, buffer, T_TLSA, &fullname);
+sec = dns_is_secure(dnsa);
+DEBUG(D_transport)
+  debug_printf("TLSA lookup ret %d %sDNSSEC\n", rc, sec ? "" : "not ");
+
+switch (rc)
   {
   case DNS_SUCCEED:
-    if (!dns_is_secure(dnsa))
-      {
-      log_write(0, LOG_MAIN, "DANE error: TLSA lookup not DNSSEC");
-      return DEFER;
-      }
-    return OK;
+    if (sec) return OK;
 
+    log_write(0, LOG_MAIN, "DANE error: TLSA lookup not DNSSEC");
+    /*FALLTHROUGH*/
   case DNS_AGAIN:
     return DEFER; /* just defer this TLS'd conn */
 
@@ -1296,44 +1322,44 @@ ehlo_response(uschar * buf, uschar checks)
 size_t bsize = Ustrlen(buf);
 
 #ifdef SUPPORT_TLS
-if (  checks & PEER_OFFERED_TLS
+if (  checks & OPTION_TLS
    && pcre_exec(regex_STARTTLS, NULL, CS buf, bsize, 0, PCRE_EOPT, NULL, 0) < 0)
-  checks &= ~PEER_OFFERED_TLS;
+  checks &= ~OPTION_TLS;
 #endif
 
-if (  checks & PEER_OFFERED_IGNQ
+if (  checks & OPTION_IGNQ
    && pcre_exec(regex_IGNOREQUOTA, NULL, CS buf, bsize, 0,
                PCRE_EOPT, NULL, 0) < 0)
-  checks &= ~PEER_OFFERED_IGNQ;
+  checks &= ~OPTION_IGNQ;
 
-if (  checks & PEER_OFFERED_CHUNKING
+if (  checks & OPTION_CHUNKING
    && pcre_exec(regex_CHUNKING, NULL, CS buf, bsize, 0, PCRE_EOPT, NULL, 0) < 0)
-  checks &= ~PEER_OFFERED_CHUNKING;
+  checks &= ~OPTION_CHUNKING;
 
 #ifndef DISABLE_PRDR
-if (  checks & PEER_OFFERED_PRDR
+if (  checks & OPTION_PRDR
    && pcre_exec(regex_PRDR, NULL, CS buf, bsize, 0, PCRE_EOPT, NULL, 0) < 0)
-  checks &= ~PEER_OFFERED_PRDR;
+  checks &= ~OPTION_PRDR;
 #endif
 
 #ifdef SUPPORT_I18N
-if (  checks & PEER_OFFERED_UTF8
+if (  checks & OPTION_UTF8
    && pcre_exec(regex_UTF8, NULL, CS buf, bsize, 0, PCRE_EOPT, NULL, 0) < 0)
-  checks &= ~PEER_OFFERED_UTF8;
+  checks &= ~OPTION_UTF8;
 #endif
 
-if (  checks & PEER_OFFERED_DSN
+if (  checks & OPTION_DSN
    && pcre_exec(regex_DSN, NULL, CS buf, bsize, 0, PCRE_EOPT, NULL, 0) < 0)
-  checks &= ~PEER_OFFERED_DSN;
+  checks &= ~OPTION_DSN;
 
-if (  checks & PEER_OFFERED_PIPE
+if (  checks & OPTION_PIPE
    && pcre_exec(regex_PIPELINING, NULL, CS buf, bsize, 0,
                PCRE_EOPT, NULL, 0) < 0)
-  checks &= ~PEER_OFFERED_PIPE;
+  checks &= ~OPTION_PIPE;
 
-if (  checks & PEER_OFFERED_SIZE
+if (  checks & OPTION_SIZE
    && pcre_exec(regex_SIZE, NULL, CS buf, bsize, 0, PCRE_EOPT, NULL, 0) < 0)
-  checks &= ~PEER_OFFERED_SIZE;
+  checks &= ~OPTION_SIZE;
 
 return checks;
 }
@@ -1345,15 +1371,22 @@ return checks;
 If given a nonzero size, first flush any buffered SMTP commands
 then emit the command.
 
-Reap previous SMTP command responses if requested.
-Reap one SMTP command response if requested.
+Reap previous SMTP command responses if requested, and always reap
+the response from a previous BDAT command.
+
+Args:
+ tctx          transport context
+ chunk_size    value for SMTP BDAT command
+ flags
+   tc_chunk_last       add LAST option to SMTP BDAT command
+   tc_reap_prev                reap response to previous SMTP commands
 
 Returns:       OK or ERROR
 */
 
 static int
-smtp_chunk_cmd_callback(int fd, transport_ctx * tctx,
-  unsigned chunk_size, unsigned flags)
+smtp_chunk_cmd_callback(transport_ctx * tctx, unsigned chunk_size,
+  unsigned flags)
 {
 smtp_transport_options_block * ob =
   (smtp_transport_options_block *)(tctx->tblock->options_block);
@@ -1361,13 +1394,14 @@ smtp_context * sx = tctx->smtp_context;
 int cmd_count = 0;
 int prev_cmd_count;
 
-/* Write SMTP chunk header command */
+/* Write SMTP chunk header command.  If not reaping responses, note that
+there may be more writes (like, the chunk data) done soon. */
 
 if (chunk_size > 0)
   {
-  if((cmd_count = smtp_write_command(&sx->outblock, FALSE, "BDAT %u%s\r\n",
-                             chunk_size,
-                             flags & tc_chunk_last ? " LAST" : "")
+  if((cmd_count = smtp_write_command(&sx->outblock,
+             flags & tc_reap_prev ? SCMD_FLUSH : SCMD_MORE,
+             "BDAT %u%s\r\n", chunk_size, flags & tc_chunk_last ? " LAST" : "")
      ) < 0) return ERROR;
   if (flags & tc_chunk_last)
     data_command = string_copy(big_buffer);  /* Save for later error message */
@@ -1484,6 +1518,7 @@ sx->dane_required = verify_check_given_host(&sx->ob->hosts_require_dane, sx->hos
 
 if ((sx->max_rcpt = sx->tblock->max_addresses) == 0) sx->max_rcpt = 999999;
 sx->peer_offered = 0;
+sx->avoid_option = 0;
 sx->igquotstr = US"";
 if (!sx->helo_data) sx->helo_data = sx->ob->helo_data;
 #ifdef EXPERIMENTAL_DSN_INFO
@@ -1541,34 +1576,17 @@ if (sx->smtps)
 the initial interaction and HELO/EHLO/LHLO. Connect timeout errors are handled
 specially so they can be identified for retries. */
 
-if (continue_hostname == NULL)
+if (!continue_hostname)
   {
   if (sx->verify)
     HDEBUG(D_verify) debug_printf("interface=%s port=%d\n", sx->interface, sx->port);
 
-  /* This puts port into host->port */
-  sx->inblock.sock = sx->outblock.sock =
-    smtp_connect(sx->host, sx->host_af, sx->port, sx->interface,
-                 sx->ob->connect_timeout, sx->tblock);
+  /* Get the actual port the connection will use, into sx->host */
 
-  if (sx->inblock.sock < 0)
-    {
-    uschar * msg = NULL;
-    if (sx->verify)
-      {
-      msg = US strerror(errno);
-      HDEBUG(D_verify) debug_printf("connect: %s\n", msg);
-      }
-    set_errno_nohost(sx->addrlist,
-      errno == ETIMEDOUT ? ERRNO_CONNECTTIMEOUT : errno,
-      sx->verify ? string_sprintf("could not connect: %s", msg)
-            : NULL,
-      DEFER, FALSE);
-    sx->send_quit = FALSE;
-    return DEFER;
-    }
+  smtp_port_for_connect(sx->host, sx->port);
 
 #if defined(SUPPORT_TLS) && defined(EXPERIMENTAL_DANE)
+    /* Do TLSA lookup for DANE */
     {
     tls_out.dane_verified = FALSE;
     tls_out.tlsa_usage = 0;
@@ -1580,7 +1598,9 @@ if (continue_hostname == NULL)
        )
        switch (rc = tlsa_lookup(sx->host, &tlsa_dnsa, sx->dane_required))
          {
-         case OK:              sx->dane = TRUE; break;
+         case OK:              sx->dane = TRUE;
+                               sx->ob->tls_tempfail_tryclear = FALSE;
+                               break;
          case FAIL_FORCED:     break;
          default:              set_errno_nohost(sx->addrlist, ERRNO_DNSDEFER,
                                  string_sprintf("DANE error: tlsa lookup %s",
@@ -1596,12 +1616,32 @@ if (continue_hostname == NULL)
        FAIL, FALSE);
       return FAIL;
       }
-
-    if (sx->dane)
-      sx->ob->tls_tempfail_tryclear = FALSE;
     }
 #endif /*DANE*/
 
+  /* Make the TCP connection */
+
+  sx->inblock.sock = sx->outblock.sock =
+    smtp_connect(sx->host, sx->host_af, sx->interface,
+                 sx->ob->connect_timeout, sx->tblock);
+
+  if (sx->inblock.sock < 0)
+    {
+    uschar * msg = NULL;
+    if (sx->verify)
+      {
+      msg = US strerror(errno);
+      HDEBUG(D_verify) debug_printf("connect: %s\n", msg);
+      }
+    set_errno_nohost(sx->addrlist,
+      errno == ETIMEDOUT ? ERRNO_CONNECTTIMEOUT : errno,
+      sx->verify ? string_sprintf("could not connect: %s", msg)
+            : NULL,
+      DEFER, FALSE);
+    sx->send_quit = FALSE;
+    return DEFER;
+    }
+
   /* Expand the greeting message while waiting for the initial response. (Makes
   sense if helo_data contains ${lookup dnsdb ...} stuff). The expansion is
   delayed till here so that $sending_interface and $sending_port are set. */
@@ -1720,7 +1760,7 @@ goto SEND_QUIT;
 #ifdef SUPPORT_TLS
   if (sx->smtps)
     {
-    smtp_peer_options |= PEER_OFFERED_TLS;
+    smtp_peer_options |= OPTION_TLS;
     suppress_tls = FALSE;
     sx->ob->tls_tempfail_tryclear = FALSE;
     smtp_command = US"SSL-on-connect";
@@ -1730,7 +1770,7 @@ goto SEND_QUIT;
 
   if (sx->esmtp)
     {
-    if (smtp_write_command(&sx->outblock, FALSE, "%s %s\r\n",
+    if (smtp_write_command(&sx->outblock, SCMD_FLUSH, "%s %s\r\n",
          sx->lmtp ? "LHLO" : "EHLO", sx->helo_data) < 0)
       goto SEND_FAILED;
     sx->esmtp_sent = TRUE;
@@ -1763,7 +1803,7 @@ goto SEND_QUIT;
     if (sx->esmtp_sent && (n = Ustrlen(sx->buffer)) < sizeof(sx->buffer)/2)
       { rsp = sx->buffer + n + 1; n = sizeof(sx->buffer) - n; }
 
-    if (smtp_write_command(&sx->outblock, FALSE, "HELO %s\r\n", sx->helo_data) < 0)
+    if (smtp_write_command(&sx->outblock, SCMD_FLUSH, "HELO %s\r\n", sx->helo_data) < 0)
       goto SEND_FAILED;
     good_response = smtp_read_response(&sx->inblock, rsp, n,
       '2', sx->ob->command_timeout);
@@ -1785,25 +1825,27 @@ goto SEND_QUIT;
       }
     }
 
-  sx->peer_offered = smtp_peer_options = 0;
+  sx->avoid_option = sx->peer_offered = smtp_peer_options = 0;
 
   if (sx->esmtp || sx->lmtp)
     {
     sx->peer_offered = ehlo_response(sx->buffer,
-      PEER_OFFERED_TLS /* others checked later */
+      OPTION_TLS       /* others checked later */
       );
 
   /* Set tls_offered if the response to EHLO specifies support for STARTTLS. */
 
 #ifdef SUPPORT_TLS
-    smtp_peer_options |= sx->peer_offered & PEER_OFFERED_TLS;
+    smtp_peer_options |= sx->peer_offered & OPTION_TLS;
 #endif
     }
   }
 
-/* For continuing deliveries down the same channel, the socket is the standard
-input, and we don't need to redo EHLO here (but may need to do so for TLS - see
-below). Set up the pointer to where subsequent commands will be left, for
+/* For continuing deliveries down the same channel, having re-exec'd  the socket
+is the standard input; for a socket held open from verify it is recorded
+in the cutthrough context block.  Either way we don't need to redo EHLO here
+(but may need to do so for TLS - see below).
+Set up the pointer to where subsequent commands will be left, for
 error messages. Note that smtp_peer_options will have been
 set from the command line if they were set in the process that passed the
 connection on. */
@@ -1815,19 +1857,30 @@ separate - we could match up by host ip+port as a bodge. */
 
 else
   {
-  sx->inblock.sock = sx->outblock.sock = 0;    /* stdin */
+  if (cutthrough.fd >= 0 && cutthrough.callout_hold_only)
+    {
+    sx->inblock.sock = sx->outblock.sock = cutthrough.fd;
+    sx->host->port = sx->port = cutthrough.host.port;
+    }
+  else
+    {
+    sx->inblock.sock = sx->outblock.sock = 0;  /* stdin */
+    smtp_port_for_connect(sx->host, sx->port); /* Record the port that was used */
+    }
   smtp_command = big_buffer;
-  sx->host->port = sx->port;    /* Record the port that was used */
   sx->helo_data = NULL;                /* ensure we re-expand ob->helo_data */
 
-  /* For a continued connection with TLS being proxied for us, nothing
-  more to do. */
+  /* For a continued connection with TLS being proxied for us, or a
+  held-open verify connection with TLS, nothing more to do. */
 
-  if (continue_proxy)
+  if (  continue_proxy_cipher
+     || (cutthrough.fd >= 0 && cutthrough.callout_hold_only && cutthrough.is_tls)
+     )
     {
     sx->peer_offered = smtp_peer_options;
-    pipelining_active = !!(smtp_peer_options & PEER_OFFERED_PIPE);
-    HDEBUG(D_transport) debug_printf("continued connection, proxied TLS\n");
+    pipelining_active = !!(smtp_peer_options & OPTION_PIPE);
+    HDEBUG(D_transport) debug_printf("continued connection, %s TLS\n",
+      continue_proxy_cipher ? "proxied" : "verify conn with");
     return OK;
     }
   HDEBUG(D_transport) debug_printf("continued connection, no TLS\n");
@@ -1842,7 +1895,7 @@ the client not be required to use TLS. If the response is bad, copy the buffer
 for error analysis. */
 
 #ifdef SUPPORT_TLS
-if (  smtp_peer_options & PEER_OFFERED_TLS
+if (  smtp_peer_options & OPTION_TLS
    && !suppress_tls
    && verify_check_given_host(&sx->ob->hosts_avoid_tls, sx->host) != OK
    && (  !sx->verify
@@ -1850,7 +1903,7 @@ if (  smtp_peer_options & PEER_OFFERED_TLS
    )  )
   {
   uschar buffer2[4096];
-  if (smtp_write_command(&sx->outblock, FALSE, "STARTTLS\r\n") < 0)
+  if (smtp_write_command(&sx->outblock, SCMD_FLUSH, "STARTTLS\r\n") < 0)
     goto SEND_FAILED;
 
   /* If there is an I/O error, transmission of this message is deferred. If
@@ -1964,7 +2017,7 @@ if (tls_out.active >= 0)
       debug_printf("not sending EHLO (host matches hosts_avoid_esmtp)\n");
     }
 
-  if (smtp_write_command(&sx->outblock, FALSE, "%s %s\r\n",
+  if (smtp_write_command(&sx->outblock, SCMD_FLUSH, "%s %s\r\n",
         sx->lmtp ? "LHLO" : greeting_cmd, sx->helo_data) < 0)
     goto SEND_FAILED;
   good_response = smtp_read_response(&sx->inblock, sx->buffer, sizeof(sx->buffer),
@@ -1988,7 +2041,7 @@ else if (  sx->smtps
   {
   errno = ERRNO_TLSREQUIRED;
   message = string_sprintf("a TLS session is required, but %s",
-    smtp_peer_options & PEER_OFFERED_TLS
+    smtp_peer_options & OPTION_TLS
     ? "an attempt to start TLS failed" : "the server did not offer TLS support");
   goto TLS_FAILED;
   }
@@ -2009,60 +2062,60 @@ if (continue_hostname == NULL
     {
     sx->peer_offered = ehlo_response(sx->buffer,
        0 /* no TLS */
-       | (sx->lmtp && sx->ob->lmtp_ignore_quota ? PEER_OFFERED_IGNQ : 0)
-       | PEER_OFFERED_CHUNKING
-       | PEER_OFFERED_PRDR
+       | (sx->lmtp && sx->ob->lmtp_ignore_quota ? OPTION_IGNQ : 0)
+       | OPTION_CHUNKING
+       | OPTION_PRDR
 #ifdef SUPPORT_I18N
-       | (sx->addrlist->prop.utf8_msg ? PEER_OFFERED_UTF8 : 0)
+       | (sx->addrlist->prop.utf8_msg ? OPTION_UTF8 : 0)
          /*XXX if we hand peercaps on to continued-conn processes,
                must not depend on this addr */
 #endif
-       | PEER_OFFERED_DSN
-       | PEER_OFFERED_PIPE
-       | (sx->ob->size_addition >= 0 ? PEER_OFFERED_SIZE : 0)
+       | OPTION_DSN
+       | OPTION_PIPE
+       | (sx->ob->size_addition >= 0 ? OPTION_SIZE : 0)
       );
 
     /* Set for IGNOREQUOTA if the response to LHLO specifies support and the
     lmtp_ignore_quota option was set. */
 
-    sx->igquotstr = sx->peer_offered & PEER_OFFERED_IGNQ ? US" IGNOREQUOTA" : US"";
+    sx->igquotstr = sx->peer_offered & OPTION_IGNQ ? US" IGNOREQUOTA" : US"";
 
     /* If the response to EHLO specified support for the SIZE parameter, note
     this, provided size_addition is non-negative. */
 
-    smtp_peer_options |= sx->peer_offered & PEER_OFFERED_SIZE;
+    smtp_peer_options |= sx->peer_offered & OPTION_SIZE;
 
     /* Note whether the server supports PIPELINING. If hosts_avoid_esmtp matched
     the current host, esmtp will be false, so PIPELINING can never be used. If
     the current host matches hosts_avoid_pipelining, don't do it. */
 
-    if (  sx->peer_offered & PEER_OFFERED_PIPE
+    if (  sx->peer_offered & OPTION_PIPE
        && verify_check_given_host(&sx->ob->hosts_avoid_pipelining, sx->host) != OK)
-      smtp_peer_options |= PEER_OFFERED_PIPE;
+      smtp_peer_options |= OPTION_PIPE;
 
     DEBUG(D_transport) debug_printf("%susing PIPELINING\n",
-      smtp_peer_options & PEER_OFFERED_PIPE ? "" : "not ");
+      smtp_peer_options & OPTION_PIPE ? "" : "not ");
 
-    if (  sx->peer_offered & PEER_OFFERED_CHUNKING
+    if (  sx->peer_offered & OPTION_CHUNKING
        && verify_check_given_host(&sx->ob->hosts_try_chunking, sx->host) != OK)
-      sx->peer_offered &= ~PEER_OFFERED_CHUNKING;
+      sx->peer_offered &= ~OPTION_CHUNKING;
 
-    if (sx->peer_offered & PEER_OFFERED_CHUNKING)
+    if (sx->peer_offered & OPTION_CHUNKING)
       {DEBUG(D_transport) debug_printf("CHUNKING usable\n");}
 
 #ifndef DISABLE_PRDR
-    if (  sx->peer_offered & PEER_OFFERED_PRDR
+    if (  sx->peer_offered & OPTION_PRDR
        && verify_check_given_host(&sx->ob->hosts_try_prdr, sx->host) != OK)
-      sx->peer_offered &= ~PEER_OFFERED_PRDR;
+      sx->peer_offered &= ~OPTION_PRDR;
 
-    if (sx->peer_offered & PEER_OFFERED_PRDR)
+    if (sx->peer_offered & OPTION_PRDR)
       {DEBUG(D_transport) debug_printf("PRDR usable\n");}
 #endif
 
     /* Note if the server supports DSN */
-    smtp_peer_options |= sx->peer_offered & PEER_OFFERED_DSN;
+    smtp_peer_options |= sx->peer_offered & OPTION_DSN;
     DEBUG(D_transport) debug_printf("%susing DSN\n",
-                       sx->peer_offered & PEER_OFFERED_DSN ? "" : "not ");
+                       sx->peer_offered & OPTION_DSN ? "" : "not ");
 
     /* Note if the response to EHLO specifies support for the AUTH extension.
     If it has, check that this host is one we want to authenticate to, and do
@@ -2079,7 +2132,7 @@ if (continue_hostname == NULL
       }
     }
   }
-pipelining_active = !!(smtp_peer_options & PEER_OFFERED_PIPE);
+pipelining_active = !!(smtp_peer_options & OPTION_PIPE);
 
 /* The setting up of the SMTP call is now complete. Any subsequent errors are
 message-specific. */
@@ -2097,7 +2150,7 @@ if (sx->addrlist->prop.utf8_msg)
   }
 
 /* If this is an international message we need the host to speak SMTPUTF8 */
-if (sx->utf8_needed && !(sx->peer_offered & PEER_OFFERED_UTF8))
+if (sx->utf8_needed && !(sx->peer_offered & OPTION_UTF8))
   {
   errno = ERRNO_UTF8_FWD;
   goto RESPONSE_FAILED;
@@ -2143,32 +2196,41 @@ return OK;
 
   /* The failure happened while setting up the call; see if the failure was
   a 5xx response (this will either be on connection, or following HELO - a 5xx
-  after EHLO causes it to try HELO). If so, fail all addresses, as this host is
-  never going to accept them. For other errors during setting up (timeouts or
-  whatever), defer all addresses, and yield DEFER, so that the host is not
-  tried again for a while. */
+  after EHLO causes it to try HELO). If so, and there are no more hosts to try,
+  fail all addresses, as this host is never going to accept them. For other
+  errors during setting up (timeouts or whatever), defer all addresses, and
+  yield DEFER, so that the host is not tried again for a while.
+
+  XXX This peeking for another host feels like a layering violation. We want
+  to note the host as unusable, but down here we shouldn't know if this was
+  the last host to try for the addr(list).  Perhaps the upper layer should be
+  the one to do set_errno() ?  The problem is that currently the addr is where
+  errno etc. are stashed, but until we run out of hosts to try the errors are
+  host-specific.  Maybe we should enhance the host_item definition? */
 
 FAILED:
   sx->ok = FALSE;                /* For when reached by GOTO */
-
-  yield = code == '5'
+  set_errno(sx->addrlist, errno, message,
+           sx->host->next
+           ? DEFER
+           : code == '5'
 #ifdef SUPPORT_I18N
-         || errno == ERRNO_UTF8_FWD
+                       || errno == ERRNO_UTF8_FWD
 #endif
-    ? FAIL : DEFER;
-
-  set_errno(sx->addrlist, errno, message, yield, pass_message, sx->host
+           ? FAIL : DEFER,
+           pass_message, sx->host
 #ifdef EXPERIMENTAL_DSN_INFO
            , sx->smtp_greeting, sx->helo_response
 #endif
            );
+  yield = DEFER;
   }
 
 
 SEND_QUIT:
 
 if (sx->send_quit)
-  (void)smtp_write_command(&sx->outblock, FALSE, "QUIT\r\n");
+  (void)smtp_write_command(&sx->outblock, SCMD_FLUSH, "QUIT\r\n");
 
 #ifdef SUPPORT_TLS
 tls_close(FALSE, TRUE);
@@ -2177,12 +2239,7 @@ tls_close(FALSE, TRUE);
 /* Close the socket, and return the appropriate value, first setting
 works because the NULL setting is passed back to the calling process, and
 remote_max_parallel is forced to 1 when delivering over an existing connection,
-
-If all went well and continue_more is set, we shouldn't actually get here if
-there are further addresses, as the return above will be taken. However,
-writing RSET might have failed, or there may be other addresses whose hosts are
-specified in the transports, and therefore not visible at top level, in which
-case continue_more won't get set. */
+*/
 
 HDEBUG(D_transport|D_acl|D_v) debug_printf_indent("  SMTP(close)>>\n");
 if (sx->send_quit)
@@ -2220,15 +2277,19 @@ int address_count;
 
 *p = 0;
 
-/* If we know the receiving MTA supports the SIZE qualification,
+/* If we know the receiving MTA supports the SIZE qualification, and we know it,
 send it, adding something to the message size to allow for imprecision
 and things that get added en route. Exim keeps the number of lines
 in a message, so we can give an accurate value for the original message, but we
 need some additional to handle added headers. (Double "." characters don't get
 included in the count.) */
 
-if (sx->peer_offered & PEER_OFFERED_SIZE)
+if (  message_size > 0
+   && sx->peer_offered & OPTION_SIZE && !(sx->avoid_option & OPTION_SIZE))
   {
+/*XXX problem here under spool_files_wireformat?
+Or just forget about lines?  Or inflate by a fixed proportion? */
+
   sprintf(CS p, " SIZE=%d", message_size+message_linecount+sx->ob->size_addition);
   while (*p) p++;
   }
@@ -2238,7 +2299,7 @@ if (sx->peer_offered & PEER_OFFERED_SIZE)
 request that */
 
 sx->prdr_active = FALSE;
-if (sx->peer_offered & PEER_OFFERED_PRDR)
+if (sx->peer_offered & OPTION_PRDR)
   for (addr = addrlist; addr; addr = addr->next)
     if (addr->transport_return == PENDING_DEFER)
       {
@@ -2257,7 +2318,7 @@ if (sx->peer_offered & PEER_OFFERED_PRDR)
 /* If it supports internationalised messages, and this meesage need that,
 request it */
 
-if (  sx->peer_offered & PEER_OFFERED_UTF8
+if (  sx->peer_offered & OPTION_UTF8
    && addrlist->prop.utf8_msg
    && !addrlist->prop.utf8_downcvt
    )
@@ -2279,7 +2340,7 @@ for (sx->dsn_all_lasthop = TRUE, addr = addrlist, address_count = 0;
 
 /* Add any DSN flags to the mail command */
 
-if (sx->peer_offered & PEER_OFFERED_DSN && !sx->dsn_all_lasthop)
+if (sx->peer_offered & OPTION_DSN && !sx->dsn_all_lasthop)
   {
   if (dsn_ret == dsn_ret_hdrs)
     { Ustrcpy(p, " RET=HDRS"); p += 9; }
@@ -2315,7 +2376,7 @@ uschar * p = sx->buffer;
 
 /* Add any DSN flags to the rcpt command */
 
-if (sx->peer_offered & PEER_OFFERED_DSN && !(addr->dsn_flags & rf_dsnlasthop))
+if (sx->peer_offered & OPTION_DSN && !(addr->dsn_flags & rf_dsnlasthop))
   {
   if (addr->dsn_flags & rf_dsnflags)
     {
@@ -2385,7 +2446,7 @@ sx->pending_MAIL = TRUE;     /* The block starts with MAIL */
   the delivery log line. */
 
   if (  sx->addrlist->prop.utf8_msg
-     && (sx->addrlist->prop.utf8_downcvt || !(sx->peer_offered & PEER_OFFERED_UTF8))
+     && (sx->addrlist->prop.utf8_downcvt || !(sx->peer_offered & OPTION_UTF8))
      )
     {
     if (s = string_address_utf8_to_alabel(s, &errstr), errstr)
@@ -2398,7 +2459,7 @@ sx->pending_MAIL = TRUE;     /* The block starts with MAIL */
     }
 #endif
 
-  rc = smtp_write_command(&sx->outblock, pipelining_active,
+  rc = smtp_write_command(&sx->outblock, pipelining_active ? SCMD_BUFFER : SCMD_FLUSH,
          "MAIL FROM:<%s>%s\r\n", s, sx->buffer);
   }
 
@@ -2449,11 +2510,15 @@ for (addr = sx->first_addr, address_count = 0;
   BOOL no_flush;
   uschar * rcpt_addr;
 
-  addr->dsn_aware = sx->peer_offered & PEER_OFFERED_DSN
+  if (tcp_out_fastopen && !tcp_out_fastopen_logged)
+    setflag(addr, af_tcp_fastopen);
+
+  addr->dsn_aware = sx->peer_offered & OPTION_DSN
     ? dsn_support_yes : dsn_support_no;
 
   address_count++;
-  no_flush = pipelining_active && !sx->verify && (!mua_wrapper || addr->next);
+  no_flush = pipelining_active && !sx->verify
+         && (!mua_wrapper || addr->next && address_count < sx->max_rcpt);
 
   build_rcptcmd_options(sx, addr);
 
@@ -2475,8 +2540,8 @@ for (addr = sx->first_addr, address_count = 0;
     }
 #endif
 
-  count = smtp_write_command(&sx->outblock, no_flush, "RCPT TO:<%s>%s%s\r\n",
-    rcpt_addr, sx->igquotstr, sx->buffer);
+  count = smtp_write_command(&sx->outblock, no_flush ? SCMD_BUFFER : SCMD_FLUSH,
+    "RCPT TO:<%s>%s%s\r\n", rcpt_addr, sx->igquotstr, sx->buffer);
 
   if (count < 0) return -5;
   if (count > 0)
@@ -2501,6 +2566,7 @@ for (addr = sx->first_addr, address_count = 0;
     }
   }      /* Loop for next address */
 
+tcp_out_fastopen_logged = TRUE;
 sx->next_addr = addr;
 return 0;
 }
@@ -2511,28 +2577,29 @@ return 0;
 * Proxy TLS connection for another transport process *
 ******************************************************/
 /*
-Use the smtp-context buffer as a staging area, and select on both the slave
-process and the TLS'd fd for data to read (per the coding in ip_recv() and
+Use the given buffer as a staging area, and select on both the given fd
+and the TLS'd client-fd for data to read (per the coding in ip_recv() and
 fd_ready() this is legitimate).  Do blocking full-size writes, and reads
 under a timeout.
 
 Arguments:
-  sx           smtp context block
+  buf          space to use for buffering
+  bufsiz       size of buffer
   proxy_fd     comms to proxied process
   timeout      per-read timeout, seconds
 */
 
-static void
-smtp_proxy_tls(smtp_context * sx, int proxy_fd, int timeout)
+void
+smtp_proxy_tls(uschar * buf, size_t bsize, int proxy_fd, int timeout)
 {
-fd_set fds;
+fd_set rfds, efds;
 int max_fd = MAX(proxy_fd, tls_out.active) + 1;
 int rc, i, fd_bits, nbytes;
 
 set_process_info("proxying TLS connection for continued transport");
-FD_ZERO(&fds);
-FD_SET(tls_out.active, &fds);
-FD_SET(proxy_fd, &fds);
+FD_ZERO(&rfds);
+FD_SET(tls_out.active, &rfds);
+FD_SET(proxy_fd, &rfds);
 
 for (fd_bits = 3; fd_bits; )
   {
@@ -2540,11 +2607,13 @@ for (fd_bits = 3; fd_bits; )
   time_t time_start = time(NULL);
 
   /* wait for data */
+  efds = rfds;
   do
     {
     struct timeval tv = { time_left, 0 };
 
-    rc = select(max_fd, (SELECT_ARG2_TYPE *)&fds, NULL, NULL, &tv);
+    rc = select(max_fd,
+      (SELECT_ARG2_TYPE *)&rfds, NULL, (SELECT_ARG2_TYPE *)&efds, &tv);
 
     if (rc < 0 && errno == EINTR)
       if ((time_left -= time(NULL) - time_start) > 0) continue;
@@ -2554,40 +2623,48 @@ for (fd_bits = 3; fd_bits; )
       DEBUG(D_transport) if (rc == 0) debug_printf("%s: timed out\n", __FUNCTION__);
       return;
       }
+
+    if (FD_ISSET(tls_out.active, &efds) || FD_ISSET(proxy_fd, &efds))
+      {
+      DEBUG(D_transport) debug_printf("select: exceptional cond on %s fd\n",
+       FD_ISSET(proxy_fd, &efds) ? "proxy" : "tls");
+      return;
+      }
     }
-  while (rc < 0 || !(FD_ISSET(tls_out.active, &fds) || FD_ISSET(proxy_fd, &fds)));
+  while (rc < 0 || !(FD_ISSET(tls_out.active, &rfds) || FD_ISSET(proxy_fd, &rfds)));
 
   /* handle inbound data */
-  if (FD_ISSET(tls_out.active, &fds))
-    if ((rc = tls_read(FALSE, sx->buffer, sizeof(sx->buffer))) <= 0)
+  if (FD_ISSET(tls_out.active, &rfds))
+    if ((rc = tls_read(FALSE, buf, bsize)) <= 0)
       {
       fd_bits &= ~1;
-      FD_CLR(tls_out.active, &fds);
+      FD_CLR(tls_out.active, &rfds);
       shutdown(proxy_fd, SHUT_WR);
+      timeout = 5;
       }
     else
       {
       for (nbytes = 0; rc - nbytes > 0; nbytes += i)
-       if ((i = write(proxy_fd, sx->buffer + nbytes, rc - nbytes)) < 0) return;
+       if ((i = write(proxy_fd, buf + nbytes, rc - nbytes)) < 0) return;
       }
   else if (fd_bits & 1)
-    FD_SET(tls_out.active, &fds);
+    FD_SET(tls_out.active, &rfds);
 
   /* handle outbound data */
-  if (FD_ISSET(proxy_fd, &fds))
-    if ((rc = read(proxy_fd, sx->buffer, sizeof(sx->buffer))) <= 0)
+  if (FD_ISSET(proxy_fd, &rfds))
+    if ((rc = read(proxy_fd, buf, bsize)) <= 0)
       {
-      fd_bits &= ~2;
-      FD_CLR(proxy_fd, &fds);
-      shutdown(tls_out.active, SHUT_WR);
+      fd_bits = 0;
+      tls_close(FALSE, TRUE);
       }
     else
       {
       for (nbytes = 0; rc - nbytes > 0; nbytes += i)
-       if ((i = tls_write(FALSE, sx->buffer + nbytes, rc - nbytes)) < 0) return;
+       if ((i = tls_write(FALSE, buf + nbytes, rc - nbytes, FALSE)) < 0)
+         return;
       }
   else if (fd_bits & 2)
-    FD_SET(proxy_fd, &fds);
+    FD_SET(proxy_fd, &rfds);
   }
 }
 #endif
@@ -2616,7 +2693,8 @@ Arguments:
                   failed by one of them.
   host            host to deliver to
   host_af         AF_INET or AF_INET6
-  port            default TCP/IP port to use, in host byte order
+  defport         default TCP/IP port to use if host does not specify, in host
+                 byte order
   interface       interface to bind to, or NULL
   tblock          transport instance block
   message_defer   set TRUE if yield is OK, but all addresses were deferred
@@ -2638,7 +2716,7 @@ Returns:          OK    - the connection was made and the delivery attempted;
 */
 
 static int
-smtp_deliver(address_item *addrlist, host_item *host, int host_af, int port,
+smtp_deliver(address_item *addrlist, host_item *host, int host_af, int defport,
   uschar *interface, transport_instance *tblock,
   BOOL *message_defer, BOOL suppress_tls)
 {
@@ -2646,22 +2724,22 @@ address_item *addr;
 int yield = OK;
 int save_errno;
 int rc;
-time_t start_delivery_time = time(NULL);
+struct timeval start_delivery_time;
 
 BOOL pass_message = FALSE;
 uschar *message = NULL;
 uschar new_message_id[MESSAGE_ID_LENGTH + 1];
-uschar *p;
 
 smtp_context sx;
 
+gettimeofday(&start_delivery_time, NULL);
 suppress_tls = suppress_tls;  /* stop compiler warning when no TLS support */
 *message_defer = FALSE;
 
 sx.addrlist = addrlist;
 sx.host = host;
 sx.host_af = host_af,
-sx.port = port;
+sx.port = defport;
 sx.interface = interface;
 sx.helo_data = NULL;
 sx.tblock = tblock;
@@ -2678,17 +2756,14 @@ set it up. This cannot be done until the identify of the host is known. */
 
 if (tblock->filter_command)
   {
-  BOOL rc;
-  uschar fbuf[64];
-  sprintf(CS fbuf, "%.50s transport", tblock->name);
-  rc = transport_set_up_command(&transport_filter_argv, tblock->filter_command,
-    TRUE, DEFER, addrlist, fbuf, NULL);
   transport_filter_timeout = tblock->filter_timeout;
 
   /* On failure, copy the error to all addresses, abandon the SMTP call, and
   yield ERROR. */
 
-  if (!rc)
+  if (!transport_set_up_command(&transport_filter_argv,
+       tblock->filter_command, TRUE, DEFER, addrlist,
+       string_sprintf("%.50s transport", tblock->name), NULL))
     {
     set_errno_nohost(addrlist->next, addrlist->basic_errno, addrlist->message, DEFER,
       FALSE);
@@ -2699,14 +2774,15 @@ if (tblock->filter_command)
   if (  transport_filter_argv
      && *transport_filter_argv
      && **transport_filter_argv
-     && sx.peer_offered & PEER_OFFERED_CHUNKING
+     && sx.peer_offered & OPTION_CHUNKING
      )
     {
-    sx.peer_offered &= ~PEER_OFFERED_CHUNKING;
+    sx.peer_offered &= ~OPTION_CHUNKING;
     DEBUG(D_transport) debug_printf("CHUNKING not usable due to transport filter\n");
     }
   }
 
+sx.first_addr = addrlist;
 
 /* For messages that have more than the maximum number of envelope recipients,
 we want to send several transactions down the same SMTP connection. (See
@@ -2718,39 +2794,61 @@ transaction to handle. */
 
 SEND_MESSAGE:
 sx.from_addr = return_path;
-sx.first_addr = sx.sync_addr = addrlist;
+sx.sync_addr = sx.first_addr;
 sx.ok = FALSE;
 sx.send_rset = TRUE;
 sx.completed_addr = FALSE;
 
 
-/* Initiate a message transfer. */
+/* If we are a continued-connection-after-verify the MAIL and RCPT
+commands were already sent; do not re-send but do mark the addrs as
+having been accepted up to RCPT stage.  A traditional cont-conn
+always has a sequence number greater than one. */
 
-switch(smtp_write_mail_and_rcpt_cmds(&sx, &yield))
+if (continue_hostname && continue_sequence == 1)
   {
-  case 0:              break;
-  case -1: case -2:    goto RESPONSE_FAILED;
-  case -3:             goto END_OFF;
-  case -4:             goto SEND_QUIT;
-  default:             goto SEND_FAILED;
-  }
+  address_item * addr;
 
-/* If we are an MUA wrapper, abort if any RCPTs were rejected, either
-permanently or temporarily. We should have flushed and synced after the last
-RCPT. */
+  sx.peer_offered = smtp_peer_options;
+  sx.pending_MAIL = FALSE;
+  sx.ok = TRUE;
+  sx.next_addr = NULL;
 
-if (mua_wrapper)
+  for (addr = addrlist; addr; addr = addr->next)
+    addr->transport_return = PENDING_OK;
+  }
+else
   {
-  address_item *badaddr;
-  for (badaddr = sx.first_addr; badaddr; badaddr = badaddr->next)
-    if (badaddr->transport_return != PENDING_OK)
-      {
-      /*XXX could we find a better errno than 0 here? */
-      set_errno_nohost(addrlist, 0, badaddr->message, FAIL,
-       testflag(badaddr, af_pass_message));
-      sx.ok = FALSE;
-      break;
-      }
+  /* Initiate a message transfer. */
+
+  switch(smtp_write_mail_and_rcpt_cmds(&sx, &yield))
+    {
+    case 0:            break;
+    case -1: case -2:  goto RESPONSE_FAILED;
+    case -3:           goto END_OFF;
+    case -4:           goto SEND_QUIT;
+    default:           goto SEND_FAILED;
+    }
+
+  /* If we are an MUA wrapper, abort if any RCPTs were rejected, either
+  permanently or temporarily. We should have flushed and synced after the last
+  RCPT. */
+
+  if (mua_wrapper)
+    {
+    address_item * a;
+    unsigned cnt;
+
+    for (a = sx.first_addr, cnt = 0; a && cnt < sx.max_rcpt; a = a->next, cnt++)
+      if (a->transport_return != PENDING_OK)
+       {
+       /*XXX could we find a better errno than 0 here? */
+       set_errno_nohost(addrlist, 0, a->message, FAIL,
+         testflag(a, af_pass_message));
+       sx.ok = FALSE;
+       break;
+       }
+    }
   }
 
 /* If ok is TRUE, we know we have got at least one good recipient, and must now
@@ -2761,10 +2859,10 @@ are pipelining. The responses are all handled by sync_responses().
 If using CHUNKING, do not send a BDAT until we know how big a chunk we want
 to send is. */
 
-if (  !(sx.peer_offered & PEER_OFFERED_CHUNKING)
+if (  !(sx.peer_offered & OPTION_CHUNKING)
    && (sx.ok || (pipelining_active && !mua_wrapper)))
   {
-  int count = smtp_write_command(&sx.outblock, FALSE, "DATA\r\n");
+  int count = smtp_write_command(&sx.outblock, SCMD_FLUSH, "DATA\r\n");
 
   if (count < 0) goto SEND_FAILED;
   switch(sync_responses(&sx, count, sx.ok ? +1 : -1))
@@ -2791,7 +2889,7 @@ for handling the SMTP dot-handling protocol, flagging to apply to headers as
 well as body. Set the appropriate timeout value to be used for each chunk.
 (Haven't been able to make it work using select() for writing yet.) */
 
-if (!(sx.peer_offered & PEER_OFFERED_CHUNKING) && !sx.ok)
+if (!(sx.peer_offered & OPTION_CHUNKING) && !sx.ok)
   {
   /* Save the first address of the next batch. */
   sx.first_addr = sx.next_addr;
@@ -2801,6 +2899,7 @@ if (!(sx.peer_offered & PEER_OFFERED_CHUNKING) && !sx.ok)
 else
   {
   transport_ctx tctx = {
+    {sx.inblock.sock},
     tblock,
     addrlist,
     US".", US"..",    /* Escaping strings */
@@ -2817,7 +2916,7 @@ else
   of responses.  The callback needs a whole bunch of state so set up
   a transport-context structure to be passed around. */
 
-  if (sx.peer_offered & PEER_OFFERED_CHUNKING)
+  if (sx.peer_offered & OPTION_CHUNKING)
     {
     tctx.check_string = tctx.escape_string = NULL;
     tctx.options |= topt_use_bdat;
@@ -2842,17 +2941,16 @@ else
   transport_write_timeout = sx.ob->data_timeout;
   smtp_command = US"sending data block";   /* For error messages */
   DEBUG(D_transport|D_v)
-    if (sx.peer_offered & PEER_OFFERED_CHUNKING)
+    if (sx.peer_offered & OPTION_CHUNKING)
       debug_printf("         will write message using CHUNKING\n");
     else
       debug_printf("  SMTP>> writing message and terminating \".\"\n");
   transport_count = 0;
 
 #ifndef DISABLE_DKIM
-  sx.ok = dkim_transport_write_message(sx.inblock.sock, &tctx, &sx.ob->dkim,
-           CUSS &message);
+  sx.ok = dkim_transport_write_message(&tctx, &sx.ob->dkim, CUSS &message);
 #else
-  sx.ok = transport_write_message(sx.inblock.sock, &tctx, 0);
+  sx.ok = transport_write_message(&tctx, 0);
 #endif
 
   /* transport_write_message() uses write() because it is called from other
@@ -2878,7 +2976,7 @@ else
 
   smtp_command = US"end of data";
 
-  if (sx.peer_offered & PEER_OFFERED_CHUNKING && sx.cmd_count > 1)
+  if (sx.peer_offered & OPTION_CHUNKING && sx.cmd_count > 1)
     {
     /* Reap any outstanding MAIL & RCPT commands, but not a DATA-go-ahead */
     switch(sync_responses(&sx, sx.cmd_count-1, 0))
@@ -2948,10 +3046,11 @@ else
   if (sx.ok)
     {
     int flag = '=';
-    int delivery_time = (int)(time(NULL) - start_delivery_time);
+    struct timeval delivery_time;
     int len;
-    uschar *conf = NULL;
+    uschar * conf = NULL;
 
+    timesince(&delivery_time, &start_delivery_time);
     sx.send_rset = FALSE;
     pipelining_active = FALSE;
 
@@ -2966,7 +3065,7 @@ else
       {
       const uschar *s = string_printing(sx.buffer);
       /* deconst cast ok here as string_printing was checked to have alloc'n'copied */
-      conf = (s == sx.buffer)? (uschar *)string_copy(s) : US s;
+      conf = (s == sx.buffer)? US string_copy(s) : US s;
       }
 
     /* Process all transported addresses - for LMTP or PRDR, read a status for
@@ -3026,14 +3125,15 @@ else
       actual host that was used. */
 
       addr->transport_return = OK;
-      addr->more_errno = delivery_time;
+      addr->more_errno = delivery_time.tv_sec;
+      addr->delivery_usec = delivery_time.tv_usec;
       addr->host_used = host;
       addr->special_action = flag;
       addr->message = conf;
 #ifndef DISABLE_PRDR
-      if (sx.prdr_active) addr->flags |= af_prdr_used;
+      if (sx.prdr_active) setflag(addr, af_prdr_used);
 #endif
-      if (sx.peer_offered & PEER_OFFERED_CHUNKING) addr->flags |= af_chunking_used;
+      if (sx.peer_offered & OPTION_CHUNKING) setflag(addr, af_chunking_used);
       flag = '-';
 
 #ifndef DISABLE_PRDR
@@ -3050,7 +3150,7 @@ else
         else
           sprintf(CS sx.buffer, "%.500s\n", addr->unique);
 
-        DEBUG(D_deliver) debug_printf("journalling %s\n", sx.buffer);
+        DEBUG(D_deliver) debug_printf("S:journalling %s", sx.buffer);
         len = Ustrlen(CS sx.buffer);
         if (write(journal_fd, sx.buffer, len) != len)
           log_write(0, LOG_MAIN|LOG_PANIC, "failed to write journal for "
@@ -3277,7 +3377,7 @@ if (sx.completed_addr && sx.ok && sx.send_quit)
      || continue_more
      || (
 #ifdef SUPPORT_TLS
-          (  tls_out.active < 0  &&  !continue_proxy
+          (  tls_out.active < 0  &&  !continue_proxy_cipher
            || verify_check_given_host(&sx.ob->hosts_nopass_tls, host) != OK
           )
         &&
@@ -3291,7 +3391,7 @@ if (sx.completed_addr && sx.ok && sx.send_quit)
     BOOL pass_message;
 
     if (sx.send_rset)
-      if (! (sx.ok = smtp_write_command(&sx.outblock, FALSE, "RSET\r\n") >= 0))
+      if (! (sx.ok = smtp_write_command(&sx.outblock, SCMD_FLUSH, "RSET\r\n") >= 0))
         {
         msg = US string_sprintf("send() to %s [%s] failed: %s", host->name,
           host->address, strerror(errno));
@@ -3323,32 +3423,39 @@ if (sx.completed_addr && sx.ok && sx.send_quit)
         continue_sequence++;             /* Causes * in logging */
         goto SEND_MESSAGE;
         }
-      if (continue_more) return yield;   /* More addresses for another run */
 
-      /* Pass the connection on to a new Exim process. */
+      /* Unless caller said it already has more messages listed for this host,
+      pass the connection on to a new Exim process (below, the call to
+      transport_pass_socket).  If the caller has more ready, just return with
+      the connection still open. */
+
 #ifdef SUPPORT_TLS
       if (tls_out.active >= 0)
-       if (verify_check_given_host(&sx.ob->hosts_noproxy_tls, host) == OK)
+       if (  continue_more
+          || verify_check_given_host(&sx.ob->hosts_noproxy_tls, host) == OK)
          {
-         /* Pass the socket, for direct use, to a new Exim process. Before
-         doing so, we must shut down TLS. Not all MTAs allow for the
-         continuation of the SMTP session when TLS is shut down. We test for
-         this by sending a new EHLO. If we don't get a good response, we don't
-         attempt to pass the socket on. */
+         /* Before passing the socket on, or returning to caller with it still
+         open, we must shut down TLS.  Not all MTAs allow for the continuation
+         of the SMTP session when TLS is shut down. We test for this by sending
+         a new EHLO. If we don't get a good response, we don't attempt to pass
+         the socket on. */
 
          tls_close(FALSE, TRUE);
          smtp_peer_options = smtp_peer_options_wrap;
          sx.ok = !sx.smtps
-           && smtp_write_command(&sx.outblock, FALSE,
+           && smtp_write_command(&sx.outblock, SCMD_FLUSH,
                                      "EHLO %s\r\n", sx.helo_data) >= 0
            && smtp_read_response(&sx.inblock, sx.buffer, sizeof(sx.buffer),
                                      '2', sx.ob->command_timeout);
+
+         if (sx.ok && continue_more)
+           return yield;               /* More addresses for another run */
          }
        else
          {
          /* Set up a pipe for proxying TLS for the new transport process */
 
-         smtp_peer_options |= PEER_OFFERED_TLS;
+         smtp_peer_options |= OPTION_TLS;
          if (sx.ok = (socketpair(AF_UNIX, SOCK_STREAM, 0, pfd) == 0))
            socket_fd = pfd[1];
          else
@@ -3359,7 +3466,10 @@ if (sx.completed_addr && sx.ok && sx.send_quit)
 # endif
                    );
          }
+      else
 #endif
+       if (continue_more)
+         return yield;                 /* More addresses for another run */
 
       /* If the socket is successfully passed, we mustn't send QUIT (or
       indeed anything!) from here. */
@@ -3376,24 +3486,34 @@ propagate it from the initial
        just passed the baton to.  Fork a child to to do it, and return to
        get logging done asap.  Which way to place the work makes assumptions
        about post-fork prioritisation which may not hold on all platforms. */
-
+#ifdef SUPPORT_TLS
        if (tls_out.active >= 0)
          {
          int pid = fork();
          if (pid > 0)          /* parent */
            {
+           DEBUG(D_transport) debug_printf("proxy-proc inter-pid %d\n", pid);
+           close(pfd[0]);
+           waitpid(pid, NULL, 0);
            tls_close(FALSE, FALSE);
            (void)close(sx.inblock.sock);
            continue_transport = NULL;
            continue_hostname = NULL;
            return yield;
            }
-         else if (pid == 0)    /* child */
+         else if (pid == 0)    /* child; fork again to disconnect totally */
            {
-           smtp_proxy_tls(&sx, pfd[0], sx.ob->command_timeout);
+           close(pfd[1]);
+           if ((pid = fork()))
+             {
+             DEBUG(D_transport) debug_printf("proxy-prox final-pid %d\n", pid);
+             _exit(pid ? EXIT_FAILURE : EXIT_SUCCESS);
+             }
+           smtp_proxy_tls(sx.buffer, sizeof(sx.buffer), pfd[0], sx.ob->command_timeout);
            exim_exit(0);
            }
          }
+#endif
        }
       }
 
@@ -3426,7 +3546,7 @@ This change is being made on 31-Jul-98. After over a year of trouble-free
 operation, the old commented-out code was removed on 17-Sep-99. */
 
 SEND_QUIT:
-if (sx.send_quit) (void)smtp_write_command(&sx.outblock, FALSE, "QUIT\r\n");
+if (sx.send_quit) (void)smtp_write_command(&sx.outblock, SCMD_FLUSH, "QUIT\r\n");
 
 END_OFF:
 
@@ -3507,7 +3627,7 @@ outblock.ptr = outbuffer;
 outblock.cmd_count = 0;
 outblock.authenticating = FALSE;
 
-(void)smtp_write_command(&outblock, FALSE, "QUIT\r\n");
+(void)smtp_write_command(&outblock, SCMD_FLUSH, "QUIT\r\n");
 (void)smtp_read_response(&inblock, buffer, sizeof(buffer), '2',
   ob->command_timeout);
 (void)close(inblock.sock);
@@ -3579,7 +3699,7 @@ smtp_transport_entry(
   address_item *addrlist)          /* addresses we are working on */
 {
 int cutoff_retry;
-int port;
+int defport;
 int hosts_defer = 0;
 int hosts_fail  = 0;
 int hosts_looked_up = 0;
@@ -3608,8 +3728,10 @@ DEBUG(D_transport)
     for (host = hostlist; host; host = host->next)
       debug_printf("  %s:%d\n", host->name, host->port);
     }
-  if (continue_hostname) debug_printf("already connected to %s [%s]\n",
-      continue_hostname, continue_host_address);
+  if (continue_hostname)
+    debug_printf("already connected to %s [%s] (on fd %d)\n",
+      continue_hostname, continue_host_address,
+      cutthrough.fd >= 0 ? cutthrough.fd : 0);
   }
 
 /* Set the flag requesting that these hosts be added to the waiting
@@ -3732,7 +3854,7 @@ else if (ob->hosts_randomize && hostlist->mx == MX_NONE && !continue_hostname)
 
 /* Sort out the default port.  */
 
-if (!smtp_get_port(ob->port, addrlist, &port, tid)) return FALSE;
+if (!smtp_get_port(ob->port, addrlist, &defport, tid)) return FALSE;
 
 /* For each host-plus-IP-address on the list:
 
@@ -3971,7 +4093,7 @@ for (cutoff_retry = 0;
     the default. */
 
     pistring = string_sprintf(":%d", host->port == PORT_NONE
-      ? port : host->port);
+      ? defport : host->port);
     if (Ustrcmp(pistring, ":25") == 0) pistring = US"";
 
     /* Select IPv4 or IPv6, and choose an outgoing interface. If the interface
@@ -4050,7 +4172,7 @@ for (cutoff_retry = 0;
       {
       if (  !host->address
          || host->status != hstatus_unusable_expired
-        || host->last_try > received_time)
+        || host->last_try > received_time.tv_sec)
         continue;
       DEBUG(D_transport) debug_printf("trying expired host %s [%s]%s\n",
           host->name, host->address, pistring);
@@ -4171,7 +4293,7 @@ for (cutoff_retry = 0;
       /* Attempt the delivery. */
 
       total_hosts_tried++;
-      rc = smtp_deliver(addrlist, thost, host_af, port, interface, tblock,
+      rc = smtp_deliver(addrlist, thost, host_af, defport, interface, tblock,
         &message_defer, FALSE);
 
       /* Yield is one of:
@@ -4218,7 +4340,7 @@ for (cutoff_retry = 0;
          "%s: delivering unencrypted to H=%s [%s] (not in hosts_require_tls)",
          first_addr->message, host->name, host->address);
         first_addr = prepare_addresses(addrlist, host);
-        rc = smtp_deliver(addrlist, thost, host_af, port, interface, tblock,
+        rc = smtp_deliver(addrlist, thost, host_af, defport, interface, tblock,
           &message_defer, TRUE);
         if (rc == DEFER && first_addr->basic_errno != ERRNO_AUTHFAIL)
           write_logs(first_addr, host);
@@ -4370,7 +4492,7 @@ for (cutoff_retry = 0;
         for (last_rule = retry->rules;
              last_rule->next;
              last_rule = last_rule->next);
-        timedout = time(NULL) - received_time > last_rule->timeout;
+        timedout = time(NULL) - received_time.tv_sec > last_rule->timeout;
         }
       else timedout = TRUE;    /* No rule => timed out */
 
@@ -4513,6 +4635,7 @@ DEBUG(D_transport) debug_printf("Leaving %s transport\n", tblock->name);
 return TRUE;   /* Each address has its status */
 }
 
+#endif /*!MACRO_PREDEF*/
 /* vi: aw ai sw=2
 */
 /* End of transport/smtp.c */
index 88b608bcc54130584c3be36f9345a7a01ea814cb..c965a72a7c2f901b864888a76b6581489f01c46e 100644 (file)
@@ -130,6 +130,7 @@ typedef struct {
   int          cmd_count;
 
   uschar       peer_offered;
+  uschar       avoid_option;
   uschar *     igquotstr;
   uschar *     helo_data;
 #ifdef EXPERIMENTAL_DSN_INFO
index 5558430686e5b3bdefaecf36ea64c50e23392dd4..1368849d66a1415cdc50fea322a8cb30d64ed189 100644 (file)
@@ -233,6 +233,7 @@ socks_opts proxies[32];                     /* max #proxies handled */
 unsigned nproxies;
 socks_opts * sob;
 unsigned size;
+blob early_data;
 
 if (!timeout) timeout = 24*60*60;      /* use 1 day for "indefinite" */
 tmo = time(NULL) + timeout;
@@ -268,6 +269,14 @@ for (nproxies = 0;
     socks_option(sob, option);
   }
 
+/* Set up the socks protocol method-selection message,
+for sending on connection */
+
+state = US"method select";
+buf[0] = 5; buf[1] = 1; buf[2] = sob->auth_type;
+early_data.data = buf;
+early_data.len = 3;
+
 /* Try proxies until a connection succeeds */
 
 for(;;)
@@ -285,11 +294,11 @@ for(;;)
   sob = &proxies[idx];
 
   /* bodge up a host struct for the proxy */
-  proxy.address = sob->proxy_host;
+  proxy.address = proxy.name = sob->proxy_host;
   proxy_af = Ustrchr(sob->proxy_host, ':') ? AF_INET6 : AF_INET;
 
   if ((fd = smtp_sock_connect(&proxy, proxy_af, sob->port,
-             interface, tb, sob->timeout)) >= 0)
+             interface, tb, sob->timeout, &early_data)) >= 0)
     {
     proxy_local_address = string_copy(proxy.address);
     proxy_local_port = sob->port;
@@ -301,13 +310,8 @@ for(;;)
   }
 
 /* Do the socks protocol stuff */
-/* Send method-selection */
 
-state = US"method select";
 HDEBUG(D_transport|D_acl|D_v) debug_printf_indent("  SOCKS>> 05 01 %02x\n", sob->auth_type);
-buf[0] = 5; buf[1] = 1; buf[2] = sob->auth_type;
-if (send(fd, buf, 3, 0) < 0)
-  goto snd_err;
 
 /* expect method response */
 
index 7be72896a2bf9c1fca31b790473959476d48b60f..9e18a804bb1c0ed779bd1375159f6be2011366e1 100644 (file)
@@ -211,10 +211,12 @@ int len;
 uschar buffer[256];
 sprintf(CS buffer, "%d 1\n", size);
 len = Ustrlen(buffer);
-(void)lseek(fd, 0, SEEK_END);
-len = write(fd, buffer, len);
-DEBUG(D_transport)
-  debug_printf("added '%.*s' to maildirsize file\n", len-1, buffer);
+if (lseek(fd, 0, SEEK_END) >= 0)
+  {
+  len = write(fd, buffer, len);
+  DEBUG(D_transport)
+    debug_printf("added '%.*s' to maildirsize file\n", len-1, buffer);
+  }
 }
 
 
index 7b7b88f66ef462c4bdb7c1b3fed990cec8fdfd21..4647785b9da36fdb2492c15618568e85bf60cf91 100644 (file)
@@ -68,7 +68,7 @@ any mixed-case annotation.  This does not really matter for a domain. */
     break;
     }
   }
-if ((rc = idn2_lookup_u8(CCS s, &s1, IDN2_NFC_INPUT)) != IDN2_OK)
+if ((rc = idn2_lookup_u8((const uint8_t *) s, &s1, IDN2_NFC_INPUT)) != IDN2_OK)
   {
   if (err) *err = US idn2_strerror(rc);
   return NULL;
@@ -98,6 +98,7 @@ string_domain_alabel_to_utf8(const uschar * alabel, uschar ** err)
 const uschar * label;
 int sep = '.';
 uschar * s = NULL;
+int size = 0, len = 0;
 
 while (label = string_nextinlist(&alabel, &sep, NULL, 0))
   if (  string_is_alabel(label)
@@ -105,7 +106,7 @@ while (label = string_nextinlist(&alabel, &sep, NULL, 0))
      )
     return NULL;
   else
-    s = string_append_listele(s, '.', label);
+    s = string_append_listele(s, &size, &len, '.', label);
 return s;
 
 #else
index 9ff1807d4fdac01ff3b2d4551b78d2c6bae60c80..ac5eb667b026e12bb41cb9be3fa58c522b158b4d 100644 (file)
@@ -39,7 +39,7 @@ static tree_node *dnsbl_cache = NULL;
 #define MT_NOT 1
 #define MT_ALL 2
 
-static uschar cutthrough_response(char, uschar **, int);
+static uschar cutthrough_response(int, char, uschar **, int);
 
 
 
@@ -68,9 +68,7 @@ int length, expire;
 time_t now;
 dbdata_callout_cache *cache_record;
 
-cache_record = dbfn_read_with_length(dbm_file, key, &length);
-
-if (cache_record == NULL)
+if (!(cache_record = dbfn_read_with_length(dbm_file, key, &length)))
   {
   HDEBUG(D_verify) debug_printf("callout cache: no %s record found for %s\n", type, key);
   return NULL;
@@ -388,7 +386,7 @@ if (addr->transport == cutthrough.addr.transport)
       deliver_domain = addr->domain;
       transport_name = addr->transport->name;
 
-      host_af = (Ustrchr(host->address, ':') == NULL)? AF_INET:AF_INET6;
+      host_af = Ustrchr(host->address, ':') ? AF_INET6 : AF_INET;
 
       if (!smtp_get_interface(tf->interface, host_af, addr, &interface,
              US"callout") ||
@@ -408,10 +406,10 @@ if (addr->transport == cutthrough.addr.transport)
 
        /* Match!  Send the RCPT TO, set done from the response */
        done =
-         smtp_write_command(&ctblock, FALSE, "RCPT TO:<%.1000s>\r\n",
+         smtp_write_command(&ctblock, SCMD_FLUSH, "RCPT TO:<%.1000s>\r\n",
            transport_rcpt_address(addr,
               addr->transport->rcpt_include_affixes)) >= 0 &&
-         cutthrough_response('2', &resp, CUTTHROUGH_DATA_TIMEOUT) == '2';
+         cutthrough_response(cutthrough.fd, '2', &resp, CUTTHROUGH_DATA_TIMEOUT) == '2';
 
        /* This would go horribly wrong if a callout fail was ignored by ACL.
        We punt by abandoning cutthrough on a reject, like the
@@ -429,7 +427,7 @@ if (addr->transport == cutthrough.addr.transport)
          }
        else
          {
-         cancel_cutthrough_connection("recipient rejected");
+         cancel_cutthrough_connection(TRUE, US"recipient rejected");
          if (!resp || errno == ETIMEDOUT)
            {
            HDEBUG(D_verify) debug_printf("SMTP timeout\n");
@@ -459,7 +457,7 @@ if (addr->transport == cutthrough.addr.transport)
       break;   /* host_list */
       }
 if (!done)
-  cancel_cutthrough_connection("incompatible connection");
+  cancel_cutthrough_connection(TRUE, US"incompatible connection");
 return done;
 }
 
@@ -490,6 +488,7 @@ Arguments:
                       vopt_callout_random => do the "random" thing
                       vopt_callout_recipsender => use real sender for recipient
                       vopt_callout_recippmaster => use postmaster for recipient
+                     vopt_callout_hold         => lazy close connection
   se_mailfrom         MAIL FROM address for sender verify; NULL => ""
   pm_mailfrom         if non-NULL, do the postmaster check with this sender
 
@@ -556,7 +555,10 @@ else
 if (cached_callout_lookup(addr, address_key, from_address,
       &options, &pm_mailfrom, &yield, failure_ptr,
       &new_domain_record, &old_domain_cache_result))
+  {
+  cancel_cutthrough_connection(TRUE, US"cache-hit");
   goto END_CALLOUT;
+  }
 
 if (!addr->transport)
   {
@@ -756,9 +758,12 @@ tls_retry_connection:
        }
 #endif
 
-      /* This would be ok for 1st rcpt of a cutthrough (XXX do we have a count?) , but no way to
-      handle a subsequent because of the RSET.  So refuse to support any. */
-      cancel_cutthrough_connection("random-recipient");
+      /* This would be ok for 1st rcpt of a cutthrough (the case handled here;
+      subsequents are done in cutthrough_multi()), but no way to
+      handle a subsequent because of the RSET vaporising the MAIL FROM.
+      So refuse to support any.  Most cutthrough use will not involve
+      random_local_part, so no loss. */
+      cancel_cutthrough_connection(TRUE, US"random-recipient");
 
       addr->address = string_sprintf("%s@%.1000s",
                                    random_local_part, rcpt_domain);
@@ -778,26 +783,33 @@ tls_retry_connection:
       postmaster-verify.
       The sync_responses() would need to be taught about it and we'd
       need another return code filtering out to here.
+
+      Avoid using a SIZE option on the MAIL for all randon-rcpt checks.
       */
 
+      sx.avoid_option = OPTION_SIZE;
+
       /* Remember when we last did a random test */
       new_domain_record.random_stamp = time(NULL);
 
       if (smtp_write_mail_and_rcpt_cmds(&sx, &yield) == 0)
        switch(addr->transport_return)
          {
-         case PENDING_OK:
+         case PENDING_OK:      /* random was accepted, unfortunately */
            new_domain_record.random_result = ccache_accept;
-           break;
-         case FAIL:
+           yield = OK;         /* Only usable verify result we can return */
+           done = TRUE;
+           goto no_conn;
+         case FAIL:            /* rejected: the preferred result */
            new_domain_record.random_result = ccache_reject;
+           sx.avoid_option = 0;
 
            /* Between each check, issue RSET, because some servers accept only
            one recipient after MAIL FROM:<>.
            XXX We don't care about that for postmaster_full.  Should we? */
 
            if ((done =
-             smtp_write_command(&sx.outblock, FALSE, "RSET\r\n") >= 0 &&
+             smtp_write_command(&sx.outblock, SCMD_FLUSH, "RSET\r\n") >= 0 &&
              smtp_read_response(&sx.inblock, sx.buffer, sizeof(sx.buffer),
                '2', callout)))
              break;
@@ -822,6 +834,8 @@ tls_retry_connection:
            sx.send_rset = TRUE;
            sx.completed_addr = FALSE;
            goto tls_retry_connection;
+         case DEFER:           /* 4xx response to random */
+           break;              /* Just to be clear. ccache_unknown, !done. */
          }
 
       /* Re-setup for main verify, or for the error message when failing */
@@ -835,12 +849,14 @@ tls_retry_connection:
     else
       done = TRUE;
 
-    /* Main verify. If the host is accepting all local parts, as determined
-    by the "random" check, we don't need to waste time doing any further
-    checking. */
+    /* Main verify.  For rcpt-verify use SIZE if we know it and we're not cacheing;
+    for sndr-verify never use it. */
 
     if (done)
       {
+      if (!(options & vopt_is_recipient  &&  options & vopt_callout_no_cache))
+       sx.avoid_option = OPTION_SIZE;
+
       done = FALSE;
       switch(smtp_write_mail_and_rcpt_cmds(&sx, &yield))
        {
@@ -849,12 +865,12 @@ tls_retry_connection:
                    case PENDING_OK:  done = TRUE;
                                      new_address_record.result = ccache_accept;
                                      break;
-                   case FAIL:        done = TRUE;
+                   case FAIL:      done = TRUE;
                                      yield = FAIL;
                                      *failure_ptr = US"recipient";
                                      new_address_record.result = ccache_reject;
                                      break;
-                   default:          break;
+                   default:        break;
                    }
                  break;
 
@@ -887,10 +903,10 @@ tls_retry_connection:
       /* Could possibly shift before main verify, just above, and be ok
       for cutthrough.  But no way to handle a subsequent rcpt, so just
       refuse any */
-      cancel_cutthrough_connection("postmaster verify");
+      cancel_cutthrough_connection(TRUE, US"postmaster verify");
       HDEBUG(D_acl|D_v) debug_printf_indent("Cutthrough cancelled by presence of postmaster verify\n");
 
-      done = smtp_write_command(&sx.outblock, FALSE, "RSET\r\n") >= 0
+      done = smtp_write_command(&sx.outblock, SCMD_FLUSH, "RSET\r\n") >= 0
           && smtp_read_response(&sx.inblock, sx.buffer,
                                sizeof(sx.buffer), '2', callout);
 
@@ -907,6 +923,7 @@ tls_retry_connection:
        sx.ok = FALSE;
        sx.send_rset = TRUE;
        sx.completed_addr = FALSE;
+       sx.avoid_option = OPTION_SIZE;
 
        if(  smtp_write_mail_and_rcpt_cmds(&sx, &yield) == 0
          && addr->transport_return == PENDING_OK
@@ -914,7 +931,7 @@ tls_retry_connection:
          done = TRUE;
        else
          done = (options & vopt_callout_fullpm) != 0
-             && smtp_write_command(&sx.outblock, FALSE,
+             && smtp_write_command(&sx.outblock, SCMD_FLUSH,
                            "RCPT TO:<postmaster>\r\n") >= 0
              && smtp_read_response(&sx.inblock, sx.buffer,
                            sizeof(sx.buffer), '2', callout);
@@ -976,7 +993,7 @@ no_conn:
        if (*sx.buffer == 0) Ustrcpy(sx.buffer, US"connection dropped");
 
        /*XXX test here is ugly; seem to have a split of responsibility for
-       building this message.  Need to reationalise.  Where is it done
+       building this message.  Need to rationalise.  Where is it done
        before here, and when not?
        Not == 5xx resp to MAIL on main-verify
        */
@@ -1003,8 +1020,10 @@ no_conn:
 
     /* Cutthrough - on a successful connect and recipient-verify with
     use-sender and we are 1st rcpt and have no cutthrough conn so far
-    here is where we want to leave the conn open */
-    if (  cutthrough.delivery
+    here is where we want to leave the conn open.  Ditto for a lazy-close
+    verify. */
+
+    if (  (cutthrough.delivery || options & vopt_callout_hold)
        && rcpt_count == 1
        && done
        && yield == OK
@@ -1016,14 +1035,29 @@ no_conn:
        && !sx.lmtp
        )
       {
-      HDEBUG(D_acl|D_v) debug_printf_indent("holding verify callout open for cutthrough delivery\n");
-
-      cutthrough.fd = sx.outblock.sock;        /* We assume no buffer in use in the outblock */
-      cutthrough.nrcpt = 1;
-      cutthrough.interface = interface;
-      cutthrough.host = *host;
-      cutthrough.addr = *addr;         /* Save the address_item for later logging */
-      cutthrough.addr.next =     NULL;
+      HDEBUG(D_acl|D_v) debug_printf_indent("holding verify callout open for %s\n",
+       cutthrough.delivery
+       ? "cutthrough delivery" : "potential further verifies and delivery");
+
+      cutthrough.callout_hold_only = !cutthrough.delivery;
+      cutthrough.is_tls =      tls_out.active >= 0;
+      cutthrough.fd =  sx.outblock.sock;       /* We assume no buffer in use in the outblock */
+      cutthrough.nrcpt =       1;
+      cutthrough.transport =   addr->transport->name;
+      cutthrough.interface =   interface;
+      cutthrough.snd_port =    sending_port;
+      cutthrough.peer_options =        smtp_peer_options;
+      cutthrough.host =                *host;
+       {
+       int oldpool = store_pool;
+       store_pool = POOL_PERM;
+       cutthrough.snd_ip = string_copy(sending_ip_address);
+       cutthrough.host.name = string_copy(host->name);
+       cutthrough.host.address = string_copy(host->address);
+       store_pool = oldpool;
+       }
+      cutthrough.addr =                *addr;          /* Save the address_item for later logging */
+      cutthrough.addr.next =   NULL;
       cutthrough.addr.host_used = &cutthrough.host;
       if (addr->parent)
         *(cutthrough.addr.parent = store_get(sizeof(address_item))) =
@@ -1036,12 +1070,12 @@ no_conn:
       }
     else
       {
-      /* Ensure no cutthrough on multiple address verifies */
+      /* Ensure no cutthrough on multiple verifies that were incompatible */
       if (options & vopt_callout_recipsender)
-        cancel_cutthrough_connection("not usable for cutthrough");
+        cancel_cutthrough_connection(TRUE, US"not usable for cutthrough");
       if (sx.send_quit)
        {
-       (void) smtp_write_command(&sx.outblock, FALSE, "QUIT\r\n");
+       (void) smtp_write_command(&sx.outblock, SCMD_FLUSH, "QUIT\r\n");
 
        /* Wait a short time for response, and discard it */
        smtp_read_response(&sx.inblock, sx.buffer, sizeof(sx.buffer),
@@ -1153,7 +1187,7 @@ if(cutthrough.fd < 0)
 
 if(
 #ifdef SUPPORT_TLS
-   (tls_out.active == cutthrough.fd) ? tls_write(FALSE, ctblock.buffer, n) :
+   tls_out.active == cutthrough.fd ? tls_write(FALSE, ctblock.buffer, n, FALSE) :
 #endif
    send(cutthrough.fd, ctblock.buffer, n, 0) > 0
   )
@@ -1184,20 +1218,27 @@ return TRUE;
 }
 
 /* Buffered output of counted data block.   Return boolean success */
-BOOL
+static BOOL
 cutthrough_puts(uschar * cp, int n)
 {
 if (cutthrough.fd < 0)       return TRUE;
 if (_cutthrough_puts(cp, n)) return TRUE;
-cancel_cutthrough_connection("transmit failed");
+cancel_cutthrough_connection(TRUE, US"transmit failed");
 return FALSE;
 }
 
+void
+cutthrough_data_puts(uschar * cp, int n)
+{
+if (cutthrough.delivery) (void) cutthrough_puts(cp, n);
+return;
+}
+
 
 static BOOL
 _cutthrough_flush_send(void)
 {
-int n= ctblock.ptr-ctblock.buffer;
+int n = ctblock.ptr - ctblock.buffer;
 
 if(n>0)
   if(!cutthrough_send(n))
@@ -1211,21 +1252,28 @@ BOOL
 cutthrough_flush_send(void)
 {
 if (_cutthrough_flush_send()) return TRUE;
-cancel_cutthrough_connection("transmit failed");
+cancel_cutthrough_connection(TRUE, US"transmit failed");
 return FALSE;
 }
 
 
-BOOL
+static BOOL
 cutthrough_put_nl(void)
 {
 return cutthrough_puts(US"\r\n", 2);
 }
 
 
+void
+cutthrough_data_put_nl(void)
+{
+cutthrough_data_puts(US"\r\n", 2);
+}
+
+
 /* Get and check response from cutthrough target */
 static uschar
-cutthrough_response(char expect, uschar ** copy, int timeout)
+cutthrough_response(int fd, char expect, uschar ** copy, int timeout)
 {
 smtp_inblock inblock;
 uschar inbuffer[4096];
@@ -1235,12 +1283,12 @@ inblock.buffer = inbuffer;
 inblock.buffersize = sizeof(inbuffer);
 inblock.ptr = inbuffer;
 inblock.ptrend = inbuffer;
-inblock.sock = cutthrough.fd;
+inblock.sock = fd;
 /* this relies on (inblock.sock == tls_out.active) */
 if(!smtp_read_response(&inblock, responsebuffer, sizeof(responsebuffer), expect, timeout))
-  cancel_cutthrough_connection("target timeout on read");
+  cancel_cutthrough_connection(TRUE, US"target timeout on read");
 
-if(copy != NULL)
+if(copy)
   {
   uschar * cp;
   *copy = cp = string_copy(responsebuffer);
@@ -1258,7 +1306,7 @@ return responsebuffer[0];
 BOOL
 cutthrough_predata(void)
 {
-if(cutthrough.fd < 0)
+if(cutthrough.fd < 0 || cutthrough.callout_hold_only)
   return FALSE;
 
 HDEBUG(D_transport|D_acl|D_v) debug_printf_indent("  SMTP>> DATA\n");
@@ -1266,13 +1314,13 @@ cutthrough_puts(US"DATA\r\n", 6);
 cutthrough_flush_send();
 
 /* Assume nothing buffered.  If it was it gets ignored. */
-return cutthrough_response('3', NULL, CUTTHROUGH_DATA_TIMEOUT) == '3';
+return cutthrough_response(cutthrough.fd, '3', NULL, CUTTHROUGH_DATA_TIMEOUT) == '3';
 }
 
 
-/* fd and tctx args only to match write_chunk() */
+/* tctx arg only to match write_chunk() */
 static BOOL
-cutthrough_write_chunk(int fd, transport_ctx * tctx, uschar * s, int len)
+cutthrough_write_chunk(transport_ctx * tctx, uschar * s, int len)
 {
 uschar * s2;
 while(s && (s2 = Ustrchr(s, '\n')))
@@ -1293,7 +1341,7 @@ cutthrough_headers_send(void)
 {
 transport_ctx tctx;
 
-if(cutthrough.fd < 0)
+if(cutthrough.fd < 0 || cutthrough.callout_hold_only)
   return FALSE;
 
 /* We share a routine with the mainline transport to handle header add/remove/rewrites,
@@ -1301,13 +1349,15 @@ if(cutthrough.fd < 0)
 */
 HDEBUG(D_acl) debug_printf_indent("----------- start cutthrough headers send -----------\n");
 
+tctx.u.fd = cutthrough.fd;
 tctx.tblock = cutthrough.addr.transport;
 tctx.addr = &cutthrough.addr;
 tctx.check_string = US".";
 tctx.escape_string = US"..";
+/*XXX check under spool_files_wireformat.  Might be irrelevant */
 tctx.options = topt_use_crlf;
 
-if (!transport_headers_send(cutthrough.fd, &tctx, &cutthrough_write_chunk))
+if (!transport_headers_send(&tctx, &cutthrough_write_chunk))
   return FALSE;
 
 HDEBUG(D_acl) debug_printf_indent("----------- done cutthrough headers send ------------\n");
@@ -1316,9 +1366,10 @@ return TRUE;
 
 
 static void
-close_cutthrough_connection(const char * why)
+close_cutthrough_connection(const uschar * why)
 {
-if(cutthrough.fd >= 0)
+int fd = cutthrough.fd;
+if(fd >= 0)
   {
   /* We could be sending this after a bunch of data, but that is ok as
      the only way to cancel the transfer in dataphase is to drop the tcp
@@ -1328,26 +1379,37 @@ if(cutthrough.fd >= 0)
   HDEBUG(D_transport|D_acl|D_v) debug_printf_indent("  SMTP>> QUIT\n");
   _cutthrough_puts(US"QUIT\r\n", 6);   /* avoid recursion */
   _cutthrough_flush_send();
+  cutthrough.fd = -1;                  /* avoid recursion via read timeout */
 
   /* Wait a short time for response, and discard it */
-  cutthrough_response('2', NULL, 1);
+  cutthrough_response(fd, '2', NULL, 1);
 
-  #ifdef SUPPORT_TLS
+#ifdef SUPPORT_TLS
   tls_close(FALSE, TRUE);
-  #endif
+#endif
   HDEBUG(D_transport|D_acl|D_v) debug_printf_indent("  SMTP(close)>>\n");
-  (void)close(cutthrough.fd);
-  cutthrough.fd = -1;
+  (void)close(fd);
   HDEBUG(D_acl) debug_printf_indent("----------- cutthrough shutdown (%s) ------------\n", why);
   }
 ctblock.ptr = ctbuffer;
 }
 
 void
-cancel_cutthrough_connection(const char * why)
+cancel_cutthrough_connection(BOOL close_noncutthrough_verifies, const uschar * why)
 {
-close_cutthrough_connection(why);
-cutthrough.delivery = FALSE;
+if (cutthrough.delivery || close_noncutthrough_verifies)
+  close_cutthrough_connection(why);
+cutthrough.delivery = cutthrough.callout_hold_only = FALSE;
+}
+
+
+void
+release_cutthrough_connection(const uschar * why)
+{
+if (cutthrough.fd < 0) return;
+HDEBUG(D_acl) debug_printf_indent("release cutthrough conn: %s\n", why);
+cutthrough.fd = -1;
+cutthrough.delivery = cutthrough.callout_hold_only = FALSE;
 }
 
 
@@ -1372,7 +1434,7 @@ if(  !cutthrough_puts(US".", 1)
   )
   return cutthrough.addr.message;
 
-res = cutthrough_response('2', &cutthrough.addr.message, CUTTHROUGH_DATA_TIMEOUT);
+res = cutthrough_response(cutthrough.fd, '2', &cutthrough.addr.message, CUTTHROUGH_DATA_TIMEOUT);
 for (addr = &cutthrough.addr; addr; addr = addr->next)
   {
   addr->message = cutthrough.addr.message;
@@ -1380,7 +1442,7 @@ for (addr = &cutthrough.addr; addr; addr = addr->next)
     {
     case '2':
       delivery_log(LOG_MAIN, addr, (int)'>', NULL);
-      close_cutthrough_connection("delivered");
+      close_cutthrough_connection(US"delivered");
       break;
 
     case '4':
@@ -1465,7 +1527,7 @@ va_list ap;
 
 va_start(ap, format);
 if (smtp_out && (f == smtp_out))
-  smtp_vprintf(format, ap);
+  smtp_vprintf(format, FALSE, ap);
 else
   vfprintf(f, format, ap);
 va_end(ap);
@@ -1727,16 +1789,16 @@ while (addr_new)
       transport. */
 
       transport_feedback tf = {
-        NULL,                       /* interface (=> any) */
-        US"smtp",                   /* port */
-        US"smtp",                   /* protocol */
-        NULL,                       /* hosts */
-        US"$smtp_active_hostname",  /* helo_data */
-        FALSE,                      /* hosts_override */
-        FALSE,                      /* hosts_randomize */
-        FALSE,                      /* gethostbyname */
-        TRUE,                       /* qualify_single */
-        FALSE                       /* search_parents */
+        .interface =           NULL,                       /* interface (=> any) */
+        .port =                        US"smtp",
+        .protocol =            US"smtp",
+        .hosts =               NULL,
+        .helo_data =           US"$smtp_active_hostname",
+        .hosts_override =      FALSE,
+        .hosts_randomize =     FALSE,
+        .gethostbyname =       FALSE,
+        .qualify_single =      TRUE,
+        .search_parents =      FALSE
         };
 
       /* If verification yielded a remote transport, we want to use that
@@ -1879,7 +1941,7 @@ while (addr_new)
         }
       respond_printf(f, "%s\n", cr);
       }
-    cancel_cutthrough_connection("routing hard fail");
+    cancel_cutthrough_connection(TRUE, US"routing hard fail");
 
     if (!full_info)
       {
@@ -1918,7 +1980,7 @@ while (addr_new)
         }
       respond_printf(f, "%s\n", cr);
       }
-    cancel_cutthrough_connection("routing soft fail");
+    cancel_cutthrough_connection(TRUE, US"routing soft fail");
 
     if (!full_info)
       {
@@ -1991,7 +2053,7 @@ while (addr_new)
       /* If stopped because more than one new address, cannot cutthrough */
 
       if (addr_new && addr_new->next)
-       cancel_cutthrough_connection("multiple addresses from routing");
+       cancel_cutthrough_connection(TRUE, US"multiple addresses from routing");
 
       yield = OK;
       goto out;
@@ -2241,18 +2303,16 @@ verify_check_header_names_ascii(uschar **msgptr)
 header_line *h;
 uschar *colon, *s;
 
-for (h = header_list; h != NULL; h = h->next)
+for (h = header_list; h; h = h->next)
   {
-   colon = Ustrchr(h->text, ':');
-   for(s = h->text; s < colon; s++)
-     {
-        if ((*s < 33) || (*s > 126))
-        {
-                *msgptr = string_sprintf("Invalid character in header \"%.*s\" found",
-                                         colon - h->text, h->text);
-                return FAIL;
-        }
-     }
+  colon = Ustrchr(h->text, ':');
+  for(s = h->text; s < colon; s++)
+    if ((*s < 33) || (*s > 126))
+      {
+      *msgptr = string_sprintf("Invalid character in header \"%.*s\" found",
+                            colon - h->text, h->text);
+      return FAIL;
+      }
   }
 return OK;
 }
@@ -2622,8 +2682,11 @@ if (ip_bind(sock, host_af, interface_address, 0) < 0)
   goto END_OFF;
   }
 
+/*XXX could take advantage of TFO early-data.  Hmm, what are the
+error returns; can we differentiate connect from data fails?
+Do we need to? */
 if (ip_connect(sock, host_af, sender_host_address, port,
-               rfc1413_query_timeout, TRUE) < 0)
+               rfc1413_query_timeout, &tcp_fastopen_nodata) < 0)
   {
   if (errno == ETIMEDOUT && LOGGING(ident_timeout))
     log_write(0, LOG_MAIN, "ident connection to %s timed out",
@@ -3094,18 +3157,16 @@ verify_check_this_host(const uschar **listptr, unsigned int *cache_bits,
 int rc;
 unsigned int *local_cache_bits = cache_bits;
 const uschar *save_host_address = deliver_host_address;
-check_host_block cb;
-cb.host_name = host_name;
-cb.host_address = host_address;
+check_host_block cb = { .host_name = host_name, .host_address = host_address };
 
-if (valueptr != NULL) *valueptr = NULL;
+if (valueptr) *valueptr = NULL;
 
 /* If the host address starts off ::ffff: it is an IPv6 address in
 IPv4-compatible mode. Find the IPv4 part for checking against IPv4
 addresses. */
 
-cb.host_ipv4 = (Ustrncmp(host_address, "::ffff:", 7) == 0)?
-  host_address + 7 : host_address;
+cb.host_ipv4 = Ustrncmp(host_address, "::ffff:", 7) == 0
+  host_address + 7 : host_address;
 
 /* During the running of the check, put the IP address into $host_address. In
 the case of calls from the smtp transport, it will already be there. However,
index 04a2d07337f8d185c9bc41950e91d83d3ea681c1..f27cc3cde679cca06a5fa5acdef3fbd63804c7c7 100644 (file)
@@ -40,6 +40,16 @@ version_cnumber_format = US"%d\0<<eximcnumber>>";
 sprintf(CS version_cnumber, CS version_cnumber_format, cnumber);
 version_string = US EXIM_VERSION_STR "\0<<eximversion>>";
 
+#ifdef EXIM_BUILD_DATE_OVERRIDE
+/* Reproducible build support; build tooling should have given us something looking like
+ * "25-Feb-2017 20:15:40" in EXIM_BUILD_DATE_OVERRIDE based on $SOURCE_DATE_EPOCH in environ
+ * per <https://reproducible-builds.org/specs/source-date-epoch/>
+ */
+version_date = date_buffer;
+version_date[0] = 0;
+Ustrncat(version_date, EXIM_BUILD_DATE_OVERRIDE, sizeof(date_buffer));
+
+#else
 Ustrcpy(today, __DATE__);
 if (today[4] == ' ') today[4] = '0';
 today[3] = today[6] = '-';
@@ -51,6 +61,7 @@ Ustrncat(version_date, today, 4);
 Ustrncat(version_date, today+7, 4);
 Ustrcat(version_date, " ");
 Ustrcat(version_date, __TIME__);
+#endif
 }
 
 /* End of version.c */
index ae5a309b972e3ba0a57d1c184226ff1eaa8d52c6..cb057386eaed0306ec8a0f1f553c91cc88e313a6 100644 (file)
@@ -67,7 +67,7 @@ mail:
 rcpt:
   accept senders = +ok_senders
          sender_domains = +ok_sender_domains
-         logwrite = :panic: rcpt accepted
+         logwrite = :panic: rcpt accepted C=$smtp_command_history
 
 # ----- Routers -----
 
index 96f3beac19c333913dbb16b52e1b5ab8de19f977..7856481dffece63df6957d865c0fb976de09aebb 100644 (file)
@@ -30,7 +30,11 @@ begin routers
 others:
   driver = manualroute
   domains = ! +local_domains
-  route_list = * localhost4.test.ex byname
+.ifdef LIST
+  route_data = 127.0.0.1:HOSTIPV4
+.else
+  route_data = localhost4.test.ex byname
+.endif
   self = send
   transport = smtp
   no_more
@@ -48,6 +52,7 @@ begin transports
 smtp:
   driver = smtp
   port = PORT_S
+  command_timeout = 1s
 
 local_delivery:
   driver = appendfile
index ed988ac85d81a6e15301312a4f2271d02c640b60..fea66e16f8d7b950f9a91350e970bd4ff582353a 100644 (file)
@@ -24,6 +24,8 @@ check_recipient:
          !verify   = sender/callout=no_cache
   deny    hosts    = V4NET.0.0.3
          !verify   = recipient/callout=no_cache
+  deny    hosts    = V4NET.0.0.7
+         !verify   = recipient/callout=no_cache,use_sender,random
   deny    hosts    = V4NET.0.0.5
          !verify   = sender/callout=no_cache/check_postmaster
   deny    hosts    = V4NET.0.0.6
index 5d172447eec07416253d7ce0ef32824e324fe9ee..f3442b25b591cdba6baaca9783d48073790c2aaa 100644 (file)
@@ -1,6 +1,7 @@
 # Exim test configuration 0547
 
 MAXNM = 100
+LOG_SELECTOR =
 
 .include DIR/aux-var/std_conf_prefix
 
@@ -10,7 +11,7 @@ primary_hostname = myhost.test.ex
 
 acl_smtp_rcpt = accept
 
-log_selector = +smtp_no_mail
+log_selector = +smtp_no_mail LOG_SELECTOR
 
 smtp_accept_max_nonmail = MAXNM
 
diff --git a/test/confs/0580 b/test/confs/0580
new file mode 100644 (file)
index 0000000..54ef7ae
--- /dev/null
@@ -0,0 +1,46 @@
+# Exim test configuration 0580
+
+OPT =
+
+.include DIR/aux-var/std_conf_prefix
+
+primary_hostname = myhost.test.ex
+
+# ----- Main settings -----
+
+acl_smtp_rcpt = check_rcpt
+
+log_selector = +received_recipients
+OPT
+
+# ----- ACLs -----
+
+begin acl
+
+check_rcpt:
+  accept  verify = recipient/callout=use_sender,hold
+
+
+# ----- Routers -----
+
+begin routers
+
+r1:
+  driver = manualroute
+  route_list = * 127.0.0.1
+  self = send
+  transport = t1
+
+
+begin transports
+
+t1:
+  driver = smtp
+  port =   PORT_S
+
+
+# ----- Retry -----
+begin retry
+
+* * F,5d,10s
+# End
diff --git a/test/confs/0581 b/test/confs/0581
new file mode 120000 (symlink)
index 0000000..35e8a25
--- /dev/null
@@ -0,0 +1 @@
+0580
\ No newline at end of file
diff --git a/test/confs/0582 b/test/confs/0582
new file mode 120000 (symlink)
index 0000000..35e8a25
--- /dev/null
@@ -0,0 +1 @@
+0580
\ No newline at end of file
diff --git a/test/confs/0906 b/test/confs/0906
new file mode 100644 (file)
index 0000000..0c7b83d
--- /dev/null
@@ -0,0 +1,97 @@
+# Exim test configuration 0906
+SERVER=
+
+exim_path = EXIM_PATH
+keep_environment =
+host_lookup_order = bydns
+spool_directory = DIR/spool
+log_file_path = DIR/spool/log/SERVER%slog
+gecos_pattern = ""
+gecos_name = CALLER_NAME
+chunking_advertise_hosts = *
+tls_advertise_hosts = ${if eq {SRV}{tls} {*}}
+
+# ----- Main settings -----
+
+spool_wireformat = true
+
+primary_hostname = testhost.test.ex
+domainlist local_domains = @ : test.ex
+
+acl_smtp_rcpt = acl_r
+log_selector = +received_recipients
+
+.ifdef _OPT_MAIN_TLS_CERTIFICATE
+tls_certificate = DIR/aux-fixed/cert1
+tls_privatekey = DIR/aux-fixed/cert1
+.endif
+
+queue_run_in_order = true
+
+# ----- ACL -----
+
+begin acl
+acl_r:
+ accept        condition = ${if != {$received_port}{PORT_S}}
+       control = queue_only
+ accept
+
+# ----- Routers -----
+
+begin routers
+
+to_server:
+  driver = accept
+  condition =  ${if = {$received_port}{PORT_S}}
+  transport =  remote_smtp${if eq {OPT}{dkim} {_dkim}}
+  errors_to =  ""
+
+fail_remote_domains:
+  driver = redirect
+  domains = ! +local_domains
+  data = :fail: unrouteable mail domain "$domain"
+
+localuser:
+  driver = accept
+  transport = local_delivery
+
+
+# ----- Transports -----
+
+begin transports
+
+local_delivery:
+  driver = appendfile
+  file = DIR/test-mail/$local_part
+  headers_add = "X-body-linecount: $body_linecount\n\
+                 X-message-linecount: $message_linecount\n\
+                 X-received-count: $received_count"
+  return_path_add
+  user = CALLER
+
+remote_smtp:
+  driver = smtp
+  hosts =      127.0.0.1
+  port =       PORT_D
+  allow_localhost
+
+remote_smtp_dkim:
+  driver = smtp
+  hosts =      127.0.0.1
+  port =       PORT_D
+  allow_localhost
+
+.ifdef OPT
+  dkim_domain =                test.ex
+  dkim_selector =      sel
+  dkim_private_key =   DIR/aux-fixed/dkim/dkim.private
+.ifndef HEADERS_MAXSIZE
+  dkim_sign_headers =  LIST
+.endif
+.endif
+
+# ----- Retry -----
+
+begin retry
+* * F,30m,5m;
+# End
diff --git a/test/confs/0907 b/test/confs/0907
new file mode 100644 (file)
index 0000000..8cb2b1b
--- /dev/null
@@ -0,0 +1,3 @@
+# This file contains a BOM at the very beginning
+tls_advertise_hosts =
+keep_environment =
diff --git a/test/confs/0908 b/test/confs/0908
new file mode 100644 (file)
index 0000000..27af1d5
--- /dev/null
@@ -0,0 +1 @@
+.include DIR/confs/0907
diff --git a/test/confs/1990 b/test/confs/1990
new file mode 100644 (file)
index 0000000..4c2bdc2
--- /dev/null
@@ -0,0 +1,48 @@
+# Exim test configuration 1990
+# TCP Fast Open
+
+SERVER=
+
+.include DIR/aux-var/std_conf_prefix
+
+primary_hostname = myhost.test.ex
+
+# ----- Main settings -----
+
+acl_smtp_rcpt = accept
+log_selector = +received_recipients +millisec
+
+# ----- Routers -----
+
+begin routers
+
+server:
+  driver = redirect
+  condition = ${if eq {SERVER}{server} {yes}{no}}
+  data = :blackhole:
+
+client:
+  driver = accept
+  condition = ${if eq {SERVER}{server}{no}{yes}}
+  transport = send_to_server
+
+
+# ----- Transports -----
+
+begin transports
+
+send_to_server:
+  driver = smtp
+  allow_localhost
+  hosts = 127.0.0.1
+  port = PORT_D
+  hosts_try_fastopen = *
+
+# ----- Retry -----
+
+begin retry
+
+* * F,5d,10s
+
+
+# End
index 7b58b73ee5e7285541b04d52a3b3d6d9afb09c35..a16b9a57ef5faf79b4a03e2fb9d934083809eb40 100644 (file)
@@ -16,6 +16,7 @@ queue_only
 queue_run_in_order
 
 tls_advertise_hosts = *
+tls_require_ciphers = NORMAL:!DHE-RSA:!DHE-DSS:!ECDHE-RSA:!ECDHE-ECDSA:!ECDHE-PSK
 
 # Set certificate only if server
 
index 45d683cb4265e0e4106e60e73a58b9fad631901d..208e17c41152f318dd9a6fd1115c07c190698018 100644 (file)
@@ -29,6 +29,15 @@ tls_privatekey = ${if eq {SERVER}{server}{DIR/aux-fixed/cert1}fail}
 
 begin routers
 
+.ifdef REQUIRE
+cl_override:
+  driver = manualroute
+  route_data = HOSTIPV4
+  retry_use_local_part
+  transport = send_to_server
+  self = send
+.endif
+
 client:
   driver = accept
   condition = ${if eq {SERVER}{server}{no}{yes}}
@@ -54,8 +63,10 @@ local_delivery:
 send_to_server:
   driver = smtp
   allow_localhost
+  hosts_override
   hosts = 127.0.0.1
   hosts_noproxy_tls = :
   port = PORT_D
+  tls_try_verify_hosts = :
 
 # End
diff --git a/test/confs/2035 b/test/confs/2035
new file mode 100644 (file)
index 0000000..f7f2257
--- /dev/null
@@ -0,0 +1,77 @@
+# Exim test configuration 2135
+
+.include DIR/aux-var/tls_conf_prefix
+
+.ifdef SERVER
+tls_certificate = DIR/aux-fixed/exim-ca/example.com/server1.example.com/server1.example.com.chain.pem
+tls_privatekey = DIR/aux-fixed/exim-ca/example.com/server1.example.com/server1.example.com.unlocked.key
+.else
+tls_advertise_hosts =
+.endif
+
+primary_hostname = myhost.test.ex
+
+# ----- Main settings -----
+
+.ifdef SERVER
+acl_smtp_rcpt = srvr_rcpt
+acl_smtp_data = srvr_data
+.else
+acl_smtp_rcpt = client_rcpt
+acl_smtp_data = client_data
+.endif
+
+log_selector = +received_recipients +outgoing_port
+
+.ifdef SERVER
+queue_only
+queue_run_in_order = true
+.endif
+
+# ----- ACLs -----
+
+begin acl
+
+client_rcpt:
+  accept
+       verify =        recipient/callout=use_sender,hold
+
+client_data:
+  accept
+
+srvr_rcpt:
+  defer        local_parts =   rcpt_defer
+  accept
+
+srvr_data:
+  defer        condition =     ${if eq {data_defer}{${local_part:$recipients}}}
+  accept
+
+# ----- Routers -----
+
+begin routers
+
+target:
+  driver =     redirect
+  condition =  ${if or {{eq {SERVER}{server}} {queue_running}}}
+  data =       :blackhole:
+
+client:
+  driver =     manualroute
+  route_list=  * 127.0.0.1::PORT_D
+  self =       send
+  transport =  t1
+  errors_to =  ""
+
+begin transports
+
+t1:
+  driver =     smtp
+  tls_verify_certificates =    DIR/aux-fixed/exim-ca/example.com/CA/CA.pem
+  tls_verify_cert_hostnames =  :
+
+# ----- Retry -----
+begin retry
+
+* * F,5d,10s
+# End
diff --git a/test/confs/2036 b/test/confs/2036
new file mode 120000 (symlink)
index 0000000..3f3e22d
--- /dev/null
@@ -0,0 +1 @@
+2035
\ No newline at end of file
diff --git a/test/confs/2037 b/test/confs/2037
new file mode 120000 (symlink)
index 0000000..3f3e22d
--- /dev/null
@@ -0,0 +1 @@
+2035
\ No newline at end of file
diff --git a/test/confs/2038 b/test/confs/2038
new file mode 100644 (file)
index 0000000..1408194
--- /dev/null
@@ -0,0 +1,63 @@
+# Exim test configuration 2035
+
+SERVER =
+
+.include DIR/aux-var/tls_conf_prefix
+
+primary_hostname = myhost.test.ex
+
+# ----- Main settings -----
+
+acl_smtp_rcpt = accept
+
+log_selector = +tls_peerdn+smtp_connection+incoming_port+received_recipients
+
+queue_only
+queue_run_in_order
+
+smtp_accept_max_nonmail = 0
+
+tls_advertise_hosts = *
+
+# Set certificate only if server
+
+tls_certificate = ${if eq {SERVER}{server}{DIR/aux-fixed/cert1}fail}
+tls_privatekey = ${if eq {SERVER}{server}{DIR/aux-fixed/cert1}fail}
+
+
+# ----- Routers -----
+
+begin routers
+
+client:
+  driver =     manualroute
+  condition =  ${if eq {SERVER}{server}{no}{yes}}
+  route_data = 127.0.0.1
+  self =       send
+  retry_use_local_part
+  transport =  send_to_server
+
+server:
+  driver = accept
+  retry_use_local_part
+  transport = local_delivery
+
+
+# ----- Transports -----
+
+begin transports
+
+local_delivery:
+  driver = appendfile
+  file = DIR/test-mail/$local_part
+  headers_add = TLS: cipher=$tls_cipher peerdn=$tls_peerdn
+  user = CALLER
+
+send_to_server:
+  driver =     smtp
+  allow_localhost
+  hosts_noproxy_tls = :
+  port =       PORT_D
+  max_rcpt =   1
+
+# End
diff --git a/test/confs/2052 b/test/confs/2052
deleted file mode 100644 (file)
index fd1f4d1..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
-# Exim test configuration 2052
-# as per 2000 but with TCP Fast Open
-
-SERVER=
-
-.include DIR/aux-var/tls_conf_prefix
-
-primary_hostname = myhost.test.ex
-
-# ----- Main settings -----
-
-acl_smtp_rcpt = accept
-
-log_selector =  +tls_peerdn
-
-queue_only
-queue_run_in_order
-
-tls_advertise_hosts = *
-# needed to force generation
-tls_dhparam = historic
-
-# Set certificate only if server
-
-tls_certificate = ${if eq {SERVER}{server}{DIR/aux-fixed/cert1}fail}
-tls_privatekey = ${if eq {SERVER}{server}{DIR/aux-fixed/cert1}fail}
-
-tls_verify_hosts = *
-tls_verify_certificates = ${if eq {SERVER}{server}{DIR/aux-fixed/cert2}fail}
-
-
-# ----- Routers -----
-
-begin routers
-
-client:
-  driver = accept
-  condition = ${if eq {SERVER}{server}{no}{yes}}
-  retry_use_local_part
-  transport = send_to_server
-
-
-# ----- Transports -----
-
-begin transports
-
-send_to_server:
-  driver = smtp
-  allow_localhost
-  hosts = 127.0.0.1
-  port = PORT_D
-  hosts_try_fastopen = *
-  tls_certificate = DIR/aux-fixed/cert2
-  tls_privatekey = DIR/aux-fixed/cert2
-  tls_verify_certificates = DIR/aux-fixed/cert2
-  tls_try_verify_hosts =
-
-
-# ----- Retry -----
-
-
-begin retry
-
-* * F,5d,10s
-
-
-# End
index 9487445ccae2652e6d2487f9bf60513f00262d3e..67936731531ba8b35aec45297cd8ef4e4eec1880 100644 (file)
@@ -16,6 +16,7 @@ queue_only
 queue_run_in_order
 
 tls_advertise_hosts = *
+tls_require_ciphers = AES256-SHA
 
 # Set certificate only if server
 
index bb64867a92c5d951c4d3b8108240db915fc62834..95b6842a95ad83f15b811ca451f42374a14a510c 100644 (file)
@@ -29,6 +29,15 @@ tls_privatekey = ${if eq {SERVER}{server}{DIR/aux-fixed/cert1}fail}
 
 begin routers
 
+.ifdef REQUIRE
+cl_override:
+  driver = manualroute
+  route_data = HOSTIPV4
+  retry_use_local_part
+  transport = send_to_server
+  self = send
+.endif
+
 client:
   driver = accept
   condition = ${if eq {SERVER}{server}{no}{yes}}
@@ -54,6 +63,7 @@ local_delivery:
 send_to_server:
   driver = smtp
   allow_localhost
+  hosts_override
   hosts = 127.0.0.1
   hosts_noproxy_tls = :
   port = PORT_D
diff --git a/test/confs/2135 b/test/confs/2135
new file mode 100644 (file)
index 0000000..f7f2257
--- /dev/null
@@ -0,0 +1,77 @@
+# Exim test configuration 2135
+
+.include DIR/aux-var/tls_conf_prefix
+
+.ifdef SERVER
+tls_certificate = DIR/aux-fixed/exim-ca/example.com/server1.example.com/server1.example.com.chain.pem
+tls_privatekey = DIR/aux-fixed/exim-ca/example.com/server1.example.com/server1.example.com.unlocked.key
+.else
+tls_advertise_hosts =
+.endif
+
+primary_hostname = myhost.test.ex
+
+# ----- Main settings -----
+
+.ifdef SERVER
+acl_smtp_rcpt = srvr_rcpt
+acl_smtp_data = srvr_data
+.else
+acl_smtp_rcpt = client_rcpt
+acl_smtp_data = client_data
+.endif
+
+log_selector = +received_recipients +outgoing_port
+
+.ifdef SERVER
+queue_only
+queue_run_in_order = true
+.endif
+
+# ----- ACLs -----
+
+begin acl
+
+client_rcpt:
+  accept
+       verify =        recipient/callout=use_sender,hold
+
+client_data:
+  accept
+
+srvr_rcpt:
+  defer        local_parts =   rcpt_defer
+  accept
+
+srvr_data:
+  defer        condition =     ${if eq {data_defer}{${local_part:$recipients}}}
+  accept
+
+# ----- Routers -----
+
+begin routers
+
+target:
+  driver =     redirect
+  condition =  ${if or {{eq {SERVER}{server}} {queue_running}}}
+  data =       :blackhole:
+
+client:
+  driver =     manualroute
+  route_list=  * 127.0.0.1::PORT_D
+  self =       send
+  transport =  t1
+  errors_to =  ""
+
+begin transports
+
+t1:
+  driver =     smtp
+  tls_verify_certificates =    DIR/aux-fixed/exim-ca/example.com/CA/CA.pem
+  tls_verify_cert_hostnames =  :
+
+# ----- Retry -----
+begin retry
+
+* * F,5d,10s
+# End
diff --git a/test/confs/2136 b/test/confs/2136
new file mode 120000 (symlink)
index 0000000..b9dc6e9
--- /dev/null
@@ -0,0 +1 @@
+2135
\ No newline at end of file
diff --git a/test/confs/2137 b/test/confs/2137
new file mode 120000 (symlink)
index 0000000..b9dc6e9
--- /dev/null
@@ -0,0 +1 @@
+2135
\ No newline at end of file
diff --git a/test/confs/2138 b/test/confs/2138
new file mode 100644 (file)
index 0000000..d6d7604
--- /dev/null
@@ -0,0 +1,64 @@
+# Exim test configuration 2135
+
+SERVER =
+
+.include DIR/aux-var/tls_conf_prefix
+
+primary_hostname = myhost.test.ex
+
+# ----- Main settings -----
+
+acl_smtp_rcpt = accept
+
+log_selector = +tls_peerdn+smtp_connection+incoming_port+received_recipients
+
+queue_only
+queue_run_in_order
+
+smtp_accept_max_nonmail = 0
+
+tls_advertise_hosts = *
+
+# Set certificate only if server
+
+tls_certificate = ${if eq {SERVER}{server}{DIR/aux-fixed/cert1}fail}
+tls_privatekey = ${if eq {SERVER}{server}{DIR/aux-fixed/cert1}fail}
+
+
+# ----- Routers -----
+
+begin routers
+
+client:
+  driver =     manualroute
+  condition =  ${if eq {SERVER}{server}{no}{yes}}
+  route_data = 127.0.0.1
+  self =       send
+  retry_use_local_part
+  transport =  send_to_server
+
+server:
+  driver = accept
+  retry_use_local_part
+  transport = local_delivery
+
+
+# ----- Transports -----
+
+begin transports
+
+local_delivery:
+  driver = appendfile
+  file = DIR/test-mail/$local_part
+  headers_add = TLS: cipher=$tls_cipher peerdn=$tls_peerdn
+  user = CALLER
+
+send_to_server:
+  driver =     smtp
+  allow_localhost
+  hosts_noproxy_tls = :
+  port =       PORT_D
+  tls_try_verify_hosts = :
+  max_rcpt =   1
+
+# End
diff --git a/test/confs/2152 b/test/confs/2152
deleted file mode 100644 (file)
index a8b6c15..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-# Exim test configuration 2152
-# as per 2100 but with TCP Fast Open
-
-SERVER=
-
-.include DIR/aux-var/tls_conf_prefix
-
-primary_hostname = myhost.test.ex
-
-.ifdef _HAVE_TLS
-# that was purely to trigger the lazy-create of builtin macros
-.endif
-# ----- Main settings -----
-
-acl_smtp_rcpt = accept
-
-log_selector =  +tls_peerdn
-
-queue_only
-queue_run_in_order
-
-tls_advertise_hosts = *
-
-# Set certificate only if server
-
-tls_certificate = ${if eq {SERVER}{server}{DIR/aux-fixed/cert1}fail}
-tls_privatekey = ${if eq {SERVER}{server}{DIR/aux-fixed/cert1}fail}
-
-tls_verify_hosts = *
-tls_verify_certificates = ${if eq {SERVER}{server}{DIR/aux-fixed/cert2}fail}
-
-
-# ----- Routers -----
-
-begin routers
-
-client:
-  driver = accept
-  condition = ${if eq {SERVER}{server}{no}{yes}}
-  retry_use_local_part
-  transport = send_to_server
-
-
-# ----- Transports -----
-
-begin transports
-
-send_to_server:
-  driver = smtp
-  allow_localhost
-  hosts = 127.0.0.1
-  port = PORT_D
-  hosts_try_fastopen = *
-  tls_certificate = DIR/aux-fixed/cert2
-  tls_privatekey = DIR/aux-fixed/cert2
-  tls_verify_certificates = DIR/aux-fixed/cert2
-  tls_try_verify_hosts = :
-
-
-# ----- Retry -----
-
-
-begin retry
-
-* * F,5d,10s
-
-
-# End
diff --git a/test/confs/4012 b/test/confs/4012
new file mode 100644 (file)
index 0000000..9afd4a0
--- /dev/null
@@ -0,0 +1,29 @@
+# Exim test configuration 4012
+# Content-scan: sock interface
+
+.include DIR/aux-var/std_conf_prefix
+
+primary_hostname = myhost.test.ex
+
+av_scanner = sock : 127.0.0.1 PORT_S : : BAD : NAME:: (\w+)
+
+# ----- Main settings -----
+
+acl_smtp_rcpt = accept
+acl_smtp_data = c_data
+
+begin acl
+
+c_data:
+  accept !malware = * OPT
+  deny  logwrite = $callout_address malware_name $malware_name
+
+# ----- Routers -----
+
+begin routers
+
+r:
+  driver = redirect
+  data = :blackhole:
+
+# End
index 8dfd46888404a2e407864677632b351901d85874..05c95a571510bb2992f7da92e52eb50110fb3eb1 100644 (file)
@@ -32,11 +32,12 @@ my_main_router:
 begin transports
 
 my_smtp:
-  driver = smtp
-  interface = HOSTIPV4
-  port = PORT_S
-  hide socks_proxy = 127.0.0.1 port=PORT_D OPT
-  debug_print = transport_name <$transport_name>
+  driver =             smtp
+  interface =          HOSTIPV4
+  port =               PORT_S
+  hide socks_proxy =   127.0.0.1 port=PORT_D OPT
+  hosts_try_fastopen = ${if eq {$local_part}{user_tfo} {*}}
+  debug_print =                transport_name <$transport_name>
 
 
 # End
diff --git a/test/confs/4027 b/test/confs/4027
new file mode 120000 (symlink)
index 0000000..4af051c
--- /dev/null
@@ -0,0 +1 @@
+4020
\ No newline at end of file
diff --git a/test/confs/4503 b/test/confs/4503
new file mode 120000 (symlink)
index 0000000..c4f73ba
--- /dev/null
@@ -0,0 +1 @@
+4500
\ No newline at end of file
index 70454c33c904acb99962d6feaa80e0abf50fe4d9..897c1a6756baef9f8a468ee518ebd721c0c4e274 100644 (file)
@@ -12,6 +12,7 @@ primary_hostname = myhost.test.ex
 acl_smtp_rcpt = accept
 acl_smtp_dkim = accept logwrite = signer: $dkim_cur_signer bits: $dkim_key_length h=$dkim_headernames
 
+DDIR=DIR/aux-fixed/dkim
 
 # ----- Routers
 
@@ -42,9 +43,18 @@ send_to_server:
 .else
   dkim_selector =      sel
 .endif
-  dkim_private_key =   DIR/aux-fixed/dkim/dkim.private
+
+  dkim_private_key =   ${if match {$dkim_selector}{^ses}       {DDIR/dkim512.private} \
+                         {${if match {$dkim_selector}{^sel} {DDIR/dkim.private} \
+                         {}}}}
+
 .ifndef HEADERS_MAXSIZE
   dkim_sign_headers =  OPT
+.else
+  dkim_identity =      allheaders@$dkim_domain
+.endif
+.ifdef VALUE
+  dkim_hash =          VALUE
 .endif
 
 # End
diff --git a/test/confs/4523 b/test/confs/4523
new file mode 120000 (symlink)
index 0000000..072f5fa
--- /dev/null
@@ -0,0 +1 @@
+4520
\ No newline at end of file
diff --git a/test/confs/4524 b/test/confs/4524
new file mode 120000 (symlink)
index 0000000..072f5fa
--- /dev/null
@@ -0,0 +1 @@
+4520
\ No newline at end of file
diff --git a/test/confs/4530 b/test/confs/4530
new file mode 120000 (symlink)
index 0000000..a8ce02c
--- /dev/null
@@ -0,0 +1 @@
+0906
\ No newline at end of file
diff --git a/test/confs/5010 b/test/confs/5010
new file mode 100644 (file)
index 0000000..927f4a4
--- /dev/null
@@ -0,0 +1,35 @@
+# Exim test configuration 5010
+
+.include DIR/aux-var/std_conf_prefix
+
+primary_hostname = myhost.test.ex
+
+# ----- Main settings -----
+
+qualify_domain = test.ex
+
+
+# ----- Routers -----
+
+begin routers
+
+all:
+  driver = accept
+  retry_use_local_part
+  transport = local_delivery
+
+
+# ----- Transports -----
+
+begin transports
+
+local_delivery:
+  driver = appendfile
+  directory = DIR/test-mail
+  maildir_format
+  quota = 30/no_check
+  quota_filecount = 1
+  user = CALLER
+  maildir_use_size_file
+
+# End
diff --git a/test/confs/5011 b/test/confs/5011
new file mode 100644 (file)
index 0000000..f1a19a8
--- /dev/null
@@ -0,0 +1,35 @@
+# Exim test configuration 5011
+
+.include DIR/aux-var/std_conf_prefix
+
+primary_hostname = myhost.test.ex
+
+# ----- Main settings -----
+
+qualify_domain = test.ex
+
+
+# ----- Routers -----
+
+begin routers
+
+all:
+  driver = accept
+  retry_use_local_part
+  transport = local_delivery
+
+
+# ----- Transports -----
+
+begin transports
+
+local_delivery:
+  driver = appendfile
+  directory = DIR/test-mail
+  maildir_format
+  quota = 30
+  quota_filecount = 1/no_check
+  user = CALLER
+  maildir_use_size_file
+
+# End
diff --git a/test/confs/5012 b/test/confs/5012
new file mode 100644 (file)
index 0000000..f4715bf
--- /dev/null
@@ -0,0 +1,35 @@
+# Exim test configuration 5011
+
+.include DIR/aux-var/std_conf_prefix
+
+primary_hostname = myhost.test.ex
+
+# ----- Main settings -----
+
+qualify_domain = test.ex
+
+
+# ----- Routers -----
+
+begin routers
+
+all:
+  driver = accept
+  retry_use_local_part
+  transport = local_delivery
+
+
+# ----- Transports -----
+
+begin transports
+
+local_delivery:
+  driver = appendfile
+  directory = DIR/test-mail
+  maildir_format
+  quota = 30/no_check
+  quota_filecount = 1/no_check
+  user = CALLER
+  maildir_use_size_file
+
+# End
index 3309870a3a09ba2aa52ae2892c574d8dcc07bebc..6e667b4299739fc0f97bc6edba83121aeb00680b 100644 (file)
@@ -21,7 +21,7 @@ domainlist local_domains = test.ex : *.test.ex
 acl_smtp_rcpt = check_recipient
 acl_smtp_data = check_data
 
-log_selector = +tls_peerdn
+log_selector = +tls_peerdn +received_recipients
 remote_max_parallel = 1
 
 tls_advertise_hosts = *
index ccc907c82a3018efb14e790bcbfe1a0aacead218..4d41e820bc8bbc222980e51fb7dd43777eb1dab3 100644 (file)
@@ -21,7 +21,7 @@ domainlist local_domains = test.ex : *.test.ex
 acl_smtp_rcpt = check_recipient
 acl_smtp_data = check_data
 
-log_selector = +tls_peerdn
+log_selector = +tls_peerdn +received_recipients
 remote_max_parallel = 1
 
 tls_advertise_hosts = *
@@ -71,7 +71,7 @@ client:
   condition = ${if eq {SERVER}{server}{no}{yes}}
   retry_use_local_part
   transport = send_to_server${if eq{$local_part}{nostaple}{1} \
-                               {${if eq{$local_part}{norequire} {2} \
+                               {${if match{$local_part}{norequire} {2} \
                                {${if eq{$local_part}{smtps} {4}{3}}} \
                             }}}
 
index ac3578dc9a3ca113814ac3d625083433ecaef9fe..01c114252a5c52d45daa6196d7d146d095a2c1d9 100644 (file)
@@ -61,10 +61,10 @@ begin transports
 send_to_server:
   driver = smtp
   allow_localhost
-  port = PORT_D
+  port = ${if match {$host}{\Ntest.ex$\N} {PORT_D}{25}}
 
   hosts_try_dane =     *
-  hosts_require_dane = !thishost.test.ex
+  hosts_require_dane = HOSTIPV4
   tls_verify_cert_hostnames = ${if eq {OPT}{no_certname} {}{*}}
   tls_try_verify_hosts = thishost.test.ex
   tls_verify_certificates = CDIR2/ca_chain.pem
index 349fbd4d37a816716ecad9a643e772d32cf9af01..73db57f9ce60cf8d0649d7e5174a21c1bdfc7301 100644 (file)
@@ -461,10 +461,24 @@ DNSSEC danelazy2            A       127.0.0.1
 DNSSEC _1225._tcp.danelazy  CNAME   test.again.dns.
 DNSSEC _1225._tcp.danelazy2 CNAME   test.again.dns.
 
-; hosts with no TLSA
+; hosts with no TLSA (just missing here, hence the TLSA NXDMAIN is _insecure_; a broken dane config)
+; 1 for dane-required, 2 for merely requested
 DNSSEC dane.no.1            A       HOSTIPV4
 DNSSEC dane.no.2            A       127.0.0.1
 
+; a broken dane config (or under attack) where the TLSA lookup fails (as opposed to there not being one)
+DNSSEC danebroken1          A       127.0.0.1
+_1225._tcp.danebroken1      CNAME   test.fail.dns.
+
+; a good dns config saying there is no dane support, by securely returning NOXDOMAIN for TLSA lookups
+; 3 for dane-required, 4 for merely requested
+; the TLSA data here is dummy; ignored
+DNSSEC dane.no.3            A       HOSTIPV4
+DNSSEC dane.no.4            A       127.0.0.1
+
+DNSSEC NXDOMAIN _1225._tcp.dane.no.3 TLSA 2 0 1 eec923139018c540a344c5191660ecba1ac3708525a98bfc338e17f31d3fa741
+DNSSEC NXDOMAIN _1225._tcp.dane.no.4 TLSA 2 0 1 eec923139018c540a344c5191660ecba1ac3708525a98bfc338e17f31d3fa741
+
 ; ------- Testing delays ------------
 
 DELAY=500 delay500   A HOSTIPV4
@@ -477,13 +491,19 @@ DELAY=1500 delay1500 A HOSTIPV4
 ;  openssl rsa -in aux-fixed/dkim/dkim.private -out /dev/stdout -pubout -outform PEM
 ;
 ; Deliberate bad version, having extra backslashes
+; sha256-hash-only version.... appears to be too long, gets truncated
 ;
 ; Another, 512-bit (with a Notes field)
+; 512 requiring sha1 hash
+; 512 requiring sha256 hash
 ;
 sel._domainkey TXT "v=DKIM1; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDXRFf+VhT+lCgFhhSkinZKcFNeRzjYdW8vT29Rbb3NadvTFwAd+cVLPFwZL8H5tUD/7JbUPqNTCPxmpgIL+V5T4tEZMorHatvvUM2qfcpQ45IfsZ+YdhbIiAslHCpy4xNxIR3zylgqRUF4+Dtsaqy3a5LhwMiKCLrnzhXk1F1hxwIDAQAB"
 sel_bad._domainkey TXT "v=DKIM1\; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDXRFf+VhT+lCgFhhSkinZKcFNeRzjYdW8vT29Rbb3NadvTFwAd+cVLPFwZL8H5tUD/7JbUPqNTCPxmpgIL+V5T4tEZMorHatvvUM2qfcpQ45IfsZ+YdhbIiAslHCpy4xNxIR3zylgqRUF4+Dtsaqy3a5LhwMiKCLrnzhXk1F1hxwIDAQAB"
+sel_sha256._domainkey TXT "v=DKIM1; h=sha256; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDXRFf+VhT+lCgFhhSkinZKcFNeRzjYdW8vT29Rbb3NadvTFwAd+cVLPFwZL8H5tUD/7JbUPqNTCPxmpgIL+V5T4tEZMorHatvvUM2qfcpQ45IfsZ+YdhbIiAslHCpy4xNxIR3zylgqRUF4+Dtsaqy3a5LhwMiKCLrnzhXk1F1hxwIDAQAB"
 
 ses._domainkey TXT "v=DKIM1; n=halfkilo; p=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL6eAQxd9didJ0/+05iDwJOqT6ly826Vi8aGPecsBiYK5/tAT97fxXk+dPWMZp9kQxtknEzYjYjAydzf+HQ2yJMCAwEAAQ=="
+ses_sha1._domainkey TXT "v=DKIM1; h=sha1; p=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL6eAQxd9didJ0/+05iDwJOqT6ly826Vi8aGPecsBiYK5/tAT97fxXk+dPWMZp9kQxtknEzYjYjAydzf+HQ2yJMCAwEAAQ=="
+ses_sha256._domainkey TXT "v=DKIM1; h=sha256; p=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAL6eAQxd9didJ0/+05iDwJOqT6ly826Vi8aGPecsBiYK5/tAT97fxXk+dPWMZp9kQxtknEzYjYjAydzf+HQ2yJMCAwEAAQ=="
 
 
 ; End
index 537cea1e9513df139f68515be3261d18810c574e..e41a29c8cb83cc0bb03b1375ecaf7d21657db55f 100644 (file)
@@ -137,7 +137,7 @@ sub flavour {
 
 sub flavours {
     my %h = map { /\.(\S+)$/, 1 }
-            glob('stdout/*.*'), glob('stderr/*.*');
+            grep { !/\.orig$/ } glob('stdout/*.*'), glob('stderr/*.*');
     return sort keys %h;
 }
 
index 74acec3a36cfe4622cbb1577c9a3e097706cfeb0..ac647a67ba76d34c7e70b459e413329c1bc3e8f5 100644 (file)
@@ -14,6 +14,7 @@
 1999-03-02 09:44:33 End queue run: pid=pppp -qf
 1999-03-02 09:44:33 Test: reject connect
 1999-03-02 09:44:33 Start queue run: pid=pppp -qf
+1999-03-02 09:44:33 10HmaX-0005vi-00 H=localhost4.test.ex [127.0.0.1]: SMTP error from remote mail server after initial connection: 550 Go away (A)
 1999-03-02 09:44:33 10HmaX-0005vi-00 ** userx@domain1 F=<CALLER@test.ex> R=others T=smtp H=localhost4.test.ex [127.0.0.1]: SMTP error from remote mail server after initial connection: 550 Go away (A)
 1999-03-02 09:44:33 10HmaY-0005vi-00 <= <> R=10HmaX-0005vi-00 U=EXIMUSER P=local S=sss
 1999-03-02 09:44:33 10HmaY-0005vi-00 => CALLER <CALLER@test.ex> F=<> R=all T=local_delivery
@@ -22,6 +23,7 @@
 1999-03-02 09:44:33 End queue run: pid=pppp -qf
 1999-03-02 09:44:33 Test: reject helo
 1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@test.ex U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmaZ-0005vi-00 H=localhost4.test.ex [127.0.0.1]: SMTP error from remote mail server after HELO the.local.host.name: 550 Go away (C)
 1999-03-02 09:44:33 10HmaZ-0005vi-00 ** userx@domain1 F=<CALLER@test.ex> R=others T=smtp H=localhost4.test.ex [127.0.0.1]: SMTP error from remote mail server after HELO the.local.host.name: 550 Go away (C)
 1999-03-02 09:44:33 10HmaZ-0005vi-00 ** usery@domain2 F=<CALLER@test.ex> R=others T=smtp H=localhost4.test.ex [127.0.0.1]: SMTP error from remote mail server after HELO the.local.host.name: 550 Go away (C)
 1999-03-02 09:44:33 10HmbA-0005vi-00 <= <> R=10HmaZ-0005vi-00 U=EXIMUSER P=local S=sss
@@ -32,3 +34,9 @@
 1999-03-02 09:44:33 10HmbB-0005vi-00 <= CALLER@test.ex U=CALLER P=local S=sss
 1999-03-02 09:44:33 10HmbB-0005vi-00 H=localhost4.test.ex [127.0.0.1]: Remote host closed connection in response to HELO the.local.host.name (EHLO response was: 550 You are banned)
 1999-03-02 09:44:33 10HmbB-0005vi-00 == userx@domain1 R=others T=smtp defer (-18) H=localhost4.test.ex [127.0.0.1]: Remote host closed connection in response to HELO the.local.host.name (EHLO response was: 550 You are banned)
+1999-03-02 09:44:33 Test: smtp-reject conn on 1MX, timeout TCP conn on 2MX
+1999-03-02 09:44:33 Start queue run: pid=pppp -qf
+1999-03-02 09:44:33 10HmbB-0005vi-00 H=127.0.0.1 [127.0.0.1]: SMTP error from remote mail server after initial connection: 554 no smtp service here
+1999-03-02 09:44:33 10HmbB-0005vi-00 H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4]: SMTP timeout after initial connection: Connection timed out
+1999-03-02 09:44:33 10HmbB-0005vi-00 == userx@domain1 R=others T=smtp defer (dd): Connection timed out H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4]: SMTP timeout after initial connection
+1999-03-02 09:44:33 End queue run: pid=pppp -qf
index f1e64701c5f96d26bc59e18ea3d9d1abebf17933..d91075fb6251c35c4e4150627faf342212e8e4dd 100644 (file)
@@ -14,6 +14,9 @@
 1999-03-02 09:44:33 H=[V4NET.0.0.5] U=root F=<ok@localhost1> rejected RCPT <z@remote.domain>: relay not permitted
 1999-03-02 09:44:33 H=[V4NET.0.0.5] U=root sender verify fail for <ok@localhost1>: 127.0.0.1 [127.0.0.1] : SMTP error from remote mail server after RCPT TO:<postmaster@localhost1>: 550 Don't like postmaster
 1999-03-02 09:44:33 H=[V4NET.0.0.5] U=root F=<ok@localhost1> rejected RCPT <z@remote.domain>: Sender verify failed
+1999-03-02 09:44:33 H=(me) [V4NET.0.0.3] U=root F=<ok@localhost1> rejected RCPT <z@remote.domain>: relay not permitted
+1999-03-02 09:44:33 H=(me) [V4NET.0.0.3] U=root F=<ok@localhost1> rejected RCPT <z@remote.domain>: relay not permitted
+1999-03-02 09:44:33 H=(me) [V4NET.0.0.7] U=root F=<ok@localhost1> rejected RCPT <z@remote.domain>: relay not permitted
 1999-03-02 09:44:33 H=[V4NET.0.0.3] U=root F=<uncheckable@localhost1> rejected RCPT <z@remote.lmtp>: 127.0.0.1 [127.0.0.1] : SMTP error from remote mail server after RCPT TO:<z@remote.lmtp>: 550 Recipient not liked
 1999-03-02 09:44:33 H=[V4NET.0.0.1] U=root sender verify defer for <bad@localhost1>: Could not complete sender verify callout: 127.0.0.1 [127.0.0.1] : Remote host closed connection in response to initial connection
 1999-03-02 09:44:33 H=[V4NET.0.0.1] U=root F=<bad@localhost1> temporarily rejected RCPT <z@test.ex>: Could not complete sender verify callout
index 0e2f661ac683be21ea37d0fc4c8446e275e36459..fa191bcd5c16ab9ea6689201028f44d89646521a 100644 (file)
 1999-03-02 09:44:33 H=[V4NET.0.0.2] U=root F=<ok@otherhost> rejected RCPT <z@test.ex>: Sender verify failed
 1999-03-02 09:44:33 H=[V4NET.0.0.2] U=root sender verify fail for <ok@otherhost>
 1999-03-02 09:44:33 H=[V4NET.0.0.2] U=root F=<ok@otherhost> rejected RCPT <z@test.ex>: Sender verify failed
-1999-03-02 09:44:33 H=[V4NET.0.0.3] U=root sender verify defer for <ok@otherhost3>: Could not complete sender verify callout: 127.0.0.1 [127.0.0.1] : response to "RCPT TO:<myhost.test.ex-dddddddd-testing@otherhost3>" was: 250 OK
-1999-03-02 09:44:33 H=[V4NET.0.0.3] U=root F=<ok@otherhost3> temporarily rejected RCPT <z@test.ex>: Could not complete sender verify callout
-1999-03-02 09:44:33 H=[V4NET.0.0.4] U=root sender verify defer for <ok@otherhost4>: Could not complete sender verify callout: 127.0.0.1 [127.0.0.1] : response to "RCPT TO:<myhost.test.ex-dddddddd-testing@otherhost4>" was: 250 OK
-1999-03-02 09:44:33 H=[V4NET.0.0.4] U=root F=<ok@otherhost4> temporarily rejected RCPT <z@test.ex>: Could not complete sender verify callout
 1999-03-02 09:44:33 H=[V4NET.0.0.5] U=root sender verify defer for <okok@otherhost51>: Could not complete sender verify callout: 127.0.0.1 [127.0.0.1] : SMTP timeout after RCPT TO:<myhost.test.ex-dddddddd-testing@otherhost51>
 1999-03-02 09:44:33 H=[V4NET.0.0.5] U=root F=<okok@otherhost51> temporarily rejected RCPT <z@test.ex>: Could not complete sender verify callout
 1999-03-02 09:44:33 10HmaX-0005vi-00 <= ok7@otherhost53 H=[V4NET.0.0.7] U=root P=smtp S=sss
index cb75f6cf450b0c1f47ab2c44c152b66d3acade36..d477a6b9b4f134a45a08e0efbc4635403b84367e 100644 (file)
@@ -1,5 +1,6 @@
 1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
 1999-03-02 09:44:33 Start queue run: pid=pppp
+1999-03-02 09:44:33 10HmaX-0005vi-00 H=127.0.0.1 [127.0.0.1]: SMTP error from remote mail server after HELO myhost.test.ex: 550 No
 1999-03-02 09:44:33 10HmaX-0005vi-00 ** x@y R=r1 T=t1 H=127.0.0.1 [127.0.0.1]: SMTP error from remote mail server after HELO myhost.test.ex: 550 No
 1999-03-02 09:44:33 10HmaY-0005vi-00 <= <> R=10HmaX-0005vi-00 U=EXIMUSER P=local S=sss
 1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
index d74b21dabb6e65cb729d1138ed425659e3d1bfe4..e0140f58b632fd2a73ff8b48b053c80df1c8eeea 100644 (file)
@@ -1,7 +1,7 @@
 1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
 1999-03-02 09:44:33 10HmaX-0005vi-00 => discarded <exim-filter@test.ex> R=r1
 1999-03-02 09:44:33 10HmaX-0005vi-00 => discarded <sieve-filter@test.ex> R=r1
-1999-03-02 09:44:33 10HmaX-0005vi-00 Completed QT=0s
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed QT=qqs
 1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
 1999-03-02 09:44:33 10HmaY-0005vi-00 => discarded <exim-filter@test.ex> R=r1
 1999-03-02 09:44:33 10HmaY-0005vi-00 == sieve-filter@test.ex R=r1 defer (-17): error in filter file: Sieve filtering not enabled
index 34defc3476d54347154b619b7f8aae17f42c73f5..79b4ace5bac066ddb0b2c3f096d2799f7f20edb8 100644 (file)
@@ -1,9 +1,10 @@
 1999-03-02 09:44:33 U=CALLER rejected EXPN x@y
-1999-03-02 09:44:33 no MAIL in SMTP connection from CALLER D=0s C=EXPN,QUIT
+1999-03-02 09:44:33 no MAIL in SMTP connection from CALLER D=qqs C=EXPN,QUIT
 
 ******** SERVER ********
+2017-07-30 18:51:05.712 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+2017-07-30 18:51:05.712 no MAIL in SMTP connection from [127.0.0.1] D=q.qqqs
 1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
-1999-03-02 09:44:33 no MAIL in SMTP connection from [127.0.0.1] D=0s
-1999-03-02 09:44:33 no MAIL in SMTP connection from [127.0.0.1] D=0s C=QUIT
+1999-03-02 09:44:33 no MAIL in SMTP connection from [127.0.0.1] D=qqs C=QUIT
 1999-03-02 09:44:33 H=(x.y.z) [127.0.0.1] rejected VRFY a@b.c
-1999-03-02 09:44:33 no MAIL in SMTP connection from (x.y.z) [127.0.0.1] D=0s C=EHLO,VRFY,QUIT
+1999-03-02 09:44:33 no MAIL in SMTP connection from (x.y.z) [127.0.0.1] D=qqs C=EHLO,VRFY,QUIT
index 831e11a89f879d112c425eb7a8bc4f75d6d06959..5baae67cb60a7976dd4b5667e8f32a0163ad9d6b 100644 (file)
@@ -3,9 +3,9 @@
 1999-03-02 09:44:33 [1235] 10HmaX-0005vi-00 => usery <usery@test.ex> R=r1 T=t1
 1999-03-02 09:44:33 [1235] 10HmaX-0005vi-00 Completed
 1999-03-02 09:44:33 [1236] 10HmaY-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
-1999-03-02 09:44:33 [1237] 10HmaY-0005vi-00 => userx <userx@test.ex> R=r1 T=t1
-1999-03-02 09:44:33 [1237] 10HmaY-0005vi-00 => userz <userz@test.ex> R=r1 T=t1
+1999-03-02 09:44:33 [1237] 10HmaY-0005vi-00 => userx <userx@test.ex> R=r1 T=t1 QT=qqs
+1999-03-02 09:44:33 [1237] 10HmaY-0005vi-00 => userz <userz@test.ex> R=r1 T=t1 QT=qqs
 1999-03-02 09:44:33 [1237] 10HmaY-0005vi-00 Completed
-1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
-1999-03-02 09:44:33 10HmaZ-0005vi-00 => userx <userx@test.ex> R=r1 T=t1
-1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
+2017-07-30 18:51:05.712 10HmaZ-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
+2017-07-30 18:51:05.712 10HmaZ-0005vi-00 => userx <userx@test.ex> R=r1 T=t1 QT=q.qqqs DT=q.qqqs
+2017-07-30 18:51:05.712 10HmaZ-0005vi-00 Completed QT=q.qqqs
index 7c38e638cd57249d8f4491c253b356bdc562f238..60ddf3c1331740749a312012844ab17c87427ac8 100644 (file)
 1999-03-02 09:44:33 H=[V4NET.0.0.2] U=root F=<ok@otherhost> rejected RCPT <z@test.ex>: Sender verify failed
 1999-03-02 09:44:33 H=[V4NET.0.0.2] U=root sender verify fail for <ok@otherhost>
 1999-03-02 09:44:33 H=[V4NET.0.0.2] U=root F=<ok@otherhost> rejected RCPT <z@test.ex>: Sender verify failed
-1999-03-02 09:44:33 H=[V4NET.0.0.3] U=root sender verify defer for <ok@otherhost3>: Could not complete sender verify callout: 127.0.0.1 [127.0.0.1] : response to "RCPT TO:<myhost.test.ex-dddddddd-testing@otherhost3>" was: 250 OK accepting that random recipient
-1999-03-02 09:44:33 H=[V4NET.0.0.3] U=root F=<ok@otherhost3> temporarily rejected RCPT <z@test.ex>: Could not complete sender verify callout
-1999-03-02 09:44:33 H=[V4NET.0.0.4] U=root sender verify defer for <ok@otherhost4>: Could not complete sender verify callout: 127.0.0.1 [127.0.0.1] : response to "RCPT TO:<myhost.test.ex-dddddddd-testing@otherhost4>" was: 250 OK
-1999-03-02 09:44:33 H=[V4NET.0.0.4] U=root F=<ok@otherhost4> temporarily rejected RCPT <z@test.ex>: Could not complete sender verify callout
 1999-03-02 09:44:33 H=[V4NET.0.0.5] U=root sender verify defer for <okok@otherhost51>: Could not complete sender verify callout: 127.0.0.1 [127.0.0.1] : SMTP timeout after RCPT TO:<myhost.test.ex-dddddddd-testing@otherhost51>
 1999-03-02 09:44:33 H=[V4NET.0.0.5] U=root F=<okok@otherhost51> temporarily rejected RCPT <z@test.ex>: Could not complete sender verify callout
 1999-03-02 09:44:33 10HmaX-0005vi-00 <= ok7@otherhost53 H=[V4NET.0.0.7] U=root P=smtp S=sss
diff --git a/test/log/0580 b/test/log/0580
new file mode 100644 (file)
index 0000000..f006778
--- /dev/null
@@ -0,0 +1,15 @@
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-smtp S=sss for usery@test.ex
+1999-03-02 09:44:33 10HmaX-0005vi-00 => usery@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message"
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-smtp S=sss for usery@test.ex usery2@test.ex
+1999-03-02 09:44:33 10HmaY-0005vi-00 => usery@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message"
+1999-03-02 09:44:33 10HmaY-0005vi-00 -> usery2@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message"
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-smtp S=sss for usery3@test.ex usery@test.ex
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => usery3@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 -> usery@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-smtp S=sss for usery4@test.ex usery5@test.ex
+1999-03-02 09:44:33 10HmbA-0005vi-00 => usery4@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message"
+1999-03-02 09:44:33 10HmbA-0005vi-00 -> usery5@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message"
+1999-03-02 09:44:33 10HmbA-0005vi-00 Completed
diff --git a/test/log/0581 b/test/log/0581
new file mode 100644 (file)
index 0000000..f554e00
--- /dev/null
@@ -0,0 +1,23 @@
+
+******** SERVER ********
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= userc@ok.example H=(test.ex) [127.0.0.1] P=esmtp S=sss for userd@test.ex
+1999-03-02 09:44:33 10HmaX-0005vi-00 => userd@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message"
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= usere@ok.example H=(test.ex) [127.0.0.1] P=esmtp S=sss for userf@test.ex
+1999-03-02 09:44:33 10HmaY-0005vi-00 => userf@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message"
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 10HmaZ-0005vi-00 <= userc@ok.example H=(test.ex) [127.0.0.1] P=esmtp S=sss for userd@test.ex userd2@test.ex
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => userd@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 -> userd2@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbA-0005vi-00 <= userc@ok.example H=(test.ex) [127.0.0.1] P=esmtp S=sss for userd3@test.ex userd2@test.ex
+1999-03-02 09:44:33 10HmbA-0005vi-00 => userd3@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message"
+1999-03-02 09:44:33 10HmbA-0005vi-00 -> userd2@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message"
+1999-03-02 09:44:33 10HmbA-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbB-0005vi-00 <= userc@ok.example H=(test.ex) [127.0.0.1] P=esmtp S=sss for userd4@test.ex userd5@test.ex
+1999-03-02 09:44:33 10HmbB-0005vi-00 => userd4@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message"
+1999-03-02 09:44:33 10HmbB-0005vi-00 -> userd5@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1] C="250 yeah got that message"
+1999-03-02 09:44:33 10HmbB-0005vi-00 Completed
diff --git a/test/log/0582 b/test/log/0582
new file mode 100644 (file)
index 0000000..8953064
--- /dev/null
@@ -0,0 +1,3 @@
+1999-03-02 09:44:33 U=CALLER F=<userg@ok.example> temporarily rejected RCPT <userg@test.ex>: Could not complete recipient verify callout: 127.0.0.1 [127.0.0.1] : SMTP error from remote mail server after RCPT TO:<userg@test.ex>: 451 not right now
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-smtp S=sss for userh@test.ex
+1999-03-02 09:44:33 10HmaX-0005vi-00 == userh@test.ex R=r1 T=t1 defer (-46) H=127.0.0.1 [127.0.0.1]: SMTP error from remote mail server after end of data: 451 not right now
index a19051aa1a5c0c638543f1d1cfa69c34cbb82958..b395954a4eb2b7d9968bab0e2d0007433f4c6879 100644 (file)
@@ -4,4 +4,4 @@
 1999-03-02 09:44:33 SMTP connection from [127.0.0.1] (TCP/IP connection count = 1)
 1999-03-02 09:44:33 SMTP connection from [127.0.0.1] closed by QUIT
 1999-03-02 09:44:33 SMTP connection from [127.0.0.1] (TCP/IP connection count = 1)
-1999-03-02 09:44:33 unexpected disconnection while reading SMTP command from [127.0.0.1]
+1999-03-02 09:44:33 unexpected disconnection while reading SMTP command from [127.0.0.1] D=qqs
index cd8c52e75f55e660a569f59f763f105f71876985..0297a891559981e925597fc9e4d05813b406849a 100644 (file)
@@ -10,6 +10,6 @@
 1999-03-02 09:44:33 SMTP connection from (tester) [127.0.0.1] lost while reading message data
 1999-03-02 09:44:33 SMTP connection from (tester) [127.0.0.1] lost while reading message data
 1999-03-02 09:44:33 10HmbD-0005vi-00 <= someone8@some.domain H=(tester) [127.0.0.1] P=esmtp K S=sss for CALLER@test.ex
-1999-03-02 09:44:33 SMTP protocol synchronization error (next input sent too soon: pipelining was not advertised): rejected "bdat 1" H=(tester) [127.0.0.1] next input="bdat 87 last\r\n"
+1999-03-02 09:44:33 SMTP protocol synchronization error (next input sent too soon: pipelining was not advertised): rejected "BDAT 1" H=(tester) [127.0.0.1] next input="BDAT 87 last\r\n"
 1999-03-02 09:44:33 SMTP call from (tester) [127.0.0.1] dropped: too many syntax or protocol errors (last command was "From: Sam@random.com")
 1999-03-02 09:44:33 SMTP connection from (tester) [127.0.0.1] lost while reading message data (header)
diff --git a/test/log/0906 b/test/log/0906
new file mode 100644 (file)
index 0000000..12e2276
--- /dev/null
@@ -0,0 +1,12 @@
+1999-03-02 09:44:33 Start queue run: pid=pppp
+1999-03-02 09:44:33 10HmaX-0005vi-00 => a <a@test.ex> R=localuser T=local_delivery
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp
+
+******** SERVER ********
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225 port 1224
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= sender@dom H=(test.com) [127.0.0.1] P=esmtp K S=sss for a@test.ex
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= <> H=localhost (testhost.test.ex) [127.0.0.1] P=esmtp K S=sss for a@test.ex
+1999-03-02 09:44:33 10HmaX-0005vi-00 no immediate delivery: queued by ACL
+1999-03-02 09:44:33 10HmaY-0005vi-00 => a@test.ex R=to_server T=remote_smtp H=127.0.0.1 [127.0.0.1] K C="250- 8nn byte chunk, total 8nn\\n250 OK id=10HmaX-0005vi-00"
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
diff --git a/test/log/1990 b/test/log/1990
new file mode 100644 (file)
index 0000000..36a7a56
--- /dev/null
@@ -0,0 +1,15 @@
+2017-07-30 18:51:05.712 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for a@test.ex
+2017-07-30 18:51:05.712 10HmaX-0005vi-00 => a@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1] C="250 OK id=10HmaY-0005vi-00"
+2017-07-30 18:51:05.712 10HmaX-0005vi-00 Completed
+2017-07-30 18:51:05.712 10HmaZ-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for b@test.ex
+2017-07-30 18:51:05.712 10HmaZ-0005vi-00 => b@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1] TFO C="250 OK id=10HmbA-0005vi-00"
+2017-07-30 18:51:05.712 10HmaZ-0005vi-00 Completed
+
+******** SERVER ********
+2017-07-30 18:51:05.712 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+2017-07-30 18:51:05.712 10HmaY-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1] P=esmtp S=sss id=E10HmaX-0005vi-00@myhost.test.ex for a@test.ex
+2017-07-30 18:51:05.712 10HmaY-0005vi-00 => :blackhole: <a@test.ex> R=server
+2017-07-30 18:51:05.712 10HmaY-0005vi-00 Completed
+2017-07-30 18:51:05.712 10HmbA-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1] TFO P=esmtp S=sss id=E10HmaZ-0005vi-00@myhost.test.ex for b@test.ex
+2017-07-30 18:51:05.712 10HmbA-0005vi-00 => :blackhole: <b@test.ex> R=server
+2017-07-30 18:51:05.712 10HmbA-0005vi-00 Completed
index 79bc3f6122c187bf5f50e199282329e5d85e5071..fc71b5f2464d8ebedd7b6b37f15cb7329417c0d9 100644 (file)
@@ -4,11 +4,22 @@
 1999-03-02 09:44:33 Start queue run: pid=pppp -qqf
 1999-03-02 09:44:33 10HmaX-0005vi-00 => userx@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no DN="C=UK,O=The Exim Maintainers,OU=Test Suite,CN=Phil Pennock" C="250 OK id=10HmbA-0005vi-00"
 1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
-1999-03-02 09:44:33 10HmaZ-0005vi-00 => userz@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* C="250 OK id=10HmbB-0005vi-00"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => userz@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C="250 OK id=10HmbB-0005vi-00"
 1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
-1999-03-02 09:44:33 10HmaY-0005vi-00 => usery@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* C="250 OK id=10HmbC-0005vi-00"
+1999-03-02 09:44:33 10HmaY-0005vi-00 => usery@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C="250 OK id=10HmbC-0005vi-00"
 1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
 1999-03-02 09:44:33 End queue run: pid=pppp -qqf
+1999-03-02 09:44:33 10HmbD-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for usera@test.ex
+1999-03-02 09:44:33 10HmbE-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for userb@test.ex
+1999-03-02 09:44:33 10HmbF-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for userc@test.ex
+1999-03-02 09:44:33 Start queue run: pid=pppp -qqf
+1999-03-02 09:44:33 10HmbD-0005vi-00 => usera@test.ex R=cl_override T=send_to_server H=127.0.0.1 [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no DN="C=UK,O=The Exim Maintainers,OU=Test Suite,CN=Phil Pennock" C="250 OK id=10HmbG-0005vi-00"
+1999-03-02 09:44:33 10HmbD-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbF-0005vi-00 => userc@test.ex R=cl_override T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C="250 OK id=10HmbH-0005vi-00"
+1999-03-02 09:44:33 10HmbF-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbE-0005vi-00 => userb@test.ex R=cl_override T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C="250 OK id=10HmbI-0005vi-00"
+1999-03-02 09:44:33 10HmbE-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qqf
 
 ******** SERVER ********
 1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
 1999-03-02 09:44:33 10HmbC-0005vi-00 => usery <usery@test.ex> R=server T=local_delivery
 1999-03-02 09:44:33 10HmbC-0005vi-00 Completed
 1999-03-02 09:44:33 End queue run: pid=pppp -qf
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 SMTP connection from [127.0.0.1]:1112 (TCP/IP connection count = 1)
+1999-03-02 09:44:33 10HmbG-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1]:1112 P=esmtps X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no S=sss id=E10HmbD-0005vi-00@myhost.test.ex for usera@test.ex
+1999-03-02 09:44:33 10HmbH-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1]:1112 P=esmtps X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no S=sss id=E10HmbF-0005vi-00@myhost.test.ex for userc@test.ex
+1999-03-02 09:44:33 10HmbI-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1]:1112 P=esmtps X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no S=sss id=E10HmbE-0005vi-00@myhost.test.ex for userb@test.ex
+1999-03-02 09:44:33 SMTP connection from localhost (myhost.test.ex) [127.0.0.1]:1112 closed by QUIT
+1999-03-02 09:44:33 Start queue run: pid=pppp -qf
+1999-03-02 09:44:33 10HmbG-0005vi-00 => usera <usera@test.ex> R=server T=local_delivery
+1999-03-02 09:44:33 10HmbG-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbH-0005vi-00 => userc <userc@test.ex> R=server T=local_delivery
+1999-03-02 09:44:33 10HmbH-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbI-0005vi-00 => userb <userb@test.ex> R=server T=local_delivery
+1999-03-02 09:44:33 10HmbI-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qf
diff --git a/test/log/2035 b/test/log/2035
new file mode 100644 (file)
index 0000000..ea33521
--- /dev/null
@@ -0,0 +1,11 @@
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-smtp S=sss for userb@test.ex
+1999-03-02 09:44:33 10HmaX-0005vi-00 => userb@test.ex R=client T=t1 H=127.0.0.1 [127.0.0.1]:1225 X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C="250 OK id=10HmaY-0005vi-00"
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 Start queue run: pid=pppp
+1999-03-02 09:44:33 10HmaY-0005vi-00 => :blackhole: <userb@test.ex> R=target
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp
+
+******** SERVER ********
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= usera@ok.example H=localhost (myhost.test.ex) [127.0.0.1] P=esmtps X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no S=sss id=E10HmaX-0005vi-00@myhost.test.ex for userb@test.ex
diff --git a/test/log/2036 b/test/log/2036
new file mode 100644 (file)
index 0000000..33b6423
--- /dev/null
@@ -0,0 +1,14 @@
+1999-03-02 09:44:33 Start queue run: pid=pppp
+1999-03-02 09:44:33 10HmaX-0005vi-00 => :blackhole: <userd@test.ex> R=target
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp
+1999-03-02 09:44:33 Start queue run: pid=pppp
+1999-03-02 09:44:33 10HmaY-0005vi-00 => :blackhole: <userf@test.ex> R=target
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp
+
+******** SERVER ********
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225 port 1224
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= userc@ok.example H=(test.ex) [127.0.0.1] P=esmtp S=sss for userd@test.ex
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225 port 1224
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= usere@ok.example H=(test.ex) [127.0.0.1] P=esmtp S=sss for userf@test.ex
diff --git a/test/log/2037 b/test/log/2037
new file mode 100644 (file)
index 0000000..ac307f2
--- /dev/null
@@ -0,0 +1,8 @@
+1999-03-02 09:44:33 U=CALLER F=<> temporarily rejected RCPT <rcpt_defer@test.ex>: Could not complete recipient verify callout: 127.0.0.1 [127.0.0.1] : SMTP error from remote mail server after RCPT TO:<rcpt_defer@test.ex>: 451 Temporary local problem - please try later
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-smtp S=sss for data_defer@test.ex
+1999-03-02 09:44:33 10HmaY-0005vi-00 == data_defer@test.ex R=client T=t1 defer (-46) H=127.0.0.1 [127.0.0.1]:1111: SMTP error from remote mail server after end of data: 451 Temporary local problem - please try later
+
+******** SERVER ********
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 H=localhost (myhost.test.ex) [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no F=<> temporarily rejected RCPT <rcpt_defer@test.ex>
+1999-03-02 09:44:33 10HmaX-0005vi-00 H=localhost (myhost.test.ex) [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no F=<> temporarily rejected after DATA
diff --git a/test/log/2038 b/test/log/2038
new file mode 100644 (file)
index 0000000..b3dfed8
--- /dev/null
@@ -0,0 +1,42 @@
+**NOTE: The delivery lines in this file have been sorted.
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for userx0@test.ex userx1@test.ex
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for usery0@test.ex usery1@test.ex
+1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for userz0@test.ex userz1@test.ex
+1999-03-02 09:44:33 Start queue run: pid=pppp -qqf
+1999-03-02 09:44:33 10HmaX-0005vi-00 => userx0@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no DN="C=UK,O=The Exim Maintainers,OU=Test Suite,CN=Phil Pennock" C="250 OK id=10HmbA-0005vi-00"
+1999-03-02 09:44:33 10HmaX-0005vi-00 => userx1@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no DN="C=UK,O=The Exim Maintainers,OU=Test Suite,CN=Phil Pennock" C="250 OK id=10HmbB-0005vi-00"
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => userz0@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C="250 OK id=10HmbC-0005vi-00"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => userz1@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C="250 OK id=10HmbD-0005vi-00"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaY-0005vi-00 => usery0@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C="250 OK id=10HmbE-0005vi-00"
+1999-03-02 09:44:33 10HmaY-0005vi-00 => usery1@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C="250 OK id=10HmbF-0005vi-00"
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qqf
+
+******** SERVER ********
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 SMTP connection from [127.0.0.1]:1111 (TCP/IP connection count = 1)
+1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1]:1111 P=esmtps X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no S=sss id=E10HmaX-0005vi-00@myhost.test.ex for userx0@test.ex
+1999-03-02 09:44:33 SMTP connection from [127.0.0.1]:1112 (TCP/IP connection count = 2)
+1999-03-02 09:44:33 10HmbB-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1]:1112 P=esmtps X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no S=sss id=E10HmaX-0005vi-00@myhost.test.ex for userx1@test.ex
+1999-03-02 09:44:33 10HmbC-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1]:1111 P=esmtps X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no S=sss id=E10HmaZ-0005vi-00@myhost.test.ex for userz0@test.ex
+1999-03-02 09:44:33 10HmbD-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1]:1111 P=esmtps X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no S=sss id=E10HmaZ-0005vi-00@myhost.test.ex for userz1@test.ex
+1999-03-02 09:44:33 SMTP connection from localhost (myhost.test.ex) [127.0.0.1]:1111 closed by QUIT
+1999-03-02 09:44:33 10HmbE-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1]:1112 P=esmtps X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no S=sss id=E10HmaY-0005vi-00@myhost.test.ex for usery0@test.ex
+1999-03-02 09:44:33 10HmbF-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1]:1112 P=esmtps X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no S=sss id=E10HmaY-0005vi-00@myhost.test.ex for usery1@test.ex
+1999-03-02 09:44:33 SMTP connection from localhost (myhost.test.ex) [127.0.0.1]:1112 closed by QUIT
+1999-03-02 09:44:33 Start queue run: pid=pppp -qf
+1999-03-02 09:44:33 10HmbA-0005vi-00 => userx0 <userx0@test.ex> R=server T=local_delivery
+1999-03-02 09:44:33 10HmbA-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbB-0005vi-00 => userx1 <userx1@test.ex> R=server T=local_delivery
+1999-03-02 09:44:33 10HmbB-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbC-0005vi-00 => userz0 <userz0@test.ex> R=server T=local_delivery
+1999-03-02 09:44:33 10HmbC-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbD-0005vi-00 => userz1 <userz1@test.ex> R=server T=local_delivery
+1999-03-02 09:44:33 10HmbD-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbE-0005vi-00 => usery0 <usery0@test.ex> R=server T=local_delivery
+1999-03-02 09:44:33 10HmbE-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbF-0005vi-00 => usery1 <usery1@test.ex> R=server T=local_delivery
+1999-03-02 09:44:33 10HmbF-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qf
diff --git a/test/log/2052 b/test/log/2052
deleted file mode 100644 (file)
index 04c72f5..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
-1999-03-02 09:44:33 Start queue run: pid=pppp -qf
-1999-03-02 09:44:33 10HmaX-0005vi-00 TLS session: (certificate verification failed): certificate invalid: delivering unencrypted to H=127.0.0.1 [127.0.0.1] (not in hosts_require_tls)
-1999-03-02 09:44:33 10HmaX-0005vi-00 => CALLER@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1] C="250 OK id=10HmaY-0005vi-00"
-1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
-1999-03-02 09:44:33 End queue run: pid=pppp -qf
-
-******** SERVER ********
-1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
-1999-03-02 09:44:33 TLS error on connection from localhost [127.0.0.1] (recv): A TLS fatal alert has been received.: Certificate is bad
-1999-03-02 09:44:33 TLS error on connection from localhost [127.0.0.1] (send): The specified session has been invalidated for some reason.
-1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1] P=esmtp S=sss id=E10HmaX-0005vi-00@myhost.test.ex
index 78638261b04cee62e838274ddca0ac863a77515c..1e8f6bb19fd4b9f25ecc45a3746c17201d6a4faf 100644 (file)
@@ -1,5 +1,5 @@
 1999-03-02 09:44:33 10HmaX-0005vi-00 <= this-user@testhost.test.ex U=this-user P=local S=sss for other-user@test.ex
-1999-03-02 09:44:33 10HmaX-0005vi-00 => other-user@test.ex R=to_server T=remote_smtp H=127.0.0.1 [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no K C="250- 351 byte chunk, total 351\\n250 OK id=10HmaY-0005vi-00"
+1999-03-02 09:44:33 10HmaX-0005vi-00 => other-user@test.ex R=to_server T=remote_smtp H=127.0.0.1 [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no K C="250- 3nn byte chunk, total 3nn\\n250 OK id=10HmaY-0005vi-00"
 1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
 
 ******** SERVER ********
index 08b08cc84beca1b14b48376cd7568323f701fc5a..1d3ca333207cf4d5a8989d0800f68cfe3e8504f2 100644 (file)
@@ -4,11 +4,22 @@
 1999-03-02 09:44:33 Start queue run: pid=pppp -qqf
 1999-03-02 09:44:33 10HmaX-0005vi-00 => userx@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" C="250 OK id=10HmbA-0005vi-00"
 1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
-1999-03-02 09:44:33 10HmaZ-0005vi-00 => userz@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* C="250 OK id=10HmbB-0005vi-00"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => userz@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLSv1:AES256-SHA:256 CV=no C="250 OK id=10HmbB-0005vi-00"
 1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
-1999-03-02 09:44:33 10HmaY-0005vi-00 => usery@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* C="250 OK id=10HmbC-0005vi-00"
+1999-03-02 09:44:33 10HmaY-0005vi-00 => usery@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLSv1:AES256-SHA:256 CV=no C="250 OK id=10HmbC-0005vi-00"
 1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
 1999-03-02 09:44:33 End queue run: pid=pppp -qqf
+1999-03-02 09:44:33 10HmbD-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for usera@test.ex
+1999-03-02 09:44:33 10HmbE-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for userb@test.ex
+1999-03-02 09:44:33 10HmbF-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for userc@test.ex
+1999-03-02 09:44:33 Start queue run: pid=pppp -qqf
+1999-03-02 09:44:33 10HmbD-0005vi-00 => usera@test.ex R=cl_override T=send_to_server H=127.0.0.1 [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" C="250 OK id=10HmbG-0005vi-00"
+1999-03-02 09:44:33 10HmbD-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbF-0005vi-00 => userc@test.ex R=cl_override T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLSv1:AES256-SHA:256 CV=no C="250 OK id=10HmbH-0005vi-00"
+1999-03-02 09:44:33 10HmbF-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbE-0005vi-00 => userb@test.ex R=cl_override T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLSv1:AES256-SHA:256 CV=no C="250 OK id=10HmbI-0005vi-00"
+1999-03-02 09:44:33 10HmbE-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qqf
 
 ******** SERVER ********
 1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
 1999-03-02 09:44:33 10HmbC-0005vi-00 => usery <usery@test.ex> R=server T=local_delivery
 1999-03-02 09:44:33 10HmbC-0005vi-00 Completed
 1999-03-02 09:44:33 End queue run: pid=pppp -qf
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 SMTP connection from [127.0.0.1]:1112 (TCP/IP connection count = 1)
+1999-03-02 09:44:33 10HmbG-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1]:1112 P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmbD-0005vi-00@myhost.test.ex for usera@test.ex
+1999-03-02 09:44:33 10HmbH-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1]:1112 P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmbF-0005vi-00@myhost.test.ex for userc@test.ex
+1999-03-02 09:44:33 10HmbI-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1]:1112 P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmbE-0005vi-00@myhost.test.ex for userb@test.ex
+1999-03-02 09:44:33 SMTP connection from localhost (myhost.test.ex) [127.0.0.1]:1112 closed by QUIT
+1999-03-02 09:44:33 Start queue run: pid=pppp -qf
+1999-03-02 09:44:33 10HmbG-0005vi-00 => usera <usera@test.ex> R=server T=local_delivery
+1999-03-02 09:44:33 10HmbG-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbH-0005vi-00 => userc <userc@test.ex> R=server T=local_delivery
+1999-03-02 09:44:33 10HmbH-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbI-0005vi-00 => userb <userb@test.ex> R=server T=local_delivery
+1999-03-02 09:44:33 10HmbI-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qf
diff --git a/test/log/2135 b/test/log/2135
new file mode 100644 (file)
index 0000000..50a8dbc
--- /dev/null
@@ -0,0 +1,11 @@
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-smtp S=sss for userb@test.ex
+1999-03-02 09:44:33 10HmaX-0005vi-00 => userb@test.ex R=client T=t1 H=127.0.0.1 [127.0.0.1]:1225 X=TLSv1:AES256-SHA:256 CV=no C="250 OK id=10HmaY-0005vi-00"
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 Start queue run: pid=pppp
+1999-03-02 09:44:33 10HmaY-0005vi-00 => :blackhole: <userb@test.ex> R=target
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp
+
+******** SERVER ********
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= usera@ok.example H=localhost (myhost.test.ex) [127.0.0.1] P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmaX-0005vi-00@myhost.test.ex for userb@test.ex
diff --git a/test/log/2136 b/test/log/2136
new file mode 100644 (file)
index 0000000..33b6423
--- /dev/null
@@ -0,0 +1,14 @@
+1999-03-02 09:44:33 Start queue run: pid=pppp
+1999-03-02 09:44:33 10HmaX-0005vi-00 => :blackhole: <userd@test.ex> R=target
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp
+1999-03-02 09:44:33 Start queue run: pid=pppp
+1999-03-02 09:44:33 10HmaY-0005vi-00 => :blackhole: <userf@test.ex> R=target
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp
+
+******** SERVER ********
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225 port 1224
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= userc@ok.example H=(test.ex) [127.0.0.1] P=esmtp S=sss for userd@test.ex
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225 port 1224
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= usere@ok.example H=(test.ex) [127.0.0.1] P=esmtp S=sss for userf@test.ex
diff --git a/test/log/2137 b/test/log/2137
new file mode 100644 (file)
index 0000000..360f31e
--- /dev/null
@@ -0,0 +1,8 @@
+1999-03-02 09:44:33 U=CALLER F=<> temporarily rejected RCPT <rcpt_defer@test.ex>: Could not complete recipient verify callout: 127.0.0.1 [127.0.0.1] : SMTP error from remote mail server after RCPT TO:<rcpt_defer@test.ex>: 451 Temporary local problem - please try later
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-smtp S=sss for data_defer@test.ex
+1999-03-02 09:44:33 10HmaY-0005vi-00 == data_defer@test.ex R=client T=t1 defer (-46) H=127.0.0.1 [127.0.0.1]:1111: SMTP error from remote mail server after end of data: 451 Temporary local problem - please try later
+
+******** SERVER ********
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 H=localhost (myhost.test.ex) [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no F=<> temporarily rejected RCPT <rcpt_defer@test.ex>
+1999-03-02 09:44:33 10HmaX-0005vi-00 H=localhost (myhost.test.ex) [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no F=<> temporarily rejected after DATA
diff --git a/test/log/2138 b/test/log/2138
new file mode 100644 (file)
index 0000000..6bc8e02
--- /dev/null
@@ -0,0 +1,42 @@
+**NOTE: The delivery lines in this file have been sorted.
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for userx0@test.ex userx1@test.ex
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for usery0@test.ex usery1@test.ex
+1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for userz0@test.ex userz1@test.ex
+1999-03-02 09:44:33 Start queue run: pid=pppp -qqf
+1999-03-02 09:44:33 10HmaX-0005vi-00 => userx0@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" C="250 OK id=10HmbA-0005vi-00"
+1999-03-02 09:44:33 10HmaX-0005vi-00 => userx1@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" C="250 OK id=10HmbB-0005vi-00"
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => userz0@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLSv1:AES256-SHA:256 CV=no C="250 OK id=10HmbC-0005vi-00"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => userz1@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLSv1:AES256-SHA:256 CV=no C="250 OK id=10HmbD-0005vi-00"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaY-0005vi-00 => usery0@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLSv1:AES256-SHA:256 CV=no C="250 OK id=10HmbE-0005vi-00"
+1999-03-02 09:44:33 10HmaY-0005vi-00 => usery1@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLSv1:AES256-SHA:256 CV=no C="250 OK id=10HmbF-0005vi-00"
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qqf
+
+******** SERVER ********
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 SMTP connection from [127.0.0.1]:1111 (TCP/IP connection count = 1)
+1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1]:1111 P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmaX-0005vi-00@myhost.test.ex for userx0@test.ex
+1999-03-02 09:44:33 SMTP connection from [127.0.0.1]:1112 (TCP/IP connection count = 2)
+1999-03-02 09:44:33 10HmbB-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1]:1112 P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmaX-0005vi-00@myhost.test.ex for userx1@test.ex
+1999-03-02 09:44:33 10HmbC-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1]:1111 P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmaZ-0005vi-00@myhost.test.ex for userz0@test.ex
+1999-03-02 09:44:33 10HmbD-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1]:1111 P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmaZ-0005vi-00@myhost.test.ex for userz1@test.ex
+1999-03-02 09:44:33 SMTP connection from localhost (myhost.test.ex) [127.0.0.1]:1111 closed by QUIT
+1999-03-02 09:44:33 10HmbE-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1]:1112 P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmaY-0005vi-00@myhost.test.ex for usery0@test.ex
+1999-03-02 09:44:33 10HmbF-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1]:1112 P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmaY-0005vi-00@myhost.test.ex for usery1@test.ex
+1999-03-02 09:44:33 SMTP connection from localhost (myhost.test.ex) [127.0.0.1]:1112 closed by QUIT
+1999-03-02 09:44:33 Start queue run: pid=pppp -qf
+1999-03-02 09:44:33 10HmbA-0005vi-00 => userx0 <userx0@test.ex> R=server T=local_delivery
+1999-03-02 09:44:33 10HmbA-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbB-0005vi-00 => userx1 <userx1@test.ex> R=server T=local_delivery
+1999-03-02 09:44:33 10HmbB-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbC-0005vi-00 => userz0 <userz0@test.ex> R=server T=local_delivery
+1999-03-02 09:44:33 10HmbC-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbD-0005vi-00 => userz1 <userz1@test.ex> R=server T=local_delivery
+1999-03-02 09:44:33 10HmbD-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbE-0005vi-00 => usery0 <usery0@test.ex> R=server T=local_delivery
+1999-03-02 09:44:33 10HmbE-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbF-0005vi-00 => usery1 <usery1@test.ex> R=server T=local_delivery
+1999-03-02 09:44:33 10HmbF-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp -qf
diff --git a/test/log/2152 b/test/log/2152
deleted file mode 100644 (file)
index 1ed6351..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
-1999-03-02 09:44:33 Start queue run: pid=pppp -qf
-1999-03-02 09:44:33 10HmaX-0005vi-00 => CALLER@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" C="250 OK id=10HmaY-0005vi-00"
-1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
-1999-03-02 09:44:33 End queue run: pid=pppp -qf
-
-******** SERVER ********
-1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
-1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex H=localhost (myhost.test.ex) [127.0.0.1] P=esmtps X=TLSv1:AES256-SHA:256 CV=yes DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" S=sss id=E10HmaX-0005vi-00@myhost.test.ex
index 4b8b84f4b735b3e29f18bfea6f47e7f53f62249c..c2c1f87427a5b4d22ee51f8879690d5e426e8a03 100644 (file)
@@ -1,7 +1,7 @@
 1999-03-02 09:44:33 10HmaX-0005vi-00 <= this-user@testhost.test.ex U=this-user P=local S=sss for other-user@test.ex
 1999-03-02 09:44:33 10HmaX-0005vi-00 [127.0.0.1] SSL verify error: depth=0 error=self signed certificate cert=/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock
 1999-03-02 09:44:33 10HmaX-0005vi-00 [127.0.0.1] SSL verify error: certificate name mismatch: DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" H="127.0.0.1"
-1999-03-02 09:44:33 10HmaX-0005vi-00 => other-user@test.ex R=to_server T=remote_smtp H=127.0.0.1 [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no K C="250- 351 byte chunk, total 351\\n250 OK id=10HmaY-0005vi-00"
+1999-03-02 09:44:33 10HmaX-0005vi-00 => other-user@test.ex R=to_server T=remote_smtp H=127.0.0.1 [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no K C="250- 3nn byte chunk, total 3nn\\n250 OK id=10HmaY-0005vi-00"
 1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
 
 ******** SERVER ********
index d047667e76d13b0bde1c4883bd50cf8e2c28e3ad..7578fc090db56a56a90abb2a04e5f12e05219b1e 100644 (file)
@@ -3,5 +3,5 @@
 1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
 1999-03-02 09:44:33 TLS error on connection from [127.0.0.1] (recv): The TLS connection was non-properly terminated.
 1999-03-02 09:44:33 TLS error on connection from [127.0.0.1] (send): The specified session has been invalidated for some reason.
-1999-03-02 09:44:33 no MAIL in SMTP connection from [127.0.0.1] D=0s X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C=EHLO,STARTTLS,AUTH
-1999-03-02 09:44:33 no MAIL in SMTP connection from (foobar) [127.0.0.1] D=0s A=plain:userx X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C=EHLO,STARTTLS,EHLO,AUTH,QUIT
+1999-03-02 09:44:33 no MAIL in SMTP connection from [127.0.0.1] D=qqs X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C=EHLO,STARTTLS,AUTH
+1999-03-02 09:44:33 no MAIL in SMTP connection from (foobar) [127.0.0.1] D=qqs A=plain:userx X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C=EHLO,STARTTLS,EHLO,AUTH,QUIT
index 2063b33ba123cce62aa2bb6f2fa809a32477d23f..842c13ade244fa8e3b48a440bcc5199e32892fb5 100644 (file)
@@ -1,5 +1,5 @@
 
 ******** SERVER ********
 1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
-1999-03-02 09:44:33 no MAIL in SMTP connection from [127.0.0.1] D=0s X=TLSv1:AES256-SHA:256 CV=no C=EHLO,STARTTLS,AUTH
-1999-03-02 09:44:33 no MAIL in SMTP connection from (foobar) [127.0.0.1] D=0s A=plain:userx X=TLSv1:AES256-SHA:256 CV=no C=EHLO,STARTTLS,EHLO,AUTH,QUIT
+1999-03-02 09:44:33 no MAIL in SMTP connection from [127.0.0.1] D=qqs X=TLSv1:AES256-SHA:256 CV=no C=EHLO,STARTTLS,AUTH
+1999-03-02 09:44:33 no MAIL in SMTP connection from (foobar) [127.0.0.1] D=qqs A=plain:userx X=TLSv1:AES256-SHA:256 CV=no C=EHLO,STARTTLS,EHLO,AUTH,QUIT
diff --git a/test/log/4027 b/test/log/4027
new file mode 100644 (file)
index 0000000..3af3f32
--- /dev/null
@@ -0,0 +1,6 @@
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss
+1999-03-02 09:44:33 10HmaX-0005vi-00 => user_tfo@test.ex R=my_main_router T=my_smtp H=127.0.0.1 [127.0.0.1]:1224 PRX=[127.0.0.1]:1225 TFO C="250 accepted OK"
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss
+1999-03-02 09:44:33 10HmaY-0005vi-00 => user_tfo@test.ex R=my_main_router T=my_smtp H=127.0.0.1 [127.0.0.1]:1224 PRX=[127.0.0.1]:1225 TFO C="250 accepted OK"
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
index a1acf570ea04b87a6396febb3ad95151b6d4f9f5..1c2d5283037981ae2b272d630522dbce3ab71337 100644 (file)
@@ -1,4 +1,5 @@
 1999-03-02 09:44:33 10HmaX-0005vi-00 <= यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local U=CALLER P=utf8local-esmtp S=sss for userz@test.ex
+1999-03-02 09:44:33 10HmaX-0005vi-00 H=127.0.0.1 [127.0.0.1]: utf8 support required but not offered for forwarding
 1999-03-02 09:44:33 10HmaX-0005vi-00 ** userz@test.ex F=<यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local> R=rmt T=rmt_smtp H=127.0.0.1 [127.0.0.1]: utf8 support required but not offered for forwarding
 1999-03-02 09:44:33 10HmaY-0005vi-00 <= <> R=10HmaX-0005vi-00 U=EXIMUSER P=local S=sss for यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local
 1999-03-02 09:44:33 10HmaY-0005vi-00 no immediate delivery: queued by ACL
index e0c0a43d9495e927fa8122d4f9147664bad11e3d..1a9aa5eaec9fa6b062273c4074c49176e9d1b31b 100644 (file)
@@ -1,4 +1,5 @@
 1999-03-02 09:44:33 10HmaX-0005vi-00 <= यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local U=CALLER P=utf8local-esmtp S=sss for userz@test.ex
+1999-03-02 09:44:33 10HmaX-0005vi-00 H=127.0.0.1 [127.0.0.1]: utf8 support required but not offered for forwarding
 1999-03-02 09:44:33 10HmaX-0005vi-00 ** userz@test.ex F=<यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local> R=rmt T=rmt_smtp H=127.0.0.1 [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no: utf8 support required but not offered for forwarding
 1999-03-02 09:44:33 10HmaY-0005vi-00 <= <> R=10HmaX-0005vi-00 U=EXIMUSER P=local S=sss for यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local
 1999-03-02 09:44:33 10HmaY-0005vi-00 no immediate delivery: queued by ACL
index fb5a1defe6e24cd54261af589b90a71d298b12da..f4d4efa3a4b4549bb047c60fdaf60ef9114009fd 100644 (file)
@@ -1,4 +1,5 @@
 1999-03-02 09:44:33 10HmaX-0005vi-00 <= यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local U=CALLER P=utf8local-esmtp S=sss for userz@test.ex
+1999-03-02 09:44:33 10HmaX-0005vi-00 H=127.0.0.1 [127.0.0.1]: utf8 support required but not offered for forwarding
 1999-03-02 09:44:33 10HmaX-0005vi-00 ** userz@test.ex F=<यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local> R=rmt T=rmt_smtp H=127.0.0.1 [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no: utf8 support required but not offered for forwarding
 1999-03-02 09:44:33 10HmaY-0005vi-00 <= <> R=10HmaX-0005vi-00 U=EXIMUSER P=local S=sss for यहलोगहिन्दीक्योंनहींबोलसकतेहैं@japanese.なぜみんな日本語を話してくれないのか.local
 1999-03-02 09:44:33 10HmaY-0005vi-00 no immediate delivery: queued by ACL
index 0e0f8400d30afb51e83ebaec385b284ca7e41a88..ec8ef088e148cbd81b72a93b30e226635d773ad4 100644 (file)
@@ -10,3 +10,6 @@
 1999-03-02 09:44:33 10HmaZ-0005vi-00 DKIM: d=test.ex s=sel c=simple/simple a=rsa-sha256 b=1024 [verification succeeded]
 1999-03-02 09:44:33 10HmaZ-0005vi-00 signer: test.ex bits: 1024
 1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@bloggs.com H=(xxx) [127.0.0.1] P=smtp S=sss id=qwerty1234@disco-zombie.net
+1999-03-02 09:44:33 10HmbA-0005vi-00 DKIM: d=test.ex s=ses_sha1 c=simple/simple a=rsa-sha1 b=512 [verification succeeded]
+1999-03-02 09:44:33 10HmbA-0005vi-00 signer: test.ex bits: 512
+1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@bloggs.com H=(xxx) [127.0.0.1] P=smtp S=sss id=qwerty1234@disco-zombie.net
diff --git a/test/log/4503 b/test/log/4503
new file mode 100644 (file)
index 0000000..7ec93a1
--- /dev/null
@@ -0,0 +1,6 @@
+
+******** SERVER ********
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 10HmaX-0005vi-00 DKIM: d=test.ex s=sel c=simple/simple a=rsa-sha512 b=1024 [verification failed - signature did not verify (headers probably modified in transit)]
+1999-03-02 09:44:33 10HmaX-0005vi-00 signer: test.ex bits: 1024
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@bloggs.com H=(xxx) [127.0.0.1] P=smtp S=sss id=qwerty1234@disco-zombie.net
index fb0f2256784fa7d304b5039d00ac583686fbc84c..027169df06fc3294bf0b51590b8d8c6d1eb41d6a 100644 (file)
@@ -13,3 +13,6 @@
 1999-03-02 09:44:33 10HmbA-0005vi-00 DKIM: validation error: RSA_LONG_LINE
 1999-03-02 09:44:33 10HmbA-0005vi-00 DKIM: Error during validation, disabling signature verification: RSA_LONG_LINE
 1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@bloggs.com H=(xxx) [127.0.0.1] P=smtp S=sss id=qwerty1234@disco-zombie.net
+1999-03-02 09:44:33 10HmbB-0005vi-00 DKIM: d=test.ex s=ses_sha256 c=simple/simple a=rsa-sha1 b=512 [verification failed - unspecified reason]
+1999-03-02 09:44:33 10HmbB-0005vi-00 signer: test.ex bits: 512
+1999-03-02 09:44:33 10HmbB-0005vi-00 <= CALLER@bloggs.com H=(xxx) [127.0.0.1] P=smtp S=sss id=qwerty1234@disco-zombie.net
index e9736fd6f3b1320fc5f16e963812bf40f21b219b..8daa636c025f8fdedfd8f88b509c83ca72848daa 100644 (file)
 1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtp S=sss id=E10HmaZ-0005vi-00@myhost.test.ex
 1999-03-02 09:44:33 10HmbA-0005vi-00 => :blackhole: <b@test.ex> R=server_dump
 1999-03-02 09:44:33 10HmbA-0005vi-00 Completed
-1999-03-02 09:44:33 10HmbC-0005vi-00 DKIM: d=test.ex s=sel c=relaxed/relaxed a=rsa-sha256 b=1024 [verification succeeded]
+1999-03-02 09:44:33 10HmbC-0005vi-00 DKIM: d=test.ex s=sel c=relaxed/relaxed a=rsa-sha256 b=1024 i=allheaders@test.ex [verification succeeded]
 1999-03-02 09:44:33 10HmbC-0005vi-00 signer: test.ex bits: 1024 h=Date:Sender:Message-Id:From:Reply-To:Subject:To:Cc:MIME-Version:Content-Type:Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive
+1999-03-02 09:44:33 10HmbC-0005vi-00 signer: allheaders@test.ex bits: 1024 h=Date:Sender:Message-Id:From:Reply-To:Subject:To:Cc:MIME-Version:Content-Type:Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive
 1999-03-02 09:44:33 10HmbC-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtp S=sss id=E10HmbB-0005vi-00@myhost.test.ex
 1999-03-02 09:44:33 10HmbC-0005vi-00 => :blackhole: <c@test.ex> R=server_dump
 1999-03-02 09:44:33 10HmbC-0005vi-00 Completed
 1999-03-02 09:44:33 10HmbE-0005vi-00 DKIM: d=test.ex s=sel_bad c=relaxed/relaxed a=rsa-sha256 b=1024 [invalid - syntax error in public key record]
-1999-03-02 09:44:33 10HmbE-0005vi-00 signer: test.ex bits: 1024 h=Date:Sender:Message-Id:From:Reply-To:Subject:To:Cc:MIME-Version:Content-Type:Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive
+1999-03-02 09:44:33 10HmbE-0005vi-00 signer: test.ex bits: 1024 h=From
 1999-03-02 09:44:33 10HmbE-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtp S=sss id=E10HmbD-0005vi-00@myhost.test.ex
 1999-03-02 09:44:33 10HmbE-0005vi-00 => :blackhole: <d@test.ex> R=server_dump
 1999-03-02 09:44:33 10HmbE-0005vi-00 Completed
index 052569fa97042fff6ccf1b2ed39ddb4f41654f37..3eaa19eb0cdb5dcb7993aaecf576aba6533e189e 100644 (file)
@@ -1,8 +1,8 @@
 1999-03-02 09:44:33 10HmaX-0005vi-00 <= sender@testhost.test.ex U=sender P=local S=sss for a@test.ex
-1999-03-02 09:44:33 10HmaX-0005vi-00 => a@test.ex R=to_server T=remote_smtp_dkim H=127.0.0.1 [127.0.0.1] K C="250- 661 byte chunk, total 661\\n250 OK id=10HmaY-0005vi-00"
+1999-03-02 09:44:33 10HmaX-0005vi-00 => a@test.ex R=to_server T=remote_smtp_dkim H=127.0.0.1 [127.0.0.1] K C="250- 6nn byte chunk, total 6nn\\n250 OK id=10HmaY-0005vi-00"
 1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
 1999-03-02 09:44:33 10HmaZ-0005vi-00 <= sender@testhost.test.ex U=sender P=local S=sss for b@test.ex
-1999-03-02 09:44:33 10HmaZ-0005vi-00 => b@test.ex R=to_server T=remote_smtp_dkim H=127.0.0.1 [127.0.0.1] K C="250- 8520 byte chunk, total 8848\\n250 OK id=10HmbA-0005vi-00"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => b@test.ex R=to_server T=remote_smtp_dkim H=127.0.0.1 [127.0.0.1] K C="250- 8nn byte chunk, total 8nn\\n250 OK id=10HmbA-0005vi-00"
 1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
 
 ******** SERVER ********
diff --git a/test/log/4523 b/test/log/4523
new file mode 100644 (file)
index 0000000..d1e5ebb
--- /dev/null
@@ -0,0 +1,12 @@
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmaX-0005vi-00 => a@test.ex R=client T=send_to_server H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] C="250 OK id=10HmaY-0005vi-00"
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+
+******** SERVER ********
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 10HmaY-0005vi-00 DKIM: d=test.ex s=sel c=relaxed/relaxed a=rsa-sha512 b=1024 i=allheaders@test.ex [verification succeeded]
+1999-03-02 09:44:33 10HmaY-0005vi-00 signer: test.ex bits: 1024 h=Date:Sender:Message-Id:From:Reply-To:Subject:To:Cc:MIME-Version:Content-Type:Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive
+1999-03-02 09:44:33 10HmaY-0005vi-00 signer: allheaders@test.ex bits: 1024 h=Date:Sender:Message-Id:From:Reply-To:Subject:To:Cc:MIME-Version:Content-Type:Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtp S=sss id=E10HmaX-0005vi-00@myhost.test.ex
+1999-03-02 09:44:33 10HmaY-0005vi-00 => :blackhole: <a@test.ex> R=server_dump
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
diff --git a/test/log/4524 b/test/log/4524
new file mode 100644 (file)
index 0000000..a6d687c
--- /dev/null
@@ -0,0 +1,12 @@
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmaX-0005vi-00 => c@test.ex R=client T=send_to_server H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] C="250 OK id=10HmaY-0005vi-00"
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+
+******** SERVER ********
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+1999-03-02 09:44:33 10HmaY-0005vi-00 DKIM: d=test.ex s=ses c=relaxed/relaxed a=rsa-sha256 b=512 [verification succeeded]
+1999-03-02 09:44:33 10HmaY-0005vi-00 DKIM: d=test.ex s=sel c=relaxed/relaxed a=rsa-sha256 b=1024 [verification succeeded]
+1999-03-02 09:44:33 10HmaY-0005vi-00 signer: test.ex bits: 512 h=From:To:Subject
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@myhost.test.ex H=the.local.host.name (myhost.test.ex) [ip4.ip4.ip4.ip4] P=esmtp S=sss id=E10HmaX-0005vi-00@myhost.test.ex
+1999-03-02 09:44:33 10HmaY-0005vi-00 => :blackhole: <c@test.ex> R=server_dump
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
diff --git a/test/log/4530 b/test/log/4530
new file mode 100644 (file)
index 0000000..f4ff011
--- /dev/null
@@ -0,0 +1,21 @@
+1999-03-02 09:44:33 Start queue run: pid=pppp
+1999-03-02 09:44:33 10HmaX-0005vi-00 => z <z@test.ex> R=localuser T=local_delivery
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaY-0005vi-00 => y <y@test.ex> R=localuser T=local_delivery
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
+1999-03-02 09:44:33 End queue run: pid=pppp
+
+******** SERVER ********
+1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1224 port 1225
+1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@bloggs.com H=(xxx) [127.0.0.1] P=esmtp S=sss for z@test.ex
+1999-03-02 09:44:33 10HmaX-0005vi-00 DKIM: d=test.ex s=sel c=relaxed/relaxed a=rsa-sha256 b=1024 [verification succeeded]
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= <> H=localhost (testhost.test.ex) [127.0.0.1] P=esmtp K S=sss for z@test.ex
+1999-03-02 09:44:33 10HmaX-0005vi-00 no immediate delivery: queued by ACL
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => z@test.ex R=to_server T=remote_smtp_dkim H=127.0.0.1 [127.0.0.1] K C="250- 6nn byte chunk, total 6nn\\n250 OK id=10HmaX-0005vi-00"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@bloggs.com H=(xxx) [127.0.0.1] P=esmtp K S=sss for y@test.ex
+1999-03-02 09:44:33 10HmaY-0005vi-00 DKIM: d=test.ex s=sel c=relaxed/relaxed a=rsa-sha256 b=1024 [verification succeeded]
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= <> H=localhost (testhost.test.ex) [127.0.0.1] P=esmtp K S=sss for y@test.ex
+1999-03-02 09:44:33 10HmaY-0005vi-00 no immediate delivery: queued by ACL
+1999-03-02 09:44:33 10HmbA-0005vi-00 => y@test.ex R=to_server T=remote_smtp_dkim H=127.0.0.1 [127.0.0.1] K C="250- 6nn byte chunk, total 6nn\\n250 OK id=10HmaY-0005vi-00"
+1999-03-02 09:44:33 10HmbA-0005vi-00 Completed
index 35da72e04539fc517be3423be2b5c034949bbd4d..8a1a7a4f4a596655ad610dadddcae006fcfd0427 100644 (file)
@@ -6,6 +6,7 @@
 1999-03-02 09:44:33 10HmaX-0005vi-00 == userx@domain1 R=others T=smtp defer (0) H=localhost4.test.ex [127.0.0.1]: SMTP error from remote mail server after HELO the.local.host.name: 450 I'm busy
 1999-03-02 09:44:33 End queue run: pid=pppp -qf
 1999-03-02 09:44:33 Start queue run: pid=pppp -qf
+1999-03-02 09:44:33 10HmaX-0005vi-00 H=localhost4.test.ex [127.0.0.1]: SMTP error from remote mail server after initial connection: 550 Go away
 1999-03-02 09:44:33 10HmaX-0005vi-00 ** userx@domain1 F=<CALLER@test.ex> R=others T=smtp H=localhost4.test.ex [127.0.0.1]: SMTP error from remote mail server after initial connection: 550 Go away
 1999-03-02 09:44:33 10HmaY-0005vi-00 <= <> R=10HmaX-0005vi-00 U=EXIMUSER P=local S=sss
 1999-03-02 09:44:33 10HmaY-0005vi-00 => CALLER <CALLER@test.ex> F=<> R=all T=local_delivery
@@ -13,6 +14,7 @@
 1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
 1999-03-02 09:44:33 End queue run: pid=pppp -qf
 1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@test.ex U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmaZ-0005vi-00 H=localhost4.test.ex [127.0.0.1]: SMTP error from remote mail server after HELO the.local.host.name: 550 Go away
 1999-03-02 09:44:33 10HmaZ-0005vi-00 ** userx@domain1 F=<CALLER@test.ex> R=others T=smtp H=localhost4.test.ex [127.0.0.1]: SMTP error from remote mail server after HELO the.local.host.name: 550 Go away
 1999-03-02 09:44:33 10HmaZ-0005vi-00 ** usery@domain2 F=<CALLER@test.ex> R=others T=smtp H=localhost4.test.ex [127.0.0.1]: SMTP error from remote mail server after HELO the.local.host.name: 550 Go away
 1999-03-02 09:44:33 10HmbA-0005vi-00 <= <> R=10HmaZ-0005vi-00 U=EXIMUSER P=local S=sss
index 6c45cd787751a828f4a88d4088fc27870fc33ac4..f4ba74f72d255273626a6dbf25f3f6df23469063 100644 (file)
@@ -2,7 +2,7 @@
 1999-03-02 09:44:33 10HmaX-0005vi-00 => userx <userx@test.ex> R=all T=local_delivery
 1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
 1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@test.ex U=CALLER P=local S=sss
-1999-03-02 09:44:33 10HmaY-0005vi-00 == userx@test.ex R=all T=local_delivery defer (-22): mailbox is full (MTA-imposed quota exceeded while writing to tmp/MAILDIR.myhost.test.ex)
+1999-03-02 09:44:33 10HmaY-0005vi-00 == userx@test.ex R=all T=local_delivery defer (-22): mailbox is full (MTA-imposed filecount quota exceeded while writing to tmp/MAILDIR.myhost.test.ex)
 1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@test.ex U=CALLER P=local S=sss
 1999-03-02 09:44:33 10HmaZ-0005vi-00 == qqq@test.ex R=all T=local_delivery defer (-22): mailbox is full (MTA-imposed filecount quota exceeded while writing to tmp/MAILDIR.myhost.test.ex)
 1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@test.ex U=CALLER P=local S=sss
diff --git a/test/log/5010 b/test/log/5010
new file mode 100644 (file)
index 0000000..deaedc6
--- /dev/null
@@ -0,0 +1,12 @@
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@test.ex U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmaX-0005vi-00 => userx <userx@test.ex> R=all T=local_delivery
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@test.ex U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmaY-0005vi-00 == userx@test.ex R=all T=local_delivery defer (-22): mailbox is full (MTA-imposed filecount quota exceeded while writing to tmp/MAILDIR.myhost.test.ex)
+1999-03-02 09:44:33 10HmaY-0005vi-00 ** userx@test.ex: retry timeout exceeded
+1999-03-02 09:44:33 10HmaZ-0005vi-00 <= <> R=10HmaY-0005vi-00 U=EXIMUSER P=local S=sss
+1999-03-02 09:44:33 10HmaZ-0005vi-00 == CALLER@test.ex R=all T=local_delivery defer (-22): mailbox is full (MTA-imposed filecount quota exceeded while writing to tmp/MAILDIR.myhost.test.ex)
+1999-03-02 09:44:33 10HmaZ-0005vi-00 ** CALLER@test.ex: retry timeout exceeded
+1999-03-02 09:44:33 10HmaZ-0005vi-00 CALLER@test.ex: error ignored
+1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
diff --git a/test/log/5011 b/test/log/5011
new file mode 100644 (file)
index 0000000..e0c7efe
--- /dev/null
@@ -0,0 +1,18 @@
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@test.ex U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmaX-0005vi-00 == userx@test.ex R=all T=local_delivery defer (-22): mailbox is full (MTA-imposed quota exceeded while writing to tmp/MAILDIR.myhost.test.ex)
+1999-03-02 09:44:33 10HmaX-0005vi-00 ** userx@test.ex: retry timeout exceeded
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= <> R=10HmaX-0005vi-00 U=EXIMUSER P=local S=sss
+1999-03-02 09:44:33 10HmaY-0005vi-00 == CALLER@test.ex R=all T=local_delivery defer (-22): mailbox is full (MTA-imposed quota exceeded while writing to tmp/MAILDIR.myhost.test.ex)
+1999-03-02 09:44:33 10HmaY-0005vi-00 ** CALLER@test.ex: retry timeout exceeded
+1999-03-02 09:44:33 10HmaY-0005vi-00 CALLER@test.ex: error ignored
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@test.ex U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmaZ-0005vi-00 == userx@test.ex R=all T=local_delivery defer (-22): mailbox is full (MTA-imposed quota exceeded while writing to tmp/MAILDIR.myhost.test.ex)
+1999-03-02 09:44:33 10HmaZ-0005vi-00 ** userx@test.ex: retry timeout exceeded
+1999-03-02 09:44:33 10HmbA-0005vi-00 <= <> R=10HmaZ-0005vi-00 U=EXIMUSER P=local S=sss
+1999-03-02 09:44:33 10HmbA-0005vi-00 == CALLER@test.ex R=all T=local_delivery defer (-22): mailbox is full (MTA-imposed quota exceeded while writing to tmp/MAILDIR.myhost.test.ex)
+1999-03-02 09:44:33 10HmbA-0005vi-00 ** CALLER@test.ex: retry timeout exceeded
+1999-03-02 09:44:33 10HmbA-0005vi-00 CALLER@test.ex: error ignored
+1999-03-02 09:44:33 10HmbA-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
diff --git a/test/log/5012 b/test/log/5012
new file mode 100644 (file)
index 0000000..e2d436a
--- /dev/null
@@ -0,0 +1,6 @@
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@test.ex U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmaX-0005vi-00 => userx <userx@test.ex> R=all T=local_delivery
+1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@test.ex U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmaY-0005vi-00 => userx <userx@test.ex> R=all T=local_delivery
+1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
index 2ddf7e2cdfb89443bc43f28db27c81486c12b6c9..56436984578fd004bc9d5e525d5e7a9e815b558a 100644 (file)
@@ -1,35 +1,35 @@
-1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss for norequire@test.ex
 1999-03-02 09:44:33 10HmaX-0005vi-00 => norequire@test.ex R=client T=send_to_server2 H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] X=TLSv1:AES256-SHA:256 CV=yes DN="/CN=server1.example.com" C="250 OK id=10HmaY-0005vi-00"
 1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
-1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss for nostaple@test.ex
 1999-03-02 09:44:33 10HmaZ-0005vi-00 => nostaple@test.ex R=client T=send_to_server1 H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] X=TLSv1:AES256-SHA:256 CV=yes DN="/CN=server1.example.com" C="250 OK id=10HmbA-0005vi-00"
 1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
-1999-03-02 09:44:33 10HmbB-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmbB-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss for CALLER@test.ex
 1999-03-02 09:44:33 10HmbB-0005vi-00 => CALLER@test.ex R=client T=send_to_server3 H=127.0.0.1 [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=yes DN="/CN=server1.example.com" C="250 OK id=10HmbC-0005vi-00"
 1999-03-02 09:44:33 10HmbB-0005vi-00 Completed
-1999-03-02 09:44:33 10HmbD-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmbD-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss for CALLER@test.ex
 1999-03-02 09:44:33 10HmbD-0005vi-00 Received TLS status callback, null content
 1999-03-02 09:44:33 10HmbD-0005vi-00 == CALLER@test.ex R=client T=send_to_server3 defer (-37) H=127.0.0.1 [127.0.0.1]: TLS session: (SSL_connect): error: <<detail omitted>>
-1999-03-02 09:44:33 10HmbE-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmbE-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss for CALLER@test.ex
 1999-03-02 09:44:33 10HmbE-0005vi-00 Server certificate revoked; reason: superseded
 1999-03-02 09:44:33 10HmbE-0005vi-00 == CALLER@test.ex R=client T=send_to_server3 defer (-37) H=127.0.0.1 [127.0.0.1]: TLS session: (SSL_connect): error: <<detail omitted>>
-1999-03-02 09:44:33 10HmbF-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmbF-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss for CALLER@test.ex
 1999-03-02 09:44:33 10HmbF-0005vi-00 Server OSCP dates invalid
 1999-03-02 09:44:33 10HmbF-0005vi-00 == CALLER@test.ex R=client T=send_to_server3 defer (-37) H=127.0.0.1 [127.0.0.1]: TLS session: (SSL_connect): error: <<detail omitted>>
 
 ******** SERVER ********
 1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
 1999-03-02 09:44:33 10HmaY-0005vi-00 client claims: ocsp status 1 (notresp)
-1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@server1.example.com H=the.local.host.name (server1.example.com) [ip4.ip4.ip4.ip4] P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmaX-0005vi-00@server1.example.com
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@server1.example.com H=the.local.host.name (server1.example.com) [ip4.ip4.ip4.ip4] P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmaX-0005vi-00@server1.example.com for norequire@test.ex
 1999-03-02 09:44:33 10HmaY-0005vi-00 => :blackhole: <norequire@test.ex> R=server
 1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
 1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
 1999-03-02 09:44:33 10HmbA-0005vi-00 client claims: ocsp status 0 (notreq)
-1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@server1.example.com H=the.local.host.name (server1.example.com) [ip4.ip4.ip4.ip4] P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmaZ-0005vi-00@server1.example.com
+1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@server1.example.com H=the.local.host.name (server1.example.com) [ip4.ip4.ip4.ip4] P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmaZ-0005vi-00@server1.example.com for nostaple@test.ex
 1999-03-02 09:44:33 10HmbA-0005vi-00 => :blackhole: <nostaple@test.ex> R=server
 1999-03-02 09:44:33 10HmbA-0005vi-00 Completed
 1999-03-02 09:44:33 10HmbC-0005vi-00 client claims: ocsp status 4 (verified)
-1999-03-02 09:44:33 10HmbC-0005vi-00 <= CALLER@server1.example.com H=(helo.data.changed) [127.0.0.1] P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmbB-0005vi-00@server1.example.com
+1999-03-02 09:44:33 10HmbC-0005vi-00 <= CALLER@server1.example.com H=(helo.data.changed) [127.0.0.1] P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmbB-0005vi-00@server1.example.com for CALLER@test.ex
 1999-03-02 09:44:33 10HmbC-0005vi-00 => :blackhole: <CALLER@test.ex> R=server
 1999-03-02 09:44:33 10HmbC-0005vi-00 Completed
 1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
index 3fc357b76db34dadfdeba9fede35c68d95974653..2b82395f9733653d389e032f6ddc8add13f0834f 100644 (file)
@@ -1,28 +1,28 @@
-1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss
-1999-03-02 09:44:33 10HmaX-0005vi-00 => norequire@test.ex R=client T=send_to_server2 H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] X=TLSv1:AES256-SHA:256 CV=yes DN="/CN=server1.example.com" C="250 OK id=10HmaY-0005vi-00"
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss for norequire_1@test.ex
+1999-03-02 09:44:33 10HmaX-0005vi-00 => norequire_1@test.ex R=client T=send_to_server2 H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] X=TLSv1:AES256-SHA:256 CV=yes DN="/CN=server1.example.com" C="250 OK id=10HmaY-0005vi-00"
 1999-03-02 09:44:33 10HmaX-0005vi-00 client ocsp status: 1 (notresp)
 1999-03-02 09:44:33 10HmaX-0005vi-00 Completed
-1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss
-1999-03-02 09:44:33 10HmaZ-0005vi-00 => norequire@test.ex R=client T=send_to_server2 H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] X=TLSv1:AES256-SHA:256 CV=yes DN="/CN=server1.example.com" C="250 OK id=10HmbA-0005vi-00"
+1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss for norequire_2@test.ex
+1999-03-02 09:44:33 10HmaZ-0005vi-00 => norequire_2@test.ex R=client T=send_to_server2 H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] X=TLSv1:AES256-SHA:256 CV=yes DN="/CN=server1.example.com" C="250 OK id=10HmbA-0005vi-00"
 1999-03-02 09:44:33 10HmaZ-0005vi-00 client ocsp status: 4 (verified)
 1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
-1999-03-02 09:44:33 10HmbB-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmbB-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss for nostaple@test.ex
 1999-03-02 09:44:33 10HmbB-0005vi-00 => nostaple@test.ex R=client T=send_to_server1 H=ip4.ip4.ip4.ip4 [ip4.ip4.ip4.ip4] X=TLSv1:AES256-SHA:256 CV=yes DN="/CN=server1.example.com" C="250 OK id=10HmbC-0005vi-00"
 1999-03-02 09:44:33 10HmbB-0005vi-00 client ocsp status: 0 (notreq)
 1999-03-02 09:44:33 10HmbB-0005vi-00 Completed
-1999-03-02 09:44:33 10HmbD-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmbD-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss for good@test.ex
 1999-03-02 09:44:33 10HmbD-0005vi-00 => good@test.ex R=client T=send_to_server3 H=127.0.0.1 [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=yes DN="/CN=server1.example.com" C="250 OK id=10HmbE-0005vi-00"
 1999-03-02 09:44:33 10HmbD-0005vi-00 client ocsp status: 4 (verified)
 1999-03-02 09:44:33 10HmbD-0005vi-00 Completed
-1999-03-02 09:44:33 10HmbF-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmbF-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss for failrequire@test.ex
 1999-03-02 09:44:33 10HmbF-0005vi-00 Received TLS status callback, null content
 1999-03-02 09:44:33 10HmbF-0005vi-00 client ocsp status: 1 (notresp)
 1999-03-02 09:44:33 10HmbF-0005vi-00 == failrequire@test.ex R=client T=send_to_server3 defer (-37) H=127.0.0.1 [127.0.0.1]: TLS session: (SSL_connect): error: <<detail omitted>>
-1999-03-02 09:44:33 10HmbG-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmbG-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss for failrevoked@test.ex
 1999-03-02 09:44:33 10HmbG-0005vi-00 Server certificate revoked; reason: superseded
 1999-03-02 09:44:33 10HmbG-0005vi-00 client ocsp status: 3 (failed)
 1999-03-02 09:44:33 10HmbG-0005vi-00 == failrevoked@test.ex R=client T=send_to_server3 defer (-37) H=127.0.0.1 [127.0.0.1]: TLS session: (SSL_connect): error: <<detail omitted>>
-1999-03-02 09:44:33 10HmbH-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss
+1999-03-02 09:44:33 10HmbH-0005vi-00 <= CALLER@server1.example.com U=CALLER P=local S=sss for failexpired@test.ex
 1999-03-02 09:44:33 10HmbH-0005vi-00 Server OSCP dates invalid
 1999-03-02 09:44:33 10HmbH-0005vi-00 client ocsp status: 3 (failed)
 1999-03-02 09:44:33 10HmbH-0005vi-00 == failexpired@test.ex R=client T=send_to_server3 defer (-37) H=127.0.0.1 [127.0.0.1]: TLS session: (SSL_connect): error: <<detail omitted>>
 ******** SERVER ********
 1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
 1999-03-02 09:44:33 10HmaY-0005vi-00 client claims: ocsp status 1
-1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@server1.example.com H=the.local.host.name (server1.example.com) [ip4.ip4.ip4.ip4] P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmaX-0005vi-00@server1.example.com
-1999-03-02 09:44:33 10HmaY-0005vi-00 => :blackhole: <norequire@test.ex> R=server
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= CALLER@server1.example.com H=the.local.host.name (server1.example.com) [ip4.ip4.ip4.ip4] P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmaX-0005vi-00@server1.example.com for norequire_1@test.ex
+1999-03-02 09:44:33 10HmaY-0005vi-00 => :blackhole: <norequire_1@test.ex> R=server
 1999-03-02 09:44:33 10HmaY-0005vi-00 Completed
 1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
 1999-03-02 09:44:33 10HmbA-0005vi-00 client claims: ocsp status 4
-1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@server1.example.com H=the.local.host.name (server1.example.com) [ip4.ip4.ip4.ip4] P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmaZ-0005vi-00@server1.example.com
-1999-03-02 09:44:33 10HmbA-0005vi-00 => :blackhole: <norequire@test.ex> R=server
+1999-03-02 09:44:33 10HmbA-0005vi-00 <= CALLER@server1.example.com H=the.local.host.name (server1.example.com) [ip4.ip4.ip4.ip4] P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmaZ-0005vi-00@server1.example.com for norequire_2@test.ex
+1999-03-02 09:44:33 10HmbA-0005vi-00 => :blackhole: <norequire_2@test.ex> R=server
 1999-03-02 09:44:33 10HmbA-0005vi-00 Completed
 1999-03-02 09:44:33 10HmbC-0005vi-00 client claims: ocsp status 0
-1999-03-02 09:44:33 10HmbC-0005vi-00 <= CALLER@server1.example.com H=the.local.host.name (server1.example.com) [ip4.ip4.ip4.ip4] P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmbB-0005vi-00@server1.example.com
+1999-03-02 09:44:33 10HmbC-0005vi-00 <= CALLER@server1.example.com H=the.local.host.name (server1.example.com) [ip4.ip4.ip4.ip4] P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmbB-0005vi-00@server1.example.com for nostaple@test.ex
 1999-03-02 09:44:33 10HmbC-0005vi-00 => :blackhole: <nostaple@test.ex> R=server
 1999-03-02 09:44:33 10HmbC-0005vi-00 Completed
 1999-03-02 09:44:33 10HmbE-0005vi-00 client claims: ocsp status 4
-1999-03-02 09:44:33 10HmbE-0005vi-00 <= CALLER@server1.example.com H=(helo.data.changed) [127.0.0.1] P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmbD-0005vi-00@server1.example.com
+1999-03-02 09:44:33 10HmbE-0005vi-00 <= CALLER@server1.example.com H=(helo.data.changed) [127.0.0.1] P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmbD-0005vi-00@server1.example.com for good@test.ex
 1999-03-02 09:44:33 10HmbE-0005vi-00 => :blackhole: <good@test.ex> R=server
 1999-03-02 09:44:33 10HmbE-0005vi-00 Completed
 1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
index 6d65bf25ee7c01785167d943f7cd0d1778658421..9d134ca6d8bd2c8d8ccbc11960d4eaf031e8117c 100644 (file)
@@ -26,6 +26,9 @@
 1999-03-02 09:44:33 10HmbH-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for CALLER@mxdanelazy.test.ex
 1999-03-02 09:44:33 10HmbI-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for CALLER@dane.no.1.test.ex
 1999-03-02 09:44:33 10HmbJ-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for CALLER@dane.no.2.test.ex
+1999-03-02 09:44:33 10HmbK-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for CALLER@danebroken1.test.ex
+1999-03-02 09:44:33 10HmbL-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for CALLER@dane.no.3.test.ex
+1999-03-02 09:44:33 10HmbM-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss for CALLER@dane.no.4.test.ex
 1999-03-02 09:44:33 Start queue run: pid=pppp -qf
 1999-03-02 09:44:33 10HmbH-0005vi-00 H=danelazy.test.ex [ip4.ip4.ip4.ip4]: DANE error: tlsa lookup DEFER
 1999-03-02 09:44:33 10HmbH-0005vi-00 H=danelazy2.test.ex [127.0.0.1]: DANE error: tlsa lookup DEFER
 1999-03-02 09:44:33 10HmbI-0005vi-00 Completed
 1999-03-02 09:44:33 10HmbJ-0005vi-00 [127.0.0.1] SSL verify error: depth=0 error=self signed certificate cert=/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock
 1999-03-02 09:44:33 10HmbJ-0005vi-00 [127.0.0.1] SSL verify error: certificate name mismatch: DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" H="dane.no.2.test.ex"
-1999-03-02 09:44:33 10HmbJ-0005vi-00 => CALLER@dane.no.2.test.ex R=client T=send_to_server H=dane.no.2.test.ex [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" C="250 OK id=10HmbK-0005vi-00"
+1999-03-02 09:44:33 10HmbJ-0005vi-00 => CALLER@dane.no.2.test.ex R=client T=send_to_server H=dane.no.2.test.ex [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" C="250 OK id=10HmbN-0005vi-00"
 1999-03-02 09:44:33 10HmbJ-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbK-0005vi-00 H=danebroken1.test.ex [127.0.0.1]: DANE error: tlsa lookup DEFER
+1999-03-02 09:44:33 10HmbK-0005vi-00 == CALLER@danebroken1.test.ex R=client T=send_to_server defer (-36): DANE error: tlsa lookup DEFER
+1999-03-02 09:44:33 10HmbL-0005vi-00 ** CALLER@dane.no.3.test.ex R=client T=send_to_server: DANE error: tlsa lookup FAIL
+1999-03-02 09:44:33 10HmbL-0005vi-00 CALLER@dane.no.3.test.ex: error ignored
+1999-03-02 09:44:33 10HmbL-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbM-0005vi-00 [127.0.0.1] SSL verify error: depth=0 error=self signed certificate cert=/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock
+1999-03-02 09:44:33 10HmbM-0005vi-00 [127.0.0.1] SSL verify error: certificate name mismatch: DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" H="dane.no.4.test.ex"
+1999-03-02 09:44:33 10HmbM-0005vi-00 => CALLER@dane.no.4.test.ex R=client T=send_to_server H=dane.no.4.test.ex [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" C="250 OK id=10HmbO-0005vi-00"
+1999-03-02 09:44:33 10HmbM-0005vi-00 Completed
 1999-03-02 09:44:33 End queue run: pid=pppp -qf
 
 ******** SERVER ********
@@ -60,6 +72,9 @@
 1999-03-02 09:44:33 10HmbG-0005vi-00 => :blackhole: <CALLER@thishost.test.ex> R=server
 1999-03-02 09:44:33 10HmbG-0005vi-00 Completed
 1999-03-02 09:44:33 exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
-1999-03-02 09:44:33 10HmbK-0005vi-00 <= <> H=localhost (myhost.test.ex) [127.0.0.1] P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmbJ-0005vi-00@myhost.test.ex for CALLER@dane.no.2.test.ex
-1999-03-02 09:44:33 10HmbK-0005vi-00 => :blackhole: <CALLER@dane.no.2.test.ex> R=server
-1999-03-02 09:44:33 10HmbK-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbN-0005vi-00 <= <> H=localhost (myhost.test.ex) [127.0.0.1] P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmbJ-0005vi-00@myhost.test.ex for CALLER@dane.no.2.test.ex
+1999-03-02 09:44:33 10HmbN-0005vi-00 => :blackhole: <CALLER@dane.no.2.test.ex> R=server
+1999-03-02 09:44:33 10HmbN-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbO-0005vi-00 <= <> H=localhost (myhost.test.ex) [127.0.0.1] P=esmtps X=TLSv1:AES256-SHA:256 CV=no S=sss id=E10HmbM-0005vi-00@myhost.test.ex for CALLER@dane.no.4.test.ex
+1999-03-02 09:44:33 10HmbO-0005vi-00 => :blackhole: <CALLER@dane.no.4.test.ex> R=server
+1999-03-02 09:44:33 10HmbO-0005vi-00 Completed
diff --git a/test/mail/0906.a b/test/mail/0906.a
new file mode 100644 (file)
index 0000000..a55f68d
--- /dev/null
@@ -0,0 +1,109 @@
+From MAILER-DAEMON Tue Mar 02 09:44:33 1999
+Return-path: <>
+Received: from localhost ([127.0.0.1] helo=testhost.test.ex)
+       by testhost.test.ex with esmtp (Exim x.yz)
+       id 10HmaX-0005vi-00
+       for a@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from [127.0.0.1] (helo=test.com)
+       by testhost.test.ex with esmtp (Exim x.yz)
+       (envelope-from <sender@dom>)
+       id 10HmaY-0005vi-00
+       for a@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Subject: foo
+X-body-linecount: 0
+X-message-linecount: 10
+X-received-count: 2
+
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+.dot
+tail
+
diff --git a/test/mail/2013.usera b/test/mail/2013.usera
new file mode 100644 (file)
index 0000000..8e17aee
--- /dev/null
@@ -0,0 +1,18 @@
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from localhost ([127.0.0.1]:1112 helo=myhost.test.ex)
+       by myhost.test.ex with esmtps (TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256)
+       (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmbG-0005vi-00
+       for usera@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmbD-0005vi-00
+       for usera@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmbD-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+TLS: cipher=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 peerdn=
+
+Test message 1
+
diff --git a/test/mail/2013.userb b/test/mail/2013.userb
new file mode 100644 (file)
index 0000000..556fb35
--- /dev/null
@@ -0,0 +1,18 @@
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from localhost ([127.0.0.1]:1112 helo=myhost.test.ex)
+       by myhost.test.ex with esmtps (TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256)
+       (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmbI-0005vi-00
+       for userb@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmbE-0005vi-00
+       for userb@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmbE-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+TLS: cipher=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 peerdn=
+
+Test message 2
+
diff --git a/test/mail/2013.userc b/test/mail/2013.userc
new file mode 100644 (file)
index 0000000..818aafb
--- /dev/null
@@ -0,0 +1,18 @@
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from localhost ([127.0.0.1]:1112 helo=myhost.test.ex)
+       by myhost.test.ex with esmtps (TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256)
+       (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmbH-0005vi-00
+       for userc@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmbF-0005vi-00
+       for userc@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmbF-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+TLS: cipher=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 peerdn=
+
+Test message 3
+
diff --git a/test/mail/2038.userx0 b/test/mail/2038.userx0
new file mode 100644 (file)
index 0000000..4acc591
--- /dev/null
@@ -0,0 +1,17 @@
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from localhost ([127.0.0.1]:1111 helo=myhost.test.ex)
+       by myhost.test.ex with esmtps (TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256)
+       (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmbA-0005vi-00
+       for userx0@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmaX-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaX-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+TLS: cipher=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 peerdn=
+
+Test message 1
+
diff --git a/test/mail/2038.userx1 b/test/mail/2038.userx1
new file mode 100644 (file)
index 0000000..2d4691e
--- /dev/null
@@ -0,0 +1,17 @@
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from localhost ([127.0.0.1]:1112 helo=myhost.test.ex)
+       by myhost.test.ex with esmtps (TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256)
+       (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmbB-0005vi-00
+       for userx1@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmaX-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaX-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+TLS: cipher=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 peerdn=
+
+Test message 1
+
diff --git a/test/mail/2038.usery0 b/test/mail/2038.usery0
new file mode 100644 (file)
index 0000000..0959b77
--- /dev/null
@@ -0,0 +1,17 @@
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from localhost ([127.0.0.1]:1112 helo=myhost.test.ex)
+       by myhost.test.ex with esmtps (TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256)
+       (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmbE-0005vi-00
+       for usery0@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmaY-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaY-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+TLS: cipher=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 peerdn=
+
+Test message 2
+
diff --git a/test/mail/2038.usery1 b/test/mail/2038.usery1
new file mode 100644 (file)
index 0000000..0aaf2a5
--- /dev/null
@@ -0,0 +1,17 @@
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from localhost ([127.0.0.1]:1112 helo=myhost.test.ex)
+       by myhost.test.ex with esmtps (TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256)
+       (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmbF-0005vi-00
+       for usery1@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmaY-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaY-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+TLS: cipher=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 peerdn=
+
+Test message 2
+
diff --git a/test/mail/2038.userz0 b/test/mail/2038.userz0
new file mode 100644 (file)
index 0000000..dac74ad
--- /dev/null
@@ -0,0 +1,17 @@
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from localhost ([127.0.0.1]:1111 helo=myhost.test.ex)
+       by myhost.test.ex with esmtps (TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256)
+       (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmbC-0005vi-00
+       for userz0@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmaZ-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaZ-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+TLS: cipher=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 peerdn=
+
+Test message 3
+
diff --git a/test/mail/2038.userz1 b/test/mail/2038.userz1
new file mode 100644 (file)
index 0000000..4797ffd
--- /dev/null
@@ -0,0 +1,17 @@
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from localhost ([127.0.0.1]:1111 helo=myhost.test.ex)
+       by myhost.test.ex with esmtps (TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256)
+       (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmbD-0005vi-00
+       for userz1@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmaZ-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaZ-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+TLS: cipher=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 peerdn=
+
+Test message 3
+
diff --git a/test/mail/2113.usera b/test/mail/2113.usera
new file mode 100644 (file)
index 0000000..43e9507
--- /dev/null
@@ -0,0 +1,18 @@
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from localhost ([127.0.0.1]:1112 helo=myhost.test.ex)
+       by myhost.test.ex with esmtps (TLSv1:AES256-SHA:256)
+       (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmbG-0005vi-00
+       for usera@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmbD-0005vi-00
+       for usera@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmbD-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+TLS: cipher=TLSv1:AES256-SHA:256 peerdn=
+
+Test message 1
+
diff --git a/test/mail/2113.userb b/test/mail/2113.userb
new file mode 100644 (file)
index 0000000..d93f45f
--- /dev/null
@@ -0,0 +1,18 @@
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from localhost ([127.0.0.1]:1112 helo=myhost.test.ex)
+       by myhost.test.ex with esmtps (TLSv1:AES256-SHA:256)
+       (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmbI-0005vi-00
+       for userb@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmbE-0005vi-00
+       for userb@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmbE-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+TLS: cipher=TLSv1:AES256-SHA:256 peerdn=
+
+Test message 2
+
diff --git a/test/mail/2113.userc b/test/mail/2113.userc
new file mode 100644 (file)
index 0000000..5bc9043
--- /dev/null
@@ -0,0 +1,18 @@
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from localhost ([127.0.0.1]:1112 helo=myhost.test.ex)
+       by myhost.test.ex with esmtps (TLSv1:AES256-SHA:256)
+       (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmbH-0005vi-00
+       for userc@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmbF-0005vi-00
+       for userc@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmbF-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+TLS: cipher=TLSv1:AES256-SHA:256 peerdn=
+
+Test message 3
+
diff --git a/test/mail/2138.userx0 b/test/mail/2138.userx0
new file mode 100644 (file)
index 0000000..952a454
--- /dev/null
@@ -0,0 +1,17 @@
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from localhost ([127.0.0.1]:1111 helo=myhost.test.ex)
+       by myhost.test.ex with esmtps (TLSv1:AES256-SHA:256)
+       (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmbA-0005vi-00
+       for userx0@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmaX-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaX-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+TLS: cipher=TLSv1:AES256-SHA:256 peerdn=
+
+Test message 1
+
diff --git a/test/mail/2138.userx1 b/test/mail/2138.userx1
new file mode 100644 (file)
index 0000000..a6f4b97
--- /dev/null
@@ -0,0 +1,17 @@
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from localhost ([127.0.0.1]:1112 helo=myhost.test.ex)
+       by myhost.test.ex with esmtps (TLSv1:AES256-SHA:256)
+       (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmbB-0005vi-00
+       for userx1@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmaX-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaX-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+TLS: cipher=TLSv1:AES256-SHA:256 peerdn=
+
+Test message 1
+
diff --git a/test/mail/2138.usery0 b/test/mail/2138.usery0
new file mode 100644 (file)
index 0000000..d0c8c27
--- /dev/null
@@ -0,0 +1,17 @@
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from localhost ([127.0.0.1]:1112 helo=myhost.test.ex)
+       by myhost.test.ex with esmtps (TLSv1:AES256-SHA:256)
+       (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmbE-0005vi-00
+       for usery0@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmaY-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaY-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+TLS: cipher=TLSv1:AES256-SHA:256 peerdn=
+
+Test message 2
+
diff --git a/test/mail/2138.usery1 b/test/mail/2138.usery1
new file mode 100644 (file)
index 0000000..b7d4c66
--- /dev/null
@@ -0,0 +1,17 @@
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from localhost ([127.0.0.1]:1112 helo=myhost.test.ex)
+       by myhost.test.ex with esmtps (TLSv1:AES256-SHA:256)
+       (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmbF-0005vi-00
+       for usery1@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmaY-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaY-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+TLS: cipher=TLSv1:AES256-SHA:256 peerdn=
+
+Test message 2
+
diff --git a/test/mail/2138.userz0 b/test/mail/2138.userz0
new file mode 100644 (file)
index 0000000..4a0f923
--- /dev/null
@@ -0,0 +1,17 @@
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from localhost ([127.0.0.1]:1111 helo=myhost.test.ex)
+       by myhost.test.ex with esmtps (TLSv1:AES256-SHA:256)
+       (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmbC-0005vi-00
+       for userz0@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmaZ-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaZ-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+TLS: cipher=TLSv1:AES256-SHA:256 peerdn=
+
+Test message 3
+
diff --git a/test/mail/2138.userz1 b/test/mail/2138.userz1
new file mode 100644 (file)
index 0000000..5aca0f5
--- /dev/null
@@ -0,0 +1,17 @@
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from localhost ([127.0.0.1]:1111 helo=myhost.test.ex)
+       by myhost.test.ex with esmtps (TLSv1:AES256-SHA:256)
+       (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmbD-0005vi-00
+       for userz1@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmaZ-0005vi-00; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaZ-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+TLS: cipher=TLSv1:AES256-SHA:256 peerdn=
+
+Test message 3
+
diff --git a/test/mail/4530.y b/test/mail/4530.y
new file mode 100644 (file)
index 0000000..445e41a
--- /dev/null
@@ -0,0 +1,26 @@
+From MAILER-DAEMON Tue Mar 02 09:44:33 1999
+Return-path: <>
+Received: from localhost ([127.0.0.1] helo=testhost.test.ex)
+       by testhost.test.ex with esmtp (Exim x.yz)
+       id 10HmaY-0005vi-00
+       for y@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=test.ex;
+       s=sel; h=LIST; bh=CVpkzY75tV/NCKk5pPx4GnM3NX83xwCiT0xVwo0G1Rs=; b=TIqPqpKM5qf
+       ZFlv2H8yio5RybWA3sLCtVmE6HmBhBKqW+uqLKG2grqJhVMJ3qXnvQQ3ixnMjMlJqfCpEBtxfsSR9
+       MGLPP9ZMdlrBNEL6XKlgE+X8bAra5zkuLZs8gy8H3/mtEfoKPs4ltB/ZK/j2FHG2+CEx+TDTIkh9E
+       wkAMrA=;
+Received: from [127.0.0.1] (helo=xxx)
+       by testhost.test.ex with esmtp (Exim x.yz)
+       (envelope-from <CALLER@bloggs.com>)
+       id 10HmbA-0005vi-00
+       for y@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Subject: simple test
+X-body-linecount: 0
+X-message-linecount: 15
+X-received-count: 2
+
+Line 1: This is a simple test.
+Line 2: This is a simple test.
+.Line 3 has a leading dot
+last line: 4
+
diff --git a/test/mail/4530.z b/test/mail/4530.z
new file mode 100644 (file)
index 0000000..1b47355
--- /dev/null
@@ -0,0 +1,26 @@
+From MAILER-DAEMON Tue Mar 02 09:44:33 1999
+Return-path: <>
+Received: from localhost ([127.0.0.1] helo=testhost.test.ex)
+       by testhost.test.ex with esmtp (Exim x.yz)
+       id 10HmaX-0005vi-00
+       for z@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=test.ex;
+       s=sel; h=LIST; bh=CVpkzY75tV/NCKk5pPx4GnM3NX83xwCiT0xVwo0G1Rs=; b=TIqPqpKM5qf
+       ZFlv2H8yio5RybWA3sLCtVmE6HmBhBKqW+uqLKG2grqJhVMJ3qXnvQQ3ixnMjMlJqfCpEBtxfsSR9
+       MGLPP9ZMdlrBNEL6XKlgE+X8bAra5zkuLZs8gy8H3/mtEfoKPs4ltB/ZK/j2FHG2+CEx+TDTIkh9E
+       wkAMrA=;
+Received: from [127.0.0.1] (helo=xxx)
+       by testhost.test.ex with esmtp (Exim x.yz)
+       (envelope-from <CALLER@bloggs.com>)
+       id 10HmaZ-0005vi-00
+       for z@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Subject: simple test
+X-body-linecount: 0
+X-message-linecount: 15
+X-received-count: 2
+
+Line 1: This is a simple test.
+Line 2: This is a simple test.
+.Line 3 has a leading dot
+last line: 4
+
diff --git a/test/mail/5010.maildirsize b/test/mail/5010.maildirsize
new file mode 100644 (file)
index 0000000..f6a87c4
--- /dev/null
@@ -0,0 +1,2 @@
+30S,1C
+ddd d
diff --git a/test/mail/5010.new/1.myhost.test.ex b/test/mail/5010.new/1.myhost.test.ex
new file mode 100644 (file)
index 0000000..4b89548
--- /dev/null
@@ -0,0 +1,17 @@
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+       (envelope-from <CALLER@test.ex>)
+       id 10HmaX-0005vi-00
+       for userx@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaX-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
diff --git a/test/mail/5011.maildirsize b/test/mail/5011.maildirsize
new file mode 100644 (file)
index 0000000..f6a87c4
--- /dev/null
@@ -0,0 +1,2 @@
+30S,1C
+ddd d
diff --git a/test/mail/5012.maildirsize b/test/mail/5012.maildirsize
new file mode 100644 (file)
index 0000000..69ef867
--- /dev/null
@@ -0,0 +1,3 @@
+30S,1C
+ddd d
+ddd d
diff --git a/test/mail/5012.new/1.myhost.test.ex b/test/mail/5012.new/1.myhost.test.ex
new file mode 100644 (file)
index 0000000..4b89548
--- /dev/null
@@ -0,0 +1,17 @@
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+       (envelope-from <CALLER@test.ex>)
+       id 10HmaX-0005vi-00
+       for userx@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaX-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
diff --git a/test/mail/5012.new/2.myhost.test.ex b/test/mail/5012.new/2.myhost.test.ex
new file mode 100644 (file)
index 0000000..ffc6a3b
--- /dev/null
@@ -0,0 +1,28 @@
+Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+       (envelope-from <CALLER@test.ex>)
+       id 10HmaY-0005vi-00
+       for userx@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Message-Id: <E10HmaY-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
index dae415203d3ea35e0b1dae5228f667dddb18448a..d6e91d34677cadf60bd89d1cc1bd12c7b419d4cd 100644 (file)
@@ -1,6 +1,6 @@
-1999-03-02 09:44:33 rcpt accepted
-1999-03-02 09:44:33 rcpt accepted
+1999-03-02 09:44:33 rcpt accepted C=MAIL,MAIL,RCPT
+1999-03-02 09:44:33 rcpt accepted C=MAIL,MAIL,RCPT,RCPT
 1999-03-02 09:44:33 ACL "warn" with "message" setting found in a non-message (EHLO or HELO) ACL: cannot specify header lines here: message ignored
-1999-03-02 09:44:33 rcpt accepted
+1999-03-02 09:44:33 rcpt accepted C=MAIL,RCPT
 1999-03-02 09:44:33 ACL "warn" with "message" setting found in a non-message (EHLO or HELO) ACL: cannot specify header lines here: message ignored
-1999-03-02 09:44:33 rcpt accepted
+1999-03-02 09:44:33 rcpt accepted C=EHLO,MAIL,RCPT
index 8f5c0ad150463fcae22590f599a8d2e4dd6b7bda..e44ddafbc42e2c4dee9b82b597fe0b5f03c86555 100644 (file)
@@ -30,6 +30,9 @@ F From: abcd@x.y.z
 1999-03-02 09:44:33 H=[V4NET.0.0.5] U=root F=<ok@localhost1> rejected RCPT <z@remote.domain>: relay not permitted
 1999-03-02 09:44:33 H=[V4NET.0.0.5] U=root sender verify fail for <ok@localhost1>: 127.0.0.1 [127.0.0.1] : SMTP error from remote mail server after RCPT TO:<postmaster@localhost1>: 550 Don't like postmaster
 1999-03-02 09:44:33 H=[V4NET.0.0.5] U=root F=<ok@localhost1> rejected RCPT <z@remote.domain>: Sender verify failed
+1999-03-02 09:44:33 H=(me) [V4NET.0.0.3] U=root F=<ok@localhost1> rejected RCPT <z@remote.domain>: relay not permitted
+1999-03-02 09:44:33 H=(me) [V4NET.0.0.3] U=root F=<ok@localhost1> rejected RCPT <z@remote.domain>: relay not permitted
+1999-03-02 09:44:33 H=(me) [V4NET.0.0.7] U=root F=<ok@localhost1> rejected RCPT <z@remote.domain>: relay not permitted
 1999-03-02 09:44:33 H=[V4NET.0.0.3] U=root F=<uncheckable@localhost1> rejected RCPT <z@remote.lmtp>: 127.0.0.1 [127.0.0.1] : SMTP error from remote mail server after RCPT TO:<z@remote.lmtp>: 550 Recipient not liked
 1999-03-02 09:44:33 H=[V4NET.0.0.1] U=root sender verify defer for <bad@localhost1>: Could not complete sender verify callout: 127.0.0.1 [127.0.0.1] : Remote host closed connection in response to initial connection
 1999-03-02 09:44:33 H=[V4NET.0.0.1] U=root F=<bad@localhost1> temporarily rejected RCPT <z@test.ex>: Could not complete sender verify callout
index 47ad1638da3b244f92c1fccdd51f64be236f5b5a..1702cec04a441fef86ff620183b18ca83b9e6a20 100644 (file)
@@ -12,9 +12,5 @@
 1999-03-02 09:44:33 H=[V4NET.0.0.2] U=root F=<ok@otherhost> rejected RCPT <z@test.ex>: Sender verify failed
 1999-03-02 09:44:33 H=[V4NET.0.0.2] U=root sender verify fail for <ok@otherhost>
 1999-03-02 09:44:33 H=[V4NET.0.0.2] U=root F=<ok@otherhost> rejected RCPT <z@test.ex>: Sender verify failed
-1999-03-02 09:44:33 H=[V4NET.0.0.3] U=root sender verify defer for <ok@otherhost3>: Could not complete sender verify callout: 127.0.0.1 [127.0.0.1] : response to "RCPT TO:<myhost.test.ex-dddddddd-testing@otherhost3>" was: 250 OK
-1999-03-02 09:44:33 H=[V4NET.0.0.3] U=root F=<ok@otherhost3> temporarily rejected RCPT <z@test.ex>: Could not complete sender verify callout
-1999-03-02 09:44:33 H=[V4NET.0.0.4] U=root sender verify defer for <ok@otherhost4>: Could not complete sender verify callout: 127.0.0.1 [127.0.0.1] : response to "RCPT TO:<myhost.test.ex-dddddddd-testing@otherhost4>" was: 250 OK
-1999-03-02 09:44:33 H=[V4NET.0.0.4] U=root F=<ok@otherhost4> temporarily rejected RCPT <z@test.ex>: Could not complete sender verify callout
 1999-03-02 09:44:33 H=[V4NET.0.0.5] U=root sender verify defer for <okok@otherhost51>: Could not complete sender verify callout: 127.0.0.1 [127.0.0.1] : SMTP timeout after RCPT TO:<myhost.test.ex-dddddddd-testing@otherhost51>
 1999-03-02 09:44:33 H=[V4NET.0.0.5] U=root F=<okok@otherhost51> temporarily rejected RCPT <z@test.ex>: Could not complete sender verify callout
index db94a4d6ee2236f26f7f44e678fc48406f36a526..bf20a240dd5ae9e8e66c8189b455fc4e0d793d3b 100644 (file)
@@ -12,9 +12,5 @@
 1999-03-02 09:44:33 H=[V4NET.0.0.2] U=root F=<ok@otherhost> rejected RCPT <z@test.ex>: Sender verify failed
 1999-03-02 09:44:33 H=[V4NET.0.0.2] U=root sender verify fail for <ok@otherhost>
 1999-03-02 09:44:33 H=[V4NET.0.0.2] U=root F=<ok@otherhost> rejected RCPT <z@test.ex>: Sender verify failed
-1999-03-02 09:44:33 H=[V4NET.0.0.3] U=root sender verify defer for <ok@otherhost3>: Could not complete sender verify callout: 127.0.0.1 [127.0.0.1] : response to "RCPT TO:<myhost.test.ex-dddddddd-testing@otherhost3>" was: 250 OK accepting that random recipient
-1999-03-02 09:44:33 H=[V4NET.0.0.3] U=root F=<ok@otherhost3> temporarily rejected RCPT <z@test.ex>: Could not complete sender verify callout
-1999-03-02 09:44:33 H=[V4NET.0.0.4] U=root sender verify defer for <ok@otherhost4>: Could not complete sender verify callout: 127.0.0.1 [127.0.0.1] : response to "RCPT TO:<myhost.test.ex-dddddddd-testing@otherhost4>" was: 250 OK
-1999-03-02 09:44:33 H=[V4NET.0.0.4] U=root F=<ok@otherhost4> temporarily rejected RCPT <z@test.ex>: Could not complete sender verify callout
 1999-03-02 09:44:33 H=[V4NET.0.0.5] U=root sender verify defer for <okok@otherhost51>: Could not complete sender verify callout: 127.0.0.1 [127.0.0.1] : SMTP timeout after RCPT TO:<myhost.test.ex-dddddddd-testing@otherhost51>
 1999-03-02 09:44:33 H=[V4NET.0.0.5] U=root F=<okok@otherhost51> temporarily rejected RCPT <z@test.ex>: Could not complete sender verify callout
diff --git a/test/rejectlog/0582 b/test/rejectlog/0582
new file mode 100644 (file)
index 0000000..614c294
--- /dev/null
@@ -0,0 +1 @@
+1999-03-02 09:44:33 U=CALLER F=<userg@ok.example> temporarily rejected RCPT <userg@test.ex>: Could not complete recipient verify callout: 127.0.0.1 [127.0.0.1] : SMTP error from remote mail server after RCPT TO:<userg@test.ex>: 451 not right now
index a7f8f069230bc08e791765d1fd9c408da37baa75..f75d9d27040fe1806372e9dfe4e08f646a02ce41 100644 (file)
@@ -1,6 +1,6 @@
 
 ******** SERVER ********
-1999-03-02 09:44:33 SMTP protocol synchronization error (next input sent too soon: pipelining was not advertised): rejected "bdat 1" H=(tester) [127.0.0.1] next input="bdat 87 last\r\n"
+1999-03-02 09:44:33 SMTP protocol synchronization error (next input sent too soon: pipelining was not advertised): rejected "BDAT 1" H=(tester) [127.0.0.1] next input="BDAT 87 last\r\n"
 Envelope-from: <someone9@some.domain>
 Envelope-to: <CALLER@test.ex>
 1999-03-02 09:44:33 SMTP call from (tester) [127.0.0.1] dropped: too many syntax or protocol errors (last command was "From: Sam@random.com")
diff --git a/test/rejectlog/2037 b/test/rejectlog/2037
new file mode 100644 (file)
index 0000000..2106413
--- /dev/null
@@ -0,0 +1,20 @@
+1999-03-02 09:44:33 U=CALLER F=<> temporarily rejected RCPT <rcpt_defer@test.ex>: Could not complete recipient verify callout: 127.0.0.1 [127.0.0.1] : SMTP error from remote mail server after RCPT TO:<rcpt_defer@test.ex>: 451 Temporary local problem - please try later
+
+******** SERVER ********
+1999-03-02 09:44:33 H=localhost (myhost.test.ex) [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no F=<> temporarily rejected RCPT <rcpt_defer@test.ex>
+1999-03-02 09:44:33 10HmaX-0005vi-00 H=localhost (myhost.test.ex) [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no F=<> temporarily rejected after DATA
+Envelope-from: <>
+Envelope-to: <data_defer@test.ex>
+P Received: from localhost ([127.0.0.1] helo=myhost.test.ex)
+       by myhost.test.ex with esmtps (TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256)
+       (Exim x.yz)
+       id 10HmaX-0005vi-00
+       for data_defer@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+P Received: from CALLER by myhost.test.ex with local-smtp (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmaY-0005vi-00
+       for data_defer@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+  Subject: test
+I Message-Id: <E10HmaY-0005vi-00@myhost.test.ex>
+F From: CALLER_NAME <CALLER@myhost.test.ex>
+  Date: Tue, 2 Mar 1999 09:44:33 +0000
diff --git a/test/rejectlog/2137 b/test/rejectlog/2137
new file mode 100644 (file)
index 0000000..6ec7345
--- /dev/null
@@ -0,0 +1,20 @@
+1999-03-02 09:44:33 U=CALLER F=<> temporarily rejected RCPT <rcpt_defer@test.ex>: Could not complete recipient verify callout: 127.0.0.1 [127.0.0.1] : SMTP error from remote mail server after RCPT TO:<rcpt_defer@test.ex>: 451 Temporary local problem - please try later
+
+******** SERVER ********
+1999-03-02 09:44:33 H=localhost (myhost.test.ex) [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no F=<> temporarily rejected RCPT <rcpt_defer@test.ex>
+1999-03-02 09:44:33 10HmaX-0005vi-00 H=localhost (myhost.test.ex) [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no F=<> temporarily rejected after DATA
+Envelope-from: <>
+Envelope-to: <data_defer@test.ex>
+P Received: from localhost ([127.0.0.1] helo=myhost.test.ex)
+       by myhost.test.ex with esmtps (TLSv1:AES256-SHA:256)
+       (Exim x.yz)
+       id 10HmaX-0005vi-00
+       for data_defer@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+P Received: from CALLER by myhost.test.ex with local-smtp (Exim x.yz)
+       (envelope-from <CALLER@myhost.test.ex>)
+       id 10HmaY-0005vi-00
+       for data_defer@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+  Subject: test
+I Message-Id: <E10HmaY-0005vi-00@myhost.test.ex>
+F From: CALLER_NAME <CALLER@myhost.test.ex>
+  Date: Tue, 2 Mar 1999 09:44:33 +0000
index ec385f2940bdcd2eece9324e6f48c0fe3ddf89d5..3bd6c77bdfd254f86c826a61c5946406e40acb23 100755 (executable)
@@ -487,9 +487,13 @@ RESET_AFTER_EXTRA_LINE_READ:
     /Tue, 2 Mar 1999 09:44:33 +0000/gx;
 
   # Date/time in logs and in one instance of a filter test
-  s/^\d{4}-\d\d-\d\d\s\d\d:\d\d:\d\d(\s[+-]\d\d\d\d)?/1999-03-02 09:44:33/gx;
+  s/^\d{4}-\d\d-\d\d\s\d\d:\d\d:\d\d(\s[+-]\d\d\d\d)?\s/1999-03-02 09:44:33 /gx;
+  s/^\d{4}-\d\d-\d\d\s\d\d:\d\d:\d\d\.\d{3}(\s[+-]\d\d\d\d)?\s/2017-07-30 18:51:05.712 /gx;
   s/^Logwrite\s"\d{4}-\d\d-\d\d\s\d\d:\d\d:\d\d/Logwrite "1999-03-02 09:44:33/gx;
 
+  s/((D|[QD]T)=)\d+s/$1qqs/g;
+  s/((D|[QD]T)=)\d\.\d{3}s/$1q.qqqs/g;
+
   # Date/time in message separators
   s/(?:[A-Z][a-z]{2}\s){2}\d\d\s\d\d:\d\d:\d\d\s\d\d\d\d
     /Tue Mar 02 09:44:33 1999/gx;
@@ -517,9 +521,6 @@ RESET_AFTER_EXTRA_LINE_READ:
   # Date/time in exim -bV output
   s/\d\d-[A-Z][a-z]{2}-\d{4}\s\d\d:\d\d:\d\d/07-Mar-2000 12:21:52/g;
 
-  # Time on queue tolerance
-  s/(QT|D)=1s/$1=0s/;
-
   # Eximstats heading
   s/Exim\sstatistics\sfrom\s\d{4}-\d\d-\d\d\s\d\d:\d\d:\d\d\sto\s
     \d{4}-\d\d-\d\d\s\d\d:\d\d:\d\d/Exim statistics from <time> to <time>/x;
@@ -910,6 +911,9 @@ RESET_AFTER_EXTRA_LINE_READ:
     # optional IDN2 variant conversions.  Accept either IDN1 or IDN2
     s/conversion  strasse.de/conversion  xn--strae-oqa.de/;
     s/conversion: german.xn--strae-oqa.de/conversion: german.straße.de/;
+
+    # subsecond timstamp info in reported header-files
+    s/^(-received_time_usec \.)\d{6}$/$1uuuuuu/;
     }
 
   # ======== stderr ========
@@ -1088,6 +1092,9 @@ RESET_AFTER_EXTRA_LINE_READ:
     # Not all platforms build with DKIM enabled
     next if /^PDKIM >> Body data for hash, canonicalized/;
 
+    # Not all platforms have sendfile support
+    next if /^cannot use sendfile for body: no support$/;
+
     #  Parts of DKIM-specific debug output depend on the time/date
     next if /^date:\w+,\{SP\}/;
     next if /^PDKIM \[[^[]+\] (Header hash|b) computed:/;
@@ -1103,6 +1110,10 @@ RESET_AFTER_EXTRA_LINE_READ:
 
     next if /^(ppppp )?setsockopt FASTOPEN: Protocol not available$/;
 
+    # Specific pointer values reported for DB operations change from run to run
+    s/^(returned from EXIM_DBOPEN: 0x)[0-9a-f]+/$1AAAAAAAA/;
+    s/^(EXIM_DBCLOSE.0x)[0-9a-f]+/$1AAAAAAAA/;
+
     # When Exim is checking the size of directories for maildir, it uses
     # the check_dir_size() function to scan directories. Of course, the order
     # of the files that are obtained using readdir() varies from system to
@@ -1154,6 +1165,9 @@ RESET_AFTER_EXTRA_LINE_READ:
     {
     # Berkeley DB version differences
     next if / Berkeley DB error: /;
+
+    # CHUNKING: exact sizes depend on hostnames in headers
+    s/(=>.* K C="250- \d)\d+ (byte chunk, total \d)\d+/$1nn $2nn/;
     }
 
   # ======== All files other than stderr ========
@@ -1513,7 +1527,7 @@ $munges =
 
     'optional_config' =>
     { 'stdout' => '/^(
-                  dkim_(canon|domain|private_key|selector|sign_headers|strict)
+                  dkim_(canon|domain|private_key|selector|sign_headers|strict|hash|identity)
                   |gnutls_require_(kx|mac|protocols)
                   |hosts_(requ(est|ire)|try)_(dane|ocsp)
                   |hosts_(avoid|nopass|require|verify_avoid)_tls
@@ -2531,7 +2545,7 @@ GetOptions(
     'keep'     => \$save_output,
     'slow'     => \$slow,
     'valgrind' => \$valgrind,
-    'range=i{2}'       => \my @range_wanted,
+    'range=s{2}'       => \my @range_wanted,
     'test=i@'          => \my @tests_wanted,
     'flavor|flavour=s' => $flavour,
     'help'             => sub { pod2usage(-exit => 0) },
@@ -2711,7 +2725,7 @@ if (defined $parm_trusted_config_list)
   open(TCL, $parm_trusted_config_list) or die "Can't open $parm_trusted_config_list: $!\n";
   my $test_config = getcwd() . '/test-config';
   die "Can't find '$test_config' in TRUSTED_CONFIG_LIST $parm_trusted_config_list."
-  if not grep { /^$test_config$/ } <TCL>;
+  if not grep { /^\Q$test_config\E$/ } <TCL>;
   }
 else
   {
@@ -4067,7 +4081,8 @@ Keep the various output files produced during a test run. (default: don't keep)
 
 =item B<--range> I<n0> I<n1>
 
-Run tests between (including) I<n0> and I<n1>.
+Run tests between (including) I<n0> and I<n1>. A "+" may be used to specify the "last
+test available".
 
 =item B<--slow>
 
index cf8dc36e04a374ce0d58dde3422299238c923d44..cb0bb188fadc388e81d20d8b236dc3dd79f69d54 100644 (file)
@@ -417,6 +417,8 @@ gei:    ${if gei{ABC}{abc}{y}{n}}
 isip:   ${if isip {1.2.3.4}{y}{n}}  1.2.3.4
 isip4:  ${if isip4{1.2.3.4}{y}{n}}  1.2.3.4
 isip6:  ${if isip6{1.2.3.4}{y}{n}}  1.2.3.4
+isip:   ${if isip {::1.2.3.256}{y}{n}}  ::1.2.3.256
+isip4:  ${if isip4{1.2.3.256}{y}{n}}  1.2.3.256
 isip:   ${if isip {1:2:3:4}{y}{n}}  1:2:3:4
 isip4:  ${if isip4{1:2:3:4}{y}{n}}  1:2:3:4
 isip6:  ${if isip6{1:2:3:4}{y}{n}}  1:2:3:4
@@ -426,6 +428,7 @@ isip6:  ${if isip6{::1}{y}{n}}      ::1
 isip:   ${if isip {fe80::a00:20ff:fe86:a061}{y}{n}}  fe80::a00:20ff:fe86:a061
 isip4:  ${if isip4{fe80::a00:20ff:fe86:a061}{y}{n}}  fe80::a00:20ff:fe86:a061
 isip6:  ${if isip6{fe80::a00:20ff:fe86:a061}{y}{n}}  fe80::a00:20ff:fe86:a061
+isip:   ${if isip {fe80::1.2.3.4}{y}{n}}  fe80::1.2.3.4
 isip:   ${if isip {rhubarb}{y}{n}}  rhubarb
 isip4:  ${if isip4{rhubarb}{y}{n}}  rhubarb
 isip6:  ${if isip6{rhubarb}{y}{n}}  rhubarb
index 655b4dd96f077a882da1e43b319ca3d39337b7b7..c27a7ebf3554342ce0c9ae19c362d95e5c6ddb66 100644 (file)
@@ -13,6 +13,7 @@ exim -odi userx@domain1
 Test message 1
 ****
 #
+sudo rm DIR/spool/db/*
 exim -z "Test: temp-rej helo"
 ****
 server PORT_S
@@ -27,6 +28,7 @@ QUIT
 exim -qf
 ****
 #
+sudo rm DIR/spool/db/*
 exim -z "Test: drop conn after banner"
 ****
 server PORT_S
@@ -35,6 +37,7 @@ server PORT_S
 exim -qf
 ****
 #
+sudo rm DIR/spool/db/*
 exim -z "Test: reject connect"
 ****
 server PORT_S
@@ -45,6 +48,7 @@ QUIT
 exim -qf
 ****
 #
+sudo rm DIR/spool/db/*
 exim -z "Test: reject helo"
 ****
 server PORT_S
@@ -74,4 +78,19 @@ Test message 4
 ****
 #
 #
+#
+sudo rm DIR/spool/db/*
+exim -z "Test: smtp-reject conn on 1MX, timeout TCP conn on 2MX"
+****
+server PORT_S 2
+554 no smtp service here
+QUIT
+220 bye
+*eof
+*sleep 2
+****
+exim -DLIST -qf
+****
+#
+#
 no_msglog_check
index a67dab2ebd9a1d9e4a3a284c94c3e8a827537f02..e53c1da7ffa94b70ae800f3c3998aebc58df7cc2 100644 (file)
@@ -12,11 +12,13 @@ RCPT TO
 QUIT
 250 OK
 ****
+# sender
 sudo exim -v -bs -oMa V4NET.0.0.1
 MAIL FROM:<ok@localhost>
 RCPT TO:<z@test.ex>
 QUIT
 ****
+# sender, no callout
 sudo exim -v -bs -oMa V4NET.0.0.2
 MAIL FROM:<unchecked@localhost>
 RCPT TO:<z@test.ex>
@@ -33,6 +35,7 @@ RCPT TO
 QUIT
 250 OK
 ****
+# sender, refused
 sudo exim -v -bs -oMa V4NET.0.0.1
 MAIL FROM:<bad@localhost>
 RCPT TO:<z@test.ex>
@@ -49,6 +52,7 @@ RCPT TO
 QUIT
 250 OK
 ****
+# sender, tmperr
 sudo exim -v -bs -oMa V4NET.0.0.1
 MAIL FROM:<uncheckable@localhost1>
 RCPT TO:<z@test.ex>
@@ -63,6 +67,7 @@ MAIL FROM
 QUIT
 250 OK
 ****
+# sender, err on mailfrom
 sudo exim -v -bs -oMa V4NET.0.0.1
 MAIL FROM:<uncheckable2@localhost1>
 RCPT TO:<z@test.ex>
@@ -78,6 +83,7 @@ MAIL FROM
 QUIT
 250 OK
 ****
+# sender, err on mailfrom
 sudo exim -v -bs -oMa V4NET.0.0.1
 MAIL FROM:<uncheckable@localhost1>
 RCPT TO:<z@test.ex>
@@ -94,6 +100,7 @@ RCPT TO
 QUIT
 250 OK
 ****
+# recipient, refused
 sudo exim -v -bs -oMa V4NET.0.0.3
 MAIL FROM:<uncheckable@localhost1>
 RCPT TO:<z@remote.domain>
@@ -111,11 +118,13 @@ RCPT TO
 QUIT
 250 OK
 ****
+# recipient, refused
 sudo exim -v -bs -oMa V4NET.0.0.3
 MAIL FROM:<uncheckable@localhost1>
 RCPT TO:<z@remote.domain>
 QUIT
 ****
+# recipient, no conneect
 sudo exim -v -bs -oMa V4NET.0.0.3
 MAIL FROM:<uncheckable@localhost1>
 RCPT TO:<z@remote.domain>
@@ -207,16 +216,17 @@ QUIT
 server PORT_S
 220 Server ready
 EHLO
-250- wotcher
+250- wotcher sverifier
 250-SIZE
 250 OK
-MAIL FROM
+MAIL FROM:<>
 250 OK
 RCPT TO
 250 OK
 QUIT
 250 OK
 ****
+# sender, size known, tgt supports sixe
 sudo exim -v -bs -oMa V4NET.0.0.6
 EHLO me
 MAIL FROM:<ok@localhost1> SIZE=420000
@@ -226,6 +236,76 @@ QUIT
 #
 server PORT_S
 220 Server ready
+EHLO
+250- wotcher rverifier
+250-SIZE
+250 OK
+MAIL FROM:<> SIZE=
+250 OK
+RCPT TO
+250 OK
+QUIT
+250 OK
+****
+# receipient, size known, tgt supports size
+sudo exim -v -bs -oMa V4NET.0.0.3
+EHLO me
+MAIL FROM:<ok@localhost1> SIZE=420000
+RCPT TO:<z@remote.domain>
+QUIT
+****
+#
+server PORT_S
+220 Server ready
+EHLO
+250- wotcher rverifier
+250-SIZE
+250 OK
+MAIL FROM:<>
+250 OK
+RCPT TO
+250 OK
+QUIT
+250 OK
+****
+# receipient, size unknown, tgt supports size
+sudo exim -v -bs -oMa V4NET.0.0.3
+EHLO me
+MAIL FROM:<ok@localhost1>
+RCPT TO:<z@remote.domain>
+QUIT
+****
+#
+server PORT_S
+220 Server ready
+EHLO
+250- wotcher rverifier
+250-SIZE
+250 OK
+MAIL FROM:<ok@localhost1>
+250 OK
+RCPT TO:<myhost.test.ex-
+550 RANDOM NOT OK
+RSET
+250 OK
+MAIL FROM:<ok@localhost1> SIZE=
+250 OK
+RCPT TO:<z@remote.domain>
+250 OK
+QUIT
+250 OK
+****
+# receipient, size known, tgt supports size, use_sender, w/random
+# stdout should see SIZE on the main but not on the random receipient's MAIL FROM
+sudo exim -v -bs -oMa V4NET.0.0.7
+EHLO me
+MAIL FROM:<ok@localhost1> SIZE=420000
+RCPT TO:<z@remote.domain>
+QUIT
+****
+#
+server PORT_S
+220 Server ready
 LHLO
 250 OK
 MAIL FROM
index 2595eff482c85c01256368f54d18e444dc1aab61..a645802a1a8ac3efb408deee23f93737f3933b40 100644 (file)
@@ -1,11 +1,14 @@
 # log_selector = +smtp_no_mail
 need_ipv4
 #
-exim -DSERVER=server -bd -oX PORT_D
+exim -DSERVER=server -DLOG_SELECTOR=+millisec -bd -oX PORT_D
 ****
 client 127.0.0.1 PORT_D
 ??? 220
 ****
+killdaemon
+exim -DSERVER=server -bd -oX PORT_D
+****
 client 127.0.0.1 PORT_D
 ??? 220
 quit
index d11064c0020016d1cebeb13551207c6da2f7f24b..1565275eacc4ede9408e16c01e36999d52d53464 100644 (file)
@@ -1,14 +1,15 @@
-# log_selector = +pid
+# log_selector = +pid , +millisec
 #
 exim -odi userx@test.ex usery@test.ex
 Message 1
 ****
-exim -odi userx@test.ex userz@test.ex
+exim -DLOG_SELECTOR=+pid+queue_time -odi userx@test.ex userz@test.ex
 Message 2
 ****
-exim -DLOG_SELECTOR= -odi userx@test.ex
+exim -d+all -DLOG_SELECTOR=+queue_time+queue_time_overall+deliver_time+millisec -odi userx@test.ex
 Message 3
 ****
 exigrep userx
 eximstats -ne -nr -nt -tnl -q0 -h0 -t0
 no_msglog_check
+no_stderr_check
diff --git a/test/scripts/0000-Basic/0580 b/test/scripts/0000-Basic/0580
new file mode 100644 (file)
index 0000000..8d8a117
--- /dev/null
@@ -0,0 +1,156 @@
+# callout lazy-close, -bs send
+need_ipv4
+#
+# a recipient verify and continued-delivery
+# cmdline -bs send
+server PORT_S
+220 Welcome
+EHLO
+250 Hi
+MAIL FROM
+250 OK
+RCPT TO
+250 OK
+DATA
+354 hit me
+.
+250 yeah got that message
+QUIT
+221 Bye
+****
+#
+exim -bs
+mail from:<userx@ok.example>
+rcpt to:<usery@test.ex>
+data
+Subject: test
+
+body
+.
+quit
+****
+sleep 1
+#
+#
+# multiple recipients
+# 1st callout result is cached (above); should not activate LCC
+server PORT_S 2
+220 Welcome
+EHLO
+250 Hi
+MAIL FROM
+250 OK
+RCPT TO
+250 OK
+QUIT
+221 Bye
+*eof
+220 Welcome
+EHLO
+250 Hi
+MAIL FROM
+250 OK
+RCPT TO
+250 OK
+RCPT TO
+250 OK
+DATA
+354 hit me
+.
+250 yeah got that message
+QUIT
+221 Bye
+****
+#
+exim -bs
+mail from:<userx@ok.example>
+rcpt to:<usery@test.ex>
+rcpt to:<usery2@test.ex>
+data
+Subject: test
+
+body
+.
+quit
+****
+sleep 1
+#
+#
+# 2nd callout result is cached (above); should not activate LCC
+server PORT_S 2
+220 Welcome
+EHLO
+250 Hi
+MAIL FROM
+250 OK
+RCPT TO
+250 OK
+QUIT
+221 Bye
+*eof
+220 Welcome
+EHLO
+250 Hi
+MAIL FROM
+250 OK
+RCPT TO
+250 OK
+RCPT TO
+250 OK
+DATA
+354 hit me
+.
+250 yeah got that message
+QUIT
+221 Bye
+****
+#
+exim -bs
+mail from:<userx@ok.example>
+rcpt to:<usery3@test.ex>
+rcpt to:<usery@test.ex>
+data
+Subject: test
+
+body
+.
+quit
+****
+sleep 1
+#
+#
+# no cache hits; should do LCC
+server PORT_S
+220 Welcome
+EHLO
+250 Hi
+MAIL FROM
+250 OK
+RCPT TO
+250 OK
+RCPT TO
+250 OK
+DATA
+354 hit me
+.
+250 yeah got that message
+QUIT
+221 Bye
+****
+#
+exim -bs
+mail from:<userx@ok.example>
+rcpt to:<usery4@test.ex>
+rcpt to:<usery5@test.ex>
+data
+Subject: test
+
+body
+.
+quit
+****
+sleep 1
+#
+#
+no_stdout_check
+no_msglog_check
diff --git a/test/scripts/0000-Basic/0581 b/test/scripts/0000-Basic/0581
new file mode 100644 (file)
index 0000000..f0ce3bc
--- /dev/null
@@ -0,0 +1,264 @@
+# callout lazy-close, smtp send
+need_ipv4
+#
+# a recipient verify and continued-delivery
+# smtp send
+server PORT_S
+220 Welcome
+EHLO
+250 Hi
+MAIL FROM
+250 OK
+RCPT TO
+250 OK
+DATA
+354 hit me
+.
+250 yeah got that message
+QUIT
+221 Bye
+****
+#
+exim -DSERVER=server -bd -oX PORT_D
+****
+#
+client 127.0.0.1 PORT_D
+??? 220
+EHLO test.ex
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250 
+MAIL FROM:<userc@ok.example>
+??? 250
+RCPT TO:<userd@test.ex>
+??? 250
+DATA
+??? 354
+Subject: test
+
+body
+.
+??? 250
+QUIT
+??? 221
+****
+sleep 1
+killdaemon
+#
+#
+# smtp send, deliver_drop_priv
+server PORT_S
+220 Welcome
+EHLO
+250 Hi
+MAIL FROM
+250 OK
+RCPT TO
+250 OK
+DATA
+354 hit me
+.
+250 yeah got that message
+QUIT
+221 Bye
+****
+#
+exim -DSERVER=server -DOPT=deliver_drop_privilege -bd -oX PORT_D
+****
+#
+client 127.0.0.1 PORT_D
+??? 220
+EHLO test.ex
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250 
+MAIL FROM:<usere@ok.example>
+??? 250
+RCPT TO:<userf@test.ex>
+??? 250
+DATA
+??? 354
+Subject: test
+
+body
+.
+??? 250
+QUIT
+??? 221
+****
+sleep 1
+killdaemon
+#
+#
+# multiple recipients
+# 1st callout result is cached (above); should not activate LCC
+# smtp send
+server PORT_S 2
+220 Welcome
+EHLO
+250 Hi
+MAIL FROM
+250 OK
+RCPT TO:<userd2@test.ex>
+250 OK
+QUIT
+221 Bye
+*eof
+220 Welcome
+EHLO
+250 Hi
+MAIL FROM
+250 OK
+RCPT TO:<userd@test.ex>
+250 OK
+RCPT TO:<userd2@test.ex>
+250 OK
+DATA
+354 hit me
+.
+250 yeah got that message
+QUIT
+221 Bye
+****
+#
+exim -DSERVER=server -bd -oX PORT_D
+****
+#
+client 127.0.0.1 PORT_D
+??? 220
+EHLO test.ex
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250 
+MAIL FROM:<userc@ok.example>
+??? 250
+RCPT TO:<userd@test.ex>
+??? 250
+RCPT TO:<userd2@test.ex>
+??? 250
+DATA
+??? 354
+Subject: test
+
+body
+.
+??? 250
+QUIT
+??? 221
+****
+sleep 1
+#
+#
+# 2nd callout result is cached (above); should not activate LCC
+# smtp send
+server PORT_S 2
+220 Welcome
+EHLO
+250 Hi
+MAIL FROM
+250 OK
+RCPT TO:<userd3@test.ex>
+250 OK
+QUIT
+221 Bye
+*eof
+220 Welcome
+EHLO
+250 Hi
+MAIL FROM
+250 OK
+RCPT TO:<userd3@test.ex>
+250 OK
+RCPT TO:<userd2@test.ex>
+250 OK
+DATA
+354 hit me
+.
+250 yeah got that message
+QUIT
+221 Bye
+****
+#
+client 127.0.0.1 PORT_D
+??? 220
+EHLO test.ex
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250 
+MAIL FROM:<userc@ok.example>
+??? 250
+RCPT TO:<userd3@test.ex>
+??? 250
+RCPT TO:<userd2@test.ex>
+??? 250
+DATA
+??? 354
+Subject: test
+
+body
+.
+??? 250
+QUIT
+??? 221
+****
+sleep 1
+#
+#
+# no cache hits; should do LCC
+# smtp send
+server PORT_S 2
+220 Welcome
+EHLO
+250 Hi
+MAIL FROM
+250 OK
+RCPT TO:<userd4@test.ex>
+250 OK
+RCPT TO:<userd5@test.ex>
+250 OK
+DATA
+354 hit me
+.
+250 yeah got that message
+QUIT
+221 Bye
+****
+#
+client 127.0.0.1 PORT_D
+??? 220
+EHLO test.ex
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250 
+MAIL FROM:<userc@ok.example>
+??? 250
+RCPT TO:<userd4@test.ex>
+??? 250
+RCPT TO:<userd5@test.ex>
+??? 250
+DATA
+??? 354
+Subject: test
+
+body
+.
+??? 250
+QUIT
+??? 221
+****
+sleep 1
+killdaemon
+#
+#
+no_stdout_check
+no_msglog_check
diff --git a/test/scripts/0000-Basic/0582 b/test/scripts/0000-Basic/0582
new file mode 100644 (file)
index 0000000..3eefcc9
--- /dev/null
@@ -0,0 +1,56 @@
+# callout lazy-close, defers
+need_ipv4
+#
+# a recipient verify and continued-delivery
+# cmdline -bs send, rcpt-time defer
+server PORT_S
+220 Welcome
+EHLO
+250 Hi
+MAIL FROM
+250 OK
+RCPT TO
+451 not right now
+QUIT
+221 Bye
+****
+#
+exim -bs
+mail from:<userg@ok.example>
+rcpt to:<userg@test.ex>
+quit
+****
+sleep 1
+#
+# cmdline -bs send, data-time defer
+server PORT_S
+220 Welcome
+EHLO
+250 Hi
+MAIL FROM
+250 OK
+RCPT TO
+250 OK
+DATA
+354 hit me
+.
+451 not right now
+QUIT
+221 Bye
+****
+#
+exim -bs
+mail from:<userh@ok.example>
+rcpt to:<userh@test.ex>
+data
+Subject: test
+
+body
+.
+quit
+****
+sleep 1
+#
+#
+no_stdout_check
+no_msglog_check
index 9908d5ecde9f17440602a14be4906500170d0966..5e88c5ae99856aa228b7110d5caa61503bfafb8b 100644 (file)
@@ -243,12 +243,12 @@ ehlo tester
 ??? 250-8BITMIME
 ??? 250-CHUNKING
 ??? 250 HELP
-mail from:someone9@some.domain
+MAIL FROM:someone9@some.domain
 ??? 250
-rcpt to:CALLER@test.ex
+RCPT TO:CALLER@test.ex
 ??? 250
-bdat 1\r\nTbdat 87 last
-To: Susan@random.com
+BDAT 1\r\nTBDAT 87 last
+o: Susan@random.com
 From: Sam@random.com
 Subject: This is a bodyless test message
 
diff --git a/test/scripts/0000-Basic/0906 b/test/scripts/0000-Basic/0906
new file mode 100644 (file)
index 0000000..18ab5bb
--- /dev/null
@@ -0,0 +1,124 @@
+# CHUNKING, spool_wireformat
+#
+exim -bd -DSERVER=server -oX PORT_D:PORT_S
+****
+#
+# Basic long message
+client 127.0.0.1 PORT_S
+??? 220
+EHLO test.com
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250
+MAIL FROM:<sender@dom>
+??? 250
+RCPT TO:<a@test.ex>
+??? 250
+BDAT 8408 LAST
+Subject: foo
+
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+.dot
+tail
+??? 250-
+??? 250
+QUIT
+****
+#
+sleep 1
+killdaemon
+exim -q
+****
+no_msglog_check
diff --git a/test/scripts/0000-Basic/0907 b/test/scripts/0000-Basic/0907
new file mode 100644 (file)
index 0000000..341a63f
--- /dev/null
@@ -0,0 +1,4 @@
+# check for BOM in an included config file (0908)
+#
+1
+exim -bP config
diff --git a/test/scripts/0000-Basic/0908 b/test/scripts/0000-Basic/0908
new file mode 120000 (symlink)
index 0000000..8cc1a8c
--- /dev/null
@@ -0,0 +1 @@
+0907
\ No newline at end of file
diff --git a/test/scripts/1990-TCP-Fast-Open/1990 b/test/scripts/1990-TCP-Fast-Open/1990
new file mode 100644 (file)
index 0000000..cbedd36
--- /dev/null
@@ -0,0 +1,45 @@
+# TCP Fast Open
+#
+# Linux:
+# Both server and client-side TFO support must be enabled in the
+# kernel, 'sudo sh -c "echo 3 > /proc/sys/net/ipv4/tcp_fastopen"'.
+#
+# A packet capture on the loopback interface will show the TFO
+# option on the SYN, but the fast-output SMTP banner will not
+# be seen unless you also deliberately emulate a long path:
+# 'sudo tc qdisc add dev lo root netem delay 100ms'
+#
+# First time runs will see a TFO request option only; subsequent
+# ones should see the TFO cookie and fast-output SMTP banner
+# (currently on a separate packet after the server SYN,ACK but before
+# the client ACK).
+#
+# The client log => lint.ex  should have a "TFO" element.
+# Assuming this is the first run since boot, the a@test recipient will not.
+#
+# The server log <= line for b@test.ex  should have a "TFO" element, but
+# this will only be obtained when the above delay is inserted into the
+# loopback net path.
+#
+#
+#
+# FreeBSD: it looks like you have to compile a custom kernel, with
+# 'options TCP_RFC7413' in the config.  Also set
+# 'net.inet.tcp.fastopen.enabled=1' in /etc/sysctl.conf
+# Untested.
+#
+exim -DSERVER=server -bd -oX PORT_D
+****
+#
+exim a@test.ex
+Testing
+****
+sleep 3
+#
+exim b@test.ex
+Testing
+****
+sleep 3
+#
+killdaemon
+no_msglog_check
diff --git a/test/scripts/1990-TCP-Fast-Open/REQUIRES b/test/scripts/1990-TCP-Fast-Open/REQUIRES
new file mode 100644 (file)
index 0000000..48cd58b
--- /dev/null
@@ -0,0 +1 @@
+support TCP_Fast_Open
index 0c2ccba359171cef07893e0aad2962675407921c..cf29efecd4b2ad83e1574db51e01b5c49898659b 100644 (file)
@@ -11,7 +11,24 @@ Test message 2
 exim userz@test.ex
 Test message 3
 ****
-exim -qqf -d-all+acl
+exim -d-all+acl -qqf
+****
+killdaemon
+exim -DSERVER=server -DNOTDAEMON -qf
+****
+#
+exim -DSERVER=server -bd -oX PORT_D
+****
+exim usera@test.ex
+Test message 1
+****
+exim userb@test.ex
+Test message 2
+****
+exim userc@test.ex
+Test message 3
+****
+exim -DEQUIRE -d-all+acl -qqf
 ****
 killdaemon
 exim -DSERVER=server -DNOTDAEMON -qf
index 65b5290935fba234e6730dfbe6f6bd923fde3b0a..76186b5e448716fbf69dc9ca9ed7b4b378f1e871 100644 (file)
@@ -6,14 +6,14 @@ exim -DSERVER=server -bd -oX PORT_D
 exim CALLER@test.ex
 Test message.
 ****
-millisleep 500
+millisleep 700
 #
 #
 # Extended: server uses SNI to choose certificate
 exim abcd@test.ex
 Test message.
 ****
-millisleep 500
+millisleep 700
 #
 #
 killdaemon
diff --git a/test/scripts/2000-GnuTLS/2035 b/test/scripts/2000-GnuTLS/2035
new file mode 100644 (file)
index 0000000..94923aa
--- /dev/null
@@ -0,0 +1,29 @@
+# client: callout lazy-close, -bs send
+gnutls
+need_ipv4
+#
+# a tls-capable target for the verify/delivery connection
+exim -bd -DSERVER=server -oX PORT_D
+****
+#
+# A recipient verify and continued-delivery.  The debug output should show "already connected to",
+# "proxied TLS", and the DATA smtp command only done by the transport process.
+# cmdline -bs send
+exim -d-all+transport -bs
+mail from:<usera@ok.example>
+rcpt to:<userb@test.ex>
+data
+Subject: test
+
+body
+.
+quit
+****
+sleep 1
+killdaemon
+exim -q
+****
+#
+#
+no_stdout_check
+no_msglog_check
diff --git a/test/scripts/2000-GnuTLS/2036 b/test/scripts/2000-GnuTLS/2036
new file mode 100644 (file)
index 0000000..cd6e9a1
--- /dev/null
@@ -0,0 +1,76 @@
+# client: callout lazy-close, smtp send
+gnutls
+need_ipv4
+#
+# a recipient verify and continued-delivery
+# smtp send
+# a tls-capable target for the verify/delivery connection on PORT_D
+# plus a daemon under test on PORT_S
+exim -bd -DSERVER=server -oX PORT_D:PORT_S
+****
+#
+client 127.0.0.1 PORT_S
+??? 220
+EHLO test.ex
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250 
+MAIL FROM:<userc@ok.example>
+??? 250
+RCPT TO:<userd@test.ex>
+??? 250
+DATA
+??? 354
+Subject: test
+
+body
+.
+??? 250
+QUIT
+??? 221
+****
+sleep 3
+killdaemon
+exim -q
+****
+#
+#
+# smtp send, deliver_drop_priv
+exim -bd -DSERVER=server -DOPT=deliver_drop_privilege -oX PORT_D:PORT_S
+****
+#
+client 127.0.0.1 PORT_S
+??? 220
+EHLO test.ex
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250 
+MAIL FROM:<usere@ok.example>
+??? 250
+RCPT TO:<userf@test.ex>
+??? 250
+DATA
+??? 354
+Subject: test
+
+body
+.
+??? 250
+QUIT
+??? 221
+****
+sleep 3
+killdaemon
+exim -q
+****
+#
+#
+#
+no_stdout_check
+no_msglog_check
diff --git a/test/scripts/2000-GnuTLS/2037 b/test/scripts/2000-GnuTLS/2037
new file mode 100644 (file)
index 0000000..ad13a3f
--- /dev/null
@@ -0,0 +1,31 @@
+# client: callout lazy-close, defers
+gnutls
+need_ipv4
+#
+exim -bd -DSERVER=server -oX PORT_D
+****
+# cmdline -bs send, rcpt-time defer
+exim -bs
+mail from:<>
+rcpt to:<rcpt_defer@test.ex>
+quit
+****
+sleep 3
+#
+# cmdline -bs send, data-time defer
+exim -bs
+mail from:<>
+rcpt to:<data_defer@test.ex>
+data
+Subject: test
+
+body
+.
+quit
+****
+sleep 3
+killdaemon
+#
+#
+no_stdout_check
+no_msglog_check
diff --git a/test/scripts/2000-GnuTLS/2038 b/test/scripts/2000-GnuTLS/2038
new file mode 100644 (file)
index 0000000..83259d9
--- /dev/null
@@ -0,0 +1,19 @@
+# TLS client: multiple messages over one connection (continue_more)
+gnutls
+exim -DSERVER=server -bd -oX PORT_D
+****
+exim userx0@test.ex userx1@test.ex
+Test message 1
+****
+exim usery0@test.ex usery1@test.ex
+Test message 2
+****
+exim userz0@test.ex userz1@test.ex
+Test message 3
+****
+exim -qqf
+****
+killdaemon
+exim -DSERVER=server -DNOTDAEMON -qf
+****
+sortlog
diff --git a/test/scripts/2000-GnuTLS/2052 b/test/scripts/2000-GnuTLS/2052
deleted file mode 100644 (file)
index fa76b48..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-# TLS client: TLS setup fails - retry in clear (with fastopen)
-#
-# If all works you'll not see any difference.  To enable in the
-# kernel, 'sudo sh -c "echo 3 > /proc/sys/net/ipv4/tcp_fastopen"'.
-# A packet capture on the loopback interface will show the TFU
-# option on the SYN, but the fast-output SMTP banner will not
-# be seen unless you also deliberately emulate a long path:
-# 'sudo tc qdisc add dev lo root netem delay 100ms'
-#
-# If the client-side is disabled in the kernel, Exim logs
-# will become noisy.
-#
-gnutls
-exim -DSERVER=server -bd -oX PORT_D
-****
-exim CALLER@test.ex
-Testing
-****
-exim -qf
-****
-killdaemon
-no_msglog_check
index 278f0342903d8b2d1f02f4793ae5b941d320cfe4..91227e8caa0a60cf708da40770dbe156cff3d019 100644 (file)
@@ -58,13 +58,7 @@ EHLO rhu.barb
 ??? 250-PIPELINING
 ??? 250-CHUNKING
 ??? 250 HELP
-MAIL FROM:<someone@some.domain>
-RCPT TO:<CALLER@test.ex>
-BDAT 88 LAST
-To: Susan@random.com
-From: Sam@random.com
-Subject: This is a bodyless test message
-
+MAIL FROM:<someone@some.domain>\r\nRCPT TO:<CALLER@test.ex>\r\nBDAT 88 LAST\r\nTo: Susan@random.com\r\nFrom: Sam@random.com\r\nSubject: This is a bodyless test message\r\n
 ??? 250
 ??? 250
 ??? 250-
index e483763a3d59f31426fdc5df0cbeedc62b663f9a..3265b460d8b986e8da4399558b202033c4d9c8c2 100644 (file)
@@ -10,7 +10,24 @@ Test message 2
 exim userz@test.ex
 Test message 3
 ****
-exim -qqf -d-all+acl
+exim -d-all+acl -qqf
+****
+killdaemon
+exim -DSERVER=server -DNOTDAEMON -qf
+****
+#
+exim -DSERVER=server -bd -oX PORT_D
+****
+exim usera@test.ex
+Test message 1
+****
+exim userb@test.ex
+Test message 2
+****
+exim userc@test.ex
+Test message 3
+****
+exim -DEQUIRE -d-all+acl -qqf
 ****
 killdaemon
 exim -DSERVER=server -DNOTDAEMON -qf
diff --git a/test/scripts/2100-OpenSSL/2135 b/test/scripts/2100-OpenSSL/2135
new file mode 100644 (file)
index 0000000..ff460c6
--- /dev/null
@@ -0,0 +1,28 @@
+# client: callout lazy-close, -bs send
+need_ipv4
+#
+# a tls-capable target for the verify/delivery connection
+exim -bd -DSERVER=server -oX PORT_D
+****
+#
+# A recipient verify and continued-delivery.  The debug output should show "already connected to",
+# "proxied TLS", and the DATA smtp command only done by the transport process.
+# cmdline -bs send
+exim -d-all+transport -bs
+mail from:<usera@ok.example>
+rcpt to:<userb@test.ex>
+data
+Subject: test
+
+body
+.
+quit
+****
+sleep 1
+killdaemon
+exim -q
+****
+#
+#
+no_stdout_check
+no_msglog_check
diff --git a/test/scripts/2100-OpenSSL/2136 b/test/scripts/2100-OpenSSL/2136
new file mode 100644 (file)
index 0000000..396075c
--- /dev/null
@@ -0,0 +1,75 @@
+# client: callout lazy-close, smtp send
+need_ipv4
+#
+# a recipient verify and continued-delivery
+# smtp send
+# a tls-capable target for the verify/delivery connection on PORT_D
+# plus a daemon under test on PORT_S
+exim -bd -DSERVER=server -oX PORT_D:PORT_S
+****
+#
+client 127.0.0.1 PORT_S
+??? 220
+EHLO test.ex
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250 
+MAIL FROM:<userc@ok.example>
+??? 250
+RCPT TO:<userd@test.ex>
+??? 250
+DATA
+??? 354
+Subject: test
+
+body
+.
+??? 250
+QUIT
+??? 221
+****
+sleep 3
+killdaemon
+exim -q
+****
+#
+#
+# smtp send, deliver_drop_priv
+exim -bd -DSERVER=server -DOPT=deliver_drop_privilege -oX PORT_D:PORT_S
+****
+#
+client 127.0.0.1 PORT_S
+??? 220
+EHLO test.ex
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250 
+MAIL FROM:<usere@ok.example>
+??? 250
+RCPT TO:<userf@test.ex>
+??? 250
+DATA
+??? 354
+Subject: test
+
+body
+.
+??? 250
+QUIT
+??? 221
+****
+sleep 3
+killdaemon
+exim -q
+****
+#
+#
+#
+no_stdout_check
+no_msglog_check
diff --git a/test/scripts/2100-OpenSSL/2137 b/test/scripts/2100-OpenSSL/2137
new file mode 100644 (file)
index 0000000..36c36fe
--- /dev/null
@@ -0,0 +1,30 @@
+# client: callout lazy-close, defers
+need_ipv4
+#
+exim -bd -DSERVER=server -oX PORT_D
+****
+# cmdline -bs send, rcpt-time defer
+exim -bs
+mail from:<>
+rcpt to:<rcpt_defer@test.ex>
+quit
+****
+sleep 3
+#
+# cmdline -bs send, data-time defer
+exim -bs
+mail from:<>
+rcpt to:<data_defer@test.ex>
+data
+Subject: test
+
+body
+.
+quit
+****
+sleep 3
+killdaemon
+#
+#
+no_stdout_check
+no_msglog_check
diff --git a/test/scripts/2100-OpenSSL/2138 b/test/scripts/2100-OpenSSL/2138
new file mode 100644 (file)
index 0000000..3a94a1f
--- /dev/null
@@ -0,0 +1,18 @@
+# TLS client: multiple messages over one connection (continue_more)
+exim -DSERVER=server -bd -oX PORT_D
+****
+exim userx0@test.ex userx1@test.ex
+Test message 1
+****
+exim usery0@test.ex usery1@test.ex
+Test message 2
+****
+exim userz0@test.ex userz1@test.ex
+Test message 3
+****
+exim -qqf
+****
+killdaemon
+exim -DSERVER=server -DNOTDAEMON -qf
+****
+sortlog
diff --git a/test/scripts/2100-OpenSSL/2152 b/test/scripts/2100-OpenSSL/2152
deleted file mode 100644 (file)
index 12a482a..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-# TLS client: TLS setup fails - retry in clear (with fastopen)
-#
-# If all works you'll not see any difference.  To enable in the
-# kernel, 'sudo sh -c "echo 3 > /proc/sys/net/ipv4/tcp_fastopen"'.
-# A packet capture on the loopback interface will show the TFO
-# option on the SYN, but the fast-output SMTP banner will not
-# be seen unless you also deliberately emulate a long path:
-# 'sudo tc qdisc add dev lo root netem delay 100ms'
-#
-# If the client-side is disabled in the kernel, Exim logs
-# will become noisy.
-#
-exim -DSERVER=server -bd -oX PORT_D
-****
-exim CALLER@test.ex
-Testing
-****
-exim -qf
-****
-killdaemon
-no_msglog_check
index 54095d49a9edbb01bc01885ab278f3921525d371..e004e5e020139f1c72d6d218bebac1c9051bbe40 100644 (file)
@@ -57,13 +57,7 @@ EHLO rhu.barb
 ??? 250-PIPELINING
 ??? 250-CHUNKING
 ??? 250 HELP
-MAIL FROM:<someone@some.domain>
-RCPT TO:<CALLER@test.ex>
-BDAT 88 LAST
-To: Susan@random.com
-From: Sam@random.com
-Subject: This is a bodyless test message
-
+MAIL FROM:<someone@some.domain>\r\nRCPT TO:<CALLER@test.ex>\r\nBDAT 88 LAST\r\nTo: Susan@random.com\r\nFrom: Sam@random.com\r\nSubject: This is a bodyless test message\r\n
 ??? 250
 ??? 250
 ??? 250-
diff --git a/test/scripts/4000-scanning/4012 b/test/scripts/4000-scanning/4012
new file mode 100644 (file)
index 0000000..42d108c
--- /dev/null
@@ -0,0 +1,45 @@
+# content scan interface: sock
+need_ipv4
+munge loopback
+#
+server PORT_S
+/
+>LF>RESULT: OK
+****
+#
+#
+#
+exim -odi -bs -DOPT=
+ehlo test.ex
+mail from:<>
+rcpt to:<userx@test.ex>
+data
+Date: Fri, 17 Dec 2004 14:35:01 +0100
+Subject: message should be accepted
+
+.
+quit
+****
+#
+#
+#
+server PORT_S
+/
+>LF>RESULT: BAD
+>LF>NAME: wibble
+****
+#
+#
+#
+exim -odi -bs -DOPT=
+ehlo test.ex
+mail from:<>
+rcpt to:<userx@test.ex>
+data
+Date: Fri, 17 Dec 2004 14:35:01 +0100
+Subject: message should be rejected
+
+due to the server response (above)
+.
+quit
+****
index 44c885b8d84cf51473666f45b3b6d4256d8c0497..4a0ac0893c4c84a1f58a17a6d169952e80c7fb76 100644 (file)
@@ -81,5 +81,4 @@ quit
 ****
 #
 #
-#
-
+# Ends
diff --git a/test/scripts/4027-TFO-socks/4027 b/test/scripts/4027-TFO-socks/4027
new file mode 100644 (file)
index 0000000..533021c
--- /dev/null
@@ -0,0 +1,83 @@
+# socks5 proxy on smtp transport, TCP Fast Open
+#
+munge loopback
+#
+#
+# TFO client, not server
+server PORT_D
+<<\x05\x01\x00
+>>\x05\x00
+<<\x05\x01\x00\x01\x7f\x00\x00\x01\x04\xc8
+>>\x05\x00\x00\x01\x7f\x00\x00\x01\xbe\xef
+220 Connected OK
+EHLO
+250-server id
+250
+MAIL FROM
+250
+RCPT TO
+250
+DATA
+354 do me
+.
+250 accepted OK
+QUIT
+250 bye
+****
+#
+#
+exim -odi -bs -DOPT=
+ehlo test.ex
+mail from:<>
+rcpt to:<user_tfo@test.ex>
+data
+Date: Fri, 17 Dec 2004 14:35:01 +0100
+Subject: message should be sent
+
+connection trying TFO
+via null-auth proxy
+.
+quit
+****
+#
+#
+#
+# TFO client and server
+server -tfo PORT_D
+<<\x05\x01\x00
+>>\x05\x00
+<<\x05\x01\x00\x01\x7f\x00\x00\x01\x04\xc8
+>>\x05\x00\x00\x01\x7f\x00\x00\x01\xbe\xef
+220 Connected OK
+EHLO
+250-server id
+250
+MAIL FROM
+250
+RCPT TO
+250
+DATA
+354 do me mate
+.
+250 accepted OK
+QUIT
+250 bye
+****
+#
+#
+exim -odi -bs -DOPT=
+ehlo test.ex
+mail from:<>
+rcpt to:<user_tfo@test.ex>
+data
+Date: Fri, 17 Dec 2004 14:35:01 +0100
+Subject: message should be sent
+
+connection using TFO
+via null-auth proxy
+.
+quit
+****
+#
+#
+# Ends
diff --git a/test/scripts/4027-TFO-socks/REQUIRES b/test/scripts/4027-TFO-socks/REQUIRES
new file mode 100644 (file)
index 0000000..f7e42e6
--- /dev/null
@@ -0,0 +1,2 @@
+support SOCKS
+support TCP_Fast_Open
index 6728b141d3056137c6c5608b870daf5e5dac001c..6b3ff5fcf3409527824e0161f37a20cfa1df932e 100644 (file)
@@ -93,6 +93,40 @@ Date: Thu, 19 Nov 2015 17:00:07 -0700
 Message-ID: <qwerty1234@disco-zombie.net>
 Subject: simple test
 
+This is a simple test.
+.
+??? 250
+QUIT
+??? 221
+****
+#
+#
+# This should pass.  The pubkey dns decord has a additional sha1-only h= field
+#
+#  - sha1, 512b
+# Mail original in aux-fixed/4500.msg1.txt
+# Sig generated by: perl aux-fixed/dkim/sign.pl --keyfile=aux-fixed/dkim/dkim512.private \
+#                       --method=simple/simple --selector=ses_sha1 < aux-fixed/4500.msg1.txt
+client 127.0.0.1 PORT_D
+??? 220
+HELO xxx
+??? 250
+MAIL FROM:<CALLER@bloggs.com>
+??? 250
+RCPT TO:<a@test.ex>
+??? 250
+DATA
+??? 354
+DKIM-Signature: v=1; a=rsa-sha1; c=simple/simple; d=test.ex; h=from:to
+       :date:message-id:subject; s=ses_sha1; bh=OB9dZVu7+5/ufs3TH9leIcE
+       pXSo=; b=hG14R3Eb/f13Pw6J0LmovHAL01KHVmVrTZ7KJrqieYTQemUaseoU2pB
+       7/g8NUwG/AsYoaw3gaAK8PqxSk2lcIQ==
+From: mrgus@text.ex
+To: bakawolf@yahoo.com
+Date: Thu, 19 Nov 2015 17:00:07 -0700
+Message-ID: <qwerty1234@disco-zombie.net>
+Subject: simple test
+
 This is a simple test.
 .
 ??? 250
diff --git a/test/scripts/4500-DKIM/4503 b/test/scripts/4500-DKIM/4503
new file mode 100644 (file)
index 0000000..aca1958
--- /dev/null
@@ -0,0 +1,45 @@
+# DKIM verify, sha512
+#
+exim -DSERVER=server -bd -oX PORT_D
+****
+#
+# This should pass, only Mail::DKIM::Signer does not handle rsa-sha512.
+#  - sha512, 1024b
+# Mail original in aux-fixed/4500.msg1.txt
+# Sig generated by: perl aux-fixed/dkim/sign.pl --algorithm=rsa-sha512 \
+#                      --method=simple/simple < aux-fixed/4500.msg1.txt
+#
+# TODO - until we have that we can only test internal consistency,
+# signing vs. verification.
+#
+client 127.0.0.1 PORT_D
+??? 220
+HELO xxx
+??? 250
+MAIL FROM:<CALLER@bloggs.com>
+??? 250
+RCPT TO:<a@test.ex>
+??? 250
+DATA
+??? 354
+DKIM-Signature: v=1; a=rsa-sha512; c=simple/simple; d=test.ex; h=from:to
+       :date:message-id:subject; s=sel; bh=3UbbJTudPxmejzh7U1Zg33U3QT+1
+       6kfV2eOTvMeiEis=; b=xQSD/JMqz0C+xKf0A1NTkPTbkDuDdJbpBuyjjT9iYvyP
+       Zez+xl0TkoPobFGVa6EN8+ZeYV18zjifhtWYLSsNmPinUtcpKQLG1zxAKmmS0JEh
+       +qihlWbeGJ5+tK588ugUzXHPj+4JBW0H6kxHvdH0l2SlQE5xs/cdggnx5QX5USY=
+From: mrgus@text.ex
+To: bakawolf@yahoo.com
+Date: Thu, 19 Nov 2015 17:00:07 -0700
+Message-ID: <qwerty1234@disco-zombie.net>
+Subject: simple test
+
+This is a simple test.
+.
+??? 250
+QUIT
+??? 221
+****
+#
+killdaemon
+no_stdout_check
+no_msglog_check
index 6eb81cc16ee1c805cbca918cf1d2ccaf98979972..e8d7c41f021fc82182cfc640b3caf432a42a4c32 100644 (file)
@@ -134,6 +134,41 @@ QUIT
 ****
 #
 #
+# This should fail as the sig on the mail uses sha1 but the dns record requires sha256
+#
+#  - sha256, 512b
+# Mail original in aux-fixed/4500.msg1.txt
+# Sig generated by: perl aux-fixed/dkim/sign.pl --keyfile=aux-fixed/dkim/dkim512.private \
+#                       --method=simple/simple --selector=ses_sha1 < aux-fixed/4500.msg1.txt
+# and then modifying the s= manually
+client 127.0.0.1 PORT_D
+??? 220
+HELO xxx
+??? 250
+MAIL FROM:<CALLER@bloggs.com>
+??? 250
+RCPT TO:<a@test.ex>
+??? 250
+DATA
+??? 354
+DKIM-Signature: v=1; a=rsa-sha1; c=simple/simple; d=test.ex; h=from:to
+       :date:message-id:subject; s=ses_sha256; bh=OB9dZVu7+5/ufs3TH9leIcE
+       pXSo=; b=hG14R3Eb/f13Pw6J0LmovHAL01KHVmVrTZ7KJrqieYTQemUaseoU2pB
+       7/g8NUwG/AsYoaw3gaAK8PqxSk2lcIQ==
+From: mrgus@text.ex
+To: bakawolf@yahoo.com
+Date: Thu, 19 Nov 2015 17:00:07 -0700
+Message-ID: <qwerty1234@disco-zombie.net>
+Subject: simple test
+
+This is a simple test.
+.
+??? 250
+QUIT
+??? 221
+****
+#
+#
 killdaemon
 no_stdout_check
 no_msglog_check
index 6efe3545aa7a614a6ac1b29a35e7620c81a58948..3e58799729613ce5db6d1dadd03f619cb068d152 100644 (file)
@@ -26,7 +26,7 @@ content
 ****
 #
 # check that on signing we warn in debug mode about verify problems
-exim -d-all+acl -DHEADERS_MAXSIZE=y -DSELECTOR=sel_bad -odf d@test.ex
+exim -d-all+acl -DOPT=From -DSELECTOR=sel_bad -odf d@test.ex
 From: nobody@example.com
 
 content
diff --git a/test/scripts/4500-DKIM/4523 b/test/scripts/4500-DKIM/4523
new file mode 100644 (file)
index 0000000..b897fc2
--- /dev/null
@@ -0,0 +1,15 @@
+# DKIM signing, sha512
+#
+exim -bd -DSERVER=server -oX PORT_D
+****
+#
+# default header set
+exim -DHEADERS_MAXSIZE=y -DVALUE=sha512 -odf a@test.ex
+From: nobody@example.com
+
+content
+****
+#
+millisleep 500
+killdaemon
+no_msglog_check
diff --git a/test/scripts/4500-DKIM/4524 b/test/scripts/4500-DKIM/4524
new file mode 100644 (file)
index 0000000..9737ad5
--- /dev/null
@@ -0,0 +1,14 @@
+# DKIM signing, multiple
+#
+exim -bd -DSERVER=server -oX PORT_D
+****
+#
+exim -DSELECTOR=ses:sel -DOPT=From:To:Subject -odf c@test.ex
+From: nobody@example.com
+
+content
+****
+#
+millisleep 500
+killdaemon
+no_msglog_check
diff --git a/test/scripts/4500-DKIM/4530 b/test/scripts/4500-DKIM/4530
new file mode 100644 (file)
index 0000000..1465d58
--- /dev/null
@@ -0,0 +1,68 @@
+# DKIM, CHUNKING, wireformat-spoolfile
+#
+exim -bd -DSERVER=server -DOPT=dkim -oX PORT_S:PORT_D
+****
+#
+# 1: non-CHUNKING injection; will not be stored as wireformat therefore
+# onward-send will not use sendfile.  Should still be signed, and verify correctly.
+client 127.0.0.1 PORT_S
+??? 220
+EHLO xxx
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250
+MAIL FROM:<CALLER@bloggs.com>
+??? 250
+RCPT TO:<z@test.ex>
+??? 250
+DATA
+??? 354
+Subject: simple test
+
+Line 1: This is a simple test.
+Line 2: This is a simple test.
+..Line 3 has a leading dot
+last line: 4
+.
+??? 250
+QUIT
+??? 221
+****
+sleep 1
+#
+# 2: CHUNKING injection; should be stored as wireformat therefore
+# onward-send should not use sendfile.  Should still be signed, and verify correctly.
+client 127.0.0.1 PORT_S
+??? 220
+EHLO xxx
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250-
+??? 250
+MAIL FROM:<CALLER@bloggs.com>
+??? 250
+RCPT TO:<y@test.ex>
+??? 250
+BDAT 129 LAST
+Subject: simple test
+
+Line 1: This is a simple test.
+Line 2: This is a simple test.
+.Line 3 has a leading dot
+last line: 4
+??? 250-
+??? 250
+QUIT
+??? 221
+****
+sleep 1
+#
+killdaemon
+exim -q
+****
+no_msglog_check
index d0dd4f363ba28cb69e4165608207faafd7eaa996..29b2ce8b43ef2debe4020eafba66f301ebf8d351 100644 (file)
@@ -9,6 +9,8 @@ QUIT
 exim -odi userx@domain1
 Test message 1
 ****
+sudo rm DIR/spool/db/*
+#
 server PORT_S
 220 Connected OK
 EHLO
@@ -20,6 +22,8 @@ QUIT
 ****
 exim -qf
 ****
+sudo rm DIR/spool/db/*
+#
 server PORT_S
 550 Go away
 QUIT
@@ -27,6 +31,8 @@ QUIT
 ****
 exim -qf
 ****
+sudo rm DIR/spool/db/*
+#
 server PORT_S
 220 Connected OK
 EHLO
diff --git a/test/scripts/5000-maildir/5010 b/test/scripts/5000-maildir/5010
new file mode 100644 (file)
index 0000000..9d30c01
--- /dev/null
@@ -0,0 +1,35 @@
+# quota and maildir with no_check_support (5010, 5011, 5012)
+exim -odi userx@test.ex
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+****
+exim -odi userx@test.ex
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+This is a message of a reasonable size. Fifty here.
+****
+no_msglog_check
diff --git a/test/scripts/5000-maildir/5011 b/test/scripts/5000-maildir/5011
new file mode 120000 (symlink)
index 0000000..c95870f
--- /dev/null
@@ -0,0 +1 @@
+5010
\ No newline at end of file
diff --git a/test/scripts/5000-maildir/5012 b/test/scripts/5000-maildir/5012
new file mode 120000 (symlink)
index 0000000..c95870f
--- /dev/null
@@ -0,0 +1 @@
+5010
\ No newline at end of file
index ddcdeed9b01376b0fa184a8bd3f79b173208deb9..ecc763510397df46ac10a4006e936648e386f449 100644 (file)
@@ -20,7 +20,7 @@ exim -bd -oX PORT_D -DSERVER=server \
 exim nostaple@test.ex
 test message.
 ****
-millisleep 500
+millisleep 700
 #
 #
 #
index d22a1aa1f1c8d037f21565909b0d432ab16c2e91..11c3a867f80bed6bd82705ef599f961100b98e1a 100644 (file)
@@ -21,7 +21,7 @@ exim -bd -oX PORT_D -DSERVER=server \
 exim norequire@test.ex
 test message.
 ****
-millisleep 500
+millisleep 700
 #
 #
 #
@@ -30,7 +30,7 @@ millisleep 500
 exim nostaple@test.ex
 test message.
 ****
-millisleep 500
+millisleep 700
 #
 #
 #
index 43c545afaae719f0347630101199fa72c036fddd..414430630817bbec4403a53412610b3aa0d0d83c 100644 (file)
@@ -5,7 +5,7 @@
 # Client works when we request but don't require OCSP stapling and none comes
 exim -bd -oX PORT_D -DSERVER=server -DRETURN=/dev/null
 ****
-exim norequire@test.ex
+exim norequire_1@test.ex
 test message.
 ****
 sleep 1
@@ -18,10 +18,10 @@ killdaemon
 exim -bd -oX PORT_D -DSERVER=server \
  -DRETURN=DIR/aux-fixed/exim-ca/example.com/server1.example.com/server1.example.com.ocsp.good.resp
 ****
-exim norequire@test.ex
+exim norequire_2@test.ex
 test message.
 ****
-millisleep 500
+millisleep 700
 #
 #
 #
@@ -30,7 +30,7 @@ millisleep 500
 exim nostaple@test.ex
 test message.
 ****
-millisleep 500
+millisleep 700
 #
 #
 #
index d1da54913157a6490ac7e8e1e2d0c58a5e1534c7..142a25ad471c317e0d8474f4424c8f08d8a13189 100644 (file)
@@ -61,14 +61,26 @@ exim -DSERVER=server -DDETAILS=ee -bd -oX PORT_D
 exim -odq CALLER@mxdanelazy.test.ex
 Testing
 ****
-### A server lacking a TLSA, required
+### A server lacking a TLSA, dane required (should fail)
 exim -odq CALLER@dane.no.1.test.ex
 Testing
 ****
-### A server lacking a TLSA, requested only
+### A server lacking a TLSA, dane requested only (should fail, as the NXDOMAIN is not DNSSEC)
 exim -odq CALLER@dane.no.2.test.ex
 Testing
 ****
+### A server where the A is dnssec and the TLSA _fails_
+exim -odq CALLER@danebroken1.test.ex
+Testing
+****
+### A server securely saying "no TLSA records here", dane required (should fail)
+exim -odq CALLER@dane.no.3.test.ex
+Testing
+****
+### A server securely saying "no TLSA records here", dane requested only (should transmit)
+exim -odq CALLER@dane.no.4.test.ex
+Testing
+****
 exim -qf
 ****
 killdaemon
index 0806136cc99a87ba437e6e8c173ade1c2a03d413..583b0128270fb23ca49da0e8390dcb175c4741cd 100644 (file)
@@ -53,11 +53,15 @@ HOST_NOT_FOUND.
 Any DNS record line in a zone file can be prefixed with "DELAY=" and
 a number of milliseconds (followed by one space).
 
-Any DNS record line in a zone file can be prefixed with "DNSSEC ";
+Any DNS record line can be prefixed with "DNSSEC ";
 if all the records found by a lookup are marked
 as such then the response will have the "AD" bit set.
 
-Any DNS record line in a zone file can be prefixed with "AA "
+Any DNS record line can be prefixed with "NXDOMAIN ";
+The record will be ignored (but the prefix set still applied);
+This lets us return a DNSSEC NXDOMAIN.
+
+Any DNS record line can be prefixed with "AA "
 if all the records found by a lookup are marked
 as such then the response will have the "AA" bit set.
 
@@ -342,9 +346,6 @@ if (typeptr->name == NULL)
 rrdomain[0] = 0;                 /* No previous domain */
 (void)fseek(f, 0, SEEK_SET);     /* Start again at the beginning */
 
-if (dnssec) *dnssec = TRUE;     /* cancelled by first nonsecure rec found */
-if (aa) *aa = TRUE;             /* cancelled by first non-aa rec found */
-
 /* Scan for RRs */
 
 while (fgets(CS buffer, sizeof(buffer), f) != NULL)
@@ -357,6 +358,7 @@ while (fgets(CS buffer, sizeof(buffer), f) != NULL)
   int qtlen = qtypelen;
   BOOL rr_sec = FALSE;
   BOOL rr_aa = FALSE;
+  BOOL rr_ignore = FALSE;
   int delay = 0;
   uint ttl = DEFAULT_TTL;
 
@@ -382,6 +384,11 @@ while (fgets(CS buffer, sizeof(buffer), f) != NULL)
       rr_sec = TRUE;
       p += 7;
       }
+    if (Ustrncmp(p, US"NXDOMAIN ", 9) == 0)     /* ignore record content */
+      {
+      rr_ignore = TRUE;
+      p += 9;
+      }
     else if (Ustrncmp(p, US"AA ", 3) == 0)      /* tagged as authoritative */
       {
       rr_aa = TRUE;
@@ -438,7 +445,12 @@ while (fgets(CS buffer, sizeof(buffer), f) != NULL)
 
   /* The domain matches */
 
-  if (yield == HOST_NOT_FOUND) yield = NO_DATA;
+  if (yield == HOST_NOT_FOUND)
+    {
+    yield = NO_DATA;
+    if (dnssec) *dnssec = TRUE;     /* cancelled by first nonsecure rec found */
+    if (aa) *aa = TRUE;             /* cancelled by first non-aa rec found */
+    }
 
   /* Compare RR types; a CNAME record is always returned */
 
@@ -462,6 +474,8 @@ while (fgets(CS buffer, sizeof(buffer), f) != NULL)
   if (aa && !rr_aa)
     *aa = FALSE;                        /* cancel AA return */
 
+  if (rr_ignore) continue;
+
   yield = 0;
   *countptr = *countptr + 1;
 
index ce55c5c377ac716be3f875b7c683eed0fb56d9b5..5af86d96f76eb4075c2b05a0de962f996456abf5 100644 (file)
@@ -26,6 +26,7 @@ on all interfaces, unless the option -noipv6 is given. */
 #include <netinet/in_systm.h>
 #include <netinet/in.h>
 #include <netinet/ip.h>
+#include <netinet/tcp.h>
 
 #ifdef HAVE_NETINET_IP_VAR_H
 # include <netinet/ip_var.h>
@@ -169,7 +170,7 @@ int connection_count = 1;
 int count;
 int on = 1;
 int timeout = 5;
-int initial_pause = 0;
+int initial_pause = 0, tfo = 0;
 int use_ipv4 = 1;
 int use_ipv6 = 1;
 int debug = 0;
@@ -214,6 +215,7 @@ if (argc > 1 && (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")))
        "\n\t-noipv6  disable ipv6"
        "\n\t-oP file write PID to file"
        "\n\t-t n     n seconds timeout"
+       "\n\t-tfo     enable TCP Fast Open"
   );
   exit(0);
   }
@@ -221,6 +223,7 @@ if (argc > 1 && (!strcmp(argv[1], "--help") || !strcmp(argv[1], "-h")))
 while (na < argc && argv[na][0] == '-')
   {
   if (strcmp(argv[na], "-d") == 0) debug = 1;
+  else if (strcmp(argv[na], "-tfo") == 0) tfo = 1;
   else if (strcmp(argv[na], "-t") == 0)
     {
     if (tmo_noerror = ((timeout = atoi(argv[++na])) < 0)) timeout = -timeout;
@@ -295,7 +298,15 @@ else
       printf("IPv6 socket creation failed: %s\n", strerror(errno));
       exit(1);
       }
-
+#ifdef TCP_FASTOPEN
+    if (tfo)
+      {
+      int backlog = 5;
+      if (setsockopt(listen_socket[v6n], IPPROTO_TCP, TCP_FASTOPEN,
+                    &backlog, sizeof(backlog)))
+       if (debug) printf("setsockopt TCP_FASTOPEN: %s\n", strerror(errno));
+      }
+#endif
     /* If this is an IPv6 wildcard socket, set IPV6_V6ONLY if that option is
     available. */
 
@@ -319,6 +330,15 @@ else
       printf("IPv4 socket creation failed: %s\n", strerror(errno));
       exit(1);
       }
+#ifdef TCP_FASTOPEN
+    if (tfo)
+      {
+      int backlog = 5;
+      if (setsockopt(listen_socket[v4n], IPPROTO_TCP, TCP_FASTOPEN,
+                    &backlog, sizeof(backlog)))
+       if (debug) printf("setsockopt TCP_FASTOPEN: %s\n", strerror(errno));
+      }
+#endif
     }
   }
 
index 310a4ef29ece98dc313c31ff5457b332bba947df..b9e93a9109114d565856bb9b24f1077e33a626c2 100644 (file)
@@ -479,4 +479,4 @@ LOG: H=[1.1.1.1] F=<BY@aa.bb> rejected RCPT <x@test.ex>
 >>> deny: condition test succeeded in ACL "check_recipient"
 >>> end of ACL "check_recipient": DENY
 LOG: H=[1.1.1.1] F=<BlOcKeD@zz.xy> rejected RCPT <x@test.ex>
-LOG: unexpected disconnection while reading SMTP command from [1.1.1.1]
+LOG: unexpected disconnection while reading SMTP command from [1.1.1.1] D=qqs
index 7c5a79ee947a6dabf98781813d13da29ec36fda0..299cc4974fe9e8f7c312fb7655e46c4f8da6a619 100644 (file)
@@ -80,9 +80,10 @@ ok@test1 in "+ok_senders"? yes (matched "+ok_senders")
 check sender_domains = +ok_sender_domains
 test1 in "somewhere : test1 : test3"? yes (matched "test1")
 test1 in "+ok_sender_domains"? yes (matched "+ok_sender_domains")
-check logwrite = :panic: rcpt accepted
+check logwrite = :panic: rcpt accepted C=$smtp_command_history
+               = :panic: rcpt accepted C=MAIL,MAIL,RCPT
 LOG: PANIC
-  rcpt accepted
+  rcpt accepted C=MAIL,MAIL,RCPT
 accept: condition test succeeded in ACL "rcpt"
 end of ACL "rcpt": ACCEPT
 using ACL "rcpt"
@@ -94,9 +95,10 @@ ok@test1 in "+ok_senders"? yes (matched "+ok_senders" - cached)
 check sender_domains = +ok_sender_domains
 cached yes match for +ok_sender_domains
 test1 in "+ok_sender_domains"? yes (matched "+ok_sender_domains" - cached)
-check logwrite = :panic: rcpt accepted
+check logwrite = :panic: rcpt accepted C=$smtp_command_history
+               = :panic: rcpt accepted C=MAIL,MAIL,RCPT,RCPT
 LOG: PANIC
-  rcpt accepted
+  rcpt accepted C=MAIL,MAIL,RCPT,RCPT
 accept: condition test succeeded in ACL "rcpt"
 end of ACL "rcpt": ACCEPT
 LOG: smtp_connection MAIN
@@ -173,9 +175,10 @@ ok@test3 in "+ok_senders"? yes (matched "+ok_senders")
 check sender_domains = +ok_sender_domains
 test3 in "somewhere : test1 : test3"? yes (matched "test3")
 test3 in "+ok_sender_domains"? yes (matched "+ok_sender_domains")
-check logwrite = :panic: rcpt accepted
+check logwrite = :panic: rcpt accepted C=$smtp_command_history
+               = :panic: rcpt accepted C=MAIL,RCPT
 LOG: PANIC
-  rcpt accepted
+  rcpt accepted C=MAIL,RCPT
 accept: condition test succeeded in ACL "rcpt"
 end of ACL "rcpt": ACCEPT
 >>Headers added by MAIL or RCPT ACL:
@@ -197,4 +200,4 @@ LOG: smtp_connection MAIN
   SMTP connection from CALLER closed by QUIT
 >>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
 1999-03-02 09:44:33 ACL "warn" with "message" setting found in a non-message (EHLO or HELO) ACL: cannot specify header lines here: message ignored
-1999-03-02 09:44:33 rcpt accepted
+1999-03-02 09:44:33 rcpt accepted C=EHLO,MAIL,RCPT
index 3de4266298bc596cb3af4b7a2ac23e64d4876593..b1d0ff9b6202d3cfb5a2bc611838d9077ecccc01 100644 (file)
@@ -38,6 +38,7 @@ cmd buf flush ddd bytes
 cmd buf flush ddd bytes
   SMTP<< 354 Send data
   SMTP>> writing message and terminating "."
+cannot use sendfile for body: spoolfile not wireformat
 writing data block fd=dddd size=sss timeout=300
   SMTP<< 250 OK
 ok=1 send_quit=1 send_rset=0 continue_more=0 yield=0 first_address is NULL
index 70f11bf4fe3b118f3334de45a6fad39d916248c4..30ed85f8d1ea3a0b10207498e96a24a86d94711f 100644 (file)
@@ -24,6 +24,7 @@ writing to file TESTSUITE/test-mail/userx
 Exim quota = 52428800 old size = sssss this message = sss (included)
   file count quota = 0 count = 0
 writing data block fd=dddd size=sss timeout=0
+cannot use sendfile for body: spoolfile not wireformat
 writing data block fd=dddd size=sss timeout=0
 writing data block fd=dddd size=sss timeout=0
 quota = 52428800 threshold = 21495808 old size = sssss message size = sss
index 6a8ee1f7e887efd40d8fa7fe6ce59def00efe343..e3282cc6f4bf333a63870ccf12a4d5102bbe6a38 100644 (file)
@@ -222,10 +222,10 @@ LOG: smtp_connection MAIN
 Connecting to 127.0.0.1 [127.0.0.1]:1224 ... connected
   SMTP<< 220 Server ready
   SMTP>> EHLO myhost.test.ex
-  SMTP<< 250- wotcher
+  SMTP<< 250- wotcher sverifier
          250-SIZE
          250 OK
-  SMTP>> MAIL FROM:<> SIZE=ssss
+  SMTP>> MAIL FROM:<>
   SMTP<< 250 OK
   SMTP>> RCPT TO:<ok@localhost1>
   SMTP<< 250 OK
@@ -236,6 +236,69 @@ LOG: smtp_connection MAIN
   SMTP connection from root closed by QUIT
 LOG: smtp_connection MAIN
   SMTP connection from root
+Connecting to 127.0.0.1 [127.0.0.1]:1224 ... connected
+  SMTP<< 220 Server ready
+  SMTP>> EHLO myhost.test.ex
+  SMTP<< 250- wotcher rverifier
+         250-SIZE
+         250 OK
+  SMTP>> MAIL FROM:<> SIZE=ssss
+  SMTP<< 250 OK
+  SMTP>> RCPT TO:<z@remote.domain>
+  SMTP<< 250 OK
+  SMTP>> QUIT
+  SMTP<< 250 OK
+  SMTP(close)>>
+LOG: MAIN REJECT
+  H=(me) [V4NET.0.0.3] U=root F=<ok@localhost1> rejected RCPT <z@remote.domain>: relay not permitted
+LOG: smtp_connection MAIN
+  SMTP connection from root closed by QUIT
+LOG: smtp_connection MAIN
+  SMTP connection from root
+Connecting to 127.0.0.1 [127.0.0.1]:1224 ... connected
+  SMTP<< 220 Server ready
+  SMTP>> EHLO myhost.test.ex
+  SMTP<< 250- wotcher rverifier
+         250-SIZE
+         250 OK
+  SMTP>> MAIL FROM:<>
+  SMTP<< 250 OK
+  SMTP>> RCPT TO:<z@remote.domain>
+  SMTP<< 250 OK
+  SMTP>> QUIT
+  SMTP<< 250 OK
+  SMTP(close)>>
+LOG: MAIN REJECT
+  H=(me) [V4NET.0.0.3] U=root F=<ok@localhost1> rejected RCPT <z@remote.domain>: relay not permitted
+LOG: smtp_connection MAIN
+  SMTP connection from root closed by QUIT
+LOG: smtp_connection MAIN
+  SMTP connection from root
+Connecting to 127.0.0.1 [127.0.0.1]:1224 ... connected
+  SMTP<< 220 Server ready
+  SMTP>> EHLO myhost.test.ex
+  SMTP<< 250- wotcher rverifier
+         250-SIZE
+         250 OK
+  SMTP>> MAIL FROM:<ok@localhost1>
+  SMTP<< 250 OK
+  SMTP>> RCPT TO:<myhost.test.ex-dddddddd-testing@remote.domain>
+  SMTP<< 550 RANDOM NOT OK
+  SMTP>> RSET
+  SMTP<< 250 OK
+  SMTP>> MAIL FROM:<ok@localhost1> SIZE=ssss
+  SMTP<< 250 OK
+  SMTP>> RCPT TO:<z@remote.domain>
+  SMTP<< 250 OK
+  SMTP>> QUIT
+  SMTP<< 250 OK
+  SMTP(close)>>
+LOG: MAIN REJECT
+  H=(me) [V4NET.0.0.7] U=root F=<ok@localhost1> rejected RCPT <z@remote.domain>: relay not permitted
+LOG: smtp_connection MAIN
+  SMTP connection from root closed by QUIT
+LOG: smtp_connection MAIN
+  SMTP connection from root
 Connecting to 127.0.0.1 [127.0.0.1]:1224 ... connected
   SMTP<< 220 Server ready
   SMTP>> LHLO myhost.test.ex
index 5f76af09afe8650509cc3f72195d8244bc344ec1..089dc2a8b7e19c5c9ff5264a7e0b8b04cb9ceb35 100644 (file)
@@ -198,9 +198,10 @@ Delivery address list:
   userx@test.ex 
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
 ensuring TESTSUITE/spool/db/retry.lockfile is owned by exim
+failed to open DB file TESTSUITE/spool/db/retry.lockfile: No such file or directory
 no retry data available
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 Considering: userx@test.ex
@@ -307,8 +308,9 @@ search_tidyup called
 --------> userx@test.ex <--------
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
 no retry data available
 search_tidyup called
 changed uid/gid: local delivery to userx <userx@test.ex> transport=t1
index 2d9967293358676070616ac2ad0f7e536dd74af0..b7c7913dfd5cff4e833b43d77ec01150eb4a2ee0 100644 (file)
@@ -145,9 +145,10 @@ Delivery address list:
   CALLER@test.ex 
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
 ensuring TESTSUITE/spool/db/retry.lockfile is owned by exim
+failed to open DB file TESTSUITE/spool/db/retry.lockfile: No such file or directory
 no retry data available
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 Considering: CALLER@test.ex
@@ -209,8 +210,9 @@ search_tidyup called
 --------> CALLER@test.ex <--------
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
 no retry data available
 search_tidyup called
 changed uid/gid: local delivery to CALLER <CALLER@test.ex> transport=t1
index 2506e1cfbf70182494f5cbbf218ea511034b81d2..4d3bb363bc82823f3d92930b6e4a6adb4b716181 100644 (file)
@@ -86,8 +86,9 @@ Delivery address list:
   kilos@recurse.test.ex 
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
 no retry data available
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 Considering: kilos@recurse.test.ex
@@ -122,8 +123,9 @@ rewrite_one_header: type=F:
 re-routed to kilos@recurse.test.ex.test.ex
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
 no retry data available
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 Considering: kilos@recurse.test.ex.test.ex
@@ -161,8 +163,9 @@ routed by r3 router
   transport: <none>
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
 no retry data available
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 Considering: kilos@recurse.test.ex.test.ex
@@ -209,8 +212,9 @@ search_tidyup called
 --------> kilos@recurse.test.ex.test.ex <--------
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
 no retry data available
 search_tidyup called
 changed uid/gid: local delivery to kilos <kilos@recurse.test.ex.test.ex> transport=t2
index bcddefdfaca29c3899e6f63fada8d3ec476f6c46..abd462b013dcb880c8b7cd57939d3daeedf26f08 100644 (file)
@@ -323,10 +323,6 @@ Connecting to 127.0.0.1 [127.0.0.1]:1224 ... connected
   SMTP(close)>>
 wrote callout cache domain record for otherhost3:
   result=1 postmaster=0 random=1
-LOG: MAIN REJECT
-  H=[V4NET.0.0.3] U=root sender verify defer for <ok@otherhost3>: Could not complete sender verify callout: 127.0.0.1 [127.0.0.1] : response to "RCPT TO:<myhost.test.ex-dddddddd-testing@otherhost3>" was: 250 OK
-LOG: MAIN REJECT
-  H=[V4NET.0.0.3] U=root F=<ok@otherhost3> temporarily rejected RCPT <z@test.ex>: Could not complete sender verify callout
 LOG: smtp_connection MAIN
   SMTP connection from root closed by QUIT
 >>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
@@ -373,10 +369,6 @@ Connecting to 127.0.0.1 [127.0.0.1]:1224 ... connected
   SMTP(close)>>
 wrote callout cache domain record for otherhost4:
   result=1 postmaster=0 random=1
-LOG: MAIN REJECT
-  H=[V4NET.0.0.4] U=root sender verify defer for <ok@otherhost4>: Could not complete sender verify callout: 127.0.0.1 [127.0.0.1] : response to "RCPT TO:<myhost.test.ex-dddddddd-testing@otherhost4>" was: 250 OK
-LOG: MAIN REJECT
-  H=[V4NET.0.0.4] U=root F=<ok@otherhost4> temporarily rejected RCPT <z@test.ex>: Could not complete sender verify callout
 LOG: smtp_connection MAIN
   SMTP connection from root closed by QUIT
 >>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
index 44e856da20ac6c5ec18f815c1f7ea3c37a5b703e..5573a9964229f000f1a39e1e685a833ffb621cdc 100644 (file)
@@ -252,9 +252,10 @@ Delivery address list:
   2@b 
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
 ensuring TESTSUITE/spool/db/retry.lockfile is owned by exim
+failed to open DB file TESTSUITE/spool/db/retry.lockfile: No such file or directory
 no retry data available
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 Considering: 2@b
@@ -289,8 +290,9 @@ search_tidyup called
 --------> 2@b <--------
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
 no retry data available
 search_tidyup called
 changed uid/gid: local delivery to 2 <2@b> transport=t1
@@ -310,6 +312,7 @@ lock file created
 mailbox TESTSUITE/test-mail/2 is locked
 writing to file TESTSUITE/test-mail/2
 writing data block fd=dddd size=sss timeout=0
+cannot use sendfile for body: spoolfile not wireformat
 writing data block fd=dddd size=sss timeout=0
 writing data block fd=dddd size=sss timeout=0
 appendfile yields 0 with errno=dd more_errno=dd
@@ -433,8 +436,9 @@ Delivery address list:
   2@b 
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
 no retry data available
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 Considering: 2@b
@@ -469,8 +473,9 @@ search_tidyup called
 --------> 2@b <--------
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
 no retry data available
 search_tidyup called
 changed uid/gid: local delivery to 2 <2@b> transport=t1
@@ -490,6 +495,7 @@ lock file created
 mailbox TESTSUITE/test-mail/2 is locked
 writing to file TESTSUITE/test-mail/2
 writing data block fd=dddd size=sss timeout=0
+cannot use sendfile for body: spoolfile not wireformat
 writing data block fd=dddd size=sss timeout=0
 writing data block fd=dddd size=sss timeout=0
 appendfile yields 0 with errno=dd more_errno=dd
index 92b3f23e1e392e0d7b7c944f51310a1941f0f2fd..5a21445c966a7bd05cde1d8e5f9502cebc0381a6 100644 (file)
@@ -9,9 +9,10 @@ set_process_info: pppp delivering specified messages
 set_process_info: pppp delivering 10HmaX-0005vi-00
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
 ensuring TESTSUITE/spool/db/retry.lockfile is owned by exim
+failed to open DB file TESTSUITE/spool/db/retry.lockfile: No such file or directory
 no retry data available
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 Considering: x@y
@@ -76,8 +77,9 @@ set_process_info: pppp delivering 10HmaX-0005vi-00 using smtp
 checking status of 127.0.0.1
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
 no retry data available
 127.0.0.1 in serialize_hosts? no (option unset)
 set_process_info: pppp delivering 10HmaX-0005vi-00 to 127.0.0.1 [127.0.0.1] (x@y)
@@ -107,8 +109,9 @@ address match test: subject=*@127.0.0.1 pattern=*
 checking status of V4NET.0.0.0
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
 no retry data available
 V4NET.0.0.0 in serialize_hosts? no (option unset)
 set_process_info: pppp delivering 10HmaX-0005vi-00 to V4NET.0.0.0 [V4NET.0.0.0] (x@y)
@@ -137,8 +140,8 @@ Deferred addresses:
  x@y
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x2
+returned from EXIM_DBOPEN: 0xAAAAAAAA
 opened hints database TESTSUITE/spool/db/retry: flags=O_RDWR
 address match test: subject=x@y pattern=*
 y in "*"? yes (matched "*")
@@ -164,6 +167,7 @@ dbfn_write: key=T:V4NET.0.0.0:V4NET.0.0.0:1224
 timed out: all retries expired
 LOG: MAIN
   ** x@y: retry timeout exceeded
+EXIM_DBCLOSE(0xAAAAAAAA)
 closed hints database and lockfile
 end of retry processing
 exec TESTSUITE/eximdir/exim -DEXIM_PATH=TESTSUITE/eximdir/exim -C TESTSUITE/test-config -d=0xebb95ced -odi -odi -t -oem -oi -f <> -E10HmaX-0005vi-00
@@ -236,8 +240,8 @@ set_process_info: pppp delivering specified messages
 set_process_info: pppp delivering 10HmaY-0005vi-00
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: 0xAAAAAAAA
 opened hints database TESTSUITE/spool/db/retry: flags=O_RDONLY
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 Considering: CALLER@myhost.test.ex
@@ -248,6 +252,7 @@ dbfn_read: key=R:CALLER@myhost.test.ex:<>
 no domain retry record
 no address retry record
 CALLER@myhost.test.ex: queued for routing
+EXIM_DBCLOSE(0xAAAAAAAA)
 closed hints database and lockfile
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 routing CALLER@myhost.test.ex
index dd0887f095a73ce29912d68b5601418c5b7b3f62..7fb82e35cae7bf10c3fe18792cbea445a91295aa 100644 (file)
@@ -28,6 +28,7 @@ mailbox TESTSUITE/test-mail/userx is locked
 writing to file TESTSUITE/test-mail/userx
 writing data block fd=dddd size=sss timeout=0
 process pppp running as transport filter: fd_write=dddd fd_read=dddd
+cannot use sendfile for body: spoolfile not wireformat
 writing data block fd=dddd size=sss timeout=0
 process pppp writing to transport filter
 copying from the filter
@@ -70,6 +71,7 @@ lock file created
 mailbox TESTSUITE/test-mail/userx is locked
 writing to file TESTSUITE/test-mail/userx
 writing data block fd=dddd size=sss timeout=0
+cannot use sendfile for body: spoolfile not wireformat
 writing data block fd=dddd size=sss timeout=0
 writing data block fd=dddd size=sss timeout=0
 appendfile yields 0 with errno=dd more_errno=dd
@@ -108,6 +110,7 @@ lock file created
 mailbox TESTSUITE/test-mail/userx is locked
 writing to file TESTSUITE/test-mail/userx
 writing data block fd=dddd size=sss timeout=0
+cannot use sendfile for body: spoolfile not wireformat
 writing data block fd=dddd size=sss timeout=0
 writing data block fd=dddd size=sss timeout=0
 appendfile yields 0 with errno=dd more_errno=dd
index b975ad05af623f4527d1bde94ef3b1163d0002cc..f61f37457536ccd703ff0a840d4d6b609a163809 100644 (file)
@@ -120,13 +120,14 @@ routed by r2 router
 Attempting full verification using callout
 locking TESTSUITE/spool/db/callout.lockfile
 locked  TESTSUITE/spool/db/callout.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/callout)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/callout> dir <TESTSUITE/spool/db> flags 0x2
+returned from EXIM_DBOPEN: 0xAAAAAAAA
 opened hints database TESTSUITE/spool/db/callout: flags=O_RDWR
 dbfn_read: key=remote
 callout cache: found domain record for remote
 dbfn_read: key=qq@remote
 callout cache: no address record found for qq@remote
+EXIM_DBCLOSE(0xAAAAAAAA)
 closed hints database and lockfile
 interface=NULL port=1224
 Connecting to 127.0.0.1 [127.0.0.1]:1224 ... connected
@@ -150,14 +151,15 @@ cmd buf flush ddd bytes
   SMTP(close)>>
 locking TESTSUITE/spool/db/callout.lockfile
 locked  TESTSUITE/spool/db/callout.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/callout)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/callout> dir <TESTSUITE/spool/db> flags 0x42
+returned from EXIM_DBOPEN: 0xAAAAAAAA
 opened hints database TESTSUITE/spool/db/callout: flags=O_RDWR|O_CREAT
 dbfn_write: key=remote
 wrote callout cache domain record for remote:
   result=1 postmaster=0 random=0
 dbfn_write: key=qq@remote
 wrote negative callout cache address record for qq@remote
+EXIM_DBCLOSE(0xAAAAAAAA)
 closed hints database and lockfile
 ----------- end verify ------------
 l_message: $acl_verify_message
@@ -231,14 +233,15 @@ routed by r2 router
 Attempting full verification using callout
 locking TESTSUITE/spool/db/callout.lockfile
 locked  TESTSUITE/spool/db/callout.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/callout)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/callout> dir <TESTSUITE/spool/db> flags 0x2
+returned from EXIM_DBOPEN: 0xAAAAAAAA
 opened hints database TESTSUITE/spool/db/callout: flags=O_RDWR
 dbfn_read: key=remote
 callout cache: found domain record for remote
 dbfn_read: key=qq@remote
 callout cache: found address record for qq@remote
 callout cache: address record is negative
+EXIM_DBCLOSE(0xAAAAAAAA)
 closed hints database and lockfile
 ----------- end verify ------------
 l_message: $acl_verify_message
index a007de31c68edc370f755f07b68de3e76ae6b6d0..8d62a2ef5b99f27c82592e6e8ce9a55de70377d3 100644 (file)
@@ -221,9 +221,10 @@ Delivery address list:
   rd+usery@test.ex 
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
 ensuring TESTSUITE/spool/db/retry.lockfile is owned by exim
+failed to open DB file TESTSUITE/spool/db/retry.lockfile: No such file or directory
 no retry data available
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 Considering: CALLER@test.ex
@@ -416,8 +417,9 @@ routed by r1 router
   transport: t1
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
 no retry data available
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 Considering: TESTSUITE/test-mail/junk
@@ -443,8 +445,9 @@ search_tidyup called
 --------> TESTSUITE/test-mail/junk <--------
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
 no retry data available
  ┌considering: /non-exist/$local_part
  ├──expanding: /non-exist/$local_part
@@ -487,6 +490,7 @@ writing to file TESTSUITE/test-mail/junk
  └─────result: From CALLER@test.ex Tue Mar 02 09:44:33 1999
  
 writing data block fd=dddd size=sss timeout=0
+cannot use sendfile for body: spoolfile not wireformat
 writing data block fd=dddd size=sss timeout=0
 writing data block fd=dddd size=sss timeout=0
 appendfile yields 0 with errno=dd more_errno=dd
@@ -501,8 +505,9 @@ LOG: MAIN
 --------> TESTSUITE/test-mail/junk <--------
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
 no retry data available
 search_tidyup called
 changed uid/gid: local delivery to TESTSUITE/test-mail/junk <TESTSUITE/test-mail/junk> transport=ft1
@@ -542,6 +547,7 @@ writing to file TESTSUITE/test-mail/junk
  └─────result: From CALLER@test.ex Tue Mar 02 09:44:33 1999
  
 writing data block fd=dddd size=sss timeout=0
+cannot use sendfile for body: spoolfile not wireformat
 writing data block fd=dddd size=sss timeout=0
 writing data block fd=dddd size=sss timeout=0
 appendfile yields 0 with errno=dd more_errno=dd
@@ -556,8 +562,9 @@ LOG: MAIN
 --------> CALLER@test.ex <--------
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
 no retry data available
 search_tidyup called
 changed uid/gid: local delivery to CALLER <CALLER@test.ex> transport=t1
@@ -581,8 +588,9 @@ LOG: MAIN
 --------> usery@test.ex <--------
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
 no retry data available
  ┌considering: /non-exist/$local_part
  ├──expanding: /non-exist/$local_part
@@ -609,8 +617,9 @@ LOG: MAIN
 --------> userz@test.ex <--------
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
 no retry data available
  ┌considering: /$local_part
  ├──expanding: /$local_part
index 716cabdf2fa2bec0dd6830057e6c4fd09d585039..a77d8cd9853a39809302a4072dd7d4ab7adcba3a 100644 (file)
@@ -74,9 +74,10 @@ Delivery address list:
   userx@test.ex 
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
 ensuring TESTSUITE/spool/db/retry.lockfile is owned by exim
+failed to open DB file TESTSUITE/spool/db/retry.lockfile: No such file or directory
 no retry data available
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 Considering: userx@test.ex
@@ -137,8 +138,9 @@ routed by r1 router
   transport: <none>
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
 no retry data available
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 Considering: TESTSUITE/test-mail/junk
@@ -156,8 +158,9 @@ search_tidyup called
 --------> TESTSUITE/test-mail/junk <--------
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
 no retry data available
 search_tidyup called
 changed uid/gid: local delivery to TESTSUITE/test-mail/junk <TESTSUITE/test-mail/junk> transport=t1
index d3d8f4c64b24d0c3c7c664c13509865f2d940712..1718307befe4240a63614a36d5a440f4903d2a9b 100644 (file)
@@ -177,9 +177,10 @@ Delivery address list:
   userx@test.ex 
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
 ensuring TESTSUITE/spool/db/retry.lockfile is owned by exim
+failed to open DB file TESTSUITE/spool/db/retry.lockfile: No such file or directory
 no retry data available
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 Considering: userx@test.ex
@@ -220,8 +221,9 @@ routed by r2 router
   transport: <none>
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
 no retry data available
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 Considering: >sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex, ...
@@ -239,8 +241,9 @@ search_tidyup called
 --------> >sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex, ... <--------
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
 no retry data available
 search_tidyup called
 changed uid/gid: local delivery to >sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex, ... <>sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex,sender@test.ex, ...> transport=t1
@@ -3375,8 +3378,9 @@ Delivery address list:
   sender@test.ex 
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
 no retry data available
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 Considering: sender@test.ex
@@ -17981,8 +17985,9 @@ sender@test.ex is a duplicate address: discarded
 --------> sender@test.ex <--------
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
 no retry data available
 search_tidyup called
 changed uid/gid: local delivery to sender <sender@test.ex> transport=t2
@@ -18004,6 +18009,7 @@ writing to file TESTSUITE/test-mail/sender
 writing data block fd=dddd size=sss timeout=0
 flushing headers buffer
 writing data block fd=dddd size=sss timeout=0
+cannot use sendfile for body: spoolfile not wireformat
 writing data block fd=dddd size=sss timeout=0
 writing data block fd=dddd size=sss timeout=0
 appendfile yields 0 with errno=dd more_errno=dd
index f3d6d6b1a7113817a148156a77e54cdb39358be8..fddbe4a46431360f28fffb902d04a31cef33dd9d 100644 (file)
@@ -74,9 +74,10 @@ Delivery address list:
   userx@test.ex 
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
 ensuring TESTSUITE/spool/db/retry.lockfile is owned by exim
+failed to open DB file TESTSUITE/spool/db/retry.lockfile: No such file or directory
 no retry data available
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 Considering: userx@test.ex
@@ -138,8 +139,9 @@ search_tidyup called
 --------> userx@test.ex <--------
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
 no retry data available
 search_tidyup called
 changed uid/gid: local delivery to userx <userx@test.ex> transport=t1
@@ -159,6 +161,7 @@ lock file created
 mailbox TESTSUITE/test-mail/userx is locked
 writing to file TESTSUITE/test-mail/userx
 writing data block fd=dddd size=sss timeout=0
+cannot use sendfile for body: spoolfile not wireformat
 writing data block fd=dddd size=sss timeout=0
 writing data block fd=dddd size=sss timeout=0
 appendfile yields 0 with errno=dd more_errno=dd
index 6ac5a0428b0af2ab1c10a2dba1abcf6264b257ab..79117e25a2ff38341a45744357b3d40934ec1c7f 100644 (file)
@@ -81,13 +81,14 @@ get[host|ipnode]byname[2] looked up these IP addresses:
 Attempting full verification using callout
 locking TESTSUITE/spool/db/callout.lockfile
 locked  TESTSUITE/spool/db/callout.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/callout)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/callout> dir <TESTSUITE/spool/db> flags 0x2
+returned from EXIM_DBOPEN: 0xAAAAAAAA
 opened hints database TESTSUITE/spool/db/callout: flags=O_RDWR
 dbfn_read: key=y
 callout cache: no domain record found for y
 dbfn_read: key=x@y
 callout cache: no address record found for x@y
+EXIM_DBCLOSE(0xAAAAAAAA)
 closed hints database and lockfile
 interface=NULL port=1224
 Connecting to 127.0.0.1 [127.0.0.1]:1224 ... connected
@@ -111,14 +112,15 @@ cmd buf flush ddd bytes
   SMTP(close)>>
 locking TESTSUITE/spool/db/callout.lockfile
 locked  TESTSUITE/spool/db/callout.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/callout)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/callout> dir <TESTSUITE/spool/db> flags 0x42
+returned from EXIM_DBOPEN: 0xAAAAAAAA
 opened hints database TESTSUITE/spool/db/callout: flags=O_RDWR|O_CREAT
 dbfn_write: key=y
 wrote callout cache domain record for y:
   result=1 postmaster=0 random=0
 dbfn_write: key=x@y
 wrote positive callout cache address record for x@y
+EXIM_DBCLOSE(0xAAAAAAAA)
 closed hints database and lockfile
 ----------- end verify ------------
 sender x@y verified ok
@@ -189,14 +191,15 @@ get[host|ipnode]byname[2] looked up these IP addresses:
 Attempting full verification using callout
 locking TESTSUITE/spool/db/callout.lockfile
 locked  TESTSUITE/spool/db/callout.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/callout)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/callout> dir <TESTSUITE/spool/db> flags 0x2
+returned from EXIM_DBOPEN: 0xAAAAAAAA
 opened hints database TESTSUITE/spool/db/callout: flags=O_RDWR
 dbfn_read: key=y
 callout cache: found domain record for y
 dbfn_read: key=x@y
 callout cache: found address record for x@y
 callout cache: address record is positive
+EXIM_DBCLOSE(0xAAAAAAAA)
 closed hints database and lockfile
 ----------- end verify ------------
 sender x@y verified ok
index 59ea69f58c325d27368e98433758d948dbf013b8..675c6239cc0bb68c718105179ba1c8bc0913936a 100644 (file)
@@ -52,6 +52,7 @@ set_process_info: pppp delivering 10HmaX-0005vi-00
 LOG: MAIN
   ** userx@test.ex R=r1 T=t1 H=127.0.0.1 [127.0.0.1]: SMTP error from remote mail server after RCPT TO:<userx@test.ex>: 550 NO
 set_process_info: pppp tidying up after delivering 10HmaX-0005vi-00
+cannot use sendfile for body: spoolfile not wireformat
 writing data block fd=dddd size=sss timeout=0
 Exim version x.yz ....
 configuration file is TESTSUITE/test-config
index 7319b67dd49dc4e51d27e1f5c6e19c8056a0a9df..56e21b60e409727a4e4094b4551cec3b1d0d6602 100644 (file)
@@ -103,9 +103,10 @@ Delivery address list:
   userx@test.ex 
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
 ensuring TESTSUITE/spool/db/retry.lockfile is owned by exim
+failed to open DB file TESTSUITE/spool/db/retry.lockfile: No such file or directory
 no retry data available
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 Considering: userx@test.ex
@@ -140,8 +141,9 @@ search_tidyup called
 --------> userx@test.ex <--------
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
 no retry data available
 search_tidyup called
 changed uid/gid: local delivery to userx <userx@test.ex> transport=t1
@@ -163,6 +165,7 @@ writing to file TESTSUITE/test-mail/userx
 writing data block fd=dddd size=sss timeout=0
 rewrite_one_header: type=F:
   From: unqualified
+cannot use sendfile for body: spoolfile not wireformat
 writing data block fd=dddd size=sss timeout=0
 writing data block fd=dddd size=sss timeout=0
 appendfile yields 0 with errno=dd more_errno=dd
index 1cdf5f013ae3a573fd6eba5af2dca4debf0dcd8f..07025d5d7980c502797a8f5a2e186774baa81b17 100644 (file)
@@ -59,6 +59,7 @@ LOG: MAIN
   == userx@myhost.test.ex R=r1 T=t1 defer (dd): Connection refused
 LOG: MAIN
   ** userx@myhost.test.ex: retry timeout exceeded
+cannot use sendfile for body: spoolfile not wireformat
 writing data block fd=dddd size=sss timeout=0
 Exim version x.yz ....
 configuration file is TESTSUITE/test-config
@@ -122,6 +123,7 @@ LOG: MAIN
   == userx@myhost.test.ex R=r1 T=t1 defer (dd): Connection refused
 LOG: MAIN
   ** userx@myhost.test.ex: retry timeout exceeded
+cannot use sendfile for body: spoolfile not wireformat
 writing data block fd=dddd size=sss timeout=0
 Exim version x.yz ....
 configuration file is TESTSUITE/test-config
index 980da7a0bcb5a5e930358472134d43b3dd429075..53932863191180666431c1b6f061192a05e06b7e 100644 (file)
@@ -8,7 +8,7 @@
 >>> host in helo_accept_junk_hosts? no (option unset)
 >>> rhu.barb in helo_lookup_domains? no (end of list)
 >>> host in smtp_accept_max_nonmail_hosts? yes (matched "*")
-LOG: no MAIL in SMTP connection from (rhu.barb) [10.9.8.7] D=0s C=...HELP,RSET,NOOP,HELP,RSET,NOOP,HELP,RSET,NOOP,HELP,RSET,NOOP,HELP,RSET,NOOP,HELP,RSET,NOOP,HELP,QUIT
+LOG: no MAIL in SMTP connection from (rhu.barb) [10.9.8.7] D=qqs C=...HELP,RSET,NOOP,HELP,RSET,NOOP,HELP,RSET,NOOP,HELP,RSET,NOOP,HELP,RSET,NOOP,HELP,RSET,NOOP,HELP,QUIT
 >>> host in hosts_connection_nolog? no (option unset)
 >>> host in host_lookup? no (option unset)
 >>> host in host_reject_connection? no (option unset)
@@ -20,6 +20,6 @@ LOG: no MAIL in SMTP connection from (rhu.barb) [10.9.8.7] D=0s C=...HELP,RSET,N
 >>> rhu.barb in helo_lookup_domains? no (end of list)
 >>> host in smtp_accept_max_nonmail_hosts? yes (matched "*")
 LOG: SMTP call from (rhu.barb) [10.9.8.7] dropped: too many nonmail commands (last was "HELP")
-LOG: no MAIL in SMTP connection from (rhu.barb) [10.9.8.7] D=0s C=HELO,RSET,NOOP,HELP,RSET,NOOP,HELP,RSET,NOOP,HELP,RSET,NOOP
+LOG: no MAIL in SMTP connection from (rhu.barb) [10.9.8.7] D=qqs C=HELO,RSET,NOOP,HELP,RSET,NOOP,HELP,RSET,NOOP,HELP,RSET,NOOP
 
 ******** SERVER ********
diff --git a/test/stderr/0551 b/test/stderr/0551
new file mode 100644 (file)
index 0000000..134ebac
--- /dev/null
@@ -0,0 +1,305 @@
+14:07:56  7857 Exim version x.yz uid=CALLER_UID gid=CALLER_GID pid=pppp D=fffdffff
+14:07:56  7857 Total 20 lookups
+14:07:56  7857 changed uid/gid: forcing real = effective
+14:07:56  7857   uid=uuuu gid=CALLER_GID pid=pppp
+14:07:56.452  7857 configuration file is TESTSUITE/test-config
+14:07:56.452  7857 log selectors = 00000ffc 0c64c60a
+14:07:56.452  7857 cwd=TESTSUITE 8 args: TESTSUITE/eximdir/exim -DEXIM_PATH=TESTSUITE/eximdir/exim -C TESTSUITE/test-config -d+all -DLOG_SELECTOR=+queue_time+queue_time_overall+deliver_time+millisec -odi userx@test.ex
+14:07:56.452  7857 admin user
+14:07:56.453  7857 changed uid/gid: privilege not needed
+14:07:56.453  7857   uid=EXIM_UID gid=EXIM_GID pid=pppp
+14:07:56.453  7857 DSN: r1 propagating DSN
+14:07:56.453  7857 seeking password data for user "CALLER": cache not available
+14:07:56.453  7857 getpwnam() succeeded uid=CALLER_UID gid=CALLER_GID
+14:07:56.453  7857 originator: uid=CALLER_UID gid=CALLER_GID login=CALLER name=CALLER_NAME
+14:07:56.453  7857 sender address = CALLER@myhost.test.ex
+14:07:56.453  7857 set_process_info: pppp accepting a local non-SMTP message from <CALLER@myhost.test.ex>
+14:07:56.453  7857 spool directory space = 157852648K inodes = 26802407 check_space = 10240K inodes = 100 msg_size = 0
+14:07:56.453  7857 log directory space = 157852648K inodes = 26802407 check_space = 10240K inodes = 100
+14:07:56.453  7857 Sender: CALLER@myhost.test.ex
+14:07:56.453  7857 Recipients:
+14:07:56.453  7857   userx@test.ex
+14:07:56.453  7857 search_tidyup called
+14:07:56.453  7857 >>Headers received:
+14:07:56.453  7857 
+14:07:56.453  7857 rewrite_one_header: type=F:
+14:07:56.453  7857   From: CALLER_NAME <CALLER@myhost.test.ex>
+14:07:56.453  7857 search_tidyup called
+14:07:56.453  7857 >>Headers after rewriting and local additions:
+14:07:56.453  7857 I Message-Id: <E10HmaZ-0005vi-00@myhost.test.ex>
+14:07:56.453  7857 F From: CALLER_NAME <CALLER@myhost.test.ex>
+14:07:56.453  7857   Date: Tue, 2 Mar 1999 09:44:33 +0000
+14:07:56.453  7857 
+14:07:56.453  7857 Data file name: TESTSUITE/spool//input//10HmaZ-0005vi-00-D
+14:07:56.455  7857 Data file written for message 10HmaZ-0005vi-00
+14:07:56.455  7857  ┌considering: ${tod_full}
+14:07:56.455  7857  ├──expanding: ${tod_full}
+14:07:56.455  7857  └─────result: Tue, 2 Mar 1999 09:44:33 +0000
+14:07:56.455  7857  ┌considering: Received: ${if def:sender_rcvhost {from $sender_rcvhost
+14:07:56.455  7857     }{${if def:sender_ident {from ${quote_local_part:$sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)
+14:07:56.455  7857     }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol14:07:56.455  7857}} (Exim $version_number)
+14:07:56.455  7857     ${if def:sender_address {(envelope-from <$sender_address>)
+14:07:56.455  7857     }}id $message_exim_id${if def:received_for {
+14:07:56.455  7857     for $received_for}}
+14:07:56.455  7857  ├──condition: def:sender_rcvhost
+14:07:56.455  7857  ├─────result: false
+14:07:56.455  7857   ┌───scanning: from $sender_rcvhost
+14:07:56.455  7857     }{${if def:sender_ident {from ${quote_local_part:$sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)
+14:07:56.455  7857     }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol14:07:56.455  7857}} (Exim $version_number)
+14:07:56.455  7857     ${if def:sender_address {(envelope-from <$sender_address>)
+14:07:56.455  7857     }}id $message_exim_id${if def:received_for {
+14:07:56.455  7857     for $received_for}}
+14:07:56.455  7857   ├──expanding: from $sender_rcvhost
+14:07:56.455  7857     
+14:07:56.455  7857   ├─────result: from 
+14:07:56.455  7857     
+14:07:56.455  7857   └───skipping: result is not used
+14:07:56.455  7857   ┌considering: ${if def:sender_ident {from ${quote_local_part:$sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)
+14:07:56.455  7857     }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol14:07:56.455  7857}} (Exim $version_number)
+14:07:56.455  7857     ${if def:sender_address {(envelope-from <$sender_address>)
+14:07:56.455  7857     }}id $message_exim_id${if def:received_for {
+14:07:56.455  7857     for $received_for}}
+14:07:56.455  7857   ├──condition: def:sender_ident
+14:07:56.455  7857   ├─────result: true
+14:07:56.455  7857    ┌considering: from ${quote_local_part:$sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)
+14:07:56.455  7857     }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol14:07:56.455  7857}} (Exim $version_number)
+14:07:56.455  7857     ${if def:sender_address {(envelope-from <$sender_address>)
+14:07:56.455  7857     }}id $message_exim_id${if def:received_for {
+14:07:56.455  7857     for $received_for}}
+14:07:56.455  7857    ╎┌considering: $sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)
+14:07:56.455  7857    ╎      }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol14:07:56.455  7857    ╎}} (Exim $version_number)
+14:07:56.455  7857    ╎      ${if def:sender_address {(envelope-from <$sender_address>)
+14:07:56.455  7857    ╎      }}id $message_exim_id${if def:received_for {
+14:07:56.455  7857    ╎      for $received_for}}
+14:07:56.455  7857    ╎├──expanding: $sender_ident
+14:07:56.455  7857    ╎└─────result: CALLER
+14:07:56.455  7857    ├──expanding: from ${quote_local_part:$sender_ident} 
+14:07:56.455  7857    └─────result: from CALLER 
+14:07:56.455  7857   ├──condition: def:sender_helo_name
+14:07:56.455  7857   ├─────result: false
+14:07:56.455  7857    ┌───scanning: (helo=$sender_helo_name)
+14:07:56.455  7857     }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol14:07:56.455  7857}} (Exim $version_number)
+14:07:56.455  7857     ${if def:sender_address {(envelope-from <$sender_address>)
+14:07:56.455  7857     }}id $message_exim_id${if def:received_for {
+14:07:56.455  7857     for $received_for}}
+14:07:56.455  7857    ├──expanding: (helo=$sender_helo_name)
+14:07:56.455  7857     
+14:07:56.455  7857    ├─────result: (helo=)
+14:07:56.455  7857     
+14:07:56.455  7857    └───skipping: result is not used
+14:07:56.455  7857   ├──expanding: ${if def:sender_ident {from ${quote_local_part:$sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)
+14:07:56.455  7857     }}
+14:07:56.455  7857   └─────result: from CALLER 
+14:07:56.455  7857  ├──condition: def:received_protocol
+14:07:56.455  7857  ├─────result: true
+14:07:56.455  7857   ┌considering: with $received_protocol14:07:56.455  7857}} (Exim $version_number)
+14:07:56.455  7857     ${if def:sender_address {(envelope-from <$sender_address>)
+14:07:56.455  7857     }}id $message_exim_id${if def:received_for {
+14:07:56.455  7857     for $received_for}}
+14:07:56.455  7857   ├──expanding: with $received_protocol
+14:07:56.455  7857   └─────result: with local
+14:07:56.455  7857  ├──condition: def:tls_cipher
+14:07:56.455  7857  ├─────result: false
+14:07:56.455  7857   ┌───scanning: ($tls_cipher)
+14:07:56.455  7857     }}(Exim $version_number)
+14:07:56.455  7857     ${if def:sender_address {(envelope-from <$sender_address>)
+14:07:56.455  7857     }}id $message_exim_id${if def:received_for {
+14:07:56.455  7857     for $received_for}}
+14:07:56.455  7857   ├──expanding: ($tls_cipher)
+14:07:56.455  7857     
+14:07:56.455  7857   ├─────result: ()
+14:07:56.455  7857     
+14:07:56.455  7857   └───skipping: result is not used
+14:07:56.455  7857  ├──condition: def:sender_address
+14:07:56.455  7857  ├─────result: true
+14:07:56.455  7857   ┌considering: (envelope-from <$sender_address>)
+14:07:56.455  7857     }}id $message_exim_id${if def:received_for {
+14:07:56.455  7857     for $received_for}}
+14:07:56.455  7857   ├──expanding: (envelope-from <$sender_address>)
+14:07:56.455  7857     
+14:07:56.455  7857   └─────result: (envelope-from <CALLER@myhost.test.ex>)
+14:07:56.455  7857     
+14:07:56.455  7857  ├──condition: def:received_for
+14:07:56.455  7857  ├─────result: true
+14:07:56.455  7857   ┌considering: 
+14:07:56.455  7857     for $received_for}}
+14:07:56.455  7857   ├──expanding: 
+14:07:56.455  7857     for $received_for
+14:07:56.455  7857   └─────result: 
+14:07:56.455  7857     for userx@test.ex
+14:07:56.455  7857  ├──expanding: Received: ${if def:sender_rcvhost {from $sender_rcvhost
+14:07:56.455  7857     }{${if def:sender_ident {from ${quote_local_part:$sender_ident} }}${if def:sender_helo_name {(helo=$sender_helo_name)
+14:07:56.455  7857     }}}}by $primary_hostname ${if def:received_protocol {with $received_protocol14:07:56.455  7857}} (Exim $version_number)
+14:07:56.455  7857     ${if def:sender_address {(envelope-from <$sender_address>)
+14:07:56.455  7857     }}id $message_exim_id${if def:received_for {
+14:07:56.455  7857     for $received_for}}
+14:07:56.455  7857  └─────result: Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+14:07:56.455  7857     (envelope-from <CALLER@myhost.test.ex>)
+14:07:56.455  7857     id 10HmaZ-0005vi-00
+14:07:56.455  7857     for userx@test.ex
+14:07:56.455  7857 >>Generated Received: header line
+14:07:56.455  7857 P Received: from CALLER by myhost.test.ex with local (Exim x.yz)
+14:07:56.455  7857     (envelope-from <CALLER@myhost.test.ex>)
+14:07:56.455  7857     id 10HmaZ-0005vi-00
+14:07:56.455  7857     for userx@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+14:07:56.455  7857 calling local_scan(); timeout=300
+14:07:56.455  7857 local_scan() returned 0 NULL
+14:07:56.455  7857  ┌considering: ${tod_full}
+14:07:56.455  7857  ├──expanding: ${tod_full}
+14:07:56.455  7857  └─────result: Tue, 2 Mar 1999 09:44:33 +0000
+14:07:56.455  7857 Writing spool header file: TESTSUITE/spool//input//hdr.7857
+14:07:56.455  7857 DSN: Write SPOOL :-dsn_envid NULL
+14:07:56.455  7857 DSN: Write SPOOL :-dsn_ret 0
+14:07:56.455  7857 DSN: Flags :0
+14:07:56.455  7857 DSN: **** SPOOL_OUT - address: |userx@test.ex| errorsto: |NULL| orcpt: |NULL| dsn_flags: 0
+14:07:56.457  7857 Renaming spool header file: TESTSUITE/spool//input//10HmaZ-0005vi-00-H
+14:07:56.459  7857 Size of headers = sss
+14:07:56.459  7857 LOG: MAIN
+14:07:56.459  7857   <= CALLER@myhost.test.ex U=CALLER P=local S=sss
+14:07:56.459  7857 search_tidyup called
+14:07:56.459  7858 exec TESTSUITE/eximdir/exim -DEXIM_PATH=TESTSUITE/eximdir/exim -DLOG_SELECTOR=+queue_time+queue_time_overall+deliver_time+millisec -C TESTSUITE/test-config -d=0xfffdffff -odi -Mc 10HmaZ-0005vi-00
+14:07:56  7858 Exim version x.yz uid=EXIM_UID gid=EXIM_GID pid=pppp D=fffdffff
+14:07:56  7858 Total 20 lookups
+14:07:56  7858 changed uid/gid: forcing real = effective
+14:07:56  7858   uid=uuuu gid=EXIM_GID pid=pppp
+14:07:56.565  7858 configuration file is TESTSUITE/test-config
+14:07:56.565  7858 log selectors = 00000ffc 0c64c60a
+14:07:56.565  7858 cwd=TESTSUITE/spool 9 args: TESTSUITE/eximdir/exim -DEXIM_PATH=TESTSUITE/eximdir/exim -DLOG_SELECTOR=+queue_time+queue_time_overall+deliver_time+millisec -C TESTSUITE/test-config -d=0xfffdffff -odi -Mc 10HmaZ-0005vi-00
+14:07:56.565  7858 trusted user
+14:07:56.565  7858 admin user
+14:07:56.565  7858 DSN: r1 propagating DSN
+14:07:56.565  7858 seeking password data for user "CALLER": cache not available
+14:07:56.565  7858 getpwnam() succeeded uid=CALLER_UID gid=CALLER_GID
+14:07:56.565  7858 set_process_info: pppp delivering specified messages
+14:07:56.565  7858 set_process_info: pppp delivering 10HmaZ-0005vi-00
+14:07:56.565  7858 Trying spool file TESTSUITE/spool//input//10HmaZ-0005vi-00-D
+14:07:56.565  7858 reading spool file 10HmaZ-0005vi-00-H
+14:07:56.565  7858 user=CALLER uid=CALLER_UID gid=CALLER_GID sender=CALLER@myhost.test.ex
+14:07:56.565  7858 sender_local=1 ident=CALLER
+14:07:56.565  7858 Non-recipients:
+14:07:56.565  7858 Empty Tree
+14:07:56.565  7858 ---- End of tree ----
+14:07:56.565  7858 recipients_count=1
+14:07:56.565  7858 **** SPOOL_IN - No additional fields
+14:07:56.565  7858 body_linecount=1 message_linecount=7
+14:07:56.565  7858 DSN: set orcpt: NULL  flags: 0
+14:07:56.565  7858 Delivery address list:
+14:07:56.565  7858   userx@test.ex 
+14:07:56.566  7858 locking TESTSUITE/spool/db/retry.lockfile
+14:07:56.566  7858 locked  TESTSUITE/spool/db/retry.lockfile
+14:07:56.566  7858 EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+14:07:56.566  7858 returned from EXIM_DBOPEN: (nil)
+14:07:56.566  7858 failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
+14:07:56.566  7858 no retry data available
+14:07:56.566  7858 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+14:07:56.566  7858 Considering: userx@test.ex
+14:07:56.566  7858 unique = userx@test.ex
+14:07:56.566  7858 no domain retry record
+14:07:56.566  7858 no address retry record
+14:07:56.566  7858 userx@test.ex: queued for routing
+14:07:56.566  7858 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+14:07:56.566  7858 routing userx@test.ex
+14:07:56.566  7858 --------> r1 router <--------
+14:07:56.566  7858 local_part=userx domain=test.ex
+14:07:56.566  7858 calling r1 router
+14:07:56.566  7858 r1 router called for userx@test.ex
+14:07:56.566  7858   domain = test.ex
+14:07:56.566  7858 set transport t1
+14:07:56.566  7858 queued for t1 transport: local_part = userx
+14:07:56.566  7858 domain = test.ex
+14:07:56.566  7858   errors_to=NULL
+14:07:56.566  7858   domain_data=NULL localpart_data=NULL
+14:07:56.566  7858 routed by r1 router
+14:07:56.566  7858   envelope to: userx@test.ex
+14:07:56.566  7858   transport: t1
+14:07:56.566  7858 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+14:07:56.566  7858 After routing:
+14:07:56.566  7858   Local deliveries:
+14:07:56.566  7858     userx@test.ex
+14:07:56.566  7858   Remote deliveries:
+14:07:56.566  7858   Failed addresses:
+14:07:56.566  7858   Deferred addresses:
+14:07:56.566  7858 search_tidyup called
+14:07:56.566  7858 >>>>>>>>>>>>>>>> Local deliveries >>>>>>>>>>>>>>>>
+14:07:56.566  7858 --------> userx@test.ex <--------
+14:07:56.566  7858 locking TESTSUITE/spool/db/retry.lockfile
+14:07:56.566  7858 locked  TESTSUITE/spool/db/retry.lockfile
+14:07:56.566  7858 EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+14:07:56.566  7858 returned from EXIM_DBOPEN: (nil)
+14:07:56.566  7858 failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
+14:07:56.566  7858 no retry data available
+14:07:56.566  7858 search_tidyup called
+14:07:56.566  7859 changed uid/gid: local delivery to userx <userx@test.ex> transport=t1
+14:07:56.566  7859   uid=CALLER_UID gid=CALLER_GID pid=pppp
+14:07:56.566  7859   home=NULL current=/
+14:07:56.566  7859 set_process_info: pppp delivering 10HmaZ-0005vi-00 to userx using t1
+14:07:56.566  7859 appendfile transport entered
+14:07:56.566  7859  ┌considering: TESTSUITE/test-mail/$local_part
+14:07:56.566  7859  ├──expanding: TESTSUITE/test-mail/$local_part
+14:07:56.566  7859  └─────result: TESTSUITE/test-mail/userx
+14:07:56.566  7859 appendfile: mode=600 notify_comsat=0 quota=0 warning=0
+14:07:56.566  7859   file=TESTSUITE/test-mail/userx format=unix
+14:07:56.566  7859   message_prefix=From ${if def:return_path{$return_path}{MAILER-DAEMON}} ${tod_bsdinbox}\n
+14:07:56.566  7859   message_suffix=\n
+14:07:56.566  7859   maildir_use_size_file=no
+14:07:56.566  7859   locking by lockfile fcntl 
+14:07:56.566  7859 lock name: TESTSUITE/test-mail/userx.lock
+14:07:56.566  7859 hitch name: TESTSUITE/test-mail/userx.lock.test.ex.dddddddd.pppppppp
+14:07:56.566  7859 lock file created
+14:07:56.566  7859 mailbox TESTSUITE/test-mail/userx is locked
+14:07:56.566  7859 writing to file TESTSUITE/test-mail/userx
+14:07:56.566  7859  ┌considering: From ${if def:return_path{$return_path}{MAILER-DAEMON}} ${tod_bsdinbox}
+14:07:56.566  7859  
+14:07:56.566  7859  ├──condition: def:return_path
+14:07:56.566  7859  ├─────result: true
+14:07:56.566  7859   ┌considering: $return_path}{MAILER-DAEMON}} ${tod_bsdinbox}
+14:07:56.566  7859   
+14:07:56.566  7859   ├──expanding: $return_path
+14:07:56.566  7859   └─────result: CALLER@myhost.test.ex
+14:07:56.566  7859   ┌───scanning: MAILER-DAEMON}} ${tod_bsdinbox}
+14:07:56.566  7859   
+14:07:56.566  7859   ├──expanding: MAILER-DAEMON
+14:07:56.566  7859   ├─────result: MAILER-DAEMON
+14:07:56.566  7859   └───skipping: result is not used
+14:07:56.566  7859  ├──expanding: From ${if def:return_path{$return_path}{MAILER-DAEMON}} ${tod_bsdinbox}
+14:07:56.566  7859  
+14:07:56.566  7859  └─────result: From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+14:07:56.566  7859  
+14:07:56.566  7859 writing data block fd=6 size=sss timeout=0
+14:07:56.567  7859 cannot use sendfile for body: spoolfile not wireformat
+14:07:56.567  7859 writing data block fd=6 size=sss timeout=0
+14:07:56.567  7859 writing data block fd=6 size=sss timeout=0
+14:07:56.568  7859 appendfile yields 0 with errno=dd more_errno=dd
+14:07:56.568  7859 search_tidyup called
+14:07:56.868  7858 journalling userx@test.ex
+14:07:56.871  7858 t1 transport returned OK for userx@test.ex
+14:07:56.871  7858 post-process userx@test.ex (0)
+14:07:56.871  7858 userx@test.ex delivered
+14:07:56.871  7858 LOG: MAIN
+14:07:56.871  7858   => userx <userx@test.ex> R=r1 T=t1 QT=q.qqqs DT=q.qqqs
+14:07:56.871  7858 >>>>>>>>>>>>>>>> deliveries are done >>>>>>>>>>>>>>>>
+14:07:56.871  7858 changed uid/gid: post-delivery tidying
+14:07:56.871  7858   uid=EXIM_UID gid=EXIM_GID pid=pppp
+14:07:56.871  7858 set_process_info: pppp tidying up after delivering 10HmaZ-0005vi-00
+14:07:56.871  7858 Processing retry items
+14:07:56.871  7858 Succeeded addresses:
+14:07:56.871  7858  userx@test.ex: no retry items
+14:07:56.871  7858 Failed addresses:
+14:07:56.871  7858 Deferred addresses:
+14:07:56.871  7858 end of retry processing
+14:07:56.871  7858 DSN: processing router : r1
+14:07:56.871  7858 DSN: processing successful delivery address: userx@test.ex
+14:07:56.871  7858 DSN: Sender_address: CALLER@myhost.test.ex
+14:07:56.871  7858 DSN: orcpt: NULL  flags: 0
+14:07:56.871  7858 DSN: envid: NULL  ret: 0
+14:07:56.871  7858 DSN: Final recipient: userx@test.ex
+14:07:56.871  7858 DSN: Remote SMTP server supports DSN: 0
+14:07:56.871  7858 DSN: not sending DSN success message
+14:07:56.871  7858 LOG: MAIN
+14:07:56.871  7858   Completed QT=q.qqqs
+14:07:56.871  7858 end delivery of 10HmaZ-0005vi-00
+14:07:56.871  7858 search_tidyup called
+14:07:56.871  7858 search_tidyup called
+14:07:56.871  7858 >>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
+14:07:56.871  7857 search_tidyup called
+14:07:56.871  7857 >>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
index 74581fd9c673505cab80bf161d93458dfa6681c6..9f634c8c4b314e2be7a333256264c1425ecad536 100644 (file)
@@ -337,10 +337,6 @@ Connecting to 127.0.0.1 [127.0.0.1]:1224 ... connected
   SMTP(close)>>
 wrote callout cache domain record for otherhost3:
   result=1 postmaster=0 random=1
-LOG: MAIN REJECT
-  H=[V4NET.0.0.3] U=root sender verify defer for <ok@otherhost3>: Could not complete sender verify callout: 127.0.0.1 [127.0.0.1] : response to "RCPT TO:<myhost.test.ex-dddddddd-testing@otherhost3>" was: 250 OK accepting that random recipient
-LOG: MAIN REJECT
-  H=[V4NET.0.0.3] U=root F=<ok@otherhost3> temporarily rejected RCPT <z@test.ex>: Could not complete sender verify callout
 LOG: smtp_connection MAIN
   SMTP connection from root closed by QUIT
 >>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
@@ -389,10 +385,6 @@ Connecting to 127.0.0.1 [127.0.0.1]:1224 ... connected
   SMTP(close)>>
 wrote callout cache domain record for otherhost4:
   result=1 postmaster=0 random=1
-LOG: MAIN REJECT
-  H=[V4NET.0.0.4] U=root sender verify defer for <ok@otherhost4>: Could not complete sender verify callout: 127.0.0.1 [127.0.0.1] : response to "RCPT TO:<myhost.test.ex-dddddddd-testing@otherhost4>" was: 250 OK
-LOG: MAIN REJECT
-  H=[V4NET.0.0.4] U=root F=<ok@otherhost4> temporarily rejected RCPT <z@test.ex>: Could not complete sender verify callout
 LOG: smtp_connection MAIN
   SMTP connection from root closed by QUIT
 >>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
index be65144469738dd46f751b47d95ad0cdef35db8c..ea998d6d7ab6409c47ef65daa6e0e4ec0d339365 100644 (file)
@@ -45,7 +45,7 @@ ppppp delay cancelled by peer close
 ppppp accept: condition test succeeded in ACL "delay4_accept"
 ppppp end of ACL "delay4_accept": ACCEPT
 ppppp LOG: lost_incoming_connection MAIN
-ppppp   unexpected disconnection while reading SMTP command from [127.0.0.1]
+ppppp   unexpected disconnection while reading SMTP command from [127.0.0.1] D=qqs
 ppppp child ppppp ended: status=0x100
 ppppp   normal exit, 1
 ppppp 0 SMTP accept processes now running
diff --git a/test/stderr/0907 b/test/stderr/0907
new file mode 100644 (file)
index 0000000..fe9ba71
--- /dev/null
@@ -0,0 +1,2 @@
+1999-03-02 09:44:33 Exim configuration error in line 1 of TESTSUITE/test-config:
+  found unexpected BOM (Byte Order Mark)
diff --git a/test/stderr/0908 b/test/stderr/0908
new file mode 100644 (file)
index 0000000..ad35a1a
--- /dev/null
@@ -0,0 +1,2 @@
+1999-03-02 09:44:33 Exim configuration error in line 1 of TESTSUITE/confs/0907:
+  found unexpected BOM (Byte Order Mark)
index 60b23885fd2922f6fbed034f7729b311821cdd54..dc42978c7c3220cf439bab365e61a395bfbee9c7 100644 (file)
@@ -49,7 +49,7 @@ cmd buf flush ddd bytes
   SMTP<< 250 OK id=10HmbB-0005vi-00
   SMTP(close)>>
 LOG: MAIN
-  => userz@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* C="250 OK id=10HmbB-0005vi-00"
+  => userz@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C="250 OK id=10HmbB-0005vi-00"
 LOG: MAIN
   Completed
 >>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
@@ -70,7 +70,86 @@ cmd buf flush ddd bytes
   SMTP(close)>>
 >>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
 LOG: MAIN
-  => usery@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* C="250 OK id=10HmbC-0005vi-00"
+  => usery@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C="250 OK id=10HmbC-0005vi-00"
+LOG: MAIN
+  Completed
+>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
+LOG: queue_run MAIN
+  End queue run: pid=pppp -qqf
+>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
+Exim version x.yz ....
+configuration file is TESTSUITE/test-config
+admin user
+LOG: queue_run MAIN
+  Start queue run: pid=pppp -qqf
+Connecting to 127.0.0.1 [127.0.0.1]:1225 ... connected
+  SMTP<< 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+  SMTP>> EHLO myhost.test.ex
+cmd buf flush ddd bytes
+  SMTP<< 250-myhost.test.ex Hello localhost [127.0.0.1]
+         250-SIZE 52428800
+         250-8BITMIME
+         250-PIPELINING
+         250-STARTTLS
+         250 HELP
+  SMTP>> STARTTLS
+cmd buf flush ddd bytes
+  SMTP<< 220 TLS go ahead
+  SMTP>> EHLO myhost.test.ex
+cmd buf flush ddd bytes
+  SMTP<< 250-myhost.test.ex Hello localhost [127.0.0.1]
+         250-SIZE 52428800
+         250-8BITMIME
+         250-PIPELINING
+         250 HELP
+  SMTP>> MAIL FROM:<CALLER@myhost.test.ex> SIZE=ssss
+  SMTP>> RCPT TO:<usera@test.ex>
+  SMTP>> DATA
+cmd buf flush ddd bytes
+  SMTP<< 250 OK
+  SMTP<< 250 Accepted
+  SMTP<< 354 Enter message, ending with "." on a line by itself
+  SMTP<< 250 OK id=10HmbG-0005vi-00
+LOG: MAIN
+  => usera@test.ex R=cl_override T=send_to_server H=127.0.0.1 [127.0.0.1] X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no DN="C=UK,O=The Exim Maintainers,OU=Test Suite,CN=Phil Pennock" C="250 OK id=10HmbG-0005vi-00"
+LOG: MAIN
+  Completed
+Exim version x.yz ....
+configuration file is TESTSUITE/test-config
+trusted user
+admin user
+  SMTP>> MAIL FROM:<CALLER@myhost.test.ex> SIZE=ssss
+  SMTP>> RCPT TO:<userc@test.ex>
+  SMTP>> DATA
+cmd buf flush ddd bytes
+  SMTP<< 250 OK
+  SMTP<< 250 Accepted
+  SMTP<< 354 Enter message, ending with "." on a line by itself
+  SMTP<< 250 OK id=10HmbH-0005vi-00
+  SMTP(close)>>
+LOG: MAIN
+  => userc@test.ex R=cl_override T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C="250 OK id=10HmbH-0005vi-00"
+LOG: MAIN
+  Completed
+>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
+Exim version x.yz ....
+configuration file is TESTSUITE/test-config
+trusted user
+admin user
+  SMTP>> MAIL FROM:<CALLER@myhost.test.ex> SIZE=ssss
+  SMTP>> RCPT TO:<userb@test.ex>
+  SMTP>> DATA
+cmd buf flush ddd bytes
+  SMTP<< 250 OK
+  SMTP<< 250 Accepted
+  SMTP<< 354 Enter message, ending with "." on a line by itself
+  SMTP<< 250 OK id=10HmbI-0005vi-00
+  SMTP>> QUIT
+cmd buf flush ddd bytes
+  SMTP(close)>>
+>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
+LOG: MAIN
+  => userb@test.ex R=cl_override T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C="250 OK id=10HmbI-0005vi-00"
 LOG: MAIN
   Completed
 >>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
diff --git a/test/stderr/2035 b/test/stderr/2035
new file mode 100644 (file)
index 0000000..dedf4ad
--- /dev/null
@@ -0,0 +1,74 @@
+Exim version x.yz ....
+configuration file is TESTSUITE/test-config
+admin user
+LOG: smtp_connection MAIN
+  SMTP connection from CALLER
+Transport port=25 replaced by host-specific port=1225
+Connecting to 127.0.0.1 [127.0.0.1]:1225 ... connected
+  SMTP<< 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+  SMTP>> EHLO myhost.test.ex
+cmd buf flush ddd bytes
+  SMTP<< 250-myhost.test.ex Hello localhost [127.0.0.1]
+         250-SIZE 52428800
+         250-8BITMIME
+         250-PIPELINING
+         250-STARTTLS
+         250 HELP
+  SMTP>> STARTTLS
+cmd buf flush ddd bytes
+  SMTP<< 220 TLS go ahead
+  SMTP>> EHLO myhost.test.ex
+cmd buf flush ddd bytes
+  SMTP<< 250-myhost.test.ex Hello localhost [127.0.0.1]
+         250-SIZE 52428800
+         250-8BITMIME
+         250-PIPELINING
+         250 HELP
+using PIPELINING
+not using DSN
+  SMTP>> MAIL FROM:<usera@ok.example>
+  SMTP>> RCPT TO:<userb@test.ex>
+cmd buf flush ddd bytes
+  SMTP<< 250 OK
+  SMTP<< 250 Accepted
+LOG: MAIN
+  <= CALLER@myhost.test.ex U=CALLER P=local-smtp S=sss
+LOG: smtp_connection MAIN
+  SMTP connection from CALLER closed by QUIT
+>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
+Exim version x.yz ....
+configuration file is TESTSUITE/test-config
+trusted user
+admin user
+>>>>>>>>>>>>>>>> Remote deliveries >>>>>>>>>>>>>>>>
+--------> userb@test.ex <--------
+t1 transport entered
+  userb@test.ex
+hostlist:
+  127.0.0.1:1225
+already connected to 127.0.0.1 [127.0.0.1] (on fd 0)
+checking status of 127.0.0.1
+127.0.0.1 [127.0.0.1]:1111 retry-status = usable
+delivering 10HmaX-0005vi-00 to 127.0.0.1 [127.0.0.1] (userb@test.ex)
+Transport port=25 replaced by host-specific port=1225
+continued connection, proxied TLS
+  SMTP>> DATA
+cmd buf flush ddd bytes
+  SMTP<< 354 Enter message, ending with "." on a line by itself
+  SMTP>> writing message and terminating "."
+cannot use sendfile for body: spoolfile not wireformat
+writing data block fd=dddd size=sss timeout=300
+  SMTP<< 250 OK id=10HmaY-0005vi-00
+ok=1 send_quit=1 send_rset=0 continue_more=0 yield=0 first_address is NULL
+  SMTP>> QUIT
+cmd buf flush ddd bytes
+  SMTP(close)>>
+Leaving t1 transport
+>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
+LOG: MAIN
+  => userb@test.ex R=client T=t1 H=127.0.0.1 [127.0.0.1]:1225 X=TLS1.x:xxxxRSA_AES_256_CBC_SHAnnn:256 CV=no C="250 OK id=10HmaY-0005vi-00"
+LOG: MAIN
+  Completed
+>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
+
+******** SERVER ********
index 55cfc39dd4a1cf2c882f135b2fa205dd92eca223..35cdabe47df27bd24ed4d471a7491833c2a6f15f 100644 (file)
@@ -49,7 +49,7 @@ cmd buf flush ddd bytes
   SMTP<< 250 OK id=10HmbB-0005vi-00
   SMTP(close)>>
 LOG: MAIN
-  => userz@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* C="250 OK id=10HmbB-0005vi-00"
+  => userz@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLSv1:AES256-SHA:256 CV=no C="250 OK id=10HmbB-0005vi-00"
 LOG: MAIN
   Completed
 >>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
@@ -70,7 +70,86 @@ cmd buf flush ddd bytes
   SMTP(close)>>
 >>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
 LOG: MAIN
-  => usery@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* C="250 OK id=10HmbC-0005vi-00"
+  => usery@test.ex R=client T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLSv1:AES256-SHA:256 CV=no C="250 OK id=10HmbC-0005vi-00"
+LOG: MAIN
+  Completed
+>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
+LOG: queue_run MAIN
+  End queue run: pid=pppp -qqf
+>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
+Exim version x.yz ....
+configuration file is TESTSUITE/test-config
+admin user
+LOG: queue_run MAIN
+  Start queue run: pid=pppp -qqf
+Connecting to 127.0.0.1 [127.0.0.1]:1225 ... connected
+  SMTP<< 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+  SMTP>> EHLO myhost.test.ex
+cmd buf flush ddd bytes
+  SMTP<< 250-myhost.test.ex Hello localhost [127.0.0.1]
+         250-SIZE 52428800
+         250-8BITMIME
+         250-PIPELINING
+         250-STARTTLS
+         250 HELP
+  SMTP>> STARTTLS
+cmd buf flush ddd bytes
+  SMTP<< 220 TLS go ahead
+  SMTP>> EHLO myhost.test.ex
+cmd buf flush ddd bytes
+  SMTP<< 250-myhost.test.ex Hello localhost [127.0.0.1]
+         250-SIZE 52428800
+         250-8BITMIME
+         250-PIPELINING
+         250 HELP
+  SMTP>> MAIL FROM:<CALLER@myhost.test.ex> SIZE=ssss
+  SMTP>> RCPT TO:<usera@test.ex>
+  SMTP>> DATA
+cmd buf flush ddd bytes
+  SMTP<< 250 OK
+  SMTP<< 250 Accepted
+  SMTP<< 354 Enter message, ending with "." on a line by itself
+  SMTP<< 250 OK id=10HmbG-0005vi-00
+LOG: MAIN
+  => usera@test.ex R=cl_override T=send_to_server H=127.0.0.1 [127.0.0.1] X=TLSv1:AES256-SHA:256 CV=no DN="/C=UK/O=The Exim Maintainers/OU=Test Suite/CN=Phil Pennock" C="250 OK id=10HmbG-0005vi-00"
+LOG: MAIN
+  Completed
+Exim version x.yz ....
+configuration file is TESTSUITE/test-config
+trusted user
+admin user
+  SMTP>> MAIL FROM:<CALLER@myhost.test.ex> SIZE=ssss
+  SMTP>> RCPT TO:<userc@test.ex>
+  SMTP>> DATA
+cmd buf flush ddd bytes
+  SMTP<< 250 OK
+  SMTP<< 250 Accepted
+  SMTP<< 354 Enter message, ending with "." on a line by itself
+  SMTP<< 250 OK id=10HmbH-0005vi-00
+  SMTP(close)>>
+LOG: MAIN
+  => userc@test.ex R=cl_override T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLSv1:AES256-SHA:256 CV=no C="250 OK id=10HmbH-0005vi-00"
+LOG: MAIN
+  Completed
+>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
+Exim version x.yz ....
+configuration file is TESTSUITE/test-config
+trusted user
+admin user
+  SMTP>> MAIL FROM:<CALLER@myhost.test.ex> SIZE=ssss
+  SMTP>> RCPT TO:<userb@test.ex>
+  SMTP>> DATA
+cmd buf flush ddd bytes
+  SMTP<< 250 OK
+  SMTP<< 250 Accepted
+  SMTP<< 354 Enter message, ending with "." on a line by itself
+  SMTP<< 250 OK id=10HmbI-0005vi-00
+  SMTP>> QUIT
+cmd buf flush ddd bytes
+  SMTP(close)>>
+>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
+LOG: MAIN
+  => userb@test.ex R=cl_override T=send_to_server H=127.0.0.1 [127.0.0.1]* X=TLSv1:AES256-SHA:256 CV=no C="250 OK id=10HmbI-0005vi-00"
 LOG: MAIN
   Completed
 >>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
diff --git a/test/stderr/2135 b/test/stderr/2135
new file mode 100644 (file)
index 0000000..ac524d2
--- /dev/null
@@ -0,0 +1,74 @@
+Exim version x.yz ....
+configuration file is TESTSUITE/test-config
+admin user
+LOG: smtp_connection MAIN
+  SMTP connection from CALLER
+Transport port=25 replaced by host-specific port=1225
+Connecting to 127.0.0.1 [127.0.0.1]:1225 ... connected
+  SMTP<< 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+  SMTP>> EHLO myhost.test.ex
+cmd buf flush ddd bytes
+  SMTP<< 250-myhost.test.ex Hello localhost [127.0.0.1]
+         250-SIZE 52428800
+         250-8BITMIME
+         250-PIPELINING
+         250-STARTTLS
+         250 HELP
+  SMTP>> STARTTLS
+cmd buf flush ddd bytes
+  SMTP<< 220 TLS go ahead
+  SMTP>> EHLO myhost.test.ex
+cmd buf flush ddd bytes
+  SMTP<< 250-myhost.test.ex Hello localhost [127.0.0.1]
+         250-SIZE 52428800
+         250-8BITMIME
+         250-PIPELINING
+         250 HELP
+using PIPELINING
+not using DSN
+  SMTP>> MAIL FROM:<usera@ok.example>
+  SMTP>> RCPT TO:<userb@test.ex>
+cmd buf flush ddd bytes
+  SMTP<< 250 OK
+  SMTP<< 250 Accepted
+LOG: MAIN
+  <= CALLER@myhost.test.ex U=CALLER P=local-smtp S=sss
+LOG: smtp_connection MAIN
+  SMTP connection from CALLER closed by QUIT
+>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
+Exim version x.yz ....
+configuration file is TESTSUITE/test-config
+trusted user
+admin user
+>>>>>>>>>>>>>>>> Remote deliveries >>>>>>>>>>>>>>>>
+--------> userb@test.ex <--------
+t1 transport entered
+  userb@test.ex
+hostlist:
+  127.0.0.1:1225
+already connected to 127.0.0.1 [127.0.0.1] (on fd 0)
+checking status of 127.0.0.1
+127.0.0.1 [127.0.0.1]:1111 retry-status = usable
+delivering 10HmaX-0005vi-00 to 127.0.0.1 [127.0.0.1] (userb@test.ex)
+Transport port=25 replaced by host-specific port=1225
+continued connection, proxied TLS
+  SMTP>> DATA
+cmd buf flush ddd bytes
+  SMTP<< 354 Enter message, ending with "." on a line by itself
+  SMTP>> writing message and terminating "."
+cannot use sendfile for body: spoolfile not wireformat
+writing data block fd=dddd size=sss timeout=300
+  SMTP<< 250 OK id=10HmaY-0005vi-00
+ok=1 send_quit=1 send_rset=0 continue_more=0 yield=0 first_address is NULL
+  SMTP>> QUIT
+cmd buf flush ddd bytes
+  SMTP(close)>>
+Leaving t1 transport
+>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
+LOG: MAIN
+  => userb@test.ex R=client T=t1 H=127.0.0.1 [127.0.0.1]:1225 X=TLSv1:AES256-SHA:256 CV=no C="250 OK id=10HmaY-0005vi-00"
+LOG: MAIN
+  Completed
+>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
+
+******** SERVER ********
index 4e997473330662d51bf7f0ac2667bd5fd84f6e34..ffdad152f489877d75247e4778375c3fa79eac15 100644 (file)
@@ -362,9 +362,10 @@ Delivery address list:
   userx@myhost.test.ex 
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
 ensuring TESTSUITE/spool/db/retry.lockfile is owned by exim
+failed to open DB file TESTSUITE/spool/db/retry.lockfile: No such file or directory
 no retry data available
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 Considering: userx@myhost.test.ex
@@ -409,8 +410,9 @@ search_tidyup called
 --------> userx@myhost.test.ex <--------
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
 no retry data available
 search_tidyup called
 changed uid/gid: local delivery to userx <userx@myhost.test.ex> transport=t1
@@ -439,6 +441,7 @@ lock file created
 mailbox TESTSUITE/test-mail/userx is locked
 writing to file TESTSUITE/test-mail/userx
 writing data block fd=dddd size=sss timeout=0
+cannot use sendfile for body: spoolfile not wireformat
 writing data block fd=dddd size=sss timeout=0
 writing data block fd=dddd size=sss timeout=0
 appendfile yields 0 with errno=dd more_errno=dd
index 99e927c6bed801ba69ea061bd0a20db9151b7086..78b0e158fcaa5fd4489606202cd54576cc1d1b48 100644 (file)
@@ -440,6 +440,13 @@ host in "10.0.0.1"? no (end of list)
 host in "10.0.0.4"? no (end of list)
 host in "10.0.0.3 : 10.0.0.4"? no (end of list)
 host in auth_advertise_hosts? yes (matched "10.0.0.5")
+Evaluating advertise_condition for mylogin athenticator
+Evaluating advertise_condition for PLAIN athenticator
+Evaluating advertise_condition for EXPLAIN athenticator
+Evaluating advertise_condition for EXPANDED athenticator
+Evaluating advertise_condition for EXPANDFAIL athenticator
+Evaluating advertise_condition for DEFER athenticator
+Evaluating advertise_condition for LOGIN athenticator
 host in chunking_advertise_hosts? no (end of list)
 SMTP>> 250-myhost.test.ex Hello CALLER at testing.testing [10.0.0.5]
 250-SIZE 52428800
index c2a856bb18b6b2134e201bf11b484f16c45da134..d8d2d7a03d0d4f7235db952dfda916990ee7d9b6 100644 (file)
@@ -23,23 +23,28 @@ cmd buf flush ddd bytes
   SMTP<< 250 OK
   SMTP<< 250 Accepted
   SMTP<< 354 Enter message, ending with "." on a line by itself
-PDKIM (checking verify key)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+PDKIM (checking verify key)>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 PDKIM >> Parsing public key record >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+ sel_bad._domainkey.test.ex.
  Raw record: v=DKIM1\;{SP}p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDXRFf+VhT+lCgFhhSkinZKcFNeRzjYdW8vT29Rbb3NadvTFwAd+cVLPFwZL8H5tUD/7JbUPqNTCPxmpgIL+V5T4tEZMorHatvvUM2qfcpQ45IfsZ+YdhbIiAslHCpy4xNxIR3zylgqRUF4+Dtsaqy3a5LhwMiKCLrnzhXk1F1hxwIDAQAB
  v=DKIM1\
  p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDXRFf+VhT+lCgFhhSkinZKcFNeRzjYdW8vT29Rbb3NadvTFwAd+cVLPFwZL8H5tUD/7JbUPqNTCPxmpgIL+V5T4tEZMorHatvvUM2qfcpQ45IfsZ+YdhbIiAslHCpy4xNxIR3zylgqRUF4+Dtsaqy3a5LhwMiKCLrnzhXk1F1hxwIDAQAB
+ Bad v= field
  Error while parsing public key record
 WARNING: bad dkim key in dns
-PDKIM (finished checking verify key)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
+PDKIM (finished checking verify key)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
 content{CR}{LF}
 PDKIM [test.ex] Body bytes hashed: 9
-PDKIM [test.ex] Body hash computed: fc06f48221d98ad6106c3845b33a2a41152482ab9e697f736ad26db4853fa657
-PDKIM >> Header data for hash, canonicalized, in sequence >>>>>>>>>>>>>>
-sender:CALLER_NAME{SP}<CALLER@myhost.test.ex>{CR}{LF}
-message-id:<E10HmbD-0005vi-00@myhost.test.ex>{CR}{LF}
+PDKIM [test.ex] Body sha256 computed: fc06f48221d98ad6106c3845b33a2a41152482ab9e697f736ad26db4853fa657
+PDKIM >> Headers to be signed:                            >>>>>>>>>>>>
+ From
+PDKIM >> Header data for hash, canonicalized, in sequence >>>>>>>>>>>>
 from:nobody@example.com{CR}{LF}
+PDKIM >> Signed DKIM-Signature header, pre-canonicalized >>>>>>>>>>>>>
+DKIM-Signature:{SP}v=1;{SP}a=rsa-sha256;{SP}q=dns/txt;{SP}c=relaxed/relaxed;{SP}d=test.ex;{CR}{LF}{TB}s=sel_bad;{SP}h=From;{SP}bh=/Ab0giHZitYQbDhFszoqQRUkgqueaX9zatJttIU/plc=;{SP}b=;
 PDKIM >> Signed DKIM-Signature header, canonicalized >>>>>>>>>>>>>>>>>
-dkim-signature:v=1;{SP}a=rsa-sha256;{SP}q=dns/txt;{SP}c=relaxed/relaxed;{SP}d=test.ex;{SP}s=sel_bad;{SP}h=Date:Sender:Message-Id:From:Reply-To:Subject:To:Cc:MIME-Version:{SP}Content-Type:Content-Transfer-Encoding:Content-ID:Content-Description:{SP}Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:{SP}In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe:{SP}List-Post:List-Owner:List-Archive;{SP}bh=/Ab0giHZitYQbDhFszoqQRUkgqueaX9zatJttIU/plc=;{SP}b=;
+dkim-signature:v=1;{SP}a=rsa-sha256;{SP}q=dns/txt;{SP}c=relaxed/relaxed;{SP}d=test.ex;{SP}s=sel_bad;{SP}h=From;{SP}bh=/Ab0giHZitYQbDhFszoqQRUkgqueaX9zatJttIU/plc=;{SP}b=;
+PDKIM [test.ex] Header sha256 computed: 241e16230df5723d899cfae9474c6b376a2ab1f81d1094e358f50ffd0e0067b3
   SMTP<< 250 OK id=10HmbE-0005vi-00
   SMTP>> QUIT
 cmd buf flush ddd bytes
index ad5c9b33154c0e2f906fa4108845635ff70d736a..08b4c9784b47482fbf2915b98732fe339531914b 100644 (file)
@@ -78,9 +78,10 @@ Delivery address list:
   userx@test.ex 
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
 ensuring TESTSUITE/spool/db/retry.lockfile is owned by exim
+failed to open DB file TESTSUITE/spool/db/retry.lockfile: No such file or directory
 no retry data available
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 Considering: userx@test.ex
@@ -116,8 +117,9 @@ routed by r1 router
   transport: <none>
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
 no retry data available
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 Considering: TESTSUITE/test-mail
@@ -135,8 +137,9 @@ search_tidyup called
 --------> TESTSUITE/test-mail <--------
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
 no retry data available
 search_tidyup called
 changed uid/gid: local delivery to TESTSUITE/test-mail <TESTSUITE/test-mail> transport=t1
@@ -155,6 +158,7 @@ created directory TESTSUITE/test-mail/new
 created directory TESTSUITE/test-mail/cur
 delivering in maildir format in TESTSUITE/test-mail
 writing to tmp/MAILDIR.mail.test.ex
+cannot use sendfile for body: spoolfile not wireformat
 writing data block fd=dddd size=sss timeout=0
 renaming temporary file
 renamed tmp/MAILDIR.mail.test.ex as new/MAILDIR.mail.test.ex
index 8b28b70556f88cfa097c3f64d47e757ee0446e7f..7e6ea98b27094c34689256895f0eb5ca7c0398d3 100644 (file)
@@ -74,9 +74,10 @@ Delivery address list:
   nofile@test.ex 
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
 ensuring TESTSUITE/spool/db/retry.lockfile is owned by exim
+failed to open DB file TESTSUITE/spool/db/retry.lockfile: No such file or directory
 no retry data available
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 Considering: nofile@test.ex
@@ -111,8 +112,9 @@ search_tidyup called
 --------> nofile@test.ex <--------
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
 no retry data available
 search_tidyup called
 changed uid/gid: local delivery to nofile <nofile@test.ex> transport=t1
@@ -149,6 +151,7 @@ delivering in maildir format in TESTSUITE/test-mail/nofile
 writing to tmp/MAILDIR.myhost.test.ex
 Exim quota = 500 old size = sssss this message = sss (included)
   file count quota = 0 count = 0
+cannot use sendfile for body: spoolfile not wireformat
 writing data block fd=dddd size=sss timeout=0
 added 'ddd 1' to maildirsize file
 renaming temporary file
@@ -262,8 +265,9 @@ Delivery address list:
   userx@test.ex 
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
 no retry data available
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 Considering: userx@test.ex
@@ -298,8 +302,9 @@ search_tidyup called
 --------> userx@test.ex <--------
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
 no retry data available
 search_tidyup called
 changed uid/gid: local delivery to userx <userx@test.ex> transport=t1
@@ -338,6 +343,7 @@ delivering in maildir format in TESTSUITE/test-mail/userx
 writing to tmp/MAILDIR.myhost.test.ex
 Exim quota = 500 old size = sssss this message = sss (included)
   file count quota = 0 count = 0
+cannot use sendfile for body: spoolfile not wireformat
 writing data block fd=dddd size=sss timeout=0
 added 'ddd 1' to maildirsize file
 renaming temporary file
@@ -451,8 +457,9 @@ Delivery address list:
   userx@test.ex 
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
 no retry data available
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 Considering: userx@test.ex
@@ -487,8 +494,9 @@ search_tidyup called
 --------> userx@test.ex <--------
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
 no retry data available
 search_tidyup called
 changed uid/gid: local delivery to userx <userx@test.ex> transport=t1
@@ -545,8 +553,8 @@ Deferred addresses:
  userx@test.ex
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x2
+returned from EXIM_DBOPEN: 0xAAAAAAAA
 opened hints database TESTSUITE/spool/db/retry: flags=O_RDWR
 address match test: subject=userx@test.ex pattern=*
 test.ex in "*"? yes (matched "*")
@@ -558,6 +566,7 @@ Writing retry data for T:userx@test.ex
   first failed=dddd last try=dddd next try=+86400 expired=0
   errno=-22 more_errno=dd mailbox is full (MTA-imposed quota exceeded while writing to tmp/MAILDIR.myhost.test.ex)
 dbfn_write: key=T:userx@test.ex
+EXIM_DBCLOSE(0xAAAAAAAA)
 closed hints database and lockfile
 end of retry processing
 delivery deferred: update_spool=1 header_rewritten=0
@@ -649,8 +658,8 @@ Delivery address list:
   userx@test.ex 
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: 0xAAAAAAAA
 opened hints database TESTSUITE/spool/db/retry: flags=O_RDONLY
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 Considering: userx@test.ex
@@ -661,6 +670,7 @@ dbfn_read: key=R:userx@test.ex:<CALLER@test.ex>
 no domain retry record
 no address retry record
 userx@test.ex: queued for routing
+EXIM_DBCLOSE(0xAAAAAAAA)
 closed hints database and lockfile
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 routing userx@test.ex
@@ -689,12 +699,13 @@ search_tidyup called
 --------> userx@test.ex <--------
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: 0xAAAAAAAA
 opened hints database TESTSUITE/spool/db/retry: flags=O_RDONLY
 dbfn_read: key=T:userx@test.ex
 retry record exists: age=ttt (max 1w)
   time to retry = tttt expired = 0
+EXIM_DBCLOSE(0xAAAAAAAA)
 closed hints database and lockfile
 search_tidyup called
 changed uid/gid: local delivery to userx <userx@test.ex> transport=t1
@@ -738,8 +749,8 @@ Deferred addresses:
  userx@test.ex
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x2
+returned from EXIM_DBOPEN: 0xAAAAAAAA
 opened hints database TESTSUITE/spool/db/retry: flags=O_RDWR
 address match test: subject=userx@test.ex pattern=*
 test.ex in "*"? yes (matched "*")
@@ -751,6 +762,7 @@ Writing retry data for T:userx@test.ex
   first failed=dddd last try=dddd next try=+86400 expired=0
   errno=-22 more_errno=dd mailbox is full (MTA-imposed quota exceeded while writing to tmp/MAILDIR.myhost.test.ex)
 dbfn_write: key=T:userx@test.ex
+EXIM_DBCLOSE(0xAAAAAAAA)
 closed hints database and lockfile
 end of retry processing
 delivery deferred: update_spool=1 header_rewritten=0
index dce0d0050390785584e8738b3afd8f95ca04a782..e494f83b5819f1934d59c297129258dc6a4f11ba 100644 (file)
@@ -74,9 +74,10 @@ Delivery address list:
   userx@test.ex 
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
 ensuring TESTSUITE/spool/db/retry.lockfile is owned by exim
+failed to open DB file TESTSUITE/spool/db/retry.lockfile: No such file or directory
 no retry data available
 >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
 Considering: userx@test.ex
@@ -111,8 +112,9 @@ search_tidyup called
 --------> userx@test.ex <--------
 locking TESTSUITE/spool/db/retry.lockfile
 locked  TESTSUITE/spool/db/retry.lockfile
-EXIM_DBOPEN(TESTSUITE/spool/db/retry)
-returned from EXIM_DBOPEN
+EXIM_DBOPEN: file <TESTSUITE/spool/db/retry> dir <TESTSUITE/spool/db> flags 0x0
+returned from EXIM_DBOPEN: (nil)
+failed to open DB file TESTSUITE/spool/db/retry: No such file or directory
 no retry data available
 search_tidyup called
 changed uid/gid: local delivery to userx <userx@test.ex> transport=t1
@@ -147,6 +149,7 @@ maildir_compute_size (timestamp_only): ddddddd
 returning maildir size=sss filecount=0
 delivering in maildir format in TESTSUITE/test-mail/userx
 writing to tmp/MAILDIR.myhost.test.ex
+cannot use sendfile for body: spoolfile not wireformat
 writing data block fd=dddd size=sss timeout=0
 added 'ddd 1' to maildirsize file
 renaming temporary file
index fd4ae87ec6dd731812cce3afe6371abecea4b5f6..b3bf8f7852be55a9ae217754837999793e29cb6c 100644 (file)
@@ -25,6 +25,7 @@ delivering in maildir format in TESTSUITE/test-mail/userx
 writing to tmp/MAILDIR.myhost.test.ex
 Exim quota = 1048576 old size = sssss this message = sss (included)
   file count quota = 0 count = -1
+cannot use sendfile for body: spoolfile not wireformat
 writing data block fd=dddd size=sss timeout=0
 renaming temporary file
 renamed tmp/MAILDIR.myhost.test.ex as new/MAILDIR.myhost.test.ex
@@ -64,6 +65,7 @@ delivering in maildir format in TESTSUITE/test-mail/userx
 writing to tmp/MAILDIR.myhost.test.ex
 Exim quota = 1048576 old size = sssss this message = sss (included)
   file count quota = 20 count = 4
+cannot use sendfile for body: spoolfile not wireformat
 writing data block fd=dddd size=sss timeout=0
 renaming temporary file
 renamed tmp/MAILDIR.myhost.test.ex as new/MAILDIR.myhost.test.ex
index 6a37deb6ed3f256ca9164e0e8cb1a9a66dd3e563..b4db690abb83cf8f0037e3a50219ef1b85ea1418 100644 (file)
@@ -119,7 +119,7 @@ cmd buf flush ddd bytes
 using PIPELINING
 not using DSN
 127.0.0.1 in hosts_require_auth? no (option unset)
-  SMTP>> MAIL FROM:<CALLER@myhost.test.ex> SIZE=ssss
+  SMTP>> MAIL FROM:<CALLER@myhost.test.ex>
   SMTP>> RCPT TO:<userx@domain.com>
 cmd buf flush ddd bytes
   SMTP<< 250 OK
@@ -345,7 +345,7 @@ cmd buf flush ddd bytes
 using PIPELINING
 not using DSN
 127.0.0.1 in hosts_require_auth? no (option unset)
-  SMTP>> MAIL FROM:<CALLER@myhost.test.ex> SIZE=ssss
+  SMTP>> MAIL FROM:<CALLER@myhost.test.ex>
   SMTP>> RCPT TO:<usery@domain.com>
 cmd buf flush ddd bytes
   SMTP<< 250 OK
@@ -571,7 +571,7 @@ cmd buf flush ddd bytes
 using PIPELINING
 not using DSN
 127.0.0.1 in hosts_require_auth? no (option unset)
-  SMTP>> MAIL FROM:<CALLER@myhost.test.ex> SIZE=ssss
+  SMTP>> MAIL FROM:<CALLER@myhost.test.ex>
   SMTP>> RCPT TO:<usery@domain.com>
 cmd buf flush ddd bytes
   SMTP<< 250 OK
index eaa40bce89b2facb1213230db573b4546eb5ca68..b3444004661284ff049c965bc1cbe3484a6da979 100644 (file)
@@ -118,7 +118,7 @@ cmd buf flush ddd bytes
 using PIPELINING
 not using DSN
 127.0.0.1 in hosts_require_auth? no (option unset)
-  SMTP>> MAIL FROM:<CALLER@myhost.test.ex> SIZE=ssss
+  SMTP>> MAIL FROM:<CALLER@myhost.test.ex>
   SMTP>> RCPT TO:<userx@domain.com>
 cmd buf flush ddd bytes
   SMTP<< 250 OK
@@ -344,7 +344,7 @@ cmd buf flush ddd bytes
 using PIPELINING
 not using DSN
 127.0.0.1 in hosts_require_auth? no (option unset)
-  SMTP>> MAIL FROM:<CALLER@myhost.test.ex> SIZE=ssss
+  SMTP>> MAIL FROM:<CALLER@myhost.test.ex>
   SMTP>> RCPT TO:<usery@domain.com>
 cmd buf flush ddd bytes
   SMTP<< 250 OK
@@ -570,7 +570,7 @@ cmd buf flush ddd bytes
 using PIPELINING
 not using DSN
 127.0.0.1 in hosts_require_auth? no (option unset)
-  SMTP>> MAIL FROM:<CALLER@myhost.test.ex> SIZE=ssss
+  SMTP>> MAIL FROM:<CALLER@myhost.test.ex>
   SMTP>> RCPT TO:<usery@domain.com>
 cmd buf flush ddd bytes
   SMTP<< 250 OK
index e4cf15c5142e998e74da3afdded28ad1f284a23a..51962ce6613068926dd6bbe4050d9ddb3508734c 100644 (file)
 >>> Attempting full verification using callout
 >>> callout cache: no domain record found for dane256ee.test.ex
 >>> callout cache: no address record found for rcptuser@dane256ee.test.ex
-MUNGED: ::1 will be omitted in what follows
->>> get[host|ipnode]byname[2] looked up these IP addresses:
->>>   name=thishost.test.ex address=127.0.0.1
->>> ip4.ip4.ip4.ip4 in hosts_require_dane? yes (end of list)
+>>> ip4.ip4.ip4.ip4 in hosts_require_dane? yes (matched "ip4.ip4.ip4.ip4")
 >>> interface=NULL port=1225
 >>> Connecting to dane256ee.test.ex [ip4.ip4.ip4.ip4]:1225 ... connected
 >>>   SMTP<< 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
@@ -53,9 +50,9 @@ MUNGED: ::1 will be omitted in what follows
 >>>          250 HELP
 >>> ip4.ip4.ip4.ip4 in hosts_avoid_pipelining? no (option unset)
 >>> ip4.ip4.ip4.ip4 in hosts_require_auth? no (option unset)
->>>   SMTP>> MAIL FROM:<> SIZE=ssss
+>>>   SMTP>> MAIL FROM:<>
 >>>   SMTP>> RCPT TO:<rcptuser@dane256ee.test.ex>
->>> cmd buf flush 62 bytes
+>>> cmd buf flush 52 bytes
 >>>   SMTP<< 250 OK
 >>>   SMTP<< 250 Accepted
 >>>   SMTP>> QUIT
@@ -68,13 +65,16 @@ MUNGED: ::1 will be omitted in what follows
 >>> ----------- end verify ------------
 >>> accept: condition test succeeded in inline ACL
 >>> end of inline ACL: ACCEPT
-LOG: unexpected disconnection while reading SMTP command from [127.0.0.1]
+LOG: unexpected disconnection while reading SMTP command from [127.0.0.1] D=qqs
 ### TLSA (2 0 1)
 ### A server with a nonverifying cert and no TLSA
 ### A server with a verifying cert and no TLSA
 ### A server with two MXs for which both TLSA lookups return defer
-### A server lacking a TLSA, required
-### A server lacking a TLSA, requested only
+### A server lacking a TLSA, dane required (should fail)
+### A server lacking a TLSA, dane requested only (should fail, as the NXDOMAIN is not DNSSEC)
+### A server where the A is dnssec and the TLSA _fails_
+### A server securely saying "no TLSA records here", dane required (should fail)
+### A server securely saying "no TLSA records here", dane requested only (should transmit)
 
 ******** SERVER ********
 ### TLSA (3 1 1)
@@ -84,5 +84,8 @@ LOG: unexpected disconnection while reading SMTP command from [127.0.0.1]
 ### A server with a nonverifying cert and no TLSA
 ### A server with a verifying cert and no TLSA
 ### A server with two MXs for which both TLSA lookups return defer
-### A server lacking a TLSA, required
-### A server lacking a TLSA, requested only
+### A server lacking a TLSA, dane required (should fail)
+### A server lacking a TLSA, dane requested only (should fail, as the NXDOMAIN is not DNSSEC)
+### A server where the A is dnssec and the TLSA _fails_
+### A server securely saying "no TLSA records here", dane required (should fail)
+### A server securely saying "no TLSA records here", dane requested only (should transmit)
index fa445b01cda1b001168e7e05471f86fa9565db85..5593f06cc20cf39818b6c70f082bb02b1cf4a1db 100644 (file)
@@ -393,6 +393,8 @@ newline     tab\134backslash ~tilde\177DEL\200\201.
 > isip:   y  1.2.3.4
 > isip4:  y  1.2.3.4
 > isip6:  n  1.2.3.4
+> isip:   n  ::1.2.3.256
+> isip4:  n  1.2.3.256
 > isip:   n  1:2:3:4
 > isip4:  n  1:2:3:4
 > isip6:  n  1:2:3:4
@@ -402,6 +404,7 @@ newline     tab\134backslash ~tilde\177DEL\200\201.
 > isip:   y  fe80::a00:20ff:fe86:a061
 > isip4:  n  fe80::a00:20ff:fe86:a061
 > isip6:  y  fe80::a00:20ff:fe86:a061
+> isip:   y  fe80::1.2.3.4
 > isip:   n  rhubarb
 > isip4:  n  rhubarb
 > isip6:  n  rhubarb
index 6855c1d3189209b077706b188b9788db5d4de233..60e2c62d2a9f1a232c99adf53d3a19c92bde3474 100644 (file)
@@ -144,6 +144,7 @@ End of script
 EXIMUSER EXIM_UID EXIM_GID
 <notsubmit@y>
 ddddddddd 0
+-received_time_usec .uuuuuu
 -helo_name rhu.barb
 -host_address 127.0.0.1.9999
 -interface_address 127.0.0.1.1225
@@ -164,6 +165,7 @@ dddP Received: from [127.0.0.1] (helo=rhu.barb)
 EXIMUSER EXIM_UID EXIM_GID
 <a@y>
 ddddddddd 0
+-received_time_usec .uuuuuu
 -helo_name rhu.barb
 -host_address 127.0.0.1.9999
 -interface_address 127.0.0.1.1225
@@ -187,6 +189,7 @@ dddF From: a@y
 EXIMUSER EXIM_UID EXIM_GID
 <>
 ddddddddd 0
+-received_time_usec .uuuuuu
 -helo_name rhu.barb
 -host_address 127.0.0.1.9999
 -interface_address 127.0.0.1.1225
@@ -208,6 +211,7 @@ dddP Received: from [127.0.0.1] (helo=rhu.barb)
 EXIMUSER EXIM_UID EXIM_GID
 <notsubmit@y>
 ddddddddd 0
+-received_time_usec .uuuuuu
 -helo_name rhu.barb
 -host_address 127.0.0.1.9999
 -interface_address 127.0.0.1.1225
@@ -229,6 +233,7 @@ dddS Sender: sender@some.where
 EXIMUSER EXIM_UID EXIM_GID
 <a@y>
 ddddddddd 0
+-received_time_usec .uuuuuu
 -helo_name rhu.barb
 -host_address 127.0.0.1.9999
 -interface_address 127.0.0.1.1225
@@ -253,6 +258,7 @@ dddF From: a@y
 EXIMUSER EXIM_UID EXIM_GID
 <a@y>
 ddddddddd 0
+-received_time_usec .uuuuuu
 -helo_name rhu.barb
 -host_address 127.0.0.1.9999
 -interface_address 127.0.0.1.1225
@@ -277,6 +283,7 @@ dddF From: a@y
 EXIMUSER EXIM_UID EXIM_GID
 <a@y>
 ddddddddd 0
+-received_time_usec .uuuuuu
 -helo_name rhu.barb
 -host_address 127.0.0.1.9999
 -interface_address 127.0.0.1.1225
index 2d484bda5990ac7d8caa6db5dfcf7a9d866777a9..708632ded1b54be58affddfc078e1f33efbe817b 100644 (file)
@@ -43,3 +43,13 @@ EHLO the.local.host.name
 550 You are banned
 HELO the.local.host.name
 End of script
+Listening on port 1224 ... 
+Connection request from [127.0.0.1]
+554 no smtp service here
+QUIT
+220 bye
+Expected EOF read from client
+Listening on port 1224 ... 
+Connection request from [ip4.ip4.ip4.ip4]
+*sleep 2
+End of script
index ea8520ef16e283b2baaedb17bd7cf90f2d7b4412..9ee7e9f546d493416db99bac97438493796bbfb5 100644 (file)
 250 Accepted\r
 221 myhost.test.ex closing connection\r
 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
+250-myhost.test.ex Hello root at me [V4NET.0.0.3]\r
+250-SIZE 52428800\r
+250-8BITMIME\r
+250-PIPELINING\r
+250 HELP\r
+250 OK\r
+550 relay not permitted\r
+221 myhost.test.ex closing connection\r
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
+250-myhost.test.ex Hello root at me [V4NET.0.0.3]\r
+250-SIZE 52428800\r
+250-8BITMIME\r
+250-PIPELINING\r
+250 HELP\r
+250 OK\r
+550 relay not permitted\r
+221 myhost.test.ex closing connection\r
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
+250-myhost.test.ex Hello root at me [V4NET.0.0.7]\r
+250-SIZE 52428800\r
+250-8BITMIME\r
+250-PIPELINING\r
+250 HELP\r
+250 OK\r
+550 relay not permitted\r
+221 myhost.test.ex closing connection\r
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
 250 OK\r
 550-Callout verification failed:\r
 550 550 Recipient not liked\r
@@ -248,10 +275,10 @@ Listening on port 1224 ...
 Connection request from [127.0.0.1]
 220 Server ready
 EHLO myhost.test.ex
-250- wotcher
+250- wotcher sverifier
 250-SIZE
 250 OK
-MAIL FROM:<> SIZE=ssss
+MAIL FROM:<>
 250 OK
 RCPT TO:<ok@localhost1>
 250 OK
@@ -261,6 +288,54 @@ End of script
 Listening on port 1224 ... 
 Connection request from [127.0.0.1]
 220 Server ready
+EHLO myhost.test.ex
+250- wotcher rverifier
+250-SIZE
+250 OK
+MAIL FROM:<> SIZE=ssss
+250 OK
+RCPT TO:<z@remote.domain>
+250 OK
+QUIT
+250 OK
+End of script
+Listening on port 1224 ... 
+Connection request from [127.0.0.1]
+220 Server ready
+EHLO myhost.test.ex
+250- wotcher rverifier
+250-SIZE
+250 OK
+MAIL FROM:<>
+250 OK
+RCPT TO:<z@remote.domain>
+250 OK
+QUIT
+250 OK
+End of script
+Listening on port 1224 ... 
+Connection request from [127.0.0.1]
+220 Server ready
+EHLO myhost.test.ex
+250- wotcher rverifier
+250-SIZE
+250 OK
+MAIL FROM:<ok@localhost1>
+250 OK
+RCPT TO:<myhost.test.ex-dddddddd-testing@remote.domain>
+550 RANDOM NOT OK
+RSET
+250 OK
+MAIL FROM:<ok@localhost1> SIZE=ssss
+250 OK
+RCPT TO:<z@remote.domain>
+250 OK
+QUIT
+250 OK
+End of script
+Listening on port 1224 ... 
+Connection request from [127.0.0.1]
+220 Server ready
 LHLO myhost.test.ex
 250 OK
 MAIL FROM:<>
index 36332a61b6f811d33557fa334f6bd41b456d07eb..5d0f2df346be976354118fed6e501617eb02e497 100644 (file)
@@ -7,6 +7,7 @@
 CALLER UID GID
 <CALLER@myhost.test.ex>
 ddddddddd 0
+-received_time_usec .uuuuuu
 -ident CALLER
 -received_protocol local
 -body_linecount 1
index 1d364b4e9b64bc114c44c1ae5bb7a776e21c354e..c19185e84b59cb551e25de42e0c926ed6f8cac58 100644 (file)
@@ -2,6 +2,7 @@
 CALLER UID GID
 <CALLER-rewritten@test.ex>
 ddddddddd 0
+-received_time_usec .uuuuuu
 -ident CALLER
 -received_protocol local
 -body_linecount 0
@@ -32,6 +33,7 @@ ddd* X-rewrote-sender: CALLER@test.ex
 CALLER UID GID
 <CALLER-rewritten@test.ex>
 ddddddddd 0
+-received_time_usec .uuuuuu
 -ident CALLER
 -received_protocol local
 -body_linecount 0
@@ -62,6 +64,7 @@ ddd* X-rewrote-sender: CALLER@test.ex
 CALLER UID GID
 <CALLER-rewritten@test.ex>
 ddddddddd 0
+-received_time_usec .uuuuuu
 -ident CALLER
 -received_protocol local
 -body_linecount 0
index 3e044dd6f3123279ba067e33de9debee376c5d35..69b80a19283f23d4c6221266f89a621218e5ac0e 100644 (file)
@@ -2,6 +2,7 @@
 CALLER UID GID
 <CALLER@myhost.test.ex>
 ddddddddd 0
+-received_time_usec .uuuuuu
 -ident CALLER
 -received_protocol local
 -body_linecount 0
@@ -38,6 +39,7 @@ dddS Resent-Sender: CALLER_NAME <CALLER@myhost.test.ex>
 CALLER UID GID
 <CALLER@myhost.test.ex>
 ddddddddd 0
+-received_time_usec .uuuuuu
 -ident CALLER
 -received_protocol local
 -body_linecount 0
@@ -67,6 +69,7 @@ dddS Resent-Sender: CALLER_NAME <CALLER@myhost.test.ex>
 CALLER UID GID
 <CALLER@myhost.test.ex>
 ddddddddd 0
+-received_time_usec .uuuuuu
 -ident CALLER
 -received_protocol local
 -body_linecount 0
index 45190072f2fb0d1e7b1ae2a37fede3d495d18310..960e8e0b7183ee6ce2c9f53e5546f6272d799ee8 100644 (file)
@@ -2,6 +2,7 @@
 CALLER UID GID
 <CALLER@myhost.test.ex>
 ddddddddd 0
+-received_time_usec .uuuuuu
 -ident CALLER
 -received_protocol local
 -body_linecount 0
@@ -30,6 +31,7 @@ dddF From: CALLER_NAME <CALLER@myhost.test.ex>
 CALLER UID GID
 <CALLER@myhost.test.ex>
 ddddddddd 0
+-received_time_usec .uuuuuu
 -ident CALLER
 -received_protocol local
 -body_linecount 0
index 52bd7ee37b7fbd2bd60d8bfe2720bbeb7f5d4b9a..fbbbc69c516bca0ee21ded96aee4850984d77966 100644 (file)
@@ -6,6 +6,7 @@
 CALLER UID GID
 <CALLER@test.ex>
 ddddddddd 0
+-received_time_usec .uuuuuu
 -ident CALLER
 -received_protocol local
 -body_linecount 0
index 8c2b9685c427c342b3df05b120ef9cc3f6a5bde4..a0af2cb92d587c745b1513e4a322bf43b8343d51 100644 (file)
@@ -78,7 +78,7 @@
 221 myhost.test.ex closing connection\r
 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
 250 OK\r
-451 Could not complete sender verify callout\r
+250 Accepted\r
 221 myhost.test.ex closing connection\r
 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
 250 OK\r
@@ -86,7 +86,7 @@
 221 myhost.test.ex closing connection\r
 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
 250 OK\r
-451 Could not complete sender verify callout\r
+250 Accepted\r
 221 myhost.test.ex closing connection\r
 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
 250 OK\r
index 59742e66692ad878471ef73f7f054c4e5794f78a..de1e5e3056b531a65d5c30a77211bebabc739167 100644 (file)
@@ -2,6 +2,7 @@
 CALLER UID GID
 <CALLER@myhost.test.ex>
 ddddddddd 0
+-received_time_usec .uuuuuu
 -ident CALLER
 -received_protocol local
 -body_linecount 0
index e64fdef167c632a45d725025c691f5b63b74acd5..c60701cbc62d78c0d7b2449b2376c1bc9ed89f0c 100644 (file)
@@ -2,6 +2,7 @@
 CALLER UID GID
 <CALLER@myhost.test.ex>
 ddddddddd 0
+-received_time_usec .uuuuuu
 -ident CALLER
 -received_protocol local
 -body_linecount 0
index 7bfea116f33cf4d4766adf89ac1bf6d6d21529cb..d26d23523fc103fe344b201b83aec30c6e868804 100644 (file)
@@ -2,6 +2,7 @@
 CALLER UID GID
 <CALLER@myhost.test.ex>
 ddddddddd 0
+-received_time_usec .uuuuuu
 -ident CALLER
 -received_protocol local
 -body_linecount 0
index 69b1bfc001239c4cf1748b58d2274655e4f34c9b..bb5977af7ddc7473aa1231f7ec2515971be64593 100644 (file)
@@ -8,6 +8,7 @@
 CALLER UID GID
 <CALLER@myhost.test.ex>
 ddddddddd 0
+-received_time_usec .uuuuuu
 -ident CALLER
 -received_protocol local-smtp
 -aclm 0 22
index ff89ff2f76ca37f74db9c2bd7b85c5e645c4d6cc..d6d3b4b188ed8422b46d4d4263e4f3a4ed746c9a 100644 (file)
@@ -8,6 +8,7 @@
 CALLER UID GID
 <CALLER@myhost.test.ex>
 ddddddddd 0
+-received_time_usec .uuuuuu
 -ident CALLER
 -received_protocol local-smtp
 -body_linecount 0
index f9cb83d19b1edf81523dfda6d2d95f000bc91261..ee77a71e68d738e4062755d6e969c608086eedec 100644 (file)
@@ -12,6 +12,7 @@
 CALLER UID GID
 <CALLER@myhost.test.ex>
 ddddddddd 0
+-received_time_usec .uuuuuu
 -ident CALLER
 -received_protocol local-smtp
 -body_linecount 2
index 83111ea92dce253162246b367ace186850f78a4f..5b8677c653cc928e3e6eb0fe2f8e56a39982569e 100644 (file)
@@ -5,6 +5,7 @@
 CALLER UID GID
 <"spaced user"@myhost.test.ex>
 ddddddddd 0
+-received_time_usec .uuuuuu
 -ident spaced user
 -received_protocol local
 -body_linecount 1
index 8af281557d36908d10d1e680b0aa227e9ec88b95..9b99fcc5486e1ffc2ae209b394f5e5d8e1e24980 100644 (file)
@@ -4,13 +4,13 @@
 1999-03-02 09:44:33 [1235] 10HmaX-0005vi-00 Completed
 
 1999-03-02 09:44:33 [1236] 10HmaY-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
-1999-03-02 09:44:33 [1237] 10HmaY-0005vi-00 => userx <userx@test.ex> R=r1 T=t1
-1999-03-02 09:44:33 [1237] 10HmaY-0005vi-00 => userz <userz@test.ex> R=r1 T=t1
+1999-03-02 09:44:33 [1237] 10HmaY-0005vi-00 => userx <userx@test.ex> R=r1 T=t1 QT=qqs
+1999-03-02 09:44:33 [1237] 10HmaY-0005vi-00 => userz <userz@test.ex> R=r1 T=t1 QT=qqs
 1999-03-02 09:44:33 [1237] 10HmaY-0005vi-00 Completed
 
-1999-03-02 09:44:33 10HmaZ-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
-1999-03-02 09:44:33 10HmaZ-0005vi-00 => userx <userx@test.ex> R=r1 T=t1
-1999-03-02 09:44:33 10HmaZ-0005vi-00 Completed
+2017-07-30 18:51:05.712 10HmaZ-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
+2017-07-30 18:51:05.712 10HmaZ-0005vi-00 => userx <userx@test.ex> R=r1 T=t1 QT=q.qqqs DT=q.qqqs
+2017-07-30 18:51:05.712 10HmaZ-0005vi-00 Completed QT=q.qqqs
 
 exigrep exit code = 0
 
index 40b265041d9cd4bac3d88a8a290159d00de868d6..d3089e7e472b6ca47d4a2514ac6a0d3f454b58b5 100644 (file)
@@ -78,7 +78,7 @@
 221 myhost.test.ex closing connection\r
 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
 250 OK\r
-451 Could not complete sender verify callout\r
+250 Accepted\r
 221 myhost.test.ex closing connection\r
 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
 250 OK\r
@@ -86,7 +86,7 @@
 221 myhost.test.ex closing connection\r
 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
 250 OK\r
-451 Could not complete sender verify callout\r
+250 Accepted\r
 221 myhost.test.ex closing connection\r
 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
 250 OK\r
index 99eb812313d5884441f5b92665b6820e406c4f22..a982ac8b601c33be07e0e1e8026786f4bd887bd6 100644 (file)
@@ -324,14 +324,14 @@ Connecting to 127.0.0.1 port 1225 ... connected
 <<< 250-CHUNKING
 ??? 250 HELP
 <<< 250 HELP
->>> mail from:someone9@some.domain
+>>> MAIL FROM:someone9@some.domain
 ??? 250
 <<< 250 OK
->>> rcpt to:CALLER@test.ex
+>>> RCPT TO:CALLER@test.ex
 ??? 250
 <<< 250 Accepted
->>> bdat 1\r\nTbdat 87 last
->>> To: Susan@random.com
+>>> BDAT 1\r\nTBDAT 87 last
+>>> o: Susan@random.com
 >>> From: Sam@random.com
 >>> Subject: This is a bodyless test message
 >>> 
diff --git a/test/stdout/0906 b/test/stdout/0906
new file mode 100644 (file)
index 0000000..0eb13cc
--- /dev/null
@@ -0,0 +1,123 @@
+Connecting to 127.0.0.1 port 1224 ... connected
+??? 220
+<<< 220 testhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+>>> EHLO test.com
+??? 250-
+<<< 250-testhost.test.ex Hello test.com [127.0.0.1]
+??? 250-
+<<< 250-SIZE 52428800
+??? 250-
+<<< 250-8BITMIME
+??? 250-
+<<< 250-PIPELINING
+??? 250-
+<<< 250-CHUNKING
+??? 250
+<<< 250 HELP
+>>> MAIL FROM:<sender@dom>
+??? 250
+<<< 250 OK
+>>> RCPT TO:<a@test.ex>
+??? 250
+<<< 250 Accepted
+>>> BDAT 8408 LAST
+>>> Subject: foo
+>>> 
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
+>>> .dot
+>>> tail
+??? 250-
+<<< 250- 8408 byte chunk, total 8408
+??? 250
+<<< 250 OK id=10HmaY-0005vi-00
+>>> QUIT
+End of script
index 7bf70310a62bf837c451834fafd855dcf03941bc..f08abd10b1b6db2ae664056f176f22cc7037cd34 100644 (file)
@@ -89,13 +89,7 @@ Succeeded in starting TLS
 <<< 250-CHUNKING
 ??? 250 HELP
 <<< 250 HELP
->>> MAIL FROM:<someone@some.domain>
->>> RCPT TO:<CALLER@test.ex>
->>> BDAT 88 LAST
->>> To: Susan@random.com
->>> From: Sam@random.com
->>> Subject: This is a bodyless test message
->>> 
+>>> MAIL FROM:<someone@some.domain>\r\nRCPT TO:<CALLER@test.ex>\r\nBDAT 88 LAST\r\nTo: Susan@random.com\r\nFrom: Sam@random.com\r\nSubject: This is a bodyless test message\r\n
 ??? 250
 <<< 250 OK
 ??? 250
index 9d386bdf7caf2d99ece5007c1c75708fb601b297..e09556e696e734448f5f90741232adceb9d52046 100644 (file)
@@ -91,13 +91,7 @@ Succeeded in starting TLS
 <<< 250-CHUNKING
 ??? 250 HELP
 <<< 250 HELP
->>> MAIL FROM:<someone@some.domain>
->>> RCPT TO:<CALLER@test.ex>
->>> BDAT 88 LAST
->>> To: Susan@random.com
->>> From: Sam@random.com
->>> Subject: This is a bodyless test message
->>> 
+>>> MAIL FROM:<someone@some.domain>\r\nRCPT TO:<CALLER@test.ex>\r\nBDAT 88 LAST\r\nTo: Susan@random.com\r\nFrom: Sam@random.com\r\nSubject: This is a bodyless test message\r\n
 ??? 250
 <<< 250 OK
 ??? 250
index f675c6c74d45883a1dd1084695c9a9153448daf4..8e20252e24bfbb4d9cfb4a28db466c2429ffc199 100644 (file)
@@ -155,6 +155,7 @@ End of script
 EXIMUSER EXIM_UID EXIM_GID
 <username@myhost.test.ex>
 ddddddddd 0
+-received_time_usec .uuuuuu
 -helo_name rhu.barb
 -host_address 127.0.0.1.9999
 -host_auth au1
@@ -181,6 +182,7 @@ dddS Sender: username@myhost.test.ex
 EXIMUSER EXIM_UID EXIM_GID
 <>
 ddddddddd 0
+-received_time_usec .uuuuuu
 -helo_name rhu.barb
 -host_address 127.0.0.1.9999
 -host_auth au1
@@ -205,6 +207,7 @@ dddF From: username@myhost.test.ex
 EXIMUSER EXIM_UID EXIM_GID
 <>
 ddddddddd 0
+-received_time_usec .uuuuuu
 -helo_name rhu.barb
 -host_address 127.0.0.1.9999
 -host_auth au1
@@ -229,6 +232,7 @@ dddF From: username@another.domain
 EXIMUSER EXIM_UID EXIM_GID
 <>
 ddddddddd 0
+-received_time_usec .uuuuuu
 -helo_name rhu.barb
 -host_address 127.0.0.1.9999
 -host_auth au1
@@ -253,6 +257,7 @@ dddF From: username@auth.id.domain
 EXIMUSER EXIM_UID EXIM_GID
 <>
 ddddddddd 0
+-received_time_usec .uuuuuu
 -helo_name rhu.barb
 -host_address 127.0.0.1.9999
 -host_auth au1
diff --git a/test/stdout/4027 b/test/stdout/4027
new file mode 100644 (file)
index 0000000..74837c4
--- /dev/null
@@ -0,0 +1,66 @@
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
+250-myhost.test.ex Hello CALLER at test.ex\r
+250-SIZE 52428800\r
+250-8BITMIME\r
+250-PIPELINING\r
+250 HELP\r
+250 OK\r
+250 Accepted\r
+354 Enter message, ending with "." on a line by itself\r
+250 OK id=10HmaX-0005vi-00\r
+221 myhost.test.ex closing connection\r
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000\r
+250-myhost.test.ex Hello CALLER at test.ex\r
+250-SIZE 52428800\r
+250-8BITMIME\r
+250-PIPELINING\r
+250 HELP\r
+250 OK\r
+250 Accepted\r
+354 Enter message, ending with "." on a line by itself\r
+250 OK id=10HmaY-0005vi-00\r
+221 myhost.test.ex closing connection\r
+
+******** SERVER ********
+Listening on port 1225 ... 
+Connection request from [ip4.ip4.ip4.ip4]
+<<\x05\x01\x00
+>>\x05\x00
+<<\x05\x01\x00\x01\x7f\x00\x00\x01\x04\xc8
+>>\x05\x00\x00\x01\x7f\x00\x00\x01\xbe\xef
+220 Connected OK
+EHLO
+250-server id
+250
+MAIL FROM
+250
+RCPT TO
+250
+DATA
+354 do me
+R
+250 accepted OK
+QUIT
+250 bye
+End of script
+Listening on port 1225 ... 
+Connection request from [ip4.ip4.ip4.ip4]
+<<\x05\x01\x00
+>>\x05\x00
+<<\x05\x01\x00\x01\x7f\x00\x00\x01\x04\xc8
+>>\x05\x00\x00\x01\x7f\x00\x00\x01\xbe\xef
+220 Connected OK
+EHLO
+250-server id
+250
+MAIL FROM
+250
+RCPT TO
+250
+DATA
+354 do me mate
+R
+250 accepted OK
+QUIT
+250 bye
+End of script
diff --git a/test/stdout/4530 b/test/stdout/4530
new file mode 100644 (file)
index 0000000..9d64ae5
--- /dev/null
@@ -0,0 +1,75 @@
+Connecting to 127.0.0.1 port 1224 ... connected
+??? 220
+<<< 220 testhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+>>> EHLO xxx
+??? 250-
+<<< 250-testhost.test.ex Hello xxx [127.0.0.1]
+??? 250-
+<<< 250-SIZE 52428800
+??? 250-
+<<< 250-8BITMIME
+??? 250-
+<<< 250-PIPELINING
+??? 250-
+<<< 250-CHUNKING
+??? 250
+<<< 250 HELP
+>>> MAIL FROM:<CALLER@bloggs.com>
+??? 250
+<<< 250 OK
+>>> RCPT TO:<z@test.ex>
+??? 250
+<<< 250 Accepted
+>>> DATA
+??? 354
+<<< 354 Enter message, ending with "." on a line by itself
+>>> Subject: simple test
+>>> 
+>>> Line 1: This is a simple test.
+>>> Line 2: This is a simple test.
+>>> ..Line 3 has a leading dot
+>>> last line: 4
+>>> .
+??? 250
+<<< 250 OK id=10HmaZ-0005vi-00
+>>> QUIT
+??? 221
+<<< 221 testhost.test.ex closing connection
+End of script
+Connecting to 127.0.0.1 port 1224 ... connected
+??? 220
+<<< 220 testhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+>>> EHLO xxx
+??? 250-
+<<< 250-testhost.test.ex Hello xxx [127.0.0.1]
+??? 250-
+<<< 250-SIZE 52428800
+??? 250-
+<<< 250-8BITMIME
+??? 250-
+<<< 250-PIPELINING
+??? 250-
+<<< 250-CHUNKING
+??? 250
+<<< 250 HELP
+>>> MAIL FROM:<CALLER@bloggs.com>
+??? 250
+<<< 250 OK
+>>> RCPT TO:<y@test.ex>
+??? 250
+<<< 250 Accepted
+>>> BDAT 129 LAST
+>>> Subject: simple test
+>>> 
+>>> Line 1: This is a simple test.
+>>> Line 2: This is a simple test.
+>>> .Line 3 has a leading dot
+>>> last line: 4
+??? 250-
+<<< 250- 129 byte chunk, total 129
+??? 250
+<<< 250 OK id=10HmbA-0005vi-00
+>>> QUIT
+??? 221
+<<< 221 testhost.test.ex closing connection
+End of script
index 1d94564ada0b53a0602faf0fdf5875a6e39aa124..32425d2e223313fc0178b94e0dccc16bf5af8238 100644 (file)
 ### A server with a nonverifying cert and no TLSA
 ### A server with a verifying cert and no TLSA
 ### A server with two MXs for which both TLSA lookups return defer
-### A server lacking a TLSA, required
-### A server lacking a TLSA, requested only
+### A server lacking a TLSA, dane required (should fail)
+### A server lacking a TLSA, dane requested only (should fail, as the NXDOMAIN is not DNSSEC)
+### A server where the A is dnssec and the TLSA _fails_
+### A server securely saying "no TLSA records here", dane required (should fail)
+### A server securely saying "no TLSA records here", dane requested only (should transmit)
 
 ******** SERVER ********
 ### TLSA (3 1 1)
@@ -25,5 +28,8 @@
 ### A server with a nonverifying cert and no TLSA
 ### A server with a verifying cert and no TLSA
 ### A server with two MXs for which both TLSA lookups return defer
-### A server lacking a TLSA, required
-### A server lacking a TLSA, requested only
+### A server lacking a TLSA, dane required (should fail)
+### A server lacking a TLSA, dane requested only (should fail, as the NXDOMAIN is not DNSSEC)
+### A server where the A is dnssec and the TLSA _fails_
+### A server securely saying "no TLSA records here", dane required (should fail)
+### A server securely saying "no TLSA records here", dane requested only (should transmit)
index 0612a20af3ab84a58f13da1fb39bd5f8b9f1015e..2fbd2decd0499ecd0711b1250b1fd40d95f56def 100644 (file)
@@ -45,7 +45,8 @@ subtest 'flavour' => sub {
     is flavour('t/samples/debian.sid/etc'), 'debian' => 'got flavour debian from debian sid w/o VERSION_ID';
     is flavour('t/samples/fedora24/etc'), 'fedora24' => 'got flavour fedora24 from os-release';
     is flavour('t/samples/empty'), undef()           => 'got empty flavour (undef)';
-    is_deeply [flavours()], ['debian8'] => 'got available flavours';
+    # we do not have flavours anymore (2017-03-18)
+    # is_deeply [flavours()], ['debian8'] => 'got available flavours';
 };
 
 done_testing;