Index: src/version.sh
===================================================================
--- src/version.sh	(Revision 2505)
+++ src/version.sh	(Arbeitskopie)
@@ -17,7 +17,7 @@
 # A timestamp, to be used by bumpversion and other scripts.
 # It can be used, for example, to 'touch' this file on every build, thus
 # forcing revision control systems to add it on every checkin automatically.
-version_stamp="2009-01-12 21:08:13"
+version_stamp="So 18. Jan 01:12:24 CET 2009"
 
 # The version number information
 version_micro=718
Index: src/settings/evermore
===================================================================
--- src/settings/evermore	(Revision 2505)
+++ src/settings/evermore	(Arbeitskopie)
@@ -67,6 +67,9 @@
 # we want mysql 
 enable_use_mysql=yes
 
+# we want iksemel
+enable_use_xml2=yes
+
 # but we do not want old names for efuns
 enable_use_deprecated=no
 
Index: src/main.c
===================================================================
--- src/main.c	(Revision 2505)
+++ src/main.c	(Arbeitskopie)
@@ -80,6 +80,10 @@
 #include "pkg-iksemel.h"
 #endif
 
+#ifdef USE_XML2
+#include "pkg-xml2.h"
+#endif
+
 #include "i-eval_cost.h"
 
 #include "../mudlib/sys/regexp.h"
@@ -453,6 +457,10 @@
         pkg_iksemel_init();
 #endif
 
+#ifdef USE_XML2
+        pkg_xml2_init();
+#endif
+
         /* If the master_name hasn't been set, select a sensible default */
         if ('\0' == master_name[0])
         {
@@ -1803,6 +1811,9 @@
 #ifdef USE_IKSEMEL
                               , "iksemel supported\n"
 #endif
+#ifdef USE_XML2
+                              , "libxml2 supported\n"
+#endif
 #ifdef USE_IPV6
                               , "IPv6 supported\n"
 #endif
Index: src/lex.c
===================================================================
--- src/lex.c	(Revision 2505)
+++ src/lex.c	(Arbeitskopie)
@@ -846,7 +846,7 @@
 #ifdef USE_SQLITE
     add_permanent_define("__SQLITE__", -1, string_copy("1"), MY_FALSE);
 #endif
-#ifdef USE_IKSEMEL
+#if defined(USE_IKSEMEL) || defined(USE_XML2)
     add_permanent_define("__XML_DOM__", -1, string_copy("1"), MY_FALSE);
 #endif
 #ifdef USE_ALISTS
Index: src/Makefile.in
===================================================================
--- src/Makefile.in	(Revision 2505)
+++ src/Makefile.in	(Arbeitskopie)
@@ -99,7 +99,7 @@
       interpret.c \
       lex.c main.c mapping.c md5.c mempools.c mregex.c mstrings.c object.c \
       otable.c\
-      parser.c parse.c pkg-alists.c pgk-iksemel.c pkg-idna.c \
+      parser.c parse.c pkg-alists.c pgk-iksemel.c pkg-xml2.c pkg-idna.c \
       pkg-mccp.c pkg-mysql.c pkg-pcre.c \
       pkg-pgsql.c pkg-sqlite.c pkg-tls.c \
       ptmalloc.c port.c ptrtable.c \
@@ -111,7 +111,7 @@
       interpret.o \
       lex.o main.o mapping.o md5.o mempools.o mregex.o mstrings.o object.o \
       otable.o \
-      parser.o parse.o pkg-alists.o pkg-iksemel.o pkg-idna.o \
+      parser.o parse.o pkg-alists.o pkg-iksemel.o pkg-xml2.o pkg-idna.o \
       pkg-mccp.o pkg-mysql.o pkg-pcre.o \
       pkg-pgsql.o pkg-sqlite.o pkg-tls.o \
       ptmalloc.o port.o ptrtable.o \
Index: src/autoconf/configure.in
===================================================================
--- src/autoconf/configure.in	(Revision 2505)
+++ src/autoconf/configure.in	(Arbeitskopie)
@@ -123,7 +123,8 @@
 AC_MY_ARG_ENABLE(use-sqlite,no,,[Enables SQLite support])
 AC_MY_ARG_ENABLE(use-pthreads,no,,[enable using of threads for socket writes])
 AC_MY_ARG_ENABLE(use-pcre,yes,,[Enables PCRE: no/yes/builtin/no-builtin])
-AC_MY_ARG_ENABLE(use-iksemel,no,,[Enables use of iksemel for XML parsing])
+AC_MY_ARG_ENABLE(use-iksemel,no,,[Enables use of iksemel for XML parsing (exclusive to xml2)])
+AC_MY_ARG_ENABLE(use-xml2,no,,[Enables use of libxml2 for XML parsing (exclusive to iksemel)])
 AC_MY_ARG_ENABLE(use-deprecated,yes,,[Enables obsolete and deprecated efuns])
 AC_MY_ARG_ENABLE(use-structs,yes,,[Enables structs])
 AC_MY_ARG_ENABLE(use-tls,no,,[Enables Transport Layer Security over Telnet: no/gnu/ssl/yes])
@@ -327,18 +328,50 @@
 
 AC_UPDATE_VAR(enable_use_iksemel)
 if test "x$enable_use_iksemel" = "x" || test "x$enable_use_iksemel" = "xyes"; then
-  cdef_use_iksemel="#define"
-  iksemel_path=
-  enable_use_iksemel="yes"
+    if test "x$enable_use_xml2" = "x" || test "x$enable_use_xml2" = "xyes" ; then
+        echo "WARNING: iksemel and xml2 support are mutual exclusive."
+        echo "         Disabling iksemel support"
+
+        cdef_use_iksemel="#undef"
+        enable_use_iksemel="no"
+        iksemel_path=
+    else
+        cdef_use_iksemel="#define"
+        iksemel_path=
+        enable_use_iksemel="yes"
+    fi
 elif test "x$enable_use_iksemel" = "xno"; then
   cdef_use_iksemel="#undef"
   iksemel_path=
 else
-  cdef_use_iksemel="#define"
-  iksemel_path="$enable_use_iksemel"
-  enable_use_iksemel="yes"
+  if test "x$enable_use_xml2" != "xno"; then
+    echo "WARNING: iksemel and xml2 support are mutual exclusive."
+    echo "         Disabling iksemel support"
+
+    cdef_use_iksemel="#undef"
+    enable_use_iksemel="no"
+    iksemel_path=
+  else
+    cdef_use_iksemel="#define"
+    iksemel_path="$enable_use_iksemel"
+    enable_use_iksemel="yes"
+  fi
 fi
 
+AC_UPDATE_VAR(enable_use_xml2)
+if test "x$enable_use_xml2" = "x" || test "x$enable_use_xml2" = "xyes"; then
+  cdef_use_xml2="#define"
+  xml2_path=
+  enable_use_xml2="yes"
+elif test "x$enable_use_xml2" = "xno"; then
+  cdef_use_xml2="yes"
+  xml2_path=
+else
+  cdef_use_xml2="#define"
+  xml2_path="$enable_use_xml2"
+  enable_use_xml2="yes"
+fi
+
 AC_UPDATE_VAR(enable_use_tls)
 if test "x$enable_use_tls" = "x" || test "x$enable_use_tls" = "xyes"; then
   cdef_use_tls="#define"
@@ -1747,6 +1780,184 @@
   fi
 fi
 
+# --- libxml2 ---
+
+if test x$xml2_path != x ; then
+    xml_config_args="$xml_config_args"
+    if test x${XML2_CONFIG+set} != xset ; then
+        XML2_CONFIG=$xml2_path/bin/xml2-config
+    fi
+fi
+
+AC_PATH_PROG(XML2_CONFIG, xml2-config, no)
+min_xml_version=2.0.0
+AC_MSG_CHECKING(for libxml - version >= $min_xml_version)
+lp_cv_has_xml2=yes
+if test "$XML2_CONFIG" = "no" ; then
+    lp_cv_has_xml2=no
+else
+    XML_CPPFLAGS=`$XML2_CONFIG $xml_config_args --cflags`
+    XML_LIBS=`$XML2_CONFIG $xml_config_args --libs`
+    xml_config_major_version=`$XML2_CONFIG $xml_config_args --version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'`
+    xml_config_minor_version=`$XML2_CONFIG $xml_config_args --version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'`
+    xml_config_micro_version=`$XML2_CONFIG $xml_config_args --version | \
+           sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'`
+    ac_save_CPPFLAGS="$CPPFLAGS"
+    ac_save_LIBS="$LIBS"
+    CPPFLAGS="$CPPFLAGS $XML_CPPFLAGS"
+    LIBS="$XML_LIBS $LIBS"
+
+dnl
+dnl Now check if the installed libxml is sufficiently new.
+dnl (Also sanity checks the results of xml2-config to some extent)
+dnl
+
+    rm -f conf.xmltest
+    AC_TRY_RUN([
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <libxml/xmlversion.h>
+
+int 
+main()
+{
+    int xml_major_version;
+    int xml_minor_version;
+    int xml_micro_version;
+    int major, minor, micro;
+    char *tmp_version;
+
+    system("touch conf.xmltest");
+
+    /* Capture xml2-config output via autoconf/configure variables */
+    /* HP/UX 9 (%@#!) writes to sscanf strings */
+    tmp_version = (char *)strdup("$min_xml_version");
+  
+    if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, &micro) != 3) 
+    {
+        printf("%s, bad version string from xml2-config\n", "$min_xml_version");
+        exit(1);
+    }
+    free(tmp_version);
+
+    /* Capture the version information from the header files */
+    tmp_version = (char *)strdup(LIBXML_DOTTED_VERSION);
+
+    if (sscanf(tmp_version, "%d.%d.%d", &xml_major_version, &xml_minor_version, &xml_micro_version) != 3) 
+    {
+        printf("%s, bad version string from libxml includes\n", "LIBXML_DOTTED_VERSION");
+        exit(1);
+    }
+    free(tmp_version);
+
+    /* Compare xml2-config output to the libxml headers */
+    if ((xml_major_version != $xml_config_major_version) 
+        || (xml_minor_version != $xml_config_minor_version) 
+        || (xml_micro_version != $xml_config_micro_version))
+    {
+        printf("*** libxml header files (version %d.%d.%d) do not match\n",
+            xml_major_version, xml_minor_version, xml_micro_version);
+        printf("*** xml2-config (version %d.%d.%d)\n",
+            $xml_config_major_version, $xml_config_minor_version, $xml_config_micro_version);
+      
+        return 1;
+    } 
+
+    /* Compare the headers to the library to make sure we match */
+    /* Less than ideal -- doesn't provide us with return value feedback, 
+     * only exits if there's a serious mismatch between header and library.
+     */
+    LIBXML_TEST_VERSION;
+
+    /* Test that the library is greater than our minimum version */
+    if ((xml_major_version > major) 
+        || ((xml_major_version == major) && (xml_minor_version > minor)) 
+        || ((xml_major_version == major) && (xml_minor_version == minor) 
+            && (xml_micro_version >= micro)))
+    {
+        return 0;
+    }
+    else
+    {
+        printf("\n*** An old version of libxml (%d.%d.%d) was found.\n",
+               xml_major_version, xml_minor_version, xml_micro_version);
+        printf("*** You need a version of libxml newer than %d.%d.%d. The latest version of\n",
+           major, minor, micro);
+        printf("*** libxml is always available from ftp://ftp.xmlsoft.org.\n");
+        printf("***\n");
+        printf("*** If you have already installed a sufficiently new version, this error\n");
+        printf("*** probably means that the wrong copy of the xml2-config shell script is\n");
+        printf("*** being found. The easiest way to fix this is to remove the old version\n");
+        printf("*** of LIBXML, but you can also set the XML2_CONFIG environment to point to the\n");
+        printf("*** correct copy of xml2-config. (In this case, you will have to\n");
+        printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n");
+        printf("*** so that the correct libraries are found at run-time))\n");
+    }
+    
+    return 1;
+}
+],, lp_cv_has_xml2=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
+    CPPFLAGS="$ac_save_CPPFLAGS"
+    LIBS="$ac_save_LIBS"
+fi
+
+if test $lp_cv_has_xml2 = yes ; then
+    AC_MSG_RESULT(yes (version $xml_config_major_version.$xml_config_minor_version.$xml_config_micro_version))
+    AC_DEFINE(HAS_XML2, 1, [Does the machine offer xml2?])
+    PKGLIBS="$PKGLIBS $XML_LIBS"
+    EXTRA_CFLAGS="$XML_CPPFLAGS $EXTRA_CFLAGS"
+else
+    AC_MSG_RESULT(no)
+    if test "$XML2_CONFIG" = "no" ; then
+       echo "*** The xml2-config script installed by LIBXML could not be found"
+       echo "*** If libxml was installed in PREFIX, make sure PREFIX/bin is in"
+       echo "*** your path, or set the XML2_CONFIG environment variable to the"
+       echo "*** full path to xml2-config."
+    else 
+       if test -f conf.xmltest ; then
+        :
+       else
+          echo "*** Could not run libxml test program, checking why..."
+          CPPFLAGS="$CPPFLAGS $XML_CPPFLAGS"
+          LIBS="$LIBS $XML_LIBS"
+          AC_TRY_LINK([
+#include <libxml/xmlversion.h>
+#include <stdio.h>
+],      [ LIBXML_TEST_VERSION; return 0;],
+        [ echo "*** The test program compiled, but did not run. This usually means"
+          echo "*** that the run-time linker is not finding LIBXML or finding the wrong"
+          echo "*** version of LIBXML. If it is not finding LIBXML, you'll need to set your"
+          echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point"
+          echo "*** to the installed location  Also, make sure you have run ldconfig if that"
+          echo "*** is required on your system"
+          echo "***"
+          echo "*** If you have an old version installed, it is best to remove it, although"
+          echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" ],
+        [ echo "*** The test program failed to compile or link. See the file config.log for the"
+          echo "*** exact error that occured. This usually means LIBXML was incorrectly installed"
+          echo "*** or that you have moved LIBXML since it was installed. In the latter case, you"
+          echo "*** may want to edit the xml2-config script: $XML2_CONFIG" ])
+          CPPFLAGS="$ac_save_CPPFLAGS"
+          LIBS="$ac_save_LIBS"
+       fi
+    fi
+       
+    XML_CPPFLAGS=""
+    XML_LIBS=""
+
+    AC_NOT_AVAILABLE(use-xml2)
+    cdef_use_xml2="#undef"
+    enable_use_xml2="no"
+    xml2=
+    lp_cv_has_xml2=no
+fi
+AC_SUBST(XML_CPPFLAGS)
+AC_SUBST(XML_LIBS)
+rm -f conf.xmltest
+
 # --- Check if we need zlib libraries for mccp ---
 
 if test "x$enable_use_mccp" = "x" || test "x$enable_use_mccp" = "xyes"; then
@@ -2727,6 +2938,7 @@
 AC_SUBST(cdef_use_pgsql)
 AC_SUBST(cdef_use_sqlite)
 AC_SUBST(cdef_use_iksemel)
+AC_SUBST(cdef_use_xml2)
 AC_SUBST(cdef_use_pthreads)
 AC_SUBST(cdef_use_alists)
 AC_SUBST(cdef_use_mccp)
Index: src/pkg-xml2.c
===================================================================
--- src/pkg-xml2.c	(Revision 0)
+++ src/pkg-xml2.c	(Revision 0)
@@ -0,0 +1,602 @@
+/*------------------------------------------------------------------
+ * xml_* Efuns
+ *
+ *------------------------------------------------------------------
+ * This file holds the efuns interfacing with libxml2 and provides 
+ * functions for handling xml files and converting them between 
+ * mappings and xml data strings.
+ *
+ *   efun: xml_
+ *------------------------------------------------------------------
+ */
+#include "driver.h"
+
+#ifdef USE_XML2
+
+#include <libxml/parser.h>
+#include <libxml/tree.h>
+#include "array.h"
+#include "xalloc.h"
+#include "mapping.h"
+#include "mstrings.h"
+#include "simulate.h"
+#include "interpret.h"
+#include "pkg-xml2.h"
+#include "typedefs.h"
+
+#include "../mudlib/sys/xml.h"
+
+/* Structure to walk over the attribute (properties in libxml2 jargon) to 
+ * create property-nodes
+ */
+typedef struct attribute_walk_extra_s attribute_walk_extra_t;
+
+/* Used to walk all attributes as well as for error handling. In case an 
+ * error happens, this structure is called too.
+ */
+struct attribute_walk_extra_s
+{
+    xmlNodePtr node;
+    int size;
+
+    char *tag_name;
+};
+
+/* Used for error handling. In case of an error our handler called with a 
+ * pointer ot this structure.
+ */
+struct xml_cleanup_s
+{
+    svalue_t head; /* push_error_handler saves the link to our handler here. */
+
+    xmlDocPtr doc;
+};
+
+static void *
+xml_pkg_malloc(size_t size)
+
+/*
+ * Realize malloc with the driver-internal xalloc rather than a direct malloc()
+ */
+{
+    return xalloc(size);
+}
+
+static void
+xml_pkg_free(void * ptr)
+
+/*
+ * Realize free with the driver-internal xfree rather than a direct free()
+ */
+{
+    xfree(ptr);
+}
+
+static void *
+xml_pkg_realloc(void * ptr, size_t size)
+
+/*
+ * Realize realloc() with the driver-internal rexalloc_traced() including file
+ * and line rather the direct realloc()
+ */
+{
+    return rexalloc(ptr, size);
+}
+
+static char *
+xml_pkg_strdup(const char * str)
+
+/*
+ * Realize strdup with the driver interal string_copy instead of the direct
+ * strdup()
+ */
+{
+    return string_copy(str);
+}
+
+void
+add_string_to_mapping(mapping_t *map, char *skey, char *svalue)
+
+/*
+ * Adds a string value under the given key to the given mapping. In case the 
+ * value already exists, it is overriden.
+ */
+{
+    svalue_t key;
+    svalue_t *value;
+
+    /* change the c string into an string_t */
+    put_c_string(&key, skey);
+
+    /* get or insert key */
+    value = get_map_lvalue(map, &key);
+
+    /* free the string_t again */
+    free_svalue(&key);
+
+    /* free maybe existing value (should not happen, i hope) */
+    free_svalue(value);
+
+    /* change the value of the key to the given value */
+    put_c_string(value, svalue);
+}
+
+void
+parse_node(svalue_t *result, xmlNodePtr node)
+
+/*
+ * Parses the xml document beginning at <node> and returns the information 
+ * on the stack in <result>.
+ */
+{
+    int i = 0;
+    int num_attributes = 0;
+    int num_children = 0;
+
+    xmlAttrPtr attrib;
+    xmlNodePtr child;
+
+    vector_t *root = NULL;
+    vector_t *children = NULL;
+    mapping_t *attributes = NULL;
+
+    /* lets figure out if the node is cdata or another tag */
+    switch (node->type)
+    {
+        case XML_TEXT_NODE:
+            put_c_n_string(result
+                        , (char *) node->content
+                        , strlen((char *) node->content));
+
+            return;
+        case XML_ELEMENT_NODE:
+            break;
+
+        default:
+            /* we ignore all others */
+            return;
+    }
+
+    /* We have a tag here, so allocate a tag array with three elements 
+     * (name, contents and attributes)
+     */
+    memsafe(root = allocate_array(XML_TAG_SIZE), sizeof(*root)
+           , "new tag array");
+
+    /* Put the array as result */
+    put_array(result, root);
+
+    /* add name to array */
+    put_c_string(&root->item[XML_TAG_NAME], (char *) node->name);
+
+    /* check if the node has any children */
+    child = node->children;
+    if (child != NULL)
+    {
+        do
+        {
+            if (child->type == XML_ELEMENT_NODE || child->type == XML_TEXT_NODE)
+            {
+                ++num_children;
+            }
+        }
+        while ((child = child->next) != NULL);
+    }
+
+    if (0 < num_children)
+    {
+        /* children need to stay in the right order, so we create another
+         * array for them
+         */
+        memsafe(children = allocate_array(num_children), sizeof(*children)
+                , "new tag contents array");
+
+        /* Add the array of all children to the node */
+        put_array(&root->item[XML_TAG_CONTENTS], children);
+
+        /* get the first child */
+        child = node->children;
+
+        do
+        {
+            if (child->type == XML_ELEMENT_NODE || child->type == XML_TEXT_NODE)
+            {
+                /* recurse here cause the child can be a string or another node */
+                parse_node(&children->item[i++], child);        
+            }
+        }
+        while ((child = child->next) != NULL);
+    }
+
+    /* Finally, lets handle the attributes, we need to find out how many
+     * attributes the node has, to allocate enough memory for them. If
+     * no attributes exist, the part in the array will be empty 
+     */
+    attrib = node->properties;
+    if (attrib != NULL)
+    {
+        do 
+        {
+            ++num_attributes;
+        }
+        while ((attrib = attrib->next) != NULL);
+    }
+
+    if (0 < num_attributes)
+    {
+        /* allocate new mapping */
+        memsafe(attributes = allocate_mapping(num_attributes, 1)
+                , sizeof(*attributes), "new attributes mapping");
+
+        /* add the attributes to the array */
+        put_mapping(&root->item[XML_TAG_ATTRIBUTES], attributes);
+
+        /* get the first one */
+        attrib = node->properties;
+
+        do
+        {
+            xmlChar * value = xmlGetProp(node, attrib->name);
+
+            add_string_to_mapping(attributes, (char *) attrib->name
+                               , (char *) value);
+
+            // we need to free the old one as the driver creates an
+            // lpc string and thus copies it
+            xmlFree(value);
+        }
+        while ((attrib = attrib->next) != NULL);
+   }
+}
+
+void
+walk_attribute_mapping(svalue_t *key, svalue_t *val, void *pextra)
+
+/*
+ * Callback for walk_mapping() used in generate_xml_node to add 
+ * property-nodes to the node given in the <pextra>. 
+ */
+{
+    char *ckey;
+    attribute_walk_extra_t *extra = pextra;
+
+    if (key->type == T_STRING)
+    {
+        ckey = get_txt(key->u.str);
+    }
+    else
+    {
+        errorf("Bad argument 1 to xml_generate(): expected string \
+                for attribute key of tag '%s'.\n", extra->tag_name);
+
+        /* NOTREACHED */
+        return;
+    }
+
+    if (val->type == T_STRING)
+    {
+        memsafe(xmlSetProp(extra->node
+                        , (xmlChar *) ckey
+                        , (xmlChar *) get_txt(val->u.str))
+              , sizeof(*ckey), "new attribute");
+    }
+    else
+    {
+        errorf("Bad argument 1 to xml_generate(): expected string for \
+                value of attribute '%s' of tag '%s'.\n"
+              , ckey, extra->tag_name);
+    }
+}
+
+static void
+xml_cleanup(svalue_t * arg)
+    
+/*
+ * Takes care, that the xml document is correctly freed in case of an error 
+ * and at the end of the f_generate_xml(). Additionally the xml-parser 
+ * is cleaned up
+ */
+{
+    struct xml_cleanup_s * data;
+
+    data = (struct xml_cleanup_s *) arg;
+
+    if (data->doc)
+    {
+        xmlFreeDoc(data->doc);
+    }
+    
+    xmlCleanupParser();
+
+    xfree(data);
+} /* xml_cleanup() */
+
+void
+generate_xml_node(vector_t * vnode, xmlNodePtr parent, xmlDocPtr doc)
+
+/* 
+ * Generates a new xml node from the given array structure with the three 
+ * elements (name, contents, attributes) and adds the node to the <parent>
+ * if it already exists, or to the xml <doc>ument, The contents element may 
+ * contain other tags, so recursion may occur.
+ */
+{
+    xmlNodePtr node;
+    svalue_t *element;
+    char *name;
+    struct xml_cleanup_s * rec_data;
+
+    if ((mp_int) VEC_SIZE(vnode) != 3)
+    {
+        errorf("Bad arg 1 to xml_generate(): tag is not an array with 3 \
+                elements.\n");
+
+        /* NOTREACHED */
+        return;
+    }
+
+    /* get the name, as this is essential */
+    element = &vnode->item[XML_TAG_NAME];
+
+    if (element->type != T_STRING)
+    {
+        errorf("Bad arg 1 to xml_generate(): first element of tag array \
+                not a string.\n");
+
+        /* NOTREACHED */
+        return;
+    }
+
+    /* get the name */
+    name = get_txt(element->u.str);
+
+    /* depending whether there is a parent or not, we start the structure 
+     * or add the node to the given one */
+    if (parent == NULL)
+    {
+        rec_data = xalloc(sizeof(*rec_data));
+        if (rec_data == NULL)
+        {
+            xmlFreeDoc(doc);
+
+            errorf("generate_xml() Out of memory: (%lu bytes) for \
+                    cleanup structure\n", (unsigned long) sizeof(*rec_data));
+
+            /* NOTREACHED */
+            return;
+        }
+        
+        rec_data->doc = doc;
+
+        push_error_handler(xml_cleanup, &(rec_data->head));
+
+        /** Create first node */
+        memsafe(doc->children = xmlNewDocNode(doc, NULL, (xmlChar *) name, NULL)
+                , 30, "new root node");
+
+        node = doc->children;
+    }
+    else
+    {
+        memsafe(node = xmlNewChild(parent, NULL, (xmlChar *) name, NULL), 30
+                , "insert new child node");
+    }
+
+    /* now handle the attributes of this one */
+    element = &vnode->item[XML_TAG_ATTRIBUTES];
+
+    /* this might be absent */
+    if (element->type == T_MAPPING)
+    {
+        attribute_walk_extra_t extra;
+
+        extra.node = node;
+        extra.size = element->u.map->num_values;
+        extra.tag_name = name;
+
+        /* walk the mapping and add all attributes */
+        walk_mapping(element->u.map, &walk_attribute_mapping, &extra);
+    }
+    else if (element->type != T_NUMBER || element->u.number != 0)
+    {
+        errorf("Bad arg 1 to xml_generate(): second element of tag array not "
+               "NULL/mapping.\n");
+
+        /* NOTREACHED */
+        return;
+    }
+
+    /* now check, if the node has a contents */
+    element = &vnode->item[XML_TAG_CONTENTS];
+
+    /* this might even be absent */
+    if (element->type == T_POINTER)
+    {
+        int size;
+        int i;
+        vector_t *contents;
+
+        /* get the vector */
+        contents = element->u.vec;
+
+        /* get its size */
+        size = (mp_int)VEC_SIZE(contents);
+        
+        for (i = 0; i < size; i++)
+        {
+            element = &contents->item[i];
+
+            if (element->type == T_STRING)
+            {
+                /* found content */
+                xmlNodePtr text;
+                
+                memsafe(text = xmlNewTextLen((xmlChar *) get_txt(element->u.str)
+                            , mstrsize(element->u.str))
+                            , mstrsize(element->u.str), "new text content");
+
+                xmlAddChild(node, text);
+            }
+            else if (element->type == T_POINTER)
+            {
+                /* found a sub tag, as iks_insert will handle the insert we do
+                 * not have anything to do with the result
+                 */
+                generate_xml_node(element->u.vec, node, doc);
+            }
+        }
+    }
+    else if (element->type != T_NUMBER || element->u.number != 0)
+    {
+        errorf("Bad arg 1 to xml_generate(): third element of tag array not "
+               "NULL/array.\n");
+
+        /* NOTREACHED */
+    }
+}
+
+void
+pkg_xml2_init()
+{
+    xmlMemSetup(xml_pkg_free, xml_pkg_malloc, xml_pkg_realloc, xml_pkg_strdup);
+}
+
+/*=========================================================================*/
+
+/*                           EFUNS                                         */
+
+/*-------------------------------------------------------------------------*/
+
+svalue_t *
+f_xml_generate(svalue_t *sp)
+
+/* EFUN xml_generate()
+ *
+ *     string xml_generate(mixed *xml)
+ *
+ * Converts the given <xml> array into an XML conform string, if
+ * possible. The <xml> argument array must have the same structure
+ * as xml_parse returns.
+ *
+ * In case the parameter does not follow these rules, errors are raised.
+ * The method returns a valid XML string otherwise.
+ */
+{
+    xmlChar * xml_string;
+    xmlDocPtr doc;
+    vector_t * root;
+    int bufferSize;
+
+    /* get the root of the structure to be used */
+    root = sp->u.vec;
+
+    /* create the document itself */
+    doc = xmlNewDoc((xmlChar *) "1.0");
+
+    /* start generating the tree */
+    generate_xml_node(root, NULL, doc);
+    
+    /* Clean up and return result */
+    free_svalue(sp);
+
+    xmlDocDumpFormatMemory(doc, &xml_string, &bufferSize, 1);
+
+    /* send the xml string back onto the stack */
+    put_c_string(sp, (char *) xml_string);
+
+    /* free the value once again */
+    xmlFree(xml_string);
+
+    /* clean up, this will free the root node too, as it calls our 
+     * error handler */
+    pop_stack();
+
+    return sp;
+}
+
+void
+xml_pkg_error_handler(void * userData, xmlErrorPtr error)
+{
+    if (error)
+    {
+        errorf("Bad arg 1 to xml_parse(): %s", error->message);
+    }
+}
+
+svalue_t *
+f_xml_parse(svalue_t * sp)
+
+/* EFUN xml_parse()
+ *
+ *     mixed * xml_parse(string xml_text)
+ *
+ * Parses the given string <xml> as a XML conform string. The string must
+ * have only one root tag, subsequent root tags are ignored.
+ *
+ * If the xml string is correct, an array is of three elements is
+ * returned, where as the following indices are defined:
+ *
+ *     string XML_TAG_NAME
+ *         The name of the XML tag.
+ *
+ *     mixed * XML_TAG_CONTENTS
+ *         The contents of this xml tag as array. This array may
+ *         contain either strings, or arrags of sub-tags again with
+ *         three elements (see example)
+ *
+ *         If the xml tag does not contain anything, the element is
+ *         set 0.
+ *
+ *     mapping XML_TAG_ATTRIBUTES
+ *         All attributes given to the XML tag as mapping where the key
+ *         is the attribute name and the value is its string value.
+ *
+ *         If the xml tag does not contain any attributes, this element
+ *         is set 0.
+ *
+ * If the XML string is not well formed, or there is not enough memory to
+ * parse the whole XML structure into the array an error is raised. In case
+ * the XML string can't be parsed, cause it is not valid XML, 0 is returned.
+ */
+{
+    struct xml_cleanup_s * rec_data;
+
+    memsafe(rec_data = xalloc(sizeof(*rec_data)), sizeof(*rec_data)
+            , "xml cleanup structure");
+    rec_data->doc = NULL;
+    push_error_handler(xml_cleanup, &(rec_data->head));
+
+    /* Disable standard error functions, as they will print out errors
+     * to stderr automatically. We do not want that.
+     */
+    xmlSetGenericErrorFunc(NULL, NULL);
+    xmlSetStructuredErrorFunc(NULL, xml_pkg_error_handler);
+
+    rec_data->doc = xmlReadMemory(get_txt(sp->u.str), mstrsize(sp->u.str)
+                                , NULL, NULL, 0);
+
+    if (rec_data->doc == NULL)
+    {
+        /* Unfortunately, the error handler is not always called */
+        errorf("Bad arg 1 to xml_parse(): not a valid XML document.\n");
+
+        /* NOT REACHED */
+        return sp;
+    }
+
+    /* we no longer need the string */
+    free_svalue(sp);
+
+    /* set 0 to always have a valid return */
+    put_number(sp, 0);
+
+    /* tree contains the tree now, this will put the resulting a */
+    parse_node(sp, xmlDocGetRootElement(rec_data->doc));
+
+    /* At the end, be nice and remove the rest using our error handler. */
+    pop_stack();
+ 
+    return sp;
+}
+ 
+#endif /* USE_XML2 */
Index: src/pkg-xml2.h
===================================================================
--- src/pkg-xml2.h	(Revision 0)
+++ src/pkg-xml2.h	(Revision 0)
@@ -0,0 +1,19 @@
+#ifndef PKG_XML2_H__
+#define PKG_XML2_H__ 1
+
+#include "driver.h"
+
+#ifdef USE_XML2
+
+#ifndef HAS_XML2
+#error "pkg-xml2 configured even though the machine doesn't support libxml2."
+#endif
+
+/* --- Prototypes --- */
+
+void pkg_xml2_init();
+
+#endif /* USE_XML2 */
+
+#endif /* PKG_XML2_H__ */
+
Index: src/config.h.in
===================================================================
--- src/config.h.in	(Revision 2505)
+++ src/config.h.in	(Arbeitskopie)
@@ -382,6 +382,10 @@
  */
 @cdef_use_iksemel@ USE_IKSEMEL
 
+/* Define this if you want libxml2 support.
+ */
+@cdef_use_xml2@ USE_XML2
+
 /* Define this if you want the obsolete and deprecated efuns.
  */
 @cdef_use_deprecated@ USE_DEPRECATED
Index: src/func_spec
===================================================================
--- src/func_spec	(Revision 2505)
+++ src/func_spec	(Arbeitskopie)
@@ -701,14 +701,13 @@
 #endif /* USE_MCCP */
 
 
-#ifdef USE_IKSEMEL
+#if defined(USE_IKSEMEL) || defined(USE_XML2)
 
 string  xml_generate(mixed *);
 mixed  *xml_parse(string);
 
-#endif /* USE_IKSEMEL */
+#endif /* USE_IKSEMEL || USE_XML2 */
 
-
 #ifdef USE_MYSQL
 
 int     db_affected_rows(int);
