summaryrefslogtreecommitdiff
path: root/ext/xmlrpc
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@baserock.org>2013-03-14 05:42:27 +0000
committer <>2013-04-03 16:25:08 +0000
commitc4dd7a1a684490673e25aaf4fabec5df138854c4 (patch)
tree4d57c44caae4480efff02b90b9be86f44bf25409 /ext/xmlrpc
downloadphp2-master.tar.gz
Imported from /home/lorry/working-area/delta_php2/php-5.4.13.tar.bz2.HEADphp-5.4.13master
Diffstat (limited to 'ext/xmlrpc')
-rw-r--r--ext/xmlrpc/CREDITS2
-rw-r--r--ext/xmlrpc/EXPERIMENTAL5
-rw-r--r--ext/xmlrpc/config.m4122
-rw-r--r--ext/xmlrpc/config.w3220
-rw-r--r--ext/xmlrpc/libxmlrpc/README17
-rw-r--r--ext/xmlrpc/libxmlrpc/acinclude.m432
-rw-r--r--ext/xmlrpc/libxmlrpc/base64.c192
-rw-r--r--ext/xmlrpc/libxmlrpc/base64.h38
-rw-r--r--ext/xmlrpc/libxmlrpc/encodings.c126
-rw-r--r--ext/xmlrpc/libxmlrpc/encodings.h46
-rw-r--r--ext/xmlrpc/libxmlrpc/queue.c982
-rw-r--r--ext/xmlrpc/libxmlrpc/queue.h89
-rw-r--r--ext/xmlrpc/libxmlrpc/simplestring.c248
-rw-r--r--ext/xmlrpc/libxmlrpc/simplestring.h76
-rw-r--r--ext/xmlrpc/libxmlrpc/system_methods.c375
-rw-r--r--ext/xmlrpc/libxmlrpc/system_methods_private.h91
-rw-r--r--ext/xmlrpc/libxmlrpc/xml_element.c767
-rw-r--r--ext/xmlrpc/libxmlrpc/xml_element.h202
-rw-r--r--ext/xmlrpc/libxmlrpc/xml_to_dandarpc.c319
-rw-r--r--ext/xmlrpc/libxmlrpc/xml_to_dandarpc.h44
-rw-r--r--ext/xmlrpc/libxmlrpc/xml_to_soap.c670
-rw-r--r--ext/xmlrpc/libxmlrpc/xml_to_soap.h44
-rw-r--r--ext/xmlrpc/libxmlrpc/xml_to_xmlrpc.c414
-rw-r--r--ext/xmlrpc/libxmlrpc/xml_to_xmlrpc.h45
-rw-r--r--ext/xmlrpc/libxmlrpc/xmlrpc.c3006
-rw-r--r--ext/xmlrpc/libxmlrpc/xmlrpc.h454
-rw-r--r--ext/xmlrpc/libxmlrpc/xmlrpc.m412
-rw-r--r--ext/xmlrpc/libxmlrpc/xmlrpc_introspection.c604
-rw-r--r--ext/xmlrpc/libxmlrpc/xmlrpc_introspection.h101
-rw-r--r--ext/xmlrpc/libxmlrpc/xmlrpc_introspection_private.h106
-rw-r--r--ext/xmlrpc/libxmlrpc/xmlrpc_private.h178
-rw-r--r--ext/xmlrpc/libxmlrpc/xmlrpc_win32.h16
-rw-r--r--ext/xmlrpc/php_xmlrpc.h96
-rw-r--r--ext/xmlrpc/tests/001.phpt55
-rw-r--r--ext/xmlrpc/tests/002.phpt53
-rw-r--r--ext/xmlrpc/tests/bug18916.phpt23
-rw-r--r--ext/xmlrpc/tests/bug37057.phpt64
-rw-r--r--ext/xmlrpc/tests/bug38431.phpt25
-rw-r--r--ext/xmlrpc/tests/bug40576.phpt77
-rw-r--r--ext/xmlrpc/tests/bug40576_64bit.phpt77
-rw-r--r--ext/xmlrpc/tests/bug42189.phpt15
-rw-r--r--ext/xmlrpc/tests/bug42736.phpt56
-rw-r--r--ext/xmlrpc/tests/bug44996.phpt51
-rw-r--r--ext/xmlrpc/tests/bug45226.phpt55
-rw-r--r--ext/xmlrpc/tests/bug45555.phpt22
-rw-r--r--ext/xmlrpc/tests/bug45556.phpt34
-rw-r--r--ext/xmlrpc/tests/bug47818.phpt41
-rw-r--r--ext/xmlrpc/tests/bug50282.phpt43
-rw-r--r--ext/xmlrpc/tests/bug50285.phpt117
-rw-r--r--ext/xmlrpc/tests/bug50761.phpt64
-rw-r--r--ext/xmlrpc/tests/bug51288.phpt16
-rw-r--r--ext/xmlrpc/tests/bug61097.phpt16
-rw-r--r--ext/xmlrpc/tests/bug61264.phpt19
-rw-r--r--ext/xmlrpc/xmlrpc-epi-php.c1546
-rw-r--r--ext/xmlrpc/xmlrpc.dsp211
55 files changed, 12219 insertions, 0 deletions
diff --git a/ext/xmlrpc/CREDITS b/ext/xmlrpc/CREDITS
new file mode 100644
index 0000000..cfb14fa
--- /dev/null
+++ b/ext/xmlrpc/CREDITS
@@ -0,0 +1,2 @@
+xmlrpc
+Dan Libby
diff --git a/ext/xmlrpc/EXPERIMENTAL b/ext/xmlrpc/EXPERIMENTAL
new file mode 100644
index 0000000..6443e99
--- /dev/null
+++ b/ext/xmlrpc/EXPERIMENTAL
@@ -0,0 +1,5 @@
+this extension is experimental,
+its functions may change their names
+or move to extension all together
+so do not rely to much on them
+you have been warned!
diff --git a/ext/xmlrpc/config.m4 b/ext/xmlrpc/config.m4
new file mode 100644
index 0000000..389d4ad
--- /dev/null
+++ b/ext/xmlrpc/config.m4
@@ -0,0 +1,122 @@
+dnl
+dnl $Id$
+dnl
+
+sinclude(ext/xmlrpc/libxmlrpc/acinclude.m4)
+sinclude(ext/xmlrpc/libxmlrpc/xmlrpc.m4)
+sinclude(libxmlrpc/acinclude.m4)
+sinclude(libxmlrpc/xmlrpc.m4)
+
+PHP_ARG_WITH(xmlrpc, for XMLRPC-EPI support,
+[ --with-xmlrpc[=DIR] Include XMLRPC-EPI support])
+
+if test -z "$PHP_LIBXML_DIR"; then
+ PHP_ARG_WITH(libxml-dir, libxml2 install dir,
+ [ --with-libxml-dir=DIR XMLRPC-EPI: libxml2 install prefix], no, no)
+fi
+
+PHP_ARG_WITH(libexpat-dir, libexpat dir for XMLRPC-EPI,
+[ --with-libexpat-dir=DIR XMLRPC-EPI: libexpat dir for XMLRPC-EPI (deprecated)],no,no)
+
+PHP_ARG_WITH(iconv-dir, iconv dir for XMLRPC-EPI,
+[ --with-iconv-dir=DIR XMLRPC-EPI: iconv dir for XMLRPC-EPI],no,no)
+
+if test "$PHP_XMLRPC" != "no"; then
+
+ PHP_ADD_EXTENSION_DEP(xmlrpc, libxml)
+ PHP_SUBST(XMLRPC_SHARED_LIBADD)
+ AC_DEFINE(HAVE_XMLRPC,1,[ ])
+
+ dnl
+ dnl Default to libxml2 if --with-libexpat-dir is not used
+ dnl
+ if test "$PHP_LIBEXPAT_DIR" = "no"; then
+
+ if test "$PHP_LIBXML" = "no"; then
+ AC_MSG_ERROR([XML-RPC extension requires LIBXML extension, add --enable-libxml])
+ fi
+
+ PHP_SETUP_LIBXML(XMLRPC_SHARED_LIBADD, [
+ if test "$PHP_XML" = "no"; then
+ PHP_ADD_SOURCES(ext/xml, compat.c)
+ PHP_ADD_BUILD_DIR(ext/xml)
+ fi
+ ], [
+ AC_MSG_ERROR([xml2-config not found. Use --with-libxml-dir=<DIR>])
+ ])
+ else
+ testval=no
+ for i in $PHP_LIBEXPAT_DIR $XMLRPC_DIR /usr/local /usr; do
+ if test -f $i/$PHP_LIBDIR/libexpat.a || test -f $i/$PHP_LIBDIR/libexpat.$SHLIB_SUFFIX_NAME; then
+ AC_DEFINE(HAVE_LIBEXPAT,1,[ ])
+ PHP_ADD_LIBRARY_WITH_PATH(expat, $i/$PHP_LIBDIR, XMLRPC_SHARED_LIBADD)
+ PHP_ADD_INCLUDE($i/include)
+ testval=yes
+ break
+ fi
+ done
+
+ if test "$testval" = "no"; then
+ AC_MSG_ERROR([XML-RPC support requires libexpat. Use --with-libexpat-dir=<DIR> (deprecated!)])
+ fi
+ fi
+
+ dnl if iconv is shared or missing then we should build iconv ourselves
+ if test "$PHP_ICONV_SHARED" = "yes" || test "$PHP_ICONV" = "no"; then
+
+ if test "$PHP_ICONV_DIR" != "no"; then
+ PHP_ICONV=$PHP_ICONV_DIR
+ fi
+
+ if test -z "$PHP_ICONV" || test "$PHP_ICONV" = "no"; then
+ PHP_ICONV=yes
+ fi
+
+ PHP_SETUP_ICONV(XMLRPC_SHARED_LIBADD, [], [
+ AC_MSG_ERROR([iconv not found, in order to build xmlrpc you need the iconv library])
+ ])
+ fi
+fi
+
+if test "$PHP_XMLRPC" = "yes"; then
+ XMLRPC_CHECKS
+ PHP_NEW_EXTENSION(xmlrpc,xmlrpc-epi-php.c libxmlrpc/base64.c \
+ libxmlrpc/simplestring.c libxmlrpc/xml_to_dandarpc.c \
+ libxmlrpc/xmlrpc_introspection.c libxmlrpc/encodings.c \
+ libxmlrpc/system_methods.c libxmlrpc/xml_to_xmlrpc.c \
+ libxmlrpc/queue.c libxmlrpc/xml_element.c libxmlrpc/xmlrpc.c \
+ libxmlrpc/xml_to_soap.c,$ext_shared,,
+ -I@ext_srcdir@/libxmlrpc -DVERSION="0.50")
+ PHP_ADD_BUILD_DIR($ext_builddir/libxmlrpc)
+ XMLRPC_MODULE_TYPE=builtin
+
+elif test "$PHP_XMLRPC" != "no"; then
+
+ if test -r $PHP_XMLRPC/include/xmlrpc.h; then
+ XMLRPC_DIR=$PHP_XMLRPC/include
+ elif test -r $PHP_XMLRPC/include/xmlrpc-epi/xmlrpc.h; then
+dnl some xmlrpc-epi header files have generic file names like
+dnl queue.h or base64.h. Distributions have to create dir
+dnl for xmlrpc-epi because of this.
+ XMLRPC_DIR=$PHP_XMLRPC/include/xmlrpc-epi
+ else
+ AC_MSG_CHECKING(for XMLRPC-EPI in default path)
+ for i in /usr/local /usr; do
+ if test -r $i/include/xmlrpc.h; then
+ XMLRPC_DIR=$i/include
+ AC_MSG_RESULT(found in $i)
+ break
+ fi
+ done
+ fi
+
+ if test -z "$XMLRPC_DIR"; then
+ AC_MSG_RESULT(not found)
+ AC_MSG_ERROR(Please reinstall the XMLRPC-EPI distribution)
+ fi
+
+ PHP_ADD_INCLUDE($XMLRPC_DIR)
+ PHP_ADD_LIBRARY_WITH_PATH(xmlrpc, $XMLRPC_DIR/$PHP_LIBDIR, XMLRPC_SHARED_LIBADD)
+ PHP_NEW_EXTENSION(xmlrpc,xmlrpc-epi-php.c, $ext_shared)
+ XMLRPC_MODULE_TYPE=external
+fi
diff --git a/ext/xmlrpc/config.w32 b/ext/xmlrpc/config.w32
new file mode 100644
index 0000000..4da691e
--- /dev/null
+++ b/ext/xmlrpc/config.w32
@@ -0,0 +1,20 @@
+// $Id$
+// vim:ft=javascript
+
+ARG_WITH("xmlrpc", "XMLRPC-EPI support", "no");
+
+if (PHP_XMLRPC != "no") {
+ if (CHECK_HEADER_ADD_INCLUDE("xmlrpc.h", "CFLAGS_XMLRPC", configure_module_dirname + "/libxmlrpc")
+ && CHECK_HEADER_ADD_INCLUDE("iconv.h", "CFLAGS")
+ && ADD_EXTENSION_DEP('xmlrpc', 'libxml')) {
+ EXTENSION('xmlrpc', 'xmlrpc-epi-php.c', PHP_XMLRPC_SHARED, "-DVERSION=\"0.50\"");
+ ADD_SOURCES(configure_module_dirname + "/libxmlrpc", "base64.c simplestring.c xml_to_dandarpc.c \
+ xmlrpc_introspection.c encodings.c system_methods.c xml_to_xmlrpc.c \
+ queue.c xml_element.c xmlrpc.c xml_to_soap.c", "xmlrpc");
+
+ } else {
+ WARNING("xmlrpc support can't be enabled, libraries or headers are missing")
+ PHP_XMLRPC = "no";
+ }
+}
+
diff --git a/ext/xmlrpc/libxmlrpc/README b/ext/xmlrpc/libxmlrpc/README
new file mode 100644
index 0000000..323edfa
--- /dev/null
+++ b/ext/xmlrpc/libxmlrpc/README
@@ -0,0 +1,17 @@
+organization of this directory is moving towards this approach:
+
+<module>.h -- public API and data types
+<module>_private.h -- protected API and data types
+<module>.c -- implementation and private API / types
+
+The rules are:
+.c files may include *_private.h.
+.h files may not include *_private.h
+
+This allows us to have a nicely encapsulated C api with opaque data types and private functions
+that are nonetheless shared between source files without redundant extern declarations..
+
+
+
+
+
diff --git a/ext/xmlrpc/libxmlrpc/acinclude.m4 b/ext/xmlrpc/libxmlrpc/acinclude.m4
new file mode 100644
index 0000000..49b6090
--- /dev/null
+++ b/ext/xmlrpc/libxmlrpc/acinclude.m4
@@ -0,0 +1,32 @@
+# Local macros for automake & autoconf
+
+AC_DEFUN([XMLRPC_FUNCTION_CHECKS],[
+
+# Standard XMLRPC list
+AC_CHECK_FUNCS( \
+ strtoul strtoull snprintf \
+ strstr strpbrk strerror\
+ memcpy memmove)
+
+])
+
+AC_DEFUN([XMLRPC_HEADER_CHECKS],[
+AC_HEADER_STDC
+AC_CHECK_HEADERS(xmlparse.h xmltok.h stdlib.h strings.h string.h)
+])
+
+AC_DEFUN([XMLRPC_TYPE_CHECKS],[
+
+AC_REQUIRE([AC_C_CONST])
+AC_REQUIRE([AC_C_INLINE])
+AC_CHECK_SIZEOF(char, 1)
+
+AC_CHECK_SIZEOF(int, 4)
+AC_CHECK_SIZEOF(long, 4)
+AC_CHECK_SIZEOF(long long, 8)
+AC_TYPE_SIZE_T
+AC_HEADER_TIME
+AC_TYPE_UID_T
+
+
+])
diff --git a/ext/xmlrpc/libxmlrpc/base64.c b/ext/xmlrpc/libxmlrpc/base64.c
new file mode 100644
index 0000000..d020bd6
--- /dev/null
+++ b/ext/xmlrpc/libxmlrpc/base64.c
@@ -0,0 +1,192 @@
+static const char rcsid[] = "#(@) $Id$";
+
+/*
+
+ Encode or decode file as MIME base64 (RFC 1341)
+
+ by John Walker
+ http://www.fourmilab.ch/
+
+ This program is in the public domain.
+
+*/
+#include <stdio.h>
+
+/* ENCODE -- Encode binary file into base64. */
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "base64.h"
+
+static unsigned char dtable[512];
+
+void buffer_new(struct buffer_st *b)
+{
+ b->length = 512;
+ b->data = malloc(sizeof(char)*(b->length));
+ b->data[0] = 0;
+ b->ptr = b->data;
+ b->offset = 0;
+}
+
+void buffer_add(struct buffer_st *b, char c)
+{
+ *(b->ptr++) = c;
+ b->offset++;
+ if (b->offset == b->length) {
+ b->length += 512;
+ b->data = realloc(b->data, b->length);
+ b->ptr = b->data + b->offset;
+ }
+}
+
+void buffer_delete(struct buffer_st *b)
+{
+ free(b->data);
+ b->length = 0;
+ b->offset = 0;
+ b->ptr = NULL;
+ b->data = NULL;
+}
+
+void base64_encode_xmlrpc(struct buffer_st *b, const char *source, int length)
+{
+ int i, hiteof = 0;
+ int offset = 0;
+ int olen;
+
+ olen = 0;
+
+ buffer_new(b);
+
+ /* Fill dtable with character encodings. */
+
+ for (i = 0; i < 26; i++) {
+ dtable[i] = 'A' + i;
+ dtable[26 + i] = 'a' + i;
+ }
+ for (i = 0; i < 10; i++) {
+ dtable[52 + i] = '0' + i;
+ }
+ dtable[62] = '+';
+ dtable[63] = '/';
+
+ while (!hiteof) {
+ unsigned char igroup[3], ogroup[4];
+ int c, n;
+
+ igroup[0] = igroup[1] = igroup[2] = 0;
+ for (n = 0; n < 3; n++) {
+ c = *(source++);
+ offset++;
+ if (offset > length) {
+ hiteof = 1;
+ break;
+ }
+ igroup[n] = (unsigned char) c;
+ }
+ if (n > 0) {
+ ogroup[0] = dtable[igroup[0] >> 2];
+ ogroup[1] = dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
+ ogroup[2] = dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
+ ogroup[3] = dtable[igroup[2] & 0x3F];
+
+ /* Replace characters in output stream with "=" pad
+ characters if fewer than three characters were
+ read from the end of the input stream. */
+
+ if (n < 3) {
+ ogroup[3] = '=';
+ if (n < 2) {
+ ogroup[2] = '=';
+ }
+ }
+ for (i = 0; i < 4; i++) {
+ buffer_add(b, ogroup[i]);
+ if (!(b->offset % 72)) {
+ /* buffer_add(b, '\r'); */
+ buffer_add(b, '\n');
+ }
+ }
+ }
+ }
+ /* buffer_add(b, '\r'); */
+ buffer_add(b, '\n');
+}
+
+void base64_decode_xmlrpc(struct buffer_st *bfr, const char *source, int length)
+{
+ int i;
+ int offset = 0;
+ int endoffile;
+ int count;
+
+ buffer_new(bfr);
+
+ for (i = 0; i < 255; i++) {
+ dtable[i] = 0x80;
+ }
+ for (i = 'A'; i <= 'Z'; i++) {
+ dtable[i] = 0 + (i - 'A');
+ }
+ for (i = 'a'; i <= 'z'; i++) {
+ dtable[i] = 26 + (i - 'a');
+ }
+ for (i = '0'; i <= '9'; i++) {
+ dtable[i] = 52 + (i - '0');
+ }
+ dtable['+'] = 62;
+ dtable['/'] = 63;
+ dtable['='] = 0;
+
+ endoffile = 0;
+
+ /*CONSTANTCONDITION*/
+ while (1) {
+ unsigned char a[4], b[4], o[3];
+
+ for (i = 0; i < 4; i++) {
+ int c;
+ while (1) {
+ c = *(source++);
+ offset++;
+ if (offset > length) endoffile = 1;
+ if (isspace(c) || c == '\n' || c == '\r') continue;
+ break;
+ }
+
+ if (endoffile) {
+ /*
+ if (i > 0) {
+ fprintf(stderr, "Input file incomplete.\n");
+ exit(1);
+ }
+ */
+ return;
+ }
+
+ if (dtable[c] & 0x80) {
+ /*
+ fprintf(stderr, "Offset %i length %i\n", offset, length);
+ fprintf(stderr, "character '%c:%x:%c' in input file.\n", c, c, dtable[c]);
+ exit(1);
+ */
+ i--;
+ continue;
+ }
+ a[i] = (unsigned char) c;
+ b[i] = (unsigned char) dtable[c];
+ }
+ o[0] = (b[0] << 2) | (b[1] >> 4);
+ o[1] = (b[1] << 4) | (b[2] >> 2);
+ o[2] = (b[2] << 6) | b[3];
+ i = a[2] == '=' ? 1 : (a[3] == '=' ? 2 : 3);
+ count = 0;
+ while (count < i) {
+ buffer_add(bfr, o[count++]);
+ }
+ if (i < 3) {
+ return;
+ }
+ }
+}
diff --git a/ext/xmlrpc/libxmlrpc/base64.h b/ext/xmlrpc/libxmlrpc/base64.h
new file mode 100644
index 0000000..6a0c8ef
--- /dev/null
+++ b/ext/xmlrpc/libxmlrpc/base64.h
@@ -0,0 +1,38 @@
+/*
+
+ Encode or decode file as MIME base64 (RFC 1341)
+
+ by John Walker
+ http://www.fourmilab.ch/
+
+ This program is in the public domain.
+
+*/
+
+
+struct buffer_st {
+ char *data;
+ int length;
+ char *ptr;
+ int offset;
+};
+
+void buffer_new(struct buffer_st *b);
+void buffer_add(struct buffer_st *b, char c);
+void buffer_delete(struct buffer_st *b);
+
+void base64_encode_xmlrpc(struct buffer_st *b, const char *source, int length);
+void base64_decode_xmlrpc(struct buffer_st *b, const char *source, int length);
+
+/*
+#define DEBUG_MALLOC
+ */
+
+#ifdef DEBUG_MALLOC
+void *_malloc_real(size_t s, char *file, int line);
+void _free_real(void *p, char *file, int line);
+
+#define malloc(s) _malloc_real(s,__FILE__,__LINE__)
+#define free(p) _free_real(p, __FILE__,__LINE__)
+#endif
+
diff --git a/ext/xmlrpc/libxmlrpc/encodings.c b/ext/xmlrpc/libxmlrpc/encodings.c
new file mode 100644
index 0000000..f4cc212
--- /dev/null
+++ b/ext/xmlrpc/libxmlrpc/encodings.c
@@ -0,0 +1,126 @@
+/*
+ This file is part of libXMLRPC - a C library for xml-encoded function calls.
+
+ Author: Dan Libby (dan@libby.com)
+ Epinions.com may be contacted at feedback@epinions-inc.com
+*/
+
+/*
+ Copyright 2000 Epinions, Inc.
+
+ Subject to the following 3 conditions, Epinions, Inc. permits you, free
+ of charge, to (a) use, copy, distribute, modify, perform and display this
+ software and associated documentation files (the "Software"), and (b)
+ permit others to whom the Software is furnished to do so as well.
+
+ 1) The above copyright notice and this permission notice shall be included
+ without modification in all copies or substantial portions of the
+ Software.
+
+ 2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF
+ ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY
+ IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ PURPOSE OR NONINFRINGEMENT.
+
+ 3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
+ OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING
+ NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH
+ DAMAGES.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifndef PHP_WIN32
+#include <php_config.h>
+#else
+#include <config.w32.h>
+#include <stdlib.h>
+#endif
+
+static const char rcsid[] = "#(@) $Id$";
+
+#include <errno.h>
+
+#ifdef HAVE_GICONV_H
+#include <giconv.h>
+#else
+#include <iconv.h>
+#endif
+
+#include "encodings.h"
+
+#ifndef ICONV_CSNMAXLEN
+#define ICONV_CSNMAXLEN 64
+#endif
+
+static char* convert(const char* src, int src_len, int *new_len, const char* from_enc, const char* to_enc) {
+ char* outbuf = 0;
+
+ if(src && src_len && from_enc && to_enc) {
+ size_t outlenleft = src_len;
+ size_t inlenleft = src_len;
+ int outlen = src_len;
+ iconv_t ic;
+ char* out_ptr = 0;
+
+ if(strlen(to_enc) >= ICONV_CSNMAXLEN || strlen(from_enc) >= ICONV_CSNMAXLEN) {
+ return NULL;
+ }
+ ic = iconv_open(to_enc, from_enc);
+ if(ic != (iconv_t)-1) {
+ size_t st;
+ outbuf = (char*)malloc(outlen + 1);
+
+ if(outbuf) {
+ out_ptr = (char*)outbuf;
+ while(inlenleft) {
+ st = iconv(ic, (char**)&src, &inlenleft, &out_ptr, &outlenleft);
+ if(st == -1) {
+ if(errno == E2BIG) {
+ int diff = out_ptr - outbuf;
+ outlen += inlenleft;
+ outlenleft += inlenleft;
+ outbuf = (char*)realloc(outbuf, outlen + 1);
+ if(!outbuf) {
+ break;
+ }
+ out_ptr = outbuf + diff;
+ }
+ else {
+ free(outbuf);
+ outbuf = 0;
+ break;
+ }
+ }
+ }
+ }
+ iconv_close(ic);
+ }
+ outlen -= outlenleft;
+
+ if(new_len) {
+ *new_len = outbuf ? outlen : 0;
+ }
+ if(outbuf) {
+ outbuf[outlen] = 0;
+ }
+ }
+ return outbuf;
+}
+
+/* returns a new string that must be freed */
+char* utf8_encode(const char *s, int len, int *newlen, const char* encoding)
+{
+ return convert(s, len, newlen, encoding, "UTF-8");
+}
+
+/* returns a new string, possibly decoded */
+char* utf8_decode(const char *s, int len, int *newlen, const char* encoding)
+{
+ return convert(s, len, newlen, "UTF-8", encoding);
+}
+
diff --git a/ext/xmlrpc/libxmlrpc/encodings.h b/ext/xmlrpc/libxmlrpc/encodings.h
new file mode 100644
index 0000000..486360b
--- /dev/null
+++ b/ext/xmlrpc/libxmlrpc/encodings.h
@@ -0,0 +1,46 @@
+/*
+ This file is part of libXMLRPC - a C library for xml-encoded function calls.
+
+ Author: Dan Libby (dan@libby.com)
+ Epinions.com may be contacted at feedback@epinions-inc.com
+*/
+
+/*
+ Copyright 2000 Epinions, Inc.
+
+ Subject to the following 3 conditions, Epinions, Inc. permits you, free
+ of charge, to (a) use, copy, distribute, modify, perform and display this
+ software and associated documentation files (the "Software"), and (b)
+ permit others to whom the Software is furnished to do so as well.
+
+ 1) The above copyright notice and this permission notice shall be included
+ without modification in all copies or substantial portions of the
+ Software.
+
+ 2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF
+ ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY
+ IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ PURPOSE OR NONINFRINGEMENT.
+
+ 3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
+ OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING
+ NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH
+ DAMAGES.
+
+*/
+
+
+#ifndef __ENCODINGS__H
+#define __ENCODINGS__H
+
+/* these defines are for legacy purposes. */
+#define encoding_utf_8 "UTF-8"
+typedef const char* ENCODING_ID;
+#define utf8_get_encoding_id_string(desired_enc) ((const char*)desired_enc)
+#define utf8_get_encoding_id_from_string(id_string) ((ENCODING_ID)id_string)
+
+char* utf8_encode(const char *s, int len, int *newlen, ENCODING_ID encoding);
+char* utf8_decode(const char *s, int len, int *newlen, ENCODING_ID encoding);
+
+#endif /* __ENCODINGS__H */
diff --git a/ext/xmlrpc/libxmlrpc/queue.c b/ext/xmlrpc/libxmlrpc/queue.c
new file mode 100644
index 0000000..2418738
--- /dev/null
+++ b/ext/xmlrpc/libxmlrpc/queue.c
@@ -0,0 +1,982 @@
+static const char rcsid[] = "#(@) $Id$";
+
+/*
+ * Date last modified: Jan 2001
+ * Modifications by Dan Libby (dan@libby.com), including:
+ * - various fixes, null checks, etc
+ * - addition of Q_Iter funcs, macros
+ */
+
+
+/*-**************************************************************
+ *
+ * File : q.c
+ *
+ * Author: Peter Yard [1993.01.02] -- 02 Jan 1993
+ *
+ * Disclaimer: This code is released to the public domain.
+ *
+ * Description:
+ * Generic double ended queue (Deque pronounced DEK) for handling
+ * any data types, with sorting.
+ *
+ * By use of various functions in this module the caller
+ * can create stacks, queues, lists, doubly linked lists,
+ * sorted lists, indexed lists. All lists are dynamic.
+ *
+ * It is the responsibility of the caller to malloc and free
+ * memory for insertion into the queue. A pointer to the object
+ * is used so that not only can any data be used but various kinds
+ * of data can be pushed on the same queue if one so wished e.g.
+ * various length string literals mixed with pointers to structures
+ * or integers etc.
+ *
+ * Enhancements:
+ * A future improvement would be the option of multiple "cursors"
+ * so that multiple locations could occur in the one queue to allow
+ * placemarkers and additional flexibility. Perhaps even use queue
+ * itself to have a list of cursors.
+ *
+ * Usage:
+ *
+ * /x init queue x/
+ * queue q;
+ * Q_Init(&q);
+ *
+ * To create a stack :
+ *
+ * Q_PushHead(&q, &mydata1); /x push x/
+ * Q_PushHead(&q, &mydata2);
+ * .....
+ * data_ptr = Q_PopHead(&q); /x pop x/
+ * .....
+ * data_ptr = Q_Head(&q); /x top of stack x/
+ *
+ * To create a FIFO:
+ *
+ * Q_PushHead(&q, &mydata1);
+ * .....
+ * data_ptr = Q_PopTail(&q);
+ *
+ * To create a double list:
+ *
+ * data_ptr = Q_Head(&q);
+ * ....
+ * data_ptr = Q_Next(&q);
+ * data_ptr = Q_Tail(&q);
+ * if (Q_IsEmpty(&q)) ....
+ * .....
+ * data_ptr = Q_Previous(&q);
+ *
+ * To create a sorted list:
+ *
+ * Q_PushHead(&q, &mydata1); /x push x/
+ * Q_PushHead(&q, &mydata2);
+ * .....
+ * if (!Q_Sort(&q, MyFunction))
+ * .. error ..
+ *
+ * /x fill in key field of mydata1.
+ * * NB: Q_Find does linear search
+ * x/
+ *
+ * if (Q_Find(&q, &mydata1, MyFunction))
+ * {
+ * /x found it, queue cursor now at correct record x/
+ * /x can retrieve with x/
+ * data_ptr = Q_Get(&q);
+ *
+ * /x alter data , write back with x/
+ * Q_Put(&q, data_ptr);
+ * }
+ *
+ * /x Search with binary search x/
+ * if (Q_Seek(&q, &mydata, MyFunction))
+ * /x etc x/
+ *
+ *
+ ****************************************************************/
+
+#ifdef _WIN32
+#include "xmlrpc_win32.h"
+#endif
+#include <stdlib.h>
+#include "queue.h"
+
+
+static void QuickSort(void *list[], int low, int high,
+ int (*Comp)(const void *, const void *));
+static int Q_BSearch(queue *q, void *key,
+ int (*Comp)(const void *, const void *));
+
+/* The index: a pointer to pointers */
+
+static void **index;
+static datanode **posn_index;
+
+
+/***
+ *
+ ** function : Q_Init
+ *
+ ** purpose : Initialise queue object and pointers.
+ *
+ ** parameters : 'queue' pointer.
+ *
+ ** returns : True_ if init successful else False_
+ *
+ ** comments :
+ ***/
+
+int Q_Init(queue *q)
+{
+ if(q) {
+ q->head = q->tail = NULL;
+ q->cursor = q->head;
+ q->size = 0;
+ q->sorted = False_;
+ }
+
+ return True_;
+}
+
+/***
+ *
+ ** function : Q_AtHead
+ *
+ ** purpose : tests if cursor is at head of queue
+ *
+ ** parameters : 'queue' pointer.
+ *
+ ** returns : boolean - True_ is at head else False_
+ *
+ ** comments :
+ *
+ ***/
+
+int Q_AtHead(queue *q)
+{
+ return(q && q->cursor == q->head);
+}
+
+
+/***
+ *
+ ** function : Q_AtTail
+ *
+ ** purpose : boolean test if cursor at tail of queue
+ *
+ ** parameters : 'queue' pointer to test.
+ *
+ ** returns : True_ or False_
+ *
+ ** comments :
+ *
+ ***/
+
+int Q_AtTail(queue *q)
+{
+ return(q && q->cursor == q->tail);
+}
+
+
+/***
+ *
+ ** function : Q_IsEmpty
+ *
+ ** purpose : test if queue has nothing in it.
+ *
+ ** parameters : 'queue' pointer
+ *
+ ** returns : True_ if IsEmpty queue, else False_
+ *
+ ** comments :
+ *
+ ***/
+
+inline int Q_IsEmpty(queue *q)
+{
+ return(!q || q->size == 0);
+}
+
+/***
+ *
+ ** function : Q_Size
+ *
+ ** purpose : return the number of elements in the queue
+ *
+ ** parameters : queue pointer
+ *
+ ** returns : number of elements
+ *
+ ** comments :
+ *
+ ***/
+
+int Q_Size(queue *q)
+{
+ return q ? q->size : 0;
+}
+
+
+/***
+ *
+ ** function : Q_Head
+ *
+ ** purpose : position queue cursor to first element (head) of queue.
+ *
+ ** parameters : 'queue' pointer
+ *
+ ** returns : pointer to data at head. If queue is IsEmpty returns NULL
+ *
+ ** comments :
+ *
+ ***/
+
+void *Q_Head(queue *q)
+{
+ if(Q_IsEmpty(q))
+ return NULL;
+
+ q->cursor = q->head;
+
+ return q->cursor->data;
+}
+
+
+/***
+ *
+ ** function : Q_Tail
+ *
+ ** purpose : locate cursor at tail of queue.
+ *
+ ** parameters : 'queue' pointer
+ *
+ ** returns : pointer to data at tail , if queue IsEmpty returns NULL
+ *
+ ** comments :
+ *
+ ***/
+
+void *Q_Tail(queue *q)
+{
+ if(Q_IsEmpty(q))
+ return NULL;
+
+ q->cursor = q->tail;
+
+ return q->cursor->data;
+}
+
+
+/***
+ *
+ ** function : Q_PushHead
+ *
+ ** purpose : put a data pointer at the head of the queue
+ *
+ ** parameters : 'queue' pointer, void pointer to the data.
+ *
+ ** returns : True_ if success else False_ if unable to push data.
+ *
+ ** comments :
+ *
+ ***/
+
+int Q_PushHead(queue *q, void *d)
+{
+ if(q && d) {
+ node *n;
+ datanode *p;
+
+ p = malloc(sizeof(datanode));
+ if(p == NULL)
+ return False_;
+
+ n = q->head;
+
+ q->head = (node*)p;
+ q->head->prev = NULL;
+
+ if(q->size == 0) {
+ q->head->next = NULL;
+ q->tail = q->head;
+ }
+ else {
+ q->head->next = (datanode*)n;
+ n->prev = q->head;
+ }
+
+ q->head->data = d;
+ q->size++;
+
+ q->cursor = q->head;
+
+ q->sorted = False_;
+
+ return True_;
+ }
+ return False_;
+}
+
+
+
+/***
+ *
+ ** function : Q_PushTail
+ *
+ ** purpose : put a data element pointer at the tail of the queue
+ *
+ ** parameters : queue pointer, pointer to the data
+ *
+ ** returns : True_ if data pushed, False_ if data not inserted.
+ *
+ ** comments :
+ *
+ ***/
+
+int Q_PushTail(queue *q, void *d)
+{
+ if(q && d) {
+ node *p;
+ datanode *n;
+
+ n = malloc(sizeof(datanode));
+ if(n == NULL)
+ return False_;
+
+ p = q->tail;
+ q->tail = (node *)n;
+
+ if(q->size == 0) {
+ q->tail->prev = NULL;
+ q->head = q->tail;
+ }
+ else {
+ q->tail->prev = (datanode *)p;
+ p->next = q->tail;
+ }
+
+ q->tail->next = NULL;
+
+ q->tail->data = d;
+ q->cursor = q->tail;
+ q->size++;
+
+ q->sorted = False_;
+
+ return True_;
+ }
+ return False_;
+}
+
+
+
+/***
+ *
+ ** function : Q_PopHead
+ *
+ ** purpose : remove and return the top element at the head of the
+ * queue.
+ *
+ ** parameters : queue pointer
+ *
+ ** returns : pointer to data element or NULL if queue is IsEmpty.
+ *
+ ** comments :
+ *
+ ***/
+
+void *Q_PopHead(queue *q)
+{
+ datanode *n;
+ void *d;
+
+ if(Q_IsEmpty(q))
+ return NULL;
+
+ d = q->head->data;
+ n = q->head->next;
+ free(q->head);
+
+ q->size--;
+
+ if(q->size == 0)
+ q->head = q->tail = q->cursor = NULL;
+ else {
+ q->head = (node *)n;
+ q->head->prev = NULL;
+ q->cursor = q->head;
+ }
+
+ q->sorted = False_;
+
+ return d;
+}
+
+
+/***
+ *
+ ** function : Q_PopTail
+ *
+ ** purpose : remove element from tail of queue and return data.
+ *
+ ** parameters : queue pointer
+ *
+ ** returns : pointer to data element that was at tail. NULL if queue
+ * IsEmpty.
+ *
+ ** comments :
+ *
+ ***/
+
+void *Q_PopTail(queue *q)
+{
+ datanode *p;
+ void *d;
+
+ if(Q_IsEmpty(q))
+ return NULL;
+
+ d = q->tail->data;
+ p = q->tail->prev;
+ free(q->tail);
+ q->size--;
+
+ if(q->size == 0)
+ q->head = q->tail = q->cursor = NULL;
+ else {
+ q->tail = (node *)p;
+ q->tail->next = NULL;
+ q->cursor = q->tail;
+ }
+
+ q->sorted = False_;
+
+ return d;
+}
+
+
+
+/***
+ *
+ ** function : Q_Next
+ *
+ ** purpose : Move to the next element in the queue without popping
+ *
+ ** parameters : queue pointer.
+ *
+ ** returns : pointer to data element of new element or NULL if end
+ * of the queue.
+ *
+ ** comments : This uses the cursor for the current position. Q_Next
+ * only moves in the direction from the head of the queue
+ * to the tail.
+ ***/
+
+void *Q_Next(queue *q)
+{
+ if(!q)
+ return NULL;
+
+ if(!q->cursor || q->cursor->next == NULL)
+ return NULL;
+
+ q->cursor = (node *)q->cursor->next;
+
+ return q->cursor->data ;
+}
+
+
+
+/***
+ *
+ ** function : Q_Previous
+ *
+ ** purpose : Opposite of Q_Next. Move to next element closer to the
+ * head of the queue.
+ *
+ ** parameters : pointer to queue
+ *
+ ** returns : pointer to data of new element else NULL if queue IsEmpty
+ *
+ ** comments : Makes cursor move towards the head of the queue.
+ *
+ ***/
+
+void *Q_Previous(queue *q)
+{
+ if(!q)
+ return NULL;
+
+ if(q->cursor->prev == NULL)
+ return NULL;
+
+ q->cursor = (node *)q->cursor->prev;
+
+ return q->cursor->data;
+}
+
+
+void *Q_Iter_Del(queue *q, q_iter iter)
+{
+ void *d;
+ datanode *n, *p;
+
+ if(!q)
+ return NULL;
+
+ if(iter == NULL)
+ return NULL;
+
+ if(iter == (q_iter)q->head)
+ return Q_PopHead(q);
+
+ if(iter == (q_iter)q->tail)
+ return Q_PopTail(q);
+
+ n = ((node*)iter)->next;
+ p = ((node*)iter)->prev;
+ d = ((node*)iter)->data;
+
+ free(iter);
+
+ if(p) {
+ p->next = n;
+ }
+ if (q->cursor == (node*)iter) {
+ if (p) {
+ q->cursor = p;
+ } else {
+ q->cursor = n;
+ }
+ }
+
+
+ if (n != NULL) {
+ n->prev = p;
+ }
+
+ q->size--;
+
+ q->sorted = False_;
+
+ return d;
+}
+
+
+
+/***
+ *
+ ** function : Q_DelCur
+ *
+ ** purpose : Delete the current queue element as pointed to by
+ * the cursor.
+ *
+ ** parameters : queue pointer
+ *
+ ** returns : pointer to data element.
+ *
+ ** comments : WARNING! It is the responsibility of the caller to
+ * free any memory. Queue cannot distinguish between
+ * pointers to literals and malloced memory.
+ *
+ ***/
+
+void *Q_DelCur(queue* q) {
+ if(q) {
+ return Q_Iter_Del(q, (q_iter)q->cursor);
+ }
+ return 0;
+}
+
+
+/***
+ *
+ ** function : Q_Destroy
+ *
+ ** purpose : Free all queue resources
+ *
+ ** parameters : queue pointer
+ *
+ ** returns : null.
+ *
+ ** comments : WARNING! It is the responsibility of the caller to
+ * free any memory. Queue cannot distinguish between
+ * pointers to literals and malloced memory.
+ *
+ ***/
+
+void Q_Destroy(queue *q)
+{
+ while(!Q_IsEmpty(q)) {
+ Q_PopHead(q);
+ }
+}
+
+
+/***
+ *
+ ** function : Q_Get
+ *
+ ** purpose : get the pointer to the data at the cursor location
+ *
+ ** parameters : queue pointer
+ *
+ ** returns : data element pointer
+ *
+ ** comments :
+ *
+ ***/
+
+void *Q_Get(queue *q)
+{
+ if(!q)
+ return NULL;
+
+ if(q->cursor == NULL)
+ return NULL;
+ return q->cursor->data;
+}
+
+
+
+/***
+ *
+ ** function : Q_Put
+ *
+ ** purpose : replace pointer to data with new pointer to data.
+ *
+ ** parameters : queue pointer, data pointer
+ *
+ ** returns : boolean- True_ if successful, False_ if cursor at NULL
+ *
+ ** comments :
+ *
+ ***/
+
+int Q_Put(queue *q, void *data)
+{
+ if(q && data) {
+ if(q->cursor == NULL)
+ return False_;
+
+ q->cursor->data = data;
+ return True_;
+ }
+ return False_;
+}
+
+
+/***
+ *
+ ** function : Q_Find
+ *
+ ** purpose : Linear search of queue for match with key in *data
+ *
+ ** parameters : queue pointer q, data pointer with data containing key
+ * comparison function here called Comp.
+ *
+ ** returns : True_ if found , False_ if not in queue.
+ *
+ ** comments : Useful for small queues that are constantly changing
+ * and would otherwise need constant sorting with the
+ * Q_Seek function.
+ * For description of Comp see Q_Sort.
+ * Queue cursor left on position found item else at end.
+ *
+ ***/
+
+int Q_Find(queue *q, void *data,
+ int (*Comp)(const void *, const void *))
+{
+ void *d;
+
+ if (q == NULL) {
+ return False_;
+ }
+
+ d = Q_Head(q);
+ do {
+ if(Comp(d, data) == 0)
+ return True_;
+ d = Q_Next(q);
+ } while(!Q_AtTail(q));
+
+ if(Comp(d, data) == 0)
+ return True_;
+
+ return False_;
+}
+
+/*======== Sorted Queue and Index functions ========= */
+
+
+static void QuickSort(void *list[], int low, int high,
+ int (*Comp)(const void *, const void *))
+{
+ int flag = 1, i, j;
+ void *key, *temp;
+
+ if(low < high) {
+ i = low;
+ j = high + 1;
+
+ key = list[ low ];
+
+ while(flag) {
+ i++;
+ while(Comp(list[i], key) < 0)
+ i++;
+
+ j--;
+ while(Comp(list[j], key) > 0)
+ j--;
+
+ if(i < j) {
+ temp = list[i];
+ list[i] = list[j];
+ list[j] = temp;
+ }
+ else flag = 0;
+ }
+
+ temp = list[low];
+ list[low] = list[j];
+ list[j] = temp;
+
+ QuickSort(list, low, j-1, Comp);
+ QuickSort(list, j+1, high, Comp);
+ }
+}
+
+
+/***
+ *
+ ** function : Q_Sort
+ *
+ ** purpose : sort the queue and allow index style access.
+ *
+ ** parameters : queue pointer, comparison function compatible with
+ * with 'qsort'.
+ *
+ ** returns : True_ if sort succeeded. False_ if error occurred.
+ *
+ ** comments : Comp function supplied by caller must return
+ * -1 if data1 < data2
+ * 0 if data1 == data2
+ * +1 if data1 > data2
+ *
+ * for Comp(data1, data2)
+ *
+ * If queue is already sorted it frees the memory of the
+ * old index and starts again.
+ *
+ ***/
+
+int Q_Sort(queue *q, int (*Comp)(const void *, const void *))
+{
+ int i;
+ void *d;
+ datanode *dn;
+
+ /* if already sorted free memory for tag array */
+
+ if(q->sorted) {
+ free(index);
+ free(posn_index);
+ q->sorted = False_;
+ }
+
+ /* Now allocate memory of array, array of pointers */
+
+ index = malloc(q->size * sizeof(q->cursor->data));
+ if(index == NULL)
+ return False_;
+
+ posn_index = malloc(q->size * sizeof(q->cursor));
+ if(posn_index == NULL) {
+ free(index);
+ return False_;
+ }
+
+ /* Walk queue putting pointers into array */
+
+ d = Q_Head(q);
+ for(i=0; i < q->size; i++) {
+ index[i] = d;
+ posn_index[i] = q->cursor;
+ d = Q_Next(q);
+ }
+
+ /* Now sort the index */
+
+ QuickSort(index, 0, q->size - 1, Comp);
+
+ /* Rearrange the actual queue into correct order */
+
+ dn = q->head;
+ i = 0;
+ while(dn != NULL) {
+ dn->data = index[i++];
+ dn = dn->next;
+ }
+
+ /* Re-position to original element */
+
+ if(d != NULL)
+ Q_Find(q, d, Comp);
+ else Q_Head(q);
+
+ q->sorted = True_;
+
+ return True_;
+}
+
+
+/***
+ *
+ ** function : Q_BSearch
+ *
+ ** purpose : binary search of queue index for node containing key
+ *
+ ** parameters : queue pointer 'q', data pointer of key 'key',
+ * Comp comparison function.
+ *
+ ** returns : integer index into array of node pointers,
+ * or -1 if not found.
+ *
+ ** comments : see Q_Sort for description of 'Comp' function.
+ *
+ ***/
+
+static int Q_BSearch( queue *q, void *key,
+ int (*Comp)(const void *, const void*))
+{
+ int low, mid, hi, val;
+
+ low = 0;
+ hi = q->size - 1;
+
+ while(low <= hi) {
+ mid = (low + hi) / 2;
+ val = Comp(key, index[ mid ]);
+
+ if(val < 0)
+ hi = mid - 1;
+
+ else if(val > 0)
+ low = mid + 1;
+
+ else /* Success */
+ return mid;
+ }
+
+ /* Not Found */
+
+ return -1;
+}
+
+
+/***
+ *
+ ** function : Q_Seek
+ *
+ ** purpose : use index to locate data according to key in 'data'
+ *
+ ** parameters : queue pointer 'q', data pointer 'data', Comp comparison
+ * function.
+ *
+ ** returns : pointer to data or NULL if could not find it or could
+ * not sort queue.
+ *
+ ** comments : see Q_Sort for description of 'Comp' function.
+ *
+ ***/
+
+void *Q_Seek(queue *q, void *data, int (*Comp)(const void *, const void *))
+{
+ int idx;
+
+ if (q == NULL) {
+ return NULL;
+ }
+
+ if(!q->sorted) {
+ if(!Q_Sort(q, Comp))
+ return NULL;
+ }
+
+ idx = Q_BSearch(q, data, Comp);
+
+ if(idx < 0)
+ return NULL;
+
+ q->cursor = posn_index[idx];
+
+ return index[idx];
+}
+
+
+
+/***
+ *
+ ** function : Q_Insert
+ *
+ ** purpose : Insert an element into an indexed queue
+ *
+ ** parameters : queue pointer 'q', data pointer 'data', Comp comparison
+ * function.
+ *
+ ** returns : pointer to data or NULL if could not find it or could
+ * not sort queue.
+ *
+ ** comments : see Q_Sort for description of 'Comp' function.
+ * WARNING! This code can be very slow since each new
+ * element means a new Q_Sort. Should only be used for
+ * the insertion of the odd element ,not the piecemeal
+ * building of an entire queue.
+ ***/
+
+int Q_Insert(queue *q, void *data, int (*Comp)(const void *, const void *))
+{
+ if (q == NULL) {
+ return False_;
+ }
+
+ Q_PushHead(q, data);
+
+ if(!Q_Sort(q, Comp))
+ return False_;
+
+ return True_;
+}
+
+/* read only funcs for iterating through queue. above funcs modify queue */
+q_iter Q_Iter_Head(queue *q) {
+ return q ? (q_iter)q->head : NULL;
+}
+
+q_iter Q_Iter_Tail(queue *q) {
+ return q ? (q_iter)q->tail : NULL;
+}
+
+q_iter Q_Iter_Next(q_iter qi) {
+ return qi ? (q_iter)((node*)qi)->next : NULL;
+}
+
+q_iter Q_Iter_Prev(q_iter qi) {
+ return qi ? (q_iter)((node*)qi)->prev : NULL;
+}
+
+void * Q_Iter_Get(q_iter qi) {
+ return qi ? ((node*)qi)->data : NULL;
+}
+
+int Q_Iter_Put(q_iter qi, void* data) {
+ if(qi) {
+ ((node*)qi)->data = data;
+ return True_;
+ }
+ return False_;
+}
diff --git a/ext/xmlrpc/libxmlrpc/queue.h b/ext/xmlrpc/libxmlrpc/queue.h
new file mode 100644
index 0000000..be73f6d
--- /dev/null
+++ b/ext/xmlrpc/libxmlrpc/queue.h
@@ -0,0 +1,89 @@
+/*
+ * Date last modified: Jan 2001
+ * Modifications by Dan Libby (dan@libby.com), including:
+ * - various fixes, null checks, etc
+ * - addition of Q_Iter funcs, macros
+ */
+
+/*
+ * File : q.h
+ *
+ * Peter Yard 02 Jan 1993.
+ *
+ * Disclaimer: This code is released to the public domain.
+ */
+
+#ifndef Q__H
+#define Q__H
+
+#ifndef False_
+ #define False_ 0
+#endif
+
+#ifndef True_
+ #define True_ 1
+#endif
+
+typedef struct nodeptr datanode;
+
+typedef struct nodeptr {
+ void *data ;
+ datanode *prev, *next ;
+} node ;
+
+/* For external use with Q_Iter* funcs */
+typedef struct nodeptr* q_iter;
+
+typedef struct {
+ node *head, *tail, *cursor;
+ int size, sorted, item_deleted;
+} queue;
+
+typedef struct {
+ void *dataptr;
+ node *loc ;
+} index_elt ;
+
+
+int Q_Init(queue *q);
+void Q_Destroy(queue *q);
+int Q_IsEmpty(queue *q);
+int Q_Size(queue *q);
+int Q_AtHead(queue *q);
+int Q_AtTail(queue *q);
+int Q_PushHead(queue *q, void *d);
+int Q_PushTail(queue *q, void *d);
+void *Q_Head(queue *q);
+void *Q_Tail(queue *q);
+void *Q_PopHead(queue *q);
+void *Q_PopTail(queue *q);
+void *Q_Next(queue *q);
+void *Q_Previous(queue *q);
+void *Q_DelCur(queue *q);
+void *Q_Get(queue *q);
+int Q_Put(queue *q, void *data);
+int Q_Sort(queue *q, int (*Comp)(const void *, const void *));
+int Q_Find(queue *q, void *data,
+ int (*Comp)(const void *, const void *));
+void *Q_Seek(queue *q, void *data,
+ int (*Comp)(const void *, const void *));
+int Q_Insert(queue *q, void *data,
+ int (*Comp)(const void *, const void *));
+
+/* read only funcs for iterating through queue. above funcs modify queue */
+q_iter Q_Iter_Head(queue *q);
+q_iter Q_Iter_Tail(queue *q);
+q_iter Q_Iter_Next(q_iter qi);
+q_iter Q_Iter_Prev(q_iter qi);
+void* Q_Iter_Get(q_iter qi);
+int Q_Iter_Put(q_iter qi, void* data); /* not read only! here for completeness. */
+void* Q_Iter_Del(queue *q, q_iter iter); /* not read only! here for completeness. */
+
+/* Fast (macro'd) versions of above */
+#define Q_Iter_Head_F(q) (q ? (q_iter)((queue*)q)->head : NULL)
+#define Q_Iter_Tail_F(q) (q ? (q_iter)((queue*)q)->tail : NULL)
+#define Q_Iter_Next_F(qi) (qi ? (q_iter)((node*)qi)->next : NULL)
+#define Q_Iter_Prev_F(qi) (qi ? (q_iter)((node*)qi)->prev : NULL)
+#define Q_Iter_Get_F(qi) (qi ? ((node*)qi)->data : NULL)
+
+#endif /* Q__H */
diff --git a/ext/xmlrpc/libxmlrpc/simplestring.c b/ext/xmlrpc/libxmlrpc/simplestring.c
new file mode 100644
index 0000000..7211d2c
--- /dev/null
+++ b/ext/xmlrpc/libxmlrpc/simplestring.c
@@ -0,0 +1,248 @@
+/*
+ This file is part of libXMLRPC - a C library for xml-encoded function calls.
+
+ Author: Dan Libby (dan@libby.com)
+ Epinions.com may be contacted at feedback@epinions-inc.com
+*/
+
+/*
+ Copyright 2000 Epinions, Inc.
+
+ Subject to the following 3 conditions, Epinions, Inc. permits you, free
+ of charge, to (a) use, copy, distribute, modify, perform and display this
+ software and associated documentation files (the "Software"), and (b)
+ permit others to whom the Software is furnished to do so as well.
+
+ 1) The above copyright notice and this permission notice shall be included
+ without modification in all copies or substantial portions of the
+ Software.
+
+ 2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF
+ ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY
+ IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ PURPOSE OR NONINFRINGEMENT.
+
+ 3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
+ OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING
+ NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH
+ DAMAGES.
+
+*/
+
+
+static const char rcsid[] = "#(@) $Id$";
+
+
+#define SIMPLESTRING_INCR 32
+
+/****h* ABOUT/simplestring
+ * NAME
+ * simplestring
+ * AUTHOR
+ * Dan Libby, aka danda (dan@libby.com)
+ * CREATION DATE
+ * 06/2000
+ * HISTORY
+ * $Log$
+ * Revision 1.3 2002/08/22 01:25:50 sniper
+ * kill some compile warnings
+ *
+ * Revision 1.2 2002/07/05 04:43:53 danda
+ * merged in updates from SF project. bring php repository up to date with xmlrpc-epi version 0.51
+ *
+ * Revision 1.4 2002/02/13 20:58:50 danda
+ * patch to make source more windows friendly, contributed by Jeff Lawson
+ *
+ * Revision 1.3 2001/09/29 21:58:05 danda
+ * adding cvs log to history section
+ *
+ * 10/15/2000 -- danda -- adding robodoc documentation
+ * PORTABILITY
+ * Coded on RedHat Linux 6.2. Builds on Solaris x86. Should build on just
+ * about anything with minor mods.
+ * NOTES
+ * This code was written primarily for xmlrpc, but has found some other uses.
+ *
+ * simplestring is, as the name implies, a simple API for dealing with C strings.
+ * Why would I write yet another string API? Because I couldn't find any that were
+ * a) free / GPL, b) simple/lightweight, c) fast, not doing unneccesary strlens all
+ * over the place. So. It is simple, and it seems to work, and it is pretty fast.
+ *
+ * Oh, and it is also binary safe, ie it can handle strings with embedded NULLs,
+ * so long as the real length is passed in.
+ *
+ * And the masses rejoiced.
+ *
+ * BUGS
+ * there must be some.
+ ******/
+
+#include <stdlib.h>
+#include <string.h>
+#include "simplestring.h"
+
+#define my_free(thing) if(thing) {free(thing); thing = 0;}
+
+/*----------------------**
+* Begin String Functions *
+*-----------------------*/
+
+/****f* FUNC/simplestring_init
+ * NAME
+ * simplestring_init
+ * SYNOPSIS
+ * void simplestring_init(simplestring* string)
+ * FUNCTION
+ * initialize string
+ * INPUTS
+ * string - pointer to a simplestring struct that will be initialized
+ * RESULT
+ * void
+ * NOTES
+ * SEE ALSO
+ * simplestring_free ()
+ * simplestring_clear ()
+ * SOURCE
+ */
+void simplestring_init(simplestring* string) {
+ memset(string, 0, sizeof(simplestring));
+}
+/******/
+
+static void simplestring_init_str(simplestring* string) {
+ string->str = (char*)malloc(SIMPLESTRING_INCR);
+ if(string->str) {
+ string->str[0] = 0;
+ string->len = 0;
+ string->size = SIMPLESTRING_INCR;
+ }
+ else {
+ string->size = 0;
+ }
+}
+
+/****f* FUNC/simplestring_clear
+ * NAME
+ * simplestring_clear
+ * SYNOPSIS
+ * void simplestring_clear(simplestring* string)
+ * FUNCTION
+ * clears contents of a string
+ * INPUTS
+ * string - the string value to clear
+ * RESULT
+ * void
+ * NOTES
+ * This function is very fast as it does not de-allocate any memory.
+ * SEE ALSO
+ *
+ * SOURCE
+ */
+void simplestring_clear(simplestring* string) {
+ if(string->str) {
+ string->str[0] = 0;
+ }
+ string->len = 0;
+}
+/******/
+
+/****f* FUNC/simplestring_free
+ * NAME
+ * simplestring_free
+ * SYNOPSIS
+ * void simplestring_free(simplestring* string)
+ * FUNCTION
+ * frees contents of a string, if any. Does *not* free the simplestring struct itself.
+ * INPUTS
+ * string - value containing string to be free'd
+ * RESULT
+ * void
+ * NOTES
+ * caller is responsible for allocating and freeing simplestring* struct itself.
+ * SEE ALSO
+ * simplestring_init ()
+ * SOURCE
+ */
+void simplestring_free(simplestring* string) {
+ if(string && string->str) {
+ my_free(string->str);
+ string->len = 0;
+ }
+}
+/******/
+
+/****f* FUNC/simplestring_addn
+ * NAME
+ * simplestring_addn
+ * SYNOPSIS
+ * void simplestring_addn(simplestring* string, const char* add, int add_len)
+ * FUNCTION
+ * copies n characters from source to target string
+ * INPUTS
+ * target - target string
+ * source - source string
+ * add_len - number of characters to copy
+ * RESULT
+ * void
+ * NOTES
+ * SEE ALSO
+ * simplestring_add ()
+ * SOURCE
+ */
+void simplestring_addn(simplestring* target, const char* source, int add_len) {
+ if(target && source) {
+ if(!target->str) {
+ simplestring_init_str(target);
+ }
+ if(target->len + add_len + 1 > target->size) {
+ /* newsize is current length + new length */
+ int newsize = target->len + add_len + 1;
+ int incr = target->size * 2;
+
+ /* align to SIMPLESTRING_INCR increments */
+ newsize = newsize - (newsize % incr) + incr;
+ target->str = (char*)realloc(target->str, newsize);
+
+ target->size = target->str ? newsize : 0;
+ }
+
+ if(target->str) {
+ if(add_len) {
+ memcpy(target->str + target->len, source, add_len);
+ }
+ target->len += add_len;
+ target->str[target->len] = 0; /* null terminate */
+ }
+ }
+}
+/******/
+
+/****f* FUNC/simplestring_add
+ * NAME
+ * simplestring_add
+ * SYNOPSIS
+ * void simplestring_add(simplestring* string, const char* add)
+ * FUNCTION
+ * appends a string of unknown length from source to target
+ * INPUTS
+ * target - the target string to append to
+ * source - the source string of unknown length
+ * RESULT
+ * void
+ * NOTES
+ * SEE ALSO
+ * simplestring_addn ()
+ * SOURCE
+ */
+void simplestring_add(simplestring* target, const char* source) {
+ if(target && source) {
+ simplestring_addn(target, source, strlen(source));
+ }
+}
+/******/
+
+
+/*----------------------
+* End String Functions *
+*--------------------**/
diff --git a/ext/xmlrpc/libxmlrpc/simplestring.h b/ext/xmlrpc/libxmlrpc/simplestring.h
new file mode 100644
index 0000000..c5d98cf
--- /dev/null
+++ b/ext/xmlrpc/libxmlrpc/simplestring.h
@@ -0,0 +1,76 @@
+/*
+ This file is part of libXMLRPC - a C library for xml-encoded function calls.
+
+ Author: Dan Libby (dan@libby.com)
+ Epinions.com may be contacted at feedback@epinions-inc.com
+*/
+
+/*
+ Copyright 2000 Epinions, Inc.
+
+ Subject to the following 3 conditions, Epinions, Inc. permits you, free
+ of charge, to (a) use, copy, distribute, modify, perform and display this
+ software and associated documentation files (the "Software"), and (b)
+ permit others to whom the Software is furnished to do so as well.
+
+ 1) The above copyright notice and this permission notice shall be included
+ without modification in all copies or substantial portions of the
+ Software.
+
+ 2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF
+ ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY
+ IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ PURPOSE OR NONINFRINGEMENT.
+
+ 3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
+ OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING
+ NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH
+ DAMAGES.
+
+*/
+
+#ifndef __SIMPLESTRING_H__
+ #define __SIMPLESTRING_H__
+
+/*-********************************
+* begin simplestring header stuff *
+**********************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ /****s* struct/simplestring
+ * NAME
+ * simplestring
+ * NOTES
+ * represents a string efficiently for fast appending, etc.
+ * SOURCE
+ */
+typedef struct _simplestring {
+ char* str; /* string buf */
+ int len; /* length of string/buf */
+ int size; /* size of allocated buffer */
+} simplestring;
+/******/
+
+#ifndef NULL
+ #define NULL 0
+#endif
+
+void simplestring_init(simplestring* string);
+void simplestring_clear(simplestring* string);
+void simplestring_free(simplestring* string);
+void simplestring_add(simplestring* string, const char* add);
+void simplestring_addn(simplestring* string, const char* add, int add_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+/*-******************************
+* end simplestring header stuff *
+********************************/
+
+#endif /* __SIMPLESTRING_H__ */
diff --git a/ext/xmlrpc/libxmlrpc/system_methods.c b/ext/xmlrpc/libxmlrpc/system_methods.c
new file mode 100644
index 0000000..c47236d
--- /dev/null
+++ b/ext/xmlrpc/libxmlrpc/system_methods.c
@@ -0,0 +1,375 @@
+/*
+ This file is part of libXMLRPC - a C library for xml-encoded function calls.
+
+ Author: Dan Libby (dan@libby.com)
+ Epinions.com may be contacted at feedback@epinions-inc.com
+*/
+
+/*
+ Copyright 2001 Epinions, Inc.
+
+ Subject to the following 3 conditions, Epinions, Inc. permits you, free
+ of charge, to (a) use, copy, distribute, modify, perform and display this
+ software and associated documentation files (the "Software"), and (b)
+ permit others to whom the Software is furnished to do so as well.
+
+ 1) The above copyright notice and this permission notice shall be included
+ without modification in all copies or substantial portions of the
+ Software.
+
+ 2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF
+ ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY
+ IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ PURPOSE OR NONINFRINGEMENT.
+
+ 3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
+ OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING
+ NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH
+ DAMAGES.
+
+*/
+
+
+/****h* ABOUT/system_methods
+ * AUTHOR
+ * Dan Libby, aka danda (dan@libby.com)
+ * HISTORY
+ * $Log$
+ * Revision 1.7 2001/09/29 21:58:05 danda
+ * adding cvs log to history section
+ *
+ * 4/28/2001 -- danda -- adding system.multicall and separating out system methods.
+ * TODO
+ * NOTES
+ *******/
+
+
+#include "queue.h"
+#include "xmlrpc.h"
+#include "xmlrpc_private.h"
+#include "xmlrpc_introspection_private.h"
+#include "system_methods_private.h"
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+
+static const char* xsm_introspection_xml =
+"<?xml version='1.0' ?>"
+
+"<introspection version='1.0'>"
+ "<typeList>"
+
+ "<typeDescription name='system.value' basetype='struct' desc='description of a value'>"
+ "<value type='string' name='name' optional='yes'>value identifier</value>"
+ "<value type='string' name='type'>value&apos;s xmlrpc or user-defined type</value>"
+ "<value type='string' name='description'>value&apos;s textual description</value> "
+ "<value type='boolean' name='optional'>true if value is optional, else it is required</value> "
+ "<value type='any' name='member' optional='yes'>a child of this element. n/a for scalar types</value> "
+ "</typeDescription>"
+
+ "<typeDescription name='system.valueList' basetype='array' desc='list of value descriptions'>"
+ "<value type='system.value'/>"
+ "</typeDescription>"
+
+ "<typeDescription name='system.stringList' basetype='array' desc='list of strings'>"
+ "<value type='string'/>"
+ "</typeDescription>"
+
+
+ "</typeList>"
+
+ "<methodList>"
+
+ "<!-- system.describeMethods -->"
+ "<methodDescription name='system.describeMethods'>"
+ "<author>Dan Libby</author>"
+ "<purpose>fully describes the methods and types implemented by this XML-RPC server.</purpose>"
+ "<version>1.1</version>"
+ "<signatures>"
+ "<signature>"
+ "<params>"
+ "<value type='array' name='methodList' optional='yes' desc='a list of methods to be described. if omitted, all are described.'>"
+ "<value type='string'>a valid method name</value>"
+ "</value>"
+ "</params>"
+ "<returns>"
+ "<value type='struct' desc='contains methods list and types list'>"
+ "<value type='array' name='methodList' desc='a list of methods'>"
+ "<value type='struct' desc='representation of a single method'>"
+ "<value type='string' name='name'>method name</value>"
+ "<value type='string' name='version' optional='yes'>method version</value>"
+ "<value type='string' name='author' optional='yes'>method author</value>"
+ "<value type='string' name='purpose' optional='yes'>method purpose</value>"
+ "<value type='array' name='signatures' desc='list of method signatures'>"
+ "<value type='struct' desc='representation of a single signature'>"
+ "<value type='system.valueList' name='params' optional='yes'>parameter list</value>"
+ "<value type='system.valueList' name='returns' optional='yes'>return value list</value>"
+ "</value>"
+ "</value>"
+ "<value type='system.stringList' name='bugs' optional='yes'>list of known bugs</value>"
+ "<value type='system.stringList' name='errors' optional='yes'>list of possible errors and error codes</value>"
+ "<value type='system.stringList' name='examples' optional='yes'>list of examples</value>"
+ "<value type='system.stringList' name='history' optional='yes'>list of modifications</value>"
+ "<value type='system.stringList' name='notes' optional='yes'>list of notes</value>"
+ "<value type='system.stringList' name='see' optional='yes'>see also. list of related methods</value>"
+ "<value type='system.stringList' name='todo' optional='yes'>list of unimplemented features</value>"
+ "</value>"
+ "</value>"
+ "<value type='array' name='typeList' desc='a list of type descriptions. Typically used for referencing complex types'>"
+ "<value type='system.value'>a type description</value>"
+ "</value>"
+ "</value>"
+ "</returns>"
+ "</signature>"
+ "</signatures>"
+ "<see>"
+ "<item name='system.listMethods' />"
+ "<item name='system.methodSignature' />"
+ "<item name='system.methodHelp' />"
+ "</see>"
+ "<example/>"
+ "<error/>"
+ "<note/>"
+ "<bug/>"
+ "<todo/>"
+ "</methodDescription>"
+
+ "<!-- system.listMethods -->"
+ "<methodDescription name='system.listMethods'>"
+ "<author>Dan Libby</author>"
+ "<purpose>enumerates the methods implemented by this XML-RPC server.</purpose>"
+ "<version>1.0</version>"
+ "<signatures>"
+ "<signature>"
+ "<returns>"
+ "<value type='array' desc='an array of strings'>"
+ "<value type='string'>name of a method implemented by the server.</value>"
+ "</value>"
+ "</returns>"
+ "</signature>"
+ "</signatures>"
+ "<see>"
+ "<item name='system.describeMethods' />"
+ "<item name='system.methodSignature' />"
+ "<item name='system.methodHelp' />"
+ "</see>"
+ "<example/>"
+ "<error/>"
+ "<note/>"
+ "<bug/>"
+ "<todo/>"
+ "</methodDescription>"
+
+ "<!-- system.methodHelp -->"
+ "<methodDescription name='system.methodHelp'>"
+ "<author>Dan Libby</author>"
+ "<purpose>provides documentation string for a single method</purpose>"
+ "<version>1.0</version>"
+ "<signatures>"
+ "<signature>"
+ "<params>"
+ "<value type='string' name='methodName'>name of the method for which documentation is desired</value>"
+ "</params>"
+ "<returns>"
+ "<value type='string'>help text if defined for the method passed, otherwise an empty string</value>"
+ "</returns>"
+ "</signature>"
+ "</signatures>"
+ "<see>"
+ "<item name='system.listMethods' />"
+ "<item name='system.methodSignature' />"
+ "<item name='system.methodHelp' />"
+ "</see>"
+ "<example/>"
+ "<error/>"
+ "<note/>"
+ "<bug/>"
+ "<todo/>"
+ "</methodDescription>"
+
+ "<!-- system.methodSignature -->"
+ "<methodDescription name='system.methodSignature'>"
+ "<author>Dan Libby</author>"
+ "<purpose>provides 1 or more signatures for a single method</purpose>"
+ "<version>1.0</version>"
+ "<signatures>"
+ "<signature>"
+ "<params>"
+ "<value type='string' name='methodName'>name of the method for which documentation is desired</value>"
+ "</params>"
+ "<returns>"
+ "<value type='array' desc='a list of arrays, each representing a signature'>"
+ "<value type='array' desc='a list of strings. the first element represents the method return value. subsequent elements represent parameters.'>"
+ "<value type='string'>a string indicating the xmlrpc type of a value. one of: string, int, double, base64, datetime, array, struct</value>"
+ "</value>"
+ "</value>"
+ "</returns>"
+ "</signature>"
+ "</signatures>"
+ "<see>"
+ "<item name='system.listMethods' />"
+ "<item name='system.methodHelp' />"
+ "<item name='system.describeMethods' />"
+ "</see>"
+ "<example/>"
+ "<error/>"
+ "<note/>"
+ "<bug/>"
+ "<todo/>"
+ "</methodDescription>"
+
+ "<!-- system.multiCall -->"
+ "<methodDescription name='system.multiCall'>"
+ "<author>Dan Libby</author>"
+ "<purpose>executes multiple methods in sequence and returns the results</purpose>"
+ "<version>1.0</version>"
+ "<signatures>"
+ "<signature>"
+ "<params>"
+ "<value type='array' name='methodList' desc='an array of method call structs'>"
+ "<value type='struct' desc='a struct representing a single method call'>"
+ "<value type='string' name='methodName' desc='name of the method to be executed'/>"
+ "<value type='array' name='params' desc='an array representing the params to a method. sub-elements should match method signature'/>"
+ "</value>"
+ "</value>"
+ "</params>"
+ "<returns>"
+ "<value type='array' desc='an array of method responses'>"
+ "<value type='array' desc='an array containing a single value, which is the method&apos;s response'/>"
+ "</value>"
+ "</returns>"
+ "</signature>"
+ "</signatures>"
+ "<see>"
+ "<item name='system.listMethods' />"
+ "<item name='system.methodHelp' />"
+ "<item name='system.describeMethods' />"
+ "</see>"
+ "<example/>"
+ "<error/>"
+ "<note/>"
+ "<bug/>"
+ "<todo/>"
+ "</methodDescription>"
+
+ "<!-- system.getCapabilities -->"
+ "<methodDescription name='system.getCapabilities'>"
+ "<author>Dan Libby</author>"
+ "<purpose>returns a list of capabilities supported by this server</purpose>"
+ "<version>1.0</version>"
+ "<notes><item>spec url: http://groups.yahoo.com/group/xml-rpc/message/2897</item></notes>"
+ "<signatures>"
+ "<signature>"
+ "<returns>"
+ "<value type='struct' desc='list of capabilities, each with a unique key defined by the capability&apos;s spec'>"
+ "<value type='struct' desc='definition of a single capability'>"
+ "<value type='string' name='specURL'>www address of the specification defining this capability</value>"
+ "<value type='int' name='specVersion'>version of the spec that this server's implementation conforms to</value>"
+ "</value>"
+ "</value>"
+ "</returns>"
+ "</signature>"
+ "</signatures>"
+ "<see>"
+ "<item name='system.listMethods' />"
+ "<item name='system.methodHelp' />"
+ "<item name='system.describeMethods' />"
+ "</see>"
+ "<example/>"
+ "<error/>"
+ "<note/>"
+ "<bug/>"
+ "<todo/>"
+ "</methodDescription>"
+
+ "</methodList>"
+"</introspection>";
+
+
+/* forward declarations for static (non public, non api) funcs */
+static XMLRPC_VALUE xsm_system_multicall_cb(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData);
+static XMLRPC_VALUE xsm_system_get_capabilities_cb(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData);
+
+/*-*******************
+* System Methods API *
+*********************/
+
+static void xsm_lazy_doc_methods_cb(XMLRPC_SERVER server, void* userData) {
+ XMLRPC_VALUE xDesc = XMLRPC_IntrospectionCreateDescription(xsm_introspection_xml, NULL);
+ XMLRPC_ServerAddIntrospectionData(server, xDesc);
+ XMLRPC_CleanupValue(xDesc);
+}
+
+void xsm_register(XMLRPC_SERVER server) {
+ xi_register_system_methods(server);
+
+ XMLRPC_ServerRegisterMethod(server, xsm_token_system_multicall, xsm_system_multicall_cb);
+ XMLRPC_ServerRegisterMethod(server, xsm_token_system_get_capabilities, xsm_system_get_capabilities_cb);
+
+ /* callback for documentation generation should it be requested */
+ XMLRPC_ServerRegisterIntrospectionCallback(server, xsm_lazy_doc_methods_cb);
+}
+
+XMLRPC_VALUE xsm_system_multicall_cb(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData) {
+ XMLRPC_VALUE xArray = XMLRPC_VectorRewind(XMLRPC_RequestGetData(input));
+ XMLRPC_VALUE xReturn = XMLRPC_CreateVector(0, xmlrpc_vector_array);
+
+ if (xArray) {
+ XMLRPC_VALUE xMethodIter = XMLRPC_VectorRewind(xArray);
+
+ while (xMethodIter) {
+ XMLRPC_REQUEST request = XMLRPC_RequestNew();
+ if(request) {
+ const char* methodName = XMLRPC_VectorGetStringWithID(xMethodIter, "methodName");
+ XMLRPC_VALUE params = XMLRPC_VectorGetValueWithID(xMethodIter, "params");
+
+ if(methodName && params) {
+ XMLRPC_VALUE xRandomArray = XMLRPC_CreateVector(0, xmlrpc_vector_array);
+ XMLRPC_RequestSetMethodName(request, methodName);
+ XMLRPC_RequestSetData(request, params);
+ XMLRPC_RequestSetRequestType(request, xmlrpc_request_call);
+
+ XMLRPC_AddValueToVector(xRandomArray,
+ XMLRPC_ServerCallMethod(server, request, userData));
+
+ XMLRPC_AddValueToVector(xReturn, xRandomArray);
+ }
+ XMLRPC_RequestFree(request, 1);
+ }
+ xMethodIter = XMLRPC_VectorNext(xArray);
+ }
+ }
+ return xReturn;
+}
+
+
+XMLRPC_VALUE xsm_system_get_capabilities_cb(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData) {
+ XMLRPC_VALUE xReturn = XMLRPC_CreateVector(0, xmlrpc_vector_struct);
+ XMLRPC_VALUE xFaults = XMLRPC_CreateVector("faults_interop", xmlrpc_vector_struct);
+ XMLRPC_VALUE xIntro = XMLRPC_CreateVector("introspection", xmlrpc_vector_struct);
+
+ /* support for fault spec */
+ XMLRPC_VectorAppendString(xFaults, "specURL", "http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php", 0);
+ XMLRPC_VectorAppendInt(xFaults, "specVersion", 20010516);
+
+ /* support for introspection spec */
+ XMLRPC_VectorAppendString(xIntro, "specURL", "http://xmlrpc-epi.sourceforge.net/specs/rfc.introspection.php", 0);
+ XMLRPC_VectorAppendInt(xIntro, "specVersion", 20010516);
+
+ XMLRPC_AddValuesToVector(xReturn,
+ xFaults,
+ xIntro,
+ NULL);
+
+ return xReturn;
+
+}
+
+/*-***********************
+* End System Methods API *
+*************************/
+
+
+
diff --git a/ext/xmlrpc/libxmlrpc/system_methods_private.h b/ext/xmlrpc/libxmlrpc/system_methods_private.h
new file mode 100644
index 0000000..72408fd
--- /dev/null
+++ b/ext/xmlrpc/libxmlrpc/system_methods_private.h
@@ -0,0 +1,91 @@
+/*
+ This file is part of libXMLRPC - a C library for xml-encoded function calls.
+
+ Author: Dan Libby (dan@libby.com)
+ Epinions.com may be contacted at feedback@epinions-inc.com
+*/
+
+/*
+ Copyright 2001 Dan Libby, Epinions, Inc.
+
+ Subject to the following 3 conditions, Epinions, Inc. permits you, free
+ of charge, to (a) use, copy, distribute, modify, perform and display this
+ software and associated documentation files (the "Software"), and (b)
+ permit others to whom the Software is furnished to do so as well.
+
+ 1) The above copyright notice and this permission notice shall be included
+ without modification in all copies or substantial portions of the
+ Software.
+
+ 2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF
+ ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY
+ IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ PURPOSE OR NONINFRINGEMENT.
+
+ 3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
+ OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING
+ NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH
+ DAMAGES.
+
+*/
+
+/* IMPORTANT!
+ *
+ * only non-public things should be in this file. It is fine for any .c file
+ * in xmlrpc/src to include it, but users of the public API should never
+ * include it, and thus *.h files that are part of the public API should
+ * never include it, or they would break if this file is not present.
+ */
+
+
+#ifndef __SYSTEM_METHODS_PRIVATE_H
+/*
+ * Avoid include redundancy.
+ */
+#define __SYSTEM_METHODS_PRIVATE_H
+
+/*----------------------------------------------------------------------------
+ * system_methods_private.h
+ *
+ * Purpose:
+ * define non-public system.* methods
+ * Comments:
+ * xsm = xmlrpc system methods
+ */
+
+/*----------------------------------------------------------------------------
+ * Constants
+ */
+#define xsm_token_system_multicall "system.multiCall"
+#define xsm_token_system_get_capabilities "system.getCapabilities"
+
+
+/*----------------------------------------------------------------------------
+ * Includes
+ */
+
+/*----------------------------------------------------------------------------
+ * Structures
+ */
+
+/*----------------------------------------------------------------------------
+ * Globals
+ */
+
+/*----------------------------------------------------------------------------
+ * Functions
+ */
+void xsm_register(XMLRPC_SERVER server);
+int xsm_is_system_method(XMLRPC_Callback cb);
+
+/*----------------------------------------------------------------------------
+ * Macros
+ */
+
+
+#endif /* __SYSTEM_METHODS_PRIVATE_H */
+
+
+
+
diff --git a/ext/xmlrpc/libxmlrpc/xml_element.c b/ext/xmlrpc/libxmlrpc/xml_element.c
new file mode 100644
index 0000000..56642d4
--- /dev/null
+++ b/ext/xmlrpc/libxmlrpc/xml_element.c
@@ -0,0 +1,767 @@
+/*
+ This file is part of libXMLRPC - a C library for xml-encoded function calls.
+
+ Author: Dan Libby (dan@libby.com)
+ Epinions.com may be contacted at feedback@epinions-inc.com
+*/
+
+/*
+ Copyright 2000 Epinions, Inc.
+
+ Subject to the following 3 conditions, Epinions, Inc. permits you, free
+ of charge, to (a) use, copy, distribute, modify, perform and display this
+ software and associated documentation files (the "Software"), and (b)
+ permit others to whom the Software is furnished to do so as well.
+
+ 1) The above copyright notice and this permission notice shall be included
+ without modification in all copies or substantial portions of the
+ Software.
+
+ 2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF
+ ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY
+ IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ PURPOSE OR NONINFRINGEMENT.
+
+ 3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
+ OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING
+ NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH
+ DAMAGES.
+
+*/
+
+
+static const char rcsid[] = "#(@) $Id$";
+
+
+
+/****h* ABOUT/xml_element
+ * NAME
+ * xml_element
+ * AUTHOR
+ * Dan Libby, aka danda (dan@libby.com)
+ * CREATION DATE
+ * 06/2000
+ * HISTORY
+ * $Log$
+ * Revision 1.9.4.1.2.1 2008/12/09 17:22:12 iliaa
+ *
+ * MFH: Fixed bug #46746 (xmlrpc_decode_request outputs non-suppressable error
+ * when given bad data).
+ *
+ * Revision 1.9.4.1 2006/07/30 11:34:02 tony2001
+ * MFH: fix compile warnings (#38257)
+ *
+ * Revision 1.9 2005/04/22 11:06:53 jorton
+ * Fixed bug #32797 (invalid C code in xmlrpc extension).
+ *
+ * Revision 1.8 2005/03/28 00:07:24 edink
+ * Reshufle includes to make it compile on windows
+ *
+ * Revision 1.7 2005/03/26 03:13:58 sniper
+ * - Made it possible to build ext/xmlrpc with libxml2
+ *
+ * Revision 1.6 2004/06/01 20:16:06 iliaa
+ * Fixed bug #28597 (xmlrpc_encode_request() incorrectly encodes chars in
+ * 200-210 range).
+ * Patch by: fernando dot nemec at folha dot com dot br
+ *
+ * Revision 1.5 2003/12/16 21:00:21 sniper
+ * Fix some compile warnings (patch by Joe Orton)
+ *
+ * Revision 1.4 2002/11/26 23:01:16 fmk
+ * removing unused variables
+ *
+ * Revision 1.3 2002/07/05 04:43:53 danda
+ * merged in updates from SF project. bring php repository up to date with xmlrpc-epi version 0.51
+ *
+ * Revision 1.9 2002/07/03 20:54:30 danda
+ * root element should not have a parent. patch from anon SF user
+ *
+ * Revision 1.8 2002/05/23 17:46:51 danda
+ * patch from mukund - fix non utf-8 encoding conversions
+ *
+ * Revision 1.7 2002/02/13 20:58:50 danda
+ * patch to make source more windows friendly, contributed by Jeff Lawson
+ *
+ * Revision 1.6 2002/01/08 01:06:55 danda
+ * enable <?xml version="1.0"?> format for parsers that are very picky.
+ *
+ * Revision 1.5 2001/09/29 21:58:05 danda
+ * adding cvs log to history section
+ *
+ * 10/15/2000 -- danda -- adding robodoc documentation
+ * TODO
+ * Nicer external API. Get rid of macros. Make opaque types, etc.
+ * PORTABILITY
+ * Coded on RedHat Linux 6.2. Builds on Solaris x86. Should build on just
+ * about anything with minor mods.
+ * NOTES
+ * This code incorporates ideas from expat-ensor from http://xml.ensor.org.
+ *
+ * It was coded primarily to act as a go-between for expat and xmlrpc. To this
+ * end, it stores xml elements, their sub-elements, and their attributes in an
+ * in-memory tree. When expat is done parsing, the tree can be walked, thus
+ * retrieving the values. The code can also be used to build a tree via API then
+ * write out the tree to a buffer, thus "serializing" the xml.
+ *
+ * It turns out this is useful for other purposes, such as parsing config files.
+ * YMMV.
+ *
+ * Some Features:
+ * - output option for xml escaping data. Choices include no escaping, entity escaping,
+ * or CDATA sections.
+ * - output option for character encoding. Defaults to (none) utf-8.
+ * - output option for verbosity/readability. ultra-compact, newlines, pretty/level indented.
+ *
+ * BUGS
+ * there must be some.
+ ******/
+
+#include "ext/xml/expat_compat.h"
+#ifdef _WIN32
+#include "xmlrpc_win32.h"
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "xml_element.h"
+#include "queue.h"
+#include "encodings.h"
+
+#define my_free(thing) if(thing) {free(thing); thing = NULL;}
+
+#define XML_DECL_START "<?xml"
+#define XML_DECL_START_LEN sizeof(XML_DECL_START) - 1
+#define XML_DECL_VERSION "version=\"1.0\""
+#define XML_DECL_VERSION_LEN sizeof(XML_DECL_VERSION) - 1
+#define XML_DECL_ENCODING_ATTR "encoding"
+#define XML_DECL_ENCODING_ATTR_LEN sizeof(XML_DECL_ENCODING_ATTR) - 1
+#define XML_DECL_ENCODING_DEFAULT "utf-8"
+#define XML_DECL_ENCODING_DEFAULT_LEN sizeof(XML_DECL_ENCODING_DEFAULT) - 1
+#define XML_DECL_END "?>"
+#define XML_DECL_END_LEN sizeof(XML_DECL_END) - 1
+#define START_TOKEN_BEGIN "<"
+#define START_TOKEN_BEGIN_LEN sizeof(START_TOKEN_BEGIN) - 1
+#define START_TOKEN_END ">"
+#define START_TOKEN_END_LEN sizeof(START_TOKEN_END) - 1
+#define EMPTY_START_TOKEN_END "/>"
+#define EMPTY_START_TOKEN_END_LEN sizeof(EMPTY_START_TOKEN_END) - 1
+#define END_TOKEN_BEGIN "</"
+#define END_TOKEN_BEGIN_LEN sizeof(END_TOKEN_BEGIN) - 1
+#define END_TOKEN_END ">"
+#define END_TOKEN_END_LEN sizeof(END_TOKEN_END) - 1
+#define ATTR_DELIMITER "\""
+#define ATTR_DELIMITER_LEN sizeof(ATTR_DELIMITER) - 1
+#define CDATA_BEGIN "<![CDATA["
+#define CDATA_BEGIN_LEN sizeof(CDATA_BEGIN) - 1
+#define CDATA_END "]]>"
+#define CDATA_END_LEN sizeof(CDATA_END) - 1
+#define EQUALS "="
+#define EQUALS_LEN sizeof(EQUALS) - 1
+#define WHITESPACE " "
+#define WHITESPACE_LEN sizeof(WHITESPACE) - 1
+#define NEWLINE "\n"
+#define NEWLINE_LEN sizeof(NEWLINE) - 1
+#define MAX_VAL_BUF 144
+#define SCALAR_STR "SCALAR"
+#define SCALAR_STR_LEN sizeof(SCALAR_STR) - 1
+#define VECTOR_STR "VECTOR"
+#define VECTOR_STR_LEN sizeof(VECTOR_STR) - 1
+#define RESPONSE_STR "RESPONSE"
+#define RESPONSE_STR_LEN sizeof(RESPONSE_STR) - 1
+
+
+/*-----------------------------
+- Begin xml_element Functions -
+-----------------------------*/
+
+/****f* xml_element/xml_elem_free_non_recurse
+ * NAME
+ * xml_elem_free_non_recurse
+ * SYNOPSIS
+ * void xml_elem_free_non_recurse(xml_element* root)
+ * FUNCTION
+ * free a single xml element. child elements will not be freed.
+ * INPUTS
+ * root - the element to free
+ * RESULT
+ * void
+ * NOTES
+ * SEE ALSO
+ * xml_elem_free ()
+ * xml_elem_new ()
+ * SOURCE
+ */
+void xml_elem_free_non_recurse(xml_element* root) {
+ if(root) {
+ xml_element_attr* attrs = Q_Head(&root->attrs);
+ while(attrs) {
+ my_free(attrs->key);
+ my_free(attrs->val);
+ my_free(attrs);
+ attrs = Q_Next(&root->attrs);
+ }
+
+ Q_Destroy(&root->children);
+ Q_Destroy(&root->attrs);
+ if(root->name) {
+ free((char *)root->name);
+ root->name = NULL;
+ }
+ simplestring_free(&root->text);
+ my_free(root);
+ }
+}
+/******/
+
+/****f* xml_element/xml_elem_free
+ * NAME
+ * xml_elem_free
+ * SYNOPSIS
+ * void xml_elem_free(xml_element* root)
+ * FUNCTION
+ * free an xml element and all of its child elements
+ * INPUTS
+ * root - the root of an xml tree you would like to free
+ * RESULT
+ * void
+ * NOTES
+ * SEE ALSO
+ * xml_elem_free_non_recurse ()
+ * xml_elem_new ()
+ * SOURCE
+ */
+void xml_elem_free(xml_element* root) {
+ if(root) {
+ xml_element* kids = Q_Head(&root->children);
+ while(kids) {
+ xml_elem_free(kids);
+ kids = Q_Next(&root->children);
+ }
+ xml_elem_free_non_recurse(root);
+ }
+}
+/******/
+
+/****f* xml_element/xml_elem_new
+ * NAME
+ * xml_elem_new
+ * SYNOPSIS
+ * xml_element* xml_elem_new()
+ * FUNCTION
+ * allocates and initializes a new xml_element
+ * INPUTS
+ * none
+ * RESULT
+ * xml_element* or NULL. NULL indicates an out-of-memory condition.
+ * NOTES
+ * SEE ALSO
+ * xml_elem_free ()
+ * xml_elem_free_non_recurse ()
+ * SOURCE
+ */
+xml_element* xml_elem_new() {
+ xml_element* elem = calloc(1, sizeof(xml_element));
+ if(elem) {
+ Q_Init(&elem->children);
+ Q_Init(&elem->attrs);
+ simplestring_init(&elem->text);
+
+ /* init empty string in case we don't find any char data */
+ simplestring_addn(&elem->text, "", 0);
+ }
+ return elem;
+}
+/******/
+
+static int xml_elem_writefunc(int (*fptr)(void *data, const char *text, int size), const char *text, void *data, int len)
+{
+ return fptr && text ? fptr(data, text, len ? len : strlen(text)) : 0;
+}
+
+
+
+static int create_xml_escape(char *pString, unsigned char c)
+{
+ int counter = 0;
+
+ pString[counter++] = '&';
+ pString[counter++] = '#';
+ if(c >= 100) {
+ pString[counter++] = c / 100 + '0';
+ c = c % 100;
+ }
+ pString[counter++] = c / 10 + '0';
+ c = c % 10;
+
+ pString[counter++] = c + '0';
+ pString[counter++] = ';';
+ return counter;
+}
+
+#define non_ascii(c) (c > 127)
+#define non_print(c) (!isprint(c))
+#define markup(c) (c == '&' || c == '\"' || c == '>' || c == '<')
+#define entity_length(c) ( (c >= 100) ? 3 : ((c >= 10) ? 2 : 1) ) + 3; /* "&#" + c + ";" */
+
+/*
+ * xml_elem_entity_escape
+ *
+ * Purpose:
+ * escape reserved xml chars and non utf-8 chars as xml entities
+ * Comments:
+ * The return value may be a new string, or null if no
+ * conversion was performed. In the latter case, *newlen will
+ * be 0.
+ * Flags (to escape)
+ * xml_elem_no_escaping = 0x000,
+ * xml_elem_entity_escaping = 0x002, // escape xml special chars as entities
+ * xml_elem_non_ascii_escaping = 0x008, // escape chars above 127
+ * xml_elem_cdata_escaping = 0x010, // wrap in cdata
+ */
+static char* xml_elem_entity_escape(const char* buf, int old_len, int *newlen, XML_ELEM_ESCAPING flags) {
+ char *pRetval = 0;
+ int iNewBufLen=0;
+
+#define should_escape(c, flag) ( ((flag & xml_elem_markup_escaping) && markup(c)) || \
+ ((flag & xml_elem_non_ascii_escaping) && non_ascii(c)) || \
+ ((flag & xml_elem_non_print_escaping) && non_print(c)) )
+
+ if(buf && *buf) {
+ const unsigned char *bufcopy;
+ char *NewBuffer;
+ int ToBeXmlEscaped=0;
+ int iLength;
+ bufcopy = buf;
+ iLength= old_len ? old_len : strlen(buf);
+ while(*bufcopy) {
+ if( should_escape(*bufcopy, flags) ) {
+ /* the length will increase by length of xml escape - the character length */
+ iLength += entity_length(*bufcopy);
+ ToBeXmlEscaped=1;
+ }
+ bufcopy++;
+ }
+
+ if(ToBeXmlEscaped) {
+
+ NewBuffer= malloc(iLength+1);
+ if(NewBuffer) {
+ bufcopy=buf;
+ while(*bufcopy) {
+ if(should_escape(*bufcopy, flags)) {
+ iNewBufLen += create_xml_escape(NewBuffer+iNewBufLen,*bufcopy);
+ }
+ else {
+ NewBuffer[iNewBufLen++]=*bufcopy;
+ }
+ bufcopy++;
+ }
+ NewBuffer[iNewBufLen] = 0;
+ pRetval = NewBuffer;
+ }
+ }
+ }
+
+ if(newlen) {
+ *newlen = iNewBufLen;
+ }
+
+ return pRetval;
+}
+
+
+static void xml_element_serialize(xml_element *el, int (*fptr)(void *data, const char *text, int size), void *data, XML_ELEM_OUTPUT_OPTIONS options, int depth)
+{
+ int i;
+ static STRUCT_XML_ELEM_OUTPUT_OPTIONS default_opts = {xml_elem_pretty, xml_elem_markup_escaping | xml_elem_non_print_escaping, XML_DECL_ENCODING_DEFAULT};
+ static char whitespace[] = " "
+ " "
+ " ";
+ depth++;
+
+ if(!el) {
+ /* fprintf(stderr, "Nothing to write\n"); */
+ return;
+ }
+ if(!options) {
+ options = &default_opts;
+ }
+
+ /* print xml declaration if at root level */
+ if(depth == 1) {
+ xml_elem_writefunc(fptr, XML_DECL_START, data, XML_DECL_START_LEN);
+ xml_elem_writefunc(fptr, WHITESPACE, data, WHITESPACE_LEN);
+ xml_elem_writefunc(fptr, XML_DECL_VERSION, data, XML_DECL_VERSION_LEN);
+ if(options->encoding && *options->encoding) {
+ xml_elem_writefunc(fptr, WHITESPACE, data, WHITESPACE_LEN);
+ xml_elem_writefunc(fptr, XML_DECL_ENCODING_ATTR, data, XML_DECL_ENCODING_ATTR_LEN);
+ xml_elem_writefunc(fptr, EQUALS, data, EQUALS_LEN);
+ xml_elem_writefunc(fptr, ATTR_DELIMITER, data, ATTR_DELIMITER_LEN);
+ xml_elem_writefunc(fptr, options->encoding, data, 0);
+ xml_elem_writefunc(fptr, ATTR_DELIMITER, data, ATTR_DELIMITER_LEN);
+ }
+ xml_elem_writefunc(fptr, XML_DECL_END, data, XML_DECL_END_LEN);
+ if(options->verbosity != xml_elem_no_white_space) {
+ xml_elem_writefunc(fptr, NEWLINE, data, NEWLINE_LEN);
+ }
+ }
+
+ if(options->verbosity == xml_elem_pretty && depth > 2) {
+ xml_elem_writefunc(fptr, whitespace, data, depth - 2);
+ }
+ /* begin element */
+ xml_elem_writefunc(fptr,START_TOKEN_BEGIN, data, START_TOKEN_BEGIN_LEN);
+ if(el->name) {
+ xml_elem_writefunc(fptr, el->name, data, 0);
+
+ /* write attrs, if any */
+ if(Q_Size(&el->attrs)) {
+ xml_element_attr* iter = Q_Head(&el->attrs);
+ while( iter ) {
+ xml_elem_writefunc(fptr, WHITESPACE, data, WHITESPACE_LEN);
+ xml_elem_writefunc(fptr, iter->key, data, 0);
+ xml_elem_writefunc(fptr, EQUALS, data, EQUALS_LEN);
+ xml_elem_writefunc(fptr, ATTR_DELIMITER, data, ATTR_DELIMITER_LEN);
+ xml_elem_writefunc(fptr, iter->val, data, 0);
+ xml_elem_writefunc(fptr, ATTR_DELIMITER, data, ATTR_DELIMITER_LEN);
+
+ iter = Q_Next(&el->attrs);
+ }
+ }
+ }
+ else {
+ xml_elem_writefunc(fptr, "None", data, 0);
+ }
+ /* if no text and no children, use abbreviated form, eg: <foo/> */
+ if(!el->text.len && !Q_Size(&el->children)) {
+ xml_elem_writefunc(fptr, EMPTY_START_TOKEN_END, data, EMPTY_START_TOKEN_END_LEN);
+ }
+ /* otherwise, print element contents */
+ else {
+ xml_elem_writefunc(fptr, START_TOKEN_END, data, START_TOKEN_END_LEN);
+
+ /* print text, if any */
+ if(el->text.len) {
+ char* escaped_str = el->text.str;
+ int buflen = el->text.len;
+
+ if(options->escaping && options->escaping != xml_elem_cdata_escaping) {
+ escaped_str = xml_elem_entity_escape(el->text.str, buflen, &buflen, options->escaping );
+ if(!escaped_str) {
+ escaped_str = el->text.str;
+ }
+ }
+
+ if(options->escaping & xml_elem_cdata_escaping) {
+ xml_elem_writefunc(fptr, CDATA_BEGIN, data, CDATA_BEGIN_LEN);
+ }
+
+ xml_elem_writefunc(fptr, escaped_str, data, buflen);
+
+ if(escaped_str != el->text.str) {
+ my_free(escaped_str);
+ }
+
+ if(options->escaping & xml_elem_cdata_escaping) {
+ xml_elem_writefunc(fptr, CDATA_END, data, CDATA_END_LEN);
+ }
+ }
+ /* no text, so print child elems */
+ else {
+ xml_element *kids = Q_Head(&el->children);
+ i = 0;
+ while( kids ) {
+ if(i++ == 0) {
+ if(options->verbosity != xml_elem_no_white_space) {
+ xml_elem_writefunc(fptr, NEWLINE, data, NEWLINE_LEN);
+ }
+ }
+ xml_element_serialize(kids, fptr, data, options, depth);
+ kids = Q_Next(&el->children);
+ }
+ if(i) {
+ if(options->verbosity == xml_elem_pretty && depth > 2) {
+ xml_elem_writefunc(fptr, whitespace, data, depth - 2);
+ }
+ }
+ }
+
+ xml_elem_writefunc(fptr, END_TOKEN_BEGIN, data, END_TOKEN_BEGIN_LEN);
+ xml_elem_writefunc(fptr,el->name ? el->name : "None", data, 0);
+ xml_elem_writefunc(fptr, END_TOKEN_END, data, END_TOKEN_END_LEN);
+ }
+ if(options->verbosity != xml_elem_no_white_space) {
+ xml_elem_writefunc(fptr, NEWLINE, data, NEWLINE_LEN);
+ }
+}
+
+/* print buf to file */
+static int file_out_fptr(void *f, const char *text, int size)
+{
+ fputs(text, (FILE *)f);
+ return 0;
+}
+
+/* print buf to simplestring */
+static int simplestring_out_fptr(void *f, const char *text, int size)
+{
+ simplestring* buf = (simplestring*)f;
+ if(buf) {
+ simplestring_addn(buf, text, size);
+ }
+ return 0;
+}
+
+/****f* xml_element/xml_elem_serialize_to_string
+ * NAME
+ * xml_elem_serialize_to_string
+ * SYNOPSIS
+ * void xml_element_serialize_to_string(xml_element *el, XML_ELEM_OUTPUT_OPTIONS options, int *buf_len)
+ * FUNCTION
+ * writes element tree as XML into a newly allocated buffer
+ * INPUTS
+ * el - root element of tree
+ * options - options determining how output is written. see XML_ELEM_OUTPUT_OPTIONS
+ * buf_len - length of returned buffer, if not null.
+ * RESULT
+ * char* or NULL. Must be free'd by caller.
+ * NOTES
+ * SEE ALSO
+ * xml_elem_serialize_to_stream ()
+ * xml_elem_parse_buf ()
+ * SOURCE
+ */
+char* xml_elem_serialize_to_string(xml_element *el, XML_ELEM_OUTPUT_OPTIONS options, int *buf_len)
+{
+ simplestring buf;
+ simplestring_init(&buf);
+
+ xml_element_serialize(el, simplestring_out_fptr, (void *)&buf, options, 0);
+
+ if(buf_len) {
+ *buf_len = buf.len;
+ }
+
+ return buf.str;
+}
+/******/
+
+/****f* xml_element/xml_elem_serialize_to_stream
+ * NAME
+ * xml_elem_serialize_to_stream
+ * SYNOPSIS
+ * void xml_elem_serialize_to_stream(xml_element *el, FILE *output, XML_ELEM_OUTPUT_OPTIONS options)
+ * FUNCTION
+ * writes element tree as XML into a stream (typically an opened file)
+ * INPUTS
+ * el - root element of tree
+ * output - stream handle
+ * options - options determining how output is written. see XML_ELEM_OUTPUT_OPTIONS
+ * RESULT
+ * void
+ * NOTES
+ * SEE ALSO
+ * xml_elem_serialize_to_string ()
+ * xml_elem_parse_buf ()
+ * SOURCE
+ */
+void xml_elem_serialize_to_stream(xml_element *el, FILE *output, XML_ELEM_OUTPUT_OPTIONS options)
+{
+ xml_element_serialize(el, file_out_fptr, (void *)output, options, 0);
+}
+/******/
+
+/*--------------------------*
+* End xml_element Functions *
+*--------------------------*/
+
+
+/*----------------------
+* Begin Expat Handlers *
+*---------------------*/
+
+typedef struct _xml_elem_data {
+ xml_element* root;
+ xml_element* current;
+ XML_ELEM_INPUT_OPTIONS input_options;
+ int needs_enc_conversion;
+} xml_elem_data;
+
+
+/* expat start of element handler */
+static void _xmlrpc_startElement(void *userData, const char *name, const char **attrs)
+{
+ xml_element *c;
+ xml_elem_data* mydata = (xml_elem_data*)userData;
+ const char** p = attrs;
+
+ if(mydata) {
+ c = mydata->current;
+
+ mydata->current = xml_elem_new();
+ mydata->current->name = (char*)strdup(name);
+ mydata->current->parent = c;
+
+ /* init attrs */
+ while(p && *p) {
+ xml_element_attr* attr = malloc(sizeof(xml_element_attr));
+ if(attr) {
+ attr->key = strdup(*p);
+ attr->val = strdup(*(p+1));
+ Q_PushTail(&mydata->current->attrs, attr);
+
+ p += 2;
+ }
+ }
+ }
+}
+
+/* expat end of element handler */
+static void _xmlrpc_endElement(void *userData, const char *name)
+{
+ xml_elem_data* mydata = (xml_elem_data*)userData;
+
+ if(mydata && mydata->current && mydata->current->parent) {
+ Q_PushTail(&mydata->current->parent->children, mydata->current);
+
+ mydata->current = mydata->current->parent;
+ }
+}
+
+/* expat char data handler */
+static void _xmlrpc_charHandler(void *userData,
+ const char *s,
+ int len)
+{
+ xml_elem_data* mydata = (xml_elem_data*)userData;
+ if(mydata && mydata->current) {
+
+ /* Check if we need to decode utf-8 parser output to another encoding */
+ if(mydata->needs_enc_conversion && mydata->input_options->encoding) {
+ int new_len = 0;
+ char* add_text = utf8_decode(s, len, &new_len, mydata->input_options->encoding);
+ if(add_text) {
+ len = new_len;
+ simplestring_addn(&mydata->current->text, add_text, len);
+ free(add_text);
+ return;
+ }
+ }
+ simplestring_addn(&mydata->current->text, s, len);
+ }
+}
+/******/
+
+/*-------------------*
+* End Expat Handlers *
+*-------------------*/
+
+/*-------------------*
+* xml_elem_parse_buf *
+*-------------------*/
+
+/****f* xml_element/xml_elem_parse_buf
+ * NAME
+ * xml_elem_parse_buf
+ * SYNOPSIS
+ * xml_element* xml_elem_parse_buf(const char* in_buf, int len, XML_ELEM_INPUT_OPTIONS options, XML_ELEM_ERROR error)
+ * FUNCTION
+ * parse a buffer containing XML into an xml_element in-memory tree
+ * INPUTS
+ * in_buf - buffer containing XML document
+ * len - length of buffer
+ * options - input options. optional
+ * error - error result data. optional. check if result is null.
+ * RESULT
+ * void
+ * NOTES
+ * The returned data must be free'd by caller
+ * SEE ALSO
+ * xml_elem_serialize_to_string ()
+ * xml_elem_free ()
+ * SOURCE
+ */
+xml_element* xml_elem_parse_buf(const char* in_buf, int len, XML_ELEM_INPUT_OPTIONS options, XML_ELEM_ERROR error)
+{
+ xml_element* xReturn = NULL;
+ char buf[100] = "";
+ static STRUCT_XML_ELEM_INPUT_OPTIONS default_opts = {encoding_utf_8};
+
+ if(!options) {
+ options = &default_opts;
+ }
+
+ if(in_buf) {
+ XML_Parser parser;
+ xml_elem_data mydata = {0};
+
+ parser = XML_ParserCreate(NULL);
+
+ mydata.root = xml_elem_new();
+ mydata.current = mydata.root;
+ mydata.input_options = options;
+ mydata.needs_enc_conversion = options->encoding && strcmp(options->encoding, encoding_utf_8);
+
+ XML_SetElementHandler(parser, (XML_StartElementHandler)_xmlrpc_startElement, (XML_EndElementHandler)_xmlrpc_endElement);
+ XML_SetCharacterDataHandler(parser, (XML_CharacterDataHandler)_xmlrpc_charHandler);
+
+ /* pass the xml_elem_data struct along */
+ XML_SetUserData(parser, (void*)&mydata);
+
+ if(!len) {
+ len = strlen(in_buf);
+ }
+
+ /* parse the XML */
+ if(XML_Parse(parser, in_buf, len, 1) == 0) {
+ enum XML_Error err_code = XML_GetErrorCode(parser);
+ int line_num = XML_GetCurrentLineNumber(parser);
+ int col_num = XML_GetCurrentColumnNumber(parser);
+ long byte_idx = XML_GetCurrentByteIndex(parser);
+/* int byte_total = XML_GetCurrentByteCount(parser); */
+ const char * error_str = XML_ErrorString(err_code);
+ if(byte_idx >= 0) {
+ snprintf(buf,
+ sizeof(buf),
+ "\n\tdata beginning %ld before byte index: %s\n",
+ byte_idx > 10 ? 10 : byte_idx,
+ in_buf + (byte_idx > 10 ? byte_idx - 10 : byte_idx));
+ }
+/*
+ fprintf(stderr, "expat reports error code %i\n"
+ "\tdescription: %s\n"
+ "\tline: %i\n"
+ "\tcolumn: %i\n"
+ "\tbyte index: %ld\n"
+ "\ttotal bytes: %i\n%s ",
+ err_code, error_str, line_num,
+ col_num, byte_idx, byte_total, buf);
+*/
+
+ /* error condition */
+ if(error) {
+ error->parser_code = (long)err_code;
+ error->line = line_num;
+ error->column = col_num;
+ error->byte_index = byte_idx;
+ error->parser_error = error_str;
+ }
+ }
+ else {
+ xReturn = (xml_element*)Q_Head(&mydata.root->children);
+ xReturn->parent = NULL;
+ }
+
+ XML_ParserFree(parser);
+
+
+ xml_elem_free_non_recurse(mydata.root);
+ }
+
+ return xReturn;
+}
+
+/******/
diff --git a/ext/xmlrpc/libxmlrpc/xml_element.h b/ext/xmlrpc/libxmlrpc/xml_element.h
new file mode 100644
index 0000000..cfe7ca2
--- /dev/null
+++ b/ext/xmlrpc/libxmlrpc/xml_element.h
@@ -0,0 +1,202 @@
+/*
+ This file is part of libXMLRPC - a C library for xml-encoded function calls.
+
+ Author: Dan Libby (dan@libby.com)
+ Epinions.com may be contacted at feedback@epinions-inc.com
+*/
+
+/*
+ Copyright 2000 Epinions, Inc.
+
+ Subject to the following 3 conditions, Epinions, Inc. permits you, free
+ of charge, to (a) use, copy, distribute, modify, perform and display this
+ software and associated documentation files (the "Software"), and (b)
+ permit others to whom the Software is furnished to do so as well.
+
+ 1) The above copyright notice and this permission notice shall be included
+ without modification in all copies or substantial portions of the
+ Software.
+
+ 2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF
+ ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY
+ IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ PURPOSE OR NONINFRINGEMENT.
+
+ 3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
+ OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING
+ NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH
+ DAMAGES.
+
+*/
+
+#ifndef __XML_ELEMENT_H__
+ #define __XML_ELEMENT_H__
+
+/* includes */
+#include <stdio.h>
+#include "queue.h"
+#include "simplestring.h"
+#include "encodings.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/****d* enum/XML_ELEM_VERBOSITY
+ * NAME
+ * XML_ELEM_VERBOSITY
+ * NOTES
+ * verbosity/readability options for generated xml
+ * SEE ALSO
+ * XML_ELEM_OUTPUT_OPTIONS
+ * SOURCE
+ */
+typedef enum _xml_elem_verbosity {
+ xml_elem_no_white_space, /* compact xml with no white space */
+ xml_elem_newlines_only, /* add newlines for enhanced readability */
+ xml_elem_pretty /* add newlines and indent accordint to depth */
+} XML_ELEM_VERBOSITY;
+/******/
+
+
+/****d* enum/XML_ELEM_ESCAPING
+ * NAME
+ * XML_ELEM_ESCAPING
+ * NOTES
+ * xml escaping options for generated xml
+ * SEE ALSO
+ * XML_ELEM_OUTPUT_OPTIONS
+ * SOURCE
+ */
+typedef enum _xml_elem_escaping {
+ xml_elem_no_escaping = 0x000,
+ xml_elem_markup_escaping = 0x002, /* entity escape xml special chars */
+ xml_elem_non_ascii_escaping = 0x008, /* entity escape chars above 127 */
+ xml_elem_non_print_escaping = 0x010, /* entity escape non print (illegal) chars */
+ xml_elem_cdata_escaping = 0x020, /* wrap in cdata section */
+} XML_ELEM_ESCAPING;
+/******/
+
+
+/****s* struct/XML_ELEM_OUTPUT_OPTIONS
+ * NAME
+ * XML_ELEM_OUTPUT_OPTIONS
+ * NOTES
+ * defines various output options
+ * SOURCE
+ */
+typedef struct _xml_output_options {
+ XML_ELEM_VERBOSITY verbosity; /* length/verbosity of xml */
+ XML_ELEM_ESCAPING escaping; /* how to escape special chars */
+ const char* encoding; /* <?xml encoding="<encoding>" ?> */
+} STRUCT_XML_ELEM_OUTPUT_OPTIONS, *XML_ELEM_OUTPUT_OPTIONS;
+/******/
+
+/****s* struct/XML_ELEM_INPUT_OPTIONS
+ * NAME
+ * XML_ELEM_INPUT_OPTIONS
+ * NOTES
+ * defines various input options
+ * SOURCE
+ */
+typedef struct _xml_input_options {
+ ENCODING_ID encoding; /* which encoding to use. */
+} STRUCT_XML_ELEM_INPUT_OPTIONS, *XML_ELEM_INPUT_OPTIONS;
+/******/
+
+/****s* struct/XML_ELEM_ERROR
+ * NAME
+ * XML_ELEM_ERROR
+ * NOTES
+ * defines an xml parser error
+ * SOURCE
+ */
+typedef struct _xml_elem_error {
+ int parser_code;
+ const char* parser_error;
+ long line;
+ long column;
+ long byte_index;
+} STRUCT_XML_ELEM_ERROR, *XML_ELEM_ERROR;
+/******/
+
+
+/*-************************
+* begin xml element stuff *
+**************************/
+
+/****s* struct/xml_elem_attr
+ * NAME
+ * xml_elem_attr
+ * NOTES
+ * representation of an xml attribute, foo="bar"
+ * SOURCE
+ */
+typedef struct _xml_element_attr {
+ char* key; /* attribute key */
+ char* val; /* attribute value */
+} xml_element_attr;
+/******/
+
+/****s* struct/xml_elem_attr
+ * NAME
+ * xml_elem_attr
+ * NOTES
+ * representation of an xml element, eg <candidate name="Harry Browne" party="Libertarian"/>
+ * SOURCE
+ */
+typedef struct _xml_element {
+ const char* name; /* element identifier */
+ simplestring text; /* text contained between element begin/end pairs */
+ struct _xml_element* parent; /* element's parent */
+
+ queue attrs; /* attribute list */
+ queue children; /* child element list */
+} xml_element;
+/******/
+
+void xml_elem_free(xml_element* root);
+void xml_elem_free_non_recurse(xml_element* root);
+xml_element* xml_elem_new(void);
+char* xml_elem_serialize_to_string(xml_element *el, XML_ELEM_OUTPUT_OPTIONS options, int *buf_len);
+void xml_elem_serialize_to_stream(xml_element *el, FILE *output, XML_ELEM_OUTPUT_OPTIONS options);
+xml_element* xml_elem_parse_buf(const char* in_buf, int len, XML_ELEM_INPUT_OPTIONS options, XML_ELEM_ERROR error);
+
+/*-**********************
+* end xml element stuff *
+************************/
+
+/*-**********************
+* Begin xml_element API *
+************************/
+
+/****d* VALUE/XMLRPC_MACROS
+ * NAME
+ * Some Helpful Macros
+ * NOTES
+ * Some macros for making life easier. Should be self-explanatory.
+ * SEE ALSO
+ * XMLRPC_AddValueToVector ()
+ * XMLRPC_VectorGetValueWithID_Case ()
+ * XMLRPC_VALUE
+ * SOURCE
+ */
+#define xml_elem_next_element(el) ((el) ? (xml_element *)Q_Next(&el->children) : NULL)
+#define xml_elem_head_element(el) ((el) ? (xml_element *)Q_Head(&el->children) : NULL)
+#define xml_elem_next_attr(el) ((el) ? (xml_element_attr *)Q_Next(&el->attrs) : NULL)
+#define xml_elem_head_attr(el) ((el) ? (xml_element_attr *)Q_Head(&el->attrs) : NULL)
+#define xml_elem_get_name(el) (char *)((el) ? el->name : NULL)
+#define xml_elem_get_val(el) (char *)((el) ? el->text.str : NULL)
+/******/
+
+
+/*-********************
+* End xml_element API *
+**********************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __XML_ELEMENT_H__ */
diff --git a/ext/xmlrpc/libxmlrpc/xml_to_dandarpc.c b/ext/xmlrpc/libxmlrpc/xml_to_dandarpc.c
new file mode 100644
index 0000000..753222c
--- /dev/null
+++ b/ext/xmlrpc/libxmlrpc/xml_to_dandarpc.c
@@ -0,0 +1,319 @@
+/*
+ This file is part of libXMLRPC - a C library for xml-encoded function calls.
+
+ Author: Dan Libby (dan@libby.com)
+ Epinions.com may be contacted at feedback@epinions-inc.com
+*/
+
+/*
+ Copyright 2000 Epinions, Inc.
+
+ Subject to the following 3 conditions, Epinions, Inc. permits you, free
+ of charge, to (a) use, copy, distribute, modify, perform and display this
+ software and associated documentation files (the "Software"), and (b)
+ permit others to whom the Software is furnished to do so as well.
+
+ 1) The above copyright notice and this permission notice shall be included
+ without modification in all copies or substantial portions of the
+ Software.
+
+ 2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF
+ ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY
+ IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ PURPOSE OR NONINFRINGEMENT.
+
+ 3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
+ OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING
+ NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH
+ DAMAGES.
+
+*/
+
+#ifdef _WIN32
+#include "xmlrpc_win32.h"
+#endif
+#include <string.h>
+#include <stdlib.h>
+#include "xml_to_dandarpc.h"
+#include "base64.h"
+
+/* list of tokens used in vocab */
+#define ELEM_METHODCALL "methodCall"
+#define ELEM_METHODNAME "methodName"
+#define ELEM_METHODRESPONSE "methodResponse"
+#define ELEM_ROOT "simpleRPC"
+
+#define ATTR_ARRAY "array"
+#define ATTR_BASE64 "base64"
+#define ATTR_BOOLEAN "boolean"
+#define ATTR_DATETIME "dateTime.iso8601"
+#define ATTR_DOUBLE "double"
+#define ATTR_ID "id"
+#define ATTR_INT "int"
+#define ATTR_MIXED "mixed"
+#define ATTR_SCALAR "scalar"
+#define ATTR_STRING "string"
+#define ATTR_STRUCT "struct"
+#define ATTR_TYPE "type"
+#define ATTR_VECTOR "vector"
+#define ATTR_VERSION "version"
+
+#define VAL_VERSION_0_9 "0.9"
+
+
+XMLRPC_VALUE xml_element_to_DANDARPC_REQUEST_worker(XMLRPC_REQUEST request, XMLRPC_VALUE xCurrent, xml_element* el) {
+ if(!xCurrent) {
+ xCurrent = XMLRPC_CreateValueEmpty();
+ }
+
+ if(el->name) {
+ const char* id = NULL;
+ const char* type = NULL;
+ xml_element_attr* attr_iter = Q_Head(&el->attrs);
+
+ while(attr_iter) {
+ if(!strcmp(attr_iter->key, ATTR_ID)) {
+ id = attr_iter->val;
+ }
+ if(!strcmp(attr_iter->key, ATTR_TYPE)) {
+ type = attr_iter->val;
+ }
+ attr_iter = Q_Next(&el->attrs);
+ }
+
+ if(id) {
+ XMLRPC_SetValueID_Case(xCurrent, id, 0, xmlrpc_case_exact);
+ }
+
+ if(!strcmp(el->name, ATTR_SCALAR)) {
+ if(!type || !strcmp(type, ATTR_STRING)) {
+ XMLRPC_SetValueString(xCurrent, el->text.str, el->text.len);
+ }
+ else if(!strcmp(type, ATTR_INT)) {
+ XMLRPC_SetValueInt(xCurrent, atoi(el->text.str));
+ }
+ else if(!strcmp(type, ATTR_BOOLEAN)) {
+ XMLRPC_SetValueBoolean(xCurrent, atoi(el->text.str));
+ }
+ else if(!strcmp(type, ATTR_DOUBLE)) {
+ XMLRPC_SetValueDouble(xCurrent, atof(el->text.str));
+ }
+ else if(!strcmp(type, ATTR_DATETIME)) {
+ XMLRPC_SetValueDateTime_ISO8601(xCurrent, el->text.str);
+ }
+ else if(!strcmp(type, ATTR_BASE64)) {
+ struct buffer_st buf;
+ base64_decode_xmlrpc(&buf, el->text.str, el->text.len);
+ XMLRPC_SetValueBase64(xCurrent, buf.data, buf.offset);
+ buffer_delete(&buf);
+ }
+ }
+ else if(!strcmp(el->name, ATTR_VECTOR)) {
+ xml_element* iter = (xml_element*)Q_Head(&el->children);
+
+ if(!type || !strcmp(type, ATTR_MIXED)) {
+ XMLRPC_SetIsVector(xCurrent, xmlrpc_vector_mixed);
+ }
+ else if(!strcmp(type, ATTR_ARRAY)) {
+ XMLRPC_SetIsVector(xCurrent, xmlrpc_vector_array);
+ }
+ else if(!strcmp(type, ATTR_STRUCT)) {
+ XMLRPC_SetIsVector(xCurrent, xmlrpc_vector_struct);
+ }
+ while( iter ) {
+ XMLRPC_VALUE xNext = XMLRPC_CreateValueEmpty();
+ xml_element_to_DANDARPC_REQUEST_worker(request, xNext, iter);
+ XMLRPC_AddValueToVector(xCurrent, xNext);
+ iter = (xml_element*)Q_Next(&el->children);
+ }
+ }
+ else {
+ xml_element* iter = (xml_element*)Q_Head(&el->children);
+ while( iter ) {
+ xml_element_to_DANDARPC_REQUEST_worker(request, xCurrent, iter);
+ iter = (xml_element*)Q_Next(&el->children);
+ }
+
+ if(!strcmp(el->name, ELEM_METHODCALL)) {
+ if(request) {
+ XMLRPC_RequestSetRequestType(request, xmlrpc_request_call);
+ }
+ }
+ else if(!strcmp(el->name, ELEM_METHODRESPONSE)) {
+ if(request) {
+ XMLRPC_RequestSetRequestType(request, xmlrpc_request_response);
+ }
+ }
+ else if(!strcmp(el->name, ELEM_METHODNAME)) {
+ if(request) {
+ XMLRPC_RequestSetMethodName(request, el->text.str);
+ }
+ }
+ }
+ }
+ return xCurrent;
+}
+
+XMLRPC_VALUE xml_element_to_DANDARPC_VALUE(xml_element* el)
+{
+ return xml_element_to_DANDARPC_REQUEST_worker(NULL, NULL, el);
+}
+
+XMLRPC_VALUE xml_element_to_DANDARPC_REQUEST(XMLRPC_REQUEST request, xml_element* el)
+{
+ if(request) {
+ return XMLRPC_RequestSetData(request, xml_element_to_DANDARPC_REQUEST_worker(request, NULL, el));
+ }
+ return NULL;
+}
+
+xml_element* DANDARPC_to_xml_element_worker(XMLRPC_REQUEST request, XMLRPC_VALUE node) {
+#define BUF_SIZE 512
+ xml_element* root = NULL;
+ if(node) {
+ char buf[BUF_SIZE];
+ const char* id = XMLRPC_GetValueID(node);
+ XMLRPC_VALUE_TYPE type = XMLRPC_GetValueType(node);
+ XMLRPC_REQUEST_OUTPUT_OPTIONS output = XMLRPC_RequestGetOutputOptions(request);
+ int bNoAddType = (type == xmlrpc_string && request && output && output->xml_elem_opts.verbosity == xml_elem_no_white_space);
+ xml_element* elem_val = xml_elem_new();
+ const char* pAttrType = NULL;
+
+ xml_element_attr* attr_type = bNoAddType ? NULL : malloc(sizeof(xml_element_attr));
+
+ if(attr_type) {
+ attr_type->key = strdup(ATTR_TYPE);
+ attr_type->val = 0;
+ Q_PushTail(&elem_val->attrs, attr_type);
+ }
+
+ elem_val->name = (type == xmlrpc_vector) ? strdup(ATTR_VECTOR) : strdup(ATTR_SCALAR);
+
+ if(id && *id) {
+ xml_element_attr* attr_id = malloc(sizeof(xml_element_attr));
+ if(attr_id) {
+ attr_id->key = strdup(ATTR_ID);
+ attr_id->val = strdup(id);
+ Q_PushTail(&elem_val->attrs, attr_id);
+ }
+ }
+
+ switch(type) {
+ case xmlrpc_string:
+ pAttrType = ATTR_STRING;
+ simplestring_addn(&elem_val->text, XMLRPC_GetValueString(node), XMLRPC_GetValueStringLen(node));
+ break;
+ case xmlrpc_int:
+ pAttrType = ATTR_INT;
+ snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueInt(node));
+ simplestring_add(&elem_val->text, buf);
+ break;
+ case xmlrpc_boolean:
+ pAttrType = ATTR_BOOLEAN;
+ snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueBoolean(node));
+ simplestring_add(&elem_val->text, buf);
+ break;
+ case xmlrpc_double:
+ pAttrType = ATTR_DOUBLE;
+ snprintf(buf, BUF_SIZE, "%f", XMLRPC_GetValueDouble(node));
+ simplestring_add(&elem_val->text, buf);
+ break;
+ case xmlrpc_datetime:
+ pAttrType = ATTR_DATETIME;
+ simplestring_add(&elem_val->text, XMLRPC_GetValueDateTime_ISO8601(node));
+ break;
+ case xmlrpc_base64:
+ {
+ struct buffer_st buf;
+ pAttrType = ATTR_BASE64;
+ base64_encode_xmlrpc(&buf, XMLRPC_GetValueBase64(node), XMLRPC_GetValueStringLen(node));
+ simplestring_addn(&elem_val->text, buf.data, buf.offset );
+ buffer_delete(&buf);
+ }
+ break;
+ case xmlrpc_vector:
+ {
+ XMLRPC_VECTOR_TYPE my_type = XMLRPC_GetVectorType(node);
+ XMLRPC_VALUE xIter = XMLRPC_VectorRewind(node);
+
+ switch(my_type) {
+ case xmlrpc_vector_array:
+ pAttrType = ATTR_ARRAY;
+ break;
+ case xmlrpc_vector_mixed:
+ pAttrType = ATTR_MIXED;
+ break;
+ case xmlrpc_vector_struct:
+ pAttrType = ATTR_STRUCT;
+ break;
+ default:
+ break;
+ }
+
+ /* recurse through sub-elements */
+ while( xIter ) {
+ xml_element* next_el = DANDARPC_to_xml_element_worker(request, xIter);
+ if(next_el) {
+ Q_PushTail(&elem_val->children, next_el);
+ }
+ xIter = XMLRPC_VectorNext(node);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ if(pAttrType && attr_type && !bNoAddType) {
+ attr_type->val = strdup(pAttrType);
+ }
+ root = elem_val;
+ }
+ return root;
+}
+
+xml_element* DANDARPC_VALUE_to_xml_element(XMLRPC_VALUE node) {
+ return DANDARPC_to_xml_element_worker(NULL, node);
+}
+
+xml_element* DANDARPC_REQUEST_to_xml_element(XMLRPC_REQUEST request) {
+ xml_element* wrapper = NULL;
+ xml_element* root = NULL;
+ if(request) {
+ XMLRPC_REQUEST_TYPE request_type = XMLRPC_RequestGetRequestType(request);
+ const char* pStr = NULL;
+ xml_element_attr* version = malloc(sizeof(xml_element_attr));
+ version->key = strdup(ATTR_VERSION);
+ version->val = strdup(VAL_VERSION_0_9);
+
+ wrapper = xml_elem_new();
+
+ if(request_type == xmlrpc_request_response) {
+ pStr = ELEM_METHODRESPONSE;
+ }
+ else if(request_type == xmlrpc_request_call) {
+ pStr = ELEM_METHODCALL;
+ }
+ if(pStr) {
+ wrapper->name = strdup(pStr);
+ }
+
+ root = xml_elem_new();
+ root->name = strdup(ELEM_ROOT);
+ Q_PushTail(&root->attrs, version);
+ Q_PushTail(&root->children, wrapper);
+
+ pStr = XMLRPC_RequestGetMethodName(request);
+
+ if(pStr) {
+ xml_element* method = xml_elem_new();
+ method->name = strdup(ELEM_METHODNAME);
+ simplestring_add(&method->text, pStr);
+ Q_PushTail(&wrapper->children, method);
+ }
+ Q_PushTail(&wrapper->children,
+ DANDARPC_to_xml_element_worker(request, XMLRPC_RequestGetData(request)));
+ }
+ return root;
+}
+
diff --git a/ext/xmlrpc/libxmlrpc/xml_to_dandarpc.h b/ext/xmlrpc/libxmlrpc/xml_to_dandarpc.h
new file mode 100644
index 0000000..6facb55
--- /dev/null
+++ b/ext/xmlrpc/libxmlrpc/xml_to_dandarpc.h
@@ -0,0 +1,44 @@
+/*
+ This file is part of libXMLRPC - a C library for xml-encoded function calls.
+
+ Author: Dan Libby (dan@libby.com)
+ Epinions.com may be contacted at feedback@epinions-inc.com
+*/
+
+/*
+ Copyright 2000 Epinions, Inc.
+
+ Subject to the following 3 conditions, Epinions, Inc. permits you, free
+ of charge, to (a) use, copy, distribute, modify, perform and display this
+ software and associated documentation files (the "Software"), and (b)
+ permit others to whom the Software is furnished to do so as well.
+
+ 1) The above copyright notice and this permission notice shall be included
+ without modification in all copies or substantial portions of the
+ Software.
+
+ 2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF
+ ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY
+ IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ PURPOSE OR NONINFRINGEMENT.
+
+ 3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
+ OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING
+ NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH
+ DAMAGES.
+
+*/
+
+#ifndef XML_TO_DANDARPC_H
+ #define XML_TO_DANDARPC_H
+
+#include "time.h"
+#include "xmlrpc.h"
+
+XMLRPC_VALUE xml_element_to_DANDARPC_VALUE(xml_element* el);
+XMLRPC_VALUE xml_element_to_DANDARPC_REQUEST(XMLRPC_REQUEST request, xml_element* el);
+xml_element* DANDARPC_VALUE_to_xml_element(XMLRPC_VALUE node);
+xml_element* DANDARPC_REQUEST_to_xml_element(XMLRPC_REQUEST request);
+
+#endif /* XML_TO_DANDARPC_H */
diff --git a/ext/xmlrpc/libxmlrpc/xml_to_soap.c b/ext/xmlrpc/libxmlrpc/xml_to_soap.c
new file mode 100644
index 0000000..664e8b7
--- /dev/null
+++ b/ext/xmlrpc/libxmlrpc/xml_to_soap.c
@@ -0,0 +1,670 @@
+/*
+ This file is part of libXMLRPC - a C library for xml-encoded function calls.
+
+ Author: Dan Libby (dan@libby.com)
+*/
+
+
+/*-**********************************************************************
+* TODO: *
+* - [SOAP-ENC:position] read sparse arrays (and write?) *
+* - [SOAP-ENC:offset] read partially transmitted arrays (and write?) *
+* - read "flattened" multi-dimensional arrays. (don't bother writing) *
+* *
+* BUGS: *
+* - does not read schema. thus only knows soap pre-defined types. *
+* - references (probably) do not work. untested. *
+* - does not expose SOAP-ENV:Header to application at all. *
+* - does not use namespaces correctly, thus: *
+* - namespaces are hard-coded in comparison tokens *
+* - if a sender uses another namespace identifer, it will break *
+************************************************************************/
+
+
+static const char rcsid[] = "#(@) $Id:";
+
+#ifdef _WIN32
+#include "xmlrpc_win32.h"
+#endif
+#include <string.h>
+#include <stdlib.h>
+#include "xml_to_soap.h"
+#include "base64.h"
+
+/* list of tokens used in vocab */
+#define TOKEN_ANY "xsd:ur-type"
+#define TOKEN_ARRAY "SOAP-ENC:Array"
+#define TOKEN_ARRAY_TYPE "SOAP-ENC:arrayType"
+#define TOKEN_BASE64 "SOAP-ENC:base64"
+#define TOKEN_BOOLEAN "xsd:boolean"
+#define TOKEN_DATETIME "xsd:timeInstant"
+#define TOKEN_DOUBLE "xsd:double"
+#define TOKEN_FLOAT "xsd:float"
+#define TOKEN_ID "id"
+#define TOKEN_INT "xsd:int"
+#define TOKEN_NULL "xsi:null"
+#define TOKEN_STRING "xsd:string"
+#define TOKEN_STRUCT "xsd:struct"
+#define TOKEN_TYPE "xsi:type"
+#define TOKEN_FAULT "SOAP-ENV:Fault"
+#define TOKEN_MUSTUNDERSTAND "SOAP-ENV:mustUnderstand"
+#define TOKEN_ACTOR "SOAP-ENV:actor"
+#define TOKEN_ACTOR_NEXT "http://schemas.xmlsoap.org/soap/actor/next"
+
+#define TOKEN_XMLRPC_FAULTCODE "faultCode"
+#define TOKEN_XMLRPC_FAULTSTRING "faultString"
+#define TOKEN_SOAP_FAULTCODE "faultcode"
+#define TOKEN_SOAP_FAULTSTRING "faultstring"
+#define TOKEN_SOAP_FAULTDETAILS "details"
+#define TOKEN_SOAP_FAULTACTOR "actor"
+
+
+/* determine if a string represents a soap type, as used in element names */
+static inline int is_soap_type(const char* soap_type) {
+ return(strstr(soap_type, "SOAP-ENC:") || strstr(soap_type, "xsd:")) ? 1 : 0;
+}
+
+/* utility func to generate a new attribute. possibly should be in xml_element.c?? */
+static xml_element_attr* new_attr(const char* key, const char* val) {
+ xml_element_attr* attr = malloc(sizeof(xml_element_attr));
+ if (attr) {
+ attr->key = key ? strdup(key) : NULL;
+ attr->val = val ? strdup(val) : NULL;
+ }
+ return attr;
+}
+
+struct array_info {
+ char kids_type[128];
+ unsigned long size;
+ /* ... ? */
+};
+
+
+/* parses soap arrayType attribute to generate an array_info structure.
+ * TODO: should deal with sparse, flattened, & multi-dimensional arrays
+ */
+static struct array_info* parse_array_type_info(const char* array_type) {
+ struct array_info* ai = NULL;
+ if (array_type) {
+ ai = (struct array_info*)calloc(1, sizeof(struct array_info));
+ if (ai) {
+ char buf[128], *p;
+ snprintf(buf, sizeof(buf), "%s", array_type);
+ p = strchr(buf, '[');
+ if (p) {
+ *p = 0;
+ }
+ strcpy(ai->kids_type, buf);
+ }
+ }
+ return ai;
+}
+
+/* performs heuristics on an xmlrpc_vector_array to determine
+ * appropriate soap arrayType string.
+ */
+static const char* get_array_soap_type(XMLRPC_VALUE node) {
+ XMLRPC_VALUE_TYPE_EASY type = xmlrpc_type_none;
+
+ XMLRPC_VALUE xIter = XMLRPC_VectorRewind(node);
+ int loopCount = 0;
+ const char* soapType = TOKEN_ANY;
+
+ type = XMLRPC_GetValueTypeEasy(xIter);
+ xIter = XMLRPC_VectorNext(node);
+
+ while (xIter) {
+ /* 50 seems like a decent # of loops. That will likely
+ * cover most cases. Any more and we start to sacrifice
+ * performance.
+ */
+ if ( (XMLRPC_GetValueTypeEasy(xIter) != type) || loopCount >= 50) {
+ type = xmlrpc_type_none;
+ break;
+ }
+ loopCount ++;
+
+ xIter = XMLRPC_VectorNext(node);
+ }
+ switch (type) {
+ case xmlrpc_type_none:
+ soapType = TOKEN_ANY;
+ break;
+ case xmlrpc_type_empty:
+ soapType = TOKEN_NULL;
+ break;
+ case xmlrpc_type_int:
+ soapType = TOKEN_INT;
+ break;
+ case xmlrpc_type_double:
+ soapType = TOKEN_DOUBLE;
+ break;
+ case xmlrpc_type_boolean:
+ soapType = TOKEN_BOOLEAN;
+ break;
+ case xmlrpc_type_string:
+ soapType = TOKEN_STRING;
+ break;
+ case xmlrpc_type_base64:
+ soapType = TOKEN_BASE64;
+ break;
+ case xmlrpc_type_datetime:
+ soapType = TOKEN_DATETIME;
+ break;
+ case xmlrpc_type_struct:
+ soapType = TOKEN_STRUCT;
+ break;
+ case xmlrpc_type_array:
+ soapType = TOKEN_ARRAY;
+ break;
+ case xmlrpc_type_mixed:
+ soapType = TOKEN_STRUCT;
+ break;
+ }
+ return soapType;
+}
+
+/* determines whether a node is a fault or not, and of which type:
+ * 0 = not a fault,
+ * 1 = xmlrpc style fault
+ * 2 = soap style fault.
+ */
+static inline int get_fault_type(XMLRPC_VALUE node) {
+ if (XMLRPC_VectorGetValueWithID(node, TOKEN_XMLRPC_FAULTCODE) &&
+ XMLRPC_VectorGetValueWithID(node, TOKEN_XMLRPC_FAULTSTRING)) {
+ return 1;
+ }
+ else if (XMLRPC_VectorGetValueWithID(node, TOKEN_SOAP_FAULTCODE) &&
+ XMLRPC_VectorGetValueWithID(node, TOKEN_SOAP_FAULTSTRING)) {
+ return 2;
+ }
+ return 0;
+}
+
+/* input: an XMLRPC_VALUE representing a fault struct in xml-rpc style.
+ * output: an XMLRPC_VALUE representing a fault struct in soap style,
+ * with xmlrpc codes mapped to soap codes, and all other values preserved.
+ * note that the returned value is a completely new value, and must be freed.
+ * the input value is untouched.
+ */
+static XMLRPC_VALUE gen_fault_xmlrpc(XMLRPC_VALUE node, xml_element* el_target) {
+ XMLRPC_VALUE xDup = XMLRPC_DupValueNew(node);
+ XMLRPC_VALUE xCode = XMLRPC_VectorGetValueWithID(xDup, TOKEN_XMLRPC_FAULTCODE);
+ XMLRPC_VALUE xStr = XMLRPC_VectorGetValueWithID(xDup, TOKEN_XMLRPC_FAULTSTRING);
+
+ XMLRPC_SetValueID(xCode, TOKEN_SOAP_FAULTCODE, 0);
+ XMLRPC_SetValueID(xStr, TOKEN_SOAP_FAULTSTRING, 0);
+
+ /* rough mapping of xmlrpc fault codes to soap codes */
+ switch (XMLRPC_GetValueInt(xCode)) {
+ case -32700: /* "parse error. not well formed", */
+ case -32701: /* "parse error. unsupported encoding" */
+ case -32702: /* "parse error. invalid character for encoding" */
+ case -32600: /* "server error. invalid xml-rpc. not conforming to spec." */
+ case -32601: /* "server error. requested method not found" */
+ case -32602: /* "server error. invalid method parameters" */
+ XMLRPC_SetValueString(xCode, "SOAP-ENV:Client", 0);
+ break;
+ case -32603: /* "server error. internal xml-rpc error" */
+ case -32500: /* "application error" */
+ case -32400: /* "system error" */
+ case -32300: /* "transport error */
+ XMLRPC_SetValueString(xCode, "SOAP-ENV:Server", 0);
+ break;
+ }
+ return xDup;
+}
+
+/* returns a new XMLRPC_VALUE representing a soap fault, comprised of a struct with four keys. */
+static XMLRPC_VALUE gen_soap_fault(const char* fault_code, const char* fault_string,
+ const char* actor, const char* details) {
+ XMLRPC_VALUE xReturn = XMLRPC_CreateVector(TOKEN_FAULT, xmlrpc_vector_struct);
+ XMLRPC_AddValuesToVector(xReturn,
+ XMLRPC_CreateValueString(TOKEN_SOAP_FAULTCODE, fault_code, 0),
+ XMLRPC_CreateValueString(TOKEN_SOAP_FAULTSTRING, fault_string, 0),
+ XMLRPC_CreateValueString(TOKEN_SOAP_FAULTACTOR, actor, 0),
+ XMLRPC_CreateValueString(TOKEN_SOAP_FAULTDETAILS, details, 0),
+ NULL);
+ return xReturn;
+}
+
+/* translates xml soap dom to native data structures. recursive. */
+XMLRPC_VALUE xml_element_to_SOAP_REQUEST_worker(XMLRPC_REQUEST request,
+ XMLRPC_VALUE xParent,
+ struct array_info* parent_array,
+ XMLRPC_VALUE xCurrent,
+ xml_element* el,
+ int depth) {
+ XMLRPC_REQUEST_TYPE rtype = xmlrpc_request_none;
+
+ /* no current element on first call */
+ if (!xCurrent) {
+ xCurrent = XMLRPC_CreateValueEmpty();
+ }
+
+ /* increment recursion depth guage */
+ depth ++;
+
+ /* safety first. must have a valid element */
+ if (el && el->name) {
+ const char* id = NULL;
+ const char* type = NULL, *arrayType=NULL, *actor = NULL;
+ xml_element_attr* attr_iter = Q_Head(&el->attrs);
+ int b_must_understand = 0;
+
+ /* in soap, types may be specified in either element name -or- with xsi:type attribute. */
+ if (is_soap_type(el->name)) {
+ type = el->name;
+ }
+ /* if our parent node, by definition a vector, is not an array, then
+ our element name must be our key identifier. */
+ else if (XMLRPC_GetVectorType(xParent) != xmlrpc_vector_array) {
+ id = el->name;
+ if(!strcmp(id, "item")) {
+ }
+ }
+
+ /* iterate through element attributes, pick out useful stuff. */
+ while (attr_iter) {
+ /* element's type */
+ if (!strcmp(attr_iter->key, TOKEN_TYPE)) {
+ type = attr_iter->val;
+ }
+ /* array type */
+ else if (!strcmp(attr_iter->key, TOKEN_ARRAY_TYPE)) {
+ arrayType = attr_iter->val;
+ }
+ /* must understand, sometimes present in headers. */
+ else if (!strcmp(attr_iter->key, TOKEN_MUSTUNDERSTAND)) {
+ b_must_understand = strchr(attr_iter->val, '1') ? 1 : 0;
+ }
+ /* actor, used in conjuction with must understand. */
+ else if (!strcmp(attr_iter->key, TOKEN_ACTOR)) {
+ actor = attr_iter->val;
+ }
+ attr_iter = Q_Next(&el->attrs);
+ }
+
+ /* check if caller says we must understand something in a header. */
+ if (b_must_understand) {
+ /* is must understand actually indended for us?
+ BUG: spec says we should also determine if actor is our URL, but
+ we do not have that information. */
+ if (!actor || !strcmp(actor, TOKEN_ACTOR_NEXT)) {
+ /* TODO: implement callbacks or other mechanism for applications
+ to "understand" these headers. For now, we just bail if we
+ get a mustUnderstand header intended for us. */
+ XMLRPC_RequestSetError(request,
+ gen_soap_fault("SOAP-ENV:MustUnderstand",
+ "SOAP Must Understand Error",
+ "", ""));
+ return xCurrent;
+ }
+ }
+
+ /* set id (key) if one was found. */
+ if (id) {
+ XMLRPC_SetValueID_Case(xCurrent, id, 0, xmlrpc_case_exact);
+ }
+
+ /* according to soap spec,
+ depth 1 = Envelope, 2 = Header, Body & Fault, 3 = methodcall or response. */
+ if (depth == 3) {
+ const char* methodname = el->name;
+ char* p = NULL;
+
+ /* BUG: we determine request or response type using presence of "Response" in element name.
+ According to spec, this is only recommended, not required. Apparently, implementations
+ are supposed to know the type of action based on state, which strikes me as a bit lame.
+ Anyway, we don't have that state info, thus we use Response as a heuristic. */
+ rtype =
+#ifdef strcasestr
+ strcasestr(el->name, "response") ? xmlrpc_request_response : xmlrpc_request_call;
+#else
+ strstr(el->name, "esponse") ? xmlrpc_request_response : xmlrpc_request_call;
+#endif
+ XMLRPC_RequestSetRequestType(request, rtype);
+
+ /* Get methodname. strip xml namespace crap. */
+ p = strchr(el->name, ':');
+ if (p) {
+ methodname = p + 1;
+ }
+ if (rtype == xmlrpc_request_call) {
+ XMLRPC_RequestSetMethodName(request, methodname);
+ }
+ }
+
+
+ /* Next, we begin to convert actual values. if no children, then must be a scalar value. */
+ if (!Q_Size(&el->children)) {
+ if (!type && parent_array && parent_array->kids_type[0]) {
+ type = parent_array->kids_type;
+ }
+ if (!type || !strcmp(type, TOKEN_STRING)) {
+ XMLRPC_SetValueString(xCurrent, el->text.str, el->text.len);
+ }
+ else if (!strcmp(type, TOKEN_INT)) {
+ XMLRPC_SetValueInt(xCurrent, atoi(el->text.str));
+ }
+ else if (!strcmp(type, TOKEN_BOOLEAN)) {
+ XMLRPC_SetValueBoolean(xCurrent, atoi(el->text.str));
+ }
+ else if (!strcmp(type, TOKEN_DOUBLE) ||
+ !strcmp(type, TOKEN_FLOAT)) {
+ XMLRPC_SetValueDouble(xCurrent, atof(el->text.str));
+ }
+ else if (!strcmp(type, TOKEN_NULL)) {
+ /* already an empty val. do nothing. */
+ }
+ else if (!strcmp(type, TOKEN_DATETIME)) {
+ XMLRPC_SetValueDateTime_ISO8601(xCurrent, el->text.str);
+ }
+ else if (!strcmp(type, TOKEN_BASE64)) {
+ struct buffer_st buf;
+ base64_decode_xmlrpc(&buf, el->text.str, el->text.len);
+ XMLRPC_SetValueBase64(xCurrent, buf.data, buf.offset);
+ buffer_delete(&buf);
+ }
+ }
+ /* Element has children, thus a vector, or "compound type" in soap-speak. */
+ else {
+ struct array_info* ai = NULL;
+ xml_element* iter = (xml_element*)Q_Head(&el->children);
+
+ if (!type || !strcmp(type, TOKEN_STRUCT)) {
+ XMLRPC_SetIsVector(xCurrent, xmlrpc_vector_struct);
+ }
+ else if (!strcmp(type, TOKEN_ARRAY) || arrayType != NULL) {
+ /* determine magic associated with soap array type.
+ this is passed down as we recurse, so our children have access to the info. */
+ ai = parse_array_type_info(arrayType); /* alloc'ed ai free'd below. */
+ XMLRPC_SetIsVector(xCurrent, xmlrpc_vector_array);
+ }
+ else {
+ /* mixed is probably closest thing we have to compound type. */
+ XMLRPC_SetIsVector(xCurrent, xmlrpc_vector_mixed);
+ }
+ /* Recurse, adding values as we go. Check for error during recursion
+ and if found, bail. this short-circuits us out of the recursion. */
+ while ( iter && !XMLRPC_RequestGetError(request) ) {
+ XMLRPC_VALUE xNext = NULL;
+ /* top level elements don't actually represent values, so we just pass the
+ current value along until we are deep enough. */
+ if ( depth <= 2 ||
+ (rtype == xmlrpc_request_response && depth <= 3) ) {
+ xml_element_to_SOAP_REQUEST_worker(request, NULL, ai, xCurrent, iter, depth);
+ }
+ /* ready to do some actual de-serialization. create a new empty value and
+ pass that along to be init'd, then add it to our current vector. */
+ else {
+ xNext = XMLRPC_CreateValueEmpty();
+ xml_element_to_SOAP_REQUEST_worker(request, xCurrent, ai, xNext, iter, depth);
+ XMLRPC_AddValueToVector(xCurrent, xNext);
+ }
+ iter = (xml_element*)Q_Next(&el->children);
+ }
+ /* cleanup */
+ if (ai) {
+ free(ai);
+ }
+ }
+ }
+ return xCurrent;
+}
+
+/* Convert soap xml dom to XMLRPC_VALUE, sans request info. untested. */
+XMLRPC_VALUE xml_element_to_SOAP_VALUE(xml_element* el)
+{
+ return xml_element_to_SOAP_REQUEST_worker(NULL, NULL, NULL, NULL, el, 0);
+}
+
+/* Convert soap xml dom to XMLRPC_REQUEST */
+XMLRPC_VALUE xml_element_to_SOAP_REQUEST(XMLRPC_REQUEST request, xml_element* el)
+{
+ if (request) {
+ return XMLRPC_RequestSetData(request, xml_element_to_SOAP_REQUEST_worker(request, NULL, NULL, NULL, el, 0));
+ }
+ return NULL;
+}
+
+
+/* translates data structures to soap/xml. recursive */
+xml_element* SOAP_to_xml_element_worker(XMLRPC_REQUEST request, XMLRPC_VALUE node) {
+#define BUF_SIZE 128
+ xml_element* elem_val = NULL;
+ if (node) {
+ int bFreeNode = 0; /* sometimes we may need to free 'node' variable */
+ char buf[BUF_SIZE];
+ XMLRPC_VALUE_TYPE_EASY type = XMLRPC_GetValueTypeEasy(node);
+ char* pName = NULL, *pAttrType = NULL;
+
+ /* create our return value element */
+ elem_val = xml_elem_new();
+
+ switch (type) {
+ case xmlrpc_type_struct:
+ case xmlrpc_type_mixed:
+ case xmlrpc_type_array:
+ if (type == xmlrpc_type_array) {
+ /* array's are _very_ special in soap.
+ TODO: Should handle sparse/partial arrays here. */
+
+ /* determine soap array type. */
+ const char* type = get_array_soap_type(node);
+ xml_element_attr* attr_array_type = NULL;
+
+ /* specify array kids type and array size. */
+ snprintf(buf, sizeof(buf), "%s[%i]", type, XMLRPC_VectorSize(node));
+ attr_array_type = new_attr(TOKEN_ARRAY_TYPE, buf);
+
+ Q_PushTail(&elem_val->attrs, attr_array_type);
+
+ pAttrType = TOKEN_ARRAY;
+ }
+ /* check for fault, which is a rather special case.
+ (can't these people design anything consistent/simple/elegant?) */
+ else if (type == xmlrpc_type_struct) {
+ int fault_type = get_fault_type(node);
+ if (fault_type) {
+ if (fault_type == 1) {
+ /* gen fault from xmlrpc style fault codes
+ notice that we get a new node, which must be freed herein. */
+ node = gen_fault_xmlrpc(node, elem_val);
+ bFreeNode = 1;
+ }
+ pName = TOKEN_FAULT;
+ }
+ }
+
+ {
+ /* recurse through sub-elements */
+ XMLRPC_VALUE xIter = XMLRPC_VectorRewind(node);
+ while ( xIter ) {
+ xml_element* next_el = SOAP_to_xml_element_worker(request, xIter);
+ if (next_el) {
+ Q_PushTail(&elem_val->children, next_el);
+ }
+ xIter = XMLRPC_VectorNext(node);
+ }
+ }
+
+ break;
+
+ /* handle scalar types */
+ case xmlrpc_type_empty:
+ pAttrType = TOKEN_NULL;
+ break;
+ case xmlrpc_type_string:
+ pAttrType = TOKEN_STRING;
+ simplestring_addn(&elem_val->text, XMLRPC_GetValueString(node), XMLRPC_GetValueStringLen(node));
+ break;
+ case xmlrpc_type_int:
+ pAttrType = TOKEN_INT;
+ snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueInt(node));
+ simplestring_add(&elem_val->text, buf);
+ break;
+ case xmlrpc_type_boolean:
+ pAttrType = TOKEN_BOOLEAN;
+ snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueBoolean(node));
+ simplestring_add(&elem_val->text, buf);
+ break;
+ case xmlrpc_type_double:
+ pAttrType = TOKEN_DOUBLE;
+ snprintf(buf, BUF_SIZE, "%f", XMLRPC_GetValueDouble(node));
+ simplestring_add(&elem_val->text, buf);
+ break;
+ case xmlrpc_type_datetime:
+ {
+ time_t tt = XMLRPC_GetValueDateTime(node);
+ struct tm *tm = localtime (&tt);
+ pAttrType = TOKEN_DATETIME;
+ if(strftime (buf, BUF_SIZE, "%Y-%m-%dT%H:%M:%SZ", tm)) {
+ simplestring_add(&elem_val->text, buf);
+ }
+ }
+ break;
+ case xmlrpc_type_base64:
+ {
+ struct buffer_st buf;
+ pAttrType = TOKEN_BASE64;
+ base64_encode_xmlrpc(&buf, XMLRPC_GetValueBase64(node), XMLRPC_GetValueStringLen(node));
+ simplestring_addn(&elem_val->text, buf.data, buf.offset );
+ buffer_delete(&buf);
+ }
+ break;
+ break;
+ default:
+ break;
+ }
+
+ /* determining element's name is a bit tricky, due to soap semantics. */
+ if (!pName) {
+ /* if the value's type is known... */
+ if (pAttrType) {
+ /* see if it has an id (key). If so, use that as name, and type as an attribute. */
+ pName = (char*)XMLRPC_GetValueID(node);
+ if (pName) {
+ Q_PushTail(&elem_val->attrs, new_attr(TOKEN_TYPE, pAttrType));
+ }
+
+ /* otherwise, use the type as the name. */
+ else {
+ pName = pAttrType;
+ }
+ }
+ /* if the value's type is not known... (a rare case?) */
+ else {
+ /* see if it has an id (key). otherwise, default to generic "item" */
+ pName = (char*)XMLRPC_GetValueID(node);
+ if (!pName) {
+ pName = "item";
+ }
+ }
+ }
+ elem_val->name = strdup(pName);
+
+ /* cleanup */
+ if (bFreeNode) {
+ XMLRPC_CleanupValue(node);
+ }
+ }
+ return elem_val;
+}
+
+/* convert XMLRPC_VALUE to soap xml dom. untested. */
+xml_element* SOAP_VALUE_to_xml_element(XMLRPC_VALUE node) {
+ return SOAP_to_xml_element_worker(NULL, node);
+}
+
+/* convert XMLRPC_REQUEST to soap xml dom. */
+xml_element* SOAP_REQUEST_to_xml_element(XMLRPC_REQUEST request) {
+ xml_element* root = xml_elem_new();
+
+ /* safety first. */
+ if (root) {
+ xml_element* body = xml_elem_new();
+ root->name = strdup("SOAP-ENV:Envelope");
+
+ /* silly namespace stuff */
+ Q_PushTail(&root->attrs, new_attr("xmlns:SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/"));
+ Q_PushTail(&root->attrs, new_attr("xmlns:xsi", "http://www.w3.org/1999/XMLSchema-instance"));
+ Q_PushTail(&root->attrs, new_attr("xmlns:xsd", "http://www.w3.org/1999/XMLSchema"));
+ Q_PushTail(&root->attrs, new_attr("xmlns:SOAP-ENC", "http://schemas.xmlsoap.org/soap/encoding/"));
+ Q_PushTail(&root->attrs, new_attr("xmlns:si", "http://soapinterop.org/xsd"));
+ Q_PushTail(&root->attrs, new_attr("xmlns:ns6", "http://testuri.org"));
+ Q_PushTail(&root->attrs, new_attr("SOAP-ENV:encodingStyle", "http://schemas.xmlsoap.org/soap/encoding/"));
+
+ /* Q_PushHead(&root->attrs, new_attr("xmlns:ks", "http://kitchen.sink.org/soap/everything/under/sun"));
+ JUST KIDDING!! :-) ----> ------------------------------------------------- */
+
+ if (body) {
+ /* go ahead and serialize first... */
+ xml_element* el_serialized =
+ SOAP_to_xml_element_worker(request,
+ XMLRPC_RequestGetData(request));
+
+ /* check for fault, in which case, there is no intermediate element */
+ if (el_serialized && !strcmp(el_serialized->name, TOKEN_FAULT)) {
+ Q_PushTail(&body->children, el_serialized);
+ }
+ /* usual case: not a fault. Add Response element in between. */
+ else {
+ xml_element* rpc = xml_elem_new();
+
+ if (rpc) {
+ const char* methodname = XMLRPC_RequestGetMethodName(request);
+ XMLRPC_REQUEST_TYPE rtype = XMLRPC_RequestGetRequestType(request);
+
+ /* if we are making a request, we want to use the methodname as is. */
+ if (rtype == xmlrpc_request_call) {
+ if (methodname) {
+ rpc->name = strdup(methodname);
+ }
+ }
+ /* if it's a response, we append "Response". Also, given xmlrpc-epi
+ API/architecture, it's likely that we don't have a methodname for
+ the response, so we have to check that. */
+ else {
+ char buf[128];
+ snprintf(buf, sizeof(buf), "%s%s",
+ methodname ? methodname : "",
+ "Response");
+
+ rpc->name = strdup(buf);
+ }
+
+ /* add serialized data to method call/response.
+ add method call/response to body element */
+ if (rpc->name) {
+ if(el_serialized) {
+ if(Q_Size(&el_serialized->children) && rtype == xmlrpc_request_call) {
+ xml_element* iter = (xml_element*)Q_Head(&el_serialized->children);
+ while(iter) {
+ Q_PushTail(&rpc->children, iter);
+ iter = (xml_element*)Q_Next(&el_serialized->children);
+ }
+ xml_elem_free_non_recurse(el_serialized);
+ }
+ else {
+ Q_PushTail(&rpc->children, el_serialized);
+ }
+ }
+
+ Q_PushTail(&body->children, rpc);
+ }
+ else {
+ /* no method name?!
+ TODO: fault here...? */
+ }
+ }
+ }
+ body->name = strdup("SOAP-ENV:Body");
+ Q_PushTail(&root->children, body);
+ }
+ }
+
+ return root;
+}
+
diff --git a/ext/xmlrpc/libxmlrpc/xml_to_soap.h b/ext/xmlrpc/libxmlrpc/xml_to_soap.h
new file mode 100644
index 0000000..9ae9308
--- /dev/null
+++ b/ext/xmlrpc/libxmlrpc/xml_to_soap.h
@@ -0,0 +1,44 @@
+/*
+ This file is part of libXMLRPC - a C library for xml-encoded function calls.
+
+ Author: Dan Libby (dan@libby.com)
+ Epinions.com may be contacted at feedback@epinions-inc.com
+*/
+
+/*
+ Copyright 2000 Epinions, Inc.
+
+ Subject to the following 3 conditions, Epinions, Inc. permits you, free
+ of charge, to (a) use, copy, distribute, modify, perform and display this
+ software and associated documentation files (the "Software"), and (b)
+ permit others to whom the Software is furnished to do so as well.
+
+ 1) The above copyright notice and this permission notice shall be included
+ without modification in all copies or substantial portions of the
+ Software.
+
+ 2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF
+ ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY
+ IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ PURPOSE OR NONINFRINGEMENT.
+
+ 3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
+ OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING
+ NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH
+ DAMAGES.
+
+*/
+
+
+#ifndef XML_TO_SOAP_H
+ #define XML_TO_SOAP_H
+
+#include "xmlrpc.h"
+
+XMLRPC_VALUE xml_element_to_SOAP_VALUE(xml_element* el);
+XMLRPC_VALUE xml_element_to_SOAP_REQUEST(XMLRPC_REQUEST request, xml_element* el);
+xml_element* SOAP_VALUE_to_xml_element(XMLRPC_VALUE node);
+xml_element* SOAP_REQUEST_to_xml_element(XMLRPC_REQUEST request);
+
+#endif /* XML_TO_XMLRPC_H */
diff --git a/ext/xmlrpc/libxmlrpc/xml_to_xmlrpc.c b/ext/xmlrpc/libxmlrpc/xml_to_xmlrpc.c
new file mode 100644
index 0000000..1397607
--- /dev/null
+++ b/ext/xmlrpc/libxmlrpc/xml_to_xmlrpc.c
@@ -0,0 +1,414 @@
+/*
+ This file is part of libXMLRPC - a C library for xml-encoded function calls.
+
+ Author: Dan Libby (dan@libby.com)
+ Epinions.com may be contacted at feedback@epinions-inc.com
+*/
+
+/*
+ Copyright 2000 Epinions, Inc.
+
+ Subject to the following 3 conditions, Epinions, Inc. permits you, free
+ of charge, to (a) use, copy, distribute, modify, perform and display this
+ software and associated documentation files (the "Software"), and (b)
+ permit others to whom the Software is furnished to do so as well.
+
+ 1) The above copyright notice and this permission notice shall be included
+ without modification in all copies or substantial portions of the
+ Software.
+
+ 2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF
+ ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY
+ IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ PURPOSE OR NONINFRINGEMENT.
+
+ 3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
+ OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING
+ NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH
+ DAMAGES.
+
+*/
+
+
+static const char rcsid[] = "#(@) $Id$";
+
+#include "php.h"
+#include "main/snprintf.h"
+#ifdef _WIN32
+#include "xmlrpc_win32.h"
+#endif
+#include <string.h>
+#include <stdlib.h>
+#include "xml_to_xmlrpc.h"
+#include "base64.h"
+
+/* list of tokens used in vocab */
+#define ELEM_ARRAY "array"
+#define ELEM_BASE64 "base64"
+#define ELEM_BOOLEAN "boolean"
+#define ELEM_DATA "data"
+#define ELEM_DATETIME "dateTime.iso8601"
+#define ELEM_DOUBLE "double"
+#define ELEM_FAULT "fault"
+#define ELEM_FAULTCODE "faultCode"
+#define ELEM_FAULTSTRING "faultString"
+#define ELEM_I4 "i4"
+#define ELEM_INT "int"
+#define ELEM_MEMBER "member"
+#define ELEM_METHODCALL "methodCall"
+#define ELEM_METHODNAME "methodName"
+#define ELEM_METHODRESPONSE "methodResponse"
+#define ELEM_NAME "name"
+#define ELEM_PARAM "param"
+#define ELEM_PARAMS "params"
+#define ELEM_STRING "string"
+#define ELEM_STRUCT "struct"
+#define ELEM_VALUE "value"
+
+
+XMLRPC_VALUE xml_element_to_XMLRPC_REQUEST_worker(XMLRPC_REQUEST request, XMLRPC_VALUE parent_vector, XMLRPC_VALUE current_val, xml_element* el) {
+ if (!current_val) {
+ /* This should only be the case for the first element */
+ current_val = XMLRPC_CreateValueEmpty();
+ }
+
+ if (el->name) {
+
+ /* first, deal with the crazy/stupid fault format */
+ if (!strcmp(el->name, ELEM_FAULT)) {
+ xml_element* fault_value = (xml_element*)Q_Head(&el->children);
+ XMLRPC_SetIsVector(current_val, xmlrpc_vector_struct);
+
+ if(fault_value) {
+ xml_element* fault_struct = (xml_element*)Q_Head(&fault_value->children);
+ if(fault_struct) {
+ xml_element* iter = (xml_element*)Q_Head(&fault_struct->children);
+
+ while (iter) {
+ XMLRPC_VALUE xNextVal = XMLRPC_CreateValueEmpty();
+ xml_element_to_XMLRPC_REQUEST_worker(request, current_val, xNextVal, iter);
+ XMLRPC_AddValueToVector(current_val, xNextVal);
+ iter = (xml_element*)Q_Next(&fault_struct->children);
+ }
+ }
+ }
+ }
+ else if (!strcmp(el->name, ELEM_DATA) /* should be ELEM_ARRAY, but there is an extra level. weird */
+ || (!strcmp(el->name, ELEM_PARAMS) &&
+ (XMLRPC_RequestGetRequestType(request) == xmlrpc_request_call)) ) { /* this "PARAMS" concept is silly. dave?! */
+ xml_element* iter = (xml_element*)Q_Head(&el->children);
+ XMLRPC_SetIsVector(current_val, xmlrpc_vector_array);
+
+ while (iter) {
+ XMLRPC_VALUE xNextVal = XMLRPC_CreateValueEmpty();
+ xml_element_to_XMLRPC_REQUEST_worker(request, current_val, xNextVal, iter);
+ XMLRPC_AddValueToVector(current_val, xNextVal);
+ iter = (xml_element*)Q_Next(&el->children);
+ }
+ }
+ else if (!strcmp(el->name, ELEM_STRUCT)) {
+ xml_element* iter = (xml_element*)Q_Head(&el->children);
+ XMLRPC_SetIsVector(current_val, xmlrpc_vector_struct);
+
+ while ( iter ) {
+ XMLRPC_VALUE xNextVal = XMLRPC_CreateValueEmpty();
+ xml_element_to_XMLRPC_REQUEST_worker(request, current_val, xNextVal, iter);
+ XMLRPC_AddValueToVector(current_val, xNextVal);
+ iter = (xml_element*)Q_Next(&el->children);
+ }
+ }
+ else if (!strcmp(el->name, ELEM_STRING) ||
+ (!strcmp(el->name, ELEM_VALUE) && Q_Size(&el->children) == 0)) {
+ XMLRPC_SetValueString(current_val, el->text.str, el->text.len);
+ }
+ else if (!strcmp(el->name, ELEM_NAME)) {
+ XMLRPC_SetValueID_Case(current_val, el->text.str, 0, xmlrpc_case_exact);
+ }
+ else if (!strcmp(el->name, ELEM_INT) || !strcmp(el->name, ELEM_I4)) {
+ XMLRPC_SetValueInt(current_val, atoi(el->text.str));
+ }
+ else if (!strcmp(el->name, ELEM_BOOLEAN)) {
+ XMLRPC_SetValueBoolean(current_val, atoi(el->text.str));
+ }
+ else if (!strcmp(el->name, ELEM_DOUBLE)) {
+ XMLRPC_SetValueDouble(current_val, atof(el->text.str));
+ }
+ else if (!strcmp(el->name, ELEM_DATETIME)) {
+ XMLRPC_SetValueDateTime_ISO8601(current_val, el->text.str);
+ }
+ else if (!strcmp(el->name, ELEM_BASE64)) {
+ struct buffer_st buf;
+ base64_decode_xmlrpc(&buf, el->text.str, el->text.len);
+ XMLRPC_SetValueBase64(current_val, buf.data, buf.offset);
+ buffer_delete(&buf);
+ }
+ else {
+ xml_element* iter;
+
+ if (!strcmp(el->name, ELEM_METHODCALL)) {
+ if (request) {
+ XMLRPC_RequestSetRequestType(request, xmlrpc_request_call);
+ }
+ }
+ else if (!strcmp(el->name, ELEM_METHODRESPONSE)) {
+ if (request) {
+ XMLRPC_RequestSetRequestType(request, xmlrpc_request_response);
+ }
+ }
+ else if (!strcmp(el->name, ELEM_METHODNAME)) {
+ if (request) {
+ XMLRPC_RequestSetMethodName(request, el->text.str);
+ }
+ }
+
+ iter = (xml_element*)Q_Head(&el->children);
+ while ( iter ) {
+ xml_element_to_XMLRPC_REQUEST_worker(request, parent_vector,
+ current_val, iter);
+ iter = (xml_element*)Q_Next(&el->children);
+ }
+ }
+ }
+ return current_val;
+}
+
+XMLRPC_VALUE xml_element_to_XMLRPC_VALUE(xml_element* el)
+{
+ return xml_element_to_XMLRPC_REQUEST_worker(NULL, NULL, NULL, el);
+}
+
+XMLRPC_VALUE xml_element_to_XMLRPC_REQUEST(XMLRPC_REQUEST request, xml_element* el)
+{
+ if (request) {
+ return XMLRPC_RequestSetData(request, xml_element_to_XMLRPC_REQUEST_worker(request, NULL, NULL, el));
+ }
+ return NULL;
+}
+
+xml_element* XMLRPC_to_xml_element_worker(XMLRPC_VALUE current_vector, XMLRPC_VALUE node,
+ XMLRPC_REQUEST_TYPE request_type, int depth) {
+#define BUF_SIZE 512
+ xml_element* root = NULL;
+ if (node) {
+ char buf[BUF_SIZE];
+ XMLRPC_VALUE_TYPE type = XMLRPC_GetValueType(node);
+ XMLRPC_VECTOR_TYPE vtype = XMLRPC_GetVectorType(node);
+ xml_element* elem_val = xml_elem_new();
+
+ /* special case for when root element is not an array */
+ if (depth == 0 &&
+ !(type == xmlrpc_vector &&
+ vtype == xmlrpc_vector_array &&
+ request_type == xmlrpc_request_call) ) {
+ int bIsFault = (vtype == xmlrpc_vector_struct && XMLRPC_VectorGetValueWithID(node, ELEM_FAULTCODE));
+
+ xml_element* next_el = XMLRPC_to_xml_element_worker(NULL, node, request_type, depth + 1);
+ if (next_el) {
+ Q_PushTail(&elem_val->children, next_el);
+ }
+ elem_val->name = strdup(bIsFault ? ELEM_FAULT : ELEM_PARAMS);
+ }
+ else {
+ switch (type) {
+ case xmlrpc_empty: /* treat null value as empty string in xmlrpc. */
+ case xmlrpc_string:
+ elem_val->name = strdup(ELEM_STRING);
+ simplestring_addn(&elem_val->text, XMLRPC_GetValueString(node), XMLRPC_GetValueStringLen(node));
+ break;
+ case xmlrpc_int:
+ elem_val->name = strdup(ELEM_INT);
+ snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueInt(node));
+ simplestring_add(&elem_val->text, buf);
+ break;
+ case xmlrpc_boolean:
+ elem_val->name = strdup(ELEM_BOOLEAN);
+ snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueBoolean(node));
+ simplestring_add(&elem_val->text, buf);
+ break;
+ case xmlrpc_double:
+ {
+ TSRMLS_FETCH();
+ elem_val->name = strdup(ELEM_DOUBLE);
+ ap_php_snprintf(buf, BUF_SIZE, "%.*G", (int) EG(precision), XMLRPC_GetValueDouble(node));
+ simplestring_add(&elem_val->text, buf);
+ }
+ break;
+ case xmlrpc_datetime:
+ elem_val->name = strdup(ELEM_DATETIME);
+ simplestring_add(&elem_val->text, XMLRPC_GetValueDateTime_ISO8601(node));
+ break;
+ case xmlrpc_base64:
+ {
+ struct buffer_st buf;
+ elem_val->name = strdup(ELEM_BASE64);
+ base64_encode_xmlrpc(&buf, XMLRPC_GetValueBase64(node), XMLRPC_GetValueStringLen(node));
+ simplestring_addn(&elem_val->text, buf.data, buf.offset );
+ buffer_delete(&buf);
+ }
+ break;
+ case xmlrpc_vector:
+ {
+ XMLRPC_VECTOR_TYPE my_type = XMLRPC_GetVectorType(node);
+ XMLRPC_VALUE xIter = XMLRPC_VectorRewind(node);
+ xml_element* root_vector_elem = elem_val;
+
+ switch (my_type) {
+ case xmlrpc_vector_array:
+ {
+ if(depth == 0) {
+ elem_val->name = strdup(ELEM_PARAMS);
+ }
+ else {
+ /* Hi my name is Dave and I like to make things as confusing
+ * as possible, thus I will throw in this 'data' element
+ * where it absolutely does not belong just so that people
+ * cannot code arrays and structs in a similar and straight
+ * forward manner. Have a good day.
+ *
+ * GRRRRRRRRR!
+ */
+ xml_element* data = xml_elem_new();
+ data->name = strdup(ELEM_DATA);
+
+ elem_val->name = strdup(ELEM_ARRAY);
+ Q_PushTail(&elem_val->children, data);
+ root_vector_elem = data;
+ }
+ }
+ break;
+ case xmlrpc_vector_mixed: /* not officially supported */
+ case xmlrpc_vector_struct:
+ elem_val->name = strdup(ELEM_STRUCT);
+ break;
+ default:
+ break;
+ }
+
+ /* recurse through sub-elements */
+ while ( xIter ) {
+ xml_element* next_el = XMLRPC_to_xml_element_worker(node, xIter, request_type, depth + 1);
+ if (next_el) {
+ Q_PushTail(&root_vector_elem->children, next_el);
+ }
+ xIter = XMLRPC_VectorNext(node);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ {
+ XMLRPC_VECTOR_TYPE vtype = XMLRPC_GetVectorType(current_vector);
+
+ if (depth == 1) {
+ xml_element* value = xml_elem_new();
+ value->name = strdup(ELEM_VALUE);
+
+ /* yet another hack for the "fault" crap */
+ if (XMLRPC_VectorGetValueWithID(node, ELEM_FAULTCODE)) {
+ root = value;
+ }
+ else {
+ xml_element* param = xml_elem_new();
+ param->name = strdup(ELEM_PARAM);
+
+ Q_PushTail(&param->children, value);
+
+ root = param;
+ }
+ Q_PushTail(&value->children, elem_val);
+ }
+ else if (vtype == xmlrpc_vector_struct || vtype == xmlrpc_vector_mixed) {
+ xml_element* member = xml_elem_new();
+ xml_element* name = xml_elem_new();
+ xml_element* value = xml_elem_new();
+
+ member->name = strdup(ELEM_MEMBER);
+ name->name = strdup(ELEM_NAME);
+ value->name = strdup(ELEM_VALUE);
+
+ simplestring_add(&name->text, XMLRPC_GetValueID(node));
+
+ Q_PushTail(&member->children, name);
+ Q_PushTail(&member->children, value);
+ Q_PushTail(&value->children, elem_val);
+
+ root = member;
+ }
+ else if (vtype == xmlrpc_vector_array) {
+ xml_element* value = xml_elem_new();
+
+ value->name = strdup(ELEM_VALUE);
+
+ Q_PushTail(&value->children, elem_val);
+
+ root = value;
+ }
+ else if (vtype == xmlrpc_vector_none) {
+ /* no parent. non-op */
+ root = elem_val;
+ }
+ else {
+ xml_element* value = xml_elem_new();
+
+ value->name = strdup(ELEM_VALUE);
+
+ Q_PushTail(&value->children, elem_val);
+
+ root = value;
+ }
+ }
+ }
+ return root;
+}
+
+xml_element* XMLRPC_VALUE_to_xml_element(XMLRPC_VALUE node) {
+ return XMLRPC_to_xml_element_worker(NULL, node, xmlrpc_request_none, 0);
+}
+
+xml_element* XMLRPC_REQUEST_to_xml_element(XMLRPC_REQUEST request) {
+ xml_element* wrapper = NULL;
+ if (request) {
+ const char* pStr = NULL;
+ XMLRPC_REQUEST_TYPE request_type = XMLRPC_RequestGetRequestType(request);
+ XMLRPC_VALUE xParams = XMLRPC_RequestGetData(request);
+
+ wrapper = xml_elem_new();
+
+ if (request_type == xmlrpc_request_call) {
+ pStr = ELEM_METHODCALL;
+ }
+ else if (request_type == xmlrpc_request_response) {
+ pStr = ELEM_METHODRESPONSE;
+ }
+ if (pStr) {
+ wrapper->name = strdup(pStr);
+ }
+
+ if(request_type == xmlrpc_request_call) {
+ pStr = XMLRPC_RequestGetMethodName(request);
+
+ if (pStr) {
+ xml_element* method = xml_elem_new();
+ method->name = strdup(ELEM_METHODNAME);
+ simplestring_add(&method->text, pStr);
+ Q_PushTail(&wrapper->children, method);
+ }
+ }
+ if (xParams) {
+ Q_PushTail(&wrapper->children,
+ XMLRPC_to_xml_element_worker(NULL, XMLRPC_RequestGetData(request), XMLRPC_RequestGetRequestType(request), 0));
+ }
+ else {
+ /* Despite the spec, the xml-rpc list folk want me to send an empty params element */
+ xml_element* params = xml_elem_new();
+ params->name = strdup(ELEM_PARAMS);
+ Q_PushTail(&wrapper->children, params);
+ }
+ }
+ return wrapper;
+}
+
diff --git a/ext/xmlrpc/libxmlrpc/xml_to_xmlrpc.h b/ext/xmlrpc/libxmlrpc/xml_to_xmlrpc.h
new file mode 100644
index 0000000..234a153
--- /dev/null
+++ b/ext/xmlrpc/libxmlrpc/xml_to_xmlrpc.h
@@ -0,0 +1,45 @@
+/*
+ This file is part of libXMLRPC - a C library for xml-encoded function calls.
+
+ Author: Dan Libby (dan@libby.com)
+ Epinions.com may be contacted at feedback@epinions-inc.com
+*/
+
+/*
+ Copyright 2000 Epinions, Inc.
+
+ Subject to the following 3 conditions, Epinions, Inc. permits you, free
+ of charge, to (a) use, copy, distribute, modify, perform and display this
+ software and associated documentation files (the "Software"), and (b)
+ permit others to whom the Software is furnished to do so as well.
+
+ 1) The above copyright notice and this permission notice shall be included
+ without modification in all copies or substantial portions of the
+ Software.
+
+ 2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF
+ ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY
+ IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ PURPOSE OR NONINFRINGEMENT.
+
+ 3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
+ OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING
+ NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH
+ DAMAGES.
+
+*/
+
+
+#ifndef XML_TO_XMLRPC_H
+ #define XML_TO_XMLRPC_H
+
+#include "time.h"
+#include "xmlrpc.h"
+
+XMLRPC_VALUE xml_element_to_XMLRPC_VALUE(xml_element* el);
+XMLRPC_VALUE xml_element_to_XMLRPC_REQUEST(XMLRPC_REQUEST request, xml_element* el);
+xml_element* XMLRPC_VALUE_to_xml_element(XMLRPC_VALUE node);
+xml_element* XMLRPC_REQUEST_to_xml_element(XMLRPC_REQUEST request);
+
+#endif /* XML_TO_XMLRPC_H */
diff --git a/ext/xmlrpc/libxmlrpc/xmlrpc.c b/ext/xmlrpc/libxmlrpc/xmlrpc.c
new file mode 100644
index 0000000..ec2321b
--- /dev/null
+++ b/ext/xmlrpc/libxmlrpc/xmlrpc.c
@@ -0,0 +1,3006 @@
+/*
+ This file is part of libXMLRPC - a C library for xml-encoded function calls.
+
+ Author: Dan Libby (dan@libby.com)
+ Epinions.com may be contacted at feedback@epinions-inc.com
+*/
+
+/*
+ Copyright 2000 Epinions, Inc.
+
+ Subject to the following 3 conditions, Epinions, Inc. permits you, free
+ of charge, to (a) use, copy, distribute, modify, perform and display this
+ software and associated documentation files (the "Software"), and (b)
+ permit others to whom the Software is furnished to do so as well.
+
+ 1) The above copyright notice and this permission notice shall be included
+ without modification in all copies or substantial portions of the
+ Software.
+
+ 2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF
+ ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY
+ IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ PURPOSE OR NONINFRINGEMENT.
+
+ 3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
+ OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING
+ NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH
+ DAMAGES.
+
+*/
+
+
+static const char rcsid[] = "#(@) $Id$";
+
+
+/****h* ABOUT/xmlrpc
+ * NAME
+ * XMLRPC_VALUE
+ * AUTHOR
+ * Dan Libby, aka danda (dan@libby.com)
+ * CREATION DATE
+ * 9/1999 - 10/2000
+ * HISTORY
+ * $Log$
+ * Revision 1.8.4.3.2.1 2008/09/10 00:07:44 felipe
+ * MFH:
+ * - Merged fix from SF project (Import Jeff Lawsons patches for XML datetime bug fixes)
+ * Fixed bugs:
+ * #45226 (xmlrpc_set_type() segfaults with valid ISO8601 date string)
+ * #18916 (xmlrpc_set_type() "not working")
+ *
+ * Revision 1.8.4.3 2007/09/18 19:49:53 iliaa
+ *
+ * Fixed bug #42189 (xmlrpc_set_type() crashes php on invalid datetime
+ * values).
+ *
+ * Revision 1.8.4.2 2007/06/07 09:07:36 tony2001
+ * MFH: php_localtime_r() checks
+ *
+ * Revision 1.8.4.1 2006/11/30 16:38:37 iliaa
+ * last set of zts fixes
+ *
+ * Revision 1.8 2005/03/28 00:07:24 edink
+ * Reshufle includes to make it compile on windows
+ *
+ * Revision 1.7 2005/03/26 03:13:58 sniper
+ * - Made it possible to build ext/xmlrpc with libxml2
+ *
+ * Revision 1.6 2004/04/27 17:33:59 iliaa
+ * Removed C++ style comments.
+ *
+ * Revision 1.5 2003/12/16 21:00:21 sniper
+ * Fix some compile warnings (patch by Joe Orton)
+ *
+ * Revision 1.4 2002/07/05 04:43:53 danda
+ * merged in updates from SF project. bring php repository up to date with xmlrpc-epi version 0.51
+ *
+ * Revision 1.22 2002/03/09 23:15:44 danda
+ * add fault interrogation funcs
+ *
+ * Revision 1.21 2002/03/09 22:27:41 danda
+ * win32 build patches contributed by Jeff Lawson
+ *
+ * Revision 1.20 2002/02/13 20:58:50 danda
+ * patch to make source more windows friendly, contributed by Jeff Lawson
+ *
+ * Revision 1.19 2001/10/12 23:25:54 danda
+ * default to writing xmlrpc
+ *
+ * Revision 1.18 2001/09/29 21:58:05 danda
+ * adding cvs log to history section
+ *
+ * 10/15/2000 -- danda -- adding robodoc documentation
+ * 08/2000 -- danda -- PHP C extension that uses XMLRPC
+ * 08/2000 -- danda -- support for two vocabularies: danda-rpc and xml-rpc
+ * 09/1999 -- danda -- Initial API, before I even knew of standard XMLRPC vocab. Response only.
+ * 07/2000 -- danda -- wrote new implementation to be compatible with xmlrpc standard and
+ * incorporated some ideas from ensor, most notably the separation of
+ * xml dom from xmlrpc api.
+ * 06/2000 -- danda -- played with expat-ensor from www.ensor.org. Cool, but some flaws.
+ * TODO
+ * PORTABILITY
+ * Coded on RedHat Linux 6.2. Builds on Solaris x86. Should build on just
+ * about anything with minor mods.
+ * NOTES
+ * Welcome to XMLRPC. For more info on the specification and history, see
+ * http://www.xmlrpc.org.
+ *
+ * This code aims to be a full-featured C implementation of XMLRPC. It does not
+ * have any networking code. Rather, it is intended to be plugged into apps
+ * or libraries with existing networking facilities, eg PHP, apache, perl, mozilla,
+ * home-brew application servers, etc.
+ *
+ * Usage Paradigm:
+ * The user of this library will typically be implementing either an XMLRPC server,
+ * an XMLRPC client, or both. The client will use the library to build an in-memory
+ * representation of a request, and then serialize (encode) that request into XML. The
+ * client will then send the XML to the server via external mechanism. The server will
+ * de-serialize the XML back into an binary representation, call the appropriate registered
+ * method -- thereby generating a response. The response will be serialized into XML and
+ * sent back to the client. The client will de-serialize it into memory, and can
+ * iterate through the results via API.
+ *
+ * Both the request and the response may consist of arbitrarily long, arbitrarily nested
+ * values. The values may be one of several types, as defined by XMLRPC_VALUE_TYPE.
+ *
+ * Features and Architecture:
+ * - The XML parsing (xml_element.c) is completely independent of the XMLRPC api. In fact,
+ * it can be used as a standalone dom implementation.
+ * - Because of this, the same XMLRPC data can be serialized into multiple xml vocabularies.
+ * It is simply a matter of writing a transport. So far, two transports have been defined.
+ * The default xmlrpc vocab (xml_to_xmlrpc.c), and simple-rpc (xml_to_dandarpc.c) which is
+ * proprietary, but imho more readable, and nice for proprietary legacy reasons.
+ * - Various output options, including: xml escaping via CDATA or entity, case folding,
+ * vocab version, and character encoding.
+ * - One to One mapping between C structures and actual values, unlike ensor which forces
+ * one to understand the arcana of the xmlrpc vocab.
+ * - support for mixed indexed/keyed vector types, making it more compatible with
+ * languages such as PHP.
+ * - quite speedy compared to implementations written in interpreted languages. Also, uses
+ * intelligent string handling, so not many strlen() calls, etc.
+ * - comprehensive API for manipulation of values
+ *******/
+
+#include "ext/xml/expat_compat.h"
+#include "main/php_reentrancy.h"
+#ifdef _WIN32
+#include "xmlrpc_win32.h"
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <time.h>
+#include <ctype.h>
+
+#include "queue.h"
+#include "xmlrpc.h"
+#include "base64.h"
+
+#include "xml_to_xmlrpc.h"
+#include "xml_to_dandarpc.h"
+#include "xml_to_soap.h"
+#include "xml_element.h"
+#include "xmlrpc_private.h"
+#include "xmlrpc_introspection_private.h"
+#include "system_methods_private.h"
+
+
+
+/*-*********************
+* Begin Time Functions *
+***********************/
+
+static time_t mkgmtime(struct tm *tm)
+{
+ static const int mdays[12] = {0,31,59,90,120,151,181,212,243,273,304,334};
+
+ return ((((((tm->tm_year - 70) * 365) + mdays[tm->tm_mon] + tm->tm_mday-1 +
+ (tm->tm_year-68-1+(tm->tm_mon>=2))/4) * 24) + tm->tm_hour) * 60 +
+ tm->tm_min) * 60 + tm->tm_sec;
+}
+
+static int date_from_ISO8601 (const char *text, time_t * value) {
+ struct tm tm;
+ int n;
+ int i;
+ char buf[30];
+
+
+ if (strchr (text, '-')) {
+ char *p = (char *) text, *p2 = buf;
+ while (p && *p) {
+ if (*p != '-') {
+ *p2 = *p;
+ p2++;
+ if (p2-buf >= sizeof(buf)) {
+ return -1;
+ }
+ }
+ p++;
+ }
+ text = buf;
+ }
+
+
+ tm.tm_isdst = -1;
+
+#define XMLRPC_IS_NUMBER(x) if (x < '0' || x > '9') return -1;
+
+ n = 1000;
+ tm.tm_year = 0;
+ for(i = 0; i < 4; i++) {
+ XMLRPC_IS_NUMBER(text[i])
+ tm.tm_year += (text[i]-'0')*n;
+ n /= 10;
+ }
+ n = 10;
+ tm.tm_mon = 0;
+ for(i = 0; i < 2; i++) {
+ XMLRPC_IS_NUMBER(text[i])
+ tm.tm_mon += (text[i+4]-'0')*n;
+ n /= 10;
+ }
+ tm.tm_mon --;
+
+ n = 10;
+ tm.tm_mday = 0;
+ for(i = 0; i < 2; i++) {
+ XMLRPC_IS_NUMBER(text[i])
+ tm.tm_mday += (text[i+6]-'0')*n;
+ n /= 10;
+ }
+
+ n = 10;
+ tm.tm_hour = 0;
+ for(i = 0; i < 2; i++) {
+ XMLRPC_IS_NUMBER(text[i])
+ tm.tm_hour += (text[i+9]-'0')*n;
+ n /= 10;
+ }
+
+ n = 10;
+ tm.tm_min = 0;
+ for(i = 0; i < 2; i++) {
+ XMLRPC_IS_NUMBER(text[i])
+ tm.tm_min += (text[i+12]-'0')*n;
+ n /= 10;
+ }
+
+ n = 10;
+ tm.tm_sec = 0;
+ for(i = 0; i < 2; i++) {
+ XMLRPC_IS_NUMBER(text[i])
+ tm.tm_sec += (text[i+15]-'0')*n;
+ n /= 10;
+ }
+
+ tm.tm_year -= 1900;
+
+ *value = mkgmtime(&tm);
+
+ return 0;
+
+}
+
+static int date_to_ISO8601 (time_t value, char *buf, int length) {
+ struct tm *tm, tmbuf;
+ tm = php_gmtime_r(&value, &tmbuf);
+ if (!tm) {
+ return 0;
+ }
+#if 0 /* TODO: soap seems to favor this method. xmlrpc the latter. */
+ return strftime (buf, length, "%Y-%m-%dT%H:%M:%SZ", tm);
+#else
+ return strftime(buf, length, "%Y%m%dT%H:%M:%SZ", tm);
+#endif
+}
+
+/*-*******************
+* End Time Functions *
+*********************/
+
+
+/*-***************************
+* Begin XMLRPC_REQUEST funcs *
+*****************************/
+
+/****f* REQUEST/XMLRPC_RequestNew
+ * NAME
+ * XMLRPC_RequestNew
+ * SYNOPSIS
+ * XMLRPC_REQUEST XMLRPC_RequestNew()
+ * FUNCTION
+ * Creates a new XMLRPC_Request data struct
+ * INPUTS
+ * none
+ * SEE ALSO
+ * XMLRPC_RequestFree ()
+ * SOURCE
+ */
+XMLRPC_REQUEST XMLRPC_RequestNew() {
+ XMLRPC_REQUEST xRequest = calloc(1, sizeof(STRUCT_XMLRPC_REQUEST));
+ if(xRequest) {
+ simplestring_init(&xRequest->methodName);
+ }
+ return xRequest;
+}
+
+/*******/
+
+/****f* REQUEST/XMLRPC_RequestFree
+ * NAME
+ * XMLRPC_RequestFree
+ * SYNOPSIS
+ * void XMLRPC_RequestFree(XMLRPC_REQUEST request, int bFreeIO)
+ * FUNCTION
+ * Free XMLRPC Request and all sub-values
+ * INPUTS
+ * request -- previously allocated request struct
+ * bFreeIO -- 1 = also free request value data, if any, 0 = ignore.
+ * SEE ALSO
+ * XMLRPC_RequestNew ()
+ * XMLRPC_CleanupValue ()
+ * SOURCE
+ */
+void XMLRPC_RequestFree(XMLRPC_REQUEST request, int bFreeIO) {
+ if(request) {
+ simplestring_free(&request->methodName);
+
+ if(request->io && bFreeIO) {
+ XMLRPC_CleanupValue(request->io);
+ }
+ if(request->error) {
+ XMLRPC_CleanupValue(request->error);
+ }
+ my_free(request);
+ }
+}
+
+/*******/
+
+/* Set Method Name to call */
+/****f* REQUEST/XMLRPC_RequestSetMethodName
+ * NAME
+ * XMLRPC_RequestSetMethodName
+ * SYNOPSIS
+ * const char* XMLRPC_RequestSetMethodName(XMLRPC_REQUEST request, const char* methodName)
+ * FUNCTION
+ * Set name of method to call with this request.
+ * INPUTS
+ * request -- previously allocated request struct
+ * methodName -- name of method
+ * SEE ALSO
+ * XMLRPC_RequestNew ()
+ * XMLRPC_RequestGetMethodName ()
+ * XMLRPC_RequestFree ()
+ * SOURCE
+ */
+const char* XMLRPC_RequestSetMethodName(XMLRPC_REQUEST request, const char* methodName) {
+ if(request) {
+ simplestring_clear(&request->methodName);
+ simplestring_add(&request->methodName, methodName);
+ return request->methodName.str;
+ }
+ return NULL;
+}
+
+/*******/
+
+/****f* REQUEST/XMLRPC_RequestGetMethodName
+ * NAME
+ * XMLRPC_RequestGetMethodName
+ * SYNOPSIS
+ * const char* XMLRPC_RequestGetMethodName(XMLRPC_REQUEST request)
+ * FUNCTION
+ * Get name of method called by this request
+ * INPUTS
+ * request -- previously allocated request struct
+ * SEE ALSO
+ * XMLRPC_RequestNew ()
+ * XMLRPC_RequestSetMethodName ()
+ * XMLRPC_RequestFree ()
+ * SOURCE
+ */
+const char* XMLRPC_RequestGetMethodName(XMLRPC_REQUEST request) {
+ return request ? request->methodName.str : NULL;
+}
+
+/*******/
+
+/****f* REQUEST/XMLRPC_RequestSetRequestType
+ * NAME
+ * XMLRPC_RequestSetRequestType
+ * SYNOPSIS
+ * XMLRPC_REQUEST_TYPE XMLRPC_RequestSetRequestType(XMLRPC_REQUEST request, XMLRPC_REQUEST_TYPE type)
+ * FUNCTION
+ * A request struct may be allocated by a caller or by xmlrpc
+ * in response to a request. This allows setting the
+ * request type.
+ * INPUTS
+ * request -- previously allocated request struct
+ * type -- request type [xmlrpc_method_call | xmlrpc_method_response]
+ * SEE ALSO
+ * XMLRPC_RequestNew ()
+ * XMLRPC_RequestGetRequestType ()
+ * XMLRPC_RequestFree ()
+ * XMLRPC_REQUEST_TYPE
+ * SOURCE
+ */
+XMLRPC_REQUEST_TYPE XMLRPC_RequestSetRequestType (XMLRPC_REQUEST request,
+ XMLRPC_REQUEST_TYPE type) {
+ if(request) {
+ request->request_type = type;
+ return request->request_type;
+ }
+ return xmlrpc_request_none;
+}
+
+/*******/
+
+/****f* REQUEST/XMLRPC_RequestGetRequestType
+ * NAME
+ * XMLRPC_RequestGetRequestType
+ * SYNOPSIS
+ * XMLRPC_REQUEST_TYPE XMLRPC_RequestGetRequestType(XMLRPC_REQUEST request)
+ * FUNCTION
+ * A request struct may be allocated by a caller or by xmlrpc
+ * in response to a request. This allows setting the
+ * request type.
+ * INPUTS
+ * request -- previously allocated request struct
+ * RESULT
+ * type -- request type [xmlrpc_method_call | xmlrpc_method_response]
+ * SEE ALSO
+ * XMLRPC_RequestNew ()
+ * XMLRPC_RequestSetRequestType ()
+ * XMLRPC_RequestFree ()
+ * XMLRPC_REQUEST_TYPE
+ * SOURCE
+ */
+XMLRPC_REQUEST_TYPE XMLRPC_RequestGetRequestType(XMLRPC_REQUEST request) {
+ return request ? request->request_type : xmlrpc_request_none;
+}
+
+/*******/
+
+
+/****f* REQUEST/XMLRPC_RequestSetData
+ * NAME
+ * XMLRPC_RequestSetData
+ * SYNOPSIS
+ * XMLRPC_VALUE XMLRPC_RequestSetData(XMLRPC_REQUEST request, XMLRPC_VALUE data)
+ * FUNCTION
+ * Associates a block of xmlrpc data with the request. The
+ * data is *not* copied. A pointer is kept. The caller
+ * should be careful not to doubly free the data value,
+ * which may optionally be free'd by XMLRPC_RequestFree().
+ * INPUTS
+ * request -- previously allocated request struct
+ * data -- previously allocated data struct
+ * RESULT
+ * XMLRPC_VALUE -- pointer to value stored, or NULL
+ * SEE ALSO
+ * XMLRPC_RequestNew ()
+ * XMLRPC_RequestGetData ()
+ * XMLRPC_RequestFree ()
+ * XMLRPC_REQUEST
+ * XMLRPC_VALUE
+ * SOURCE
+ */
+XMLRPC_VALUE XMLRPC_RequestSetData(XMLRPC_REQUEST request, XMLRPC_VALUE data) {
+ if(request && data) {
+ if (request->io) {
+ XMLRPC_CleanupValue (request->io);
+ }
+ request->io = XMLRPC_CopyValue(data);
+ return request->io;
+ }
+ return NULL;
+}
+
+/*******/
+
+/****f* REQUEST/XMLRPC_RequestGetData
+ * NAME
+ * XMLRPC_RequestGetData
+ * SYNOPSIS
+ * XMLRPC_VALUE XMLRPC_RequestGetData(XMLRPC_REQUEST request)
+ * FUNCTION
+ * Returns data associated with request, if any.
+ * INPUTS
+ * request -- previously allocated request struct
+ * RESULT
+ * XMLRPC_VALUE -- pointer to value stored, or NULL
+ * SEE ALSO
+ * XMLRPC_RequestNew ()
+ * XMLRPC_RequestSetData ()
+ * XMLRPC_RequestFree ()
+ * XMLRPC_REQUEST
+ * XMLRPC_VALUE
+ * SOURCE
+ */
+XMLRPC_VALUE XMLRPC_RequestGetData(XMLRPC_REQUEST request) {
+ return request ? request->io : NULL;
+}
+
+/*******/
+
+/****f* REQUEST/XMLRPC_RequestSetError
+ * NAME
+ * XMLRPC_RequestSetError
+ * SYNOPSIS
+ * XMLRPC_VALUE XMLRPC_RequestSetError(XMLRPC_REQUEST request, XMLRPC_VALUE error)
+ * FUNCTION
+ * Associates a block of xmlrpc data, representing an error
+ * condition, with the request.
+ * INPUTS
+ * request -- previously allocated request struct
+ * error -- previously allocated error code or struct
+ * RESULT
+ * XMLRPC_VALUE -- pointer to value stored, or NULL
+ * NOTES
+ * This is a private function for usage by internals only.
+ * SEE ALSO
+ * XMLRPC_RequestGetError ()
+ * SOURCE
+ */
+XMLRPC_VALUE XMLRPC_RequestSetError (XMLRPC_REQUEST request, XMLRPC_VALUE error) {
+ if (request && error) {
+ if (request->error) {
+ XMLRPC_CleanupValue (request->error);
+ }
+ request->error = XMLRPC_CopyValue (error);
+ return request->error;
+ }
+ return NULL;
+}
+
+/*******/
+
+/****f* REQUEST/XMLRPC_RequestGetError
+ * NAME
+ * XMLRPC_RequestGetError
+ * SYNOPSIS
+ * XMLRPC_VALUE XMLRPC_RequestGetError(XMLRPC_REQUEST request)
+ * FUNCTION
+ * Returns error data associated with request, if any.
+ * INPUTS
+ * request -- previously allocated request struct
+ * RESULT
+ * XMLRPC_VALUE -- pointer to error value stored, or NULL
+ * NOTES
+ * This is a private function for usage by internals only.
+ * SEE ALSO
+ * XMLRPC_RequestSetError ()
+ * XMLRPC_RequestFree ()
+ * SOURCE
+ */
+XMLRPC_VALUE XMLRPC_RequestGetError (XMLRPC_REQUEST request) {
+ return request ? request->error : NULL;
+}
+
+/*******/
+
+
+/****f* REQUEST/XMLRPC_RequestSetOutputOptions
+ * NAME
+ * XMLRPC_RequestSetOutputOptions
+ * SYNOPSIS
+ * XMLRPC_REQUEST_OUTPUT_OPTIONS XMLRPC_RequestSetOutputOptions(XMLRPC_REQUEST request, XMLRPC_REQUEST_OUTPUT_OPTIONS output)
+ * FUNCTION
+ * Sets output options used for generating XML. The output struct
+ * is copied, and may be freed by the caller.
+ * INPUTS
+ * request -- previously allocated request struct
+ * output -- output options struct initialized by caller
+ * RESULT
+ * XMLRPC_REQUEST_OUTPUT_OPTIONS -- pointer to value stored, or NULL
+ * SEE ALSO
+ * XMLRPC_RequestNew ()
+ * XMLRPC_RequestGetOutputOptions ()
+ * XMLRPC_RequestFree ()
+ * XMLRPC_REQUEST
+ * XMLRPC_REQUEST_OUTPUT_OPTIONS
+ * SOURCE
+ */
+XMLRPC_REQUEST_OUTPUT_OPTIONS XMLRPC_RequestSetOutputOptions(XMLRPC_REQUEST request, XMLRPC_REQUEST_OUTPUT_OPTIONS output) {
+ if(request && output) {
+ memcpy (&request->output, output,
+ sizeof (STRUCT_XMLRPC_REQUEST_OUTPUT_OPTIONS));
+ return &request->output;
+ }
+ return NULL;
+}
+
+/*******/
+
+
+/****f* REQUEST/XMLRPC_RequestGetOutputOptions
+ * NAME
+ * XMLRPC_RequestGetOutputOptions
+ * SYNOPSIS
+ * XMLRPC_REQUEST_OUTPUT_OPTIONS XMLRPC_RequestGetOutputOptions(XMLRPC_REQUEST request)
+ * FUNCTION
+ * Gets a pointer to output options used for generating XML.
+ * INPUTS
+ * request -- previously allocated request struct
+ * RESULT
+ * XMLRPC_REQUEST_OUTPUT_OPTIONS -- pointer to options stored, or NULL
+ * SEE ALSO
+ * XMLRPC_RequestNew ()
+ * XMLRPC_RequestSetOutputOptions ()
+ * XMLRPC_RequestFree ()
+ * XMLRPC_REQUEST
+ * XMLRPC_REQUEST_OUTPUT_OPTIONS
+ * SOURCE
+ */
+XMLRPC_REQUEST_OUTPUT_OPTIONS XMLRPC_RequestGetOutputOptions(XMLRPC_REQUEST request) {
+ return request ? &request->output : NULL;
+}
+
+/*******/
+
+/*-*************************
+* End XMLRPC_REQUEST funcs *
+***************************/
+
+
+/*-***************************
+* Begin Serializiation funcs *
+*****************************/
+
+/****f* SERIALIZE/XMLRPC_VALUE_ToXML
+ * NAME
+ * XMLRPC_VALUE_ToXML
+ * SYNOPSIS
+ * char* XMLRPC_VALUE_ToXML(XMLRPC_VALUE val)
+ * FUNCTION
+ * encode XMLRPC_VALUE into XML buffer. Note that the generated
+ * buffer will not contain a methodCall.
+ * INPUTS
+ * val -- previously allocated XMLRPC_VALUE
+ * buf_len -- length of returned buffer, if not null
+ * RESULT
+ * char* -- newly allocated buffer containing XML.
+ * It is the caller's responsibility to free it.
+ * SEE ALSO
+ * XMLRPC_REQUEST_ToXML ()
+ * XMLRPC_VALUE_FromXML ()
+ * XMLRPC_Free ()
+ * XMLRPC_VALUE
+ * SOURCE
+ */
+char* XMLRPC_VALUE_ToXML(XMLRPC_VALUE val, int* buf_len) {
+ xml_element *root_elem = XMLRPC_VALUE_to_xml_element(val);
+ char* pRet = NULL;
+
+ if(root_elem) {
+ pRet = xml_elem_serialize_to_string(root_elem, NULL, buf_len);
+ xml_elem_free(root_elem);
+ }
+ return pRet;
+}
+
+/*******/
+
+/****f* SERIALIZE/XMLRPC_REQUEST_ToXML
+ * NAME
+ * XMLRPC_REQUEST_ToXML
+ * SYNOPSIS
+ * char* XMLRPC_REQUEST_ToXML(XMLRPC_REQUEST request)
+ * FUNCTION
+ * encode XMLRPC_REQUEST into XML buffer
+ * INPUTS
+ * request -- previously allocated XMLRPC_REQUEST
+ * buf_len -- size of returned buf, if not null
+ * RESULT
+ * char* -- newly allocated buffer containing XML.
+ * It is the caller's responsibility to free it.
+ * SEE ALSO
+ * XMLRPC_REQUEST_ToXML ()
+ * XMLRPC_REQUEST_FromXML ()
+ * XMLRPC_Free ()
+ * XMLRPC_VALUE_ToXML ()
+ * XMLRPC_REQUEST
+ * SOURCE
+ */
+char* XMLRPC_REQUEST_ToXML(XMLRPC_REQUEST request, int* buf_len) {
+ char* pRet = NULL;
+ if (request) {
+ xml_element *root_elem = NULL;
+ if (request->output.version == xmlrpc_version_simple) {
+ root_elem = DANDARPC_REQUEST_to_xml_element (request);
+ }
+ else if (request->output.version == xmlrpc_version_1_0 ||
+ request->output.version == xmlrpc_version_none) {
+ root_elem = XMLRPC_REQUEST_to_xml_element (request);
+ }
+ else if (request->output.version == xmlrpc_version_soap_1_1) {
+ root_elem = SOAP_REQUEST_to_xml_element (request);
+ }
+
+ if(root_elem) {
+ pRet =
+ xml_elem_serialize_to_string (root_elem,
+ &request->output.xml_elem_opts,
+ buf_len);
+ xml_elem_free(root_elem);
+ }
+ }
+ return pRet;
+}
+
+/*******/
+
+/****f* SERIALIZE/XMLRPC_VALUE_FromXML
+ * NAME
+ * XMLRPC_VALUE_FromXML
+ * SYNOPSIS
+ * XMLRPC_VALUE XMLRPC_VALUE_FromXML(const char* in_buf, int le
+ * FUNCTION
+ * Retrieve XMLRPC_VALUE from XML buffer. Note that this will
+ * ignore any methodCall. See XMLRPC_REQUEST_FromXML
+ * INPUTS
+ * in_buf -- character buffer containing XML
+ * len -- length of buffer
+ * RESULT
+ * XMLRPC_VALUE -- newly allocated data, or NULL if error. Should
+ * be free'd by caller.
+ * SEE ALSO
+ * XMLRPC_VALUE_ToXML ()
+ * XMLRPC_REQUEST_FromXML ()
+ * XMLRPC_VALUE
+ * SOURCE
+ */
+XMLRPC_VALUE XMLRPC_VALUE_FromXML (const char *in_buf, int len, XMLRPC_REQUEST_INPUT_OPTIONS in_options) {
+ XMLRPC_VALUE xResponse = NULL;
+ XMLRPC_REQUEST req = XMLRPC_REQUEST_FromXML(in_buf, len, in_options);
+
+ if(req) {
+ xResponse = req->io;
+ XMLRPC_RequestFree(req, 0);
+ }
+ return xResponse;
+}
+
+/*******/
+
+/* map parser errors to standard xml-rpc errors */
+static XMLRPC_VALUE map_expat_errors(XML_ELEM_ERROR error) {
+ XMLRPC_VALUE xReturn = NULL;
+ if(error) {
+ XMLRPC_ERROR_CODE code;
+ char buf[1024];
+ snprintf(buf, sizeof(buf),
+ "error occurred at line %ld, column %ld, byte index %ld",
+ error->line, error->column, error->byte_index);
+
+ /* expat specific errors */
+ switch(error->parser_code) {
+ case XML_ERROR_UNKNOWN_ENCODING:
+ code = xmlrpc_error_parse_unknown_encoding;
+ break;
+ case XML_ERROR_INCORRECT_ENCODING:
+ code = xmlrpc_error_parse_bad_encoding;
+ break;
+ default:
+ code = xmlrpc_error_parse_xml_syntax;
+ break;
+ }
+ xReturn = XMLRPC_UtilityCreateFault(code, buf);
+ }
+ return xReturn;
+}
+
+/****f* SERIALIZE/XMLRPC_REQUEST_FromXML
+ * NAME
+ * XMLRPC_REQUEST_FromXML
+ * SYNOPSIS
+ * XMLRPC_REQUEST XMLRPC_REQUEST_FromXML(const char* in_buf, int le
+ * FUNCTION
+ * Retrieve XMLRPC_REQUEST from XML buffer
+ * INPUTS
+ * in_buf -- character buffer containing XML
+ * len -- length of buffer
+ * RESULT
+ * XMLRPC_REQUEST -- newly allocated data, or NULL if error. Should
+ * be free'd by caller.
+ * SEE ALSO
+ * XMLRPC_REQUEST_ToXML ()
+ * XMLRPC_VALUE_FromXML ()
+ * XMLRPC_REQUEST
+ * SOURCE
+ */
+XMLRPC_REQUEST XMLRPC_REQUEST_FromXML (const char *in_buf, int len,
+ XMLRPC_REQUEST_INPUT_OPTIONS in_options) {
+ XMLRPC_REQUEST request = XMLRPC_RequestNew();
+ STRUCT_XML_ELEM_ERROR error = {0};
+
+ if(request) {
+ xml_element *root_elem =
+ xml_elem_parse_buf (in_buf, len,
+ (in_options ? &in_options->xml_elem_opts : NULL),
+ &error);
+
+ if(root_elem) {
+ if(!strcmp(root_elem->name, "simpleRPC")) {
+ request->output.version = xmlrpc_version_simple;
+ xml_element_to_DANDARPC_REQUEST(request, root_elem);
+ }
+ else if (!strcmp (root_elem->name, "SOAP-ENV:Envelope")) {
+ request->output.version = xmlrpc_version_soap_1_1;
+ xml_element_to_SOAP_REQUEST (request, root_elem);
+ }
+ else {
+ request->output.version = xmlrpc_version_1_0;
+ xml_element_to_XMLRPC_REQUEST(request, root_elem);
+ }
+ xml_elem_free(root_elem);
+ }
+ else {
+ if(error.parser_error) {
+ XMLRPC_RequestSetError (request, map_expat_errors (&error));
+ }
+ }
+ }
+
+ return request;
+}
+
+/*******/
+
+/*-************************
+* End Serialization Funcs *
+**************************/
+
+
+
+/****f* VALUE/XMLRPC_CreateValueEmpty
+ * NAME
+ * XMLRPC_CreateValueEmpty
+ * SYNOPSIS
+ * XMLRPC_VALUE XMLRPC_CreateValueEmpty ()
+ * FUNCTION
+ * Create an XML value to be used/modified elsewhere.
+ * INPUTS
+ * RESULT
+ * XMLRPC_VALUE. The new value, or NULL on failure.
+ * SEE ALSO
+ * XMLRPC_CleanupValue ()
+ * XMLRPC_VALUE
+ * SOURCE
+ */
+XMLRPC_VALUE XMLRPC_CreateValueEmpty() {
+ XMLRPC_VALUE v = calloc(1, sizeof(STRUCT_XMLRPC_VALUE));
+ if(v) {
+#ifdef XMLRPC_DEBUG_REFCOUNT
+ printf ("calloc'd 0x%x\n", v);
+#endif
+ v->type = xmlrpc_empty;
+ simplestring_init(&v->id);
+ simplestring_init(&v->str);
+ }
+ return v;
+}
+
+/*******/
+
+/****f* VALUE/XMLRPC_SetValueID_Case
+ * NAME
+ * XMLRPC_SetValueID_Case
+ * SYNOPSIS
+ * const char *XMLRPC_SetValueID_Case(XMLRPC_VALUE value, const char* id, int len, XMLRPC_CASE id_case)
+ * FUNCTION
+ * Assign an ID (key) to an XMLRPC value.
+ * INPUTS
+ * value The xml value who's ID we will set.
+ * id The desired new id.
+ * len length of id string if known, or 0 if unknown.
+ * id_case one of XMLRPC_CASE
+ * RESULT
+ * const char* pointer to the newly allocated id string, or NULL
+ * SEE ALSO
+ * XMLRPC_SetValueID ()
+ * XMLRPC_GetValueID ()
+ * XMLRPC_VALUE
+ * XMLRPC_CASE
+ * SOURCE
+ */
+const char *XMLRPC_SetValueID_Case(XMLRPC_VALUE value, const char* id, int len, XMLRPC_CASE id_case) {
+ const char* pRetval = NULL;
+ if(value) {
+ if(id) {
+ simplestring_clear(&value->id);
+ (len > 0) ? simplestring_addn(&value->id, id, len) :
+ simplestring_add(&value->id, id);
+
+ /* upper or lower case string in place if required. could be a seperate func. */
+ if(id_case == xmlrpc_case_lower || id_case == xmlrpc_case_upper) {
+ int i;
+ for(i = 0; i < value->id.len; i++) {
+ value->id.str[i] =
+ (id_case ==
+ xmlrpc_case_lower) ? tolower (value->id.
+ str[i]) : toupper (value->
+ id.
+ str[i]);
+ }
+ }
+
+ pRetval = value->id.str;
+
+#ifdef XMLRPC_DEBUG_REFCOUNT
+ printf("set value id: %s\n", pRetval);
+#endif
+ }
+ }
+
+ return pRetval;
+}
+
+/*******/
+
+
+/****f* VALUE/XMLRPC_SetValueString
+ * NAME
+ * XMLRPC_SetValueString
+ * SYNOPSIS
+ * const char *XMLRPC_SetValueString(XMLRPC_VALUE value, const char* val, int len)
+ * FUNCTION
+ * Assign a string value to an XMLRPC_VALUE, and set it to type xmlrpc_string
+ * INPUTS
+ * value The xml value who's ID we will set.
+ * val The desired new string val.
+ * len length of val string if known, or 0 if unknown.
+ * RESULT
+ * const char* pointer to the newly allocated value string, or NULL
+ * SEE ALSO
+ * XMLRPC_GetValueString ()
+ * XMLRPC_VALUE
+ * XMLRPC_VALUE_TYPE
+ * SOURCE
+ */
+const char *XMLRPC_SetValueString(XMLRPC_VALUE value, const char* val, int len) {
+ char *pRetval = NULL;
+ if(value && val) {
+ simplestring_clear(&value->str);
+ (len > 0) ? simplestring_addn(&value->str, val, len) :
+ simplestring_add(&value->str, val);
+ value->type = xmlrpc_string;
+ pRetval = (char *)value->str.str;
+ }
+
+ return pRetval;
+}
+
+/*******/
+
+/****f* VALUE/XMLRPC_SetValueInt
+ * NAME
+ * XMLRPC_SetValueInt
+ * SYNOPSIS
+ * void XMLRPC_SetValueInt(XMLRPC_VALUE value, int val)
+ * FUNCTION
+ * Assign an int value to an XMLRPC_VALUE, and set it to type xmlrpc_int
+ * INPUTS
+ * value The xml value who's ID we will set.
+ * val The desired new integer value
+ * RESULT
+ * SEE ALSO
+ * XMLRPC_GetValueInt ()
+ * XMLRPC_VALUE
+ * XMLRPC_VALUE_TYPE
+ * SOURCE
+ */
+void XMLRPC_SetValueInt(XMLRPC_VALUE value, int val) {
+ if(value) {
+ value->type = xmlrpc_int;
+ value->i = val;
+ }
+}
+
+/*******/
+
+/****f* VALUE/XMLRPC_SetValueBoolean
+ * NAME
+ * XMLRPC_SetValueBoolean
+ * SYNOPSIS
+ * void XMLRPC_SetValueBoolean(XMLRPC_VALUE value, int val)
+ * FUNCTION
+ * Assign a boolean value to an XMLRPC_VALUE, and set it to type xmlrpc_boolean
+ * INPUTS
+ * value The xml value who's value we will set.
+ * val The desired new boolean value. [0 | 1]
+ * RESULT
+ * SEE ALSO
+ * XMLRPC_GetValueBoolean ()
+ * XMLRPC_VALUE
+ * XMLRPC_VALUE_TYPE
+ * SOURCE
+ */
+void XMLRPC_SetValueBoolean(XMLRPC_VALUE value, int val) {
+ if(value) {
+ value->type = xmlrpc_boolean;
+ value->i = val ? 1 : 0;
+ }
+}
+
+/*******/
+
+
+/****f* VECTOR/XMLRPC_SetIsVector
+ * NAME
+ * XMLRPC_SetIsVector
+ * SYNOPSIS
+ * int XMLRPC_SetIsVector(XMLRPC_VALUE value, XMLRPC_VECTOR_TYPE type)
+ * FUNCTION
+ * Set the XMLRPC_VALUE to be a vector (list) type. The vector may be one of
+ * [xmlrpc_array | xmlrpc_struct | xmlrpc_mixed]. An array has only index values.
+ * A struct has key/val pairs. Mixed allows both index and key/val combinations.
+ * INPUTS
+ * value The xml value who's vector type we will set
+ * type New type of vector as enumerated by XMLRPC_VECTOR_TYPE
+ * RESULT
+ * int 1 if successful, 0 otherwise
+ * SEE ALSO
+ * XMLRPC_GetValueType ()
+ * XMLRPC_GetVectorType ()
+ * XMLRPC_VALUE
+ * XMLRPC_VECTOR_TYPE
+ * XMLRPC_VALUE_TYPE
+ * SOURCE
+ */
+int XMLRPC_SetIsVector(XMLRPC_VALUE value, XMLRPC_VECTOR_TYPE type) {
+ int bSuccess = 0;
+
+ if (value) {
+ /* we can change the type so long as nothing is currently stored. */
+ if(value->type == xmlrpc_vector) {
+ if(value->v) {
+ if(!Q_Size(value->v->q)) {
+ value->v->type = type;
+ }
+ }
+ }
+ else {
+ value->v = calloc(1, sizeof(STRUCT_XMLRPC_VECTOR));
+ if(value->v) {
+ value->v->q = (queue*)malloc(sizeof(queue));
+ if(value->v->q) {
+ Q_Init(value->v->q);
+ value->v->type = type;
+ value->type = xmlrpc_vector;
+ bSuccess = 1;
+ }
+ }
+ }
+ }
+
+ return bSuccess;
+}
+
+/*******/
+
+/****f* VECTOR/XMLRPC_CreateVector
+ * NAME
+ * XMLRPC_CreateVector
+ * SYNOPSIS
+ * XMLRPC_VALUE XMLRPC_CreateVector(const char* id, XMLRPC_VECTOR_TYPE type)
+ * FUNCTION
+ * Create a new vector and optionally set an id.
+ * INPUTS
+ * id The id of the vector, or NULL
+ * type New type of vector as enumerated by XMLRPC_VECTOR_TYPE
+ * RESULT
+ * XMLRPC_VALUE The new vector, or NULL on failure.
+ * SEE ALSO
+ * XMLRPC_CreateValueEmpty ()
+ * XMLRPC_SetIsVector ()
+ * XMLRPC_GetValueType ()
+ * XMLRPC_GetVectorType ()
+ * XMLRPC_VALUE
+ * XMLRPC_VECTOR_TYPE
+ * XMLRPC_VALUE_TYPE
+ * SOURCE
+ */
+XMLRPC_VALUE XMLRPC_CreateVector(const char* id, XMLRPC_VECTOR_TYPE type) {
+ XMLRPC_VALUE val = NULL;
+
+ val = XMLRPC_CreateValueEmpty();
+ if(val) {
+ if(XMLRPC_SetIsVector(val, type)) {
+ if(id) {
+ const char *pSVI = NULL;
+
+ pSVI = XMLRPC_SetValueID(val, id, 0);
+ if(NULL == pSVI) {
+ val = NULL;
+ }
+ }
+ }
+ else {
+ val = NULL;
+ }
+ }
+ return val;
+}
+
+/*******/
+
+
+/* Not yet implemented.
+ *
+ * This should use a hash to determine if a given target id has already
+ * been appended.
+ *
+ * Alternately, it could walk the entire vector, but that could be quite
+ * slow for very large lists.
+ */
+static int isDuplicateEntry(XMLRPC_VALUE target, XMLRPC_VALUE source) {
+ return 0;
+}
+
+/****f* VECTOR/XMLRPC_AddValueToVector
+ * NAME
+ * XMLRPC_AddValueToVector
+ * SYNOPSIS
+ * int XMLRPC_AddValueToVector(XMLRPC_VALUE target, XMLRPC_VALUE source)
+ * FUNCTION
+ * Add (append) an existing XMLRPC_VALUE to a vector.
+ * INPUTS
+ * target The target vector
+ * source The source value to append
+ * RESULT
+ * int 1 if successful, else 0
+ * SEE ALSO
+ * XMLRPC_AddValuesToVector ()
+ * XMLRPC_VectorGetValueWithID_Case ()
+ * XMLRPC_VALUE
+ * NOTES
+ * The function will fail and return 0 if an attempt is made to add
+ * a value with an ID into a vector of type xmlrpc_vector_array. Such
+ * values can only be added to xmlrpc_vector_struct.
+ * SOURCE
+ */
+int XMLRPC_AddValueToVector(XMLRPC_VALUE target, XMLRPC_VALUE source) {
+ if(target && source) {
+ if(target->type == xmlrpc_vector && target->v &&
+ target->v->q && target->v->type != xmlrpc_vector_none) {
+
+ /* guard against putting value of unknown type into vector */
+ switch(source->type) {
+ case xmlrpc_empty:
+ case xmlrpc_base64:
+ case xmlrpc_boolean:
+ case xmlrpc_datetime:
+ case xmlrpc_double:
+ case xmlrpc_int:
+ case xmlrpc_string:
+ case xmlrpc_vector:
+ /* Guard against putting a key/val pair into an array vector */
+ if( !(source->id.len && target->v->type == xmlrpc_vector_array) ) {
+ if (isDuplicateEntry (target, source)
+ || Q_PushTail (target->v->q, XMLRPC_CopyValue (source))) {
+ return 1;
+ }
+ }
+ else {
+ /* fprintf (stderr,
+ "xmlrpc: attempted to add key/val pair to vector of type array\n"); */
+ }
+ break;
+ default:
+ /* fprintf (stderr,
+ "xmlrpc: attempted to add value of unknown type to vector\n"); */
+ break;
+ }
+ }
+ }
+ return 0;
+}
+
+/*******/
+
+
+/****f* VECTOR/XMLRPC_AddValuesToVector
+ * NAME
+ * XMLRPC_AddValuesToVector
+ * SYNOPSIS
+ * XMLRPC_AddValuesToVector ( target, val1, val2, val3, val(n), 0 )
+ * XMLRPC_AddValuesToVector( XMLRPC_VALUE, ... )
+ * FUNCTION
+ * Add (append) a series of existing XMLRPC_VALUE to a vector.
+ * INPUTS
+ * target The target vector
+ * ... The source value(s) to append. The last item *must* be 0.
+ * RESULT
+ * int 1 if successful, else 0
+ * SEE ALSO
+ * XMLRPC_AddValuesToVector ()
+ * XMLRPC_VectorGetValueWithID_Case ()
+ * XMLRPC_VALUE
+ * NOTES
+ * This function may actually return failure after it has already modified
+ * or added items to target. You can not trust the state of target
+ * if this function returns failure.
+ * SOURCE
+ */
+int XMLRPC_AddValuesToVector(XMLRPC_VALUE target, ...) {
+ int iRetval = 0;
+
+ if(target) {
+ if(target->type == xmlrpc_vector) {
+ XMLRPC_VALUE v = NULL;
+ va_list vl;
+
+ va_start(vl, target);
+
+ do {
+ v = va_arg(vl, XMLRPC_VALUE);
+ if(v) {
+ if(!XMLRPC_AddValueToVector(target, v)) {
+ iRetval = 0;
+ break;
+ }
+ }
+ }
+ while (v);
+
+ va_end(vl);
+
+ if(NULL == v) {
+ iRetval = 1;
+ }
+ }
+ }
+ return iRetval;
+}
+
+/*******/
+
+
+/****f* VECTOR/XMLRPC_VectorGetValueWithID_Case
+ * NAME
+ * XMLRPC_VectorGetValueWithID_Case
+ * SYNOPSIS
+ * XMLRPC_VALUE XMLRPC_VectorGetValueWithID_Case(XMLRPC_VALUE vector, const char* id, XMLRPC_CASE_COMPARISON id_case)
+ * FUNCTION
+ * Get value from vector matching id (key)
+ * INPUTS
+ * vector The source vector
+ * id The key to find
+ * id_case Rule for how to match key
+ * RESULT
+ * int 1 if successful, else 0
+ * SEE ALSO
+ * XMLRPC_SetValueID_Case ()
+ * XMLRPC_VALUE
+ * XMLRPC_CASE_COMPARISON
+ * SOURCE
+ */
+XMLRPC_VALUE XMLRPC_VectorGetValueWithID_Case (XMLRPC_VALUE vector, const char *id,
+ XMLRPC_CASE_COMPARISON id_case) {
+ if(vector && vector->v && vector->v->q) {
+ q_iter qi = Q_Iter_Head_F(vector->v->q);
+
+ while(qi) {
+ XMLRPC_VALUE xIter = Q_Iter_Get_F(qi);
+ if(xIter && xIter->id.str) {
+ if(id_case == xmlrpc_case_sensitive) {
+ if(!strcmp(xIter->id.str, id)) {
+ return xIter;
+ }
+ }
+ else if(id_case == xmlrpc_case_insensitive) {
+ if(!strcasecmp(xIter->id.str, id)) {
+ return xIter;
+ }
+ }
+ }
+ qi = Q_Iter_Next_F(qi);
+ }
+ }
+ return NULL;
+}
+
+/*******/
+
+
+int XMLRPC_VectorRemoveValue(XMLRPC_VALUE vector, XMLRPC_VALUE value) {
+ if(vector && vector->v && vector->v->q && value) {
+ q_iter qi = Q_Iter_Head_F(vector->v->q);
+
+ while(qi) {
+ XMLRPC_VALUE xIter = Q_Iter_Get_F(qi);
+ if(xIter == value) {
+ XMLRPC_CleanupValue(xIter);
+ Q_Iter_Del(vector->v->q, qi);
+ return 1;
+ }
+ qi = Q_Iter_Next_F(qi);
+ }
+ }
+ return 0;
+}
+
+
+/****f* VALUE/XMLRPC_CreateValueString
+ * NAME
+ * XMLRPC_CreateValueString
+ * SYNOPSIS
+ * XMLRPC_VALUE XMLRPC_CreateValueString(const char* id, const char* val, int len)
+ * FUNCTION
+ * Create an XMLRPC_VALUE, and assign a string to it
+ * INPUTS
+ * id The id of the value, or NULL
+ * val The desired new string val.
+ * len length of val string if known, or 0 if unknown.
+ * RESULT
+ * newly allocated XMLRPC_VALUE, or NULL
+ * SEE ALSO
+ * XMLRPC_GetValueString ()
+ * XMLRPC_CreateValueEmpty ()
+ * XMLRPC_VALUE
+ * XMLRPC_VALUE_TYPE
+ * SOURCE
+ */
+XMLRPC_VALUE XMLRPC_CreateValueString(const char* id, const char* val, int len) {
+ XMLRPC_VALUE value = NULL;
+ if(val) {
+ value = XMLRPC_CreateValueEmpty();
+ if(value) {
+ XMLRPC_SetValueString(value, val, len);
+ if(id) {
+ XMLRPC_SetValueID(value, id, 0);
+ }
+ }
+ }
+ return value;
+}
+
+/*******/
+
+/****f* VALUE/XMLRPC_CreateValueInt
+ * NAME
+ * XMLRPC_CreateValueInt
+ * SYNOPSIS
+ * XMLRPC_VALUE XMLRPC_CreateValueInt(const char* id, int i)
+ * FUNCTION
+ * Create an XMLRPC_VALUE, and assign an int to it
+ * INPUTS
+ * id The id of the value, or NULL
+ * i The desired new int val.
+ * RESULT
+ * newly allocated XMLRPC_VALUE, or NULL
+ * SEE ALSO
+ * XMLRPC_GetValueInt ()
+ * XMLRPC_CreateValueEmpty ()
+ * XMLRPC_VALUE
+ * XMLRPC_VALUE_TYPE
+ * SOURCE
+ */
+XMLRPC_VALUE XMLRPC_CreateValueInt(const char* id, int i) {
+ XMLRPC_VALUE val = XMLRPC_CreateValueEmpty();
+ if(val) {
+ XMLRPC_SetValueInt(val, i);
+ if(id) {
+ XMLRPC_SetValueID(val, id, 0);
+ }
+ }
+ return val;
+}
+
+/*******/
+
+/****f* VALUE/XMLRPC_CreateValueBoolean
+ * NAME
+ * XMLRPC_CreateValueBoolean
+ * SYNOPSIS
+ * XMLRPC_VALUE XMLRPC_CreateValueBoolean(const char* id, int i)
+ * FUNCTION
+ * Create an XMLRPC_VALUE, and assign an int to it
+ * INPUTS
+ * id The id of the value, or NULL
+ * i The desired new int val.
+ * RESULT
+ * newly allocated XMLRPC_VALUE, or NULL
+ * SEE ALSO
+ * XMLRPC_GetValueBoolean ()
+ * XMLRPC_CreateValueEmpty ()
+ * XMLRPC_VALUE
+ * XMLRPC_VALUE_TYPE
+ * SOURCE
+ */
+XMLRPC_VALUE XMLRPC_CreateValueBoolean(const char* id, int i) {
+ XMLRPC_VALUE val = XMLRPC_CreateValueEmpty();
+ if(val) {
+ XMLRPC_SetValueBoolean(val, i);
+ if(id) {
+ XMLRPC_SetValueID(val, id, 0);
+ }
+ }
+ return val;
+}
+
+/*******/
+
+
+/****f* VALUE/XMLRPC_CleanupValue
+ * NAME
+ * XMLRPC_CleanupValue
+ * SYNOPSIS
+ * void XMLRPC_CleanupValue(XMLRPC_VALUE value)
+ * FUNCTION
+ * Frees all memory allocated for an XMLRPC_VALUE and any of its children (if a vector)
+ * INPUTS
+ * value The id of the value to be cleaned up.
+ * RESULT
+ * void
+ * NOTES
+ * Normally this function will be called for the topmost vector, thus free-ing
+ * all children. If a child of a vector is free'd first, results are undefined.
+ * Failure to call this function *will* cause memory leaks.
+ *
+ * Also, this function is implemented using reference counting. Thus a value
+ * may be added and freed from multiple parents so long as a reference is added
+ * first using XMLRPC_CopyValue()
+ * SEE ALSO
+ * XMLRPC_RequestFree ()
+ * XMLRPC_CreateValueEmpty ()
+ * XMLRPC_CopyValue()
+ * XMLRPC_VALUE
+ * SOURCE
+ */
+void XMLRPC_CleanupValue(XMLRPC_VALUE value) {
+ if(value) {
+ if(value->iRefCount > 0) {
+ value->iRefCount --;
+ }
+
+#ifdef XMLRPC_DEBUG_REFCOUNT
+ if(value->id.str) {
+ printf ("decremented refcount of %s, now %i\n", value->id.str,
+ value->iRefCount);
+ }
+ else {
+ printf ("decremented refcount of 0x%x, now %i\n", value,
+ value->iRefCount);
+ }
+#endif
+
+ if(value->type == xmlrpc_vector) {
+ if(value->v) {
+ if(value->iRefCount == 0) {
+ XMLRPC_VALUE cur = (XMLRPC_VALUE)Q_Head(value->v->q);
+ while( cur ) {
+ XMLRPC_CleanupValue(cur);
+
+ /* Make sure some idiot didn't include a vector as a child of itself
+ * and thus it would have already free'd these.
+ */
+ if(value->v && value->v->q) {
+ cur = Q_Next(value->v->q);
+ }
+ else {
+ break;
+ }
+ }
+
+ Q_Destroy(value->v->q);
+ my_free(value->v->q);
+ my_free(value->v);
+ }
+ }
+ }
+
+
+ if(value->iRefCount == 0) {
+
+ /* guard against freeing invalid types */
+ switch(value->type) {
+ case xmlrpc_empty:
+ case xmlrpc_base64:
+ case xmlrpc_boolean:
+ case xmlrpc_datetime:
+ case xmlrpc_double:
+ case xmlrpc_int:
+ case xmlrpc_string:
+ case xmlrpc_vector:
+#ifdef XMLRPC_DEBUG_REFCOUNT
+ if(value->id.str) {
+ printf("free'd %s\n", value->id.str);
+ }
+ else {
+ printf("free'd 0x%x\n", value);
+ }
+#endif
+ simplestring_free(&value->id);
+ simplestring_free(&value->str);
+
+ memset(value, 0, sizeof(STRUCT_XMLRPC_VALUE));
+ my_free(value);
+ break;
+ default:
+ /* fprintf (stderr,
+ "xmlrpc: attempted to free value of invalid type\n"); */
+ break;
+ }
+ }
+ }
+}
+
+/*******/
+
+
+/****f* VALUE/XMLRPC_SetValueDateTime
+ * NAME
+ * XMLRPC_SetValueDateTime
+ * SYNOPSIS
+ * void XMLRPC_SetValueDateTime(XMLRPC_VALUE value, time_t time)
+ * FUNCTION
+ * Assign time value to XMLRPC_VALUE
+ * INPUTS
+ * value The target XMLRPC_VALUE
+ * time The desired new unix time value (time_t)
+ * RESULT
+ * void
+ * SEE ALSO
+ * XMLRPC_GetValueDateTime ()
+ * XMLRPC_SetValueDateTime_ISO8601 ()
+ * XMLRPC_CreateValueDateTime ()
+ * XMLRPC_VALUE
+ * SOURCE
+ */
+void XMLRPC_SetValueDateTime(XMLRPC_VALUE value, time_t time) {
+ if(value) {
+ char timeBuf[30];
+ value->type = xmlrpc_datetime;
+ value->i = time;
+
+ timeBuf[0] = 0;
+
+ date_to_ISO8601(time, timeBuf, sizeof(timeBuf));
+
+ if(timeBuf[0]) {
+ XMLRPC_SetValueDateTime_ISO8601 (value, timeBuf);
+ }
+ }
+}
+
+/*******/
+
+/****f* VALUE/XMLRPC_CopyValue
+ * NAME
+ * XMLRPC_CopyValue
+ * SYNOPSIS
+ * XMLRPC_VALUE XMLRPC_CopyValue(XMLRPC_VALUE value)
+ * FUNCTION
+ * Make a copy (reference) of an XMLRPC_VALUE
+ * INPUTS
+ * value The target XMLRPC_VALUE
+ * RESULT
+ * XMLRPC_VALUE -- address of the copy
+ * SEE ALSO
+ * XMLRPC_CleanupValue ()
+ * XMLRPC_DupValueNew ()
+ * NOTES
+ * This function is implemented via reference counting, so the
+ * returned value is going to be the same as the passed in value.
+ * The value must be freed the same number of times it is copied
+ * or there will be a memory leak.
+ * SOURCE
+ */
+XMLRPC_VALUE XMLRPC_CopyValue(XMLRPC_VALUE value) {
+ if(value) {
+ value->iRefCount ++;
+#ifdef XMLRPC_DEBUG_REFCOUNT
+ if(value->id.str) {
+ printf ("incremented refcount of %s, now %i\n", value->id.str,
+ value->iRefCount);
+ }
+ else {
+ printf ("incremented refcount of 0x%x, now %i\n", value,
+ value->iRefCount);
+ }
+#endif
+ }
+ return value;
+}
+
+/*******/
+
+
+/****f* VALUE/XMLRPC_DupValueNew
+ * NAME
+ * XMLRPC_DupValueNew
+ * SYNOPSIS
+ * XMLRPC_VALUE XMLRPC_DupValueNew(XMLRPC_VALUE value)
+ * FUNCTION
+ * Make a duplicate (non reference) of an XMLRPC_VALUE with newly allocated mem.
+ * INPUTS
+ * value The source XMLRPC_VALUE to duplicate
+ * RESULT
+ * XMLRPC_VALUE -- address of the duplicate value
+ * SEE ALSO
+ * XMLRPC_CleanupValue ()
+ * XMLRPC_CopyValue ()
+ * NOTES
+ * Use this when function when you need to modify the contents of
+ * the copied value seperately from the original.
+ *
+ * this function is recursive, thus the value and all of its children
+ * (if any) will be duplicated.
+ * SOURCE
+ */
+XMLRPC_VALUE XMLRPC_DupValueNew (XMLRPC_VALUE xSource) {
+ XMLRPC_VALUE xReturn = NULL;
+ if (xSource) {
+ xReturn = XMLRPC_CreateValueEmpty ();
+ if (xSource->id.len) {
+ XMLRPC_SetValueID (xReturn, xSource->id.str, xSource->id.len);
+ }
+
+ switch (xSource->type) {
+ case xmlrpc_int:
+ case xmlrpc_boolean:
+ XMLRPC_SetValueInt (xReturn, xSource->i);
+ break;
+ case xmlrpc_string:
+ case xmlrpc_base64:
+ XMLRPC_SetValueString (xReturn, xSource->str.str, xSource->str.len);
+ break;
+ case xmlrpc_datetime:
+ XMLRPC_SetValueDateTime (xReturn, xSource->i);
+ break;
+ case xmlrpc_double:
+ XMLRPC_SetValueDouble (xReturn, xSource->d);
+ break;
+ case xmlrpc_vector:
+ {
+ q_iter qi = Q_Iter_Head_F (xSource->v->q);
+ XMLRPC_SetIsVector (xReturn, xSource->v->type);
+
+ while (qi) {
+ XMLRPC_VALUE xIter = Q_Iter_Get_F (qi);
+ XMLRPC_AddValueToVector (xReturn, XMLRPC_DupValueNew (xIter));
+ qi = Q_Iter_Next_F (qi);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return xReturn;
+}
+
+/*******/
+
+
+
+/****f* VALUE/XMLRPC_CreateValueDateTime
+ * NAME
+ * XMLRPC_CreateValueDateTime
+ * SYNOPSIS
+ * XMLRPC_VALUE XMLRPC_CreateValueDateTime(const char* id, time_t time)
+ * FUNCTION
+ * Create new datetime value from time_t
+ * INPUTS
+ * id id of the new value, or NULL
+ * time The desired unix time value (time_t)
+ * RESULT
+ * void
+ * SEE ALSO
+ * XMLRPC_GetValueDateTime ()
+ * XMLRPC_SetValueDateTime ()
+ * XMLRPC_CreateValueDateTime_ISO8601 ()
+ * XMLRPC_VALUE
+ * SOURCE
+ */
+XMLRPC_VALUE XMLRPC_CreateValueDateTime(const char* id, time_t time) {
+ XMLRPC_VALUE val = XMLRPC_CreateValueEmpty();
+ if(val) {
+ XMLRPC_SetValueDateTime(val, time);
+ if(id) {
+ XMLRPC_SetValueID(val, id, 0);
+ }
+ }
+ return val;
+}
+
+/*******/
+
+
+/****f* VALUE/XMLRPC_SetValueDateTime_ISO8601
+ * NAME
+ * XMLRPC_SetValueDateTime_ISO8601
+ * SYNOPSIS
+ * void XMLRPC_SetValueDateTime_ISO8601(XMLRPC_VALUE value, const char* s)
+ * FUNCTION
+ * Set datetime value from IS08601 encoded string
+ * INPUTS
+ * value The target XMLRPC_VALUE
+ * s The desired new time value
+ * RESULT
+ * void
+ * BUGS
+ * This function currently attempts to convert the time string to a valid unix time
+ * value before passing it. Behavior when the string is invalid or out of range
+ * is not well defined, but will probably result in Jan 1, 1970 (0) being passed.
+ * SEE ALSO
+ * XMLRPC_GetValueDateTime_ISO8601 ()
+ * XMLRPC_CreateValueDateTime_ISO8601 ()
+ * XMLRPC_CreateValueDateTime ()
+ * XMLRPC_VALUE
+ * SOURCE
+ */
+void XMLRPC_SetValueDateTime_ISO8601(XMLRPC_VALUE value, const char* s) {
+ if(value) {
+ time_t time_val = 0;
+ if(s) {
+ value->type = xmlrpc_datetime;
+ date_from_ISO8601(s, &time_val);
+ value->i = time_val;
+ simplestring_clear(&value->str);
+ simplestring_add(&value->str, s);
+ }
+ }
+}
+
+/*******/
+
+/****f* VALUE/XMLRPC_CreateValueDateTime_ISO8601
+ * NAME
+ * XMLRPC_CreateValueDateTime_ISO8601
+ * SYNOPSIS
+ * XMLRPC_VALUE XMLRPC_CreateValueDateTime_ISO8601(const char* id, const char *s)
+ * FUNCTION
+ * Create datetime value from IS08601 encoded string
+ * INPUTS
+ * id The id of the new value, or NULL
+ * s The desired new time value
+ * RESULT
+ * newly allocated XMLRPC_VALUE, or NULL if no value created.
+ * BUGS
+ * See XMLRPC_SetValueDateTime_ISO8601 ()
+ * SEE ALSO
+ * XMLRPC_GetValueDateTime_ISO8601 ()
+ * XMLRPC_SetValueDateTime_ISO8601 ()
+ * XMLRPC_CreateValueDateTime ()
+ * XMLRPC_VALUE
+ * SOURCE
+ */
+XMLRPC_VALUE XMLRPC_CreateValueDateTime_ISO8601(const char* id, const char *s) {
+ XMLRPC_VALUE val = XMLRPC_CreateValueEmpty();
+ if(val) {
+ XMLRPC_SetValueDateTime_ISO8601(val, s);
+ if(id) {
+ XMLRPC_SetValueID(val, id, 0);
+ }
+ }
+ return val;
+}
+
+/*******/
+
+
+/****f* VALUE/XMLRPC_SetValueBase64
+ * NAME
+ * XMLRPC_SetValueBase64
+ * SYNOPSIS
+ * void XMLRPC_SetValueBase64(XMLRPC_VALUE value, const char* s, int len)
+ * FUNCTION
+ * Set base64 value. Base64 is useful for transferring binary data, such as an image.
+ * INPUTS
+ * value The target XMLRPC_VALUE
+ * s The desired new binary value
+ * len The length of s, or NULL. If buffer is not null terminated, len *must* be passed.
+ * RESULT
+ * void
+ * NOTES
+ * Data is set/stored/retrieved as passed in, but is base64 encoded for XML transfer, and
+ * decoded on the other side. This is transparent to the caller.
+ * SEE ALSO
+ * XMLRPC_GetValueBase64 ()
+ * XMLRPC_CreateValueBase64 ()
+ * XMLRPC_VALUE
+ * SOURCE
+ */
+void XMLRPC_SetValueBase64(XMLRPC_VALUE value, const char* s, int len) {
+ if(value && s) {
+ simplestring_clear(&value->str);
+ (len > 0) ? simplestring_addn(&value->str, s, len) :
+ simplestring_add(&value->str, s);
+ value->type = xmlrpc_base64;
+ }
+}
+
+/*******/
+
+
+/****f* VALUE/XMLRPC_CreateValueBase64
+ * NAME
+ * XMLRPC_CreateValueBase64
+ * SYNOPSIS
+ * XMLRPC_VALUE XMLRPC_CreateValueBase64(const char* id, const char* s, int len)
+ * FUNCTION
+ * Create base64 value. Base64 is useful for transferring binary data, such as an image.
+ * INPUTS
+ * id id of the new value, or NULL
+ * s The desired new binary value
+ * len The length of s, or NULL. If buffer is not null terminated, len *must* be passed.
+ * RESULT
+ * newly allocated XMLRPC_VALUE, or NULL if error
+ * NOTES
+ * See XMLRPC_SetValueBase64 ()
+ * SEE ALSO
+ * XMLRPC_GetValueBase64 ()
+ * XMLRPC_SetValueBase64 ()
+ * XMLRPC_VALUE
+ * SOURCE
+ */
+XMLRPC_VALUE XMLRPC_CreateValueBase64(const char* id, const char* s, int len) {
+ XMLRPC_VALUE val = XMLRPC_CreateValueEmpty();
+ if(val) {
+ XMLRPC_SetValueBase64(val, s, len);
+ if(id) {
+ XMLRPC_SetValueID(val, id, 0);
+ }
+ }
+ return val;
+}
+
+/*******/
+
+/****f* VALUE/XMLRPC_SetValueDouble
+ * NAME
+ * XMLRPC_SetValueDouble
+ * SYNOPSIS
+ * void XMLRPC_SetValueDouble(XMLRPC_VALUE value, double val)
+ * FUNCTION
+ * Set double (floating point) value.
+ * INPUTS
+ * value The target XMLRPC_VALUE
+ * val The desired new double value
+ * RESULT
+ * void
+ * SEE ALSO
+ * XMLRPC_GetValueDouble ()
+ * XMLRPC_CreateValueDouble ()
+ * XMLRPC_VALUE
+ * SOURCE
+ */
+void XMLRPC_SetValueDouble(XMLRPC_VALUE value, double val) {
+ if(value) {
+ value->type = xmlrpc_double;
+ value->d = val;
+ }
+}
+
+/*******/
+
+/****f* VALUE/XMLRPC_CreateValueDouble
+ * NAME
+ * XMLRPC_CreateValueDouble
+ * SYNOPSIS
+ * XMLRPC_VALUE XMLRPC_CreateValueDouble(const char* id, double d)
+ * FUNCTION
+ * Create double (floating point) value.
+ * INPUTS
+ * id id of the newly created value, or NULL
+ * d The desired new double value
+ * RESULT
+ * void
+ * SEE ALSO
+ * XMLRPC_GetValueDouble ()
+ * XMLRPC_CreateValueDouble ()
+ * XMLRPC_VALUE
+ * SOURCE
+ */
+XMLRPC_VALUE XMLRPC_CreateValueDouble(const char* id, double d) {
+ XMLRPC_VALUE val = XMLRPC_CreateValueEmpty();
+ if(val) {
+ XMLRPC_SetValueDouble(val, d);
+ if(id) {
+ XMLRPC_SetValueID(val, id, 0);
+ }
+ }
+ return val;
+}
+
+/*******/
+
+/****f* VALUE/XMLRPC_GetValueString
+ * NAME
+ * XMLRPC_GetValueString
+ * SYNOPSIS
+ * const char* XMLRPC_GetValueString(XMLRPC_VALUE value)
+ * FUNCTION
+ * retrieve string value
+ * INPUTS
+ * value source XMLRPC_VALUE of type xmlrpc_string
+ * RESULT
+ * void
+ * SEE ALSO
+ * XMLRPC_SetValueString ()
+ * XMLRPC_GetValueType ()
+ * XMLRPC_VALUE
+ * SOURCE
+ */
+const char* XMLRPC_GetValueString(XMLRPC_VALUE value) {
+ return ((value && value->type == xmlrpc_string) ? value->str.str : 0);
+}
+
+/*******/
+
+/****f* VALUE/XMLRPC_GetValueStringLen
+ * NAME
+ * XMLRPC_GetValueStringLen
+ * SYNOPSIS
+ * int XMLRPC_GetValueStringLen(XMLRPC_VALUE value)
+ * FUNCTION
+ * determine length of string value
+ * INPUTS
+ * value XMLRPC_VALUE of type xmlrpc_string
+ * RESULT
+ * length of string, or 0
+ * NOTES
+ * SEE ALSO
+ * XMLRPC_SetValueString ()
+ * XMLRPC_GetValueString ()
+ * SOURCE
+ */
+int XMLRPC_GetValueStringLen(XMLRPC_VALUE value) {
+ return ((value) ? value->str.len : 0);
+}
+
+/*******/
+
+/****f* VALUE/XMLRPC_GetValueInt
+ * NAME
+ * XMLRPC_GetValueInt
+ * SYNOPSIS
+ * int XMLRPC_GetValueInt(XMLRPC_VALUE value)
+ * FUNCTION
+ * retrieve integer value.
+ * INPUTS
+ * value XMLRPC_VALUE of type xmlrpc_int
+ * RESULT
+ * integer value or 0 if value is not valid int
+ * NOTES
+ * use XMLRPC_GetValueType () to be sure if 0 is real return value or not
+ * SEE ALSO
+ * XMLRPC_SetValueInt ()
+ * XMLRPC_CreateValueInt ()
+ * SOURCE
+ */
+int XMLRPC_GetValueInt(XMLRPC_VALUE value) {
+ return ((value && value->type == xmlrpc_int) ? value->i : 0);
+}
+
+/*******/
+
+/****f* VALUE/XMLRPC_GetValueBoolean
+ * NAME
+ * XMLRPC_GetValueBoolean
+ * SYNOPSIS
+ * int XMLRPC_GetValueBoolean(XMLRPC_VALUE value)
+ * FUNCTION
+ * retrieve boolean value.
+ * INPUTS
+ * XMLRPC_VALUE of type xmlrpc_boolean
+ * RESULT
+ * boolean value or 0 if value is not valid boolean
+ * NOTES
+ * use XMLRPC_GetValueType() to be sure if 0 is real value or not
+ * SEE ALSO
+ * XMLRPC_SetValueBoolean ()
+ * XMLRPC_CreateValueBoolean ()
+ * SOURCE
+ */
+int XMLRPC_GetValueBoolean(XMLRPC_VALUE value) {
+ return ((value && value->type == xmlrpc_boolean) ? value->i : 0);
+}
+
+/*******/
+
+/****f* VALUE/XMLRPC_GetValueDouble
+ * NAME
+ * XMLRPC_GetValueDouble
+ * SYNOPSIS
+ * double XMLRPC_GetValueDouble(XMLRPC_VALUE value)
+ * FUNCTION
+ * retrieve double value
+ * INPUTS
+ * XMLRPC_VALUE of type xmlrpc_double
+ * RESULT
+ * double value or 0 if value is not valid double.
+ * NOTES
+ * use XMLRPC_GetValueType() to be sure if 0 is real value or not
+ * SEE ALSO
+ * XMLRPC_SetValueDouble ()
+ * XMLRPC_CreateValueDouble ()
+ * SOURCE
+ */
+double XMLRPC_GetValueDouble(XMLRPC_VALUE value) {
+ return ((value && value->type == xmlrpc_double) ? value->d : 0);
+}
+
+/*******/
+
+/****f* VALUE/XMLRPC_GetValueBase64
+ * NAME
+ * XMLRPC_GetValueBase64
+ * SYNOPSIS
+ * const char* XMLRPC_GetValueBase64(XMLRPC_VALUE value)
+ * FUNCTION
+ * retrieve binary value
+ * INPUTS
+ * XMLRPC_VALUE of type xmlrpc_base64
+ * RESULT
+ * pointer to binary value or 0 if value is not valid.
+ * SEE ALSO
+ * XMLRPC_SetValueBase64 ()
+ * XMLRPC_CreateValueBase64 ()
+ * NOTES
+ * Call XMLRPC_GetValueStringLen() to retrieve real length of binary data. strlen()
+ * will not be accurate, as returned data may contain embedded nulls.
+ * SOURCE
+ */
+const char* XMLRPC_GetValueBase64(XMLRPC_VALUE value) {
+ return ((value && value->type == xmlrpc_base64) ? value->str.str : 0);
+}
+
+/*******/
+
+/****f* VALUE/XMLRPC_GetValueDateTime
+ * NAME
+ * XMLRPC_GetValueDateTime
+ * SYNOPSIS
+ * time_t XMLRPC_GetValueDateTime(XMLRPC_VALUE value)
+ * FUNCTION
+ * retrieve time_t value
+ * INPUTS
+ * XMLRPC_VALUE of type xmlrpc_datetime
+ * RESULT
+ * time_t value or 0 if value is not valid datetime.
+ * NOTES
+ * use XMLRPC_GetValueType() to be sure if 0 is real value or not
+ * SEE ALSO
+ * XMLRPC_SetValueDateTime ()
+ * XMLRPC_GetValueDateTime_ISO8601 ()
+ * XMLRPC_CreateValueDateTime ()
+ * SOURCE
+ */
+time_t XMLRPC_GetValueDateTime(XMLRPC_VALUE value) {
+ return (time_t)((value && value->type == xmlrpc_datetime) ? value->i : 0);
+}
+
+/*******/
+
+/****f* VALUE/XMLRPC_GetValueDateTime_IOS8601
+ * NAME
+ * XMLRPC_GetValueDateTime_IOS8601
+ * SYNOPSIS
+ * const char* XMLRPC_GetValueDateTime_IOS8601(XMLRPC_VALUE value)
+ * FUNCTION
+ * retrieve ISO8601 formatted time value
+ * INPUTS
+ * XMLRPC_VALUE of type xmlrpc_datetime
+ * RESULT
+ * const char* value or 0 if value is not valid datetime.
+ * SEE ALSO
+ * XMLRPC_SetValueDateTime_IOS8601 ()
+ * XMLRPC_GetValueDateTime ()
+ * XMLRPC_CreateValueDateTime_IOS8601 ()
+ * SOURCE
+ */
+const char* XMLRPC_GetValueDateTime_ISO8601(XMLRPC_VALUE value) {
+ return ((value && value->type == xmlrpc_datetime) ? value->str.str : 0);
+}
+
+/*******/
+
+/* Get ID (key) of value or NULL */
+/****f* VALUE/XMLRPC_GetValueID
+ * NAME
+ * XMLRPC_GetValueID
+ * SYNOPSIS
+ * const char* XMLRPC_GetValueID(XMLRPC_VALUE value)
+ * FUNCTION
+ * retrieve id (key) of value
+ * INPUTS
+ * XMLRPC_VALUE of any type
+ * RESULT
+ * const char* pointer to id of value, or NULL
+ * NOTES
+ * SEE ALSO
+ * XMLRPC_SetValueID()
+ * XMLRPC_CreateValueEmpty()
+ * SOURCE
+ */
+const char* XMLRPC_GetValueID(XMLRPC_VALUE value) {
+ return (const char*)((value && value->id.len) ? value->id.str : 0);
+}
+
+/*******/
+
+
+/****f* VECTOR/XMLRPC_VectorSize
+ * NAME
+ * XMLRPC_VectorSize
+ * SYNOPSIS
+ * int XMLRPC_VectorSize(XMLRPC_VALUE value)
+ * FUNCTION
+ * retrieve size of vector
+ * INPUTS
+ * XMLRPC_VALUE of type xmlrpc_vector
+ * RESULT
+ * count of items in vector
+ * NOTES
+ * This is a cheap operation even on large vectors. Vector size is
+ * maintained by queue during add/remove ops.
+ * SEE ALSO
+ * XMLRPC_AddValueToVector ()
+ * SOURCE
+ */
+int XMLRPC_VectorSize(XMLRPC_VALUE value) {
+ int size = 0;
+ if(value && value->type == xmlrpc_vector && value->v) {
+ size = Q_Size(value->v->q);
+ }
+ return size;
+}
+
+/*******/
+
+/****f* VECTOR/XMLRPC_VectorRewind
+ * NAME
+ * XMLRPC_VectorRewind
+ * SYNOPSIS
+ * XMLRPC_VALUE XMLRPC_VectorRewind(XMLRPC_VALUE value)
+ * FUNCTION
+ * reset vector to first item
+ * INPUTS
+ * XMLRPC_VALUE of type xmlrpc_vector
+ * RESULT
+ * first XMLRPC_VALUE in list, or NULL if empty or error.
+ * NOTES
+ * Be careful to rewind any vector passed in to you if you expect to
+ * iterate through the entire list.
+ * SEE ALSO
+ * XMLRPC_VectorNext ()
+ * SOURCE
+ */
+XMLRPC_VALUE XMLRPC_VectorRewind(XMLRPC_VALUE value) {
+ XMLRPC_VALUE xReturn = NULL;
+ if(value && value->type == xmlrpc_vector && value->v) {
+ xReturn = (XMLRPC_VALUE)Q_Head(value->v->q);
+ }
+ return xReturn;
+}
+
+/*******/
+
+/****f* VECTOR/XMLRPC_VectorNext
+ * NAME
+ * XMLRPC_VectorNext
+ * SYNOPSIS
+ * XMLRPC_VALUE XMLRPC_VectorNext(XMLRPC_VALUE value)
+ * FUNCTION
+ * Iterate vector to next item in list.
+ * INPUTS
+ * XMLRPC_VALUE of type xmlrpc_vector
+ * RESULT
+ * Next XMLRPC_VALUE in vector, or NULL if at end.
+ * NOTES
+ * SEE ALSO
+ * XMLRPC_VectorRewind ()
+ * SOURCE
+ */
+XMLRPC_VALUE XMLRPC_VectorNext(XMLRPC_VALUE value) {
+ XMLRPC_VALUE xReturn = NULL;
+ if(value && value->type == xmlrpc_vector && value->v) {
+ xReturn = (XMLRPC_VALUE)Q_Next(value->v->q);
+ }
+ return xReturn;
+}
+
+/*******/
+
+/****f* VALUE/XMLRPC_GetValueType
+ * NAME
+ * XMLRPC_GetValueType
+ * SYNOPSIS
+ * XMLRPC_VALUE_TYPE XMLRPC_GetValueType(XMLRPC_VALUE value)
+ * FUNCTION
+ * determine data type of the XMLRPC_VALUE
+ * INPUTS
+ * XMLRPC_VALUE target of query
+ * RESULT
+ * data type of value as enumerated by XMLRPC_VALUE_TYPE
+ * NOTES
+ * all values are of type xmlrpc_empty until set.
+ * Deprecated for public use. See XMLRPC_GetValueTypeEasy
+ * SEE ALSO
+ * XMLRPC_SetValue*
+ * XMLRPC_CreateValue*
+ * XMLRPC_Append*
+ * XMLRPC_GetValueTypeEasy ()
+ * SOURCE
+ */
+XMLRPC_VALUE_TYPE XMLRPC_GetValueType(XMLRPC_VALUE value) {
+ return value ? value->type : xmlrpc_empty;
+}
+
+/*******/
+
+/* Vector type accessor */
+/****f* VALUE/XMLRPC_GetVectorType
+ * NAME
+ * XMLRPC_GetVectorType
+ * SYNOPSIS
+ * XMLRPC_VECTOR_TYPE XMLRPC_GetVectorType(XMLRPC_VALUE value)
+ * FUNCTION
+ * determine vector type of the XMLRPC_VALUE
+ * INPUTS
+ * XMLRPC_VALUE of type xmlrpc_vector
+ * RESULT
+ * vector type of value as enumerated by XMLRPC_VECTOR_TYPE.
+ * xmlrpc_none if not a value.
+ * NOTES
+ * xmlrpc_none is returned if value is not a vector
+ * Deprecated for public use. See XMLRPC_GetValueTypeEasy
+ * SEE ALSO
+ * XMLRPC_SetIsVector ()
+ * XMLRPC_GetValueType ()
+ * XMLRPC_GetValueTypeEasy ()
+ * SOURCE
+ */
+XMLRPC_VECTOR_TYPE XMLRPC_GetVectorType(XMLRPC_VALUE value) {
+ return(value && value->v) ? value->v->type : xmlrpc_none;
+}
+
+/*******/
+
+/****f* VALUE/XMLRPC_GetValueTypeEasy
+ * NAME
+ * XMLRPC_GetValueTypeEasy
+ * SYNOPSIS
+ * XMLRPC_VALUE_TYPE_EASY XMLRPC_GetValueTypeEasy(XMLRPC_VALUE value)
+ * FUNCTION
+ * determine data type of the XMLRPC_VALUE. includes vector types.
+ * INPUTS
+ * XMLRPC_VALUE target of query
+ * RESULT
+ * data type of value as enumerated by XMLRPC_VALUE_TYPE_EASY
+ * xmlrpc_type_none if not a value.
+ * NOTES
+ * all values are of type xmlrpc_type_empty until set.
+ * SEE ALSO
+ * XMLRPC_SetValue*
+ * XMLRPC_CreateValue*
+ * XMLRPC_Append*
+ * SOURCE
+ */
+XMLRPC_VALUE_TYPE_EASY XMLRPC_GetValueTypeEasy (XMLRPC_VALUE value) {
+ if (value) {
+ switch (value->type) {
+ case xmlrpc_vector:
+ switch (value->v->type) {
+ case xmlrpc_vector_none:
+ return xmlrpc_type_none;
+ case xmlrpc_vector_struct:
+ return xmlrpc_type_struct;
+ case xmlrpc_vector_mixed:
+ return xmlrpc_type_mixed;
+ case xmlrpc_vector_array:
+ return xmlrpc_type_array;
+ }
+ default:
+ /* evil cast, but we know they are the same */
+ return(XMLRPC_VALUE_TYPE_EASY) value->type;
+ }
+ }
+ return xmlrpc_none;
+}
+
+/*******/
+
+
+
+/*-*******************
+* Begin Server Funcs *
+*********************/
+
+
+/****f* VALUE/XMLRPC_ServerCreate
+ * NAME
+ * XMLRPC_ServerCreate
+ * SYNOPSIS
+ * XMLRPC_SERVER XMLRPC_ServerCreate()
+ * FUNCTION
+ * Allocate/Init XMLRPC Server Resources.
+ * INPUTS
+ * none
+ * RESULT
+ * newly allocated XMLRPC_SERVER
+ * NOTES
+ * SEE ALSO
+ * XMLRPC_ServerDestroy ()
+ * XMLRPC_GetGlobalServer ()
+ * SOURCE
+ */
+XMLRPC_SERVER XMLRPC_ServerCreate() {
+ XMLRPC_SERVER server = calloc(1, sizeof(STRUCT_XMLRPC_SERVER));
+ if(server) {
+ Q_Init(&server->methodlist);
+ Q_Init(&server->docslist);
+
+ /* register system methods */
+ xsm_register(server);
+ }
+ return server;
+}
+
+/*******/
+
+/* Return global server. Not locking! Not Thread Safe! */
+/****f* VALUE/XMLRPC_GetGlobalServer
+ * NAME
+ * XMLRPC_GetGlobalServer
+ * SYNOPSIS
+ * XMLRPC_SERVER XMLRPC_GetGlobalServer()
+ * FUNCTION
+ * Allocates a global (process-wide) server, or returns pointer if pre-existing.
+ * INPUTS
+ * none
+ * RESULT
+ * pointer to global server, or 0 if error.
+ * NOTES
+ * ***WARNING*** This function is not thread safe. It is included only for the very lazy.
+ * Multi-threaded programs that use this may experience problems.
+ * BUGS
+ * There is currently no way to cleanup the global server gracefully.
+ * SEE ALSO
+ * XMLRPC_ServerCreate ()
+ * SOURCE
+ */
+XMLRPC_SERVER XMLRPC_GetGlobalServer() {
+ static XMLRPC_SERVER xsServer = 0;
+ if(!xsServer) {
+ xsServer = XMLRPC_ServerCreate();
+ }
+ return xsServer;
+}
+
+/*******/
+
+/****f* VALUE/XMLRPC_ServerDestroy
+ * NAME
+ * XMLRPC_ServerDestroy
+ * SYNOPSIS
+ * void XMLRPC_ServerDestroy(XMLRPC_SERVER server)
+ * FUNCTION
+ * Free Server Resources
+ * INPUTS
+ * server The server to be free'd
+ * RESULT
+ * void
+ * NOTES
+ * This frees the server struct and any methods that have been added.
+ * SEE ALSO
+ * XMLRPC_ServerCreate ()
+ * SOURCE
+ */
+void XMLRPC_ServerDestroy(XMLRPC_SERVER server) {
+ if(server) {
+ doc_method* dm = Q_Head(&server->docslist);
+ server_method* sm = Q_Head(&server->methodlist);
+ while( dm ) {
+ my_free(dm);
+ dm = Q_Next(&server->docslist);
+ }
+ while( sm ) {
+ if(sm->name) {
+ my_free(sm->name);
+ }
+ if(sm->desc) {
+ XMLRPC_CleanupValue(sm->desc);
+ }
+ my_free(sm);
+ sm = Q_Next(&server->methodlist);
+ }
+ if(server->xIntrospection) {
+ XMLRPC_CleanupValue(server->xIntrospection);
+ }
+
+ Q_Destroy(&server->methodlist);
+ Q_Destroy(&server->docslist);
+ my_free(server);
+ }
+}
+
+/*******/
+
+
+/****f* VALUE/XMLRPC_ServerRegisterMethod
+ * NAME
+ * XMLRPC_ServerRegisterMethod
+ * SYNOPSIS
+ * void XMLRPC_ServerRegisterMethod(XMLRPC_SERVER server, const char *name, XMLRPC_Callback cb)
+ * FUNCTION
+ * Register new XMLRPC method with server
+ * INPUTS
+ * server The XMLRPC_SERVER to register the method with
+ * name public name of the method
+ * cb C function that implements the method
+ * RESULT
+ * int - 1 if success, else 0
+ * NOTES
+ * A C function must be registered for every "method" that the server recognizes. The
+ * method name is equivalent to <methodCall><name> method name </name></methodCall> in the
+ * XML syntax.
+ * SEE ALSO
+ * XMLRPC_ServerFindMethod ()
+ * XMLRPC_ServerCallMethod ()
+ * SOURCE
+ */
+int XMLRPC_ServerRegisterMethod(XMLRPC_SERVER server, const char *name, XMLRPC_Callback cb) {
+ if(server && name && cb) {
+
+ server_method* sm = malloc(sizeof(server_method));
+
+ if(sm) {
+ sm->name = strdup(name);
+ sm->method = cb;
+ sm->desc = NULL;
+
+ return Q_PushTail(&server->methodlist, sm);
+ }
+ }
+ return 0;
+}
+
+/*******/
+
+server_method* find_method(XMLRPC_SERVER server, const char* name) {
+ server_method* sm;
+
+ q_iter qi = Q_Iter_Head_F(&server->methodlist);
+
+ while( qi ) {
+ sm = Q_Iter_Get_F(qi);
+ if(sm && !strcmp(sm->name, name)) {
+ return sm;
+ }
+ qi = Q_Iter_Next_F(qi);
+ }
+ return NULL;
+}
+
+
+const char* type_to_str(XMLRPC_VALUE_TYPE type, XMLRPC_VECTOR_TYPE vtype) {
+ switch(type) {
+ case xmlrpc_none:
+ return "none";
+ case xmlrpc_empty:
+ return "empty";
+ case xmlrpc_base64:
+ return "base64";
+ case xmlrpc_boolean:
+ return "boolean";
+ case xmlrpc_datetime:
+ return "datetime";
+ case xmlrpc_double:
+ return "double";
+ case xmlrpc_int:
+ return "int";
+ case xmlrpc_string:
+ return "string";
+ case xmlrpc_vector:
+ switch(vtype) {
+ case xmlrpc_vector_none:
+ return "none";
+ case xmlrpc_vector_array:
+ return "array";
+ case xmlrpc_vector_mixed:
+ return "mixed vector (struct)";
+ case xmlrpc_vector_struct:
+ return "struct";
+ }
+ }
+ return "unknown";
+}
+
+/****f* VALUE/XMLRPC_ServerFindMethod
+ * NAME
+ * XMLRPC_ServerFindMethod
+ * SYNOPSIS
+ * XMLRPC_Callback XMLRPC_ServerFindMethod(XMLRPC_SERVER server, const char* callName)
+ * FUNCTION
+ * retrieve C callback associated with a given method name.
+ * INPUTS
+ * server The XMLRPC_SERVER the method is registered with
+ * callName the method to find
+ * RESULT
+ * previously registered XMLRPC_Callback, or NULL
+ * NOTES
+ * Typically, this is used to determine if a requested method exists, without actually calling it.
+ * SEE ALSO
+ * XMLRPC_ServerCallMethod ()
+ * XMLRPC_ServerRegisterMethod ()
+ * SOURCE
+ */
+XMLRPC_Callback XMLRPC_ServerFindMethod(XMLRPC_SERVER server, const char* callName) {
+ if(server && callName) {
+ q_iter qi = Q_Iter_Head_F(&server->methodlist);
+ while( qi ) {
+ server_method* sm = Q_Iter_Get_F(qi);
+ if(sm && !strcmp(sm->name, callName)) {
+ return sm->method;
+ }
+ qi = Q_Iter_Next_F(qi);
+ }
+ }
+ return NULL;
+}
+
+/*******/
+
+
+/* Call method specified in request */
+/****f* VALUE/XMLRPC_ServerCallMethod
+ * NAME
+ * XMLRPC_ServerCallMethod
+ * SYNOPSIS
+ * XMLRPC_VALUE XMLRPC_ServerCallMethod(XMLRPC_SERVER server, XMLRPC_REQUEST request, void* userData)
+ * FUNCTION
+ *
+ * INPUTS
+ * server The XMLRPC_SERVER the method is registered with
+ * request the request to handle
+ * userData any additional data to pass to the C callback, or NULL
+ * RESULT
+ * XMLRPC_VALUE allocated by the callback, or NULL
+ * NOTES
+ * It is typically the caller's responsibility to free the returned value.
+ *
+ * Often the caller will want to serialize the result as XML, via
+ * XMLRPC_VALUE_To_XML () or XMLRPC_REQUEST_To_XML ()
+ * SEE ALSO
+ * XMLRPC_ServerFindMethod ()
+ * XMLRPC_ServerRegisterMethod ()
+ * XMLRPC_CleanupValue ()
+ * SOURCE
+ */
+XMLRPC_VALUE XMLRPC_ServerCallMethod(XMLRPC_SERVER server, XMLRPC_REQUEST request, void* userData) {
+ XMLRPC_VALUE xReturn = NULL;
+
+ /* check for error set during request parsing / generation */
+ if(request && request->error) {
+ xReturn = XMLRPC_CopyValue(request->error);
+ }
+ else if (server && request) {
+ XMLRPC_Callback cb =
+ XMLRPC_ServerFindMethod (server, request->methodName.str);
+ if(cb) {
+ xReturn = cb(server, request, userData);
+ }
+ else {
+ xReturn =
+ XMLRPC_UtilityCreateFault (xmlrpc_error_unknown_method,
+ request->methodName.str);
+ }
+ }
+ return xReturn;
+}
+
+/*******/
+
+/*-*****************
+* End server funcs *
+*******************/
+
+
+/*-***********************************
+* Begin XMLRPC General Options funcs *
+*************************************/
+
+/* For options used by XMLRPC_VALUE funcs that otherwise do not have
+ * parameters for options. Kind of gross. :(
+ */
+typedef struct _xmlrpc_options {
+ XMLRPC_CASE id_case;
+ XMLRPC_CASE_COMPARISON id_case_compare;
+}
+STRUCT_XMLRPC_OPTIONS, *XMLRPC_OPTIONS;
+
+static XMLRPC_OPTIONS XMLRPC_GetDefaultOptions() {
+ static STRUCT_XMLRPC_OPTIONS options = {
+ xmlrpc_case_exact,
+ xmlrpc_case_sensitive
+ };
+ return &options;
+}
+
+/****f* VALUE/XMLRPC_GetDefaultIdCase
+ * NAME
+ * XMLRPC_GetDefaultIdCase
+ * SYNOPSIS
+ * XMLRPC_CASE XMLRPC_GetDefaultIdCase()
+ * FUNCTION
+ * Gets default case options used by XMLRPC_VALUE funcs
+ * INPUTS
+ * none
+ * RESULT
+ * XMLRPC_CASE
+ * BUGS
+ * Nasty and gross. Should be server specific, but that requires changing all
+ * the XMLRPC_VALUE api's.
+ * SEE ALSO
+ * XMLRPC_SetDefaultIdCase ()
+ * SOURCE
+ */
+XMLRPC_CASE XMLRPC_GetDefaultIdCase() {
+ XMLRPC_OPTIONS options = XMLRPC_GetDefaultOptions();
+ return options->id_case;
+}
+
+/*******/
+
+/****f* VALUE/XMLRPC_SetDefaultIdCase
+ * NAME
+ * XMLRPC_SetDefaultIdCase
+ * SYNOPSIS
+ * XMLRPC_CASE XMLRPC_SetDefaultIdCase(XMLRPC_CASE id_case)
+ * FUNCTION
+ * Sets default case options used by XMLRPC_VALUE funcs
+ * INPUTS
+ * id_case case options as enumerated by XMLRPC_CASE
+ * RESULT
+ * XMLRPC_CASE -- newly set option
+ * BUGS
+ * Nasty and gross. Should be server specific, but that requires changing all
+ * the XMLRPC_VALUE api's.
+ * SEE ALSO
+ * XMLRPC_GetDefaultIdCase ()
+ * SOURCE
+ */
+XMLRPC_CASE XMLRPC_SetDefaultIdCase(XMLRPC_CASE id_case) {
+ XMLRPC_OPTIONS options = XMLRPC_GetDefaultOptions();
+ options->id_case = id_case;
+ return options->id_case;
+}
+
+/*******/
+
+/****f* VALUE/XMLRPC_GetDefaultIdCaseComparison
+ * NAME
+ * XMLRPC_GetDefaultIdCaseComparison
+ * SYNOPSIS
+ * XMLRPC_CASE XMLRPC_GetDefaultIdCaseComparison( )
+ * FUNCTION
+ * Gets default case comparison options used by XMLRPC_VALUE funcs
+ * INPUTS
+ * none
+ * RESULT
+ * XMLRPC_CASE_COMPARISON default
+ * BUGS
+ * Nasty and gross. Should be server specific, but that requires changing all
+ * the XMLRPC_VALUE api's.
+ * SEE ALSO
+ * XMLRPC_SetDefaultIdCaseComparison ()
+ * SOURCE
+ */
+XMLRPC_CASE_COMPARISON XMLRPC_GetDefaultIdCaseComparison() {
+ XMLRPC_OPTIONS options = XMLRPC_GetDefaultOptions();
+ return options->id_case_compare;
+}
+
+/*******/
+
+/****f* VALUE/XMLRPC_SetDefaultIdCaseComparison
+ * NAME
+ * XMLRPC_SetDefaultIdCaseComparison
+ * SYNOPSIS
+ * XMLRPC_CASE XMLRPC_SetDefaultIdCaseComparison( XMLRPC_CASE_COMPARISON id_case_compare )
+ * FUNCTION
+ * Gets default case comparison options used by XMLRPC_VALUE funcs
+ * INPUTS
+ * id_case_compare case comparison rule to set as default
+ * RESULT
+ * XMLRPC_CASE_COMPARISON newly set default
+ * BUGS
+ * Nasty and gross. Should be server specific, but that requires changing all
+ * the XMLRPC_VALUE api's.
+ * SEE ALSO
+ * XMLRPC_GetDefaultIdCaseComparison ()
+ * SOURCE
+ */
+XMLRPC_CASE_COMPARISON XMLRPC_SetDefaultIdCaseComparison(XMLRPC_CASE_COMPARISON id_case_compare) {
+ XMLRPC_OPTIONS options = XMLRPC_GetDefaultOptions();
+ options->id_case_compare = id_case_compare;
+ return options->id_case_compare;
+}
+
+/*******/
+
+/*-*********************************
+* End XMLRPC General Options funcs *
+***********************************/
+
+
+/*-******************
+* Fault API funcs *
+********************/
+
+/****f* UTILITY/XMLRPC_UtilityCreateFault
+ * NAME
+ * XMLRPC_UtilityCreateFault
+ * SYNOPSIS
+ * XMLRPC_VALUE XMLRPC_UtilityCreateFault( int fault_code, const char* fault_string )
+ * FUNCTION
+ * generates a struct containing a string member with id "faultString" and an int member
+ * with id "faultCode". When using the xmlrpc xml serialization, these will be translated
+ * to <fault><value><struct>... format.
+ * INPUTS
+ * fault_code application specific error code. can be 0.
+ * fault_string application specific error string. cannot be null.
+ * RESULT
+ * XMLRPC_VALUE a newly created struct vector representing the error, or null on error.
+ * NOTES
+ * This is a utility function. xmlrpc "faults" are not directly represented in this xmlrpc
+ * API or data structures. It is the author's view, that this API is intended for simple
+ * data types, and a "fault" is a complex data type consisting of multiple simple data
+ * types. This function is provided for convenience only, the same result could be
+ * achieved directly by the application.
+ *
+ * This function now supports some "standardized" fault codes, as specified at.
+ * http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php.
+ * If one of these fault codes is received, the description string will automatically
+ * be prefixed with a standard error string and 2 newlines.
+ *
+ * The actual transformation between this complex type and the xml "<fault>" element takes
+ * place in the xmlrpc to xml serialization layer. This step is not performed when using the
+ * simplerpc serialization, meaning that there will be no "<fault>" element in that
+ * serialization. There will simply be a standard struct with 2 child elements.
+ * imho, the "<fault>" element is unnecessary and/or out of place as part of the standard API.
+ *
+ * SOURCE
+ */
+XMLRPC_VALUE XMLRPC_UtilityCreateFault(int fault_code, const char* fault_string) {
+ XMLRPC_VALUE xOutput = NULL;
+
+ char* string = NULL;
+ simplestring description;
+ simplestring_init(&description);
+
+ switch (fault_code) {
+ case xmlrpc_error_parse_xml_syntax:
+ string = xmlrpc_error_parse_xml_syntax_str;
+ break;
+ case xmlrpc_error_parse_unknown_encoding:
+ string = xmlrpc_error_parse_unknown_encoding_str;
+ break;
+ case xmlrpc_error_parse_bad_encoding:
+ string = xmlrpc_error_parse_bad_encoding_str;
+ break;
+ case xmlrpc_error_invalid_xmlrpc:
+ string = xmlrpc_error_invalid_xmlrpc_str;
+ break;
+ case xmlrpc_error_unknown_method:
+ string = xmlrpc_error_unknown_method_str;
+ break;
+ case xmlrpc_error_invalid_params:
+ string = xmlrpc_error_invalid_params_str;
+ break;
+ case xmlrpc_error_internal_server:
+ string = xmlrpc_error_internal_server_str;
+ break;
+ case xmlrpc_error_application:
+ string = xmlrpc_error_application_str;
+ break;
+ case xmlrpc_error_system:
+ string = xmlrpc_error_system_str;
+ break;
+ case xmlrpc_error_transport:
+ string = xmlrpc_error_transport_str;
+ break;
+ }
+
+ simplestring_add(&description, string);
+
+ if(string && fault_string) {
+ simplestring_add(&description, "\n\n");
+ }
+ simplestring_add(&description, fault_string);
+
+
+ if(description.len) {
+ xOutput = XMLRPC_CreateVector(NULL, xmlrpc_vector_struct);
+
+ XMLRPC_VectorAppendString (xOutput, "faultString", description.str,
+ description.len);
+ XMLRPC_VectorAppendInt(xOutput, "faultCode", fault_code);
+ }
+
+ simplestring_free(&description);
+
+ return xOutput;
+}
+
+/*******/
+
+
+/****f* FAULT/XMLRPC_ValueIsFault
+ * NAME
+ * XMLRPC_ValueIsFault
+ * SYNOPSIS
+ * int XMLRPC_ValueIsFault (XMLRPC_VALUE value)
+ * FUNCTION
+ * Determines if a value encapsulates a fault "object"
+ * INPUTS
+ * value any XMLRPC_VALUE
+ * RESULT
+ * 1 if it is a fault, else 0
+ * SEE ALSO
+ * XMLRPC_ResponseIsFault ()
+ * SOURCE
+ */
+int XMLRPC_ValueIsFault (XMLRPC_VALUE value) {
+ if( XMLRPC_VectorGetValueWithID(value, "faultCode") &&
+ XMLRPC_VectorGetValueWithID(value, "faultString") ) {
+ return 1;
+ }
+ return 0;
+}
+/*******/
+
+
+/****f* FAULT/XMLRPC_ResponseIsFault
+ * NAME
+ * XMLRPC_ResponseIsFault
+ * SYNOPSIS
+ * int XMLRPC_ResponseIsFault (XMLRPC_REQUEST response)
+ * FUNCTION
+ * Determines if a response contains an encapsulated fault "object"
+ * INPUTS
+ * value any XMLRPC_REQUEST. typically of type xmlrpc_request_response
+ * RESULT
+ * 1 if it contains a fault, else 0
+ * SEE ALSO
+ * XMLRPC_ValueIsFault ()
+ * SOURCE
+ */
+int XMLRPC_ResponseIsFault(XMLRPC_REQUEST response) {
+ return XMLRPC_ValueIsFault( XMLRPC_RequestGetData(response) );
+}
+
+/*******/
+
+/****f* FAULT/XMLRPC_GetValueFaultCode
+ * NAME
+ * XMLRPC_GetValueFaultCode
+ * SYNOPSIS
+ * int XMLRPC_GetValueFaultCode (XMLRPC_VALUE value)
+ * FUNCTION
+ * returns fault code from a struct, if any
+ * INPUTS
+ * value XMLRPC_VALUE of type xmlrpc_vector_struct.
+ * RESULT
+ * fault code, else 0.
+ * BUGS
+ * impossible to distinguish faultCode == 0 from faultCode not present.
+ * SEE ALSO
+ * XMLRPC_GetResponseFaultCode ()
+ * SOURCE
+ */
+int XMLRPC_GetValueFaultCode (XMLRPC_VALUE value) {
+ return XMLRPC_VectorGetIntWithID(value, "faultCode");
+}
+
+/*******/
+
+/****f* FAULT/XMLRPC_GetResponseFaultCode
+ * NAME
+ * XMLRPC_GetResponseFaultCode
+ * SYNOPSIS
+ * int XMLRPC_GetResponseFaultCode(XMLRPC_REQUEST response)
+ * FUNCTION
+ * returns fault code from a response, if any
+ * INPUTS
+ * response XMLRPC_REQUEST. typically of type xmlrpc_request_response.
+ * RESULT
+ * fault code, else 0.
+ * BUGS
+ * impossible to distinguish faultCode == 0 from faultCode not present.
+ * SEE ALSO
+ * XMLRPC_GetValueFaultCode ()
+ * SOURCE
+ */
+int XMLRPC_GetResponseFaultCode(XMLRPC_REQUEST response) {
+ return XMLRPC_GetValueFaultCode( XMLRPC_RequestGetData(response) );
+}
+
+/*******/
+
+
+/****f* FAULT/XMLRPC_GetValueFaultString
+ * NAME
+ * XMLRPC_GetValueFaultString
+ * SYNOPSIS
+ * const char* XMLRPC_GetValueFaultString (XMLRPC_VALUE value)
+ * FUNCTION
+ * returns fault string from a struct, if any
+ * INPUTS
+ * value XMLRPC_VALUE of type xmlrpc_vector_struct.
+ * RESULT
+ * fault string, else 0.
+ * SEE ALSO
+ * XMLRPC_GetResponseFaultString ()
+ * SOURCE
+ */
+const char* XMLRPC_GetValueFaultString (XMLRPC_VALUE value) {
+ return XMLRPC_VectorGetStringWithID(value, "faultString");
+}
+
+/*******/
+
+/****f* FAULT/XMLRPC_GetResponseFaultString
+ * NAME
+ * XMLRPC_GetResponseFaultString
+ * SYNOPSIS
+ * const char* XMLRPC_GetResponseFaultString (XMLRPC_REQUEST response)
+ * FUNCTION
+ * returns fault string from a response, if any
+ * INPUTS
+ * response XMLRPC_REQUEST. typically of type xmlrpc_request_response.
+ * RESULT
+ * fault string, else 0.
+ * SEE ALSO
+ * XMLRPC_GetValueFaultString ()
+ * SOURCE
+ */
+const char* XMLRPC_GetResponseFaultString (XMLRPC_REQUEST response) {
+ return XMLRPC_GetValueFaultString( XMLRPC_RequestGetData(response) );
+}
+
+/*******/
+
+
+/*-******************
+* Utility API funcs *
+********************/
+
+
+/****f* UTILITY/XMLRPC_Free
+ * NAME
+ * XMLRPC_Free
+ * SYNOPSIS
+ * void XMLRPC_Free(void* mem)
+ * FUNCTION
+ * frees a block of memory allocated by xmlrpc.
+ * INPUTS
+ * mem memory to free
+ * RESULT
+ * void
+ * NOTES
+ * Useful for OS's where memory must be free'd
+ * in the same library in which it is allocated.
+ * SOURCE
+ */
+void XMLRPC_Free(void* mem) {
+ my_free(mem);
+}
+
+/*******/
+
+
+/****f* UTILITY/XMLRPC_GetVersionString
+ * NAME
+ * XMLRPC_GetVersionString
+ * SYNOPSIS
+ * const char* XMLRPC_GetVersionString()
+ * FUNCTION
+ * returns library version string
+ * INPUTS
+ *
+ * RESULT
+ * const char*
+ * NOTES
+ * SOURCE
+ */
+const char* XMLRPC_GetVersionString() {
+ return XMLRPC_VERSION_STR;
+}
+
+/*******/
+
+
+/*-**********************
+* End Utility API funcs *
+************************/
diff --git a/ext/xmlrpc/libxmlrpc/xmlrpc.h b/ext/xmlrpc/libxmlrpc/xmlrpc.h
new file mode 100644
index 0000000..dde3d5e
--- /dev/null
+++ b/ext/xmlrpc/libxmlrpc/xmlrpc.h
@@ -0,0 +1,454 @@
+/*
+ This file is part of libXMLRPC - a C library for xml-encoded function calls.
+
+ Author: Dan Libby (dan@libby.com)
+ Epinions.com may be contacted at feedback@epinions-inc.com
+*/
+
+/*
+ Copyright 2000 Epinions, Inc.
+
+ Subject to the following 3 conditions, Epinions, Inc. permits you, free
+ of charge, to (a) use, copy, distribute, modify, perform and display this
+ software and associated documentation files (the "Software"), and (b)
+ permit others to whom the Software is furnished to do so as well.
+
+ 1) The above copyright notice and this permission notice shall be included
+ without modification in all copies or substantial portions of the
+ Software.
+
+ 2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF
+ ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY
+ IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ PURPOSE OR NONINFRINGEMENT.
+
+ 3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
+ OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING
+ NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH
+ DAMAGES.
+
+*/
+
+#ifndef XMLRPC_ALREADY_INCLUDED
+#define XMLRPC_ALREADY_INCLUDED 1
+
+/* includes */
+#include "xml_element.h"
+#include <time.h> /* for time_t */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* allow version to be specified via compile line define */
+#ifndef XMLRPC_LIB_VERSION
+ #define XMLRPC_LIB_VERSION "0.51"
+#endif
+
+/* this number, representing the date, must be increased each time the API changes */
+#define XMLRPC_API_NO 20020623
+
+/* this string should be changed with each packaged release */
+#define XMLRPC_VERSION_STR "xmlrpc-epi v. " XMLRPC_LIB_VERSION
+
+/* where to find more info. shouldn't need to change much */
+#define XMLRPC_HOME_PAGE_STR "http://xmlprc-epi.sourceforge.net/"
+
+
+/****d* VALUE/XMLRPC_VALUE_TYPE
+ * NAME
+ * XMLRPC_VALUE_TYPE
+ * NOTES
+ * Defines data types for XMLRPC_VALUE
+ * Deprecated for public use. See XMLRPC_VALUE_TYPE_EASY
+ * SEE ALSO
+ * XMLRPC_VECTOR_TYPE
+ * XMLRPC_REQUEST_TYPE
+ * SOURCE
+ */
+typedef enum _XMLRPC_VALUE_TYPE {
+ xmlrpc_none, /* not a value */
+ xmlrpc_empty, /* empty value, eg NULL */
+ xmlrpc_base64, /* base64 value, eg binary data */
+ xmlrpc_boolean, /* boolean [0 | 1] */
+ xmlrpc_datetime, /* datetime [ISO8601 | time_t] */
+ xmlrpc_double, /* double / floating point */
+ xmlrpc_int, /* integer */
+ xmlrpc_string, /* string */
+ xmlrpc_vector /* vector, aka list, array */
+} XMLRPC_VALUE_TYPE;
+/*******/
+
+/****d* VALUE/XMLRPC_VECTOR_TYPE
+ * NAME
+ * XMLRPC_VECTOR_TYPE
+ * NOTES
+ * Defines data types for XMLRPC_VECTOR.
+ * Deprecated for public use. See XMLRPC_VALUE_TYPE_EASY
+ * SEE ALSO
+ * XMLRPC_VALUE_TYPE
+ * XMLRPC_REQUEST_TYPE
+ * SOURCE
+ */
+typedef enum _XMLRPC_VECTOR_TYPE {
+ xmlrpc_vector_none, /* not an array */
+ xmlrpc_vector_array, /* no values may have key names */
+ xmlrpc_vector_mixed, /* some values may have key names */
+ xmlrpc_vector_struct /* all values must have key names */
+} XMLRPC_VECTOR_TYPE;
+/*******/
+
+/****d* VALUE/XMLRPC_VALUE_TYPE_EASY
+ * NAME
+ * XMLRPC_VALUE_TYPE_EASY
+ * NOTES
+ * Defines data types for XMLRPC_VALUE, including vector types.
+ * SEE ALSO
+ * XMLRPC_VECTOR_TYPE
+ * XMLRPC_REQUEST_TYPE
+ * SOURCE
+ */
+typedef enum _XMLRPC_VALUE_TYPE_EASY {
+ xmlrpc_type_none, /* not a value */
+ xmlrpc_type_empty, /* empty value, eg NULL */
+ xmlrpc_type_base64, /* base64 value, eg binary data */
+ xmlrpc_type_boolean, /* boolean [0 | 1] */
+ xmlrpc_type_datetime, /* datetime [ISO8601 | time_t] */
+ xmlrpc_type_double, /* double / floating point */
+ xmlrpc_type_int, /* integer */
+ xmlrpc_type_string, /* string */
+/* -- IMPORTANT: identical to XMLRPC_VALUE_TYPE to this point. -- */
+ xmlrpc_type_array, /* vector array */
+ xmlrpc_type_mixed, /* vector mixed */
+ xmlrpc_type_struct /* vector struct */
+} XMLRPC_VALUE_TYPE_EASY;
+/*******/
+
+
+/****d* VALUE/XMLRPC_REQUEST_TYPE
+ * NAME
+ * XMLRPC_REQUEST_TYPE
+ * NOTES
+ * Defines data types for XMLRPC_REQUEST
+ * SEE ALSO
+ * XMLRPC_VALUE_TYPE
+ * XMLRPC_VECTOR_TYPE
+ * SOURCE
+ */
+typedef enum _xmlrpc_request_type {
+ xmlrpc_request_none, /* not a valid request */
+ xmlrpc_request_call, /* calling/invoking a method */
+ xmlrpc_request_response, /* responding to a method call */
+} XMLRPC_REQUEST_TYPE;
+/*******/
+
+/****d* VALUE/XMLRPC_ERROR_CODE
+ * NAME
+ * XMLRPC_ERROR_CODE
+ * NOTES
+ * All existing error codes
+ * SEE ALSO
+ * XMLRPC_REQUEST_ERROR
+ * SOURCE
+ */
+typedef enum _xmlrpc_error_code {
+ xmlrpc_error_none = 0, /* not an error */
+ xmlrpc_error_parse_xml_syntax = -32700,
+ xmlrpc_error_parse_unknown_encoding = -32701,
+ xmlrpc_error_parse_bad_encoding = -32702,
+ xmlrpc_error_invalid_xmlrpc = -32600,
+ xmlrpc_error_unknown_method = -32601,
+ xmlrpc_error_invalid_params = -32602,
+ xmlrpc_error_internal_server = -32603,
+ xmlrpc_error_application = -32500,
+ xmlrpc_error_system = -32400,
+ xmlrpc_error_transport = -32300
+} XMLRPC_ERROR_CODE;
+/******/
+
+#define xmlrpc_error_parse_xml_syntax_str "parse error. not well formed."
+#define xmlrpc_error_parse_unknown_encoding_str "parse error. unknown encoding"
+#define xmlrpc_error_parse_bad_encoding_str "parse error. invalid character for encoding"
+#define xmlrpc_error_invalid_xmlrpc_str "server error. xml-rpc not conforming to spec"
+#define xmlrpc_error_unknown_method_str "server error. method not found."
+#define xmlrpc_error_invalid_params_str "server error. invalid method parameters"
+#define xmlrpc_error_internal_server_str "server error. internal xmlrpc library error"
+#define xmlrpc_error_application_str "application error."
+#define xmlrpc_error_system_str "system error."
+#define xmlrpc_error_transport_str "transport error."
+
+
+
+/****d* VALUE/XMLRPC_VERSION
+ * NAME
+ * XMLRPC_VERSION
+ * NOTES
+ * Defines xml vocabulary used for generated xml
+ * SEE ALSO
+ * XMLRPC_REQUEST_OUTPUT_OPTIONS
+ * XMLRPC_REQUEST_To_XML ()
+ * SOURCE
+ */
+typedef enum _xmlrpc_version {
+ xmlrpc_version_none = 0, /* not a recognized vocabulary */
+ xmlrpc_version_1_0 = 1, /* xmlrpc 1.0 standard vocab */
+ xmlrpc_version_simple = 2, /* alt more readable vocab */
+ xmlrpc_version_danda = 2, /* same as simple. legacy */
+ xmlrpc_version_soap_1_1 = 3 /* SOAP. version 1.1 */
+} XMLRPC_VERSION;
+/******/
+
+/****s* VALUE/XMLRPC_REQUEST_OUTPUT_OPTIONS
+ * NAME
+ * XMLRPC_REQUEST_OUTPUT_OPTIONS
+ * NOTES
+ * Defines output options for generated xml
+ * SEE ALSO
+ * XMLRPC_VERSION
+ * XML_ELEM_OUTPUT_OPTIONS
+ * XMLRPC_REQUEST_To_XML ()
+ * SOURCE
+ */
+typedef struct _xmlrpc_request_output_options {
+ STRUCT_XML_ELEM_OUTPUT_OPTIONS xml_elem_opts; /* xml_element specific output options */
+ XMLRPC_VERSION version; /* xml vocabulary to use */
+} STRUCT_XMLRPC_REQUEST_OUTPUT_OPTIONS, *XMLRPC_REQUEST_OUTPUT_OPTIONS;
+/******/
+
+/****s* VALUE/XMLRPC_REQUEST_INPUT_OPTIONS
+ * NAME
+ * XMLRPC_REQUEST_INPUT_OPTIONS
+ * NOTES
+ * Defines options for reading in xml data
+ * SEE ALSO
+ * XMLRPC_VERSION
+ * XML_ELEM_INPUT_OPTIONS
+ * XMLRPC_REQUEST_From_XML ()
+ * SOURCE
+ */
+typedef struct _xmlrpc_request_input_options {
+ STRUCT_XML_ELEM_INPUT_OPTIONS xml_elem_opts; /* xml_element specific output options */
+} STRUCT_XMLRPC_REQUEST_INPUT_OPTIONS, *XMLRPC_REQUEST_INPUT_OPTIONS;
+/******/
+
+/****s* VALUE/XMLRPC_ERROR
+ * NAME
+ * XMLRPC_ERROR
+ * NOTES
+ * For the reporting and handling of errors
+ * SOURCE
+ */
+typedef struct _xmlrpc_error {
+ XMLRPC_ERROR_CODE code;
+ STRUCT_XML_ELEM_ERROR xml_elem_error; /* xml_element errors (parser errors) */
+} STRUCT_XMLRPC_ERROR, *XMLRPC_ERROR;
+/******/
+
+
+/****d* VALUE/XMLRPC_CASE_COMPARISON
+ * NAME
+ * XMLRPC_CASE_COMPARISON
+ * NOTES
+ * Defines case comparison options for XMLRPC_VALUE/VECTOR API's
+ * SEE ALSO
+ * XMLRPC_CASE
+ * XMLRPC_VALUE
+ * SOURCE
+ */
+typedef enum _xmlrpc_case_comparison {
+ xmlrpc_case_insensitive, /* use case-insensitive compare */
+ xmlrpc_case_sensitive /* use case-sensitive compare */
+} XMLRPC_CASE_COMPARISON;
+/******/
+
+/****d* VALUE/XMLRPC_CASE
+ * NAME
+ * XMLRPC_CASE
+ * NOTES
+ * Defines case behavior when setting IDs in XMLRPC_VALUE API's
+ * SEE ALSO
+ * XMLRPC_CASE_COMPARISON
+ * XMLRPC_VALUE
+ * SOURCE
+ */
+typedef enum _xmlrpc_case {
+ xmlrpc_case_exact, /* leave case alone */
+ xmlrpc_case_lower, /* lower-case id */
+ xmlrpc_case_upper /* upper-case id */
+} XMLRPC_CASE;
+/******/
+
+/* if you don't like these defaults, you can set them with XMLRPC_SetDefaultIdCase*() */
+#define XMLRPC_DEFAULT_ID_CASE XMLRPC_GetDefaultIdCase()
+#define XMLRPC_DEFAULT_ID_CASE_SENSITIVITY XMLRPC_GetDefaultIdCaseComparison()
+
+/* opaque (non-public) types. defined locally in xmlrpc.c */
+typedef struct _xmlrpc_request* XMLRPC_REQUEST;
+typedef struct _xmlrpc_server* XMLRPC_SERVER;
+typedef struct _xmlrpc_value* XMLRPC_VALUE;
+
+/****d* VALUE/XMLRPC_Callback
+ * NAME
+ * XMLRPC_Callback
+ * NOTES
+ * Function prototype for user defined method handlers (callbacks).
+ * SEE ALSO
+ * XMLRPC_ServerRegisterMethod ()
+ * XMLRPC_ServerCallMethod ()
+ * XMLRPC_REQUEST
+ * XMLRPC_VALUE
+ * SOURCE
+ */
+typedef XMLRPC_VALUE (*XMLRPC_Callback)(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData);
+/******/
+
+/* ID Case Defaults */
+XMLRPC_CASE XMLRPC_GetDefaultIdCase(void);
+XMLRPC_CASE XMLRPC_SetDefaultIdCase(XMLRPC_CASE id_case);
+XMLRPC_CASE_COMPARISON XMLRPC_GetDefaultIdCaseComparison(void);
+XMLRPC_CASE_COMPARISON XMLRPC_SetDefaultIdCaseComparison(XMLRPC_CASE_COMPARISON id_case);
+
+/* Vector manipulation */
+int XMLRPC_VectorSize(XMLRPC_VALUE value);
+XMLRPC_VALUE XMLRPC_VectorRewind(XMLRPC_VALUE value);
+XMLRPC_VALUE XMLRPC_VectorNext(XMLRPC_VALUE value);
+int XMLRPC_SetIsVector(XMLRPC_VALUE value, XMLRPC_VECTOR_TYPE type);
+int XMLRPC_AddValueToVector(XMLRPC_VALUE target, XMLRPC_VALUE source);
+int XMLRPC_AddValuesToVector(XMLRPC_VALUE target, ...);
+int XMLRPC_VectorRemoveValue(XMLRPC_VALUE vector, XMLRPC_VALUE value);
+XMLRPC_VALUE XMLRPC_VectorGetValueWithID_Case(XMLRPC_VALUE vector, const char* id, XMLRPC_CASE_COMPARISON id_case);
+
+
+/* Create values */
+XMLRPC_VALUE XMLRPC_CreateValueBoolean(const char* id, int truth);
+XMLRPC_VALUE XMLRPC_CreateValueBase64(const char* id, const char* s, int len);
+XMLRPC_VALUE XMLRPC_CreateValueDateTime(const char* id, time_t time);
+XMLRPC_VALUE XMLRPC_CreateValueDateTime_ISO8601(const char* id, const char *s);
+XMLRPC_VALUE XMLRPC_CreateValueDouble(const char* id, double f);
+XMLRPC_VALUE XMLRPC_CreateValueInt(const char* id, int i);
+XMLRPC_VALUE XMLRPC_CreateValueString(const char* id, const char* s, int len);
+XMLRPC_VALUE XMLRPC_CreateValueEmpty(void);
+XMLRPC_VALUE XMLRPC_CreateVector(const char* id, XMLRPC_VECTOR_TYPE type);
+
+/* Cleanup values */
+void XMLRPC_CleanupValue(XMLRPC_VALUE value);
+
+/* Request error */
+XMLRPC_VALUE XMLRPC_RequestSetError (XMLRPC_REQUEST request, XMLRPC_VALUE error);
+XMLRPC_VALUE XMLRPC_RequestGetError (XMLRPC_REQUEST request);
+
+/* Copy values */
+XMLRPC_VALUE XMLRPC_CopyValue(XMLRPC_VALUE value);
+XMLRPC_VALUE XMLRPC_DupValueNew(XMLRPC_VALUE xSource);
+
+/* Set Values */
+void XMLRPC_SetValueDateTime(XMLRPC_VALUE value, time_t time);
+void XMLRPC_SetValueDateTime_ISO8601(XMLRPC_VALUE value, const char* s);
+void XMLRPC_SetValueDouble(XMLRPC_VALUE value, double val);
+void XMLRPC_SetValueInt(XMLRPC_VALUE value, int val);
+void XMLRPC_SetValueBoolean(XMLRPC_VALUE value, int val);
+const char *XMLRPC_SetValueString(XMLRPC_VALUE value, const char* s, int len);
+void XMLRPC_SetValueBase64(XMLRPC_VALUE value, const char* s, int len);
+const char *XMLRPC_SetValueID_Case(XMLRPC_VALUE value, const char* id, int len, XMLRPC_CASE id_case);
+#define XMLRPC_SetValueID(value, id, len) XMLRPC_SetValueID_Case(value, id, len, XMLRPC_DEFAULT_ID_CASE)
+
+/* Get Values */
+const char* XMLRPC_GetValueString(XMLRPC_VALUE value);
+int XMLRPC_GetValueStringLen(XMLRPC_VALUE value);
+int XMLRPC_GetValueInt(XMLRPC_VALUE value);
+int XMLRPC_GetValueBoolean(XMLRPC_VALUE value);
+double XMLRPC_GetValueDouble(XMLRPC_VALUE value);
+const char* XMLRPC_GetValueBase64(XMLRPC_VALUE value);
+time_t XMLRPC_GetValueDateTime(XMLRPC_VALUE value);
+const char* XMLRPC_GetValueDateTime_ISO8601(XMLRPC_VALUE value);
+const char* XMLRPC_GetValueID(XMLRPC_VALUE value);
+
+/* Type introspection */
+XMLRPC_VALUE_TYPE XMLRPC_GetValueType(XMLRPC_VALUE v);
+XMLRPC_VALUE_TYPE_EASY XMLRPC_GetValueTypeEasy(XMLRPC_VALUE v);
+XMLRPC_VECTOR_TYPE XMLRPC_GetVectorType(XMLRPC_VALUE v);
+
+/* Parsing and Creating XML */
+XMLRPC_REQUEST XMLRPC_REQUEST_FromXML(const char* in_buf, int len, XMLRPC_REQUEST_INPUT_OPTIONS in_options);
+XMLRPC_VALUE XMLRPC_VALUE_FromXML(const char* in_buf, int len, XMLRPC_REQUEST_INPUT_OPTIONS in_options);
+char* XMLRPC_REQUEST_ToXML(XMLRPC_REQUEST request, int *buf_len);
+char* XMLRPC_VALUE_ToXML(XMLRPC_VALUE val, int* buf_len);
+
+/* Request manipulation funcs */
+const char* XMLRPC_RequestSetMethodName(XMLRPC_REQUEST request, const char* methodName);
+const char* XMLRPC_RequestGetMethodName(XMLRPC_REQUEST request);
+XMLRPC_REQUEST XMLRPC_RequestNew(void);
+void XMLRPC_RequestFree(XMLRPC_REQUEST request, int bFreeIO);
+XMLRPC_REQUEST_OUTPUT_OPTIONS XMLRPC_RequestSetOutputOptions(XMLRPC_REQUEST request, XMLRPC_REQUEST_OUTPUT_OPTIONS output);
+XMLRPC_REQUEST_OUTPUT_OPTIONS XMLRPC_RequestGetOutputOptions(XMLRPC_REQUEST request);
+XMLRPC_VALUE XMLRPC_RequestSetData(XMLRPC_REQUEST request, XMLRPC_VALUE data);
+XMLRPC_VALUE XMLRPC_RequestGetData(XMLRPC_REQUEST request);
+XMLRPC_REQUEST_TYPE XMLRPC_RequestSetRequestType(XMLRPC_REQUEST request, XMLRPC_REQUEST_TYPE type);
+XMLRPC_REQUEST_TYPE XMLRPC_RequestGetRequestType(XMLRPC_REQUEST request);
+
+/* Server Creation/Destruction; Method Registration and Invocation */
+XMLRPC_SERVER XMLRPC_ServerCreate(void);
+XMLRPC_SERVER XMLRPC_GetGlobalServer(void); /* better to use XMLRPC_ServerCreate if you can */
+void XMLRPC_ServerDestroy(XMLRPC_SERVER server);
+int XMLRPC_ServerRegisterMethod(XMLRPC_SERVER server, const char *name, XMLRPC_Callback cb);
+XMLRPC_Callback XMLRPC_ServerFindMethod(XMLRPC_SERVER server, const char* callName);
+XMLRPC_VALUE XMLRPC_ServerCallMethod(XMLRPC_SERVER server, XMLRPC_REQUEST request, void* userData);
+
+#include "xmlrpc_introspection.h"
+
+/* Fault interrogation funcs */
+int XMLRPC_ValueIsFault (XMLRPC_VALUE value);
+int XMLRPC_ResponseIsFault(XMLRPC_REQUEST response);
+int XMLRPC_GetValueFaultCode (XMLRPC_VALUE value);
+int XMLRPC_GetResponseFaultCode(XMLRPC_REQUEST response);
+const char* XMLRPC_GetValueFaultString (XMLRPC_VALUE value);
+const char* XMLRPC_GetResponseFaultString (XMLRPC_REQUEST response);
+
+
+/* Public Utility funcs */
+XMLRPC_VALUE XMLRPC_UtilityCreateFault(int fault_code, const char* fault_string);
+void XMLRPC_Free(void* mem);
+const char* XMLRPC_GetVersionString(void);
+
+/****d* VALUE/XMLRPC_MACROS
+ * NAME
+ * Some Helpful Macros
+ * NOTES
+ * Some macros for making life easier. Should be self-explanatory.
+ * SEE ALSO
+ * XMLRPC_AddValueToVector ()
+ * XMLRPC_VectorGetValueWithID_Case ()
+ * XMLRPC_VALUE
+ * SOURCE
+ */
+
+/* Append values to vector */
+#define XMLRPC_VectorAppendString(vector, id, s, len) XMLRPC_AddValueToVector(vector, XMLRPC_CreateValueString(id, s, len))
+#define XMLRPC_VectorAppendBase64(vector, id, s, len) XMLRPC_AddValueToVector(vector, XMLRPC_CreateValueBase64(id, s, len))
+#define XMLRPC_VectorAppendDateTime(vector, id, time) XMLRPC_AddValueToVector(vector, XMLRPC_CreateValueDateTime(id, time))
+#define XMLRPC_VectorAppendDateTime_ISO8601(vector, id, s) XMLRPC_AddValueToVector(vector, XMLRPC_CreateValueDateTime_ISO8601(id, s))
+#define XMLRPC_VectorAppendDouble(vector, id, f) XMLRPC_AddValueToVector(vector, XMLRPC_CreateValueDouble(id, f))
+#define XMLRPC_VectorAppendInt(vector, id, i) XMLRPC_AddValueToVector(vector, XMLRPC_CreateValueInt(id, i))
+#define XMLRPC_VectorAppendBoolean(vector, id, i) XMLRPC_AddValueToVector(vector, XMLRPC_CreateValueBoolean(id, i))
+
+/* Get named values from vector */
+#define XMLRPC_VectorGetValueWithID(vector, id) XMLRPC_VectorGetValueWithID_Case(vector, id, XMLRPC_DEFAULT_ID_CASE_SENSITIVITY)
+#define XMLRPC_VectorGetStringWithID(vector, id) XMLRPC_GetValueString(XMLRPC_VectorGetValueWithID(vector, id))
+#define XMLRPC_VectorGetBase64WithID(vector, id) XMLRPC_GetValueBase64(XMLRPC_VectorGetValueWithID(vector, id))
+#define XMLRPC_VectorGetDateTimeWithID(vector, id) XMLRPC_GetValueDateTime(XMLRPC_VectorGetValueWithID(vector, id))
+#define XMLRPC_VectorGetDoubleWithID(vector, id) XMLRPC_GetValueDouble(XMLRPC_VectorGetValueWithID(vector, id))
+#define XMLRPC_VectorGetIntWithID(vector, id) XMLRPC_GetValueInt(XMLRPC_VectorGetValueWithID(vector, id))
+#define XMLRPC_VectorGetBooleanWithID(vector, id) XMLRPC_GetValueBoolean(XMLRPC_VectorGetValueWithID(vector, id))
+
+/******/
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* not XMLRPC_ALREADY_INCLUDED */
+
+
+
diff --git a/ext/xmlrpc/libxmlrpc/xmlrpc.m4 b/ext/xmlrpc/libxmlrpc/xmlrpc.m4
new file mode 100644
index 0000000..87da92d
--- /dev/null
+++ b/ext/xmlrpc/libxmlrpc/xmlrpc.m4
@@ -0,0 +1,12 @@
+AC_DEFUN([XMLRPC_CHECKS],[
+
+AC_REQUIRE([AC_PROG_CC])
+AC_REQUIRE([AC_PROG_LN_S])
+AC_REQUIRE([AC_PROG_RANLIB])
+
+AC_DEFINE(UNDEF_THREADS_HACK,,[ ])
+
+XMLRPC_HEADER_CHECKS
+XMLRPC_TYPE_CHECKS
+XMLRPC_FUNCTION_CHECKS
+])
diff --git a/ext/xmlrpc/libxmlrpc/xmlrpc_introspection.c b/ext/xmlrpc/libxmlrpc/xmlrpc_introspection.c
new file mode 100644
index 0000000..9964d83
--- /dev/null
+++ b/ext/xmlrpc/libxmlrpc/xmlrpc_introspection.c
@@ -0,0 +1,604 @@
+/*
+ This file is part of libXMLRPC - a C library for xml-encoded function calls.
+
+ Author: Dan Libby (dan@libby.com)
+ Epinions.com may be contacted at feedback@epinions-inc.com
+*/
+
+/*
+ Copyright 2001 Epinions, Inc.
+
+ Subject to the following 3 conditions, Epinions, Inc. permits you, free
+ of charge, to (a) use, copy, distribute, modify, perform and display this
+ software and associated documentation files (the "Software"), and (b)
+ permit others to whom the Software is furnished to do so as well.
+
+ 1) The above copyright notice and this permission notice shall be included
+ without modification in all copies or substantial portions of the
+ Software.
+
+ 2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF
+ ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY
+ IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ PURPOSE OR NONINFRINGEMENT.
+
+ 3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
+ OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING
+ NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH
+ DAMAGES.
+
+*/
+
+
+/****h* ABOUT/xmlrpc_introspection
+ * AUTHOR
+ * Dan Libby, aka danda (dan@libby.com)
+ * HISTORY
+ * $Log$
+ * Revision 1.4 2003/12/16 21:00:21 sniper
+ * Fix some compile warnings (patch by Joe Orton)
+ *
+ * Revision 1.3 2002/07/05 04:43:53 danda
+ * merged in updates from SF project. bring php repository up to date with xmlrpc-epi version 0.51
+ *
+ * Revision 1.9 2001/09/29 21:58:05 danda
+ * adding cvs log to history section
+ *
+ * 4/10/2001 -- danda -- initial introspection support
+ * TODO
+ * NOTES
+ *******/
+
+
+#ifdef _WIN32
+#include "xmlrpc_win32.h"
+#endif
+#include "queue.h"
+#include "xmlrpc.h"
+#include "xmlrpc_private.h"
+#include "xmlrpc_introspection_private.h"
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+
+/* forward declarations for static (non public, non api) funcs */
+static XMLRPC_VALUE xi_system_describe_methods_cb(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData);
+static XMLRPC_VALUE xi_system_list_methods_cb(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData);
+static XMLRPC_VALUE xi_system_method_signature_cb(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData);
+static XMLRPC_VALUE xi_system_method_help_cb(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData);
+
+
+/*-**********************************
+* Introspection Callbacks (methods) *
+************************************/
+
+/* iterates through a list of structs and finds the one with key "name" matching
+ * needle. slow, would benefit from a struct key hash.
+ */
+static inline XMLRPC_VALUE find_named_value(XMLRPC_VALUE list, const char* needle) {
+ XMLRPC_VALUE xIter = XMLRPC_VectorRewind(list);
+ while(xIter) {
+ const char* name = XMLRPC_VectorGetStringWithID(xIter, xi_token_name);
+ if(name && !strcmp(name, needle)) {
+ return xIter;
+ }
+ xIter = XMLRPC_VectorNext(list);
+ }
+ return NULL;
+}
+
+
+/* iterates through docs callbacks and calls any that have not yet been called */
+static void check_docs_loaded(XMLRPC_SERVER server, void* userData) {
+ if(server) {
+ q_iter qi = Q_Iter_Head_F(&server->docslist);
+ while( qi ) {
+ doc_method* dm = Q_Iter_Get_F(qi);
+ if(dm && !dm->b_called) {
+ dm->method(server, userData);
+ dm->b_called = 1;
+ }
+ qi = Q_Iter_Next_F(qi);
+ }
+ }
+}
+
+
+/* utility function for xi_system_describe_methods_cb */
+static inline void describe_method(XMLRPC_SERVER server, XMLRPC_VALUE vector, const char* method) {
+ if(method) {
+ server_method* sm = find_method(server, method);
+ if(sm) {
+ XMLRPC_AddValueToVector(vector, sm->desc);
+ }
+ }
+}
+
+
+
+/* system.describeMethods() callback */
+static XMLRPC_VALUE xi_system_describe_methods_cb(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData) {
+ XMLRPC_VALUE xParams = XMLRPC_VectorRewind(XMLRPC_RequestGetData(input));
+ XMLRPC_VALUE xResponse = XMLRPC_CreateVector(NULL, xmlrpc_vector_struct);
+ XMLRPC_VALUE xMethodList = XMLRPC_CreateVector("methodList", xmlrpc_vector_array);
+ XMLRPC_VALUE xTypeList = NULL;
+ int bAll = 1;
+
+ /* lazy loading of introspection data */
+ check_docs_loaded(server, userData);
+
+ xTypeList = XMLRPC_VectorGetValueWithID(server->xIntrospection, "typeList");
+
+ XMLRPC_AddValueToVector(xResponse, xTypeList);
+ XMLRPC_AddValueToVector(xResponse, xMethodList);
+
+ /* check if we have any param */
+ if(xParams) {
+ /* check if string or vector (1 or n) */
+ XMLRPC_VALUE_TYPE type = XMLRPC_GetValueType(xParams);
+ if(type == xmlrpc_string) {
+ /* just one. spit it out. */
+ describe_method(server, xMethodList, XMLRPC_GetValueString(xParams));
+ bAll = 0;
+ }
+ else if(type == xmlrpc_vector) {
+ /* multiple. spit all out */
+ XMLRPC_VALUE xIter = XMLRPC_VectorRewind(xParams);
+ while(xIter) {
+ describe_method(server, xMethodList, XMLRPC_GetValueString(xIter));
+ xIter = XMLRPC_VectorNext(xParams);
+ }
+ bAll = 0;
+ }
+ }
+
+ /* otherwise, default to sending all methods */
+ if(bAll) {
+ q_iter qi = Q_Iter_Head_F(&server->methodlist);
+ while( qi ) {
+ server_method* sm = Q_Iter_Get_F(qi);
+ if(sm) {
+ XMLRPC_AddValueToVector(xMethodList, sm->desc);
+ }
+ qi = Q_Iter_Next_F(qi);
+ }
+ }
+
+ return xResponse;
+}
+
+/* this complies with system.listMethods as defined at http://xmlrpc.usefulinc.com/doc/reserved.html */
+static XMLRPC_VALUE xi_system_list_methods_cb(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData) {
+ XMLRPC_VALUE xResponse = XMLRPC_CreateVector(NULL, xmlrpc_vector_array);
+
+ q_iter qi = Q_Iter_Head_F(&server->methodlist);
+ while( qi ) {
+ server_method* sm = Q_Iter_Get_F(qi);
+ if(sm) {
+ XMLRPC_VectorAppendString(xResponse, 0, sm->name, 0);
+ }
+ qi = Q_Iter_Next_F(qi);
+ }
+ return xResponse;
+}
+
+/* this complies with system.methodSignature as defined at
+ * http://xmlrpc.usefulinc.com/doc/sysmethodsig.html
+ */
+static XMLRPC_VALUE xi_system_method_signature_cb(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData) {
+ const char* method = XMLRPC_GetValueString(XMLRPC_VectorRewind(XMLRPC_RequestGetData(input)));
+ XMLRPC_VALUE xResponse = NULL;
+
+ /* lazy loading of introspection data */
+ check_docs_loaded(server, userData);
+
+ if(method) {
+ server_method* sm = find_method(server, method);
+ if(sm && sm->desc) {
+ XMLRPC_VALUE xTypesArray = XMLRPC_CreateVector(NULL, xmlrpc_vector_array);
+ XMLRPC_VALUE xIter, xParams, xSig, xSigIter;
+ const char* type;
+
+ /* array of possible signatures. */
+ xResponse = XMLRPC_CreateVector(NULL, xmlrpc_vector_array);
+
+ /* find first signature */
+ xSig = XMLRPC_VectorGetValueWithID(sm->desc, xi_token_signatures);
+ xSigIter = XMLRPC_VectorRewind( xSig );
+
+ /* iterate through sigs */
+ while(xSigIter) {
+ /* first type is the return value */
+ type = XMLRPC_VectorGetStringWithID(XMLRPC_VectorRewind(
+ XMLRPC_VectorGetValueWithID(xSigIter, xi_token_returns)),
+ xi_token_type);
+ XMLRPC_AddValueToVector(xTypesArray,
+ XMLRPC_CreateValueString(NULL,
+ type ? type : type_to_str(xmlrpc_none, 0),
+ 0));
+
+ /* the rest are parameters */
+ xParams = XMLRPC_VectorGetValueWithID(xSigIter, xi_token_params);
+ xIter = XMLRPC_VectorRewind(xParams);
+
+ /* iter through params, adding to types array */
+ while(xIter) {
+ XMLRPC_AddValueToVector(xTypesArray,
+ XMLRPC_CreateValueString(NULL,
+ XMLRPC_VectorGetStringWithID(xIter, xi_token_type),
+ 0));
+ xIter = XMLRPC_VectorNext(xParams);
+ }
+
+ /* add types for this signature */
+ XMLRPC_AddValueToVector(xResponse, xTypesArray);
+
+ xSigIter = XMLRPC_VectorNext( xSig );
+ }
+ }
+ }
+
+ return xResponse;
+}
+
+/* this complies with system.methodHelp as defined at
+ * http://xmlrpc.usefulinc.com/doc/sysmethhelp.html
+ */
+static XMLRPC_VALUE xi_system_method_help_cb(XMLRPC_SERVER server, XMLRPC_REQUEST input, void* userData) {
+ const char* method = XMLRPC_GetValueString(XMLRPC_VectorRewind(XMLRPC_RequestGetData(input)));
+ XMLRPC_VALUE xResponse = NULL;
+
+ /* lazy loading of introspection data */
+ check_docs_loaded(server, userData);
+
+ if(method) {
+ server_method* sm = find_method(server, method);
+ if(sm && sm->desc) {
+ const char* help = XMLRPC_VectorGetStringWithID(sm->desc, xi_token_purpose);
+
+ /* returns a documentation string, or empty string */
+ xResponse = XMLRPC_CreateValueString(NULL, help ? help : xi_token_empty, 0);
+ }
+ }
+
+ return xResponse;
+}
+
+/*-**************************************
+* End Introspection Callbacks (methods) *
+****************************************/
+
+
+/*-************************
+* Introspection Utilities *
+**************************/
+
+/* performs registration of introspection methods */
+void xi_register_system_methods(XMLRPC_SERVER server) {
+ XMLRPC_ServerRegisterMethod(server, xi_token_system_list_methods, xi_system_list_methods_cb);
+ XMLRPC_ServerRegisterMethod(server, xi_token_system_method_help, xi_system_method_help_cb);
+ XMLRPC_ServerRegisterMethod(server, xi_token_system_method_signature, xi_system_method_signature_cb);
+ XMLRPC_ServerRegisterMethod(server, xi_token_system_describe_methods, xi_system_describe_methods_cb);
+}
+
+/* describe a value (param, return, type) */
+static XMLRPC_VALUE describeValue_worker(const char* type, const char* id, const char* desc, int optional, const char* default_val, XMLRPC_VALUE sub_params) {
+ XMLRPC_VALUE xParam = NULL;
+ if(id || desc) {
+ xParam = XMLRPC_CreateVector(NULL, xmlrpc_vector_struct);
+ XMLRPC_VectorAppendString(xParam, xi_token_name, id, 0);
+ XMLRPC_VectorAppendString(xParam, xi_token_type, type, 0);
+ XMLRPC_VectorAppendString(xParam, xi_token_description, desc, 0);
+ if(optional != 2) {
+ XMLRPC_VectorAppendInt(xParam, xi_token_optional, optional);
+ }
+ if(optional == 1 && default_val) {
+ XMLRPC_VectorAppendString(xParam, xi_token_default, default_val, 0);
+ }
+ XMLRPC_AddValueToVector(xParam, sub_params);
+ }
+ return xParam;
+}
+
+
+/* convert an xml tree conforming to spec <url tbd> to XMLRPC_VALUE
+ * suitable for use with XMLRPC_ServerAddIntrospectionData
+ */
+XMLRPC_VALUE xml_element_to_method_description(xml_element* el, XMLRPC_ERROR err) {
+ XMLRPC_VALUE xReturn = NULL;
+
+ if(el->name) {
+ const char* name = NULL;
+ const char* type = NULL;
+ const char* basetype = NULL;
+ const char* desc = NULL;
+ const char* def = NULL;
+ int optional = 0;
+ xml_element_attr* attr_iter = Q_Head(&el->attrs);
+
+ /* grab element attributes up front to save redundant while loops */
+ while(attr_iter) {
+ if(!strcmp(attr_iter->key, "name")) {
+ name = attr_iter->val;
+ }
+ else if(!strcmp(attr_iter->key, "type")) {
+ type = attr_iter->val;
+ }
+ else if(!strcmp(attr_iter->key, "basetype")) {
+ basetype = attr_iter->val;
+ }
+ else if(!strcmp(attr_iter->key, "desc")) {
+ desc = attr_iter->val;
+ }
+ else if(!strcmp(attr_iter->key, "optional")) {
+ if(attr_iter->val && !strcmp(attr_iter->val, "yes")) {
+ optional = 1;
+ }
+ }
+ else if(!strcmp(attr_iter->key, "default")) {
+ def = attr_iter->val;
+ }
+ attr_iter = Q_Next(&el->attrs);
+ }
+
+ /* value and typeDescription behave about the same */
+ if(!strcmp(el->name, "value") || !strcmp(el->name, "typeDescription")) {
+ XMLRPC_VALUE xSubList = NULL;
+ const char* ptype = !strcmp(el->name, "value") ? type : basetype;
+ if(ptype) {
+ if(Q_Size(&el->children) &&
+ (!strcmp(ptype, "array") || !strcmp(ptype, "struct") || !strcmp(ptype, "mixed"))) {
+ xSubList = XMLRPC_CreateVector("member", xmlrpc_vector_array);
+
+ if(xSubList) {
+ xml_element* elem_iter = Q_Head(&el->children);
+ while(elem_iter) {
+ XMLRPC_AddValueToVector(xSubList,
+ xml_element_to_method_description(elem_iter, err));
+ elem_iter = Q_Next(&el->children);
+ }
+ }
+ }
+ xReturn = describeValue_worker(ptype, name, (desc ? desc : (xSubList ? NULL : el->text.str)), optional, def, xSubList);
+ }
+ }
+
+ /* these three kids are about equivalent */
+ else if(!strcmp(el->name, "params") ||
+ !strcmp(el->name, "returns") ||
+ !strcmp(el->name, "signature")) {
+ if(Q_Size(&el->children)) {
+ xml_element* elem_iter = Q_Head(&el->children);
+ xReturn = XMLRPC_CreateVector(!strcmp(el->name, "signature") ? NULL : el->name, xmlrpc_vector_struct);
+
+
+ while(elem_iter) {
+ XMLRPC_AddValueToVector(xReturn,
+ xml_element_to_method_description(elem_iter, err));
+ elem_iter = Q_Next(&el->children);
+ }
+ }
+ }
+
+
+ else if(!strcmp(el->name, "methodDescription")) {
+ xml_element* elem_iter = Q_Head(&el->children);
+ xReturn = XMLRPC_CreateVector(NULL, xmlrpc_vector_struct);
+
+ XMLRPC_VectorAppendString(xReturn, xi_token_name, name, 0);
+
+ while(elem_iter) {
+ XMLRPC_AddValueToVector(xReturn,
+ xml_element_to_method_description(elem_iter, err));
+ elem_iter = Q_Next(&el->children);
+ }
+ }
+
+ /* items are slightly special */
+ else if(!strcmp(el->name, "item")) {
+ xReturn = XMLRPC_CreateValueString(name, el->text.str, el->text.len);
+ }
+
+ /* sure. we'll let any ol element with children through */
+ else if(Q_Size(&el->children)) {
+ xml_element* elem_iter = Q_Head(&el->children);
+ xReturn = XMLRPC_CreateVector(el->name, xmlrpc_vector_mixed);
+
+ while(elem_iter) {
+ XMLRPC_AddValueToVector(xReturn,
+ xml_element_to_method_description(elem_iter, err));
+ elem_iter = Q_Next(&el->children);
+ }
+ }
+
+ /* or anything at all really, so long as its got some text.
+ * no reason being all snotty about a spec, right?
+ */
+ else if(el->name && el->text.len) {
+ xReturn = XMLRPC_CreateValueString(el->name, el->text.str, el->text.len);
+ }
+ }
+
+ return xReturn;
+}
+
+/*-****************************
+* End Introspection Utilities *
+******************************/
+
+
+
+/*-******************
+* Introspection API *
+********************/
+
+
+/****f* VALUE/XMLRPC_IntrospectionCreateDescription
+ * NAME
+ * XMLRPC_IntrospectionCreateDescription
+ * SYNOPSIS
+ * XMLRPC_VALUE XMLRPC_IntrospectionCreateDescription(const char* xml, XMLRPC_ERROR err)
+ * FUNCTION
+ * converts raw xml describing types and methods into an
+ * XMLRPC_VALUE suitable for use with XMLRPC_ServerAddIntrospectionData()
+ * INPUTS
+ * xml - xml data conforming to introspection spec at <url tbd>
+ * err - optional pointer to error struct. filled in if error occurs and not NULL.
+ * RESULT
+ * XMLRPC_VALUE - newly created value, or NULL if fatal error.
+ * BUGS
+ * Currently does little or no validation of xml.
+ * Only parse errors are currently reported in err, not structural errors.
+ * SEE ALSO
+ * XMLRPC_ServerAddIntrospectionData ()
+ * SOURCE
+ */
+XMLRPC_VALUE XMLRPC_IntrospectionCreateDescription(const char* xml, XMLRPC_ERROR err) {
+ XMLRPC_VALUE xReturn = NULL;
+ xml_element* root = xml_elem_parse_buf(xml, 0, 0, err ? &err->xml_elem_error : NULL);
+
+ if(root) {
+ xReturn = xml_element_to_method_description(root, err);
+
+ xml_elem_free(root);
+ }
+
+ return xReturn;
+
+}
+/*******/
+
+
+/****f* SERVER/XMLRPC_ServerAddIntrospectionData
+ * NAME
+ * XMLRPC_ServerAddIntrospectionData
+ * SYNOPSIS
+ * int XMLRPC_ServerAddIntrospectionData(XMLRPC_SERVER server, XMLRPC_VALUE desc)
+ * FUNCTION
+ * updates server with additional introspection data
+ * INPUTS
+ * server - target server
+ * desc - introspection data, should be a struct generated by
+ * XMLRPC_IntrospectionCreateDescription ()
+ * RESULT
+ * int - 1 if success, else 0
+ * NOTES
+ * - function will fail if neither typeList nor methodList key is present in struct.
+ * - if method or type already exists, it will be replaced.
+ * - desc is never freed by the server. caller is responsible for cleanup.
+ * BUGS
+ * - horribly slow lookups. prime candidate for hash improvements.
+ * - uglier and more complex than I like to see for API functions.
+ * SEE ALSO
+ * XMLRPC_ServerAddIntrospectionData ()
+ * XMLRPC_ServerRegisterIntrospectionCallback ()
+ * XMLRPC_CleanupValue ()
+ * SOURCE
+ */
+int XMLRPC_ServerAddIntrospectionData(XMLRPC_SERVER server, XMLRPC_VALUE desc) {
+ int bSuccess = 0;
+ if(server && desc) {
+ XMLRPC_VALUE xNewTypes = XMLRPC_VectorGetValueWithID(desc, "typeList");
+ XMLRPC_VALUE xNewMethods = XMLRPC_VectorGetValueWithID(desc, "methodList");
+ XMLRPC_VALUE xServerTypes = XMLRPC_VectorGetValueWithID(server->xIntrospection, "typeList");
+
+ if(xNewMethods) {
+ XMLRPC_VALUE xMethod = XMLRPC_VectorRewind(xNewMethods);
+
+ while(xMethod) {
+ const char* name = XMLRPC_VectorGetStringWithID(xMethod, xi_token_name);
+ server_method* sm = find_method(server, name);
+
+ if(sm) {
+ if(sm->desc) {
+ XMLRPC_CleanupValue(sm->desc);
+ }
+ sm->desc = XMLRPC_CopyValue(xMethod);
+ bSuccess = 1;
+ }
+
+ xMethod = XMLRPC_VectorNext(xNewMethods);
+ }
+ }
+ if(xNewTypes) {
+ if(!xServerTypes) {
+ if(!server->xIntrospection) {
+ server->xIntrospection = XMLRPC_CreateVector(NULL, xmlrpc_vector_struct);
+ }
+
+ XMLRPC_AddValueToVector(server->xIntrospection, xNewTypes);
+ bSuccess = 1;
+ }
+ else {
+ XMLRPC_VALUE xIter = XMLRPC_VectorRewind(xNewTypes);
+ while(xIter) {
+ /* get rid of old values */
+ XMLRPC_VALUE xPrev = find_named_value(xServerTypes, XMLRPC_VectorGetStringWithID(xIter, xi_token_name));
+ if(xPrev) {
+ XMLRPC_VectorRemoveValue(xServerTypes, xPrev);
+ }
+ XMLRPC_AddValueToVector(xServerTypes, xIter);
+ bSuccess = 1;
+ xIter = XMLRPC_VectorNext(xNewTypes);
+ }
+ }
+ }
+ }
+ return bSuccess;
+}
+/*******/
+
+
+/****f* SERVER/XMLRPC_ServerRegisterIntrospectionCallback
+ * NAME
+ * XMLRPC_ServerRegisterIntrospectionCallback
+ * SYNOPSIS
+ * int XMLRPC_ServerRegisterIntrospectionCallback(XMLRPC_SERVER server, XMLRPC_IntrospectionCallback cb)
+ * FUNCTION
+ * registers a callback for lazy generation of introspection data
+ * INPUTS
+ * server - target server
+ * cb - callback that will generate introspection data
+ * RESULT
+ * int - 1 if success, else 0
+ * NOTES
+ * parsing xml and generating introspection data is fairly expensive, thus a
+ * server may wish to wait until this data is actually requested before generating
+ * it. Any number of callbacks may be registered at any time. A given callback
+ * will only ever be called once, the first time an introspection request is
+ * processed after the time of callback registration.
+ * SEE ALSO
+ * XMLRPC_ServerAddIntrospectionData ()
+ * XMLRPC_IntrospectionCreateDescription ()
+ * SOURCE
+ */
+int XMLRPC_ServerRegisterIntrospectionCallback(XMLRPC_SERVER server, XMLRPC_IntrospectionCallback cb) {
+ int bSuccess = 0;
+ if(server && cb) {
+
+ doc_method* dm = calloc(1, sizeof(doc_method));
+
+ if(dm) {
+ dm->method = cb;
+ dm->b_called = 0;
+
+ if(Q_PushTail(&server->docslist, dm)) {
+ bSuccess = 1;
+ }
+ else {
+ my_free(dm);
+ }
+ }
+ }
+ return 0;
+}
+/*******/
+
+/*-**********************
+* End Introspection API *
+************************/
+
+
+
diff --git a/ext/xmlrpc/libxmlrpc/xmlrpc_introspection.h b/ext/xmlrpc/libxmlrpc/xmlrpc_introspection.h
new file mode 100644
index 0000000..656e441
--- /dev/null
+++ b/ext/xmlrpc/libxmlrpc/xmlrpc_introspection.h
@@ -0,0 +1,101 @@
+/*
+ This file is part of libXMLRPC - a C library for xml-encoded function calls.
+
+ Author: Dan Libby (dan@libby.com)
+ Epinions.com may be contacted at feedback@epinions-inc.com
+*/
+
+/*
+ Copyright 2000 Epinions, Inc.
+
+ Subject to the following 3 conditions, Epinions, Inc. permits you, free
+ of charge, to (a) use, copy, distribute, modify, perform and display this
+ software and associated documentation files (the "Software"), and (b)
+ permit others to whom the Software is furnished to do so as well.
+
+ 1) The above copyright notice and this permission notice shall be included
+ without modification in all copies or substantial portions of the
+ Software.
+
+ 2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF
+ ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY
+ IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ PURPOSE OR NONINFRINGEMENT.
+
+ 3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
+ OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING
+ NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH
+ DAMAGES.
+
+*/
+
+/* IMPORTANT!
+ *
+ * only public (official API) things should be in this file. Anything else
+ * should go in <group>_private.h, or in the appropriate .c file.
+ */
+
+
+#ifndef __XI_INTROSPECTION_H
+/*
+ * Avoid include redundancy.
+ */
+#define __XI_INTROSPECTION_H
+
+/*----------------------------------------------------------------------------
+ * xmlrpc_introspection.h
+ *
+ * Purpose:
+ * define public introspection API
+ * Comments:
+ */
+
+/*----------------------------------------------------------------------------
+ * Constants
+ */
+ #define xi_token_params "params"
+ #define xi_token_returns "returns"
+ #define xi_token_related "related"
+ #define xi_token_sub "sub"
+
+
+/*----------------------------------------------------------------------------
+ * Includes
+ */
+
+/*----------------------------------------------------------------------------
+ * Structures
+ */
+
+ /****d* VALUE/XMLRPC_IntrospectionCallback
+ * NAME
+ * XMLRPC_IntrospectionCallback
+ * NOTES
+ * Function prototype for lazy documentation generation (not generated until requested).
+ * SOURCE
+ */
+typedef void (*XMLRPC_IntrospectionCallback)(XMLRPC_SERVER server, void* userData);
+/******/
+
+
+/*----------------------------------------------------------------------------
+ * Globals
+ */
+
+/*----------------------------------------------------------------------------
+ * Functions
+ */
+XMLRPC_VALUE XMLRPC_IntrospectionCreateDescription(const char* xml, XMLRPC_ERROR error);
+int XMLRPC_ServerAddIntrospectionData(XMLRPC_SERVER server, XMLRPC_VALUE desc);
+int XMLRPC_ServerRegisterIntrospectionCallback(XMLRPC_SERVER server, XMLRPC_IntrospectionCallback cb);
+
+/*----------------------------------------------------------------------------
+ * Macros
+ */
+
+
+#endif /* __XI_INTROSPECTION_H */
+
+
+
diff --git a/ext/xmlrpc/libxmlrpc/xmlrpc_introspection_private.h b/ext/xmlrpc/libxmlrpc/xmlrpc_introspection_private.h
new file mode 100644
index 0000000..7b97fa7
--- /dev/null
+++ b/ext/xmlrpc/libxmlrpc/xmlrpc_introspection_private.h
@@ -0,0 +1,106 @@
+/*
+ This file is part of libXMLRPC - a C library for xml-encoded function calls.
+
+ Author: Dan Libby (dan@libby.com)
+ Epinions.com may be contacted at feedback@epinions-inc.com
+*/
+
+/*
+ Copyright 2001 Dan Libby, Epinions, Inc.
+
+ Subject to the following 3 conditions, Epinions, Inc. permits you, free
+ of charge, to (a) use, copy, distribute, modify, perform and display this
+ software and associated documentation files (the "Software"), and (b)
+ permit others to whom the Software is furnished to do so as well.
+
+ 1) The above copyright notice and this permission notice shall be included
+ without modification in all copies or substantial portions of the
+ Software.
+
+ 2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF
+ ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY
+ IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ PURPOSE OR NONINFRINGEMENT.
+
+ 3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
+ OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING
+ NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH
+ DAMAGES.
+
+*/
+
+/* IMPORTANT!
+ *
+ * only non-public things should be in this file. It is fine for any .c file
+ * in xmlrpc/src to include it, but users of the public API should never
+ * include it, and thus *.h files that are part of the public API should
+ * never include it, or they would break if this file is not present.
+ */
+
+
+#ifndef __XI_INTROSPECTION_PRIVATE_H
+/*
+ * Avoid include redundancy.
+ */
+#define __XI_INTROSPECTION_PRIVATE_H
+
+/*----------------------------------------------------------------------------
+ * xmlrpc_introspection_private.h
+ *
+ * Purpose:
+ * define non-public introspection routines
+ * Comments:
+ */
+
+/*----------------------------------------------------------------------------
+ * Constants
+ */
+#define xi_token_default "default"
+#define xi_token_description "description"
+#define xi_token_name "name"
+#define xi_token_optional "optional"
+#define xi_token_params "params"
+#define xi_token_purpose "purpose"
+#define xi_token_returns "returns"
+#define xi_token_signatures "signatures"
+#define xi_token_type "type"
+#define xi_token_version "version"
+#define xi_token_empty ""
+#define xi_token_system_describe_methods "system.describeMethods"
+#define xi_token_system_list_methods "system.listMethods"
+#define xi_token_system_method_help "system.methodHelp"
+#define xi_token_system_method_signature "system.methodSignature"
+
+
+/*----------------------------------------------------------------------------
+ * Includes
+ */
+
+/*----------------------------------------------------------------------------
+ * Structures
+ */
+typedef struct _doc_method {
+ XMLRPC_IntrospectionCallback method;
+ int b_called;
+} doc_method;
+
+/*----------------------------------------------------------------------------
+ * Globals
+ */
+
+/*----------------------------------------------------------------------------
+ * Functions
+ */
+void xi_register_system_methods(XMLRPC_SERVER server);
+
+/*----------------------------------------------------------------------------
+ * Macros
+ */
+
+
+#endif /* __XI_INTROSPECTION_PRIVATE_H */
+
+
+
+
diff --git a/ext/xmlrpc/libxmlrpc/xmlrpc_private.h b/ext/xmlrpc/libxmlrpc/xmlrpc_private.h
new file mode 100644
index 0000000..65c6b13
--- /dev/null
+++ b/ext/xmlrpc/libxmlrpc/xmlrpc_private.h
@@ -0,0 +1,178 @@
+/*
+ This file is part of libXMLRPC - a C library for xml-encoded function calls.
+
+ Author: Dan Libby (dan@libby.com)
+ Epinions.com may be contacted at feedback@epinions-inc.com
+*/
+
+/*
+ Copyright 2000 Epinions, Inc.
+
+ Subject to the following 3 conditions, Epinions, Inc. permits you, free
+ of charge, to (a) use, copy, distribute, modify, perform and display this
+ software and associated documentation files (the "Software"), and (b)
+ permit others to whom the Software is furnished to do so as well.
+
+ 1) The above copyright notice and this permission notice shall be included
+ without modification in all copies or substantial portions of the
+ Software.
+
+ 2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF
+ ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY
+ IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ PURPOSE OR NONINFRINGEMENT.
+
+ 3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
+ OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING
+ NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH
+ DAMAGES.
+
+*/
+
+/* only non-public things should be in this file. It is fine for any .c file
+ * in xmlrpc/src to include it, but users of the public API should never
+ * include it, and thus *.h files that are part of the public API should
+ * never include it, or they would break if this file is not present.
+ */
+
+#ifndef XMLRPC_PRIVATE_ALREADY_INCLUDED
+/*
+ * Avoid include redundancy.
+ */
+#define XMLRPC_PRIVATE_ALREADY_INCLUDED
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*----------------------------------------------------------------------------
+ * xmlrpc_private.h
+ *
+ * Purpose:
+ * define non-public intra-library routines & data
+ * Comments:
+ */
+
+/*----------------------------------------------------------------------------
+ * Constants
+ */
+
+
+/*----------------------------------------------------------------------------
+ * Includes
+ */
+
+/*----------------------------------------------------------------------------
+ * Structures
+ */
+
+/* Some of these are typedef'd in xmlrpc.h for public use */
+
+typedef struct _xmlrpc_vector* XMLRPC_VECTOR;
+
+/****s* VALUE/XMLRPC_VALUE
+ * NAME
+ * XMLRPC_VALUE
+ * NOTES
+ * A value of variable data type. The most important object in this API. :)
+ *
+ * This struct is opaque to callers and should be accessed only via accessor functions.
+ * SEE ALSO
+ * XMLRPC_REQUEST
+ * XMLRPC_CreateValueEmpty ()
+ * XMLRPC_CleanupValue ()
+ * SOURCE
+ */
+typedef struct _xmlrpc_value {
+ XMLRPC_VALUE_TYPE type; /* data type of this value */
+ XMLRPC_VECTOR v; /* vector type specific info */
+ simplestring str; /* string value buffer */
+ simplestring id; /* id of this value. possibly empty. */
+ int i; /* integer value. */
+ double d; /* double value */
+ int iRefCount; /* So we know when we can delete the value . */
+} STRUCT_XMLRPC_VALUE;
+/******/
+
+/****s* VALUE/XMLRPC_REQUEST
+ * NAME
+ * XMLRPC_REQUEST
+ * NOTES
+ * Internal representation of an XML request.
+ *
+ * This struct is opaque to callers and should be accessed only via accessor functions.
+ *
+ * SEE ALSO
+ * XMLRPC_VALUE
+ * XMLRPC_RequestNew ()
+ * XMLRPC_RequestFree ()
+ * SOURCE
+ */
+typedef struct _xmlrpc_request {
+ XMLRPC_VALUE io; /* data associated with this request */
+ simplestring methodName; /* name of method being called */
+ XMLRPC_REQUEST_TYPE request_type; /* type of request */
+ STRUCT_XMLRPC_REQUEST_OUTPUT_OPTIONS output; /* xml output options */
+ XMLRPC_VALUE error; /* error codes */
+} STRUCT_XMLRPC_REQUEST;
+/******/
+
+/* Vector type. Used by XMLRPC_VALUE. Never visible to users of the API. */
+typedef struct _xmlrpc_vector {
+ XMLRPC_VECTOR_TYPE type; /* vector type */
+ queue *q; /* list of child values */
+} STRUCT_XMLRPC_VECTOR;
+/******/
+
+/****s* VALUE/XMLRPC_SERVER
+ * NAME
+ * XMLRPC_SERVER
+ * NOTES
+ * internal representation of an xmlrpc server
+ *
+ * This struct is opaque to callers and should be accessed only via accessor functions.
+ *
+ * SEE ALSO
+ * XMLRPC_ServerCreate ()
+ * XMLRPC_ServerDestroy ()
+ * SOURCE
+ */
+typedef struct _xmlrpc_server {
+ queue methodlist; /* list of callback methods */
+ queue docslist; /* list of introspection callbacks */
+ XMLRPC_VALUE xIntrospection;
+} STRUCT_XMLRPC_SERVER;
+/******/
+
+typedef struct _server_method {
+ char* name;
+ XMLRPC_VALUE desc;
+ XMLRPC_Callback method;
+} server_method;
+
+
+/*----------------------------------------------------------------------------
+ * Globals
+ */
+
+/*----------------------------------------------------------------------------
+ * Functions
+ */
+server_method* find_method(XMLRPC_SERVER server, const char* name);
+const char* type_to_str(XMLRPC_VALUE_TYPE type, XMLRPC_VECTOR_TYPE vtype);
+
+/*----------------------------------------------------------------------------
+ * Macros
+ */
+#define my_free(thing) if(thing) {free(thing); thing = 0;}
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* XMLRPC_PRIVATE_ALREADY_INCLUDED */
+
diff --git a/ext/xmlrpc/libxmlrpc/xmlrpc_win32.h b/ext/xmlrpc/libxmlrpc/xmlrpc_win32.h
new file mode 100644
index 0000000..b212ccd
--- /dev/null
+++ b/ext/xmlrpc/libxmlrpc/xmlrpc_win32.h
@@ -0,0 +1,16 @@
+#ifndef _XMLRPC_WIN32_H
+#define _XMLRPC_WIN32_H
+/* just some things needed to compile win32 */
+#include <windows.h>
+#include <stdlib.h>
+#ifndef inline
+# define inline __inline
+#endif
+#ifndef snprintf
+# define snprintf _snprintf
+#endif
+#ifndef strcasecmp
+# define strcasecmp(s1, s2) stricmp(s1, s2)
+#endif
+
+#endif \ No newline at end of file
diff --git a/ext/xmlrpc/php_xmlrpc.h b/ext/xmlrpc/php_xmlrpc.h
new file mode 100644
index 0000000..00f9020
--- /dev/null
+++ b/ext/xmlrpc/php_xmlrpc.h
@@ -0,0 +1,96 @@
+/*
+ This file is part of, or distributed with, libXMLRPC - a C library for
+ xml-encoded function calls.
+
+ Author: Dan Libby (dan@libby.com)
+ Epinions.com may be contacted at feedback@epinions-inc.com
+*/
+
+/*
+ Copyright 2001 Epinions, Inc.
+
+ Subject to the following 3 conditions, Epinions, Inc. permits you, free
+ of charge, to (a) use, copy, distribute, modify, perform and display this
+ software and associated documentation files (the "Software"), and (b)
+ permit others to whom the Software is furnished to do so as well.
+
+ 1) The above copyright notice and this permission notice shall be included
+ without modification in all copies or substantial portions of the
+ Software.
+
+ 2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF
+ ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY
+ IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ PURPOSE OR NONINFRINGEMENT.
+
+ 3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
+ OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING
+ NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH
+ DAMAGES.
+
+*/
+
+/* auto-generated portions of this file are also subject to the php license */
+
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Dan Libby |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+#ifndef _PHP_XMLRPC_H
+#define _PHP_XMLRPC_H
+
+#if 1 /* HAVE_XMLRPC */
+
+extern zend_module_entry xmlrpc_module_entry;
+#define phpext_xmlrpc_ptr &xmlrpc_module_entry
+
+PHP_MINIT_FUNCTION(xmlrpc);
+PHP_MINFO_FUNCTION(xmlrpc);
+
+PHP_FUNCTION(xmlrpc_encode);
+PHP_FUNCTION(xmlrpc_decode);
+PHP_FUNCTION(xmlrpc_decode_request);
+PHP_FUNCTION(xmlrpc_encode_request);
+PHP_FUNCTION(xmlrpc_get_type);
+PHP_FUNCTION(xmlrpc_set_type);
+PHP_FUNCTION(xmlrpc_is_fault);
+PHP_FUNCTION(xmlrpc_server_create);
+PHP_FUNCTION(xmlrpc_server_destroy);
+PHP_FUNCTION(xmlrpc_server_register_method);
+PHP_FUNCTION(xmlrpc_server_call_method);
+PHP_FUNCTION(xmlrpc_parse_method_descriptions);
+PHP_FUNCTION(xmlrpc_server_add_introspection_data);
+PHP_FUNCTION(xmlrpc_server_register_introspection_callback);
+
+#else
+
+#define phpext_xmlrpc_ptr NULL
+
+#endif
+
+#endif /* _PHP_XMLRPC_H */
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
diff --git a/ext/xmlrpc/tests/001.phpt b/ext/xmlrpc/tests/001.phpt
new file mode 100644
index 0000000..2625096
--- /dev/null
+++ b/ext/xmlrpc/tests/001.phpt
@@ -0,0 +1,55 @@
+--TEST--
+xmlrpc_encode_request() with wrong arguments
+--SKIPIF--
+<?php if (!extension_loaded("xmlrpc")) print "skip"; ?>
+--FILE--
+<?php
+
+var_dump(xmlrpc_encode_request(-1, 1));
+var_dump(xmlrpc_encode_request("", 1));
+var_dump(xmlrpc_encode_request(array(), 1));
+var_dump(xmlrpc_encode_request(3.4, 1));
+
+echo "Done\n";
+?>
+--EXPECTF--
+string(174) "<?xml version="1.0" encoding="iso-8859-1"?>
+<methodCall>
+<methodName>-1</methodName>
+<params>
+ <param>
+ <value>
+ <int>1</int>
+ </value>
+ </param>
+</params>
+</methodCall>
+"
+string(160) "<?xml version="1.0" encoding="iso-8859-1"?>
+<methodCall>
+<methodName/>
+<params>
+ <param>
+ <value>
+ <int>1</int>
+ </value>
+ </param>
+</params>
+</methodCall>
+"
+
+Warning: xmlrpc_encode_request() expects parameter 1 to be string, array given in %s on line %d
+NULL
+string(175) "<?xml version="1.0" encoding="iso-8859-1"?>
+<methodCall>
+<methodName>3.4</methodName>
+<params>
+ <param>
+ <value>
+ <int>1</int>
+ </value>
+ </param>
+</params>
+</methodCall>
+"
+Done
diff --git a/ext/xmlrpc/tests/002.phpt b/ext/xmlrpc/tests/002.phpt
new file mode 100644
index 0000000..8358646
--- /dev/null
+++ b/ext/xmlrpc/tests/002.phpt
@@ -0,0 +1,53 @@
+--TEST--
+xmlrpc_encode_request() and various arguments
+--SKIPIF--
+<?php if (!extension_loaded("xmlrpc")) print "skip"; ?>
+--FILE--
+<?php
+
+$r = xmlrpc_encode_request("method", array());
+var_dump(xmlrpc_decode_request($r, $method));
+var_dump($method);
+
+$r = xmlrpc_encode_request("method", 1);
+var_dump(xmlrpc_decode_request($r, $method));
+var_dump($method);
+
+$r = xmlrpc_encode_request("method", 'param');
+var_dump(xmlrpc_decode_request($r, $method));
+var_dump($method);
+
+$r = xmlrpc_encode_request(-1, "");
+var_dump(xmlrpc_decode_request($r, $method));
+var_dump($method);
+
+$r = xmlrpc_encode_request(array(), 1);
+var_dump(xmlrpc_decode_request($r, $method));
+var_dump($method);
+
+echo "Done\n";
+?>
+--EXPECTF--
+array(0) {
+}
+string(6) "method"
+array(1) {
+ [0]=>
+ int(1)
+}
+string(6) "method"
+array(1) {
+ [0]=>
+ string(5) "param"
+}
+string(6) "method"
+array(1) {
+ [0]=>
+ string(0) ""
+}
+string(2) "-1"
+
+Warning: xmlrpc_encode_request() expects parameter 1 to be string, array given in %s on line %d
+NULL
+string(2) "-1"
+Done
diff --git a/ext/xmlrpc/tests/bug18916.phpt b/ext/xmlrpc/tests/bug18916.phpt
new file mode 100644
index 0000000..487838b
--- /dev/null
+++ b/ext/xmlrpc/tests/bug18916.phpt
@@ -0,0 +1,23 @@
+--TEST--
+Bug #18916 (xmlrpc_set_type() not working)
+--SKIPIF--
+<?php if (!extension_loaded("xmlrpc")) print "skip"; ?>
+--INI--
+date.timezone="America/Sao_Paulo"
+--FILE--
+<?php
+
+$params = date("Ymd\TH:i:s", time());
+xmlrpc_set_type($params, 'datetime');
+echo xmlrpc_encode($params);
+
+?>
+--EXPECTF--
+<?xml version="1.0" encoding="utf-8"?>
+<params>
+<param>
+ <value>
+ <dateTime.iso8601>%dT%d:%d:%d</dateTime.iso8601>
+ </value>
+</param>
+</params>
diff --git a/ext/xmlrpc/tests/bug37057.phpt b/ext/xmlrpc/tests/bug37057.phpt
new file mode 100644
index 0000000..013cc91
--- /dev/null
+++ b/ext/xmlrpc/tests/bug37057.phpt
@@ -0,0 +1,64 @@
+--TEST--
+Bug #37057 (xmlrpc_decode() may produce arrays with numeric string keys which are unaccessible)
+--SKIPIF--
+<?php if (!extension_loaded("xmlrpc")) print "skip"; ?>
+--FILE--
+<?php
+$response='<?xml version="1.0"?>
+<methodResponse>
+ <params>
+ <param>
+ <value>
+ <struct>
+ <member>
+ <name>50</name>
+ <value><string>0.29</string></value>
+ </member>
+ </struct>
+ </value>
+ </param>
+ </params>
+</methodResponse>';
+
+$retval=xmlrpc_decode($response);
+var_dump($retval);
+var_dump($retval["50"]);
+var_dump($retval[50]);
+
+$response='<?xml version="1.0"?>
+<methodResponse>
+ <params>
+ <param>
+ <value>
+ <struct>
+ <member>
+ <name>0</name>
+ <value><string>0.29</string></value>
+ </member>
+ </struct>
+ </value>
+ </param>
+ </params>
+</methodResponse>';
+
+$retval=xmlrpc_decode($response);
+var_dump($retval);
+var_dump($retval["0"]);
+var_dump($retval[0]);
+
+echo "Done\n";
+?>
+--EXPECT--
+array(1) {
+ [50]=>
+ string(4) "0.29"
+}
+string(4) "0.29"
+string(4) "0.29"
+array(1) {
+ [0]=>
+ string(4) "0.29"
+}
+string(4) "0.29"
+string(4) "0.29"
+Done
diff --git a/ext/xmlrpc/tests/bug38431.phpt b/ext/xmlrpc/tests/bug38431.phpt
new file mode 100644
index 0000000..288fe10
--- /dev/null
+++ b/ext/xmlrpc/tests/bug38431.phpt
@@ -0,0 +1,25 @@
+--TEST--
+Bug #38431 (xmlrpc_get_type() crashes PHP on objects)
+--SKIPIF--
+<?php if (!extension_loaded("xmlrpc")) print "skip"; ?>
+--FILE--
+<?php
+
+var_dump(xmlrpc_get_type(new stdclass));
+var_dump(xmlrpc_get_type(array()));
+$var = array(1,2,3);
+var_dump(xmlrpc_get_type($var));
+$var = array("test"=>1,2,3);
+var_dump(xmlrpc_get_type($var));
+$var = array("test"=>1,"test2"=>2);
+var_dump(xmlrpc_get_type($var));
+
+echo "Done\n";
+?>
+--EXPECTF--
+string(5) "array"
+string(5) "array"
+string(5) "array"
+string(5) "mixed"
+string(6) "struct"
+Done
diff --git a/ext/xmlrpc/tests/bug40576.phpt b/ext/xmlrpc/tests/bug40576.phpt
new file mode 100644
index 0000000..404aba3
--- /dev/null
+++ b/ext/xmlrpc/tests/bug40576.phpt
@@ -0,0 +1,77 @@
+--TEST--
+Bug #40576 (double values are truncated to 6 decimal digits when encoding)
+--SKIPIF--
+<?php
+if (!extension_loaded("xmlrpc")) print "skip";
+if (PHP_INT_SIZE != 4) die("skip this test is for 32bit platform only");
+?>
+--INI--
+precision=12
+--FILE--
+<?php
+
+var_dump(xmlrpc_encode(1.123456789));
+var_dump(xmlrpc_encode(11234567891010));
+var_dump(xmlrpc_encode(11234567));
+var_dump(xmlrpc_encode(""));
+var_dump(xmlrpc_encode("test"));
+var_dump(xmlrpc_encode("1.22222222222222222222222"));
+
+echo "Done\n";
+?>
+--EXPECTF--
+string(125) "<?xml version="1.0" encoding="utf-8"?>
+<params>
+<param>
+ <value>
+ <double>1.123456789</double>
+ </value>
+</param>
+</params>
+"
+string(130) "<?xml version="1.0" encoding="utf-8"?>
+<params>
+<param>
+ <value>
+ <double>1.1234567891E+13</double>
+ </value>
+</param>
+</params>
+"
+string(116) "<?xml version="1.0" encoding="utf-8"?>
+<params>
+<param>
+ <value>
+ <int>11234567</int>
+ </value>
+</param>
+</params>
+"
+string(106) "<?xml version="1.0" encoding="utf-8"?>
+<params>
+<param>
+ <value>
+ <string/>
+ </value>
+</param>
+</params>
+"
+string(118) "<?xml version="1.0" encoding="utf-8"?>
+<params>
+<param>
+ <value>
+ <string>test</string>
+ </value>
+</param>
+</params>
+"
+string(139) "<?xml version="1.0" encoding="utf-8"?>
+<params>
+<param>
+ <value>
+ <string>1.22222222222222222222222</string>
+ </value>
+</param>
+</params>
+"
+Done
diff --git a/ext/xmlrpc/tests/bug40576_64bit.phpt b/ext/xmlrpc/tests/bug40576_64bit.phpt
new file mode 100644
index 0000000..bb4cbe7
--- /dev/null
+++ b/ext/xmlrpc/tests/bug40576_64bit.phpt
@@ -0,0 +1,77 @@
+--TEST--
+Bug #40576 (double values are truncated to 6 decimal digits when encoding)
+--SKIPIF--
+<?php
+if (!extension_loaded("xmlrpc")) print "skip";
+if (PHP_INT_SIZE != 8) die("skip this test is for 64bit platform only");
+?>
+--INI--
+precision=12
+--FILE--
+<?php
+
+var_dump(xmlrpc_encode(1.123456789));
+var_dump(xmlrpc_encode(11234567891010));
+var_dump(xmlrpc_encode(11234567));
+var_dump(xmlrpc_encode(""));
+var_dump(xmlrpc_encode("test"));
+var_dump(xmlrpc_encode("1.22222222222222222222222"));
+
+echo "Done\n";
+?>
+--EXPECTF--
+string(125) "<?xml version="1.0" encoding="utf-8"?>
+<params>
+<param>
+ <value>
+ <double>1.123456789</double>
+ </value>
+</param>
+</params>
+"
+string(119) "<?xml version="1.0" encoding="utf-8"?>
+<params>
+<param>
+ <value>
+ <int>-1066555326</int>
+ </value>
+</param>
+</params>
+"
+string(116) "<?xml version="1.0" encoding="utf-8"?>
+<params>
+<param>
+ <value>
+ <int>11234567</int>
+ </value>
+</param>
+</params>
+"
+string(106) "<?xml version="1.0" encoding="utf-8"?>
+<params>
+<param>
+ <value>
+ <string/>
+ </value>
+</param>
+</params>
+"
+string(118) "<?xml version="1.0" encoding="utf-8"?>
+<params>
+<param>
+ <value>
+ <string>test</string>
+ </value>
+</param>
+</params>
+"
+string(139) "<?xml version="1.0" encoding="utf-8"?>
+<params>
+<param>
+ <value>
+ <string>1.22222222222222222222222</string>
+ </value>
+</param>
+</params>
+"
+Done
diff --git a/ext/xmlrpc/tests/bug42189.phpt b/ext/xmlrpc/tests/bug42189.phpt
new file mode 100644
index 0000000..55e726c
--- /dev/null
+++ b/ext/xmlrpc/tests/bug42189.phpt
@@ -0,0 +1,15 @@
+--TEST--
+Bug #42189 (xmlrpc_get_type() crashes PHP on invalid dates)
+--SKIPIF--
+<?php if (!extension_loaded("xmlrpc")) print "skip"; ?>
+--FILE--
+<?php
+$a = '~~~~~~~~~~~~~~~~~~';
+$ok = xmlrpc_set_type($a, 'datetime');
+var_dump($ok);
+
+echo "Done\n";
+?>
+--EXPECT--
+bool(false)
+Done
diff --git a/ext/xmlrpc/tests/bug42736.phpt b/ext/xmlrpc/tests/bug42736.phpt
new file mode 100644
index 0000000..b9a46cf
--- /dev/null
+++ b/ext/xmlrpc/tests/bug42736.phpt
@@ -0,0 +1,56 @@
+--TEST--
+Bug #42736 (xmlrpc_server_call_method() crashes)
+--SKIPIF--
+<?php if (!extension_loaded("xmlrpc")) print "skip"; ?>
+--FILE--
+<?php
+
+class SOAP_Array {
+ public function get($id){
+ return $this->add($id);
+ }
+}
+
+$xml = xmlrpc_server_create();
+
+$Myrequest = '<?xml version="1.0" encoding="UTF-8"?><methodCall><methodName>GetProducts</methodName><params><param><value><dateTime.iso8601>20060922T14:26:19</dateTime.iso8601></value></param></params></methodCall>';
+
+class MyClass {
+ function GetProducts($dummy, $time){
+ return array('faultString' => $time);
+ }
+}
+$myclass = new MyClass();
+xmlrpc_server_register_method($xml, 'GetProducts', array($myclass, 'GetProducts'));
+$response = xmlrpc_server_call_method($xml, $Myrequest, null);
+
+var_dump($response);
+
+echo "Done\n";
+?>
+--EXPECTF--
+string(402) "<?xml version="1.0" encoding="iso-8859-1"?>
+<methodResponse>
+<params>
+ <param>
+ <value>
+ <struct>
+ <member>
+ <name>faultString</name>
+ <value>
+ <array>
+ <data>
+ <value>
+ <dateTime.iso8601>20060922T14:26:19</dateTime.iso8601>
+ </value>
+ </data>
+ </array>
+ </value>
+ </member>
+ </struct>
+ </value>
+ </param>
+</params>
+</methodResponse>
+"
+Done
diff --git a/ext/xmlrpc/tests/bug44996.phpt b/ext/xmlrpc/tests/bug44996.phpt
new file mode 100644
index 0000000..0f4d016
--- /dev/null
+++ b/ext/xmlrpc/tests/bug44996.phpt
@@ -0,0 +1,51 @@
+--TEST--
+Bug #44996 (xmlrpc_decode() ignores time zone on iso8601.datetime)
+--SKIPIF--
+<?php if (!extension_loaded("xmlrpc")) print "skip"; ?>
+--FILE--
+<?php
+
+function DecodeDatetime($datetime) {
+ print "\nISO 8601 datetime $datetime\n";
+ $obj = xmlrpc_decode("<?xml version=\"1.0\"?><methodResponse><params><param><value><dateTime.iso8601>$datetime</dateTime.iso8601></value></param></params></methodResponse>");
+ print_r($obj);
+}
+
+DecodeDatetime("20010909T01:46:40Z");
+DecodeDatetime("20010909T00:46:40-01");
+DecodeDatetime("2001-09-09T08:46:40+07:00");
+DecodeDatetime("2001-09-08T21:46:40-0400");
+
+?>
+--EXPECT--
+ISO 8601 datetime 20010909T01:46:40Z
+stdClass Object
+(
+ [scalar] => 20010909T01:46:40Z
+ [xmlrpc_type] => datetime
+ [timestamp] => 1000000000
+)
+
+ISO 8601 datetime 20010909T00:46:40-01
+stdClass Object
+(
+ [scalar] => 20010909T00:46:40-01
+ [xmlrpc_type] => datetime
+ [timestamp] => 1000000000
+)
+
+ISO 8601 datetime 2001-09-09T08:46:40+07:00
+stdClass Object
+(
+ [scalar] => 2001-09-09T08:46:40+07:00
+ [xmlrpc_type] => datetime
+ [timestamp] => 1000000000
+)
+
+ISO 8601 datetime 2001-09-08T21:46:40-0400
+stdClass Object
+(
+ [scalar] => 2001-09-08T21:46:40-0400
+ [xmlrpc_type] => datetime
+ [timestamp] => 1000000000
+)
diff --git a/ext/xmlrpc/tests/bug45226.phpt b/ext/xmlrpc/tests/bug45226.phpt
new file mode 100644
index 0000000..e053850
--- /dev/null
+++ b/ext/xmlrpc/tests/bug45226.phpt
@@ -0,0 +1,55 @@
+--TEST--
+Bug #45226 (xmlrpc_set_type() segfaults with valid ISO8601 date string)
+--INI--
+date.timezone="America/Sao_Paulo"
+--SKIPIF--
+<?php if (!extension_loaded("xmlrpc")) print "skip"; ?>
+--FILE--
+<?php
+
+$d = date(DATE_ISO8601);
+xmlrpc_set_type($d, 'datetime');
+echo xmlrpc_encode_request('method.call', array('date' => $d));
+
+$d = '2008-01-01 20:00:00';
+xmlrpc_set_type($d, 'datetime');
+echo xmlrpc_encode_request('method.call', array('date' => $d));
+
+?>
+--EXPECTF--
+<?xml version="1.0" encoding="iso-8859-1"?>
+<methodCall>
+<methodName>method.call</methodName>
+<params>
+ <param>
+ <value>
+ <struct>
+ <member>
+ <name>date</name>
+ <value>
+ <dateTime.iso8601>%d-%d-%dT%d:%d:%d%s%d</dateTime.iso8601>
+ </value>
+ </member>
+ </struct>
+ </value>
+ </param>
+</params>
+</methodCall>
+<?xml version="1.0" encoding="iso-8859-1"?>
+<methodCall>
+<methodName>method.call</methodName>
+<params>
+ <param>
+ <value>
+ <struct>
+ <member>
+ <name>date</name>
+ <value>
+ <dateTime.iso8601>%d-%d-%d %d:%d:%d</dateTime.iso8601>
+ </value>
+ </member>
+ </struct>
+ </value>
+ </param>
+</params>
+</methodCall>
diff --git a/ext/xmlrpc/tests/bug45555.phpt b/ext/xmlrpc/tests/bug45555.phpt
new file mode 100644
index 0000000..6b3da24
--- /dev/null
+++ b/ext/xmlrpc/tests/bug45555.phpt
@@ -0,0 +1,22 @@
+--TEST--
+Bug #45555 (Segfault with invalid non-string as register_introspection_callback)
+--SKIPIF--
+<?php if (!extension_loaded("xmlrpc")) print "skip"; ?>
+--FILE--
+<?php
+
+$options = array ();
+$request = xmlrpc_encode_request ("system.describeMethods", $options);
+$server = xmlrpc_server_create ();
+
+xmlrpc_server_register_introspection_callback($server, 1);
+xmlrpc_server_register_introspection_callback($server, array('foo', 'bar'));
+
+$options = array ('output_type' => 'xml', 'version' => 'xmlrpc');
+xmlrpc_server_call_method ($server, $request, NULL, $options);
+
+?>
+--EXPECTF--
+Warning: xmlrpc_server_call_method(): Invalid callback '1' passed in %s on line %d
+
+Warning: xmlrpc_server_call_method(): Invalid callback 'foo::bar' passed in %s on line %d
diff --git a/ext/xmlrpc/tests/bug45556.phpt b/ext/xmlrpc/tests/bug45556.phpt
new file mode 100644
index 0000000..34897d8
--- /dev/null
+++ b/ext/xmlrpc/tests/bug45556.phpt
@@ -0,0 +1,34 @@
+--TEST--
+Bug #45556 (Return value from callback isn't freed)
+--SKIPIF--
+<?php if (!extension_loaded("xmlrpc")) print "skip"; ?>
+--FILE--
+<?php
+
+$options = array ();
+$request = xmlrpc_encode_request ("system.describeMethods", $options);
+$server = xmlrpc_server_create ();
+
+
+function foo() { return 11111; }
+
+class bar {
+ static public function test() {
+ return 'foo';
+ }
+}
+
+xmlrpc_server_register_introspection_callback($server, 'foobar');
+xmlrpc_server_register_introspection_callback($server, array('bar', 'test'));
+xmlrpc_server_register_introspection_callback($server, array('foo', 'bar'));
+
+$options = array ('output_type' => 'xml', 'version' => 'xmlrpc');
+xmlrpc_server_call_method ($server, $request, NULL, $options);
+
+?>
+--EXPECTF--
+Warning: xmlrpc_server_call_method(): Invalid callback 'foobar' passed in %s on line %d
+
+Warning: xmlrpc_server_call_method(): xml parse error: [line 1, column 1, message: Invalid document end] Unable to add introspection data returned from bar::test() in %s on line %d
+
+Warning: xmlrpc_server_call_method(): Invalid callback 'foo::bar' passed in %s on line %d
diff --git a/ext/xmlrpc/tests/bug47818.phpt b/ext/xmlrpc/tests/bug47818.phpt
new file mode 100644
index 0000000..a2944d8
--- /dev/null
+++ b/ext/xmlrpc/tests/bug47818.phpt
@@ -0,0 +1,41 @@
+--TEST--
+Bug #47818 (Segfault due to bound callback param)
+--SKIPIF--
+<?php if (!extension_loaded("xmlrpc")) print "skip"; ?>
+--FILE--
+<?php
+
+class MyXmlRpc {
+ private $s;
+ private $method;
+
+ function impl($method_name, $params, $user_data){
+ $this->method = $method_name;
+ print "Inside impl(): {$this->method}\n";
+ return array_sum($params);
+ }
+
+ function __construct() {
+ $this->s = xmlrpc_server_create();
+ xmlrpc_server_register_method($this->s, 'add', array($this, 'impl'));
+ }
+
+ function call($req) {
+ return xmlrpc_server_call_method($this->s, $req, null);
+ }
+
+ function getMethod() {return $this->method;}
+
+}
+
+$x = new MyXmlRpc;
+$resp = $x->call(xmlrpc_encode_request('add', array(1, 2, 3)));
+
+$method = $x->getMethod();
+
+print "Global scope: $method\n";
+
+?>
+--EXPECTF--
+Inside impl(): add
+Global scope: add
diff --git a/ext/xmlrpc/tests/bug50282.phpt b/ext/xmlrpc/tests/bug50282.phpt
new file mode 100644
index 0000000..eb35fe3
--- /dev/null
+++ b/ext/xmlrpc/tests/bug50282.phpt
@@ -0,0 +1,43 @@
+--TEST--
+Bug #50282 (xmlrpc_encode_request() changes object into array in calling function)
+--SKIPIF--
+<?php if (!extension_loaded("xmlrpc")) print "skip"; ?>
+--FILE--
+<?php
+
+class One { var $x = 10; }
+
+$o = new One();
+var_dump($o);
+var_dump(xmlrpc_encode_request('test', $o));
+var_dump($o);
+
+?>
+--EXPECTF--
+object(One)#%d (1) {
+ ["x"]=>
+ int(10)
+}
+string(279) "<?xml version="1.0" encoding="iso-8859-1"?>
+<methodCall>
+<methodName>test</methodName>
+<params>
+ <param>
+ <value>
+ <struct>
+ <member>
+ <name>x</name>
+ <value>
+ <int>10</int>
+ </value>
+ </member>
+ </struct>
+ </value>
+ </param>
+</params>
+</methodCall>
+"
+object(One)#%d (1) {
+ ["x"]=>
+ int(10)
+}
diff --git a/ext/xmlrpc/tests/bug50285.phpt b/ext/xmlrpc/tests/bug50285.phpt
new file mode 100644
index 0000000..5da803c
--- /dev/null
+++ b/ext/xmlrpc/tests/bug50285.phpt
@@ -0,0 +1,117 @@
+--TEST--
+Bug #50285 (xmlrpc does not preserve keys in encoded indexed arrays)
+--SKIPIF--
+<?php if (!extension_loaded("xmlrpc")) print "skip"; ?>
+--FILE--
+<?php
+
+function test1($func, $params) {
+ return array(1=>'One', 3=>'Three', 5=>'Five');
+}
+
+function test2($func, $params) {
+ return array('One', 'Three', 'Five', 5);
+}
+
+function test3($func, $params) {
+ return array('One', 3 => 'Three', b'Five' => 5, 'Six');
+}
+
+function test4($func, $params) {
+ return array('One', 'Three', 'Five', b'Six' => 6);
+}
+
+$server = xmlrpc_server_create();
+$result = xmlrpc_server_register_method($server, 'test1', 'test1');
+$HTTP_RAW_POST_DATA = <<<EOD
+<?xml version="1.0" encoding="UTF-8"?>
+<methodCall>
+<methodName>test1</methodName>
+<params />
+</methodCall>
+EOD;
+$response = xmlrpc_server_call_method($server, $HTTP_RAW_POST_DATA, null);
+var_dump(xmlrpc_decode($response));
+
+// ------------
+
+$server = xmlrpc_server_create();
+$result = xmlrpc_server_register_method($server, 'test2', 'test2');
+$HTTP_RAW_POST_DATA = <<<EOD
+<?xml version="1.0" encoding="UTF-8"?>
+<methodCall>
+<methodName>test2</methodName>
+<params />
+</methodCall>
+EOD;
+$response = xmlrpc_server_call_method($server, $HTTP_RAW_POST_DATA, null);
+var_dump(xmlrpc_decode($response));
+
+// ------------
+
+$server = xmlrpc_server_create();
+$result = xmlrpc_server_register_method($server, 'test3', 'test3');
+$HTTP_RAW_POST_DATA = <<<EOD
+<?xml version="1.0" encoding="UTF-8"?>
+<methodCall>
+<methodName>test3</methodName>
+<params />
+</methodCall>
+EOD;
+$response = xmlrpc_server_call_method($server, $HTTP_RAW_POST_DATA, null);
+var_dump(xmlrpc_decode($response));
+
+// ------------
+
+$server = xmlrpc_server_create();
+$result = xmlrpc_server_register_method($server, 'test4', 'test4');
+$HTTP_RAW_POST_DATA = <<<EOD
+<?xml version="1.0" encoding="UTF-8"?>
+<methodCall>
+<methodName>test4</methodName>
+<params />
+</methodCall>
+EOD;
+$response = xmlrpc_server_call_method($server, $HTTP_RAW_POST_DATA, null);
+var_dump(xmlrpc_decode($response));
+
+?>
+--EXPECT--
+array(3) {
+ [1]=>
+ string(3) "One"
+ [3]=>
+ string(5) "Three"
+ [5]=>
+ string(4) "Five"
+}
+array(4) {
+ [0]=>
+ string(3) "One"
+ [1]=>
+ string(5) "Three"
+ [2]=>
+ string(4) "Five"
+ [3]=>
+ int(5)
+}
+array(4) {
+ [0]=>
+ string(3) "One"
+ [3]=>
+ string(5) "Three"
+ ["Five"]=>
+ int(5)
+ [4]=>
+ string(3) "Six"
+}
+array(4) {
+ [0]=>
+ string(3) "One"
+ [1]=>
+ string(5) "Three"
+ [2]=>
+ string(4) "Five"
+ ["Six"]=>
+ int(6)
+}
diff --git a/ext/xmlrpc/tests/bug50761.phpt b/ext/xmlrpc/tests/bug50761.phpt
new file mode 100644
index 0000000..ada1940
--- /dev/null
+++ b/ext/xmlrpc/tests/bug50761.phpt
@@ -0,0 +1,64 @@
+--TEST--
+Bug #50761 (system.multiCall crashes)
+--SKIPIF--
+<?php if (!extension_loaded("xmlrpc")) print "skip"; ?>
+--FILE--
+<?php
+$req = '<?xml version="1.0"?>
+<methodCall>
+<methodName>system.multiCall</methodName>
+<params><param><value><array><data>
+<value><struct>
+<member><name>methodName</name><value><string>testMethodA</string></value></member>
+<member><name>params</name><value><array><data><value><string>A</string>
+</value></data></array></value></member>
+</struct></value>
+<value><struct>
+<member><name>methodName</name><value><string>testMethodB</string></value></member>
+<member><name>params</name><value><array><data><value><string>B</string>
+</value></data></array></value></member>
+</struct></value>
+</data></array></value></param></params>
+</methodCall>';
+
+function testA($methodName, $params, $var){ return "C"; }
+function testB($methodName, $params, $var){ return "D"; }
+
+$server = xmlrpc_server_create();
+xmlrpc_server_register_method($server, 'testMethodA', 'testA');
+xmlrpc_server_register_method($server, 'testMethodB', 'testB');
+$res = xmlrpc_server_call_method($server, $req, null);
+echo $res;
+?>
+--EXPECT--
+<?xml version="1.0" encoding="iso-8859-1"?>
+<methodResponse>
+<params>
+ <param>
+ <value>
+ <array>
+ <data>
+ <value>
+ <array>
+ <data>
+ <value>
+ <string>C</string>
+ </value>
+ </data>
+ </array>
+ </value>
+ <value>
+ <array>
+ <data>
+ <value>
+ <string>D</string>
+ </value>
+ </data>
+ </array>
+ </value>
+ </data>
+ </array>
+ </value>
+ </param>
+</params>
+</methodResponse>
diff --git a/ext/xmlrpc/tests/bug51288.phpt b/ext/xmlrpc/tests/bug51288.phpt
new file mode 100644
index 0000000..ba34136
--- /dev/null
+++ b/ext/xmlrpc/tests/bug51288.phpt
@@ -0,0 +1,16 @@
+--TEST--
+Bug #51288 (CVE-2010-0397, NULL pointer deref when no <methodName> in request)
+--SKIPIF--
+<?php if (!extension_loaded("xmlrpc")) print "skip"; ?>
+--FILE--
+<?php
+$method = NULL;
+$req = '<?xml version="1.0"?><methodCall></methodCall>';
+var_dump(xmlrpc_decode_request($req, $method));
+var_dump($method);
+echo "Done\n";
+?>
+--EXPECT--
+NULL
+NULL
+Done
diff --git a/ext/xmlrpc/tests/bug61097.phpt b/ext/xmlrpc/tests/bug61097.phpt
new file mode 100644
index 0000000..1b75247
--- /dev/null
+++ b/ext/xmlrpc/tests/bug61097.phpt
@@ -0,0 +1,16 @@
+--TEST--
+Bug #61097 (Memory leak in xmlrpc functions copying zvals)
+--SKIPIF--
+<?php if (!extension_loaded("xmlrpc")) print "skip"; ?>
+--FILE--
+<?php
+$server = xmlrpc_server_create();
+
+$method = 'abc';
+xmlrpc_server_register_introspection_callback($server, $method);
+xmlrpc_server_register_method($server, 'abc', $method);
+
+echo 'Done';
+?>
+--EXPECT--
+Done
diff --git a/ext/xmlrpc/tests/bug61264.phpt b/ext/xmlrpc/tests/bug61264.phpt
new file mode 100644
index 0000000..24e4b27
--- /dev/null
+++ b/ext/xmlrpc/tests/bug61264.phpt
@@ -0,0 +1,19 @@
+--TEST--
+Bug #61264: xmlrpc_parse_method_descriptions leaks temporary variable
+--SKIPIF--
+<?php if (!extension_loaded("xmlrpc")) print "skip"; ?>
+--FILE--
+<?php
+$xml = <<<XML
+<?xml version="1.0" encoding="utf-8"?>
+<a>
+ <b>foo</b>
+</a>
+XML;
+var_dump(xmlrpc_parse_method_descriptions($xml));
+?>
+--EXPECT--
+array(1) {
+ ["b"]=>
+ string(3) "foo"
+}
diff --git a/ext/xmlrpc/xmlrpc-epi-php.c b/ext/xmlrpc/xmlrpc-epi-php.c
new file mode 100644
index 0000000..925b554
--- /dev/null
+++ b/ext/xmlrpc/xmlrpc-epi-php.c
@@ -0,0 +1,1546 @@
+/*
+ This file is part of, or distributed with, libXMLRPC - a C library for
+ xml-encoded function calls.
+
+ Author: Dan Libby (dan@libby.com)
+ Epinions.com may be contacted at feedback@epinions-inc.com
+*/
+
+/*
+ Copyright 2001 Epinions, Inc.
+
+ Subject to the following 3 conditions, Epinions, Inc. permits you, free
+ of charge, to (a) use, copy, distribute, modify, perform and display this
+ software and associated documentation files (the "Software"), and (b)
+ permit others to whom the Software is furnished to do so as well.
+
+ 1) The above copyright notice and this permission notice shall be included
+ without modification in all copies or substantial portions of the
+ Software.
+
+ 2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF
+ ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY
+ IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR
+ PURPOSE OR NONINFRINGEMENT.
+
+ 3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
+ SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
+ OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING
+ NEGLIGENCE), EVEN IF EPINIONS, INC. IS AWARE OF THE POSSIBILITY OF SUCH
+ DAMAGES.
+
+*/
+
+/* auto-generated portions of this file are also subject to the php license */
+
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: Dan Libby |
+ +----------------------------------------------------------------------+
+ */
+
+/* $Id$ */
+
+/**********************************************************************
+* BUGS: *
+* - when calling a php user function, there appears to be no way to *
+* distinguish between a return value of null, and no return value *
+* at all. The xml serialization layer(s) will then return a value *
+* of null, when the right thing may be no value at all. (SOAP) *
+**********************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php.h"
+#include "ext/standard/info.h"
+#include "ext/standard/php_string.h"
+#include "ext/date/php_date.h"
+#include "php_ini.h"
+#include "php_xmlrpc.h"
+#include "xmlrpc.h"
+
+#define PHP_EXT_VERSION "0.51"
+
+static int le_xmlrpc_server;
+
+/* {{{ arginfo */
+ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_encode, 0, 0, 1)
+ ZEND_ARG_INFO(0, value)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_decode, 0, 0, 1)
+ ZEND_ARG_INFO(0, value)
+ ZEND_ARG_INFO(0, encoding)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_decode_request, 0, 0, 2)
+ ZEND_ARG_INFO(0, xml)
+ ZEND_ARG_INFO(1, method)
+ ZEND_ARG_INFO(0, encoding)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_encode_request, 0, 0, 2)
+ ZEND_ARG_INFO(0, method)
+ ZEND_ARG_INFO(0, params)
+ ZEND_ARG_INFO(0, output_options)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_set_type, 0, 0, 2)
+ ZEND_ARG_INFO(1, value)
+ ZEND_ARG_INFO(0, type)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_is_fault, 0, 0, 1)
+ ZEND_ARG_INFO(0, arg)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO(arginfo_xmlrpc_server_create, 0)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_server_destroy, 0, 0, 1)
+ ZEND_ARG_INFO(0, server)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_server_register_method, 0, 0, 3)
+ ZEND_ARG_INFO(0, server)
+ ZEND_ARG_INFO(0, method_name)
+ ZEND_ARG_INFO(0, function)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_server_call_method, 0, 0, 3)
+ ZEND_ARG_INFO(0, server)
+ ZEND_ARG_INFO(0, xml)
+ ZEND_ARG_INFO(0, user_data)
+ ZEND_ARG_INFO(0, output_options)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_parse_method_descriptions, 0, 0, 1)
+ ZEND_ARG_INFO(0, xml)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_server_add_introspection_data, 0, 0, 2)
+ ZEND_ARG_INFO(0, server)
+ ZEND_ARG_INFO(0, desc)
+ZEND_END_ARG_INFO()
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_xmlrpc_server_register_introspection_callback, 0, 0, 2)
+ ZEND_ARG_INFO(0, server)
+ ZEND_ARG_INFO(0, function)
+ZEND_END_ARG_INFO()
+/* }}} */
+
+const zend_function_entry xmlrpc_functions[] = {
+ PHP_FE(xmlrpc_encode, arginfo_xmlrpc_encode)
+ PHP_FE(xmlrpc_decode, arginfo_xmlrpc_decode)
+ PHP_FE(xmlrpc_decode_request, arginfo_xmlrpc_decode_request)
+ PHP_FE(xmlrpc_encode_request, arginfo_xmlrpc_encode_request)
+ PHP_FE(xmlrpc_get_type, arginfo_xmlrpc_encode)
+ PHP_FE(xmlrpc_set_type, arginfo_xmlrpc_set_type)
+ PHP_FE(xmlrpc_is_fault, arginfo_xmlrpc_is_fault)
+ PHP_FE(xmlrpc_server_create, arginfo_xmlrpc_server_create)
+ PHP_FE(xmlrpc_server_destroy, arginfo_xmlrpc_server_destroy)
+ PHP_FE(xmlrpc_server_register_method, arginfo_xmlrpc_server_register_method)
+ PHP_FE(xmlrpc_server_call_method, arginfo_xmlrpc_server_call_method)
+ PHP_FE(xmlrpc_parse_method_descriptions, arginfo_xmlrpc_parse_method_descriptions)
+ PHP_FE(xmlrpc_server_add_introspection_data, arginfo_xmlrpc_server_add_introspection_data)
+ PHP_FE(xmlrpc_server_register_introspection_callback, arginfo_xmlrpc_server_register_introspection_callback)
+ PHP_FE_END
+};
+
+zend_module_entry xmlrpc_module_entry = {
+ STANDARD_MODULE_HEADER,
+ "xmlrpc",
+ xmlrpc_functions,
+ PHP_MINIT(xmlrpc),
+ NULL,
+ NULL,
+ NULL,
+ PHP_MINFO(xmlrpc),
+ PHP_EXT_VERSION,
+ STANDARD_MODULE_PROPERTIES
+};
+
+#ifdef COMPILE_DL_XMLRPC
+ZEND_GET_MODULE(xmlrpc)
+#endif
+
+/*******************************
+* local structures and defines *
+*******************************/
+
+/* per server data */
+typedef struct _xmlrpc_server_data {
+ zval* method_map;
+ zval* introspection_map;
+ XMLRPC_SERVER server_ptr;
+} xmlrpc_server_data;
+
+
+/* how to format output */
+typedef struct _php_output_options {
+ int b_php_out;
+ int b_auto_version;
+ STRUCT_XMLRPC_REQUEST_OUTPUT_OPTIONS xmlrpc_out;
+} php_output_options;
+
+/* data passed to C callback */
+typedef struct _xmlrpc_callback_data {
+ zval* xmlrpc_method;
+ zval* php_function;
+ zval* caller_params;
+ zval* return_data;
+ xmlrpc_server_data* server;
+ char php_executed;
+} xmlrpc_callback_data;
+
+/* output options */
+#define OUTPUT_TYPE_KEY "output_type"
+#define OUTPUT_TYPE_KEY_LEN (sizeof(OUTPUT_TYPE_KEY) - 1)
+#define OUTPUT_TYPE_VALUE_PHP "php"
+#define OUTPUT_TYPE_VALUE_XML "xml"
+
+#define VERBOSITY_KEY "verbosity"
+#define VERBOSITY_KEY_LEN (sizeof(VERBOSITY_KEY) - 1)
+#define VERBOSITY_VALUE_NO_WHITE_SPACE "no_white_space"
+#define VERBOSITY_VALUE_NEWLINES_ONLY "newlines_only"
+#define VERBOSITY_VALUE_PRETTY "pretty"
+
+#define ESCAPING_KEY "escaping"
+#define ESCAPING_KEY_LEN (sizeof(ESCAPING_KEY) - 1)
+#define ESCAPING_VALUE_CDATA "cdata"
+#define ESCAPING_VALUE_NON_ASCII "non-ascii"
+#define ESCAPING_VALUE_NON_PRINT "non-print"
+#define ESCAPING_VALUE_MARKUP "markup"
+
+#define VERSION_KEY "version"
+#define VERSION_KEY_LEN (sizeof(VERSION_KEY) - 1)
+#define VERSION_VALUE_SIMPLE "simple"
+#define VERSION_VALUE_XMLRPC "xmlrpc"
+#define VERSION_VALUE_SOAP11 "soap 1.1"
+#define VERSION_VALUE_AUTO "auto"
+
+#define ENCODING_KEY "encoding"
+#define ENCODING_KEY_LEN (sizeof(ENCODING_KEY) - 1)
+#define ENCODING_DEFAULT "iso-8859-1"
+
+/* value types */
+#define OBJECT_TYPE_ATTR "xmlrpc_type"
+#define OBJECT_VALUE_ATTR "scalar"
+#define OBJECT_VALUE_TS_ATTR "timestamp"
+
+/* faults */
+#define FAULT_CODE "faultCode"
+#define FAULT_CODE_LEN (sizeof(FAULT_CODE) - 1)
+#define FAULT_STRING "faultString"
+#define FAULT_STRING_LEN (sizeof(FAULT_STRING) - 1)
+
+/***********************
+* forward declarations *
+***********************/
+XMLRPC_VALUE_TYPE get_zval_xmlrpc_type(zval* value, zval** newvalue);
+static void php_xmlrpc_introspection_callback(XMLRPC_SERVER server, void* data);
+int sset_zval_xmlrpc_type(zval* value, XMLRPC_VALUE_TYPE type);
+zval* decode_request_worker(char *xml_in, int xml_in_len, char *encoding_in, zval* method_name_out);
+const char* xmlrpc_type_as_str(XMLRPC_VALUE_TYPE type, XMLRPC_VECTOR_TYPE vtype);
+XMLRPC_VALUE_TYPE xmlrpc_str_as_type(const char* str);
+XMLRPC_VECTOR_TYPE xmlrpc_str_as_vector_type(const char* str);
+int set_zval_xmlrpc_type(zval* value, XMLRPC_VALUE_TYPE type);
+
+/*********************
+* startup / shutdown *
+*********************/
+
+static void destroy_server_data(xmlrpc_server_data *server TSRMLS_DC)
+{
+ if (server) {
+ XMLRPC_ServerDestroy(server->server_ptr);
+
+ zval_dtor(server->method_map);
+ FREE_ZVAL(server->method_map);
+
+ zval_dtor(server->introspection_map);
+ FREE_ZVAL(server->introspection_map);
+
+ efree(server);
+ }
+}
+
+/* called when server is being destructed. either when xmlrpc_server_destroy
+ * is called, or when request ends. */
+static void xmlrpc_server_destructor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
+{
+ if (rsrc && rsrc->ptr) {
+ destroy_server_data((xmlrpc_server_data*) rsrc->ptr TSRMLS_CC);
+ }
+}
+
+/* module init */
+PHP_MINIT_FUNCTION(xmlrpc)
+{
+ le_xmlrpc_server = zend_register_list_destructors_ex(xmlrpc_server_destructor, NULL, "xmlrpc server", module_number);
+
+ return SUCCESS;
+}
+
+/* display info in phpinfo() */
+PHP_MINFO_FUNCTION(xmlrpc)
+{
+ php_info_print_table_start();
+ php_info_print_table_row(2, "core library version", XMLRPC_GetVersionString());
+ php_info_print_table_row(2, "php extension version", PHP_EXT_VERSION);
+ php_info_print_table_row(2, "author", "Dan Libby");
+ php_info_print_table_row(2, "homepage", "http://xmlrpc-epi.sourceforge.net");
+ php_info_print_table_row(2, "open sourced by", "Epinions.com");
+ php_info_print_table_end();
+}
+
+/*******************
+* random utilities *
+*******************/
+
+/* Utility functions for adding data types to arrays, with or without key (assoc, non-assoc).
+ * Could easily be further generalized to work with objects.
+ */
+#if 0
+static int add_long(zval* list, char* id, int num) {
+ if(id) return add_assoc_long(list, id, num);
+ else return add_next_index_long(list, num);
+}
+
+static int add_double(zval* list, char* id, double num) {
+ if(id) return add_assoc_double(list, id, num);
+ else return add_next_index_double(list, num);
+}
+
+static int add_string(zval* list, char* id, char* string, int duplicate) {
+ if(id) return add_assoc_string(list, id, string, duplicate);
+ else return add_next_index_string(list, string, duplicate);
+}
+
+static int add_stringl(zval* list, char* id, char* string, uint length, int duplicate) {
+ if(id) return add_assoc_stringl(list, id, string, length, duplicate);
+ else return add_next_index_stringl(list, string, length, duplicate);
+}
+
+#endif
+
+static int add_zval(zval* list, const char* id, zval** val)
+{
+ if (list && val) {
+ if (id) {
+ int id_len = strlen(id);
+ if (!(id_len > 1 && id[0] == '0') && is_numeric_string((char *)id, id_len, NULL, NULL, 0) == IS_LONG) {
+ long index = strtol(id, NULL, 0);
+ return zend_hash_index_update(Z_ARRVAL_P(list), index, (void *) val, sizeof(zval **), NULL);
+ } else {
+ return zend_hash_update(Z_ARRVAL_P(list), (char*) id, strlen(id) + 1, (void *) val, sizeof(zval **), NULL);
+ }
+ } else {
+ return zend_hash_next_index_insert(Z_ARRVAL_P(list), (void *) val, sizeof(zval **), NULL);
+ }
+ }
+ /* what is the correct return on error? */
+ return 0;
+}
+
+#define my_zend_hash_get_current_key(ht, my_key, num_index) zend_hash_get_current_key(ht, my_key, num_index, 0)
+
+
+/*************************
+* input / output options *
+*************************/
+
+/* parse an array (user input) into output options suitable for use by xmlrpc engine
+ * and determine whether to return data as xml or php vars */
+static void set_output_options(php_output_options* options, zval* output_opts)
+{
+ if (options) {
+
+ /* defaults */
+ options->b_php_out = 0;
+ options->b_auto_version = 1;
+ options->xmlrpc_out.version = xmlrpc_version_1_0;
+ options->xmlrpc_out.xml_elem_opts.encoding = ENCODING_DEFAULT;
+ options->xmlrpc_out.xml_elem_opts.verbosity = xml_elem_pretty;
+ options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_markup_escaping | xml_elem_non_ascii_escaping | xml_elem_non_print_escaping;
+
+ if (output_opts && Z_TYPE_P(output_opts) == IS_ARRAY) {
+ zval** val;
+
+ /* type of output (xml/php) */
+ if (zend_hash_find(Z_ARRVAL_P(output_opts), OUTPUT_TYPE_KEY, OUTPUT_TYPE_KEY_LEN + 1, (void**) &val) == SUCCESS) {
+ if (Z_TYPE_PP(val) == IS_STRING) {
+ if (!strcmp(Z_STRVAL_PP(val), OUTPUT_TYPE_VALUE_PHP)) {
+ options->b_php_out = 1;
+ } else if (!strcmp(Z_STRVAL_PP(val), OUTPUT_TYPE_VALUE_XML)) {
+ options->b_php_out = 0;
+ }
+ }
+ }
+
+ /* verbosity of generated xml */
+ if (zend_hash_find(Z_ARRVAL_P(output_opts), VERBOSITY_KEY, VERBOSITY_KEY_LEN + 1, (void**) &val) == SUCCESS) {
+ if (Z_TYPE_PP(val) == IS_STRING) {
+ if (!strcmp(Z_STRVAL_PP(val), VERBOSITY_VALUE_NO_WHITE_SPACE)) {
+ options->xmlrpc_out.xml_elem_opts.verbosity = xml_elem_no_white_space;
+ } else if (!strcmp(Z_STRVAL_PP(val), VERBOSITY_VALUE_NEWLINES_ONLY)) {
+ options->xmlrpc_out.xml_elem_opts.verbosity = xml_elem_newlines_only;
+ } else if (!strcmp(Z_STRVAL_PP(val), VERBOSITY_VALUE_PRETTY)) {
+ options->xmlrpc_out.xml_elem_opts.verbosity = xml_elem_pretty;
+ }
+ }
+ }
+
+ /* version of xml to output */
+ if (zend_hash_find(Z_ARRVAL_P(output_opts), VERSION_KEY, VERSION_KEY_LEN + 1, (void**) &val) == SUCCESS) {
+ if (Z_TYPE_PP(val) == IS_STRING) {
+ options->b_auto_version = 0;
+ if (!strcmp(Z_STRVAL_PP(val), VERSION_VALUE_XMLRPC)) {
+ options->xmlrpc_out.version = xmlrpc_version_1_0;
+ } else if (!strcmp(Z_STRVAL_PP(val), VERSION_VALUE_SIMPLE)) {
+ options->xmlrpc_out.version = xmlrpc_version_simple;
+ } else if (!strcmp((*val)->value.str.val, VERSION_VALUE_SOAP11)) {
+ options->xmlrpc_out.version = xmlrpc_version_soap_1_1;
+ } else { /* if(!strcmp((*val)->value.str.val, VERSION_VALUE_AUTO)) { */
+ options->b_auto_version = 1;
+ }
+ }
+ }
+
+ /* encoding code set */
+ if (zend_hash_find(Z_ARRVAL_P(output_opts), ENCODING_KEY, ENCODING_KEY_LEN + 1, (void**)&val) == SUCCESS) {
+ if (Z_TYPE_PP(val) == IS_STRING) {
+ options->xmlrpc_out.xml_elem_opts.encoding = estrdup(Z_STRVAL_PP(val));
+ }
+ }
+
+ /* escaping options */
+ if (zend_hash_find(Z_ARRVAL_P(output_opts), ESCAPING_KEY, ESCAPING_KEY_LEN + 1, (void**)&val) == SUCCESS) {
+ /* multiple values allowed. check if array */
+ if (Z_TYPE_PP(val) == IS_ARRAY) {
+ zval** iter_val;
+
+ zend_hash_internal_pointer_reset(Z_ARRVAL_PP(val));
+ options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_no_escaping;
+
+ while (1) {
+ if (zend_hash_get_current_data(Z_ARRVAL_PP(val), (void**)&iter_val) == SUCCESS) {
+ if (Z_TYPE_PP(iter_val) == IS_STRING && Z_STRVAL_PP(iter_val)) {
+ if (!strcmp(Z_STRVAL_PP(iter_val), ESCAPING_VALUE_CDATA)) {
+ options->xmlrpc_out.xml_elem_opts.escaping |= xml_elem_cdata_escaping;
+ } else if (!strcmp(Z_STRVAL_PP(iter_val), ESCAPING_VALUE_NON_ASCII)) {
+ options->xmlrpc_out.xml_elem_opts.escaping |= xml_elem_non_ascii_escaping;
+ } else if (!strcmp(Z_STRVAL_PP(iter_val), ESCAPING_VALUE_NON_PRINT)) {
+ options->xmlrpc_out.xml_elem_opts.escaping |= xml_elem_non_print_escaping;
+ } else if (!strcmp(Z_STRVAL_PP(iter_val), ESCAPING_VALUE_MARKUP)) {
+ options->xmlrpc_out.xml_elem_opts.escaping |= xml_elem_markup_escaping;
+ }
+ }
+ } else {
+ break;
+ }
+ zend_hash_move_forward(Z_ARRVAL_PP(val));
+ }
+ /* else, check for single value */
+ } else if (Z_TYPE_PP(val) == IS_STRING) {
+ if (!strcmp(Z_STRVAL_PP(val), ESCAPING_VALUE_CDATA)) {
+ options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_cdata_escaping;
+ } else if (!strcmp(Z_STRVAL_PP(val), ESCAPING_VALUE_NON_ASCII)) {
+ options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_non_ascii_escaping;
+ } else if (!strcmp(Z_STRVAL_PP(val), ESCAPING_VALUE_NON_PRINT)) {
+ options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_non_print_escaping;
+ } else if (!strcmp(Z_STRVAL_PP(val), ESCAPING_VALUE_MARKUP)) {
+ options->xmlrpc_out.xml_elem_opts.escaping = xml_elem_markup_escaping;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+/******************
+* encode / decode *
+******************/
+
+/* php arrays have no distinction between array and struct types.
+ * they even allow mixed. Thus, we determine the type by iterating
+ * through the entire array and figuring out each element.
+ * room for some optimation here if we stop after a specific # of elements.
+ */
+static XMLRPC_VECTOR_TYPE determine_vector_type (HashTable *ht)
+{
+ int bArray = 0, bStruct = 0, bMixed = 0;
+ unsigned long num_index, last_num = 0;
+ char* my_key;
+
+ zend_hash_internal_pointer_reset(ht);
+ while (1) {
+ int res = my_zend_hash_get_current_key(ht, &my_key, &num_index);
+
+ if (res == HASH_KEY_IS_LONG) {
+ if (bStruct) {
+ bMixed = 1;
+ break;
+ } else if (last_num > 0 && last_num != num_index-1) {
+ bStruct = 1;
+ break;
+ }
+ bArray = 1;
+ last_num = num_index;
+ } else if (res == HASH_KEY_NON_EXISTANT) {
+ break;
+ } else if (res == HASH_KEY_IS_STRING) {
+ if (bArray) {
+ bMixed = 1;
+ break;
+ }
+ bStruct = 1;
+ }
+ zend_hash_move_forward(ht);
+ }
+ return bMixed ? xmlrpc_vector_mixed : (bStruct ? xmlrpc_vector_struct : xmlrpc_vector_array);
+}
+
+/* recursively convert php values into xmlrpc values */
+static XMLRPC_VALUE PHP_to_XMLRPC_worker (const char* key, zval* in_val, int depth TSRMLS_DC)
+{
+ XMLRPC_VALUE xReturn = NULL;
+
+ if (in_val) {
+ zval* val = NULL;
+ XMLRPC_VALUE_TYPE type = get_zval_xmlrpc_type(in_val, &val);
+
+ if (val) {
+ switch (type) {
+ case xmlrpc_base64:
+ if (Z_TYPE_P(val) == IS_NULL) {
+ xReturn = XMLRPC_CreateValueEmpty();
+ XMLRPC_SetValueID(xReturn, key, 0);
+ } else {
+ xReturn = XMLRPC_CreateValueBase64(key, Z_STRVAL_P(val), Z_STRLEN_P(val));
+ }
+ break;
+ case xmlrpc_datetime:
+ convert_to_string(val);
+ xReturn = XMLRPC_CreateValueDateTime_ISO8601(key, Z_STRVAL_P(val));
+ break;
+ case xmlrpc_boolean:
+ convert_to_boolean(val);
+ xReturn = XMLRPC_CreateValueBoolean(key, Z_LVAL_P(val));
+ break;
+ case xmlrpc_int:
+ convert_to_long(val);
+ xReturn = XMLRPC_CreateValueInt(key, Z_LVAL_P(val));
+ break;
+ case xmlrpc_double:
+ convert_to_double(val);
+ xReturn = XMLRPC_CreateValueDouble(key, Z_DVAL_P(val));
+ break;
+ case xmlrpc_string:
+ convert_to_string(val);
+ xReturn = XMLRPC_CreateValueString(key, Z_STRVAL_P(val), Z_STRLEN_P(val));
+ break;
+ case xmlrpc_vector:
+ {
+ unsigned long num_index;
+ zval** pIter;
+ char* my_key;
+ HashTable *ht = NULL;
+ zval *val_arr;
+ XMLRPC_VECTOR_TYPE vtype;
+
+ ht = HASH_OF(val);
+ if (ht && ht->nApplyCount > 1) {
+ php_error_docref(NULL TSRMLS_CC, E_ERROR, "XML-RPC doesn't support circular references");
+ return NULL;
+ }
+
+ MAKE_STD_ZVAL(val_arr);
+ MAKE_COPY_ZVAL(&val, val_arr);
+ convert_to_array(val_arr);
+
+ vtype = determine_vector_type(Z_ARRVAL_P(val_arr));
+ xReturn = XMLRPC_CreateVector(key, vtype);
+
+ zend_hash_internal_pointer_reset(Z_ARRVAL_P(val_arr));
+ while(zend_hash_get_current_data(Z_ARRVAL_P(val_arr), (void**)&pIter) == SUCCESS) {
+ int res = my_zend_hash_get_current_key(Z_ARRVAL_P(val_arr), &my_key, &num_index);
+
+ switch (res) {
+ case HASH_KEY_NON_EXISTANT:
+ break;
+ case HASH_KEY_IS_STRING:
+ case HASH_KEY_IS_LONG:
+ ht = HASH_OF(*pIter);
+ if (ht) {
+ ht->nApplyCount++;
+ }
+ if (res == HASH_KEY_IS_LONG) {
+ char *num_str = NULL;
+
+ if (vtype != xmlrpc_vector_array) {
+ spprintf(&num_str, 0, "%ld", num_index);
+ }
+ XMLRPC_AddValueToVector(xReturn, PHP_to_XMLRPC_worker(num_str, *pIter, depth++ TSRMLS_CC));
+ if (num_str) {
+ efree(num_str);
+ }
+ } else {
+ XMLRPC_AddValueToVector(xReturn, PHP_to_XMLRPC_worker(my_key, *pIter, depth++ TSRMLS_CC));
+ }
+ if (ht) {
+ ht->nApplyCount--;
+ }
+ break;
+ }
+ zend_hash_move_forward(Z_ARRVAL_P(val_arr));
+ }
+ zval_ptr_dtor(&val_arr);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ return xReturn;
+}
+
+static XMLRPC_VALUE PHP_to_XMLRPC(zval* root_val TSRMLS_DC)
+{
+ return PHP_to_XMLRPC_worker(NULL, root_val, 0 TSRMLS_CC);
+}
+
+/* recursively convert xmlrpc values into php values */
+static zval* XMLRPC_to_PHP(XMLRPC_VALUE el)
+{
+ zval* elem = NULL;
+ const char* pStr;
+
+ if (el) {
+ XMLRPC_VALUE_TYPE type = XMLRPC_GetValueType(el);
+
+ MAKE_STD_ZVAL(elem); /* init. very important. spent a frustrating day finding this out. */
+
+ switch(type) {
+ case xmlrpc_empty:
+ Z_TYPE_P(elem) = IS_NULL;
+ break;
+ case xmlrpc_string:
+ pStr = XMLRPC_GetValueString(el);
+ if (pStr) {
+ Z_STRLEN_P(elem) = XMLRPC_GetValueStringLen(el);
+ Z_STRVAL_P(elem) = estrndup(pStr, Z_STRLEN_P(elem));
+ Z_TYPE_P(elem) = IS_STRING;
+ }
+ break;
+ case xmlrpc_int:
+ Z_LVAL_P(elem) = XMLRPC_GetValueInt(el);
+ Z_TYPE_P(elem) = IS_LONG;
+ break;
+ case xmlrpc_boolean:
+ Z_LVAL_P(elem) = XMLRPC_GetValueBoolean(el);
+ Z_TYPE_P(elem) = IS_BOOL;
+ break;
+ case xmlrpc_double:
+ Z_DVAL_P(elem) = XMLRPC_GetValueDouble(el);
+ Z_TYPE_P(elem) = IS_DOUBLE;
+ break;
+ case xmlrpc_datetime:
+ Z_STRLEN_P(elem) = XMLRPC_GetValueStringLen(el);
+ Z_STRVAL_P(elem) = estrndup(XMLRPC_GetValueDateTime_ISO8601(el), Z_STRLEN_P(elem));
+ Z_TYPE_P(elem) = IS_STRING;
+ break;
+ case xmlrpc_base64:
+ pStr = XMLRPC_GetValueBase64(el);
+ if (pStr) {
+ Z_STRLEN_P(elem) = XMLRPC_GetValueStringLen(el);
+ Z_STRVAL_P(elem) = estrndup(pStr, Z_STRLEN_P(elem));
+ Z_TYPE_P(elem) = IS_STRING;
+ }
+ break;
+ case xmlrpc_vector:
+ array_init(elem);
+ {
+ XMLRPC_VALUE xIter = XMLRPC_VectorRewind(el);
+
+ while( xIter ) {
+ zval *val = XMLRPC_to_PHP(xIter);
+ if (val) {
+ add_zval(elem, XMLRPC_GetValueID(xIter), &val);
+ }
+ xIter = XMLRPC_VectorNext(el);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ set_zval_xmlrpc_type(elem, type);
+ }
+ return elem;
+}
+
+/* {{{ proto string xmlrpc_encode_request(string method, mixed params [, array output_options])
+ Generates XML for a method request */
+PHP_FUNCTION(xmlrpc_encode_request)
+{
+ XMLRPC_REQUEST xRequest = NULL;
+ char *outBuf;
+ zval *vals, *out_opts = NULL;
+ char *method = NULL;
+ int method_len;
+ php_output_options out;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s!z|a", &method, &method_len, &vals, &out_opts) == FAILURE) {
+ return;
+ }
+
+ set_output_options(&out, out_opts ? out_opts : 0);
+
+ if (return_value_used) {
+ xRequest = XMLRPC_RequestNew();
+
+ if (xRequest) {
+ XMLRPC_RequestSetOutputOptions(xRequest, &out.xmlrpc_out);
+ if (method == NULL) {
+ XMLRPC_RequestSetRequestType(xRequest, xmlrpc_request_response);
+ } else {
+ XMLRPC_RequestSetMethodName(xRequest, method);
+ XMLRPC_RequestSetRequestType(xRequest, xmlrpc_request_call);
+ }
+ if (Z_TYPE_P(vals) != IS_NULL) {
+ XMLRPC_RequestSetData(xRequest, PHP_to_XMLRPC(vals TSRMLS_CC));
+ }
+
+ outBuf = XMLRPC_REQUEST_ToXML(xRequest, 0);
+ if (outBuf) {
+ RETVAL_STRING(outBuf, 1);
+ free(outBuf);
+ }
+ XMLRPC_RequestFree(xRequest, 1);
+ }
+ }
+
+ if (strcmp(out.xmlrpc_out.xml_elem_opts.encoding, ENCODING_DEFAULT) != 0) {
+ efree((char *)out.xmlrpc_out.xml_elem_opts.encoding);
+ }
+}
+/* }}} */
+
+/* {{{ proto string xmlrpc_encode(mixed value)
+ Generates XML for a PHP value */
+PHP_FUNCTION(xmlrpc_encode)
+{
+ XMLRPC_VALUE xOut = NULL;
+ zval **arg1;
+ char *outBuf;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &arg1) == FAILURE) {
+ return;
+ }
+
+ if (return_value_used) {
+ /* convert native php type to xmlrpc type */
+ xOut = PHP_to_XMLRPC(*arg1 TSRMLS_CC);
+
+ /* generate raw xml from xmlrpc data */
+ outBuf = XMLRPC_VALUE_ToXML(xOut, 0);
+
+ if (xOut) {
+ if (outBuf) {
+ RETVAL_STRING(outBuf, 1);
+ free(outBuf);
+ }
+ /* cleanup */
+ XMLRPC_CleanupValue(xOut);
+ }
+ }
+}
+/* }}} */
+
+zval* decode_request_worker(char *xml_in, int xml_in_len, char *encoding_in, zval* method_name_out) /* {{{ */
+{
+ zval* retval = NULL;
+ XMLRPC_REQUEST response;
+ STRUCT_XMLRPC_REQUEST_INPUT_OPTIONS opts = {{0}};
+ const char *method_name;
+ opts.xml_elem_opts.encoding = encoding_in ? utf8_get_encoding_id_from_string(encoding_in) : ENCODING_DEFAULT;
+
+ /* generate XMLRPC_REQUEST from raw xml */
+ response = XMLRPC_REQUEST_FromXML(xml_in, xml_in_len, &opts);
+ if (response) {
+ /* convert xmlrpc data to native php types */
+ retval = XMLRPC_to_PHP(XMLRPC_RequestGetData(response));
+
+ if (XMLRPC_RequestGetRequestType(response) == xmlrpc_request_call) {
+ if (method_name_out) {
+ method_name = XMLRPC_RequestGetMethodName(response);
+ if (method_name) {
+ zval_dtor(method_name_out);
+ Z_TYPE_P(method_name_out) = IS_STRING;
+ Z_STRVAL_P(method_name_out) = estrdup(method_name);
+ Z_STRLEN_P(method_name_out) = strlen(Z_STRVAL_P(method_name_out));
+ } else if (retval) {
+ zval_ptr_dtor(&retval);
+ retval = NULL;
+ }
+ }
+ }
+
+ /* dust, sweep, and mop */
+ XMLRPC_RequestFree(response, 1);
+ }
+ return retval;
+}
+/* }}} */
+
+/* {{{ proto array xmlrpc_decode_request(string xml, string& method [, string encoding])
+ Decodes XML into native PHP types */
+PHP_FUNCTION(xmlrpc_decode_request)
+{
+ char *xml, *encoding = NULL;
+ zval **method;
+ int xml_len, encoding_len = 0;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sZ|s", &xml, &xml_len, &method, &encoding, &encoding_len) == FAILURE) {
+ return;
+ }
+
+
+ if (return_value_used) {
+ zval* retval = decode_request_worker(xml, xml_len, encoding_len ? encoding : NULL, *method);
+ if (retval) {
+ *return_value = *retval;
+ FREE_ZVAL(retval);
+ }
+ }
+}
+/* }}} */
+
+/* {{{ proto array xmlrpc_decode(string xml [, string encoding])
+ Decodes XML into native PHP types */
+PHP_FUNCTION(xmlrpc_decode)
+{
+ char *arg1, *arg2 = NULL;
+ int arg1_len, arg2_len = 0;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|s", &arg1, &arg1_len, &arg2, &arg2_len) == FAILURE) {
+ return;
+ }
+
+ if (return_value_used) {
+ zval* retval = decode_request_worker(arg1, arg1_len, arg2_len ? arg2 : NULL, NULL);
+ if (retval) {
+ *return_value = *retval;
+ FREE_ZVAL(retval);
+ }
+ }
+}
+/* }}} */
+
+/*************************
+* server related methods *
+*************************/
+
+/* {{{ proto resource xmlrpc_server_create(void)
+ Creates an xmlrpc server */
+PHP_FUNCTION(xmlrpc_server_create)
+{
+ if (zend_parse_parameters_none() == FAILURE) {
+ return;
+ }
+
+ if (return_value_used) {
+ zval *method_map, *introspection_map;
+ xmlrpc_server_data *server = emalloc(sizeof(xmlrpc_server_data));
+ MAKE_STD_ZVAL(method_map);
+ MAKE_STD_ZVAL(introspection_map);
+
+ array_init(method_map);
+ array_init(introspection_map);
+
+ /* allocate server data. free'd in destroy_server_data() */
+ server->method_map = method_map;
+ server->introspection_map = introspection_map;
+ server->server_ptr = XMLRPC_ServerCreate();
+
+ XMLRPC_ServerRegisterIntrospectionCallback(server->server_ptr, php_xmlrpc_introspection_callback);
+
+ /* store for later use */
+ ZEND_REGISTER_RESOURCE(return_value,server, le_xmlrpc_server);
+ }
+}
+/* }}} */
+
+/* {{{ proto int xmlrpc_server_destroy(resource server)
+ Destroys server resources */
+PHP_FUNCTION(xmlrpc_server_destroy)
+{
+ zval *arg1;
+ int bSuccess = FAILURE, type;
+ xmlrpc_server_data *server;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &arg1) == FAILURE) {
+ return;
+ }
+
+ server = zend_list_find(Z_LVAL_P(arg1), &type);
+
+ if (server && type == le_xmlrpc_server) {
+ bSuccess = zend_list_delete(Z_LVAL_P(arg1));
+
+ /* called by hashtable destructor
+ * destroy_server_data(server);
+ */
+ }
+ RETVAL_LONG(bSuccess == SUCCESS);
+}
+/* }}} */
+
+/* called by xmlrpc C engine as method handler for all registered methods.
+ * it then calls the corresponding PHP function to handle the method.
+ */
+static XMLRPC_VALUE php_xmlrpc_callback(XMLRPC_SERVER server, XMLRPC_REQUEST xRequest, void* data) /* {{{ */
+{
+ xmlrpc_callback_data* pData = (xmlrpc_callback_data*)data;
+ zval** php_function;
+ zval* xmlrpc_params;
+ zval* callback_params[3];
+ TSRMLS_FETCH();
+
+ zval_dtor(pData->xmlrpc_method);
+ zval_dtor(pData->return_data);
+
+ /* convert xmlrpc to native php types */
+ ZVAL_STRING(pData->xmlrpc_method, XMLRPC_RequestGetMethodName(xRequest), 1);
+ xmlrpc_params = XMLRPC_to_PHP(XMLRPC_RequestGetData(xRequest));
+
+ /* check if the called method has been previous registered */
+ if(zend_hash_find(Z_ARRVAL_P(pData->server->method_map),
+ Z_STRVAL_P(pData->xmlrpc_method),
+ Z_STRLEN_P(pData->xmlrpc_method) + 1,
+ (void**)&php_function) == SUCCESS) {
+
+ pData->php_function = *php_function;
+ }
+
+ /* setup data hoojum */
+ callback_params[0] = pData->xmlrpc_method;
+ callback_params[1] = xmlrpc_params;
+ callback_params[2] = pData->caller_params;
+
+ /* Use same C function for all methods */
+
+ /* php func prototype: function user_func($method_name, $xmlrpc_params, $user_params) */
+ call_user_function(CG(function_table), NULL, pData->php_function, pData->return_data, 3, callback_params TSRMLS_CC);
+
+ pData->php_executed = 1;
+
+ zval_ptr_dtor(&xmlrpc_params);
+
+ return PHP_to_XMLRPC(pData->return_data TSRMLS_CC);
+}
+/* }}} */
+
+/* called by the C server when it first receives an introspection request. We pass this on to
+ * our PHP listeners, if any
+ */
+static void php_xmlrpc_introspection_callback(XMLRPC_SERVER server, void* data) /* {{{ */
+{
+ zval retval, **php_function;
+ zval *callback_params[1];
+ char *php_function_name;
+ xmlrpc_callback_data* pData = (xmlrpc_callback_data*)data;
+ TSRMLS_FETCH();
+
+ /* setup data hoojum */
+ callback_params[0] = pData->caller_params;
+
+ /* loop through and call all registered callbacks */
+ zend_hash_internal_pointer_reset(Z_ARRVAL_P(pData->server->introspection_map));
+ while (1) {
+ if (zend_hash_get_current_data(Z_ARRVAL_P(pData->server->introspection_map), (void**)&php_function) == SUCCESS) {
+ if (zend_is_callable(*php_function, 0, &php_function_name TSRMLS_CC)) {
+ /* php func prototype: function string user_func($user_params) */
+ if (call_user_function(CG(function_table), NULL, *php_function, &retval, 1, callback_params TSRMLS_CC) == SUCCESS) {
+ XMLRPC_VALUE xData;
+ STRUCT_XMLRPC_ERROR err = {0};
+
+ /* return value should be a string */
+ convert_to_string(&retval);
+
+ xData = XMLRPC_IntrospectionCreateDescription(Z_STRVAL(retval), &err);
+
+ if (xData) {
+ if (!XMLRPC_ServerAddIntrospectionData(server, xData)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to add introspection data returned from %s(), improper element structure", php_function_name);
+ }
+ XMLRPC_CleanupValue(xData);
+ } else {
+ /* could not create description */
+ if (err.xml_elem_error.parser_code) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "xml parse error: [line %ld, column %ld, message: %s] Unable to add introspection data returned from %s()",
+ err.xml_elem_error.column, err.xml_elem_error.line, err.xml_elem_error.parser_error, php_function_name);
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to add introspection data returned from %s()", php_function_name);
+ }
+ }
+ zval_dtor(&retval);
+ } else {
+ /* user func failed */
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error calling user introspection callback: %s()", php_function_name);
+ }
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid callback '%s' passed", php_function_name);
+ }
+ efree(php_function_name);
+ } else {
+ break;
+ }
+ zend_hash_move_forward(Z_ARRVAL_P(pData->server->introspection_map));
+ }
+
+ /* so we don't call the same callbacks ever again */
+ zend_hash_clean(Z_ARRVAL_P(pData->server->introspection_map));
+}
+/* }}} */
+
+/* {{{ proto bool xmlrpc_server_register_method(resource server, string method_name, string function)
+ Register a PHP function to handle method matching method_name */
+PHP_FUNCTION(xmlrpc_server_register_method)
+{
+ char *method_key;
+ int method_key_len;
+ zval *handle, *method_name_save, **method_name;
+ int type;
+ xmlrpc_server_data* server;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsZ", &handle, &method_key, &method_key_len, &method_name) == FAILURE) {
+ return;
+ }
+
+ server = zend_list_find(Z_LVAL_P(handle), &type);
+
+ if (type == le_xmlrpc_server) {
+ /* register with C engine. every method just calls our standard callback,
+ * and it then dispatches to php as necessary
+ */
+ if (XMLRPC_ServerRegisterMethod(server->server_ptr, method_key, php_xmlrpc_callback)) {
+ /* save for later use */
+ ALLOC_ZVAL(method_name_save);
+ MAKE_COPY_ZVAL(method_name, method_name_save);
+
+ /* register our php method */
+ add_zval(server->method_map, method_key, &method_name_save);
+
+ RETURN_BOOL(1);
+ }
+ }
+ RETURN_BOOL(0);
+}
+/* }}} */
+
+/* {{{ proto bool xmlrpc_server_register_introspection_callback(resource server, string function)
+ Register a PHP function to generate documentation */
+PHP_FUNCTION(xmlrpc_server_register_introspection_callback)
+{
+ zval **method_name, *handle, *method_name_save;
+ int type;
+ xmlrpc_server_data* server;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rZ", &handle, &method_name) == FAILURE) {
+ return;
+ }
+
+ server = zend_list_find(Z_LVAL_P(handle), &type);
+
+ if (type == le_xmlrpc_server) {
+ /* save for later use */
+ ALLOC_ZVAL(method_name_save);
+ MAKE_COPY_ZVAL(method_name, method_name_save);
+
+ /* register our php method */
+ add_zval(server->introspection_map, NULL, &method_name_save);
+
+ RETURN_BOOL(1);
+ }
+ RETURN_BOOL(0);
+}
+/* }}} */
+
+/* this function is itchin for a re-write */
+
+/* {{{ proto mixed xmlrpc_server_call_method(resource server, string xml, mixed user_data [, array output_options])
+ Parses XML requests and call methods */
+PHP_FUNCTION(xmlrpc_server_call_method)
+{
+ xmlrpc_callback_data data = {0};
+ XMLRPC_REQUEST xRequest;
+ STRUCT_XMLRPC_REQUEST_INPUT_OPTIONS input_opts;
+ xmlrpc_server_data* server;
+ zval **caller_params, *handle, *output_opts = NULL;
+ char *rawxml;
+ int rawxml_len, type;
+ php_output_options out;
+ int argc =ZEND_NUM_ARGS();
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsZ|a", &handle, &rawxml, &rawxml_len, &caller_params, &output_opts) != SUCCESS) {
+ return;
+ }
+ /* user output options */
+ if (argc == 3) {
+ set_output_options(&out, NULL);
+ } else {
+ set_output_options(&out, output_opts);
+ }
+
+ server = zend_list_find(Z_LVAL_P(handle), &type);
+
+ if (type == le_xmlrpc_server) {
+ /* HACK: use output encoding for now */
+ input_opts.xml_elem_opts.encoding = utf8_get_encoding_id_from_string(out.xmlrpc_out.xml_elem_opts.encoding);
+
+ /* generate an XMLRPC_REQUEST from the raw xml input */
+ xRequest = XMLRPC_REQUEST_FromXML(rawxml, rawxml_len, &input_opts);
+
+ if (xRequest) {
+ const char* methodname = XMLRPC_RequestGetMethodName(xRequest);
+ XMLRPC_VALUE xAnswer = NULL;
+ MAKE_STD_ZVAL(data.xmlrpc_method); /* init. very important. spent a frustrating day finding this out. */
+ MAKE_STD_ZVAL(data.return_data);
+ Z_TYPE_P(data.return_data) = IS_NULL; /* in case value is never init'd, we don't dtor to think it is a string or something */
+ Z_TYPE_P(data.xmlrpc_method) = IS_NULL;
+
+ /* setup some data to pass to the callback function */
+ data.caller_params = *caller_params;
+ data.php_executed = 0;
+ data.server = server;
+
+ /* We could just call the php method directly ourselves at this point, but we do this
+ * with a C callback in case the xmlrpc library ever implements some cool usage stats,
+ * or somesuch.
+ */
+ xAnswer = XMLRPC_ServerCallMethod(server->server_ptr, xRequest, &data);
+ if (xAnswer && out.b_php_out) {
+ zval_dtor(data.return_data);
+ FREE_ZVAL(data.return_data);
+ data.return_data = XMLRPC_to_PHP(xAnswer);
+ } else if (data.php_executed && !out.b_php_out && !xAnswer) {
+ xAnswer = PHP_to_XMLRPC(data.return_data TSRMLS_CC);
+ }
+
+ /* should we return data as xml? */
+ if (!out.b_php_out) {
+ XMLRPC_REQUEST xResponse = XMLRPC_RequestNew();
+ if (xResponse) {
+ char *outBuf = 0;
+ int buf_len = 0;
+
+ /* automagically determine output serialization type from request type */
+ if (out.b_auto_version) {
+ XMLRPC_REQUEST_OUTPUT_OPTIONS opts = XMLRPC_RequestGetOutputOptions(xRequest);
+ if (opts) {
+ out.xmlrpc_out.version = opts->version;
+ }
+ }
+ /* set some required request hoojum */
+ XMLRPC_RequestSetOutputOptions(xResponse, &out.xmlrpc_out);
+ XMLRPC_RequestSetRequestType(xResponse, xmlrpc_request_response);
+ XMLRPC_RequestSetData(xResponse, xAnswer);
+ XMLRPC_RequestSetMethodName(xResponse, methodname);
+
+ /* generate xml */
+ outBuf = XMLRPC_REQUEST_ToXML(xResponse, &buf_len);
+ if (outBuf) {
+ RETVAL_STRINGL(outBuf, buf_len, 1);
+ free(outBuf);
+ }
+ /* cleanup after ourselves. what a sty! */
+ XMLRPC_RequestFree(xResponse, 0);
+ }
+ } else { /* or as native php types? */
+ *return_value = *data.return_data;
+ zval_copy_ctor(return_value);
+ }
+
+ /* cleanup after ourselves. what a sty! */
+ zval_ptr_dtor(&data.xmlrpc_method);
+
+ zval_dtor(data.return_data);
+ FREE_ZVAL(data.return_data);
+
+ if (xAnswer) {
+ XMLRPC_CleanupValue(xAnswer);
+ }
+
+ XMLRPC_RequestFree(xRequest, 1);
+ }
+ }
+}
+/* }}} */
+
+/* {{{ proto int xmlrpc_server_add_introspection_data(resource server, array desc)
+ Adds introspection documentation */
+PHP_FUNCTION(xmlrpc_server_add_introspection_data)
+{
+ zval *handle, *desc;
+ int type;
+ xmlrpc_server_data* server;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ra", &handle, &desc) == FAILURE) {
+ return;
+ }
+
+ server = zend_list_find(Z_LVAL_P(handle), &type);
+
+ if (type == le_xmlrpc_server) {
+ XMLRPC_VALUE xDesc = PHP_to_XMLRPC(desc TSRMLS_CC);
+ if (xDesc) {
+ int retval = XMLRPC_ServerAddIntrospectionData(server->server_ptr, xDesc);
+ XMLRPC_CleanupValue(xDesc);
+ RETURN_LONG(retval);
+ }
+ }
+ RETURN_LONG(0);
+}
+/* }}} */
+
+/* {{{ proto array xmlrpc_parse_method_descriptions(string xml)
+ Decodes XML into a list of method descriptions */
+PHP_FUNCTION(xmlrpc_parse_method_descriptions)
+{
+ zval *retval;
+ char *arg1;
+ int arg1_len;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg1, &arg1_len) == FAILURE) {
+ return;
+ }
+
+ if (return_value_used) {
+ STRUCT_XMLRPC_ERROR err = {0};
+ XMLRPC_VALUE xVal = XMLRPC_IntrospectionCreateDescription(arg1, &err);
+ if (xVal) {
+ retval = XMLRPC_to_PHP(xVal);
+
+ if (retval) {
+ RETVAL_ZVAL(retval, 1, 1);
+ }
+ /* dust, sweep, and mop */
+ XMLRPC_CleanupValue(xVal);
+ } else {
+ /* could not create description */
+ if (err.xml_elem_error.parser_code) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "xml parse error: [line %ld, column %ld, message: %s] Unable to create introspection data",
+ err.xml_elem_error.column, err.xml_elem_error.line, err.xml_elem_error.parser_error);
+ } else {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid xml structure. Unable to create introspection data");
+ }
+
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "xml parse error. no method description created");
+ }
+ }
+}
+/* }}} */
+
+/************
+* type data *
+************/
+
+#define XMLRPC_TYPE_COUNT 9
+#define XMLRPC_VECTOR_TYPE_COUNT 4
+#define TYPE_STR_MAP_SIZE (XMLRPC_TYPE_COUNT + XMLRPC_VECTOR_TYPE_COUNT)
+
+/* return a string matching a given xmlrpc type */
+static const char** get_type_str_mapping(void) /* {{{ */
+{
+ static const char* str_mapping[TYPE_STR_MAP_SIZE];
+ static int first = 1;
+ if (first) {
+ /* warning. do not add/delete without changing size define */
+ str_mapping[xmlrpc_none] = "none";
+ str_mapping[xmlrpc_empty] = "empty";
+ str_mapping[xmlrpc_base64] = "base64";
+ str_mapping[xmlrpc_boolean] = "boolean";
+ str_mapping[xmlrpc_datetime] = "datetime";
+ str_mapping[xmlrpc_double] = "double";
+ str_mapping[xmlrpc_int] = "int";
+ str_mapping[xmlrpc_string] = "string";
+ str_mapping[xmlrpc_vector] = "vector";
+ str_mapping[XMLRPC_TYPE_COUNT + xmlrpc_vector_none] = "none";
+ str_mapping[XMLRPC_TYPE_COUNT + xmlrpc_vector_array] = "array";
+ str_mapping[XMLRPC_TYPE_COUNT + xmlrpc_vector_mixed] = "mixed";
+ str_mapping[XMLRPC_TYPE_COUNT + xmlrpc_vector_struct] = "struct";
+ first = 0;
+ }
+ return (const char**)str_mapping;
+}
+/* }}} */
+
+/* map an xmlrpc type to a string */
+const char* xmlrpc_type_as_str(XMLRPC_VALUE_TYPE type, XMLRPC_VECTOR_TYPE vtype) /* {{{ */
+{
+ const char** str_mapping = get_type_str_mapping();
+
+ if (vtype == xmlrpc_vector_none) {
+ return str_mapping[type];
+ } else {
+ return str_mapping[XMLRPC_TYPE_COUNT + vtype];
+ }
+}
+/* }}} */
+
+/* map a string to an xmlrpc type */
+XMLRPC_VALUE_TYPE xmlrpc_str_as_type(const char* str) /* {{{ */
+{
+ const char** str_mapping = get_type_str_mapping();
+ int i;
+
+ if (str) {
+ for (i = 0; i < XMLRPC_TYPE_COUNT; i++) {
+ if (!strcmp(str_mapping[i], str)) {
+ return (XMLRPC_VALUE_TYPE) i;
+ }
+ }
+ }
+ return xmlrpc_none;
+}
+/* }}} */
+
+/* map a string to an xmlrpc vector type */
+XMLRPC_VECTOR_TYPE xmlrpc_str_as_vector_type(const char* str) /* {{{ */
+{
+ const char** str_mapping = get_type_str_mapping();
+ int i;
+
+ if (str) {
+ for (i = XMLRPC_TYPE_COUNT; i < TYPE_STR_MAP_SIZE; i++) {
+ if (!strcmp(str_mapping[i], str)) {
+ return (XMLRPC_VECTOR_TYPE) (i - XMLRPC_TYPE_COUNT);
+ }
+ }
+ }
+ return xmlrpc_none;
+}
+/* }}} */
+
+/* set a given value to a particular type.
+ * note: this only works on strings, and only for date and base64,
+ * which do not have native php types. black magic lies herein.
+ */
+int set_zval_xmlrpc_type(zval* value, XMLRPC_VALUE_TYPE newtype) /* {{{ */
+{
+ int bSuccess = FAILURE;
+ TSRMLS_FETCH();
+
+ /* we only really care about strings because they can represent
+ * base64 and datetime. all other types have corresponding php types
+ */
+ if (Z_TYPE_P(value) == IS_STRING) {
+ if (newtype == xmlrpc_base64 || newtype == xmlrpc_datetime) {
+ const char* typestr = xmlrpc_type_as_str(newtype, xmlrpc_vector_none);
+ zval* type;
+
+ MAKE_STD_ZVAL(type);
+
+ Z_TYPE_P(type) = IS_STRING;
+ Z_STRVAL_P(type) = estrdup(typestr);
+ Z_STRLEN_P(type) = strlen(typestr);
+
+ if (newtype == xmlrpc_datetime) {
+ XMLRPC_VALUE v = XMLRPC_CreateValueDateTime_ISO8601(NULL, value->value.str.val);
+ if (v) {
+ time_t timestamp = (time_t) php_parse_date((char *)XMLRPC_GetValueDateTime_ISO8601(v), NULL);
+ if (timestamp != -1) {
+ zval* ztimestamp;
+
+ MAKE_STD_ZVAL(ztimestamp);
+
+ ztimestamp->type = IS_LONG;
+ ztimestamp->value.lval = timestamp;
+
+ convert_to_object(value);
+ if (SUCCESS == zend_hash_update(Z_OBJPROP_P(value), OBJECT_TYPE_ATTR, sizeof(OBJECT_TYPE_ATTR), (void *) &type, sizeof(zval *), NULL)) {
+ bSuccess = zend_hash_update(Z_OBJPROP_P(value), OBJECT_VALUE_TS_ATTR, sizeof(OBJECT_VALUE_TS_ATTR), (void *) &ztimestamp, sizeof(zval *), NULL);
+ }
+ } else {
+ zval_ptr_dtor(&type);
+ }
+ XMLRPC_CleanupValue(v);
+ } else {
+ zval_ptr_dtor(&type);
+ }
+ } else {
+ convert_to_object(value);
+ bSuccess = zend_hash_update(Z_OBJPROP_P(value), OBJECT_TYPE_ATTR, sizeof(OBJECT_TYPE_ATTR), (void *) &type, sizeof(zval *), NULL);
+ }
+ }
+ }
+
+ return bSuccess;
+}
+/* }}} */
+
+/* return xmlrpc type of a php value */
+XMLRPC_VALUE_TYPE get_zval_xmlrpc_type(zval* value, zval** newvalue) /* {{{ */
+{
+ XMLRPC_VALUE_TYPE type = xmlrpc_none;
+ TSRMLS_FETCH();
+
+ if (value) {
+ switch (Z_TYPE_P(value)) {
+ case IS_NULL:
+ type = xmlrpc_base64;
+ break;
+#ifndef BOOL_AS_LONG
+
+ /* Right thing to do, but it breaks some legacy code. */
+ case IS_BOOL:
+ type = xmlrpc_boolean;
+ break;
+#else
+ case IS_BOOL:
+#endif
+ case IS_LONG:
+ case IS_RESOURCE:
+ type = xmlrpc_int;
+ break;
+ case IS_DOUBLE:
+ type = xmlrpc_double;
+ break;
+ case IS_CONSTANT:
+ type = xmlrpc_string;
+ break;
+ case IS_STRING:
+ type = xmlrpc_string;
+ break;
+ case IS_ARRAY:
+ case IS_CONSTANT_ARRAY:
+ type = xmlrpc_vector;
+ break;
+ case IS_OBJECT:
+ {
+ zval** attr;
+ type = xmlrpc_vector;
+
+ if (zend_hash_find(Z_OBJPROP_P(value), OBJECT_TYPE_ATTR, sizeof(OBJECT_TYPE_ATTR), (void**) &attr) == SUCCESS) {
+ if (Z_TYPE_PP(attr) == IS_STRING) {
+ type = xmlrpc_str_as_type(Z_STRVAL_PP(attr));
+ }
+ }
+ break;
+ }
+ }
+
+ /* if requested, return an unmolested (magic removed) copy of the value */
+ if (newvalue) {
+ zval** val;
+
+ if ((type == xmlrpc_base64 && Z_TYPE_P(value) != IS_NULL) || type == xmlrpc_datetime) {
+ if (zend_hash_find(Z_OBJPROP_P(value), OBJECT_VALUE_ATTR, sizeof(OBJECT_VALUE_ATTR), (void**) &val) == SUCCESS) {
+ *newvalue = *val;
+ }
+ } else {
+ *newvalue = value;
+ }
+ }
+ }
+
+ return type;
+}
+/* }}} */
+
+/* {{{ proto bool xmlrpc_set_type(string value, string type)
+ Sets xmlrpc type, base64 or datetime, for a PHP string value */
+PHP_FUNCTION(xmlrpc_set_type)
+{
+ zval **arg;
+ char *type;
+ int type_len;
+ XMLRPC_VALUE_TYPE vtype;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Zs", &arg, &type, &type_len) == FAILURE) {
+ return;
+ }
+
+ vtype = xmlrpc_str_as_type(type);
+ if (vtype != xmlrpc_none) {
+ if (set_zval_xmlrpc_type(*arg, vtype) == SUCCESS) {
+ RETURN_TRUE;
+ }
+ } else {
+ zend_error(E_WARNING,"invalid type '%s' passed to xmlrpc_set_type()", type);
+ }
+ RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto string xmlrpc_get_type(mixed value)
+ Gets xmlrpc type for a PHP value. Especially useful for base64 and datetime strings */
+PHP_FUNCTION(xmlrpc_get_type)
+{
+ zval **arg;
+ XMLRPC_VALUE_TYPE type;
+ XMLRPC_VECTOR_TYPE vtype = xmlrpc_vector_none;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Z", &arg) == FAILURE) {
+ return;
+ }
+
+ type = get_zval_xmlrpc_type(*arg, 0);
+ if (type == xmlrpc_vector) {
+ vtype = determine_vector_type((Z_TYPE_PP(arg) == IS_OBJECT) ? Z_OBJPROP_PP(arg) : Z_ARRVAL_PP(arg));
+ }
+
+ RETURN_STRING((char*) xmlrpc_type_as_str(type, vtype), 1);
+}
+/* }}} */
+
+/* {{{ proto bool xmlrpc_is_fault(array)
+ Determines if an array value represents an XMLRPC fault. */
+PHP_FUNCTION(xmlrpc_is_fault)
+{
+ zval *arg, **val;
+
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &arg) == FAILURE) {
+ return;
+ }
+
+ /* The "correct" way to do this would be to call the xmlrpc
+ * library XMLRPC_ValueIsFault() func. However, doing that
+ * would require us to create an xmlrpc value from the php
+ * array, which is rather expensive, especially if it was
+ * a big array. Thus, we resort to this not so clever hackery.
+ */
+ if (zend_hash_find(Z_ARRVAL_P(arg), FAULT_CODE, FAULT_CODE_LEN + 1, (void**) &val) == SUCCESS &&
+ zend_hash_find(Z_ARRVAL_P(arg), FAULT_STRING, FAULT_STRING_LEN + 1, (void**) &val) == SUCCESS) {
+ RETURN_TRUE;
+ }
+
+ RETURN_FALSE;
+}
+/* }}} */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
+
diff --git a/ext/xmlrpc/xmlrpc.dsp b/ext/xmlrpc/xmlrpc.dsp
new file mode 100644
index 0000000..8c455d3
--- /dev/null
+++ b/ext/xmlrpc/xmlrpc.dsp
@@ -0,0 +1,211 @@
+# Microsoft Developer Studio Project File - Name="xmlrpc" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=xmlrpc - Win32 Debug_TS
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "xmlrpc.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "xmlrpc.mak" CFG="xmlrpc - Win32 Debug_TS"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "xmlrpc - Win32 Debug_TS" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "xmlrpc - Win32 Release_TS" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "xmlrpc - Win32 Debug_TS"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug_TS"
+# PROP BASE Intermediate_Dir "Debug_TS"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug_TS"
+# PROP Intermediate_Dir "Debug_TS"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "XMLRPC_EXPORTS" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /I "..\.." /I "..\..\main" /I "..\..\Zend" /I "..\..\TSRM" /I "libxmlrpc" /I "..\..\bundle\expat" /D HAVE_XMLRPC=1 /D "ZEND_WIN32" /D "PHP_WIN32" /D ZEND_DEBUG=1 /D ZTS=1 /D COMPILE_DL_XMLRPC=1 /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "XMLRPC_EXPORTS" /YX /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x1009 /d "_DEBUG"
+# ADD RSC /l 0x1009 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 php5ts_debug.lib expat.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"..\..\Debug_TS/php_xmlrpc.dll" /pdbtype:sept /libpath:"..\..\Debug_TS"
+
+!ELSEIF "$(CFG)" == "xmlrpc - Win32 Release_TS"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release_TS"
+# PROP BASE Intermediate_Dir "Release_TS"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release_TS"
+# PROP Intermediate_Dir "Release_TS"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "XMLRPC_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\.." /I "..\..\main" /I "..\..\Zend" /I "..\..\TSRM" /I "libxmlrpc" /I "..\..\bundle\expat" /D HAVE_XMLRPC=1 /D "ZEND_WIN32" /D ZEND_DEBUG=0 /D "PHP_WIN32" /D ZTS=1 /D COMPILE_DL_XMLRPC=1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "XMLRPC_EXPORTS" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x1009 /d "NDEBUG"
+# ADD RSC /l 0x1009 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
+# ADD LINK32 php5ts.lib expat.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"..\..\Release_TS/php_xmlrpc.dll" /libpath:"..\..\Release_TS"
+
+!ENDIF
+
+# Begin Target
+
+# Name "xmlrpc - Win32 Debug_TS"
+# Name "xmlrpc - Win32 Release_TS"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=".\xmlrpc-epi-php.c"
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl"
+# Begin Source File
+
+SOURCE=.\php_xmlrpc.h
+# End Source File
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
+# End Group
+# Begin Group "libxmlrpc"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\libxmlrpc\base64.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\libxmlrpc\base64.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\libxmlrpc\encodings.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\libxmlrpc\encodings.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\libxmlrpc\queue.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\libxmlrpc\queue.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\libxmlrpc\simplestring.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\libxmlrpc\simplestring.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\libxmlrpc\system_methods.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\libxmlrpc\system_methods_private.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\libxmlrpc\xml_element.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\libxmlrpc\xml_element.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\libxmlrpc\xml_to_dandarpc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\libxmlrpc\xml_to_dandarpc.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\libxmlrpc\xml_to_soap.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\libxmlrpc\xml_to_soap.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\libxmlrpc\xml_to_xmlrpc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\libxmlrpc\xml_to_xmlrpc.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\libxmlrpc\xmlrpc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\libxmlrpc\xmlrpc.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\libxmlrpc\xmlrpc_introspection.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\libxmlrpc\xmlrpc_introspection.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\libxmlrpc\xmlrpc_introspection_private.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\libxmlrpc\xmlrpc_private.h
+# End Source File
+# End Group
+# End Target
+# End Project