transport dynamic modules
authorJeremy Harris <jgh146exb@wizmail.org>
Thu, 15 Aug 2024 13:53:22 +0000 (14:53 +0100)
committerJeremy Harris <jgh146exb@wizmail.org>
Thu, 15 Aug 2024 13:53:22 +0000 (14:53 +0100)
21 files changed:
doc/doc-docbook/spec.xfpt
doc/doc-txt/NewStuff
src/scripts/Configure-Makefile
src/scripts/MakeLinks
src/scripts/drivers-Makefile [new file with mode: 0755]
src/scripts/routers-Makefile [deleted file]
src/src/EDITME
src/src/drtables.c
src/src/globals.h
src/src/route.c
src/src/routers/Makefile
src/src/transport.c
src/src/transports/Makefile
src/src/transports/appendfile.c
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
test/confs/0000
test/runtest

index 84597da830f56e7f0286787f13ce71607fcc0726..9fbf7a2db31bf9b29a21d872a97c5d9790928cc8 100644 (file)
@@ -2072,6 +2072,7 @@ withdrawn.
 .section "Dynamically loaded module support" "SECTdynamicmodules"
 .cindex "lookup modules"
 .cindex "router modules"
+.cindex "transport modules"
 .cindex "dynamic modules"
 .cindex ".so building"
 On some platforms, Exim supports not compiling all lookup types directly into
@@ -2083,7 +2084,7 @@ dependencies.
 Most, but not all, lookup types can be built this way.
 
 .new
-Similarly, router drivers can be built as external modules.
+Similarly, router and transport drivers can be built as external modules.
 This permits a smaller exim binary, growing only as needed for the
 runtime cofiguration.
 .wen
index bb7f2290e201a4c4683873c354b7d5a43b18b3a4..be0f0c679643daa6745039c77ad88e437deaf59b 100644 (file)
@@ -14,8 +14,8 @@ Version 4.98
 
  3. Events smtp:fail:protocol and smtp:fail:syntax
 
- 4. JSON lookup support, and all the router driver except manualroute,
-    can now be built as lodable modules
+ 4. JSON lookup support, all the router drivers except manualroute, and all the transport
+    drivers except smtp can now be built as lodable modules
 
 Version 4.98
 ------------
index 3b0528940ff311a0f73e6d2f86b04830f409006e..20e686b51d84f6c058731d4740d321ee36564afb 100755 (executable)
@@ -10,6 +10,7 @@
 
 LC_ALL=C
 export LC_ALL
+set -e
 
 
 # First off, get the OS type, and check that there is a make file for it.
@@ -291,12 +292,16 @@ rm -f $mftt
 cp ../src/lookups/Makefile $look_mf_pre
 ../scripts/lookups-Makefile
 
-class="routers"
-cp ../src/$class/Makefile $class/Makefile.predynamic
-../scripts/$class-Makefile
-mv routers/Makefile.postdynamic $class/Makefile
-rm $class/Makefile.predynamic
-class=
+while read class classdef names
+do
+  cp ../src/$class/Makefile $class/Makefile.predynamic
+  CLASS=$class CLASSDEF=$classdef DRNAMES="$names" ../scripts/drivers-Makefile
+  mv $class/Makefile.postdynamic $class/Makefile
+  rm $class/Makefile.predynamic
+done <<-END
+ routers ROUTER                ACCEPT DNSLOOKUP IPLITERAL IPLOOKUP MANUALROUTE QUERYPROGRAM REDIRECT
+ transports TRANSPORT  APPENDFILE AUTOREPLY LMTP PIPE QUEUEFILE SMTP
+END
 
 # See if there is a definition of EXIM_PERL in what we have built so far.
 # If so, run Perl to find the default values for PERL_CC, PERL_CCOPTS,
index f413c625edb11a1bd763a97089f372d4771d86e3..998b73bf9f7e199c5c97fb20a19125337bdb6ae9 100755 (executable)
@@ -63,7 +63,8 @@ cd ..
 d="transports"
 mkdir $d
 cd $d
-for f in README Makefile appendfile.h appendfile.c autoreply.h \
+# Makefile is generated
+for f in README appendfile.h appendfile.c autoreply.h \
   autoreply.c lmtp.h lmtp.c pipe.h pipe.c queuefile.c queuefile.h \
   smtp.h smtp.c smtp_socks.c tf_maildir.c tf_maildir.h
 do
diff --git a/src/scripts/drivers-Makefile b/src/scripts/drivers-Makefile
new file mode 100755 (executable)
index 0000000..0c3da19
--- /dev/null
@@ -0,0 +1,176 @@
+#! /bin/sh
+
+# Copyright (c) The Exim Maintainers 1995 - 2024
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+set -e
+class=${CLASS:?}
+classdef=${CLASSDEF:?}
+drnames="${DRNAMES:?}"
+
+# We turn the configure-built build-$foo/$class/Makefile.predynamic into Makefile.
+# This is used for router and transport drivers, called from scripts/Configure-Makefile.
+
+# We always re-exec ourselves at least once, because it's the cleanest and
+# most portable way to turn on various features we expect of POSIX sh.
+if [ -z "$EXIM_DRIVER_MAKEFILE_ADJUSTED" ]
+then
+  SHELL=/bin/sh
+  EXIM_DRIVER_MAKEFILE_ADJUSTED=yes
+  export EXIM_DRIVER_MAKEFILE_ADJUSTED
+
+  # Solaris sh and tr are problematic until we get xpg4 variants
+  if [ -x /usr/xpg4/bin/sh ]
+  then
+    PATH="/usr/xpg4/bin:$PATH"
+    export PATH
+    SHELL=/usr/xpg4/bin/sh
+    export SHELL
+  fi
+
+  # IRIX uses /bin/ksh for sh but in a compatibility mode unless $_XPG == 1,
+  # where said compatibility mode disables $(...)
+  _XPG=1
+  export _XPG
+
+  # We need the _right_ tr, so must do that first; but if a shell which
+  # we're more confident is sane is available, let's try that.  Mostly,
+  # the problem is that "local" is not actually in "the" standard, it's
+  # just in every not-insane shell.  Though arguably, there are no shells
+  # with POSIX-ish syntax which qualify as "not insane".
+  for b in /bin/dash /bin/bash /usr/local/bin/bash
+  do
+    if [ -x "$b" ]
+    then
+      SHELL="$b"
+      break
+    fi
+  done
+  # if we get a report of a system with zsh but not bash, we can add that
+  # to the list, but be sure to enable sh_word_split in that case.
+
+  exec "$SHELL" "$0" "$@"
+fi
+
+input=$class/Makefile.predynamic
+target=$class/Makefile.postdynamic
+defs_source=Makefile-t
+tag_marker='MAGIC-TAG-MODS-OBJ-RULES-GO-HERE'
+
+tab='  '
+
+# We rely on tr(1) for translating case below.  Some people export
+# values of LC_CTYPE and LC_COLLATE which apparently break our assumptions.
+# We're a script expecting certain output based on known inputs and not dealing
+# with UTF8, so we should be safe doing this:
+LC_ALL=C
+export LC_ALL
+
+if [ -f "$defs_source" ]
+then
+  :
+  # we are happy
+else
+  echo >&2 "$0: ERROR: MISSING FILE '${defs_source}'"
+  echo >&2 "$0: SHOULD HAVE BEEN CALLED FROM scripts/Configure-Makefile"
+  exit 1
+fi
+
+# nb: do not permit leading whitespace for this, as CFLAGS_DYNAMIC is exported
+# to the lookups subdir via a line with leading whitespace which otherwise
+# matches
+if grep -q "^CFLAGS_DYNAMIC[ $tab?:]*=" "$defs_source"
+then
+  # we have a definition, we're good to go
+  echo >&2 ">>> Creating $class/Makefile for building dynamic modules"
+  enable_dynamic=yes
+else
+  echo >&2 ">>> Creating $class/Makefile without dynamic module support"
+  enable_dynamic=''
+  # We always do something now, since there should always be a lookup,
+  # and now we need to run in order to put the OBJ=$(OBJ)+ rules in.  So we
+  # continue on.
+fi
+
+# For the want_ checks, we need to let the user override values from the make
+# command-line, not just check the Makefile.
+
+want_dynamic() {
+  local dyn_name="$1"
+  local re="(${classdef}|EXPERIMENTAL)_${dyn_name}[ $tab]*=[ $tab]*2"
+  env | grep -E -q "^$re"
+  if [ $? -eq 0 ]; then return 0; fi
+  grep -E -q "^[ $tab]*$re" "$defs_source"
+}
+
+want_at_all() {
+  local want_name="$1"
+  local re="(${classdef}|EXPERIMENTAL)_${want_name}[ $tab]*=[ $tab]*."
+  env | grep -E -q "^$re"
+  if [ $? -eq 0 ]; then return 0; fi
+  grep -E -q "^[ $tab]*$re" "$defs_source"
+}
+
+# The values of these variables will be emitted into the Makefile.
+
+MODS=""
+OBJ=""
+
+emit_module_rule() {
+  local name="$1"
+  local mod_name pkgconf
+  if [ "${name%:*}" = "$name" ]
+  then
+    # Square brackets are redundant but benign for POSIX compliant tr,
+    # however Solaris /usr/bin/tr requires them. Sometimes Solaris
+    # gets installed without a complete set of xpg4 tools, sigh.
+    mod_name=$(echo $name | tr [A-Z] [a-z])
+  else
+    mod_name="${name#*:}"
+    name="${name%:*}"
+  fi
+
+  if want_dynamic "$name"
+  then
+    if [ -z "$enable_dynamic" ]; then
+      echo >&2 "Missing CFLAGS_DYNAMIC prevents building dynamic $name"
+      exit 1
+    fi
+    MODS="${MODS} ${mod_name}.so"
+#    pkgconf=$(grep "^${classdef}_${name}_PC" "$defs_source")
+#    if [ $? -eq 0 ]; then
+#      pkgconf=$(echo $pkgconf | sed 's/^.*= *//')
+#      echo "${classdef}_${mod_name}_INCLUDE = $(pkg-config --cflags $pkgconf)"
+#      echo "${classdef}_${mod_name}_LIBS = $(pkg-config --libs $pkgconf)"
+#    else
+#      grep "^${classdef}_${name}_" "$defs_source"
+#      echo "${classdef}_${mod_name}_INCLUDE = \$(${classdef}_${name}_INCLUDE)"
+#      echo "${classdef}_${mod_name}_LIBS = \$(${classdef}_${name}_LIBS)"
+#    fi
+  elif want_at_all "$name"
+  then
+    OBJ="${OBJ} ${mod_name}.o"
+  fi
+}
+
+rm -f "$target"
+exec 5>&1
+exec > "$target"
+
+sed -n "1,/$tag_marker/p" < "$input"
+
+for name_mod in $drnames
+do
+  emit_module_rule $name_mod
+done
+
+echo "MODS = $MODS"
+echo "OBJ = $OBJ"
+
+sed -n "/$tag_marker/,\$p" < "$input"
+
+exec >&5
+
+# Configure-Makefile will move $target into place
+
+# vim: set ft=sh sw=2 :
diff --git a/src/scripts/routers-Makefile b/src/scripts/routers-Makefile
deleted file mode 100755 (executable)
index 5bb6a78..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-#! /bin/sh
-
-# Copyright (c) The Exim Maintainers 1995 - 2021
-# SPDX-License-Identifier: GPL-2.0-or-later
-
-# We turn the configure-built build-$foo/routers/Makefile.predynamic into Makefile
-
-# We always re-exec ourselves at least once, because it's the cleanest and
-# most portable way to turn on various features we expect of POSIX sh.
-if [ -z "$EXIM_ROUTER_MAKEFILE_ADJUSTED" ]
-then
-  SHELL=/bin/sh
-  EXIM_ROUTER_MAKEFILE_ADJUSTED=yes
-  export EXIM_ROUTER_MAKEFILE_ADJUSTED
-
-  # Solaris sh and tr are problematic until we get xpg4 variants
-  if [ -x /usr/xpg4/bin/sh ]
-  then
-    PATH="/usr/xpg4/bin:$PATH"
-    export PATH
-    SHELL=/usr/xpg4/bin/sh
-    export SHELL
-  fi
-
-  # IRIX uses /bin/ksh for sh but in a compatibility mode unless $_XPG == 1,
-  # where said compatibility mode disables $(...)
-  _XPG=1
-  export _XPG
-
-  # We need the _right_ tr, so must do that first; but if a shell which
-  # we're more confident is sane is available, let's try that.  Mostly,
-  # the problem is that "local" is not actually in "the" standard, it's
-  # just in every not-insane shell.  Though arguably, there are no shells
-  # with POSIX-ish syntax which qualify as "not insane".
-  for b in /bin/dash /bin/bash /usr/local/bin/bash
-  do
-    if [ -x "$b" ]
-    then
-      SHELL="$b"
-      break
-    fi
-  done
-  # if we get a report of a system with zsh but not bash, we can add that
-  # to the list, but be sure to enable sh_word_split in that case.
-
-  exec "$SHELL" "$0" "$@"
-fi
-
-input=routers/Makefile.predynamic
-target=routers/Makefile.postdynamic
-defs_source=Makefile-t
-tag_marker='MAGIC-TAG-MODS-OBJ-RULES-GO-HERE'
-
-tab='  '
-
-# We rely on tr(1) for translating case below.  Some people export
-# values of LC_CTYPE and LC_COLLATE which apparently break our assumptions.
-# We're a script expecting certain output based on known inputs and not dealing
-# with UTF8, so we should be safe doing this:
-LC_ALL=C
-export LC_ALL
-
-if [ -f "$defs_source" ]
-then
-  :
-  # we are happy
-else
-  echo >&2 "$0: ERROR: MISSING FILE '${defs_source}'"
-  echo >&2 "$0: SHOULD HAVE BEEN CALLED FROM scripts/Configure-Makefile"
-  exit 1
-fi
-
-# nb: do not permit leading whitespace for this, as CFLAGS_DYNAMIC is exported
-# to the lookups subdir via a line with leading whitespace which otherwise
-# matches
-if grep -q "^CFLAGS_DYNAMIC[ $tab?:]*=" "$defs_source"
-then
-  # we have a definition, we're good to go
-  echo >&2 ">>> Creating routers/Makefile for building dynamic modules"
-  enable_dynamic=yes
-else
-  echo >&2 ">>> Creating routers/Makefile without dynamic module support"
-  enable_dynamic=''
-  # We always do something now, since there should always be a lookup,
-  # and now we need to run in order to put the OBJ=$(OBJ)+ rules in.  So we
-  # continue on.
-fi
-
-# For the want_ checks, we need to let the user override values from the make
-# command-line, not just check the Makefile.
-
-want_dynamic() {
-  local dyn_name="$1"
-  local re="ROUTER_${dyn_name}[ $tab]*=[ $tab]*2"
-  env | grep -q "^$re"
-  if [ $? -eq 0 ]; then return 0; fi
-  grep -q "^[ $tab]*$re" "$defs_source"
-}
-
-want_at_all() {
-  local want_name="$1"
-  local re="ROUTER_${want_name}[ $tab]*=[ $tab]*."
-  env | grep -q "^$re"
-  if [ $? -eq 0 ]; then return 0; fi
-  grep -q "^[ $tab]*$re" "$defs_source"
-}
-
-# Adapted want_at_all above to work for EXPERIMENTAL features
-want_experimental() {
-  local want_name="$1"
-  local re="EXPERIMENTAL_${want_name}[ $tab]*=[ $tab]*."
-  env | grep -q "^$re"
-  if [ $? -eq 0 ]; then return 0; fi
-  grep -q "^[ $tab]*$re" "$defs_source"
-}
-
-# The values of these variables will be emitted into the Makefile.
-
-MODS=""
-OBJ=""
-
-emit_module_rule() {
-  local name="$1"
-  local mod_name pkgconf
-  if [ "${name%:*}" = "$name" ]
-  then
-    # Square brackets are redundant but benign for POSIX compliant tr,
-    # however Solaris /usr/bin/tr requires them. Sometimes Solaris
-    # gets installed without a complete set of xpg4 tools, sigh.
-    mod_name=$(echo $name | tr [A-Z] [a-z])
-  else
-    mod_name="${name#*:}"
-    name="${name%:*}"
-  fi
-
-  if want_dynamic "$name"
-  then
-    if [ -z "$enable_dynamic" ]; then
-      echo >&2 "Missing CFLAGS_DYNAMIC prevents building dynamic $name"
-      exit 1
-    fi
-    MODS="${MODS} ${mod_name}.so"
-#    pkgconf=$(grep "^ROUTER_${name}_PC" "$defs_source")
-#    if [ $? -eq 0 ]; then
-#      pkgconf=$(echo $pkgconf | sed 's/^.*= *//')
-#      echo "ROUTER_${mod_name}_INCLUDE = $(pkg-config --cflags $pkgconf)"
-#      echo "ROUTER_${mod_name}_LIBS = $(pkg-config --libs $pkgconf)"
-#    else
-#      grep "^ROUTER_${name}_" "$defs_source"
-#      echo "ROUTER_${mod_name}_INCLUDE = \$(ROUTER_${name}_INCLUDE)"
-#      echo "ROUTER_${mod_name}_LIBS = \$(ROUTER_${name}_LIBS)"
-#    fi
-  elif want_at_all "$name"
-  then
-    OBJ="${OBJ} ${mod_name}.o"
-  fi
-}
-
-rm -f "$target"
-exec 5>&1
-exec > "$target"
-
-sed -n "1,/$tag_marker/p" < "$input"
-
-for name_mod in \
-    ACCEPT DNSLOOKUP IPLITERAL IPLOOKUP MANUALROUTE QUERYPROGRAM REDIRECT
-do
-  emit_module_rule $name_mod
-done
-
-echo "MODS = $MODS"
-echo "OBJ = $OBJ"
-
-sed -n "/$tag_marker/,\$p" < "$input"
-
-exec >&5
-
-# Configure-Makefile will move $target into place
-
-# vim: set ft=sh sw=2 :
index 5e755692fd5b878abf14b4b2e067a630ea6f6960..820793032de4fb087dc8ad3c41a167cfa5502b7c 100644 (file)
@@ -344,6 +344,15 @@ ROUTER_REDIRECT=yes
 # file. By commenting out those you know you don't want to use, you can make
 # the binary a bit smaller. If you are unsure, leave all of these included for
 # now.
+#
+# If set to "2" instead of "yes" then the corresponding driver will be
+# built as a module and must be installed into LOOKUP_MODULE_DIR (the name
+# is historic).
+# You need to add -export-dynamic -rdynamic to EXTRALIBS. You may also need to
+# add -ldl to EXTRALIBS so that dlopen() is available to Exim. You need to
+# define CFLAGS_DYNAIC and LOOKUP_MODULE_DIR below so the builds are done right,
+# and so the exim binary actually loads dynamic lookup modules.
+# The smtp transport cannot be built as a module.
 
 TRANSPORT_APPENDFILE=yes
 TRANSPORT_AUTOREPLY=yes
index b514090966b7f2843dbf9ae14052ad9c9af83d5e..026f2ff97b712b7d71b5a682747e155d57fffe56 100644 (file)
@@ -230,134 +230,11 @@ exim binary. */
 
 #include "routers/rf_functions.h"
 
-#ifdef TRANSPORT_APPENDFILE
-# include "transports/appendfile.h"
-#endif
-
-#ifdef TRANSPORT_AUTOREPLY
-# include "transports/autoreply.h"
-#endif
-
-#ifdef TRANSPORT_LMTP
-# include "transports/lmtp.h"
-#endif
-
-#ifdef TRANSPORT_PIPE
-# include "transports/pipe.h"
-#endif
-
-#ifdef EXPERIMENTAL_QUEUEFILE
-# include "transports/queuefile.h"
-#endif
-
-#ifdef TRANSPORT_SMTP
-# include "transports/smtp.h"
-#endif
-
 
 router_info * routers_available = NULL;
+transport_info * transports_available = NULL;
 
 
-transport_info * transports_available_newlist = NULL;
-transport_info transports_available_oldarray[] = {
-#ifdef TRANSPORT_APPENDFILE
-  {
-  .drinfo = {
-    .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
-  {
-  .drinfo = {
-    .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
-  {
-  .drinfo = {
-    .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
-  {
-  .drinfo = {
-    .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
-  {
-  .drinfo = {
-    .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
-  {
-  .drinfo = {
-    .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
-  { .drinfo = { .driver_name = US"" }}
-};
 
 #ifndef MACRO_PREDEF
 
@@ -429,35 +306,69 @@ return g;
 gstring *
 transport_show_supported(gstring * g)
 {
-g = string_cat(g, US"Transports:");
-#ifdef TRANSPORT_APPENDFILE
-  g = string_cat(g, US" appendfile");
-  #ifdef SUPPORT_MAILDIR
-    g = string_cat(g, US"/maildir");   /* damn these subclasses */
-  #endif
-  #ifdef SUPPORT_MAILSTORE
-    g = string_cat(g, US"/mailstore");
-  #endif
-  #ifdef SUPPORT_MBX
-    g = string_cat(g, US"/mbx");
-  #endif
-#endif
-#ifdef TRANSPORT_AUTOREPLY
-  g = string_cat(g, US" autoreply");
-#endif
-#ifdef TRANSPORT_LMTP
-  g = string_cat(g, US" lmtp");
-#endif
-#ifdef TRANSPORT_PIPE
-  g = string_cat(g, US" pipe");
-#endif
-#ifdef EXPERIMENTAL_QUEUEFILE
-  g = string_cat(g, US" queuefile");
-#endif
-#ifdef TRANSPORT_SMTP
-  g = string_cat(g, US" smtp");
+uschar * b = US""              /* static-build transportnames */
+#if defined(TRANSPORT_APPENDFILE) && TRANSPORT_APPENDFILE!=2
+  " appendfile"
+ifdef SUPPORT_MAILDIR
+    "/maildir"
+endif
+ifdef SUPPORT_MAILSTORE
+    "/mailstore"
+endif
+ifdef SUPPORT_MBX
+    "/mbx"
+endif
+#endif
+#if defined(TRANSPORT_AUTOREPLY) && TRANSPORT_AUTOREPLY!=2
+  " autoreply"
+#endif
+#if defined(TRANSPORT_LMTP) && TRANSPORT_LMTP!=2
+  " lmtp"
+#endif
+#if defined(TRANSPORT_PIPE) && TRANSPORT_PIPE!=2
+  " pipe"
+#endif
+#if defined(EXPERIMENTAL_QUEUEFILE) && EXPERIMENTAL_QUEUEFILE!=2
+  " queuefile"
+#endif
+#if defined(TRANSPORT_SMTP) && TRANSPORT_SMTP!=2
+  " smtp"
 #endif
-return string_cat(g, US"\n");
+  ;
+
+uschar * d = US""              /* dynamic-module transportnames */
+#if defined(TRANSPORT_APPENDFILE) && TRANSPORT_APPENDFILE==2
+  " appendfile"
+# ifdef SUPPORT_MAILDIR
+    "/maildir"
+# endif
+# ifdef SUPPORT_MAILSTORE
+    "/mailstore"
+# endif
+# ifdef SUPPORT_MBX
+    "/mbx"
+# endif
+#endif
+#if defined(TRANSPORT_AUTOREPLY) && TRANSPORT_AUTOREPLY==2
+  " autoreply"
+#endif
+#if defined(TRANSPORT_LMTP) && TRANSPORT_LMTP==2
+  " lmtp"
+#endif
+#if defined(TRANSPORT_PIPE) && TRANSPORT_PIPE==2
+  " pipe"
+#endif
+#if defined(EXPERIMENTAL_QUEUEFILE) && EXPERIMENTAL_QUEUEFILE==2
+  " queuefile"
+#endif
+#if defined(TRANSPORT_SMTP) && TRANSPORT_SMTP==2
+  " smtp"
+#endif
+  ;
+
+if (*b) g = string_fmt_append(g, "Transports (built-in):%s\n", b);
+if (*d) g = string_fmt_append(g, "Transports (dynamic): %s\n", d);
+return g;
 }
 
 
index 6bca06c00999ade79137a7f6f424fbf5a7527bf9..7fc888f5baee4bf12cace4603418817eb5a1c5f2 100644 (file)
@@ -1111,10 +1111,9 @@ extern int     transport_newlines;     /* Accurate count of number of newline ch
 extern const uschar **transport_filter_argv; /* For on-the-fly filtering */
 extern int     transport_filter_timeout; /* Timeout for same */
 
-extern transport_info transports_available_oldarray[]; /* Vector of available transports */
-extern transport_info * transports_available_newlist;
-extern transport_instance *transports; /* Chain of instantiated transports */
-extern transport_instance transport_defaults; /* Default values */
+extern transport_info * transports_available;  /* Listof available transports */
+extern transport_instance *transports;         /* Chain of instantiated transports */
+extern transport_instance transport_defaults;  /* Default values */
 
 extern int     transport_write_timeout;/* Set to time out individual writes */
 
index 07f0a6b20d9635e23f58d474398be9f011e2a420..293d21c50b7f2b4118fdc80e0e1be5129b35dfa4 100644 (file)
@@ -227,7 +227,6 @@ function. */
 void
 route_init(void)
 {
-
 int old_pool = store_pool;
 store_pool = POOL_PERM;
   {
index d13a493e9d4f8b448f815242b9c9311f9615d2db..8ff3d81ab17ca7983aa89e2a052268dcc1c3dcf3 100644 (file)
@@ -7,7 +7,7 @@
 
 # nb: at build time, the version of this file used will have had some
 #     extra variable definitions and prepended to it and module build rules
-#     interpolated below. This is done by scripts/routers-Makefile.
+#     interpolated below. This is done by scripts/drivers-Makefile.
 
 # MAGIC-TAG-MODS-OBJ-RULES-GO-HERE
 
index e42625ce82e6b0051132e3cb01f9c3a18b5f6f97..063fda3617f60baed0b671cecec1812b20817d38 100644 (file)
@@ -102,8 +102,7 @@ uschar buf[64];
 
 options_from_list(optionlist_transports, nelem(optionlist_transports), US"TRANSPORTS", NULL);
 
-//for (transport_info * ti= transports_available; ti->drinfo.driver_name[0]; ti++)
-for (driver_info * di= (driver_info *)transports_available_newlist; di; di = di->next)
+for (driver_info * di= (driver_info *)transports_available; di; di = di->next)
   {
   spf(buf, sizeof(buf), US"_DRIVER_TRANSPORT_%T", di->driver_name);
   builtin_macro_create(buf);
@@ -146,21 +145,51 @@ the work. */
 void
 transport_init(void)
 {
-for (transport_info * tblent = transports_available_oldarray;
-    *tblent->drinfo.driver_name; tblent++)
+int old_pool = store_pool;
+store_pool = POOL_PERM;
   {
-  driver_info * listent = store_get(sizeof(transport_info), tblent);
-  memcpy(listent, tblent, sizeof(transport_info));
-  listent->next = (driver_info *)transports_available_newlist;
-  transports_available_newlist = (transport_info *)listent;
+  driver_info ** anchor = (driver_info **) &transports_available;
+  extern transport_info appendfile_transport_info;
+  extern transport_info autoreply_transport_info;
+  extern transport_info lmtp_transport_info;
+  extern transport_info pipe_transport_info;
+  extern transport_info queuefile_transport_info;
+  extern transport_info smtp_transport_info;
+
+  /* Add the transport drivers that are built for static linkage to the
+  list of availables. */
+
+#if defined(TRANSPORT_APPENDFILE) && TRANSPORT_APPENDFILE!=2
+  add_driver_info(anchor, &appendfile_transport_info.drinfo, sizeof(transport_info));
+#endif
+#if defined(TRANSPORT_AUTOREPLY) && TRANSPORT_AUTOREPLY!=2
+  add_driver_info(anchor, &autoreply_transport_info.drinfo, sizeof(transport_info));
+#endif
+#if defined(TRANSPORT_LMTP) && TRANSPORT_LMTP!=2
+  add_driver_info(anchor, &lmtp_transport_info.drinfo, sizeof(transport_info));
+#endif
+#if defined(TRANSPORT_PIPE) && TRANSPORT_PIPE!=2
+  add_driver_info(anchor, &pipe_transport_info.drinfo, sizeof(transport_info));
+#endif
+#if defined(EXPERIMENTAL_QUEUEFILE) && EXPERIMENTAL_QUEUEFILE!=2
+  add_driver_info(anchor, &queuefile_transport_info.drinfo, sizeof(transport_info));
+#endif
+#if defined(TRANSPORT_SMTP) && TRANSPORT_SMTP!=2
+  add_driver_info(anchor, &smtp_transport_info.drinfo, sizeof(transport_info));
+#endif
   }
+store_pool = old_pool;
+
+/* Read the config file "transports" section, creating a transportsinstance list.
+For any yet-undiscovered driver, check for a loadable module and add it to
+those available. */
 
 readconf_driver_init((driver_instance **)&transports,     /* chain anchor */
-  (driver_info **)&transports_available_newlist,   /* available drivers */
-  sizeof(transport_info),                /* size of info block */
-  &transport_defaults,                   /* default values for generic options */
-  sizeof(transport_instance),            /* size of instance block */
-  optionlist_transports,                 /* generic options */
+  (driver_info **)&transports_available, /* available drivers */
+  sizeof(transport_info),              /* size of info block */
+  &transport_defaults,                 /* default values for generic options */
+  sizeof(transport_instance),          /* size of instance block */
+  optionlist_transports,               /* generic options */
   optionlist_transports_size,
   US"transport");
 
index 4eea141ec9481a6d8d21adbacb7e8d3dcc19c326..8f759ecf010fba6da59fe2f69b13f5476633e80a 100644 (file)
@@ -1,8 +1,16 @@
 # Make file for building a library containing all the available transports and
 # calling it transports.a. This is called from the main make file, after cd'ing
 # to the transports subdirectory.
+#
+# Copyright (c) The Exim Maintainers 2021 - 2024
 
-OBJ = appendfile.o autoreply.o lmtp.o pipe.o queuefile.o smtp.o smtp_socks.o tf_maildir.o
+# nb: at build time, the version of this file used will have had some
+#     extra variable definitions and prepended to it and module build rules
+#     interpolated below. This is done by scripts/drivers-Makefile.
+
+# MAGIC-TAG-MODS-OBJ-RULES-GO-HERE
+
+all:           transports.a $(MODS)
 
 transports.a:    $(OBJ)
                 @$(RM_COMMAND) -f transports.a
@@ -10,18 +18,40 @@ transports.a:    $(OBJ)
                 @$(AR) transports.a $(OBJ)
                 $(RANLIB) $@
 
-.SUFFIXES:       .o .c
+.SUFFIXES:       .o .c .so
 .c.o:;           @echo "$(CC) $*.c"
                 $(FE)$(CC) -c $(CFLAGS) $(INCLUDE) $*.c
 
-appendfile.o:    $(HDRS) appendfile.c appendfile.h tf_maildir.h
-autoreply.o:     $(HDRS) autoreply.c autoreply.h
-lmtp.o:          $(HDRS) lmtp.c lmtp.h
-pipe.o:          $(HDRS) pipe.c pipe.h
-queuefile.o:     $(HDRS) queuefile.c queuefile.h
-smtp.o:          $(HDRS) smtp.c smtp.h
-smtp_socks.o:    $(HDRS) smtp_socks.c smtp.h
+.c.so:;          @echo "$(CC) -shared $*.c"
+                $(FE)$(CC) -DDYNLOOKUP $(CFLAGS_DYNAMIC) $(CFLAGS) $(INCLUDE) $(DLFLAGS) $*.c -o $@
+
+
+$(OBJ) $(MOD): $(HDRS)
+
+autoreply.o autoreply.so:      autoreply.c autoreply.h
+lmtp.o lmtp.so:                        lmtp.c lmtp.h
+pipe.o pipe.so:                        pipe.c pipe.h
+queuefile.o queuefile.so:      queuefile.c queuefile.h
+
+
+# These ones depend on more than one .c source
+
+appendfile.o:  appendfile.c appendfile.h tf_maildir.c tf_maildir.h
+       @echo "$(CC) appendfile.c tf_maildir.c"
+       $(FE)$(CC) $(CFLAGS) $(INCLUDE) appendfile.c tf_maildir.c -r -o $@
+
+appendfile.so: appendfile.c appendfile.h tf_maildir.c tf_maildir.h
+       @echo "$(CC) -shared appendfile.c tf_maildir.c"
+       $(FE)$(CC) -DDYNLOOKUP $(CFLAGS_DYNAMIC) $(CFLAGS) $(INCLUDE) $(DLFLAGS) \
+               appendfile.c tf_maildir.c -o $@
+
+smtp.o:        smtp.c smtp_socks.c smtp.h
+       @echo "$(CC) smtp.c smtp_socks.c"
+       $(FE)$(CC) $(CFLAGS) $(INCLUDE) smtp.c smtp_socks.c -r -o $@
 
-tf_maildir.o:    $(HDRS) tf_maildir.c tf_maildir.h appendfile.h
+smtp.so: smtp.c smtp_socks.c smtp.h
+       @echo "$(CC) -shared smtp.c smtp_socks.c"
+       $(FE)$(CC) -DDYNLOOKUP $(CFLAGS_DYNAMIC) $(CFLAGS) $(INCLUDE) $(DLFLAGS) \
+               smtp.c smtp_socks.c -o $@
 
 # End
index 14ef13c97d9c43488f33468b924717b0c4e33d30..08a59543c5bfcd96fd63103305c235b84f71114b 100644 (file)
@@ -3319,6 +3319,31 @@ ret_panic:
   return FALSE;
 }
 
+
+
+
+# ifdef DYNLOOKUP
+#  define appendfile_transport_info _transport_info
+# endif
+
+transport_info appendfile_transport_info = {
+.drinfo = {
+  .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,
+# ifdef DYNLOOKUP
+  .dyn_magic =         TRANSPORT_MAGIC,
+# endif
+  },
+.code =                appendfile_transport_entry,
+.tidyup =      NULL,
+.closedown =   NULL,
+.local =       TRUE
+};
+
 #endif /*!MACRO_PREDEF*/
 #endif /*TRANSPORT_APPENDFILE*/
 /* End of transport/appendfile.c */
index a6080695e07333dd677c0c2cf1e0ee797178709f..9223bc791d4b8b1ea895e9bf0ef2fc8025d93648 100644 (file)
@@ -806,6 +806,31 @@ DEBUG(D_transport) debug_printf("%s transport succeeded\n", trname);
 return FALSE;
 }
 
+
+
+
+# ifdef DYNLOOKUP
+#  define autoreply_transport_info _transport_info
+# endif
+
+transport_info autoreply_transport_info = {
+.drinfo = {
+  .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,
+# ifdef DYNLOOKUP
+  .dyn_magic =         TRANSPORT_MAGIC,
+# endif
+  },
+.code =                autoreply_transport_entry,
+.tidyup =      NULL,
+.closedown =   NULL,
+.local =       TRUE
+};
+
 #endif /*!MACRO_PREDEF*/
 #endif /*TRANSPORT_AUTOREPOL*/
 /* End of transport/autoreply.c */
index ae92952924b7855a636dc7034f7bdd36474fc638..1bff274c1ad64700cec3f83cad960fef8e172aca 100644 (file)
@@ -808,6 +808,31 @@ MINUS_N:
   return FALSE;
 }
 
+
+
+
+# ifdef DYNLOOKUP
+#  define lmtp_transport_info _transport_info
+# endif
+
+transport_info lmtp_transport_info = {
+.drinfo = {
+  .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,
+# ifdef DYNLOOKUP
+  .dyn_magic =         TRANSPORT_MAGIC,
+# endif
+  },
+.code =                lmtp_transport_entry,
+.tidyup =      NULL,
+.closedown =   NULL,
+.local =       TRUE
+};
+
 #endif /*!MACRO_PREDEF*/
 #endif /*TRANSPORT_LMTP*/
 /* End of transport/lmtp.c */
index 1b90c43149288297342907ee26818e44557573b6..b765eeae5cdf1bc82ba3e0c19d5f7c4a24699752 100644 (file)
@@ -1128,6 +1128,31 @@ if (addr->transport_return != OK)
 return FALSE;
 }
 
+
+
+
+# ifdef DYNLOOKUP
+#  define pipe_transport_info _transport_info
+# endif
+
+transport_info pipe_transport_info = {
+.drinfo = {
+  .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,
+# ifdef DYNLOOKUP
+  .dyn_magic =         TRANSPORT_MAGIC,
+# endif
+  },
+.code =                pipe_transport_entry,
+.tidyup =      NULL,
+.closedown =   NULL,
+.local =       TRUE
+};
+
 #endif /*!MACRO_PREDEF*/
 #endif /*TRASPORT_PIPE*/
 /* End of transport/pipe.c */
index 2c35b3145ef683c8f1abea6443e23709b9e27e66..64031e55db41701ebe8e26b4f41ded6a547c3027 100644 (file)
@@ -285,5 +285,30 @@ put in the first address of a batch. */
 return FALSE;
 }
 
+
+
+
+# ifdef DYNLOOKUP
+#  define queuefile_transport_info _transport_info
+# endif
+
+transport_info queuefile_transport_info = {
+.drinfo = {
+  .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,
+# ifdef DYNLOOKUP
+  .dyn_magic =         TRANSPORT_MAGIC,
+# endif
+  },
+.code =                queuefile_transport_entry,
+.tidyup =      NULL,
+.closedown =   NULL,
+.local =       TRUE
+};
+
 #endif /*!MACRO_PREDEF*/
 #endif /*EXPERIMENTAL_QUEUEFILE*/
index 25858d982117544e2bc4ef135688aa29781c235d..d25a2b1f64e292234040d609689cb6fb123cbca0 100644 (file)
@@ -6230,6 +6230,31 @@ DEBUG(D_transport) debug_printf("Leaving %s transport\n", trname);
 return TRUE;   /* Each address has its status */
 }
 
+
+
+
+# ifdef DYNLOOKUP
+#  define smtp_transport_info _transport_info
+# endif
+
+transport_info smtp_transport_info = {
+.drinfo = {
+  .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,
+# ifdef DYNLOOKUP
+  .dyn_magic =         TRANSPORT_MAGIC,
+# endif
+  },
+.code =                smtp_transport_entry,
+.tidyup =      NULL,
+.closedown =   smtp_transport_closedown,
+.local =       FALSE
+};
+
 #endif /*!MACRO_PREDEF*/
 /* vi: aw ai sw=2
 */
index 795701bd778dd58830e19d68f17581a1df379254..5db8ac8cfbeab242298742fe0be8c0a2701482b4 100644 (file)
@@ -11,5 +11,6 @@ tls_advertise_hosts =
 keep_environment =
 
 begin routers
+begin transports
 
 # End
index 2922335511654bc68864ddb9a7efe6c3e48d5375..6326723249c1da38e2a8b01c4deb44fc39bf5d83 100755 (executable)
@@ -1164,7 +1164,7 @@ RESET_AFTER_EXTRA_LINE_READ:
                  | Lookups(?:\(built-in\))?:
                  | Support\ for:
                  | Routers\ \((?:built-in|dynamic)\):
-                 | Transports:
+                 | Transports\ \((?:built-in|dynamic)\):
                  | Malware:
                  | log\ selectors\ =
                  | cwd=
@@ -3754,7 +3754,7 @@ while (<EXIMINFO>)
     print;
     @temp = split /(\s+)/, $1;
     push(@temp, ' ');
-    my %temp_routers= @temp;
+    my %temp_routers = @temp;
     @parm_routers{keys %temp_routers} = values %temp_routers;
     }
 
@@ -3762,13 +3762,15 @@ while (<EXIMINFO>)
   # that the basic transport name is set, and then the name with each of the
   # options.
 
-  elsif (/^Transports: (.*)/)
+  elsif (/^Transports \((?:built-in|dynamic)\): (.*)/)
     {
     print;
     @temp = split /(\s+)/, $1;
     my($i,$k);
     push(@temp, ' ');
-    %parm_transports = @temp;
+    my %temp_transports = @temp;
+    @parm_transports{keys %temp_transports} = values %temp_transports;
+
     foreach $k (keys %parm_transports)
       {
       if ($k =~ "/")