diff --git a/CHANGES b/CHANGES
index 8a6c673bc9c4f0ecf5b25e4d01c094f052505a2c..39e70cea51d884765e54a1a5c3c6548e9352c994 100644
--- a/CHANGES
+++ b/CHANGES
@@ -24,6 +24,17 @@ chan_sip
 --- Functionality changes from Asterisk 14.0.0 to Asterisk 14.1.0 ----------
 ------------------------------------------------------------------------------
 
+Build System
+------------------
+ * The res_digium_phone, codec_g729a, codec_silk, codec_siren7 and
+   codec_siren14 binary modules hosted at downloads.digium.com can now be
+   automatically downloaded and installed during the Asterisk install
+   process.  If selected in menuselect, when 'make install' is run, the
+   script will check the downloads site for a new version and download
+   and install it if needed.  The '--with-externals-cache' option to
+   ./configure can be used to specify a location to cache the latest
+   tarballs so they don't have to be re-downloaded for every install.
+
 app_voicemail
 ------------------
  * Added "tps_queue_high" and "tps_queue_low" options.
diff --git a/Makefile b/Makefile
index bf8f0f89a11237238b263fae6acc46fbc1fc9d6c..992e1d3019a32e8ae1d7da1d06e8c2df3c06e70c 100644
--- a/Makefile
+++ b/Makefile
@@ -618,9 +618,10 @@ $(SUBDIRS_INSTALL):
 
 NEWMODS:=$(foreach d,$(MOD_SUBDIRS),$(notdir $(wildcard $(d)/*.so)))
 OLDMODS=$(filter-out $(NEWMODS) $(notdir $(DESTDIR)$(ASTMODDIR)),$(notdir $(wildcard $(DESTDIR)$(ASTMODDIR)/*.so)))
+BADMODS=$(strip $(filter-out $(shell ./build_tools/list_valid_installed_externals),$(OLDMODS)))
 
 oldmodcheck:
-	@if [ -n "$(OLDMODS)" ]; then \
+	@if [ -n "$(BADMODS)" ]; then \
 		echo " WARNING WARNING WARNING" ;\
 		echo "" ;\
 		echo " Your Asterisk modules directory, located at" ;\
@@ -630,7 +631,7 @@ oldmodcheck:
 		echo " modules are compatible with this version before" ;\
 		echo " attempting to run Asterisk." ;\
 		echo "" ;\
-		for f in $(OLDMODS); do \
+		for f in $(BADMODS); do \
 			echo "    $$f" ;\
 		done ;\
 		echo "" ;\
@@ -980,7 +981,7 @@ menuselect/nmenuselect: menuselect/makeopts .lastclean
 menuselect/makeopts: makeopts .lastclean
 	+$(MAKE_MENUSELECT) makeopts
 
-menuselect-tree: $(foreach dir,$(filter-out main,$(MOD_SUBDIRS)),$(wildcard $(dir)/*.c) $(wildcard $(dir)/*.cc)) build_tools/cflags.xml build_tools/cflags-devmode.xml sounds/sounds.xml build_tools/embed_modules.xml utils/utils.xml agi/agi.xml configure makeopts
+menuselect-tree: $(foreach dir,$(filter-out main,$(MOD_SUBDIRS)),$(wildcard $(dir)/*.c) $(wildcard $(dir)/*.cc) $(wildcard $(dir)/*.xml)) build_tools/cflags.xml build_tools/cflags-devmode.xml sounds/sounds.xml build_tools/embed_modules.xml utils/utils.xml agi/agi.xml configure makeopts
 	@echo "Generating input for menuselect ..."
 	@echo "<?xml version=\"1.0\"?>" > $@
 	@echo >> $@
diff --git a/Makefile.moddir_rules b/Makefile.moddir_rules
index 9b5f3f13a27828c3ed4b37f9a1c95ac4888d597c..95e62788f2fb80052b11e52d9f050a6713b1b1bb 100644
--- a/Makefile.moddir_rules
+++ b/Makefile.moddir_rules
@@ -146,6 +146,18 @@ clean::
 install:: all
 	@echo "Installing modules from `basename $(CURDIR)`..."
 	@for x in $(LOADABLE_MODS:%=%.so); do $(INSTALL) -m 755 $$x "$(DESTDIR)$(ASTMODDIR)" ; done
+ifneq ($(findstring :,$(XMLSTARLET)$(BASH)),:)
+	@if [ -f .moduleinfo ] ; then \
+		declare -A DISABLED_MODS ;\
+		for x in $(MENUSELECT_$(MENUSELECT_CATEGORY)) ; do DISABLED_MODS[$${x}]=1 ; done ;\
+		EXTERNAL_MODS=$$(xmlstarlet sel -t -m "/category/member[support_level = 'external']" -v "@name" -n .moduleinfo) ;\
+		for x in $${EXTERNAL_MODS} ; do \
+			if [ -z "$${DISABLED_MODS[$${x}]}" ] ; then \
+				$(ASTTOPDIR)/build_tools/download_externals $${x} ;\
+			fi ;\
+		done ;\
+	fi
+endif
 
 uninstall::
 
diff --git a/build_tools/download_externals b/build_tools/download_externals
new file mode 100755
index 0000000000000000000000000000000000000000..8d5872df7994d13b76eebed77946044e723c4aab
--- /dev/null
+++ b/build_tools/download_externals
@@ -0,0 +1,180 @@
+#!/usr/bin/env bash
+
+if [[ ( ${BASH_VERSINFO[0]} == 4 && ${BASH_VERSINFO[1]} > 1 ) || ${BASH_VERSINFO[0]} > 4 ]] ; then
+	shopt -s compat41
+fi
+set -e
+
+ASTTOPDIR=${ASTTOPDIR:-.}
+
+module_name=$1
+
+if [[ -z ${module_name} ]] ; then
+	echo "You must supply a module name."
+	exit 64
+fi
+
+tmpdir=$(mktemp -d)
+if [[ -z "${tmpdir}" ]] ; then
+	echo "${module_name}: Unable to create temporary directory."
+	exit 1
+fi
+trap "rm -rf ${tmpdir}" EXIT
+
+sed -r -e "s/^([^ =]+)\s*=\s*(.*)$/\1=\"\2\"/g" ${ASTTOPDIR}/makeopts >${tmpdir}/makeopts
+source ${tmpdir}/makeopts
+if [[ -z "${ASTMODDIR}" ]] ; then
+	echo "${module_name}: Unable to parse ${ASTTOPDIR}/makeopts."
+	exit 1
+fi
+
+XMLSTARLET=${XMLSTARLET:-xmlstarlet}
+if [[ "${XMLSTARLET}" = ":" ]] ; then
+	echo "${module_name}: The externals downloader requires xmlstarlet to be installed."
+	exit 1
+fi
+
+cache_dir="${EXTERNALS_CACHE_DIR}"
+if [[ -z ${cache_dir} ]] ; then
+	cache_dir=${tmpdir}
+fi
+
+version=$(${ASTTOPDIR}/build_tools/make_version ${ASTTOPDIR})
+if [[ ! ${version} =~ ^(GIT-)?([^.-]+)[.-].* ]] ; then
+	echo "${module_name}: Couldn't parse version ${version}"
+	exit 1
+fi
+major_version=${BASH_REMATCH[2]}
+
+if [[ "${major_version}" == "master" ]] ; then
+	echo "${module_name}: External module downloading is not available in the 'master' git branch.  Please disable in menuselect and download manually."
+	exit 1
+fi
+
+major_version=${major_version}.0
+
+if [[ "${HOST_CPU}" = "x86_64" ]] ; then
+	host_bits=64
+else
+	host_bits=32
+fi
+
+remote_url=$(${XMLSTARLET} sel -t -v "/menu/category/member[@name = '${module_name}']/member_data/downloader/@remote_url" ${ASTTOPDIR}/menuselect-tree || :)
+if [[ -n "${remote_url}" ]] ; then
+	remote_url="${remote_url}/asterisk-${major_version}/x86-${host_bits}"
+else
+	directory_name=$(${XMLSTARLET} sel -t -v "/menu/category/member[@name = '${module_name}']/member_data/downloader/@directory_name" ${ASTTOPDIR}/menuselect-tree || :)
+	remote_url="http://downloads.digium.com/pub/telephony/${directory_name:-${module_name}}/asterisk-${major_version}/x86-${host_bits}"
+fi
+
+version_convert() {
+	local v=${1##*_}
+	if [[ ${v} =~ ([0-9]+)[.]([0-9]+)[.]([0-9]+) ]] ; then
+		v=$(( ${BASH_REMATCH[1]}<<18 | ${BASH_REMATCH[2]}<<9 | ${BASH_REMATCH[3]} ))
+	fi
+	echo ${v}
+}
+
+${WGET} -q -O ${tmpdir}/manifest.xml ${remote_url}/manifest.xml || {
+	echo "${module_name}: Unable to fetch ${remote_url}/manifest.xml"
+	exit 1
+}
+
+rpv=$(${XMLSTARLET} sel -t -v "/package/@version" ${tmpdir}/manifest.xml)
+rpvi=$(version_convert ${rpv})
+echo "${module_name}: Remote package version ${rpv} (${rpvi})"
+
+module_dir=${module_name}-${rpv}-x86_${host_bits}
+tarball=${module_dir}.tar.gz
+export need_install=0
+
+if [[ -f ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml ]] ; then
+	package_arch=$(${XMLSTARLET} sel -t -v "/package/@arch" ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml)
+	ipv=$(${XMLSTARLET} sel -t -v "/package/@version" ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml)
+	ipvi=$(version_convert ${ipv})
+	ip_major=${ipv%_*}
+	echo "${module_name}: Installed package version ${ipv} (${ipvi})"
+	if [[ "${ip_major}" != "${major_version}" || "${package_arch}" != "x86_${host_bits}" ]] ; then
+		echo "${module_name}: The installed package is not for this version of Asterisk.  Reinstalling."
+		need_install=1
+	elif [[ ${rpvi} > ${ipvi} ]] ; then
+		echo "${module_name}: A newer package is available"
+		need_install=1
+	else
+		sums=$(${XMLSTARLET} sel -t -m "//file" -v "@md5sum" -n ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml)
+		for sum in ${sums} ; do
+			install_path=$(${XMLSTARLET} sel -t -v "//file[@md5sum = '${sum}']/@install_path" ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml )
+			f=${DESTDIR}$(eval echo ${install_path})
+			if [[ ! -f ${f} ]] ; then
+				echo Not found: ${f}
+				need_install=1
+			else
+				cs=$(md5sum ${f} | cut -b1-32)
+				if [[ "${cs}" !=  "${sum}" ]] ; then
+					echo Checksum mismatch: ${f}
+					need_install=1
+				fi
+			fi
+		done
+	fi
+else
+	need_install=1
+fi
+
+if [[ ${need_install} == 1 ]] ; then
+	if [[ ( -n "${ipvi}" ) && ${ipvi} > ${rpvi} ]] ; then
+		echo "${module_name}: Installed package is newer than that available for download."
+		exit 0
+	fi
+else
+	echo "${module_name} is up to date."
+	exit 0;
+fi
+
+need_download=1
+if [[ -f ${cache_dir}/${module_name}.manifest.xml ]] ; then
+	cpv=$(${XMLSTARLET} sel -t -v "/package/@version" ${cache_dir}/${module_name}.manifest.xml)
+	cpvi=$(version_convert ${cpv})
+	echo "${module_name}: Cached package version ${cpv} (${cpvi})"
+	if [[ ${cpvi} == ${rpvi} && ( -f ${cache_dir}/${tarball} ) ]] ; then
+		echo "${module_name}: Cached version is available."
+		need_download=0
+	fi
+fi
+
+if [[ ${need_download} = 1 ]] ; then
+	echo "${module_name}: Downloading ${remote_url}/${tarball}"
+	${WGET} -q -O ${cache_dir}/${tarball} ${remote_url}/${tarball} || {
+		echo "${module_name}: Unable to fetch ${remote_url}/${tarball}"
+		exit 1
+	}
+	cp ${tmpdir}/manifest.xml  ${cache_dir}/${module_name}.manifest.xml
+fi
+
+tar -xzf ${cache_dir}/${tarball} -C ${cache_dir}
+trap "rm -rf ${cache_dir}/${module_dir} ; rm -rf ${tmpdir}" EXIT
+
+echo "${module_name}: Installing."
+
+if [[ $EUID == 0 ]] ; then
+	install_params="--group=0 --owner=0"
+fi
+
+names=$(${XMLSTARLET} sel -t -m "//file" -v "@name" -n ${cache_dir}/${module_dir}/manifest.xml)
+for name in ${names} ; do
+	source_path=${cache_dir}/${module_dir}/${name}
+	install_path=$(${XMLSTARLET} sel -t -v "//file[@name = '${name}']/@install_path" ${cache_dir}/${module_dir}/manifest.xml)
+	install_path=${DESTDIR}$(eval echo ${install_path})
+	executable=$(${XMLSTARLET} sel -t -v "//file[@name = '${name}']/@executable" ${cache_dir}/${module_dir}/manifest.xml || :)
+	if [[ "${executable}" = "yes" ]] ; then
+		mode=0755
+	else
+		mode=0644
+	fi
+
+	${INSTALL} -Dp ${install_params} --mode=${mode} ${source_path} ${install_path}
+
+done
+${INSTALL} -Dp ${install_params} --mode=0644 ${cache_dir}/${module_dir}/manifest.xml ${DESTDIR}${ASTMODDIR}/${module_name}.manifest.xml
+
+echo "${module_name}: Installed."
diff --git a/build_tools/list_valid_installed_externals b/build_tools/list_valid_installed_externals
new file mode 100755
index 0000000000000000000000000000000000000000..12aff3f95a05657f04857505ff4d697b57d9bf80
--- /dev/null
+++ b/build_tools/list_valid_installed_externals
@@ -0,0 +1,55 @@
+#!/usr/bin/env bash
+
+if [[ ( ${BASH_VERSINFO[0]} == 4 && ${BASH_VERSINFO[1]} > 1 ) || ${BASH_VERSINFO[0]} > 4 ]] ; then
+	shopt -s compat41
+fi
+set -e
+
+ASTTOPDIR=${ASTTOPDIR:-.}
+
+tmpdir=$(mktemp -d)
+if [[ -z "${tmpdir}" ]] ; then
+	echo "${module_name}: Unable to create temporary directory."
+	exit 1
+fi
+trap "rm -rf ${tmpdir}" EXIT
+
+sed -r -e "s/^([^ =]+)\s*=\s*(.*)$/\1=\"\2\"/g" ${ASTTOPDIR}/makeopts >${tmpdir}/makeopts
+source ${tmpdir}/makeopts
+if [[ -z "${ASTMODDIR}" ]] ; then
+	echo "${module_name}: Unable to parse ${ASTTOPDIR}/makeopts."
+	exit 1
+fi
+
+XMLSTARLET=${XMLSTARLET:-xmlstarlet}
+if [[ "${XMLSTARLET}" = ":" ]] ; then
+	echo "${module_name}: The externals downloader requires xmlstarlet to be installed."
+	exit 1
+fi
+
+version=$(${ASTTOPDIR}/build_tools/make_version ${ASTTOPDIR})
+if [[ ! ${version} =~ ^(GIT-)?([^.-]+)[.-].* ]] ; then
+	echo "${module_name}: Couldn't parse version ${version}"
+	exit 1
+fi
+major_version=${BASH_REMATCH[2]}.0
+
+if [[ "${HOST_CPU}" = "x86_64" ]] ; then
+	host_bits=64
+else
+	host_bits=32
+fi
+
+names=""
+for manifest in ${DESTDIR}${ASTMODDIR}/*.manifest.xml ; do
+	if [ ! -f "$manifest" ] ; then
+		break
+	fi
+	package_version=$(${XMLSTARLET} sel -t -v "/package/@version" ${manifest})
+	package_major_version=${package_version%_*}
+	package_arch=$(${XMLSTARLET} sel -t -v "/package/@arch" ${manifest})
+	if [[ "$package_major_version" = "$major_version" && "${package_arch}" = "x86_${host_bits}" ]] ; then
+		names+=$(${XMLSTARLET} sel -t -m "//file[@executable = 'yes']" -v "concat(@name, ' ')" ${manifest})
+	fi
+done
+echo $names
diff --git a/build_tools/make_version b/build_tools/make_version
index fd14a550aace172a83f066cf149283f8a699dedd..3e0f4a0b0fed56c033ced83718dcf96d7472d882 100755
--- a/build_tools/make_version
+++ b/build_tools/make_version
@@ -89,11 +89,13 @@ elif [ -d ${1}/.git ]; then
     if [ -z ${GIT} ]; then
         GIT="git"
     fi
-
+	
     if ! command -v ${GIT} >/dev/null 2>&1; then
         echo "UNKNOWN__and_probably_unsupported"
         exit 1
     fi
+	cd ${1} 
+    
     # If the first log commit messages indicates that this is checked into
     # subversion, we'll just use the SVN- form of the revision.
     MODIFIED=""
diff --git a/build_tools/menuselect-deps.in b/build_tools/menuselect-deps.in
index a04440955565f0244b678c785fb4bed24fad84a5..9b077680e6dcdfeaa49f04a5a2b1318ed579150c 100644
--- a/build_tools/menuselect-deps.in
+++ b/build_tools/menuselect-deps.in
@@ -31,6 +31,8 @@ KQUEUE=@PBX_KQUEUE@
 LDAP=@PBX_LDAP@
 LIBEDIT=@PBX_LIBEDIT@
 LIBXML2=@PBX_LIBXML2@
+XMLSTARLET=@PBX_XMLSTARLET@
+BASH=@PBX_BASH@
 LTDL=@PBX_LTDL@
 LUA=@PBX_LUA@
 MISDN=@PBX_MISDN@
diff --git a/codecs/codecs.xml b/codecs/codecs.xml
new file mode 100644
index 0000000000000000000000000000000000000000..ac3c6e6389c15fec89150bce52db3cf013af9a75
--- /dev/null
+++ b/codecs/codecs.xml
@@ -0,0 +1,25 @@
+<member name="codec_silk" displayname="Download the SILK codec from Digium.  See http://downloads.digium.com/pub/telephony/codec_silk/README.">
+	<support_level>external</support_level>
+	<depend>xmlstarlet</depend>
+	<depend>bash</depend>
+	<defaultenabled>no</defaultenabled>
+</member>
+<member name="codec_siren7" displayname="Download the Siren7 codec from Digium.  See http://downloads.digium.com/pub/telephony/codec_siren7/README.">
+	<support_level>external</support_level>
+	<depend>xmlstarlet</depend>
+	<depend>bash</depend>
+	<defaultenabled>no</defaultenabled>
+</member>
+<member name="codec_siren14" displayname="Download the Siren14 codec from Digium.  See http://downloads.digium.com/pub/telephony/codec_siren14/README.">
+	<support_level>external</support_level>
+	<depend>xmlstarlet</depend>
+	<depend>bash</depend>
+	<defaultenabled>no</defaultenabled>
+</member>
+<member name="codec_g729a" displayname="Download the g729a codec from Digium.  A license must be purchased for this codec.  See http://downloads.digium.com/pub/telephony/codec_g729/README.">
+	<support_level>external</support_level>
+	<depend>xmlstarlet</depend>
+	<depend>bash</depend>
+	<defaultenabled>no</defaultenabled>
+	<member_data><downloader directory_name="codec_g729"/></member_data>
+</member>
diff --git a/configure b/configure
index 3e5140ddb63766a0375dc52f7adc6ab176f5eef1..6aecaa0c6abe88923a451540b59d9d56904e0d5c 100755
--- a/configure
+++ b/configure
@@ -822,6 +822,7 @@ PBX_SPANDSP
 SPANDSP_DIR
 SPANDSP_INCLUDE
 SPANDSP_LIB
+EXTERNALS_CACHE_DIR
 SOUNDS_CACHE_DIR
 PBX_SDL_IMAGE
 SDL_IMAGE_DIR
@@ -1202,6 +1203,8 @@ PTHREAD_CC
 ax_pthread_config
 MD5
 SOXMIX
+PBX_BASH
+PBX_XMLSTARLET
 PBX_FLEX
 PBX_BISON
 OPENSSL
@@ -1211,6 +1214,7 @@ DOWNLOAD
 FETCH
 ALEMBIC
 GIT
+BASH
 XMLSTARLET
 XMLLINT
 KPATHSEA
@@ -1398,6 +1402,7 @@ with_resample
 with_sdl
 with_SDL_image
 with_sounds_cache
+with_externals_cache
 with_spandsp
 with_ss7
 with_speex
@@ -2144,6 +2149,8 @@ Optional Packages:
   --with-SDL_image=PATH   use Sdl Image files in PATH
   --with-sounds-cache=PATH
                           use cached sound tarfiles in PATH
+  --with-externals-cache=PATH
+                          use cached external module tarfiles in PATH
   --with-spandsp=PATH     use SPANDSP files in PATH
   --with-ss7=PATH         use ISDN SS7 files in PATH
   --with-speex=PATH       use Speex files in PATH
@@ -7489,6 +7496,47 @@ $as_echo "no" >&6; }
 fi
 
 
+# Extract the first word of "bash", so it can be a program name with args.
+set dummy bash; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_BASH+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $BASH in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_BASH="$BASH" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_BASH="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  test -z "$ac_cv_path_BASH" && ac_cv_path_BASH=":"
+  ;;
+esac
+fi
+BASH=$ac_cv_path_BASH
+if test -n "$BASH"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $BASH" >&5
+$as_echo "$BASH" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
 # Extract the first word of "git", so it can be a program name with args.
 set dummy git; ac_word=$2
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
@@ -7796,6 +7844,20 @@ else
 fi
 
 
+if test "x${XMLSTARLET}" = "x:" ; then
+	PBX_XMLSTARLET=0
+else
+	PBX_XMLSTARLET=1
+fi
+
+
+if test "x${BASH}" = "x:" ; then
+	PBX_BASH=0
+else
+	PBX_BASH=1
+fi
+
+
 if test -n "$ac_tool_prefix"; then
   # Extract the first word of "${ac_tool_prefix}soxmix", so it can be a program name with args.
 set dummy ${ac_tool_prefix}soxmix; ac_word=$2
@@ -11526,6 +11588,30 @@ fi
 
 
 
+
+# Check whether --with-externals-cache was given.
+if test "${with_externals_cache+set}" = set; then :
+  withval=$with_externals_cache;
+	case ${withval} in
+	n|no)
+		unset EXTERNALS_CACHE_DIR
+		;;
+	*)
+		if test "x${withval}" = "x"; then
+			:
+		else
+			EXTERNALS_CACHE_DIR="${withval}"
+		fi
+		;;
+	esac
+
+else
+  :
+fi
+
+
+
+
     SPANDSP_DESCRIP="SPANDSP"
     SPANDSP_OPTION="spandsp"
     PBX_SPANDSP=0
diff --git a/configure.ac b/configure.ac
index 950cfc5a13776692d7f55cc891b1c4cf94f99259..4995d615b5082369e20a934e4390b49de788fe3b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -281,6 +281,7 @@ AC_PATH_PROG([CATDVI], [catdvi], :)
 AC_PATH_PROG([KPATHSEA], [kpsewhich], :)
 AC_PATH_PROG([XMLLINT], [xmllint], :)
 AC_PATH_PROG([XMLSTARLET], [xmlstarlet], :)
+AC_PATH_PROG([BASH], [bash], :)
 AC_PATH_PROG([GIT], [git], :)
 AC_PATH_PROG([ALEMBIC], [alembic], :)
 if test "${WGET}" != ":" ; then
@@ -340,6 +341,20 @@ else
 fi
 AC_SUBST(PBX_FLEX)
 
+if test "x${XMLSTARLET}" = "x:" ; then
+	PBX_XMLSTARLET=0
+else
+	PBX_XMLSTARLET=1
+fi
+AC_SUBST(PBX_XMLSTARLET)
+
+if test "x${BASH}" = "x:" ; then
+	PBX_BASH=0
+else
+	PBX_BASH=1
+fi
+AC_SUBST(PBX_BASH)
+
 AC_CHECK_TOOL([SOXMIX], [soxmix], [:])
 if test "${SOXMIX}" != ":" ; then
 	AC_DEFINE([HAVE_SOXMIX], 1, [Define to 1 if your system has soxmix application.])
@@ -521,6 +536,7 @@ AST_EXT_LIB_SETUP([RESAMPLE], [LIBRESAMPLE], [resample])
 AST_EXT_LIB_SETUP([SDL], [Sdl], [sdl])
 AST_EXT_LIB_SETUP([SDL_IMAGE], [Sdl Image], [SDL_image])
 AST_OPTION_ONLY([sounds-cache], [SOUNDS_CACHE_DIR], [cached sound tarfiles], [])
+AST_OPTION_ONLY([externals-cache], [EXTERNALS_CACHE_DIR], [cached external module tarfiles], [])
 AST_EXT_LIB_SETUP([SPANDSP], [SPANDSP], [spandsp])
 AST_EXT_LIB_SETUP([SS7], [ISDN SS7], [ss7])
 AST_EXT_LIB_SETUP([SPEEX], [Speex], [speex])
diff --git a/makeopts.in b/makeopts.in
index f0b0d0ef51d81f1486846e2389fbfbdad547be6f..86b7f9d99afa85f896dd98c5509a830c8f460906 100644
--- a/makeopts.in
+++ b/makeopts.in
@@ -28,11 +28,13 @@ WGET=@WGET@
 FETCH=@FETCH@
 DOWNLOAD=@DOWNLOAD@
 SOUNDS_CACHE_DIR=@SOUNDS_CACHE_DIR@
+EXTERNALS_CACHE_DIR=@EXTERNALS_CACHE_DIR@
 RUBBER=@RUBBER@
 CATDVI=@CATDVI@
 KPATHSEA=@KPATHSEA@
 XMLLINT=@XMLLINT@
 XMLSTARLET=@XMLSTARLET@
+BASH=@BASH@
 MD5=@MD5@
 SHA1SUM=@SHA1SUM@
 OPENSSL=@OPENSSL@
diff --git a/res/res.xml b/res/res.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e9cb5f962cf40b3180c1395717c466c8dd8b247e
--- /dev/null
+++ b/res/res.xml
@@ -0,0 +1,6 @@
+<member name="res_digium_phone" displayname="Download the Digium Phone Module for Asterisk.  See http://downloads.digium.com/pub/telephony/res_digium_phone/README.">
+	<support_level>external</support_level>
+	<depend>xmlstarlet</depend>
+	<depend>bash</depend>
+	<defaultenabled>no</defaultenabled>
+</member>