--- /dev/null
+From e5be948a65fe601024e5d4256f64efbfed3dd72e Mon Sep 17 00:00:00 2001
+From: Jeremy Harris <jgh146exb@wizmail.org>
+Date: Mon, 18 Mar 2019 00:31:43 +0000
+Subject: [PATCH 4/5] Logging: fix initial listening-on log line
+
+(cherry picked from commit 254f38d1c5ada5e4df0bccb385dc466549620c71)
+---
+ doc/ChangeLog | 4 +++
+ src/daemon.c | 73 +++++++++++++++++++++++++++----------------
+ src/host.c | 1 +
+ src/structs.h | 1 +
+ test/confs/0282 | 2 +-
+ test/log/0282 | 2 +-
+ 6 files changed, 54 insertions(+), 29 deletions(-)
+
+diff --git a/doc/ChangeLog b/doc/ChangeLog
+index 0f8d05b2..3c0ffbf0 100644
+--- a/doc/ChangeLog
++++ b/doc/ChangeLog
+@@ -23,10 +23,14 @@ JB/01 Bug 2375: fix expansions of 822 addresses having comments in local-part
+
+ JH/08 Add hardening against SRV & TLSA lookups the hit CNAMEs (a nonvalid
+ configuration). If a CNAME target was not a wellformed name pattern, a
+ crash could result.
+
++JH/09 Logging: Fix initial listening-on line for multiple ports for an IP when
++ the OS reports them interleaved with other addresses.
++
++
+
+ Exim version 4.92
+ -----------------
+
+ JH/01 Remove code calling the customisable local_scan function, unless a new
+diff --git a/src/daemon.c b/src/daemon.c
+index a852192e..01da3936 100644
+--- a/src/daemon.c
++++ b/src/daemon.c
+@@ -1625,12 +1625,12 @@ if (f.inetd_wait_mode)
+ else if (f.daemon_listen)
+ {
+ int i, j;
+ int smtp_ports = 0;
+ int smtps_ports = 0;
+- ip_address_item * ipa, * i2;
+- uschar * p = big_buffer;
++ ip_address_item * ipa;
++ uschar * p;
+ uschar * qinfo = queue_interval > 0
+ ? string_sprintf("-q%s", readconf_printtime(queue_interval))
+ : US"no queue runs";
+
+ /* Build a list of listening addresses in big_buffer, but limit it to 10
+@@ -1638,73 +1638,92 @@ else if (f.daemon_listen)
+
+ It is now possible to have some ports listening for SMTPS (the old,
+ deprecated protocol that starts TLS without using STARTTLS), and others
+ listening for standard SMTP. Keep their listings separate. */
+
+- for (j = 0; j < 2; j++)
++ for (int j = 0, i; 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. */
++ SMTPS ports. Build IP+port strings. */
+
+ 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;
+- }
+- }
++ smtp_ports++;
+ else
+- if (smtps_ports++ == 0)
+- p += sprintf(CS p, "%sSMTPS on",
+- smtp_ports == 0 ? "" : " and for ");
++ smtps_ports++;
+
+ /* 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)
+ {
+- p += sprintf(CS p, " port %d (IPv6 and IPv4)", ipa->port);
+- ipa = ipa->next;
++ ipa->log = string_sprintf(" port %d (IPv6 and IPv4)", ipa->port);
++ (ipa = ipa->next)->log = NULL;
+ }
+ else if (ipa->v6_include_v4)
+- p += sprintf(CS p, " port %d (IPv6 with IPv4)", ipa->port);
++ ipa->log = string_sprintf(" port %d (IPv6 with IPv4)", ipa->port);
+ else
+- p += sprintf(CS p, " port %d (IPv6)", ipa->port);
++ ipa->log = string_sprintf(" port %d (IPv6)", ipa->port);
+ }
+ else if (ipa->address[0] == 0) /* v4 wildcard */
+- p += sprintf(CS p, " port %d (IPv4)", ipa->port);
++ ipa->log = string_sprintf(" port %d (IPv4)", ipa->port);
+ else /* check for previously-seen IP */
+ {
++ ip_address_item * i2;
+ 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);
++ for (p = i2->log; *p; ) p++; /* end of existing string */
++ if (*--p == '}') *p = '\0'; /* drop EOL */
++ while (isdigit(*--p)) ; /* char before port */
++
++ i2->log = *p == ':' /* no list yet? */
++ ? string_sprintf("%.*s{%s,%d}",
++ (int)(p - i2->log + 1), i2->log, p+1, ipa->port)
++ : string_sprintf("%s,%d}", i2->log, ipa->port);
++ ipa->log = NULL;
+ break;
+ }
+ if (i2 == ipa) /* first-time IP */
+- p += sprintf(CS p, " [%s]:%d", ipa->address, ipa->port);
++ ipa->log = string_sprintf(" [%s]:%d", ipa->address, ipa->port);
+ }
+ }
+ }
++ }
+
+- if (ipa)
++ p = big_buffer;
++ for (int j = 0, i; j < 2; j++)
++ {
++ /* First time round, look for SMTP ports; second time round, look for
++ SMTPS ports. For the first one of each, insert leading text. */
++
++ if (j == 0)
+ {
+- memcpy(p, " ...", 5);
+- p += 4;
++ if (smtp_ports > 0)
++ p += sprintf(CS p, "SMTP on");
+ }
++ 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) */
++
++ for (i = 0, ipa = addresses; i < 10 && ipa; i++, ipa = ipa->next)
++ if (host_is_tls_on_connect_port(ipa->port) == (j > 0))
++ if (ipa->log)
++ p += sprintf(CS p, "%s", ipa->log);
++
++ if (ipa)
++ p += sprintf(CS p, " ...");
+ }
+
+ log_write(0, LOG_MAIN,
+ "exim %s daemon started: pid=%d, %s, listening for %s",
+ version_string, getpid(), qinfo, big_buffer);
+diff --git a/src/host.c b/src/host.c
+index 29c977fe..a3b0977b 100644
+--- a/src/host.c
++++ b/src/host.c
+@@ -757,10 +757,11 @@ while ((s = string_nextinlist(&list, &sep, NULL, 0)))
+ next = store_get(sizeof(ip_address_item));
+ next->next = NULL;
+ Ustrcpy(next->address, s);
+ next->port = port;
+ next->v6_include_v4 = FALSE;
++ next->log = NULL;
+
+ if (!yield)
+ yield = last = next;
+ else
+ {
+diff --git a/src/structs.h b/src/structs.h
+index 20db0e5f..1e63d752 100644
+--- a/src/structs.h
++++ b/src/structs.h
+@@ -442,10 +442,11 @@ hold an IPv6 address. */
+ typedef struct ip_address_item {
+ struct ip_address_item *next;
+ int port;
+ BOOL v6_include_v4; /* Used in the daemon */
+ uschar address[46];
++ uschar * log; /* portion of "listening on" log line */
+ } ip_address_item;
+
+ /* Structure for chaining together arbitrary strings. */
+
+ typedef struct string_item {
+--
+2.20.1
+