summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHeiko Schlittermann (HS12-RIPE) <hs@schlittermann.de>2016-03-02 18:19:53 +0100
committerHeiko Schlittermann (HS12-RIPE) <hs@schlittermann.de>2016-03-02 18:19:53 +0100
commit1285b353732a341aa761d23add643f2cb873a0a5 (patch)
tree0091e6aca125b29a8d3e991ff0e82c54f20520b2
parentdd90c19962a63fe966e17c75b4a36639302d1e67 (diff)
parenta6937ae2f5a39dfd22fde73aa394b3e28d826b4a (diff)
downloadexim4-1285b353732a341aa761d23add643f2cb873a0a5.tar.gz
Merge branch 'exim-4_86_1+fixes' into exim-4_86_2+fixes
Branch exim-4_86_1+fixes will not be maintained anymore!
-rw-r--r--doc/doc-docbook/spec.xfpt21
-rw-r--r--doc/doc-txt/ChangeLog48
-rw-r--r--src/src/daemon.c1
-rw-r--r--src/src/deliver.c24
-rw-r--r--src/src/dns.c3
-rw-r--r--src/src/functions.h2
-rw-r--r--src/src/lookupapi.h7
-rw-r--r--src/src/lookups/README7
-rw-r--r--src/src/lookups/cdb.c2
-rw-r--r--src/src/lookups/dbmdb.c6
-rw-r--r--src/src/lookups/dnsdb.c5
-rw-r--r--src/src/lookups/dsearch.c2
-rw-r--r--src/src/lookups/ibase.c2
-rw-r--r--src/src/lookups/ldap.c8
-rw-r--r--src/src/lookups/lf_functions.h4
-rw-r--r--src/src/lookups/lf_sqlperform.c6
-rw-r--r--src/src/lookups/lsearch.c8
-rw-r--r--src/src/lookups/mysql.c10
-rw-r--r--src/src/lookups/nis.c4
-rw-r--r--src/src/lookups/nisplus.c2
-rw-r--r--src/src/lookups/oracle.c2
-rw-r--r--src/src/lookups/passwd.c2
-rw-r--r--src/src/lookups/pgsql.c8
-rw-r--r--src/src/lookups/redis.c8
-rw-r--r--src/src/lookups/spf.c14
-rw-r--r--src/src/lookups/sqlite.c4
-rw-r--r--src/src/lookups/testdb.c4
-rw-r--r--src/src/lookups/whoson.c2
-rw-r--r--src/src/mime.c39
-rw-r--r--src/src/pdkim/base64.c20
-rw-r--r--src/src/receive.c10
-rw-r--r--src/src/search.c73
-rw-r--r--src/src/smtp_in.c18
-rw-r--r--src/src/smtp_out.c5
-rw-r--r--src/src/structs.h11
-rw-r--r--src/src/transport.c2
-rw-r--r--src/src/transports/smtp.c35
-rw-r--r--src/src/verify.c50
-rw-r--r--test/confs/061065
-rw-r--r--test/confs/220017
-rw-r--r--test/confs/220137
-rw-r--r--test/dnszones-src/db.test.ex6
-rw-r--r--test/log/061013
-rw-r--r--test/log/22001
-rw-r--r--test/log/22017
-rw-r--r--test/log/40005
-rw-r--r--test/log/54004
-rw-r--r--test/mail/4000.userx39
-rw-r--r--test/rejectlog/06104
-rw-r--r--test/scripts/0000-Basic/061033
-rw-r--r--test/scripts/2200-dnsdb/220013
-rw-r--r--test/scripts/2200-dnsdb/220118
-rw-r--r--test/scripts/4000-scanning/400030
-rw-r--r--test/scripts/5400-cutthrough/540034
-rw-r--r--test/src/fakens.c17
-rw-r--r--test/stderr/01432
-rw-r--r--test/stderr/220052
-rw-r--r--test/stderr/220195
-rw-r--r--test/stdout/061016
-rw-r--r--test/stdout/22003
-rw-r--r--test/stdout/3450.debian876
-rw-r--r--test/stdout/3454.debian880
-rw-r--r--test/stdout/400011
-rw-r--r--test/stdout/540045
64 files changed, 1035 insertions, 167 deletions
diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt
index 6a1963043..c9cbb6970 100644
--- a/doc/doc-docbook/spec.xfpt
+++ b/doc/doc-docbook/spec.xfpt
@@ -7012,6 +7012,15 @@ The form if &"retry_VAL"& where VAL is an integer.
The default count is set by the main configuration option &%dns_retry%&.
.wen
+.new
+.cindex cacheing "of dns lookup"
+.cindex TTL "of dns lookup"
+.cindex DNS TTL
+Dnsdb lookup results are cached within a single process (and its children).
+The cache entry lifetime is limited to the smallest time-to-live (TTL)
+value of the set of returned DNS records.
+.wen
+
.section "Pseudo dnsdb record types" "SECID66"
.cindex "MX record" "in &(dnsdb)& lookup"
@@ -9412,7 +9421,7 @@ yields &"42"&, and
.code
${listextract{-3}{<, x,42,99,& Mailer,,/bin/bash}{result: $value}}
.endd
-yields &"result: 99"&.
+yields &"result: 42"&.
If {<&'string3'&>} is omitted, an empty string is used for string3.
If {<&'string2'&>} is also omitted, the value that was
@@ -29348,9 +29357,15 @@ deny dnslists = blackholes.mail-abuse.org
warn message = X-Warn: sending host is on dialups list
dnslists = dialups.mail-abuse.org
.endd
-DNS list lookups are cached by Exim for the duration of the SMTP session,
+.cindex cacheing "of dns lookup"
+.cindex DNS TTL
+DNS list lookups are cached by Exim for the duration of the SMTP session
+.new
+(but limited by the DNS return TTL value),
+.wen
so a lookup based on the IP address is done at most once for any incoming
-connection. Exim does not share information between multiple incoming
+connection (assuming long-enough TTL).
+Exim does not share information between multiple incoming
connections (but your local name server cache should be active).
diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog
index 27365beae..004b66a7d 100644
--- a/doc/doc-txt/ChangeLog
+++ b/doc/doc-txt/ChangeLog
@@ -2,7 +2,53 @@ Change log file for Exim from version 4.21
-------------------------------------------
-HS/04 Add support for keep_environment and add_environment options.
+Exim version 4.86.1+fixes
+-----------------------
+Cherry-Picked from the master development branch
+------------------------------------------------
+
+JH/02 Bug 728: Close logfiles after a daemon-process "exceptional" log write.
+ If not running log_selector +smtp_connection the mainlog would be held
+ open indefinitely after a "too many connections" event, including to a
+ deleted file after a log rotate. Leave the per net connection logging
+ leaving it open for efficiency as that will be quickly detected by the
+ check on the next write.
+
+HS/01 Bug 1671: Fix post transport crash.
+ Processing the wait-<transport> messages could crash the delivery
+ process if the message IDs didn't exist for some reason. When
+ using 'split_spool_directory=yes' the construction of the spool
+ file name failed already, exposing the same netto behaviour.
+
+JH/06 Bug 1395: time-limit cacheing of DNS lookups, to the TTL value. This may
+ matter for fast-change records such as DNSBLs.
+
+JH/07 Bug 1678: Always record an interface option value, if set, as part of a
+ retry record, even if constant. There may be multiple transports with
+ different interface settings and the retry behaviour needs to be kept
+ distinct.
+
+JH/13 Bug 1708: avoid misaligned access in cached lookup.
+
+JH/09 Bug 1700: ignore space & tab embedded in base64 during decode.
+
+JH/38 Fix cutthrough bug with body lines having a single dot. The dot was
+ incorrectly not doubled on cutthrough transmission, hence seen as a
+ body-termination at the receiving system - resulting in truncated mails.
+ Commonly the sender saw a TCP-level error, and retransmitted the nessage
+ via the normal store-and-forward channel. This could result in duplicates
+ received - but deduplicating mailstores were liable to retain only the
+ initial truncated version.
+
+
+Exim version 4.86.1
+-------------------
+
+HS/04 SECURITY: Add support for keep_environment and add_environment
+ options. Change the working directory to / during startup.
+ CVE-2016-1531
+
+
Exim version 4.86
-----------------
JH/01 Bug 1545: The smtp transport option "retry_include_ip_address" is now
diff --git a/src/src/daemon.c b/src/src/daemon.c
index 894a96f25..a7a49f034 100644
--- a/src/src/daemon.c
+++ b/src/src/daemon.c
@@ -735,6 +735,7 @@ else (void)close(dup_accept_socket);
/* Release any store used in this process, including the store used for holding
the incoming host address and an expanded active_hostname. */
+log_close_all();
store_reset(reset_point);
sender_host_address = NULL;
}
diff --git a/src/src/deliver.c b/src/src/deliver.c
index 78f8f4bd4..4154ff77a 100644
--- a/src/src/deliver.c
+++ b/src/src/deliver.c
@@ -9,6 +9,7 @@
#include "exim.h"
+#include <assert.h>
/* Data block for keeping track of subprocesses for parallel remote
@@ -7904,17 +7905,36 @@ if (!regex_IGNOREQUOTA) regex_IGNOREQUOTA =
uschar *
deliver_get_sender_address (uschar * id)
{
+int rc;
+uschar * new_sender_address,
+ * save_sender_address;
+
if (!spool_open_datafile(id))
return NULL;
+/* Save and restore the global sender_address. I'm not sure if we should
+not save/restore all the other global variables too, because
+spool_read_header() may change all of them. But OTOH, when this
+deliver_get_sender_address() gets called, the current message is done
+already and nobody needs the globals anymore. (HS12, 2015-08-21) */
+
sprintf(CS spoolname, "%s-H", id);
-if (spool_read_header(spoolname, TRUE, TRUE) != spool_read_OK)
+save_sender_address = sender_address;
+
+rc = spool_read_header(spoolname, TRUE, TRUE);
+
+new_sender_address = sender_address;
+sender_address = save_sender_address;
+
+if (rc != spool_read_OK)
return NULL;
+assert(new_sender_address);
+
(void)close(deliver_datafile);
deliver_datafile = -1;
-return sender_address;
+return new_sender_address;
}
/* vi: aw ai sw=2
diff --git a/src/src/dns.c b/src/src/dns.c
index 64958d983..abed1264a 100644
--- a/src/src/dns.c
+++ b/src/src/dns.c
@@ -390,7 +390,8 @@ from the following bytes. */
dnss->aptr += namelen;
GETSHORT(dnss->srr.type, dnss->aptr); /* Record type */
-dnss->aptr += 6; /* Don't want class or TTL */
+dnss->aptr += 2; /* Don't want class */
+GETLONG(dnss->srr.ttl, dnss->aptr); /* TTL */
GETSHORT(dnss->srr.size, dnss->aptr); /* Size of data portion */
dnss->srr.data = dnss->aptr; /* The record's data follows */
dnss->aptr += dnss->srr.size; /* Advance to next RR */
diff --git a/src/src/functions.h b/src/src/functions.h
index fe20b035b..afa362f7c 100644
--- a/src/src/functions.h
+++ b/src/src/functions.h
@@ -375,7 +375,7 @@ extern int smtp_sock_connect(host_item *, int, int, uschar *,
extern int smtp_feof(void);
extern int smtp_ferror(void);
extern uschar *smtp_get_connection_info(void);
-extern BOOL smtp_get_interface(uschar *, int, address_item *, BOOL *,
+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(void);
diff --git a/src/src/lookupapi.h b/src/src/lookupapi.h
index cdd1c85bf..03de8f675 100644
--- a/src/src/lookupapi.h
+++ b/src/src/lookupapi.h
@@ -34,7 +34,7 @@ typedef struct lookup_info {
int, /* length of key or query */
uschar **, /* for returning answer */
uschar **, /* for error message */
- BOOL *); /* to request cache cleanup */
+ uint *); /* cache TTL, sconds */
void (*close)( /* close function */
void *); /* handle */
void (*tidy)(void); /* tidy function */
@@ -46,9 +46,10 @@ typedef struct lookup_info {
} lookup_info;
/* This magic number is used by the following lookup_module_info structure
- for checking API compatibility. It's equivalent to the string"LMM2" */
-#define LOOKUP_MODULE_INFO_MAGIC 0x4c4d4d32
+ for checking API compatibility. It used to be equivalent to the string"LMM3" */
+#define LOOKUP_MODULE_INFO_MAGIC 0x4c4d4933
/* Version 2 adds: version_report */
+/* Version 3 change: non/cache becomes TTL in seconds */
typedef struct lookup_module_info {
uint magic;
diff --git a/src/src/lookups/README b/src/src/lookups/README
index 98905dc5c..31fea6448 100644
--- a/src/src/lookups/README
+++ b/src/src/lookups/README
@@ -122,12 +122,15 @@ DEFER. The arguments are:
uschar **errmsg where to put an error message on failure;
this is initially set to "", and should be left
as that for a standard "entry not found" error
- BOOL *do_cache the lookup should set this to FALSE when it changes data.
- This is TRUE by default. When set to FALSE the cache tree
+ uint *do_cache the lookup should set this to 0 when it changes data.
+ This is MAXINT by default. When set to 0 the cache tree
of the current search handle will be cleaned and the
current result will NOT be cached. Currently the mysql
and pgsql lookups use this when UPDATE/INSERT queries are
executed.
+ If set to a nonzero number of seconds, the cached value
+ becomes unusable after this time. Currently the dnsdb
+ lookup uses this to support the TTL value.
Even though the key is zero-terminated, the length is passed because in the
common case it has been computed already and is often needed.
diff --git a/src/src/lookups/cdb.c b/src/src/lookups/cdb.c
index ea017def1..ba925dc12 100644
--- a/src/src/lookups/cdb.c
+++ b/src/src/lookups/cdb.c
@@ -279,7 +279,7 @@ cdb_find(void *handle,
int key_len,
uschar **result,
uschar **errmsg,
- BOOL *do_cache)
+ uint *do_cache)
{
struct cdb_state * cdbp = handle;
uint32 item_key_len,
diff --git a/src/src/lookups/dbmdb.c b/src/src/lookups/dbmdb.c
index 03248e490..b8c42d596 100644
--- a/src/src/lookups/dbmdb.c
+++ b/src/src/lookups/dbmdb.c
@@ -87,7 +87,7 @@ the keylength in order to include the terminating zero. */
static int
dbmdb_find(void *handle, uschar *filename, const uschar *keystring, int length,
- uschar **result, uschar **errmsg, BOOL *do_cache)
+ uschar **result, uschar **errmsg, uint *do_cache)
{
EXIM_DB *d = (EXIM_DB *)handle;
EXIM_DATUM key, data;
@@ -120,7 +120,7 @@ return FAIL;
int
static dbmnz_find(void *handle, uschar *filename, const uschar *keystring, int length,
- uschar **result, uschar **errmsg, BOOL *do_cache)
+ uschar **result, uschar **errmsg, uint *do_cache)
{
return dbmdb_find(handle, filename, keystring, length-1, result, errmsg,
do_cache);
@@ -140,7 +140,7 @@ return dbmdb_find(handle, filename, keystring, length-1, result, errmsg,
static int
dbmjz_find(void *handle, uschar *filename, const uschar *keystring, int length,
- uschar **result, uschar **errmsg, BOOL *do_cache)
+ uschar **result, uschar **errmsg, uint *do_cache)
{
uschar *key_item, *key_buffer, *key_p;
const uschar *key_elems = keystring;
diff --git a/src/src/lookups/dnsdb.c b/src/src/lookups/dnsdb.c
index e3de279e2..70e6c8c63 100644
--- a/src/src/lookups/dnsdb.c
+++ b/src/src/lookups/dnsdb.c
@@ -131,7 +131,7 @@ separator, as always, is colon. */
static int
dnsdb_find(void *handle, uschar *filename, const uschar *keystring, int length,
- uschar **result, uschar **errmsg, BOOL *do_cache)
+ uschar **result, uschar **errmsg, uint *do_cache)
{
int rc;
int size = 256;
@@ -388,6 +388,9 @@ while ((domain = string_nextinlist(&keystring, &sep, NULL, 0)))
{
if (rr->type != searchtype) continue;
+ if (*do_cache > rr->ttl)
+ *do_cache = rr->ttl;
+
if (type == T_A || type == T_AAAA || type == T_ADDRESSES)
{
dns_address *da;
diff --git a/src/src/lookups/dsearch.c b/src/src/lookups/dsearch.c
index f8c592adb..9f7dd8da0 100644
--- a/src/src/lookups/dsearch.c
+++ b/src/src/lookups/dsearch.c
@@ -67,7 +67,7 @@ for us. */
int
static dsearch_find(void *handle, uschar *dirname, const uschar *keystring, int length,
- uschar **result, uschar **errmsg, BOOL *do_cache)
+ uschar **result, uschar **errmsg, uint *do_cache)
{
struct stat statbuf;
int save_errno;
diff --git a/src/src/lookups/ibase.c b/src/src/lookups/ibase.c
index 23e1dea60..7fd53d011 100644
--- a/src/src/lookups/ibase.c
+++ b/src/src/lookups/ibase.c
@@ -451,7 +451,7 @@ deferred with a retryable error. */
static int
ibase_find(void *handle, uschar * filename, uschar * query, int length,
- uschar ** result, uschar ** errmsg, BOOL *do_cache)
+ uschar ** result, uschar ** errmsg, uint *do_cache)
{
int sep = 0;
uschar *server;
diff --git a/src/src/lookups/ldap.c b/src/src/lookups/ldap.c
index a56eff326..b870df147 100644
--- a/src/src/lookups/ldap.c
+++ b/src/src/lookups/ldap.c
@@ -1339,7 +1339,7 @@ The handle and filename arguments are not used. */
static int
eldap_find(void *handle, uschar *filename, const uschar *ldap_url, int length,
- uschar **result, uschar **errmsg, BOOL *do_cache)
+ uschar **result, uschar **errmsg, uint *do_cache)
{
/* Keep picky compilers happy */
do_cache = do_cache;
@@ -1348,7 +1348,7 @@ return(control_ldap_search(ldap_url, SEARCH_LDAP_SINGLE, result, errmsg));
static int
eldapm_find(void *handle, uschar *filename, const uschar *ldap_url, int length,
- uschar **result, uschar **errmsg, BOOL *do_cache)
+ uschar **result, uschar **errmsg, uint *do_cache)
{
/* Keep picky compilers happy */
do_cache = do_cache;
@@ -1357,7 +1357,7 @@ return(control_ldap_search(ldap_url, SEARCH_LDAP_MULTIPLE, result, errmsg));
static int
eldapdn_find(void *handle, uschar *filename, const uschar *ldap_url, int length,
- uschar **result, uschar **errmsg, BOOL *do_cache)
+ uschar **result, uschar **errmsg, uint *do_cache)
{
/* Keep picky compilers happy */
do_cache = do_cache;
@@ -1366,7 +1366,7 @@ return(control_ldap_search(ldap_url, SEARCH_LDAP_DN, result, errmsg));
int
eldapauth_find(void *handle, uschar *filename, const uschar *ldap_url, int length,
- uschar **result, uschar **errmsg, BOOL *do_cache)
+ uschar **result, uschar **errmsg, uint *do_cache)
{
/* Keep picky compilers happy */
do_cache = do_cache;
diff --git a/src/src/lookups/lf_functions.h b/src/src/lookups/lf_functions.h
index 73e93037e..d2487d362 100644
--- a/src/src/lookups/lf_functions.h
+++ b/src/src/lookups/lf_functions.h
@@ -12,7 +12,7 @@ extern int lf_check_file(int, uschar *, int, int, uid_t *, gid_t *,
extern uschar *lf_quote(uschar *, uschar *, int, uschar *, int *, int *);
extern int lf_sqlperform(const uschar *, const uschar *, const uschar *,
const uschar *, uschar **,
- uschar **, BOOL *, int(*)(const uschar *, uschar *, uschar **,
- uschar **, BOOL *, BOOL *));
+ uschar **, uint *, int(*)(const uschar *, uschar *, uschar **,
+ uschar **, BOOL *, uint *));
/* End of lf_functions.h */
diff --git a/src/src/lookups/lf_sqlperform.c b/src/src/lookups/lf_sqlperform.c
index 2d7f32684..6d4f7a798 100644
--- a/src/src/lookups/lf_sqlperform.c
+++ b/src/src/lookups/lf_sqlperform.c
@@ -27,7 +27,7 @@ Arguments:
query the query
result where to pass back the result
errmsg where to pass back an error message
- do_cache to be set FALSE if data is changed
+ do_cache to be set zero if data is changed
func the lookup function to call
Returns: the return from the lookup function, or DEFER
@@ -36,8 +36,8 @@ Returns: the return from the lookup function, or DEFER
int
lf_sqlperform(const uschar *name, const uschar *optionname,
const uschar *optserverlist, const uschar *query,
- uschar **result, uschar **errmsg, BOOL *do_cache,
- int(*fn)(const uschar *, uschar *, uschar **, uschar **, BOOL *, BOOL *))
+ uschar **result, uschar **errmsg, uint *do_cache,
+ int(*fn)(const uschar *, uschar *, uschar **, uschar **, BOOL *, uint *))
{
int sep, rc;
uschar *server;
diff --git a/src/src/lookups/lsearch.c b/src/src/lookups/lsearch.c
index 3883d4ba0..eb70a45fa 100644
--- a/src/src/lookups/lsearch.c
+++ b/src/src/lookups/lsearch.c
@@ -323,7 +323,7 @@ return FAIL;
static int
lsearch_find(void *handle, uschar *filename, const uschar *keystring, int length,
- uschar **result, uschar **errmsg, BOOL *do_cache)
+ uschar **result, uschar **errmsg, uint *do_cache)
{
do_cache = do_cache; /* Keep picky compilers happy */
return internal_lsearch_find(handle, filename, keystring, length, result,
@@ -340,7 +340,7 @@ return internal_lsearch_find(handle, filename, keystring, length, result,
static int
wildlsearch_find(void *handle, uschar *filename, const uschar *keystring, int length,
- uschar **result, uschar **errmsg, BOOL *do_cache)
+ uschar **result, uschar **errmsg, uint *do_cache)
{
do_cache = do_cache; /* Keep picky compilers happy */
return internal_lsearch_find(handle, filename, keystring, length, result,
@@ -357,7 +357,7 @@ return internal_lsearch_find(handle, filename, keystring, length, result,
static int
nwildlsearch_find(void *handle, uschar *filename, const uschar *keystring, int length,
- uschar **result, uschar **errmsg, BOOL *do_cache)
+ uschar **result, uschar **errmsg, uint *do_cache)
{
do_cache = do_cache; /* Keep picky compilers happy */
return internal_lsearch_find(handle, filename, keystring, length, result,
@@ -375,7 +375,7 @@ return internal_lsearch_find(handle, filename, keystring, length, result,
static int
iplsearch_find(void *handle, uschar *filename, const uschar *keystring, int length,
- uschar **result, uschar **errmsg, BOOL *do_cache)
+ uschar **result, uschar **errmsg, uint *do_cache)
{
do_cache = do_cache; /* Keep picky compilers happy */
if ((length == 1 && keystring[0] == '*') ||
diff --git a/src/src/lookups/mysql.c b/src/src/lookups/mysql.c
index 8dff86ad1..1ce8831e8 100644
--- a/src/src/lookups/mysql.c
+++ b/src/src/lookups/mysql.c
@@ -74,7 +74,7 @@ Arguments:
resultptr where to store the result
errmsg where to point an error message
defer_break TRUE if no more servers are to be tried after DEFER
- do_cache set false if data is changed
+ do_cache set zero if data is changed
The server string is of the form "host/dbname/user/password". The host can be
host:port. This string is in a nextinlist temporary buffer, so can be
@@ -85,7 +85,7 @@ Returns: OK, FAIL, or DEFER
static int
perform_mysql_search(const uschar *query, uschar *server, uschar **resultptr,
- uschar **errmsg, BOOL *defer_break, BOOL *do_cache)
+ uschar **errmsg, BOOL *defer_break, uint *do_cache)
{
MYSQL *mysql_handle = NULL; /* Keep compilers happy */
MYSQL_RES *mysql_result = NULL;
@@ -225,7 +225,7 @@ can be detected by calling mysql_field_count(). If its result is zero, no data
was expected (this is all explained clearly in the MySQL manual). In this case,
we return the number of rows affected by the command. In this event, we do NOT
want to cache the result; also the whole cache for the handle must be cleaned
-up. Setting do_cache FALSE requests this. */
+up. Setting do_cache zero requests this. */
if ((mysql_result = mysql_use_result(mysql_handle)) == NULL)
{
@@ -233,7 +233,7 @@ if ((mysql_result = mysql_use_result(mysql_handle)) == NULL)
{
DEBUG(D_lookup) debug_printf("MYSQL: query was not one that returns data\n");
result = string_sprintf("%d", mysql_affected_rows(mysql_handle));
- *do_cache = FALSE;
+ *do_cache = 0;
goto MYSQL_EXIT;
}
*errmsg = string_sprintf("MYSQL: lookup result failed: %s\n",
@@ -341,7 +341,7 @@ shared with other SQL lookups. */
static int
mysql_find(void *handle, uschar *filename, const uschar *query, int length,
- uschar **result, uschar **errmsg, BOOL *do_cache)
+ uschar **result, uschar **errmsg, uint *do_cache)
{
return lf_sqlperform(US"MySQL", US"mysql_servers", mysql_servers, query,
result, errmsg, do_cache, perform_mysql_search);
diff --git a/src/src/lookups/nis.c b/src/src/lookups/nis.c
index 7b012b14c..1faa884a1 100644
--- a/src/src/lookups/nis.c
+++ b/src/src/lookups/nis.c
@@ -42,7 +42,7 @@ code. */
static int
nis_find(void *handle, uschar *filename, uschar *keystring, int length,
- uschar **result, uschar **errmsg, BOOL *do_cache)
+ uschar **result, uschar **errmsg, uint *do_cache)
{
int rc;
uschar *nis_data;
@@ -68,7 +68,7 @@ return (rc == YPERR_KEY || rc == YPERR_MAP)? FAIL : DEFER;
static int
nis0_find(void *handle, uschar *filename, uschar *keystring, int length,
- uschar **result, uschar **errmsg, BOOL *do_cache)
+ uschar **result, uschar **errmsg, uint *do_cache)
{
int rc;
uschar *nis_data;
diff --git a/src/src/lookups/nisplus.c b/src/src/lookups/nisplus.c
index 8895ceeec..a4a7a2d5b 100644
--- a/src/src/lookups/nisplus.c
+++ b/src/src/lookups/nisplus.c
@@ -43,7 +43,7 @@ equals sign. */
static int
nisplus_find(void *handle, uschar *filename, uschar *query, int length,
- uschar **result, uschar **errmsg, BOOL *do_cache)
+ uschar **result, uschar **errmsg, uint *do_cache)
{
int i;
int ssize = 0;
diff --git a/src/src/lookups/oracle.c b/src/src/lookups/oracle.c
index 1f2520ac0..adb17b4da 100644
--- a/src/src/lookups/oracle.c
+++ b/src/src/lookups/oracle.c
@@ -517,7 +517,7 @@ deferred with a retryable error. */
static int
oracle_find(void *handle, uschar *filename, uschar *query, int length,
- uschar **result, uschar **errmsg, BOOL *do_cache)
+ uschar **result, uschar **errmsg, uint *do_cache)
{
int sep = 0;
uschar *server;
diff --git a/src/src/lookups/passwd.c b/src/src/lookups/passwd.c
index e726f3e8e..315677ffa 100644
--- a/src/src/lookups/passwd.c
+++ b/src/src/lookups/passwd.c
@@ -34,7 +34,7 @@ return (void *)(-1); /* Just return something non-null */
static int
passwd_find(void *handle, uschar *filename, const uschar *keystring, int length,
- uschar **result, uschar **errmsg, BOOL *do_cache)
+ uschar **result, uschar **errmsg, uint *do_cache)
{
struct passwd *pw;
diff --git a/src/src/lookups/pgsql.c b/src/src/lookups/pgsql.c
index c86ac23ed..4be3d98f1 100644
--- a/src/src/lookups/pgsql.c
+++ b/src/src/lookups/pgsql.c
@@ -119,7 +119,7 @@ Returns: OK, FAIL, or DEFER
static int
perform_pgsql_search(const uschar *query, uschar *server, uschar **resultptr,
- uschar **errmsg, BOOL *defer_break, BOOL *do_cache)
+ uschar **errmsg, BOOL *defer_break, uint *do_cache)
{
PGconn *pg_conn = NULL;
PGresult *pg_result = NULL;
@@ -290,10 +290,10 @@ else
/* The command was successful but did not return any data since it was
* not SELECT but either an INSERT, UPDATE or DELETE statement. Tell the
* high level code to not cache this query, and clean the current cache for
- * this handle by setting *do_cache FALSE. */
+ * this handle by setting *do_cache zero. */
result = string_copy(US PQcmdTuples(pg_result));
offset = Ustrlen(result);
- *do_cache = FALSE;
+ *do_cache = 0;
DEBUG(D_lookup) debug_printf("PGSQL: command does not return any data "
"but was successful. Rows affected: %s\n", result);
@@ -399,7 +399,7 @@ shared with other SQL lookups. */
static int
pgsql_find(void *handle, uschar *filename, const uschar *query, int length,
- uschar **result, uschar **errmsg, BOOL *do_cache)
+ uschar **result, uschar **errmsg, uint *do_cache)
{
return lf_sqlperform(US"PostgreSQL", US"pgsql_servers", pgsql_servers, query,
result, errmsg, do_cache, perform_pgsql_search);
diff --git a/src/src/lookups/redis.c b/src/src/lookups/redis.c
index ac4d0ec30..18cd3a0af 100644
--- a/src/src/lookups/redis.c
+++ b/src/src/lookups/redis.c
@@ -65,7 +65,7 @@ redis_tidy(void)
*/
static int
perform_redis_search(uschar *command, uschar *server, uschar **resultptr,
- uschar **errmsg, BOOL *defer_break, BOOL *do_cache)
+ uschar **errmsg, BOOL *defer_break, uint *do_cache)
{
redisContext *redis_handle = NULL; /* Keep compilers happy */
redisReply *redis_reply = NULL;
@@ -197,7 +197,7 @@ perform_redis_search(uschar *command, uschar *server, uschar **resultptr,
case REDIS_REPLY_ERROR:
*errmsg = string_sprintf("REDIS: lookup result failed: %s\n", redis_reply->str);
*defer_break = FALSE;
- *do_cache = FALSE;
+ *do_cache = 0;
goto REDIS_EXIT;
/* NOTREACHED */
@@ -205,7 +205,7 @@ perform_redis_search(uschar *command, uschar *server, uschar **resultptr,
case REDIS_REPLY_NIL:
DEBUG(D_lookup) debug_printf("REDIS: query was not one that returned any data\n");
result = string_sprintf("");
- *do_cache = FALSE;
+ *do_cache = 0;
goto REDIS_EXIT;
/* NOTREACHED */
@@ -304,7 +304,7 @@ perform_redis_search(uschar *command, uschar *server, uschar **resultptr,
static int
redis_find(void *handle __attribute__((unused)), uschar *filename __attribute__((unused)),
- uschar *command, int length, uschar **result, uschar **errmsg, BOOL *do_cache)
+ uschar *command, int length, uschar **result, uschar **errmsg, uint *do_cache)
{
return lf_sqlperform(US"Redis", US"redis_servers", redis_servers, command,
result, errmsg, do_cache, perform_redis_search);
diff --git a/src/src/lookups/spf.c b/src/src/lookups/spf.c
index 23ad2addd..2671fc9c4 100644
--- a/src/src/lookups/spf.c
+++ b/src/src/lookups/spf.c
@@ -31,7 +31,9 @@ static void dummy(int x) { dummy2(x-1); }
#include <spf2/spf_dns_resolv.h>
#include <spf2/spf_dns_cache.h>
-static void *spf_open(uschar *filename, uschar **errmsg) {
+static void *
+spf_open(uschar *filename, uschar **errmsg)
+{
SPF_server_t *spf_server = NULL;
spf_server = SPF_server_new(SPF_DNS_CACHE, 0);
if (spf_server == NULL) {
@@ -41,13 +43,17 @@ static void *spf_open(uschar *filename, uschar **errmsg) {
return (void *) spf_server;
}
-static void spf_close(void *handle) {
+static void
+spf_close(void *handle)
+{
SPF_server_t *spf_server = handle;
if (spf_server) SPF_server_free(spf_server);
}
-static int spf_find(void *handle, uschar *filename, uschar *keystring, int key_len,
- uschar **result, uschar **errmsg, BOOL *do_cache) {
+static int
+spf_find(void *handle, uschar *filename, uschar *keystring, int key_len,
+ uschar **result, uschar **errmsg, uint *do_cache)
+{
SPF_server_t *spf_server = handle;
SPF_request_t *spf_request = NULL;
SPF_response_t *spf_response = NULL;
diff --git a/src/src/lookups/sqlite.c b/src/src/lookups/sqlite.c
index bb92c8c18..e2330f920 100644
--- a/src/src/lookups/sqlite.c
+++ b/src/src/lookups/sqlite.c
@@ -81,7 +81,7 @@ return 0;
static int
sqlite_find(void *handle, uschar *filename, const uschar *query, int length,
- uschar **result, uschar **errmsg, BOOL *do_cache)
+ uschar **result, uschar **errmsg, uint *do_cache)
{
int ret;
struct strbuf res = { NULL, 0, 0 };
@@ -93,7 +93,7 @@ if (ret != SQLITE_OK)
return FAIL;
}
-if (res.string == NULL) *do_cache = FALSE;
+if (res.string == NULL) *do_cache = 0;
*result = res.string;
return OK;
diff --git a/src/src/lookups/testdb.c b/src/src/lookups/testdb.c
index c82fa7f3e..401f7c8bf 100644
--- a/src/src/lookups/testdb.c
+++ b/src/src/lookups/testdb.c
@@ -38,7 +38,7 @@ return (void *)(1); /* Just return something non-null */
static int
testdb_find(void *handle, uschar *filename, const uschar *query, int length,
- uschar **result, uschar **errmsg, BOOL *do_cache)
+ uschar **result, uschar **errmsg, uint *do_cache)
{
handle = handle; /* Keep picky compilers happy */
filename = filename;
@@ -57,7 +57,7 @@ if (Ustrcmp(query, "defer") == 0)
return DEFER;
}
-if (Ustrcmp(query, "nocache") == 0) *do_cache = FALSE;
+if (Ustrcmp(query, "nocache") == 0) *do_cache = 0;
*result = string_copy(query);
return OK;
diff --git a/src/src/lookups/whoson.c b/src/src/lookups/whoson.c
index 4166089bd..9ac5a3a43 100644
--- a/src/src/lookups/whoson.c
+++ b/src/src/lookups/whoson.c
@@ -36,7 +36,7 @@ return (void *)(1); /* Just return something non-null */
static int
whoson_find(void *handle, uschar *filename, uschar *query, int length,
- uschar **result, uschar **errmsg, BOOL *do_cache)
+ uschar **result, uschar **errmsg, uint *do_cache)
{
uschar buffer[80];
handle = handle; /* Keep picky compilers happy */
diff --git a/src/src/mime.c b/src/src/mime.c
index 618364a3e..cc9ffb7c6 100644
--- a/src/src/mime.c
+++ b/src/src/mime.c
@@ -550,7 +550,8 @@ int size = 0, ptr = 0;
uschar * val = string_cat(NULL, &size, &ptr, US"=?", 2);
uschar c;
-val = string_cat(val, &size, &ptr, charset, Ustrlen(charset));
+if (charset)
+ val = string_cat(val, &size, &ptr, charset, Ustrlen(charset));
val = string_cat(val, &size, &ptr, US"?Q?", 3);
while ((c = *fname))
@@ -607,7 +608,7 @@ while(1)
if (!fgets(CS header, MIME_MAX_HEADER_SIZE, f))
{
/* Hit EOF or read error. Ugh. */
- DEBUG(D_acl) debug_printf("Hit EOF ...\n");
+ DEBUG(D_acl) debug_printf("MIME: Hit EOF ...\n");
return rc;
}
@@ -619,12 +620,12 @@ while(1)
if (Ustrncmp((header+2+Ustrlen(context->boundary)), "--", 2) == 0)
{
/* END boundary found */
- DEBUG(D_acl) debug_printf("End boundary found %s\n",
+ DEBUG(D_acl) debug_printf("MIME: End boundary found %s\n",
context->boundary);
return rc;
}
- DEBUG(D_acl) debug_printf("Next part with boundary %s\n",
+ DEBUG(D_acl) debug_printf("MIME: Next part with boundary %s\n",
context->boundary);
break;
}
@@ -648,7 +649,7 @@ while(1)
for (q = p; *q != ';' && *q; q++) ;
*mh->value = string_copynlc(p, q-p);
- DEBUG(D_acl) debug_printf("found %s MIME header, value is '%s'\n",
+ DEBUG(D_acl) debug_printf("MIME: found %s header, value is '%s'\n",
mh->name, *mh->value);
if (*(p = q)) p++; /* jump past the ; */
@@ -666,7 +667,7 @@ while(1)
{
mime_parameter * mp;
- DEBUG(D_acl) debug_printf(" considering paramlist '%s'\n", p);
+ DEBUG(D_acl) debug_printf("MIME: considering paramlist '%s'\n", p);
if ( !mime_filename
&& strncmpic(CUS"content-disposition:", header, 20) == 0
@@ -700,22 +701,27 @@ while(1)
uschar * s = q;
/* look for a ' in the "filename" */
- while(*s != '\'' && *s) s++; /* s is ' or NUL */
+ while(*s != '\'' && *s) s++; /* s is 1st ' or NUL */
if ((size = s-q) > 0)
- {
mime_filename_charset = string_copyn(q, size);
- p = s;
- while(*p == '\'' && *p) p++; /* p is after ' */
- }
+ if (*(p = s)) p++;
+ while(*p == '\'') p++; /* p is after 2nd ' */
}
else
p = q;
+ DEBUG(D_acl) debug_printf("MIME: charset %s fname '%s'\n",
+ mime_filename_charset ? mime_filename_charset : US"<NULL>", p);
+
temp_string = rfc2231_to_2047(p, mime_filename_charset, &slen);
- temp_string = rfc2047_decode(temp_string, FALSE, NULL, 32,
+ DEBUG(D_acl) debug_printf("MIME: 2047-name %s\n", temp_string);
+
+ temp_string = rfc2047_decode(temp_string, FALSE, NULL, ' ',
NULL, &err_msg);
+ DEBUG(D_acl) debug_printf("MIME: plain-name %s\n", temp_string);
+
size = Ustrlen(temp_string);
if (size == slen)
@@ -750,7 +756,7 @@ while(1)
&dummy_errstr)
: NULL;
DEBUG(D_acl) debug_printf(
- " found %s MIME parameter in %s header, value '%s'\n",
+ "MIME: found %s parameter in %s header, value '%s'\n",
mp->name, mh->name, *mp->value);
break; /* done matching param names */
@@ -768,7 +774,7 @@ while(1)
if (decoding_failed) mime_filename = mime_fname_rfc2231;
DEBUG(D_acl) debug_printf(
- " found %s MIME parameter in %s header, value is '%s'\n",
+ "MIME: found %s parameter in %s header, value is '%s'\n",
"filename", mh->name, mime_filename);
}
}
@@ -809,8 +815,9 @@ while(1)
(nested_context.boundary != NULL) &&
(Ustrncmp(mime_content_type,"multipart",9) == 0) )
{
- DEBUG(D_acl) debug_printf("Entering multipart recursion, boundary '%s'\n",
- nested_context.boundary);
+ DEBUG(D_acl)
+ debug_printf("MIME: Entering multipart recursion, boundary '%s'\n",
+ nested_context.boundary);
nested_context.context =
context && context->context == MBC_ATTACHMENT
diff --git a/src/src/pdkim/base64.c b/src/src/pdkim/base64.c
index a82fc2d75..1395be42c 100644
--- a/src/src/pdkim/base64.c
+++ b/src/src/pdkim/base64.c
@@ -128,20 +128,22 @@ int base64_decode( unsigned char *dst, int *dlen,
for( i = j = n = 0; i < slen; i++ )
{
+ unsigned char c = src[i];
+
if( ( slen - i ) >= 2 &&
- src[i] == '\r' && src[i + 1] == '\n' )
+ c == '\r' && src[i + 1] == '\n' )
continue;
- if( src[i] == '\n' )
+ if( c == '\n' || c == ' ' || c == '\t' )
continue;
- if( src[i] == '=' && ++j > 2 )
+ if( c == '=' && ++j > 2 )
return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
- if( src[i] > 127 || base64_dec_map[src[i]] == 127 )
+ if( c > 127 || base64_dec_map[src[i]] == 127 )
return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
- if( base64_dec_map[src[i]] < 64 && j != 0 )
+ if( base64_dec_map[c] < 64 && j != 0 )
return( POLARSSL_ERR_BASE64_INVALID_CHARACTER );
n++;
@@ -160,11 +162,13 @@ int base64_decode( unsigned char *dst, int *dlen,
for( j = 3, n = x = 0, p = dst; i > 0; i--, src++ )
{
- if( *src == '\r' || *src == '\n' )
+ unsigned char c = *src;
+
+ if( c == '\r' || c == '\n' || c == ' ' || c == '\t' )
continue;
- j -= ( base64_dec_map[*src] == 64 );
- x = (x << 6) | ( base64_dec_map[*src] & 0x3F );
+ j -= ( base64_dec_map[c] == 64 );
+ x = (x << 6) | ( base64_dec_map[c] & 0x3F );
if( ++n == 4 )
{
diff --git a/src/src/receive.c b/src/src/receive.c
index 64cf1ae70..d1f81d3e8 100644
--- a/src/src/receive.c
+++ b/src/src/receive.c
@@ -835,7 +835,15 @@ while ((ch = (receive_getc)()) != EOF)
ch_state = 4;
continue;
}
- ch_state = 1; /* The dot itself is removed */
+ /* The dot was removed at state 3. For a doubled dot, here, reinstate
+ it to cutthrough. The current ch, dot or not, is passed both to cutthrough
+ and to file below. */
+ if (ch == '.')
+ {
+ uschar c= ch;
+ (void) cutthrough_puts(&c, 1);
+ }
+ ch_state = 1;
break;
case 4: /* After [CR] LF . CR */
diff --git a/src/src/search.c b/src/src/search.c
index a05529196..ccad25021 100644
--- a/src/src/search.c
+++ b/src/src/search.c
@@ -466,6 +466,7 @@ internal_search_find(void *handle, uschar *filename, uschar *keystring)
{
tree_node *t = (tree_node *)handle;
search_cache *c = (search_cache *)(t->data.ptr);
+expiring_data *e;
uschar *data = NULL;
int search_type = t->name[0] - '0';
int old_pool = store_pool;
@@ -491,18 +492,27 @@ store_pool = POOL_SEARCH;
/* Look up the data for the key, unless it is already in the cache for this
file. No need to check c->item_cache for NULL, tree_search will do so. */
-if ((t = tree_search(c->item_cache, keystring)) == NULL)
+if ( (t = tree_search(c->item_cache, keystring))
+ && (!(e = t->data.ptr)->expiry || e->expiry > time(NULL))
+ )
+ { /* Data was in the cache already; set the pointer from the tree node */
+ data = e->ptr;
+ DEBUG(D_lookup) debug_printf("cached data used for lookup of %s%s%s\n",
+ keystring,
+ filename ? US"\n in " : US"", filename ? filename : US"");
+ }
+else
{
- BOOL do_cache = TRUE;
+ uint do_cache = UINT_MAX;
int keylength = Ustrlen(keystring);
DEBUG(D_lookup)
{
- if (filename != NULL)
- debug_printf("file lookup required for %s\n in %s\n",
- keystring, filename);
- else
- debug_printf("database lookup required for %s\n", keystring);
+ if (t) debug_printf("cached data found but past valid time; ");
+ debug_printf("%s lookup required for %s%s%s\n",
+ filename ? US"file" : US"database",
+ keystring,
+ filename ? US"\n in " : US"", filename ? filename : US"");
}
/* Call the code for the different kinds of search. DEFER is handled
@@ -511,9 +521,7 @@ if ((t = tree_search(c->item_cache, keystring)) == NULL)
if (lookup_list[search_type]->find(c->handle, filename, keystring, keylength,
&data, &search_error_message, &do_cache) == DEFER)
- {
search_find_defer = TRUE;
- }
/* A record that has been found is now in data, which is either NULL
or points to a bit of dynamic store. Cache the result of the lookup if
@@ -524,10 +532,22 @@ if ((t = tree_search(c->item_cache, keystring)) == NULL)
else if (do_cache)
{
int len = keylength + 1;
- t = store_get(sizeof(tree_node) + len);
- memcpy(t->name, keystring, len);
- t->data.ptr = data;
- tree_insertnode(&c->item_cache, t);
+
+ if (t) /* Previous, out-of-date cache entry. Update with the */
+ { /* new result and forget the old one */
+ e->expiry = do_cache == UINT_MAX ? 0 : time(NULL)+do_cache;
+ e->ptr = data;
+ }
+ else
+ {
+ e = store_get(sizeof(expiring_data) + sizeof(tree_node) + len);
+ e->expiry = do_cache == UINT_MAX ? 0 : time(NULL)+do_cache;
+ e->ptr = data;
+ t = (tree_node *)(e+1);
+ memcpy(t->name, keystring, len);
+ t->data.ptr = e;
+ tree_insertnode(&c->item_cache, t);
+ }
}
/* If caching was disabled, empty the cache tree. We just set the cache
@@ -540,34 +560,19 @@ if ((t = tree_search(c->item_cache, keystring)) == NULL)
}
}
-/* Data was in the cache already; set the pointer from the tree node */
-
-else
- {
- data = US t->data.ptr;
- DEBUG(D_lookup) debug_printf("cached data used for lookup of %s%s%s\n",
- keystring,
- (filename == NULL)? US"" : US"\n in ",
- (filename == NULL)? US"" : filename);
- }
-
-/* Debug: output the answer */
-
DEBUG(D_lookup)
{
- if (data == NULL)
- {
- if (search_find_defer) debug_printf("lookup deferred: %s\n",
- search_error_message);
- else debug_printf("lookup failed\n");
- }
- else debug_printf("lookup yielded: %s\n", data);
+ if (data)
+ debug_printf("lookup yielded: %s\n", data);
+ else if (search_find_defer)
+ debug_printf("lookup deferred: %s\n", search_error_message);
+ else debug_printf("lookup failed\n");
}
/* Return it in new dynamic store in the regular pool */
store_pool = old_pool;
-return (data == NULL)? NULL : string_copy(data);
+return data ? string_copy(data) : NULL;
}
diff --git a/src/src/smtp_in.c b/src/src/smtp_in.c
index cf0a5d642..980d54bca 100644
--- a/src/src/smtp_in.c
+++ b/src/src/smtp_in.c
@@ -9,6 +9,7 @@
#include "exim.h"
+#include <assert.h>
/* Initialize for TCP wrappers if so configured. It appears that the macro
@@ -232,6 +233,7 @@ static uschar *protocols[] = {
/* Sanity check and validate optional args to MAIL FROM: envelope */
enum {
+ ENV_MAIL_OPT_NULL,
ENV_MAIL_OPT_SIZE, ENV_MAIL_OPT_BODY, ENV_MAIL_OPT_AUTH,
#ifndef DISABLE_PRDR
ENV_MAIL_OPT_PRDR,
@@ -240,7 +242,6 @@ enum {
#ifdef EXPERIMENTAL_INTERNATIONAL
ENV_MAIL_OPT_UTF8,
#endif
- ENV_MAIL_OPT_NULL
};
typedef struct {
uschar * name; /* option requested during MAIL cmd */
@@ -260,7 +261,8 @@ static env_mail_type_t env_mail_type_list[] = {
#ifdef EXPERIMENTAL_INTERNATIONAL
{ US"SMTPUTF8",ENV_MAIL_OPT_UTF8, FALSE }, /* rfc6531 */
#endif
- { US"NULL", ENV_MAIL_OPT_NULL, FALSE }
+ /* keep this the last entry */
+ { US"NULL", ENV_MAIL_OPT_NULL, FALSE },
};
/* When reading SMTP from a remote host, we have to use our own versions of the
@@ -3887,7 +3889,7 @@ while (done <= 0)
if (!extract_option(&name, &value)) break;
for (mail_args = env_mail_type_list;
- (char *)mail_args < (char *)env_mail_type_list + sizeof(env_mail_type_list);
+ mail_args->value != ENV_MAIL_OPT_NULL;
mail_args++
)
if (strcmpic(name, mail_args->name) == 0)
@@ -4066,15 +4068,17 @@ while (done <= 0)
}
break;
#endif
- /* Unknown option. Stick back the terminator characters and break
+ /* No valid option. Stick back the terminator characters and break
the loop. Do the name-terminator second as extract_option sets
- value==name when it found no equal-sign.
- An error for a malformed address will occur. */
- default:
+ value==name when it found no equal-sign.
+ An error for a malformed address will occur. */
+ case ENV_MAIL_OPT_NULL:
value[-1] = '=';
name[-1] = ' ';
arg_error = TRUE;
break;
+
+ default: assert(0);
}
/* Break out of for loop if switch() had bad argument or
when start of the email address is reached */
diff --git a/src/src/smtp_out.c b/src/src/smtp_out.c
index c704a0b0f..2fdf38bb0 100644
--- a/src/src/smtp_out.c
+++ b/src/src/smtp_out.c
@@ -26,7 +26,6 @@ Arguments:
which case the function does nothing
host_af AF_INET or AF_INET6 for the outgoing IP address
addr the mail address being handled (for setting errors)
- changed if not NULL, set TRUE if expansion actually changed istring
interface point this to the interface
msg to add to any error message
@@ -36,7 +35,7 @@ Returns: TRUE on success, FALSE on failure, with error message
BOOL
smtp_get_interface(uschar *istring, int host_af, address_item *addr,
- BOOL *changed, uschar **interface, uschar *msg)
+ uschar **interface, uschar *msg)
{
const uschar * expint;
uschar *iface;
@@ -54,8 +53,6 @@ if (expint == NULL)
return FALSE;
}
-if (changed != NULL) *changed = expint != istring;
-
while (isspace(*expint)) expint++;
if (*expint == 0) return TRUE;
diff --git a/src/src/structs.h b/src/src/structs.h
index 6f143d634..d9da38b0d 100644
--- a/src/src/structs.h
+++ b/src/src/structs.h
@@ -657,6 +657,16 @@ typedef struct tree_node {
uschar name[1]; /* node name - variable length */
} tree_node;
+/* Structure for holding time-limited data such as DNS returns.
+We use this rather than extending tree_node to avoid wasting
+space for most tree use (variables...) at the cost of complexity
+for the lookups cache */
+
+typedef struct expiring_data {
+ time_t expiry; /* if nonzero, data invalid after this time */
+ void *ptr; /* pointer to data */
+} expiring_data;
+
/* Structure for holding the handle and the cached last lookup for searches.
This block is pointed to by the tree entry for the file. The file can get
closed if too many are opened at once. There is a LRU chain for deciding which
@@ -676,6 +686,7 @@ uncompressed, but the data pointer is into the raw data. */
typedef struct {
uschar name[DNS_MAXNAME]; /* domain name */
int type; /* record type */
+ unsigned short ttl; /* time-to-live, seconds */
int size; /* size of data */
uschar *data; /* pointer to data */
} dns_record;
diff --git a/src/src/transport.c b/src/src/transport.c
index fa6f869cd..a6ad3ed34 100644
--- a/src/src/transport.c
+++ b/src/src/transport.c
@@ -1752,7 +1752,7 @@ while (1)
{
if (split_spool_directory)
sprintf(CS spool_file, "%s%c/%s-D",
- spool_dir, new_message_id[5], msgq[i].message_id);
+ spool_dir, msgq[i].message_id[5], msgq[i].message_id);
else
sprintf(CS spool_file, "%s%s-D", spool_dir, msgq[i].message_id);
diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c
index a95241349..ba7fb5ecc 100644
--- a/src/src/transports/smtp.c
+++ b/src/src/transports/smtp.c
@@ -1274,14 +1274,19 @@ we will veto this new message. */
static BOOL
smtp_are_same_identities(uschar * message_id, smtp_compare_t * s_compare)
{
-uschar * save_sender_address = sender_address;
-uschar * current_local_identity =
+
+uschar * message_local_identity,
+ * current_local_identity,
+ * new_sender_address;
+
+current_local_identity =
smtp_local_identity(s_compare->current_sender_address, s_compare->tblock);
-uschar * new_sender_address = deliver_get_sender_address(message_id);
-uschar * message_local_identity =
- smtp_local_identity(new_sender_address, s_compare->tblock);
-sender_address = save_sender_address;
+if (!(new_sender_address = deliver_get_sender_address(message_id)))
+ return 0;
+
+message_local_identity =
+ smtp_local_identity(new_sender_address, s_compare->tblock);
return Ustrcmp(current_local_identity, message_local_identity) == 0;
}
@@ -3169,7 +3174,6 @@ for (cutoff_retry = 0; expired &&
BOOL serialized = FALSE;
BOOL host_is_expired = FALSE;
BOOL message_defer = FALSE;
- BOOL ifchanges = FALSE;
BOOL some_deferred = FALSE;
address_item *first_addr = NULL;
uschar *interface = NULL;
@@ -3345,15 +3349,18 @@ for (cutoff_retry = 0; expired &&
if (Ustrcmp(pistring, ":25") == 0) pistring = US"";
/* Select IPv4 or IPv6, and choose an outgoing interface. If the interface
- string changes upon expansion, we must add it to the key that is used for
- retries, because connections to the same host from a different interface
- should be treated separately. */
+ string is set, even if constant (as different transports can have different
+ constant settings), we must add it to the key that is used for retries,
+ because connections to the same host from a different interface should be
+ treated separately. */
host_af = (Ustrchr(host->address, ':') == NULL)? AF_INET : AF_INET6;
- if (!smtp_get_interface(ob->interface, host_af, addrlist, &ifchanges,
- &interface, tid))
- return FALSE;
- if (ifchanges) pistring = string_sprintf("%s/%s", pistring, interface);
+ if ((rs = ob->interface) && *rs)
+ {
+ if (!smtp_get_interface(rs, host_af, addrlist, &interface, tid))
+ return FALSE;
+ pistring = string_sprintf("%s/%s", pistring, interface);
+ }
/* The first time round the outer loop, check the status of the host by
inspecting the retry data. The second time round, we are interested only
diff --git a/src/src/verify.c b/src/src/verify.c
index e00e7b9eb..6411c7ee1 100644
--- a/src/src/verify.c
+++ b/src/src/verify.c
@@ -21,6 +21,7 @@ uschar ctbuffer[8192];
/* Structure for caching DNSBL lookups */
typedef struct dnsbl_cache_block {
+ time_t expiry;
dns_address *rhs;
uschar *text;
int rc;
@@ -443,7 +444,7 @@ can do it there for the non-rcpt-verify case. For this we keep an addresscount.
host_af = (Ustrchr(host->address, ':') == NULL)? AF_INET:AF_INET6;
- if (!smtp_get_interface(tf->interface, host_af, addr, NULL, &interface,
+ if (!smtp_get_interface(tf->interface, host_af, addr, &interface,
US"callout") ||
!smtp_get_port(tf->port, addr, &port, US"callout"))
log_write(0, LOG_MAIN|LOG_PANIC, "<%s>: %s", addr->address,
@@ -578,7 +579,7 @@ can do it there for the non-rcpt-verify case. For this we keep an addresscount.
deliver_domain = addr->domain;
transport_name = addr->transport->name;
- if ( !smtp_get_interface(tf->interface, host_af, addr, NULL, &interface,
+ if ( !smtp_get_interface(tf->interface, host_af, addr, &interface,
US"callout")
|| !smtp_get_port(tf->port, addr, &port, US"callout")
)
@@ -3584,21 +3585,37 @@ if (!string_format(query, sizeof(query), "%s.%s", prepend, domain))
/* Look for this query in the cache. */
-t = tree_search(dnsbl_cache, query);
+if ( (t = tree_search(dnsbl_cache, query))
+ && (cb = t->data.ptr)->expiry > time(NULL)
+ )
+
+/* Previous lookup was cached */
+
+ {
+ HDEBUG(D_dnsbl) debug_printf("using result of previous DNS lookup\n");
+ }
/* If not cached from a previous lookup, we must do a DNS lookup, and
cache the result in permanent memory. */
-if (t == NULL)
+else
{
+ uint ttl = 3600;
+
store_pool = POOL_PERM;
- /* Set up a tree entry to cache the lookup */
+ if (t)
+ {
+ HDEBUG(D_dnsbl) debug_printf("cached data found but past valid time; ");
+ }
- t = store_get(sizeof(tree_node) + Ustrlen(query));
- Ustrcpy(t->name, query);
- t->data.ptr = cb = store_get(sizeof(dnsbl_cache_block));
- (void)tree_insertnode(&dnsbl_cache, t);
+ else
+ { /* Set up a tree entry to cache the lookup */
+ t = store_get(sizeof(tree_node) + Ustrlen(query));
+ Ustrcpy(t->name, query);
+ t->data.ptr = cb = store_get(sizeof(dnsbl_cache_block));
+ (void)tree_insertnode(&dnsbl_cache, t);
+ }
/* Do the DNS loopup . */
@@ -3616,7 +3633,10 @@ if (t == NULL)
Quite apart from one A6 RR generating multiple addresses, there are DNS
lists that return more than one A record, so we must handle multiple
- addresses generated in that way as well. */
+ addresses generated in that way as well.
+
+ Mark the cache entry with the "now" plus the minimum of the address TTLs,
+ or some suitably far-future time if none were found. */
if (cb->rc == DNS_SUCCEED)
{
@@ -3634,6 +3654,7 @@ if (t == NULL)
*addrp = da;
while (da->next != NULL) da = da->next;
addrp = &(da->next);
+ if (ttl > rr->ttl) ttl = rr->ttl;
}
}
}
@@ -3645,17 +3666,10 @@ if (t == NULL)
if (cb->rhs == NULL) cb->rc = DNS_NODATA;
}
+ cb->expiry = time(NULL)+ttl;
store_pool = old_pool;
}
-/* Previous lookup was cached */
-
-else
- {
- HDEBUG(D_dnsbl) debug_printf("using result of previous DNS lookup\n");
- cb = t->data.ptr;
- }
-
/* We now have the result of the DNS lookup, either newly done, or cached
from a previous call. If the lookup succeeded, check against the address
list if there is one. This may be a positive equality list (introduced by
diff --git a/test/confs/0610 b/test/confs/0610
new file mode 100644
index 000000000..f805c086c
--- /dev/null
+++ b/test/confs/0610
@@ -0,0 +1,65 @@
+# Exim test configuration 0610
+
+SERVER =
+
+exim_path = EXIM_PATH
+host_lookup_order = bydns
+#primary_hostname = myhost.test.ex
+rfc1413_query_timeout = 0s
+spool_directory = DIR/spool
+log_file_path = DIR/spool/log/SERVER%slog
+log_selector = +sender_on_delivery
+gecos_pattern = ""
+gecos_name = CALLER_NAME
+
+# ----- Main settings -----
+
+acl_smtp_connect = conn_chk
+acl_smtp_rcpt = accept
+
+untrusted_set_sender = *
+queue_only
+queue_run_in_order
+
+# ----- ACL -----
+
+begin acl
+
+conn_chk:
+ defer condition = ${if eq {SERVER}{server}}
+ accept
+
+# ----- Routers -----
+
+begin routers
+
+client:
+ driver = accept
+ transport = $sender_address_local_part
+
+# ----- Transports -----
+
+begin transports
+
+t1:
+ driver = smtp
+ allow_localhost
+ hosts = 127.0.0.1
+ port = PORT_D
+ interface = 127.0.0.1
+
+t2:
+ driver = smtp
+ allow_localhost
+ hosts = 127.0.0.1
+ port = PORT_D
+ interface = 127.0.0.2
+
+# ----- Retry -----
+
+begin retry
+
+* * F,5d,10s
+
+# End
+
diff --git a/test/confs/2200 b/test/confs/2200
index 47924c56a..c7d58b411 100644
--- a/test/confs/2200
+++ b/test/confs/2200
@@ -1,4 +1,5 @@
# Exim test configuration 2200
+# Check for dnsdb cache TTL handling
exim_path = EXIM_PATH
keep_environment =
@@ -9,4 +10,20 @@ log_file_path = DIR/spool/log/%slog
gecos_pattern = ""
gecos_name = CALLER_NAME
+# ----- Main settings -----
+
+acl_not_smtp = check_rcpt
+queue_only
+
+begin acl
+
+check_rcpt:
+ warn
+ set acl_m1 = ${map {<,$recipients} \
+ {${lookup dnsdb{a=${domain:$item}}{$value}fail}}}
+ delay = 4s
+ set acl_m1 = ${map {<,$recipients} \
+ {${lookup dnsdb{a=${domain:$item}}{$value}fail}}}
+ accept
+
# End
diff --git a/test/confs/2201 b/test/confs/2201
index dc01308e6..cce94bb29 100644
--- a/test/confs/2201
+++ b/test/confs/2201
@@ -13,11 +13,43 @@ gecos_name = CALLER_NAME
trusted_users = CALLER
+acl_smtp_rcpt = check_rcpt
+acl_not_smtp = check_sndr
+queue_only
+
+# - ACL --
+begin acl
+
+check_rcpt:
+ # Do not care about result, looking at debug output
+ # expect an original lookup, a cached lookup avoidance
+ # then a TTL-required repeat lookup
+ warn dnslists = rbl.test.ex/V4NET.11.12.14
+ dnslists = rbl.test.ex/V4NET.11.12.14
+ delay = 4s
+ dnslists = rbl.test.ex/V4NET.11.12.14
+ accept
+
+check_sndr:
+ # Do not care about result, looking at debug output
+ # expect an original lookup, a cached lookup avoidance
+ # then a TTL-required repeat lookup
+ warn sender_domains = dnsdb;a=$sender_address_domain
+ sender_domains = dnsdb;a=$sender_address_domain
+ delay = 4s
+ sender_domains = dnsdb;a=$sender_address_domain
+ accept
+
# ----- Routers -----
begin routers
+r0:
+ driver = accept
+ senders = a@shorthost.test.ex
+ transport = remote_delivery
+
r1:
driver = accept
domains = dnsdb;$domain
@@ -42,6 +74,11 @@ local_delivery:
file = DIR/test-mail/$local_part
user = CALLER
+remote_delivery:
+ driver = smtp
+ hosts = 127.0.0.1
+ allow_localhost
+ port = PORT_D
# ----- Retry -----
diff --git a/test/dnszones-src/db.test.ex b/test/dnszones-src/db.test.ex
index 4cbf0f251..61f274eb0 100644
--- a/test/dnszones-src/db.test.ex
+++ b/test/dnszones-src/db.test.ex
@@ -51,6 +51,10 @@ mx.xn--1xa A V4NET.255.255.255
thishost A 127.0.0.1
localhost4 A 127.0.0.1
+; A localhost with short TTL
+
+TTL=2 shorthost A 127.0.0.1
+
; Something that gives both the IP and the loopback
@@ -170,7 +174,7 @@ cname4 CNAME thishost
13.12.11.V4NET.rbl A 127.0.0.2
TXT "This is a test blacklisting message"
-14.12.11.V4NET.rbl A 127.0.0.2
+TTL=2 14.12.11.V4NET.rbl A 127.0.0.2
TXT "This is a test blacklisting message"
15.12.11.V4NET.rbl A 127.0.0.2
TXT "This is a very long blacklisting message, continuing for ages and ages and certainly being longer than 128 characters which was a previous limit on the length that Exim was prepared to handle."
diff --git a/test/log/0610 b/test/log/0610
new file mode 100644
index 000000000..d9e584b6d
--- /dev/null
+++ b/test/log/0610
@@ -0,0 +1,13 @@
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= t1@dustyshoes.tld U=CALLER P=local-smtp S=sss
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= t2@dustybelt.tld U=CALLER P=local-smtp S=sss
+1999-03-02 09:44:33 Start queue run: pid=pppp -qq
+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 initial connection: 451 Temporary local problem - please try later
+1999-03-02 09:44:33 10HmaX-0005vi-00 == fred@anotherone.tld R=client T=t1 defer (0) H=127.0.0.1 [127.0.0.1]: SMTP error from remote mail server after initial connection: 451 Temporary local problem - please try later
+1999-03-02 09:44:33 10HmaY-0005vi-00 H=127.0.0.1 [127.0.0.1]: SMTP error from remote mail server after initial connection: 451 Temporary local problem - please try later
+1999-03-02 09:44:33 10HmaY-0005vi-00 == fred@anotherone.tld R=client T=t2 defer (0) H=127.0.0.1 [127.0.0.1]: SMTP error from remote mail server after initial connection: 451 Temporary local problem - please try later
+1999-03-02 09:44:33 End queue run: pid=pppp -qq
+
+******** 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=[127.0.0.1] temporarily rejected connection in "connect" ACL
+1999-03-02 09:44:33 H=[127.0.0.2] temporarily rejected connection in "connect" ACL
diff --git a/test/log/2200 b/test/log/2200
new file mode 100644
index 000000000..f59faf8b9
--- /dev/null
+++ b/test/log/2200
@@ -0,0 +1 @@
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local S=sss
diff --git a/test/log/2201 b/test/log/2201
new file mode 100644
index 000000000..d413ddaf3
--- /dev/null
+++ b/test/log/2201
@@ -0,0 +1,7 @@
+1999-03-02 09:44:33 10HmaX-0005vi-00 <= a@shorthost.test.ex U=CALLER P=local S=sss
+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 Start queue run: pid=pppp
+1999-03-02 09:44:33 10HmaY-0005vi-00 <= a@shorthost.test.ex H=localhost (myhost.test.ex) [127.0.0.1] P=esmtp S=sss id=E10HmaX-0005vi-00@myhost.test.ex
+1999-03-02 09:44:33 10HmaX-0005vi-00 => t@test.ex R=r0 T=remote_delivery 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
diff --git a/test/log/4000 b/test/log/4000
index bb1a04fe9..c39fb583c 100644
--- a/test/log/4000
+++ b/test/log/4000
@@ -13,6 +13,9 @@
1999-03-02 09:44:33 10HmbB-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss id=20041217133501.GA3059@test.ex T="Nasty4"
1999-03-02 09:44:33 10HmbB-0005vi-00 => userx <userx@test.ex> R=r1 T=t1
1999-03-02 09:44:33 10HmbB-0005vi-00 Completed
-1999-03-02 09:44:33 10HmbC-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss id=20041217133501.GA3058@test.ex
+1999-03-02 09:44:33 10HmbC-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss id=20041217133501.GA3058@test.ex T="Nasty5"
1999-03-02 09:44:33 10HmbC-0005vi-00 => userx <userx@test.ex> R=r1 T=t1
1999-03-02 09:44:33 10HmbC-0005vi-00 Completed
+1999-03-02 09:44:33 10HmbD-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss id=20041217133502.GA3059@test.ex T="Nasty6"
+1999-03-02 09:44:33 10HmbD-0005vi-00 => userx <userx@test.ex> R=r1 T=t1
+1999-03-02 09:44:33 10HmbD-0005vi-00 Completed
diff --git a/test/log/5400 b/test/log/5400
index a72dfeead..f8d7c9e8f 100644
--- a/test/log/5400
+++ b/test/log/5400
@@ -52,3 +52,7 @@
1999-03-02 09:44:33 10HmbG-0005vi-00 >> userx@localhost4.test.ex R=dns T=smtp H=localhost4.test.ex [127.0.0.1] C="250 OK"
1999-03-02 09:44:33 10HmbG-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss for userx@localhost4.test.ex usery@thishost.test.ex
1999-03-02 09:44:33 10HmbG-0005vi-00 Completed
+1999-03-02 09:44:33 rcpt for userx@domain.com
+1999-03-02 09:44:33 10HmbH-0005vi-00 >> userx@domain.com R=all T=smtp H=127.0.0.1 [127.0.0.1] C="250 OK"
+1999-03-02 09:44:33 10HmbH-0005vi-00 <= CALLER@myhost.test.ex U=CALLER P=local-esmtp S=sss for userx@domain.com
+1999-03-02 09:44:33 10HmbH-0005vi-00 Completed
diff --git a/test/mail/4000.userx b/test/mail/4000.userx
index f59b904f3..486fb039d 100644
--- a/test/mail/4000.userx
+++ b/test/mail/4000.userx
@@ -303,6 +303,7 @@ Received: from CALLER (helo=test.ex)
for userx@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
Date: Tue, 2 Mar 1999 09:44:33 +0000
Message-ID: <20041217133501.GA3058@test.ex>
+Subject: Nasty5
Mime-Version: 1.0
Content-Type: multipart/mixed; boundary="T4sUOijqQbZv57TR"
From: CALLER_NAME <CALLER@myhost.test.ex>
@@ -360,3 +361,41 @@ Content-Disposition: attachment; filename*=ISO-8859-1''%74%65%73%74%20%E4%20%74%
--T4sUOijqQbZv57TR--
+From CALLER@myhost.test.ex Tue Mar 02 09:44:33 1999
+Received: from CALLER (helo=test.ex)
+ by myhost.test.ex with local-esmtp (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmbD-0005vi-00
+ for userx@test.ex; Tue, 2 Mar 1999 09:44:33 +0000
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+From: J Caesar <jcaesar@test.ex>
+To: a-list00@exim.org
+Message-ID: <20041217133502.GA3059@test.ex>
+Mime-Version: 1.0
+Content-Type: application/pdf;
+ name*=''2015.11.13%20-%20Pr%C3%A4sentation%20GI%20-%20LK.PDF
+Content-Disposition: attachment;
+ filename*=''2015.11.13%20-%20Pr%C3%A4sentation%20GI%20-%20LK.PDF
+Subject: Nasty6
+Sender: CALLER_NAME <CALLER@myhost.test.ex>
+X-0-content-type: application/pdf
+X-0-filename: 2015.11.13 - Präsentation GI - LK.PDF
+X-0-charset:
+X-0-boundary:
+X-0-content-disposition: attachment
+X-0-content-transfer-encoding:
+X-0-content-id:
+X-0-content-description:
+X-0-is-multipart: 0
+X-0-is-coverletter: 1
+X-0-is-rfc822: 0
+X-0-decode-filename: TESTSUITE/spool/scan/10HmbD-0005vi-00/10HmbD-0005vi-00-00000
+X-0-content-size: 1
+
+--T4sUOijqQbZv57TR
+Content-Type: text/plain;
+
+foobar
+
+--T4sUOijqQbZv57TR--
+
diff --git a/test/rejectlog/0610 b/test/rejectlog/0610
new file mode 100644
index 000000000..c1384b3de
--- /dev/null
+++ b/test/rejectlog/0610
@@ -0,0 +1,4 @@
+
+******** SERVER ********
+1999-03-02 09:44:33 H=[127.0.0.1] temporarily rejected connection in "connect" ACL
+1999-03-02 09:44:33 H=[127.0.0.2] temporarily rejected connection in "connect" ACL
diff --git a/test/scripts/0000-Basic/0610 b/test/scripts/0000-Basic/0610
new file mode 100644
index 000000000..ff690f63f
--- /dev/null
+++ b/test/scripts/0000-Basic/0610
@@ -0,0 +1,33 @@
+# retry: transport with fixed interface
+# Exim test configuration 0610
+#
+exim -DSERVER=server -bd -oX PORT_D
+****
+#
+exim -bs
+MAIL FROM:<t1@dustyshoes.tld>
+RCPT TO:<fred@anotherone.tld>
+DATA
+This is a test message.
+.
+RSET
+MAIL FROM:<t2@dustybelt.tld>
+RCPT TO:<fred@anotherone.tld>
+DATA
+Subject: second
+
+This is a second test message.
+.
+QUIT
+****
+#
+#
+exim -qq
+****
+#
+# Should get two separate retry records.
+dump retry
+#
+#
+killdaemon
+no_msglog_check
diff --git a/test/scripts/2200-dnsdb/2200 b/test/scripts/2200-dnsdb/2200
index 40837dbd0..9f6262524 100644
--- a/test/scripts/2200-dnsdb/2200
+++ b/test/scripts/2200-dnsdb/2200
@@ -49,3 +49,16 @@ defer_strict:ten-1 ${lookup dnsdb{defer_strict,a=test.again.dns:ten-1.te
delay1500 ${lookup dnsdb{retrans_1s,retry_2,a=delay1500.test.ex}}
****
+#
+# Cacheability
+exim -d-all+lookup -be
+a=localhost.test.ex ${lookup dnsdb{a=localhost.test.ex}{$value}fail}
+a=localhost.test.ex ${lookup dnsdb{a=localhost.test.ex}{$value}fail}
+****
+#
+# TTL-limited noncacheability
+exim -d-all+lookup -odq user@shorthost.test.ex
+****
+#
+no_msglog_check
+#
diff --git a/test/scripts/2200-dnsdb/2201 b/test/scripts/2200-dnsdb/2201
index 600298793..d432ca187 100644
--- a/test/scripts/2200-dnsdb/2201
+++ b/test/scripts/2200-dnsdb/2201
@@ -1,6 +1,24 @@
# query-style lookup in domains, local_parts, senders
+munge debug_pid
exim -d -bt test.ex@test.ex unknown@test.ex
****
2
exim -f a@b.c -bt test.ex@test.ex unknown@test.ex
****
+#
+#
+# lookup non/cacheability, lookup done as a list item
+exim -d-all+lookup -odq -f a@shorthost.test.ex t@test.ex
+****
+#
+#
+# lookup non/cacheability, lookup done for a dnslists= ACL condition
+exim -DSERVER=server -d-all+dnsbl -bd -oX PORT_D
+****
+exim -q
+****
+#
+killdaemon
+millisleep 500
+no_msglog_check
+#
diff --git a/test/scripts/4000-scanning/4000 b/test/scripts/4000-scanning/4000
index eda235b10..b29aed1e0 100644
--- a/test/scripts/4000-scanning/4000
+++ b/test/scripts/4000-scanning/4000
@@ -194,6 +194,7 @@ rcpt to:<userx@test.ex>
data
Date: Fri, 17 Dec 2004 14:35:01 +0100
Message-ID: <20041217133501.GA3058@test.ex>
+Subject: Nasty5
Mime-Version: 1.0
Content-Type: multipart/mixed; boundary="T4sUOijqQbZv57TR"
@@ -213,3 +214,32 @@ Content-Disposition: attachment; filename*=ISO-8859-1''%74%65%73%74%20%E4%20%74%
.
quit
****
+#
+#
+# This one has a legit param; empty charset
+#
+exim -odi -bs
+ehlo test.ex
+mail from:<>
+rcpt to:<userx@test.ex>
+data
+Date: Fri, 17 Dec 2004 14:35:01 +0100
+From: J Caesar <jcaesar@test.ex>
+To: a-list00@exim.org
+Message-ID: <20041217133502.GA3059@test.ex>
+Mime-Version: 1.0
+Content-Type: application/pdf;
+ name*=''2015.11.13%20-%20Pr%C3%A4sentation%20GI%20-%20LK.PDF
+Content-Disposition: attachment;
+ filename*=''2015.11.13%20-%20Pr%C3%A4sentation%20GI%20-%20LK.PDF
+Subject: Nasty6
+
+--T4sUOijqQbZv57TR
+Content-Type: text/plain;
+
+foobar
+
+--T4sUOijqQbZv57TR--
+.
+quit
+****
diff --git a/test/scripts/5400-cutthrough/5400 b/test/scripts/5400-cutthrough/5400
index 5344ba51c..109b43928 100644
--- a/test/scripts/5400-cutthrough/5400
+++ b/test/scripts/5400-cutthrough/5400
@@ -414,5 +414,39 @@ QUIT
#
#
#
+# data having line with (logical, doubled on wire) single dot
+server PORT_S
+220 ESMTP
+EHLO
+250 OK
+MAIL FROM:
+250 Sender OK
+RCPT TO:
+250 Recipient OK
+DATA
+354 Send data
+.
+250 OK
+QUIT
+250 OK
+****
+exim -bs -odf
+EHLO myhost.test.ex
+MAIL FROM:<CALLER@myhost.test.ex>
+RCPT TO:<userx@domain.com>
+DATA
+Subject: singledot test
+
+This data has a line with a single dot... next:
+..
+and this is the line right after.
+Next we have a line with a leading dot:
+..test
+and this is the next line.
+
+.
+QUIT
+****
+#
#
# End
diff --git a/test/src/fakens.c b/test/src/fakens.c
index a03f94a07..7e93979ec 100644
--- a/test/src/fakens.c
+++ b/test/src/fakens.c
@@ -61,6 +61,9 @@ Any DNS record line in a zone file 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.
+Any DNS record line in a zone file can be prefixed with "TTL=" and
+a number of seconds (followed by one space).
+
*/
#include <ctype.h>
@@ -105,6 +108,8 @@ typedef struct tlist {
int value;
} tlist;
+#define DEFAULT_TTL 3600U
+
/* On some (older?) operating systems, the standard ns_t_xxx definitions are
not available, and only the older T_xxx ones exist in nameser.h. If ns_t_a is
not defined, assume we are in this state. A really old system might not even
@@ -347,6 +352,7 @@ while (fgets(CS buffer, sizeof(buffer), f) != NULL)
BOOL rr_sec = FALSE;
BOOL rr_aa = FALSE;
int delay = 0;
+ uint ttl = DEFAULT_TTL;
p = buffer;
while (isspace(*p)) p++;
@@ -380,6 +386,12 @@ while (fgets(CS buffer, sizeof(buffer), f) != NULL)
for (p += 6; *p >= '0' && *p <= '9'; p++) delay = delay*10 + *p - '0';
if (isspace(*p)) p++;
}
+ else if (Ustrncmp(p, US"TTL=", 4) == 0) /* TTL for record */
+ {
+ ttl = 0;
+ for (p += 4; *p >= '0' && *p <= '9'; p++) ttl = ttl*10 + *p - '0';
+ if (isspace(*p)) p++;
+ }
else
break;
}
@@ -459,7 +471,10 @@ while (fgets(CS buffer, sizeof(buffer), f) != NULL)
*pk++ = 0;
*pk++ = 1; /* class = IN */
- pk += 4; /* TTL field; don't care */
+ *pk++ = (ttl >>24) & 255;
+ *pk++ = (ttl >>16) & 255;
+ *pk++ = (ttl >> 8) & 255;
+ *pk++ = ttl & 255;
rdlptr = pk; /* remember rdlength field */
pk += 2;
diff --git a/test/stderr/0143 b/test/stderr/0143
index 054d65d28..cff499045 100644
--- a/test/stderr/0143
+++ b/test/stderr/0143
@@ -15,7 +15,7 @@ transport_name <my_smtp>
my_smtp transport entered
userx@domain.com
checking status of 127.0.0.1
-127.0.0.1 [127.0.0.1]:1111 status = usable
+127.0.0.1 [127.0.0.1]:1111/ip4.ip4.ip4.ip4 status = usable
delivering 10HmaX-0005vi-00 to 127.0.0.1 [127.0.0.1] (userx@domain.com)
Connecting to 127.0.0.1 [127.0.0.1]:1224 from ip4.ip4.ip4.ip4 ... connected
SMTP<< 220 ESMTP
diff --git a/test/stderr/2200 b/test/stderr/2200
new file mode 100644
index 000000000..4fec895ea
--- /dev/null
+++ b/test/stderr/2200
@@ -0,0 +1,52 @@
+Exim version x.yz ....
+configuration file is TESTSUITE/test-config
+admin user
+search_open: dnsdb "NULL"
+search_find: file="NULL"
+ key="a=localhost.test.ex" partial=-1 affix=NULL starflags=0
+LRU list:
+internal_search_find: file="NULL"
+ type=dnsdb key="a=localhost.test.ex"
+database lookup required for a=localhost.test.ex
+dnsdb key: localhost.test.ex
+lookup yielded: 127.0.0.1
+search_open: dnsdb "NULL"
+ cached open
+search_find: file="NULL"
+ key="a=localhost.test.ex" partial=-1 affix=NULL starflags=0
+LRU list:
+internal_search_find: file="NULL"
+ type=dnsdb key="a=localhost.test.ex"
+cached data used for lookup of a=localhost.test.ex
+lookup yielded: 127.0.0.1
+search_tidyup called
+>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
+Exim version x.yz ....
+configuration file is TESTSUITE/test-config
+admin user
+search_tidyup called
+search_tidyup called
+search_open: dnsdb "NULL"
+search_find: file="NULL"
+ key="a=shorthost.test.ex" partial=-1 affix=NULL starflags=0
+LRU list:
+internal_search_find: file="NULL"
+ type=dnsdb key="a=shorthost.test.ex"
+database lookup required for a=shorthost.test.ex
+dnsdb key: shorthost.test.ex
+lookup yielded: 127.0.0.1
+search_open: dnsdb "NULL"
+ cached open
+search_find: file="NULL"
+ key="a=shorthost.test.ex" partial=-1 affix=NULL starflags=0
+LRU list:
+internal_search_find: file="NULL"
+ type=dnsdb key="a=shorthost.test.ex"
+cached data found but past valid time; database lookup required for a=shorthost.test.ex
+dnsdb key: shorthost.test.ex
+lookup yielded: 127.0.0.1
+LOG: MAIN
+ <= CALLER@myhost.test.ex U=CALLER P=local S=sss
+created log directory TESTSUITE/spool/log
+search_tidyup called
+>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
diff --git a/test/stderr/2201 b/test/stderr/2201
index 925d3c6f7..523ae4395 100644
--- a/test/stderr/2201
+++ b/test/stderr/2201
@@ -3,9 +3,11 @@ changed uid/gid: forcing real = effective
uid=uuuu gid=CALLER_GID pid=pppp
seeking password data for user "CALLER": cache not available
getpwnam() succeeded uid=CALLER_UID gid=CALLER_GID
+tls_validate_require_cipher child ppppp ended: status=0x0
configuration file is TESTSUITE/test-config
trusted user
admin user
+DSN: r0 propagating DSN
DSN: r1 propagating DSN
DSN: r2 propagating DSN
seeking password data for user "CALLER": using cached result
@@ -19,6 +21,12 @@ Testing test.ex@test.ex
Considering test.ex@test.ex
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
routing test.ex@test.ex
+--------> r0 router <--------
+local_part=test.ex domain=test.ex
+checking senders
+address match test: subject=CALLER@myhost.test.ex pattern=a@shorthost.test.ex
+CALLER@myhost.test.ex in "a@shorthost.test.ex"? no (end of list)
+r0 router skipped: senders mismatch
--------> r1 router <--------
local_part=test.ex domain=test.ex
checking domains
@@ -62,6 +70,12 @@ Testing unknown@test.ex
Considering unknown@test.ex
>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
routing unknown@test.ex
+--------> r0 router <--------
+local_part=unknown domain=test.ex
+checking senders
+address match test: subject=CALLER@myhost.test.ex pattern=a@shorthost.test.ex
+CALLER@myhost.test.ex in "a@shorthost.test.ex"? no (end of list)
+r0 router skipped: senders mismatch
--------> r1 router <--------
local_part=unknown domain=test.ex
checking domains
@@ -132,3 +146,84 @@ routed by r2 router
transport: local_delivery
search_tidyup called
>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
+Exim version x.yz ....
+configuration file is TESTSUITE/test-config
+trusted user
+admin user
+search_tidyup called
+search_tidyup called
+search_open: dnsdb "NULL"
+search_find: file="NULL"
+ key="a=shorthost.test.ex" partial=-1 affix=NULL starflags=0
+LRU list:
+internal_search_find: file="NULL"
+ type=dnsdb key="a=shorthost.test.ex"
+database lookup required for a=shorthost.test.ex
+dnsdb key: shorthost.test.ex
+lookup yielded: 127.0.0.1
+search_open: dnsdb "NULL"
+ cached open
+search_find: file="NULL"
+ key="a=shorthost.test.ex" partial=-1 affix=NULL starflags=0
+LRU list:
+internal_search_find: file="NULL"
+ type=dnsdb key="a=shorthost.test.ex"
+cached data used for lookup of a=shorthost.test.ex
+lookup yielded: 127.0.0.1
+search_open: dnsdb "NULL"
+ cached open
+search_find: file="NULL"
+ key="a=shorthost.test.ex" partial=-1 affix=NULL starflags=0
+LRU list:
+internal_search_find: file="NULL"
+ type=dnsdb key="a=shorthost.test.ex"
+cached data found but past valid time; database lookup required for a=shorthost.test.ex
+dnsdb key: shorthost.test.ex
+lookup yielded: 127.0.0.1
+LOG: MAIN
+ <= a@shorthost.test.ex U=CALLER P=local S=sss
+created log directory TESTSUITE/spool/log
+search_tidyup called
+>>>>>>>>>>>>>>>> Exim pid=pppp terminating with rc=0 >>>>>>>>>>>>>>>>
+
+******** SERVER ********
+Exim version x.yz ....
+configuration file is TESTSUITE/test-config
+trusted user
+admin user
+ppppp daemon_smtp_port overridden by -oX:
+ppppp <: 1225
+ppppp listening on all interfaces (IPv6) port 1225
+ppppp listening on all interfaces (IPv4) port 1225
+ppppp pid written to TESTSUITE/spool/exim-daemon.pid
+ppppp LOG: MAIN
+ppppp exim x.yz daemon started: pid=pppp, no queue runs, listening for SMTP on port 1225
+ppppp daemon running with uid=EXIM_UID gid=EXIM_GID euid=EXIM_UID egid=EXIM_GID
+ppppp Listening...
+ppppp Connection request from 127.0.0.1 port sssss
+ppppp 1 SMTP accept process running
+ppppp Listening...
+ppppp Process ppppp is handling incoming connection from [127.0.0.1]
+ppppp Process ppppp is ready for new message
+ppppp DNS list check: rbl.test.ex/V4NET.11.12.14
+ppppp new DNS lookup for 14.12.11.V4NET.rbl.test.ex
+ppppp DNS lookup for 14.12.11.V4NET.rbl.test.ex succeeded (yielding 127.0.0.2)
+ppppp => that means V4NET.11.12.14 is listed at rbl.test.ex
+ppppp DNS list check: rbl.test.ex/V4NET.11.12.14
+ppppp using result of previous DNS lookup
+ppppp DNS lookup for 14.12.11.V4NET.rbl.test.ex succeeded (yielding 127.0.0.2)
+ppppp => that means V4NET.11.12.14 is listed at rbl.test.ex
+ppppp DNS list check: rbl.test.ex/V4NET.11.12.14
+ppppp cached data found but past valid time; new DNS lookup for 14.12.11.V4NET.rbl.test.ex
+ppppp DNS lookup for 14.12.11.V4NET.rbl.test.ex succeeded (yielding 127.0.0.2)
+ppppp => that means V4NET.11.12.14 is listed at rbl.test.ex
+PDKIM >> Hashed body data, canonicalized >>>>>>>>>>>>>>>>>>>>>>>>>>>>>
+ppppp LOG: MAIN
+ppppp <= a@shorthost.test.ex H=localhost (myhost.test.ex) [127.0.0.1] P=esmtp S=sss id=E10HmaX-0005vi-00@myhost.test.ex
+ppppp Process ppppp is ready for new message
+ppppp LOG: smtp_connection MAIN
+ppppp SMTP connection from localhost (myhost.test.ex) [127.0.0.1] closed by QUIT
+ppppp child ppppp ended: status=0x0
+ppppp normal exit, 0
+ppppp 0 SMTP accept processes now running
+ppppp Listening...
diff --git a/test/stdout/0610 b/test/stdout/0610
new file mode 100644
index 000000000..24291b53f
--- /dev/null
+++ b/test/stdout/0610
@@ -0,0 +1,16 @@
+220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250 OK
+250 Accepted
+354 Enter message, ending with "." on a line by itself
+250 OK id=10HmaX-0005vi-00
+250 Reset OK
+250 OK
+250 Accepted
+354 Enter message, ending with "." on a line by itself
+250 OK id=10HmaY-0005vi-00
+221 the.local.host.name closing connection
++++++++++++++++++++++++++++
+ T:127.0.0.1:127.0.0.1:1225/127.0.0.1 0 65 H=127.0.0.1 [127.0.0.1]: SMTP error from remote mail server after initial connection: 451 Temporary local problem - please try later
+first failed = time last try = time2 next try = time2 + 10
+ T:127.0.0.1:127.0.0.1:1225/127.0.0.2 0 65 H=127.0.0.1 [127.0.0.1]: SMTP error from remote mail server after initial connection: 451 Temporary local problem - please try later
+first failed = time last try = time2 next try = time2 + 10
diff --git a/test/stdout/2200 b/test/stdout/2200
index b77594803..71ff12017 100644
--- a/test/stdout/2200
+++ b/test/stdout/2200
@@ -51,3 +51,6 @@ ten-2.test.ex
>
> delay1500 ip4.ip4.ip4.ip4
>
+> a=localhost.test.ex 127.0.0.1
+> a=localhost.test.ex 127.0.0.1
+>
diff --git a/test/stdout/3450.debian8 b/test/stdout/3450.debian8
new file mode 100644
index 000000000..bddcb4deb
--- /dev/null
+++ b/test/stdout/3450.debian8
@@ -0,0 +1,76 @@
+Connecting to ip4.ip4.ip4.ip4 port 1225 ... connected
+??? 220
+<<< 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+>>> ehlo foobar
+??? 250-
+<<< 250-myhost.test.ex Hello foobar [ip4.ip4.ip4.ip4]
+??? 250-
+<<< 250-SIZE 52428800
+??? 250-
+<<< 250-8BITMIME
+??? 250-
+<<< 250-PIPELINING
+??? 250-
+<<< 250-AUTH PLAIN
+??? 250-
+<<< 250-STARTTLS
+??? 250
+<<< 250 HELP
+>>> auth plain AHVzZXJ4AHNlY3JldA==
+??? 235
+<<< 235 Authentication succeeded
+>>> quit
+??? 221
+<<< 221 myhost.test.ex closing connection
+End of script
+Connecting to 127.0.0.1 port 1225 ... connected
+??? 220
+<<< 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+>>> ehlo foobar
+??? 250-
+<<< 250-myhost.test.ex Hello foobar [127.0.0.1]
+??? 250-
+<<< 250-SIZE 52428800
+??? 250-
+<<< 250-8BITMIME
+??? 250-
+<<< 250-PIPELINING
+??? 250-
+<<< 250-AUTH PLAIN
+??? 250-
+<<< 250-STARTTLS
+??? 250
+<<< 250 HELP
+>>> auth plain AHVzZXJ4AHNlY3JldA==
+??? 503
+<<< 503 STARTTLS required before AUTH
+>>> starttls
+??? 220
+<<< 220 TLS go ahead
+Attempting to start TLS
+SSL info: before/connect initialization
+SSL info: before/connect initialization
+SSL info: SSL negotiation finished successfully
+SSL info: SSL negotiation finished successfully
+SSL connection using AES256-SHA
+Succeeded in starting TLS
+>>> ehlo foobar
+??? 250-
+<<< 250-myhost.test.ex Hello foobar [127.0.0.1]
+??? 250-
+<<< 250-SIZE 52428800
+??? 250-
+<<< 250-8BITMIME
+??? 250-
+<<< 250-PIPELINING
+??? 250-
+<<< 250-AUTH PLAIN
+??? 250
+<<< 250 HELP
+>>> auth plain AHVzZXJ4AHNlY3JldA==
+??? 235
+<<< 235 Authentication succeeded
+>>> quit
+??? 221
+<<< 221 myhost.test.ex closing connection
+End of script
diff --git a/test/stdout/3454.debian8 b/test/stdout/3454.debian8
new file mode 100644
index 000000000..66dc56386
--- /dev/null
+++ b/test/stdout/3454.debian8
@@ -0,0 +1,80 @@
+Connecting to 127.0.0.1 port 1225 ... connected
+??? 220
+<<< 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+>>> ehlo foobar
+??? 250-myhost
+<<< 250-myhost.test.ex Hello foobar [127.0.0.1]
+??? 250-SIZE
+<<< 250-SIZE 52428800
+??? 250-8BITMIME
+<<< 250-8BITMIME
+??? 250-PIPELINING
+<<< 250-PIPELINING
+??? 250-AUTH
+<<< 250-AUTH PLAIN
+??? 250-STARTTLS
+<<< 250-STARTTLS
+??? 250 HELP
+<<< 250 HELP
+>>> starttls
+??? 220 TLS
+<<< 220 TLS go ahead
+Attempting to start TLS
+SSL info: before/connect initialization
+SSL info: before/connect initialization
+SSL info: SSL negotiation finished successfully
+SSL info: SSL negotiation finished successfully
+SSL connection using AES256-SHA
+Succeeded in starting TLS
+>>> auth plain AHVzZXJ4AHNlY3JldA==
+??? 503
+<<< 503 AUTH command used when not advertised
+End of script
+Connecting to 127.0.0.1 port 1225 ... connected
+??? 220
+<<< 220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+>>> ehlo foobar
+??? 250-myhost
+<<< 250-myhost.test.ex Hello foobar [127.0.0.1]
+??? 250-SIZE
+<<< 250-SIZE 52428800
+??? 250-8BITMIME
+<<< 250-8BITMIME
+??? 250-PIPELINING
+<<< 250-PIPELINING
+??? 250-AUTH
+<<< 250-AUTH PLAIN
+??? 250-STARTTLS
+<<< 250-STARTTLS
+??? 250 HELP
+<<< 250 HELP
+>>> starttls
+??? 220 TLS
+<<< 220 TLS go ahead
+Attempting to start TLS
+SSL info: before/connect initialization
+SSL info: before/connect initialization
+SSL info: SSL negotiation finished successfully
+SSL info: SSL negotiation finished successfully
+SSL connection using AES256-SHA
+Succeeded in starting TLS
+>>> ehlo foobar
+??? 250-myhost
+<<< 250-myhost.test.ex Hello foobar [127.0.0.1]
+??? 250-SIZE
+<<< 250-SIZE 52428800
+??? 250-8BITMIME
+<<< 250-8BITMIME
+??? 250-PIPELINING
+<<< 250-PIPELINING
+??? 250-AUTH
+<<< 250-AUTH PLAIN
+??? 250 HELP
+<<< 250 HELP
+>>> auth plain AHVzZXJ4AHNlY3JldA==
+??? 235
+<<< 235 Authentication succeeded
+>>> quit
+??? 221
+<<< 221 myhost.test.ex closing connection
+End of script
diff --git a/test/stdout/4000 b/test/stdout/4000
index 95511480e..c1e2b2450 100644
--- a/test/stdout/4000
+++ b/test/stdout/4000
@@ -64,3 +64,14 @@
354 Enter message, ending with "." on a line by itself
250 OK id=10HmbC-0005vi-00
221 myhost.test.ex closing connection
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-myhost.test.ex Hello CALLER at test.ex
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250 HELP
+250 OK
+250 Accepted
+354 Enter message, ending with "." on a line by itself
+250 OK id=10HmbD-0005vi-00
+221 myhost.test.ex closing connection
diff --git a/test/stdout/5400 b/test/stdout/5400
index 05f2ef037..20de2df09 100644
--- a/test/stdout/5400
+++ b/test/stdout/5400
@@ -115,6 +115,17 @@
354 Enter message, ending with "." on a line by itself
250 OK id=10HmbG-0005vi-00
221 myhost.test.ex closing connection
+220 myhost.test.ex ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000
+250-myhost.test.ex Hello CALLER at myhost.test.ex
+250-SIZE 52428800
+250-8BITMIME
+250-PIPELINING
+250 HELP
+250 OK
+250 Accepted
+354 Enter message, ending with "." on a line by itself
+250 OK id=10HmbH-0005vi-00
+221 myhost.test.ex closing connection
******** SERVER ********
Listening on port 1224 ...
@@ -508,3 +519,37 @@ Date: Tue, 2 Mar 1999 09:44:33 +0000
QUIT
250 OK
End of script
+Listening on port 1224 ...
+Connection request from [ip4.ip4.ip4.ip4]
+220 ESMTP
+EHLO myhost.test.ex
+250 OK
+MAIL FROM:<CALLER@myhost.test.ex>
+250 Sender OK
+RCPT TO:<userx@domain.com>
+250 Recipient OK
+DATA
+354 Send data
+Received: from CALLER (helo=myhost.test.ex)
+ by myhost.test.ex with local-esmtp (Exim x.yz)
+ (envelope-from <CALLER@myhost.test.ex>)
+ id 10HmbH-0005vi-00
+ for userx@domain.com; Tue, 2 Mar 1999 09:44:33 +0000
+Subject: singledot test
+Message-Id: <E10HmbH-0005vi-00@myhost.test.ex>
+From: CALLER_NAME <CALLER@myhost.test.ex>
+Date: Tue, 2 Mar 1999 09:44:33 +0000
+X-hdr-rtr-new: +++
+
+This data has a line with a single dot... next:
+..
+and this is the line right after.
+Next we have a line with a leading dot:
+..test
+and this is the next line.
+
+.
+250 OK
+QUIT
+250 OK
+End of script