diff --git a/build_tools/menuselect-deps.in b/build_tools/menuselect-deps.in
index 161c67b39aac1c12535dff60b2bbc58a053e5e5f..f66d7bd64d3c9608806cde9cfeab4b19de94d7a0 100644
--- a/build_tools/menuselect-deps.in
+++ b/build_tools/menuselect-deps.in
@@ -32,6 +32,7 @@ KQUEUE=@PBX_KQUEUE@
 LDAP=@PBX_LDAP@
 LIBEDIT=@PBX_LIBEDIT@
 LIBXML2=@PBX_LIBXML2@
+LIBXSLT=@PBX_LIBXSLT@
 XMLSTARLET=@PBX_XMLSTARLET@
 BASH=@PBX_BASH@
 LUA=@PBX_LUA@
diff --git a/configure b/configure
index 5bfd90c9144eff52a58fac94bc9df915f0f9e109..22fe0acf792674b7ff6cf9b98a9209b8dc31a28e 100755
--- a/configure
+++ b/configure
@@ -9406,8 +9406,8 @@ $as_echo "$as_me: checking whether system openssl > 1.1.0" >&6;}
    if test "x${PBX_OPENSSL}" != "x1" -a "${USE_OPENSSL}" != "no"; then
 
 pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for openssl >= 1.1.0" >&5
-$as_echo_n "checking for openssl >= 1.1.0... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OPENSSL" >&5
+$as_echo_n "checking for OPENSSL... " >&6; }
 
 if test -n "$OPENSSL_CFLAGS"; then
     pkg_cv_OPENSSL_CFLAGS="$OPENSSL_CFLAGS"
@@ -9447,7 +9447,7 @@ fi
 
 
 if test $pkg_failed = yes; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+   	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 
 if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
@@ -9468,7 +9468,7 @@ fi
 
 
 elif test $pkg_failed = untried; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+     	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 
             PBX_OPENSSL=0
@@ -9497,8 +9497,8 @@ $as_echo "$as_me: checking whether alternate openssl11 is installed" >&6;}
    if test "x${PBX_OPENSSL}" != "x1" -a "${USE_OPENSSL}" != "no"; then
 
 pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for openssl11" >&5
-$as_echo_n "checking for openssl11... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OPENSSL" >&5
+$as_echo_n "checking for OPENSSL... " >&6; }
 
 if test -n "$OPENSSL_CFLAGS"; then
     pkg_cv_OPENSSL_CFLAGS="$OPENSSL_CFLAGS"
@@ -9538,7 +9538,7 @@ fi
 
 
 if test $pkg_failed = yes; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+   	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 
 if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
@@ -9559,7 +9559,7 @@ fi
 
 
 elif test $pkg_failed = untried; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+     	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 
             PBX_OPENSSL=0
@@ -9593,8 +9593,8 @@ $as_echo "$as_me: checking fallback system openssl" >&6;}
    if test "x${PBX_OPENSSL}" != "x1" -a "${USE_OPENSSL}" != "no"; then
 
 pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for openssl" >&5
-$as_echo_n "checking for openssl... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OPENSSL" >&5
+$as_echo_n "checking for OPENSSL... " >&6; }
 
 if test -n "$OPENSSL_CFLAGS"; then
     pkg_cv_OPENSSL_CFLAGS="$OPENSSL_CFLAGS"
@@ -9634,7 +9634,7 @@ fi
 
 
 if test $pkg_failed = yes; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+   	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 
 if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
@@ -9655,7 +9655,7 @@ fi
 
 
 elif test $pkg_failed = untried; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+     	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 
             PBX_OPENSSL=0
@@ -14095,8 +14095,8 @@ done
    if test "x${PBX_LIBEDIT}" != "x1" -a "${USE_LIBEDIT}" != "no"; then
 
 pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libedit" >&5
-$as_echo_n "checking for libedit... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBEDIT" >&5
+$as_echo_n "checking for LIBEDIT... " >&6; }
 
 if test -n "$LIBEDIT_CFLAGS"; then
     pkg_cv_LIBEDIT_CFLAGS="$LIBEDIT_CFLAGS"
@@ -14136,7 +14136,7 @@ fi
 
 
 if test $pkg_failed = yes; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+   	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 
 if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
@@ -14157,7 +14157,7 @@ fi
 
 
 elif test $pkg_failed = untried; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+     	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 
             PBX_LIBEDIT=0
@@ -14555,8 +14555,8 @@ if test "$JANSSON_BUNDLED" = "no" ; then
    if test "x${PBX_JANSSON}" != "x1" -a "${USE_JANSSON}" != "no"; then
 
 pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for jansson >= 2.11" >&5
-$as_echo_n "checking for jansson >= 2.11... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for JANSSON" >&5
+$as_echo_n "checking for JANSSON... " >&6; }
 
 if test -n "$JANSSON_CFLAGS"; then
     pkg_cv_JANSSON_CFLAGS="$JANSSON_CFLAGS"
@@ -14596,7 +14596,7 @@ fi
 
 
 if test $pkg_failed = yes; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+   	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 
 if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
@@ -14617,7 +14617,7 @@ fi
 
 
 elif test $pkg_failed = untried; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+     	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 
             PBX_JANSSON=0
@@ -15134,6 +15134,8 @@ if test "${DISABLE_XMLDOC}" != "yes"; then
 
 $as_echo "#define AST_XML_DOCS 1" >>confdefs.h
 
+fi
+
 
 if test "x${PBX_LIBXSLT}" != "x1" -a "${USE_LIBXSLT}" != "no"; then
    pbxlibdir=""
@@ -15327,8 +15329,6 @@ fi
 
 
 
-fi
-
 # Check whether --enable-permanent-dlopen was given.
 if test "${enable_permanent_dlopen+set}" = set; then :
   enableval=$enable_permanent_dlopen; case "${enableval}" in
@@ -15412,7 +15412,7 @@ else
     We can't simply define LARGE_OFF_T to be 9223372036854775807,
     since some C++ compilers masquerading as C compilers
     incorrectly reject 9223372036854775807.  */
-#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
   int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
 		       && LARGE_OFF_T % 2147483647 == 1)
 		      ? 1 : -1];
@@ -15458,7 +15458,7 @@ else
     We can't simply define LARGE_OFF_T to be 9223372036854775807,
     since some C++ compilers masquerading as C compilers
     incorrectly reject 9223372036854775807.  */
-#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
   int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
 		       && LARGE_OFF_T % 2147483647 == 1)
 		      ? 1 : -1];
@@ -15482,7 +15482,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
     We can't simply define LARGE_OFF_T to be 9223372036854775807,
     since some C++ compilers masquerading as C compilers
     incorrectly reject 9223372036854775807.  */
-#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
   int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
 		       && LARGE_OFF_T % 2147483647 == 1)
 		      ? 1 : -1];
@@ -15527,7 +15527,7 @@ else
     We can't simply define LARGE_OFF_T to be 9223372036854775807,
     since some C++ compilers masquerading as C compilers
     incorrectly reject 9223372036854775807.  */
-#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
   int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
 		       && LARGE_OFF_T % 2147483647 == 1)
 		      ? 1 : -1];
@@ -15551,7 +15551,7 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
     We can't simply define LARGE_OFF_T to be 9223372036854775807,
     since some C++ compilers masquerading as C compilers
     incorrectly reject 9223372036854775807.  */
-#define LARGE_OFF_T ((((off_t) 1 << 31) << 31) - 1 + (((off_t) 1 << 31) << 31))
+#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
   int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
 		       && LARGE_OFF_T % 2147483647 == 1)
 		      ? 1 : -1];
@@ -16851,8 +16851,6 @@ main ()
     if (*(data + i) != *(data3 + i))
       return 14;
   close (fd);
-  free (data);
-  free (data3);
   return 0;
 }
 _ACEOF
@@ -21279,8 +21277,8 @@ if test "${USE_ILBC}" != "no"; then
    if test "x${PBX_ILBC}" != "x1" -a "${USE_ILBC}" != "no"; then
 
 pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libilbc" >&5
-$as_echo_n "checking for libilbc... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ILBC" >&5
+$as_echo_n "checking for ILBC... " >&6; }
 
 if test -n "$ILBC_CFLAGS"; then
     pkg_cv_ILBC_CFLAGS="$ILBC_CFLAGS"
@@ -21320,7 +21318,7 @@ fi
 
 
 if test $pkg_failed = yes; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+   	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 
 if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
@@ -21341,7 +21339,7 @@ fi
 
 
 elif test $pkg_failed = untried; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+     	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 
             PBX_ILBC=0
@@ -24000,8 +23998,8 @@ rm -f core conftest.err conftest.$ac_objext \
    if test "x${PBX_NETSNMP}" != "x1" -a "${USE_NETSNMP}" != "no"; then
 
 pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for netsnmp-agent" >&5
-$as_echo_n "checking for netsnmp-agent... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for NETSNMP" >&5
+$as_echo_n "checking for NETSNMP... " >&6; }
 
 if test -n "$NETSNMP_CFLAGS"; then
     pkg_cv_NETSNMP_CFLAGS="$NETSNMP_CFLAGS"
@@ -24041,7 +24039,7 @@ fi
 
 
 if test $pkg_failed = yes; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+   	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 
 if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
@@ -24062,7 +24060,7 @@ fi
 
 
 elif test $pkg_failed = untried; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+     	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 
             PBX_NETSNMP=0
@@ -25608,8 +25606,8 @@ if test "$USE_PJPROJECT" != "no" ; then
    if test "x${PBX_PJPROJECT}" != "x1" -a "${USE_PJPROJECT}" != "no"; then
 
 pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libpjproject" >&5
-$as_echo_n "checking for libpjproject... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PJPROJECT" >&5
+$as_echo_n "checking for PJPROJECT... " >&6; }
 
 if test -n "$PJPROJECT_CFLAGS"; then
     pkg_cv_PJPROJECT_CFLAGS="$PJPROJECT_CFLAGS"
@@ -25649,7 +25647,7 @@ fi
 
 
 if test $pkg_failed = yes; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+   	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 
 if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
@@ -25670,7 +25668,7 @@ fi
 
 
 elif test $pkg_failed = untried; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+     	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 
             PBX_PJPROJECT=0
@@ -26861,8 +26859,8 @@ fi
    if test "x${PBX_PYTHONDEV}" != "x1" -a "${USE_PYTHONDEV}" != "no"; then
 
 pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for python-2.7" >&5
-$as_echo_n "checking for python-2.7... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PYTHONDEV" >&5
+$as_echo_n "checking for PYTHONDEV... " >&6; }
 
 if test -n "$PYTHONDEV_CFLAGS"; then
     pkg_cv_PYTHONDEV_CFLAGS="$PYTHONDEV_CFLAGS"
@@ -26902,7 +26900,7 @@ fi
 
 
 if test $pkg_failed = yes; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+   	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 
 if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
@@ -26923,7 +26921,7 @@ fi
 
 
 elif test $pkg_failed = untried; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+     	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 
             PBX_PYTHONDEV=0
@@ -26949,8 +26947,8 @@ fi
    if test "x${PBX_PYTHONDEV}" != "x1" -a "${USE_PYTHONDEV}" != "no"; then
 
 pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for python2" >&5
-$as_echo_n "checking for python2... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PYTHONDEV" >&5
+$as_echo_n "checking for PYTHONDEV... " >&6; }
 
 if test -n "$PYTHONDEV_CFLAGS"; then
     pkg_cv_PYTHONDEV_CFLAGS="$PYTHONDEV_CFLAGS"
@@ -26990,7 +26988,7 @@ fi
 
 
 if test $pkg_failed = yes; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+   	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 
 if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
@@ -27011,7 +27009,7 @@ fi
 
 
 elif test $pkg_failed = untried; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+     	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 
             PBX_PYTHONDEV=0
@@ -27037,8 +27035,8 @@ fi
    if test "x${PBX_PYTHONDEV}" != "x1" -a "${USE_PYTHONDEV}" != "no"; then
 
 pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for python" >&5
-$as_echo_n "checking for python... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PYTHONDEV" >&5
+$as_echo_n "checking for PYTHONDEV... " >&6; }
 
 if test -n "$PYTHONDEV_CFLAGS"; then
     pkg_cv_PYTHONDEV_CFLAGS="$PYTHONDEV_CFLAGS"
@@ -27078,7 +27076,7 @@ fi
 
 
 if test $pkg_failed = yes; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+   	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 
 if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
@@ -27099,7 +27097,7 @@ fi
 
 
 elif test $pkg_failed = untried; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+     	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 
             PBX_PYTHONDEV=0
@@ -27233,8 +27231,8 @@ fi
    if test "x${PBX_PORTAUDIO}" != "x1" -a "${USE_PORTAUDIO}" != "no"; then
 
 pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for portaudio-2.0" >&5
-$as_echo_n "checking for portaudio-2.0... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PORTAUDIO" >&5
+$as_echo_n "checking for PORTAUDIO... " >&6; }
 
 if test -n "$PORTAUDIO_CFLAGS"; then
     pkg_cv_PORTAUDIO_CFLAGS="$PORTAUDIO_CFLAGS"
@@ -27274,7 +27272,7 @@ fi
 
 
 if test $pkg_failed = yes; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+   	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 
 if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
@@ -27295,7 +27293,7 @@ fi
 
 
 elif test $pkg_failed = untried; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+     	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 
             PBX_PORTAUDIO=0
@@ -33244,8 +33242,8 @@ for ver in 3.0 2.6 2.4 2.2 2.0; do
    if test "x${PBX_GMIME}" != "x1" -a "${USE_GMIME}" != "no"; then
 
 pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for gmime-$ver" >&5
-$as_echo_n "checking for gmime-$ver... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GMIME" >&5
+$as_echo_n "checking for GMIME... " >&6; }
 
 if test -n "$GMIME_CFLAGS"; then
     pkg_cv_GMIME_CFLAGS="$GMIME_CFLAGS"
@@ -33285,7 +33283,7 @@ fi
 
 
 if test $pkg_failed = yes; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+   	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 
 if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
@@ -33306,7 +33304,7 @@ fi
 
 
 elif test $pkg_failed = untried; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+     	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 
             PBX_GMIME=0
@@ -34681,8 +34679,8 @@ fi
    if test "x${PBX_GTK2}" != "x1" -a "${USE_GTK2}" != "no"; then
 
 pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for gtk+-2.0" >&5
-$as_echo_n "checking for gtk+-2.0... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GTK2" >&5
+$as_echo_n "checking for GTK2... " >&6; }
 
 if test -n "$GTK2_CFLAGS"; then
     pkg_cv_GTK2_CFLAGS="$GTK2_CFLAGS"
@@ -34722,7 +34720,7 @@ fi
 
 
 if test $pkg_failed = yes; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+   	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 
 if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
@@ -34743,7 +34741,7 @@ fi
 
 
 elif test $pkg_failed = untried; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+     	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 
             PBX_GTK2=0
@@ -34792,8 +34790,8 @@ fi
    if test "x${PBX_SYSTEMD}" != "x1" -a "${USE_SYSTEMD}" != "no"; then
 
 pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for libsystemd" >&5
-$as_echo_n "checking for libsystemd... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for SYSTEMD" >&5
+$as_echo_n "checking for SYSTEMD... " >&6; }
 
 if test -n "$SYSTEMD_CFLAGS"; then
     pkg_cv_SYSTEMD_CFLAGS="$SYSTEMD_CFLAGS"
@@ -34833,7 +34831,7 @@ fi
 
 
 if test $pkg_failed = yes; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+   	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 
 if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
@@ -34854,7 +34852,7 @@ fi
 
 
 elif test $pkg_failed = untried; then
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+     	{ $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 
             PBX_SYSTEMD=0
diff --git a/configure.ac b/configure.ac
index 9eb62b8341057674cbf79d3b4941660175f3805a..0d6817e68a2976fbb22add10e127eac2abbe2a0b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -770,11 +770,11 @@ AC_ARG_ENABLE([xmldoc],
 AC_SUBST([DISABLE_XMLDOC])
 if test "${DISABLE_XMLDOC}" != "yes"; then
         AC_DEFINE([AST_XML_DOCS], 1, [Define to enable XML documentation.])
-        AST_EXT_LIB_CHECK([LIBXSLT], [xslt], [xsltLoadStylesheetPI], [libxslt/xsltInternals.h], [${LIBXML2_LIB}], [${LIBXML2_INCLUDE}])
-        AST_EXT_LIB_CHECK([LIBXSLT_CLEANUP], [xslt], [xsltCleanupGlobals], [libxslt/xsltInternals.h], [${LIBXML2_LIB}], [${LIBXML2_INCLUDE}])
-
 fi
 
+AST_EXT_LIB_CHECK([LIBXSLT], [xslt], [xsltLoadStylesheetPI], [libxslt/xsltInternals.h], [${LIBXML2_LIB}], [${LIBXML2_INCLUDE}])
+AST_EXT_LIB_CHECK([LIBXSLT_CLEANUP], [xslt], [xsltCleanupGlobals], [libxslt/xsltInternals.h], [${LIBXML2_LIB}], [${LIBXML2_INCLUDE}])
+
 AC_ARG_ENABLE([permanent-dlopen],
 	[AS_HELP_STRING([--enable-permanent-dlopen],
 		[Enable when your libc has a permanent dlopen like musl])],
diff --git a/include/asterisk/config.h b/include/asterisk/config.h
index f4f6c9d5f7951b7f93840300432c16ad605a8975..afac2290e2a79d7d2bfac64777f8cfb3df6b85cd 100644
--- a/include/asterisk/config.h
+++ b/include/asterisk/config.h
@@ -1005,6 +1005,23 @@ int ast_variable_list_replace_variable(struct ast_variable **head, struct ast_va
 struct ast_str *ast_variable_list_join(const struct ast_variable *head, const char *item_separator,
 	const char *name_value_separator, const char *quote_char, struct ast_str **str);
 
+/*!
+ * \brief Parse a string into an ast_variable list.  The reverse of ast_variable_list_join
+ *
+ * \param input                The name-value pair string to parse.
+ * \param item_separator       The string used to separate the list items.
+ *                             Only the first character in the string will be used.
+ *                             If NULL, "," will be used.
+ * \param name_value_separator The string used to separate each item's name and value.
+ *                             Only the first character in the string will be used.
+ *                             If NULL, "=" will be used.
+ *
+ * \retval A pointer to a list of ast_variables.
+ * \retval NULL if there was an error or no variables could be parsed.
+ */
+struct ast_variable *ast_variable_list_from_string(const char *input, const char *item_separator,
+	const char *name_value_separator);
+
 /*!
  * \brief Update variable value within a config
  *
diff --git a/include/asterisk/xml.h b/include/asterisk/xml.h
index 13af3c6b601dd29631114a5ebff1a2ad9e9091b2..9d43560a3e40fc0155188f35352d6a229c23a6da 100644
--- a/include/asterisk/xml.h
+++ b/include/asterisk/xml.h
@@ -21,9 +21,12 @@
  * \brief Asterisk XML abstraction layer
  */
 
+#include "asterisk/vector.h"
+
 struct ast_xml_node;
 struct ast_xml_doc;
 struct ast_xml_xpath_results;
+struct ast_xslt_doc;
 
 /*!
  * \brief Initialize the XML library implementation.
@@ -184,6 +187,19 @@ int ast_xml_set_attribute(struct ast_xml_node *node, const char *name, const cha
  */
 struct ast_xml_node *ast_xml_find_element(struct ast_xml_node *root_node, const char *name, const char *attrname, const char *attrvalue);
 struct ast_xml_ns *ast_xml_find_namespace(struct ast_xml_doc *doc, struct ast_xml_node *node, const char *ns_name);
+
+/*!
+ * \brief Get the prefix of a namespace.
+ * \param ns The namespace
+ * \return The prefix of the namespace.
+ */
+const char *ast_xml_get_ns_prefix(struct ast_xml_ns *ns);
+
+/*!
+ * \brief Get the href of a namespace.
+ * \param ns The namespace
+ * \return The href of the namespace.
+ */
 const char *ast_xml_get_ns_href(struct ast_xml_ns *ns);
 
 /*!
@@ -259,6 +275,15 @@ int ast_xml_xpath_num_results(struct ast_xml_xpath_results *results);
  */
 struct ast_xml_node *ast_xml_xpath_get_first_result(struct ast_xml_xpath_results *results);
 
+/*!
+ * \brief Return a specific result node of an XPath query
+ * \param results The XPath results object to get the result from
+ * \param n The index of the result to get
+ * \return The nth result in the XPath object on success
+ * \retval NULL on error
+ */
+struct ast_xml_node *ast_xml_xpath_get_result(struct ast_xml_xpath_results *results, int n);
+
 /*!
  * \brief Execute an XPath query on an XML document
  * \param doc XML document to query
@@ -270,4 +295,80 @@ struct ast_xml_node *ast_xml_xpath_get_first_result(struct ast_xml_xpath_results
  */
 struct ast_xml_xpath_results *ast_xml_query(struct ast_xml_doc *doc, const char *xpath_str);
 
+/*!
+ * \brief Namespace definition
+ */
+struct ast_xml_namespace_def {
+	const char *prefix;
+	const char *href;
+};
+
+AST_VECTOR(ast_xml_namespace_def_vector, struct ast_xml_namespace_def);
+
+/*!
+ * \brief Execute an XPath query on an XML document with namespaces
+ * \param doc XML document to query
+ * \param xpath_str The XPath query string to execute on the document
+ * \param namespaces A vector of ast_xml_namespace structures (not pointers)
+ * \return An object containing the results of the XPath query on success
+ * \retval NULL on failure
+ */
+struct ast_xml_xpath_results *ast_xml_query_with_namespaces(struct ast_xml_doc *doc, const char *xpath_str,
+	struct ast_xml_namespace_def_vector *namespaces);
+
+#ifdef HAVE_LIBXSLT
+
+/*! \brief Open an XSLT document that resides in memory.
+ *
+ * \param buffer The address where the stylesheet is stored
+ * \param size   The number of bytes in the stylesheet
+ *
+ * \return The stylesheet document.  Must be closed with ast_xslt_close().
+ */
+struct ast_xslt_doc *ast_xslt_read_memory(char *buffer, size_t size);
+
+/*!
+ * \brief Open an XSLT document.
+ *
+ * \param filename stylesheet path.
+ *
+ * \return The stylesheet document.  Must be closed with ast_xslt_close().
+ */
+struct ast_xslt_doc *ast_xslt_open(char *filename);
+
+/*!
+ * \brief Close a stylesheet document and free its resources.
+ *
+ * \param xslt XSLT stylesheet to close
+ */
+void ast_xslt_close(struct ast_xslt_doc *xslt);
+
+/*!
+ * \brief Apply an XSLT stylesheet to an XML document
+ *
+ * \param xslt    XSLT stylesheet to apply.
+ * \param xml     XML document the stylesheet will be applied to.
+ * \param params  An array of name value pairs to pass as parameters
+ *                The array must terminate with a NULL sentinel.
+ *                Example:  { "name1", "value1", "name2", "value2", NULL }
+ *
+ * \return A pointer to the result document which must be freed with ast_xml_close()
+ */
+struct ast_xml_doc *ast_xslt_apply(struct ast_xslt_doc *xslt, struct ast_xml_doc *doc, const char **params);
+
+/*!
+ * \brief Save the results of applying a stylesheet to a string
+ *
+ * \param buffer[out]  A pointer to a char * to receive the address of the result string.
+ *                     The buffer must be freed with ast_xml_free_text().
+ * \param length[out]  A pointer to an int to receive the result string length.
+ * \param result       The result document from ast_xslt_apply.
+ * \param xslt         The stylesheet that was applied.
+ *
+ * \return 0 on success, any other value on failure.
+ */
+int ast_xslt_save_result_to_string(char **buffer, int *length, struct ast_xml_doc *result,
+	struct ast_xslt_doc *xslt);
+
+#endif /* HAVE_LIBXSLT */
 #endif /* _ASTERISK_XML_H */
diff --git a/main/config.c b/main/config.c
index 92a24de6345507f25ca965d325c9f4f7c32285f9..122e7aad480e3005ae755c9c8a98383d8cc94a15 100644
--- a/main/config.c
+++ b/main/config.c
@@ -722,6 +722,39 @@ struct ast_str *ast_variable_list_join(const struct ast_variable *head, const ch
 	return local_str;
 }
 
+struct ast_variable *ast_variable_list_from_string(const char *input, const char *item_separator,
+	const char *name_value_separator)
+{
+	char item_sep;
+	char nv_sep;
+	struct ast_variable *new_list = NULL;
+	struct ast_variable *new_var = NULL;
+	char *item_string;
+	char *item;
+	char *item_name;
+	char *item_value;
+
+	if (ast_strlen_zero(input)) {
+		return NULL;
+	}
+
+	item_sep = ast_strlen_zero(item_separator) ? ',' : item_separator[0];
+	nv_sep = ast_strlen_zero(name_value_separator) ? '=' : name_value_separator[0];
+	item_string = ast_strip(ast_strdupa(input));
+
+	while ((item = ast_strsep(&item_string, item_sep, AST_STRSEP_ALL))) {
+		item_name = ast_strsep(&item, nv_sep, AST_STRSEP_ALL);
+		item_value = ast_strsep(&item, nv_sep, AST_STRSEP_ALL);
+		new_var = ast_variable_new(item_name, item_value, "");
+		if (!new_var) {
+			ast_variables_destroy(new_list);
+			return NULL;
+		}
+		ast_variable_list_append(&new_list, new_var);
+	}
+	return new_list;
+}
+
 const char *ast_config_option(struct ast_config *cfg, const char *cat, const char *var)
 {
 	const char *tmp;
diff --git a/main/xml.c b/main/xml.c
index 88c9edffde5c23e18fe91c3a6ed984e3433983a2..987f1253995934a2603c3dbf08fc007f542de171 100644
--- a/main/xml.c
+++ b/main/xml.c
@@ -36,25 +36,33 @@
 #include <libxml/tree.h>
 #include <libxml/xinclude.h>
 #include <libxml/xpath.h>
+#include <libxml/xpathInternals.h>
 /* libxml2 ast_xml implementation. */
 #ifdef HAVE_LIBXSLT
 	#include <libxslt/xsltInternals.h>
 	#include <libxslt/transform.h>
+	#include <libxslt/xsltutils.h>
 #endif /* HAVE_LIBXSLT */
 
 
 int ast_xml_init(void)
 {
 	LIBXML_TEST_VERSION
-
+#ifdef HAVE_LIBXSLT
+	xsltInit();
+#endif
 	return 0;
 }
 
 int ast_xml_finish(void)
 {
 	xmlCleanupParser();
+#ifdef HAVE_LIBXSLT
 #ifdef HAVE_LIBXSLT_CLEANUP
 	xsltCleanupGlobals();
+#else
+	xsltUninit();
+#endif
 #endif
 
 	return 0;
@@ -68,6 +76,8 @@ struct ast_xml_doc *ast_xml_open(char *filename)
 		return NULL;
 	}
 
+	xmlSubstituteEntitiesDefault(1);
+
 	doc = xmlReadFile(filename, NULL, XML_PARSE_RECOVER);
 	if (!doc) {
 		return NULL;
@@ -309,6 +319,11 @@ struct ast_xml_ns *ast_xml_find_namespace(struct ast_xml_doc *doc, struct ast_xm
 	return (struct ast_xml_ns *) ns;
 }
 
+const char *ast_xml_get_ns_prefix(struct ast_xml_ns *ns)
+{
+	return (const char *) ((xmlNsPtr) ns)->prefix;
+}
+
 const char *ast_xml_get_ns_href(struct ast_xml_ns *ns)
 {
 	return (const char *) ((xmlNsPtr) ns)->href;
@@ -376,13 +391,24 @@ struct ast_xml_node *ast_xml_xpath_get_first_result(struct ast_xml_xpath_results
 	return (struct ast_xml_node *) ((xmlXPathObjectPtr) results)->nodesetval->nodeTab[0];
 }
 
+struct ast_xml_node *ast_xml_xpath_get_result(struct ast_xml_xpath_results *results, int i)
+{
+	return (struct ast_xml_node *) ((xmlXPathObjectPtr) results)->nodesetval->nodeTab[i];
+}
+
 void ast_xml_xpath_results_free(struct ast_xml_xpath_results *results)
 {
+	if (!results) {
+		return;
+	}
 	xmlXPathFreeObject((xmlXPathObjectPtr) results);
 }
 
 int ast_xml_xpath_num_results(struct ast_xml_xpath_results *results)
 {
+	if (!results) {
+		return 0;
+	}
 	return ((xmlXPathObjectPtr) results)->nodesetval->nodeNr;
 }
 
@@ -408,4 +434,149 @@ struct ast_xml_xpath_results *ast_xml_query(struct ast_xml_doc *doc, const char
 	return (struct ast_xml_xpath_results *) result;
 }
 
+struct ast_xml_xpath_results *ast_xml_query_with_namespaces(struct ast_xml_doc *doc, const char *xpath_str,
+	struct ast_xml_namespace_def_vector *namespaces)
+{
+	xmlXPathContextPtr context;
+	xmlXPathObjectPtr result;
+	int i;
+
+	if (!(context = xmlXPathNewContext((xmlDoc *) doc))) {
+		ast_log(LOG_ERROR, "Could not create XPath context!\n");
+		return NULL;
+	}
+
+	for (i = 0; i < AST_VECTOR_SIZE(namespaces); i++) {
+		struct ast_xml_namespace_def ns = AST_VECTOR_GET(namespaces, i);
+		if (xmlXPathRegisterNs(context, (xmlChar *)ns.prefix,
+			(xmlChar *)ns.href) != 0) {
+			xmlXPathFreeContext(context);
+			ast_log(LOG_ERROR, "Could not register namespace %s:%s\n",
+				ns.prefix, ns.href);
+			return NULL;
+		}
+	}
+
+	result = xmlXPathEvalExpression((xmlChar *) xpath_str, context);
+	xmlXPathFreeContext(context);
+	if (!result) {
+		ast_log(LOG_WARNING, "Error for query: %s\n", xpath_str);
+		return NULL;
+	}
+	if (xmlXPathNodeSetIsEmpty(result->nodesetval)) {
+		xmlXPathFreeObject(result);
+		ast_debug(5, "No results for query: %s\n", xpath_str);
+		return NULL;
+	}
+	return (struct ast_xml_xpath_results *) result;
+}
+
+#ifdef HAVE_LIBXSLT
+struct ast_xslt_doc *ast_xslt_open(char *filename)
+{
+	xsltStylesheet *xslt;
+	xmlDoc *xml;
+
+	xmlSubstituteEntitiesDefault(1);
+
+	xml = xmlReadFile(filename, NULL, XML_PARSE_RECOVER);
+	if (!xml) {
+		return NULL;
+	}
+
+	if (xmlXIncludeProcess(xml) < 0) {
+		xmlFreeDoc(xml);
+		return NULL;
+	}
+	xmlXPathOrderDocElems(xml);
+
+	if (!(xslt = xsltParseStylesheetDoc(xml))) {
+		xmlFreeDoc(xml);
+		return NULL;
+	}
+
+	return (struct ast_xslt_doc *) xslt;
+}
+
+struct ast_xslt_doc *ast_xslt_read_memory(char *buffer, size_t size)
+{
+	xsltStylesheet *xslt;
+	xmlDoc *doc;
+
+	if (!buffer) {
+		return NULL;
+	}
+
+	xmlSubstituteEntitiesDefault(1);
+
+	if (!(doc = xmlParseMemory(buffer, (int) size))) {
+		return NULL;
+	}
+
+	if (xmlXIncludeProcess(doc) < 0) {
+		xmlFreeDoc(doc);
+		return NULL;
+	}
+
+	if (!(xslt = xsltParseStylesheetDoc(doc))) {
+		xmlFreeDoc(doc);
+		return NULL;
+	}
+
+	return (struct ast_xslt_doc *) xslt;
+}
+
+void ast_xslt_close(struct ast_xslt_doc *axslt)
+{
+	if (!axslt) {
+		return;
+	}
+
+	xsltFreeStylesheet((xsltStylesheet *) axslt);
+}
+
+struct ast_xml_doc *ast_xslt_apply(struct ast_xslt_doc *axslt, struct ast_xml_doc *axml, const char **params)
+{
+	xsltStylesheet *xslt = (xsltStylesheet *)axslt;
+	xmlDoc *xml = (xmlDoc *)axml;
+	xsltTransformContextPtr ctxt;
+	xmlNs *ns;
+	xmlDoc *res;
+	int options = XSLT_PARSE_OPTIONS;
+
+	/*
+	 * Normally we could just call xsltApplyStylesheet() without creating
+	 * our own transform context but we need to pass parameters to it
+	 * that have namespace prefixes and that's not supported.  Instead
+	 * we have to create a transform context, iterate over the namespace
+	 * declarations in the stylesheet (not the incoming xml document),
+	 * and add them to the transform context's xpath context.
+	 *
+	 * The alternative would be to pass the parameters with namespaces
+	 * as text strings but that's not intuitive and results in much
+	 * slower performance than adding the namespaces here.
+	 */
+	ctxt = xsltNewTransformContext(xslt, xml);
+	xsltSetCtxtParseOptions(ctxt, options);
+
+	for (ns = xslt->doc->children->nsDef; ns; ns = ns->next) {
+		if (xmlXPathRegisterNs(ctxt->xpathCtxt, ns->prefix, ns->href) != 0) {
+			xmlXPathFreeContext(ctxt->xpathCtxt);
+			xsltFreeTransformContext(ctxt);
+			return NULL;
+		}
+	}
+
+	res = xsltApplyStylesheetUser(xslt, xml, params, NULL, NULL, ctxt);
+
+	return (struct ast_xml_doc *)res;
+}
+
+int ast_xslt_save_result_to_string(char **buffer, int *length, struct ast_xml_doc *result,
+	struct ast_xslt_doc *axslt)
+{
+	return xsltSaveResultToString((xmlChar **)buffer, length, (xmlDoc *)result, (xsltStylesheet *)axslt);
+}
+
+#endif /* defined(HAVE_LIBXSLT) */
 #endif /* defined(HAVE_LIBXML2) */
diff --git a/tests/test_config.c b/tests/test_config.c
index 5b44b446e003a1700cfe8282aaa6237c8a478d81..1a0ddaf836cd82e22d583c515adb46a8d4817bcf 100644
--- a/tests/test_config.c
+++ b/tests/test_config.c
@@ -1943,6 +1943,35 @@ AST_TEST_DEFINE(variable_list_join_replace)
 
 	return AST_TEST_PASS;
 }
+
+AST_TEST_DEFINE(variable_list_from_string)
+{
+	RAII_VAR(struct ast_variable *, list, NULL, ast_variables_destroy);
+	RAII_VAR(struct ast_str *, str, NULL, ast_free);
+	char *parse_string;
+
+	switch (cmd) {
+	case TEST_INIT:
+		info->name = "variable_list_from_string";
+		info->category = "/main/config/";
+		info->summary = "Test parsing a string into a variable list";
+		info->description =	info->summary;
+		return AST_TEST_NOT_RUN;
+	case TEST_EXECUTE:
+		break;
+	}
+
+	parse_string = "abc = 'def', ghi = 'j,kl', mno='pq=r', stu = 'vwx=\"yz\", ABC = \"DEF\"'";
+	list = ast_variable_list_from_string(parse_string, ",", "=");
+	ast_test_validate(test, list != NULL);
+	str = ast_variable_list_join(list, "|", "^", "@", NULL);
+
+	ast_test_validate(test,
+		strcmp(ast_str_buffer(str), "abc^@def@|ghi^@j,kl@|mno^@pq=r@|stu^@vwx=\"yz\", ABC = \"DEF\"@") == 0);
+
+	return AST_TEST_PASS;
+}
+
 static int unload_module(void)
 {
 	AST_TEST_UNREGISTER(config_save);
@@ -1956,6 +1985,7 @@ static int unload_module(void)
 	AST_TEST_UNREGISTER(config_dialplan_function);
 	AST_TEST_UNREGISTER(variable_lists_match);
 	AST_TEST_UNREGISTER(variable_list_join_replace);
+	AST_TEST_UNREGISTER(variable_list_from_string);
 	return 0;
 }
 
@@ -1972,6 +2002,7 @@ static int load_module(void)
 	AST_TEST_REGISTER(config_dialplan_function);
 	AST_TEST_REGISTER(variable_lists_match);
 	AST_TEST_REGISTER(variable_list_join_replace);
+	AST_TEST_REGISTER(variable_list_from_string);
 	return AST_MODULE_LOAD_SUCCESS;
 }