Annotation of embedaddon/php/ext/xmlrpc/libxmlrpc/xmlrpc.c, revision 1.1

1.1     ! misho       1: /*
        !             2:   This file is part of libXMLRPC - a C library for xml-encoded function calls.
        !             3: 
        !             4:   Author: Dan Libby (dan@libby.com)
        !             5:   Epinions.com may be contacted at feedback@epinions-inc.com
        !             6: */
        !             7: 
        !             8: /*  
        !             9:   Copyright 2000 Epinions, Inc. 
        !            10: 
        !            11:   Subject to the following 3 conditions, Epinions, Inc.  permits you, free 
        !            12:   of charge, to (a) use, copy, distribute, modify, perform and display this 
        !            13:   software and associated documentation files (the "Software"), and (b) 
        !            14:   permit others to whom the Software is furnished to do so as well.  
        !            15: 
        !            16:   1) The above copyright notice and this permission notice shall be included 
        !            17:   without modification in all copies or substantial portions of the 
        !            18:   Software.  
        !            19: 
        !            20:   2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF 
        !            21:   ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY 
        !            22:   IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR 
        !            23:   PURPOSE OR NONINFRINGEMENT.  
        !            24: 
        !            25:   3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT, 
        !            26:   SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT 
        !            27:   OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING 
        !            28:   NEGLIGENCE), EVEN IF EPINIONS, INC.  IS AWARE OF THE POSSIBILITY OF SUCH 
        !            29:   DAMAGES.    
        !            30: 
        !            31: */
        !            32: 
        !            33: 
        !            34: static const char rcsid[] = "#(@) $Id: xmlrpc.c 270900 2008-12-09 17:22:12Z iliaa $";
        !            35: 
        !            36: 
        !            37: /****h* ABOUT/xmlrpc
        !            38:  * NAME
        !            39:  *   XMLRPC_VALUE
        !            40:  * AUTHOR
        !            41:  *   Dan Libby, aka danda  (dan@libby.com)
        !            42:  * CREATION DATE
        !            43:  *   9/1999 - 10/2000
        !            44:  * HISTORY
        !            45:  *   $Log$
        !            46:  *   Revision 1.8.4.3.2.1  2008/09/10 00:07:44  felipe
        !            47:  *   MFH:
        !            48:  *   - Merged fix from SF project (Import Jeff Lawsons patches for XML datetime bug fixes)
        !            49:  *     Fixed bugs:
        !            50:  *     #45226 (xmlrpc_set_type() segfaults with valid ISO8601 date string)
        !            51:  *     #18916 (xmlrpc_set_type() "not working")
        !            52:  *
        !            53:  *   Revision 1.8.4.3  2007/09/18 19:49:53  iliaa
        !            54:  *
        !            55:  *   Fixed bug #42189 (xmlrpc_set_type() crashes php on invalid datetime
        !            56:  *     values).
        !            57:  *
        !            58:  *   Revision 1.8.4.2  2007/06/07 09:07:36  tony2001
        !            59:  *   MFH: php_localtime_r() checks
        !            60:  *
        !            61:  *   Revision 1.8.4.1  2006/11/30 16:38:37  iliaa
        !            62:  *   last set of zts fixes
        !            63:  *
        !            64:  *   Revision 1.8  2005/03/28 00:07:24  edink
        !            65:  *   Reshufle includes to make it compile on windows
        !            66:  *
        !            67:  *   Revision 1.7  2005/03/26 03:13:58  sniper
        !            68:  *   - Made it possible to build ext/xmlrpc with libxml2
        !            69:  *
        !            70:  *   Revision 1.6  2004/04/27 17:33:59  iliaa
        !            71:  *   Removed C++ style comments.
        !            72:  *
        !            73:  *   Revision 1.5  2003/12/16 21:00:21  sniper
        !            74:  *   Fix some compile warnings (patch by Joe Orton)
        !            75:  *
        !            76:  *   Revision 1.4  2002/07/05 04:43:53  danda
        !            77:  *   merged in updates from SF project.  bring php repository up to date with xmlrpc-epi version 0.51
        !            78:  *
        !            79:  *   Revision 1.22  2002/03/09 23:15:44  danda
        !            80:  *   add fault interrogation funcs
        !            81:  *
        !            82:  *   Revision 1.21  2002/03/09 22:27:41  danda
        !            83:  *   win32 build patches contributed by Jeff Lawson
        !            84:  *
        !            85:  *   Revision 1.20  2002/02/13 20:58:50  danda
        !            86:  *   patch to make source more windows friendly, contributed by Jeff Lawson
        !            87:  *
        !            88:  *   Revision 1.19  2001/10/12 23:25:54  danda
        !            89:  *   default to writing xmlrpc
        !            90:  *
        !            91:  *   Revision 1.18  2001/09/29 21:58:05  danda
        !            92:  *   adding cvs log to history section
        !            93:  *
        !            94:  *   10/15/2000 -- danda -- adding robodoc documentation
        !            95:  *   08/2000 -- danda -- PHP C extension that uses XMLRPC                     
        !            96:  *   08/2000 -- danda -- support for two vocabularies: danda-rpc and xml-rpc
        !            97:  *   09/1999 -- danda -- Initial API, before I even knew of standard XMLRPC vocab. Response only.
        !            98:  *   07/2000 -- danda -- wrote new implementation to be compatible with xmlrpc standard and
        !            99:  *                       incorporated some ideas from ensor, most notably the separation of
        !           100:  *                       xml dom from xmlrpc api.
        !           101:  *   06/2000 -- danda -- played with expat-ensor from www.ensor.org.  Cool, but some flaws.
        !           102:  * TODO
        !           103:  * PORTABILITY
        !           104:  *   Coded on RedHat Linux 6.2.  Builds on Solaris x86.  Should build on just
        !           105:  *   about anything with minor mods.
        !           106:  * NOTES
        !           107:  *   Welcome to XMLRPC.  For more info on the specification and history, see
        !           108:  *   http://www.xmlrpc.org.
        !           109:  *
        !           110:  *   This code aims to be a full-featured C implementation of XMLRPC.  It does not
        !           111:  *   have any networking code.  Rather, it is intended to be plugged into apps
        !           112:  *   or libraries with existing networking facilities, eg PHP, apache, perl, mozilla, 
        !           113:  *   home-brew application servers, etc.
        !           114:  *
        !           115:  *   Usage Paradigm:
        !           116:  *     The user of this library will typically be implementing either an XMLRPC server,
        !           117:  *     an XMLRPC client, or both.  The client will use the library to build an in-memory
        !           118:  *     representation of a request, and then serialize (encode) that request into XML. The
        !           119:  *     client will then send the XML to the server via external mechanism.  The server will
        !           120:  *     de-serialize the XML back into an binary representation, call the appropriate registered
        !           121:  *     method -- thereby generating a response.  The response will be serialized into XML and
        !           122:  *     sent back to the client.  The client will de-serialize it into memory, and can
        !           123:  *     iterate through the results via API.
        !           124:  *
        !           125:  *     Both the request and the response may consist of arbitrarily long, arbitrarily nested
        !           126:  *     values.  The values may be one of several types, as defined by XMLRPC_VALUE_TYPE.
        !           127:  *
        !           128:  *   Features and Architecture:
        !           129:  *     - The XML parsing (xml_element.c) is completely independent of the XMLRPC api. In fact,
        !           130:  *       it can be used as a standalone dom implementation.
        !           131:  *     - Because of this, the same XMLRPC data can be serialized into multiple xml vocabularies.
        !           132:  *       It is simply a matter of writing a transport.  So far, two transports have been defined.
        !           133:  *       The default xmlrpc vocab (xml_to_xmlrpc.c), and simple-rpc (xml_to_dandarpc.c) which is 
        !           134:  *       proprietary, but imho more readable, and nice for proprietary legacy reasons.
        !           135:  *     - Various output options, including: xml escaping via CDATA or entity, case folding,
        !           136:  *       vocab version, and character encoding.
        !           137:  *     - One to One mapping between C structures and actual values, unlike ensor which forces
        !           138:  *       one to understand the arcana of the xmlrpc vocab.
        !           139:  *     - support for mixed indexed/keyed vector types, making it more compatible with 
        !           140:  *       languages such as PHP.
        !           141:  *     - quite speedy compared to implementations written in interpreted languages. Also, uses
        !           142:  *       intelligent string handling, so not many strlen() calls, etc.
        !           143:  *     - comprehensive API for manipulation of values
        !           144:  *******/
        !           145: 
        !           146: #include "ext/xml/expat_compat.h"
        !           147: #include "main/php_reentrancy.h"
        !           148: #ifdef _WIN32
        !           149: #include "xmlrpc_win32.h"
        !           150: #endif
        !           151: #include <stdio.h>
        !           152: #include <stdlib.h>
        !           153: #include <string.h>
        !           154: #include <stdarg.h>
        !           155: #include <time.h>
        !           156: #include <ctype.h>
        !           157: 
        !           158: #include "queue.h"
        !           159: #include "xmlrpc.h"
        !           160: #include "base64.h"
        !           161: 
        !           162: #include "xml_to_xmlrpc.h"
        !           163: #include "xml_to_dandarpc.h"
        !           164: #include "xml_to_soap.h"
        !           165: #include "xml_element.h"
        !           166: #include "xmlrpc_private.h"
        !           167: #include "xmlrpc_introspection_private.h"
        !           168: #include "system_methods_private.h"
        !           169: 
        !           170: 
        !           171: 
        !           172: /*-*********************
        !           173: * Begin Time Functions *
        !           174: ***********************/
        !           175: 
        !           176: static time_t mkgmtime(struct tm *tm)
        !           177: {
        !           178:     static const int mdays[12] = {0,31,59,90,120,151,181,212,243,273,304,334};
        !           179: 
        !           180:     return ((((((tm->tm_year - 70) * 365) + mdays[tm->tm_mon] + tm->tm_mday-1 +
        !           181:                   (tm->tm_year-68-1+(tm->tm_mon>=2))/4) * 24) + tm->tm_hour) * 60 +
        !           182:         tm->tm_min) * 60 + tm->tm_sec;
        !           183: }
        !           184: 
        !           185: static int date_from_ISO8601 (const char *text, time_t * value) {
        !           186:    struct tm tm;
        !           187:    int n;
        !           188:    int i;
        !           189:    char buf[30];
        !           190:        
        !           191: 
        !           192:        if (strchr (text, '-')) {
        !           193:                char *p = (char *) text, *p2 = buf;
        !           194:                while (p && *p) {
        !           195:                        if (*p != '-') {
        !           196:                                *p2 = *p;
        !           197:                                p2++;
        !           198:                                if (p2-buf >= sizeof(buf)) {
        !           199:                                        return -1;
        !           200:                                }
        !           201:                        }
        !           202:                        p++;
        !           203:                }
        !           204:                        text = buf;
        !           205:        }
        !           206: 
        !           207: 
        !           208:    tm.tm_isdst = -1;
        !           209: 
        !           210: #define XMLRPC_IS_NUMBER(x) if (x < '0' || x > '9') return -1;
        !           211: 
        !           212:    n = 1000;
        !           213:    tm.tm_year = 0;
        !           214:    for(i = 0; i < 4; i++) {
        !           215:       XMLRPC_IS_NUMBER(text[i])
        !           216:       tm.tm_year += (text[i]-'0')*n;
        !           217:       n /= 10;
        !           218:    }
        !           219:    n = 10;
        !           220:    tm.tm_mon = 0;
        !           221:    for(i = 0; i < 2; i++) {
        !           222:       XMLRPC_IS_NUMBER(text[i])
        !           223:       tm.tm_mon += (text[i+4]-'0')*n;
        !           224:       n /= 10;
        !           225:    }
        !           226:    tm.tm_mon --;
        !           227: 
        !           228:    n = 10;
        !           229:    tm.tm_mday = 0;
        !           230:    for(i = 0; i < 2; i++) {
        !           231:       XMLRPC_IS_NUMBER(text[i])
        !           232:       tm.tm_mday += (text[i+6]-'0')*n;
        !           233:       n /= 10;
        !           234:    }
        !           235: 
        !           236:    n = 10;
        !           237:    tm.tm_hour = 0;
        !           238:    for(i = 0; i < 2; i++) {
        !           239:       XMLRPC_IS_NUMBER(text[i])
        !           240:       tm.tm_hour += (text[i+9]-'0')*n;
        !           241:       n /= 10;
        !           242:    }
        !           243: 
        !           244:    n = 10;
        !           245:    tm.tm_min = 0;
        !           246:    for(i = 0; i < 2; i++) {
        !           247:       XMLRPC_IS_NUMBER(text[i])
        !           248:       tm.tm_min += (text[i+12]-'0')*n;
        !           249:       n /= 10;
        !           250:    }
        !           251: 
        !           252:    n = 10;
        !           253:    tm.tm_sec = 0;
        !           254:    for(i = 0; i < 2; i++) {
        !           255:       XMLRPC_IS_NUMBER(text[i])
        !           256:       tm.tm_sec += (text[i+15]-'0')*n;
        !           257:       n /= 10;
        !           258:    }
        !           259: 
        !           260:    tm.tm_year -= 1900;
        !           261: 
        !           262:    *value = mkgmtime(&tm);
        !           263: 
        !           264:    return 0;
        !           265: 
        !           266: }
        !           267: 
        !           268: static int date_to_ISO8601 (time_t value, char *buf, int length) {
        !           269:    struct tm *tm, tmbuf;
        !           270:    tm = php_gmtime_r(&value, &tmbuf);
        !           271:    if (!tm) {
        !           272:           return 0;
        !           273:    }
        !           274: #if 0  /* TODO: soap seems to favor this method. xmlrpc the latter. */
        !           275:        return strftime (buf, length, "%Y-%m-%dT%H:%M:%SZ", tm);
        !           276: #else
        !           277:    return strftime(buf, length, "%Y%m%dT%H:%M:%SZ", tm);
        !           278: #endif
        !           279: }
        !           280: 
        !           281: /*-*******************
        !           282: * End Time Functions *
        !           283: *********************/
        !           284: 
        !           285: 
        !           286: /*-***************************
        !           287: * Begin XMLRPC_REQUEST funcs *
        !           288: *****************************/
        !           289: 
        !           290: /****f* REQUEST/XMLRPC_RequestNew
        !           291:  * NAME
        !           292:  *   XMLRPC_RequestNew
        !           293:  * SYNOPSIS
        !           294:  *   XMLRPC_REQUEST XMLRPC_RequestNew()
        !           295:  * FUNCTION
        !           296:  *   Creates a new XMLRPC_Request data struct
        !           297:  * INPUTS
        !           298:  *   none
        !           299:  * SEE ALSO
        !           300:  *   XMLRPC_RequestFree ()
        !           301:  * SOURCE
        !           302:  */
        !           303: XMLRPC_REQUEST XMLRPC_RequestNew() {
        !           304:    XMLRPC_REQUEST xRequest = calloc(1, sizeof(STRUCT_XMLRPC_REQUEST));
        !           305:    if(xRequest) {
        !           306:       simplestring_init(&xRequest->methodName);
        !           307:    }
        !           308:    return xRequest;
        !           309: }
        !           310: 
        !           311: /*******/
        !           312: 
        !           313: /****f* REQUEST/XMLRPC_RequestFree
        !           314:  * NAME
        !           315:  *   XMLRPC_RequestFree
        !           316:  * SYNOPSIS
        !           317:  *   void XMLRPC_RequestFree(XMLRPC_REQUEST request, int bFreeIO)
        !           318:  * FUNCTION
        !           319:  *   Free XMLRPC Request and all sub-values
        !           320:  * INPUTS
        !           321:  *   request -- previously allocated request struct
        !           322:  *   bFreeIO -- 1 = also free request value data, if any, 0 = ignore.
        !           323:  * SEE ALSO
        !           324:  *   XMLRPC_RequestNew ()
        !           325:  *   XMLRPC_CleanupValue ()
        !           326:  * SOURCE
        !           327:  */
        !           328: void XMLRPC_RequestFree(XMLRPC_REQUEST request, int bFreeIO) {
        !           329:    if(request) {
        !           330:       simplestring_free(&request->methodName);
        !           331: 
        !           332:       if(request->io && bFreeIO) {
        !           333:          XMLRPC_CleanupValue(request->io);
        !           334:       }
        !           335:       if(request->error) {
        !           336:          XMLRPC_CleanupValue(request->error);
        !           337:       }
        !           338:       my_free(request);
        !           339:    }
        !           340: }
        !           341: 
        !           342: /*******/
        !           343: 
        !           344: /* Set Method Name to call */
        !           345: /****f* REQUEST/XMLRPC_RequestSetMethodName
        !           346:  * NAME
        !           347:  *   XMLRPC_RequestSetMethodName
        !           348:  * SYNOPSIS
        !           349:  *   const char* XMLRPC_RequestSetMethodName(XMLRPC_REQUEST request, const char* methodName)
        !           350:  * FUNCTION
        !           351:  *   Set name of method to call with this request.
        !           352:  * INPUTS
        !           353:  *   request -- previously allocated request struct
        !           354:  *   methodName -- name of method
        !           355:  * SEE ALSO
        !           356:  *   XMLRPC_RequestNew ()
        !           357:  *   XMLRPC_RequestGetMethodName ()
        !           358:  *   XMLRPC_RequestFree ()
        !           359:  * SOURCE
        !           360:  */
        !           361: const char* XMLRPC_RequestSetMethodName(XMLRPC_REQUEST request, const char* methodName) {
        !           362:    if(request) {
        !           363:       simplestring_clear(&request->methodName);
        !           364:       simplestring_add(&request->methodName, methodName);
        !           365:       return request->methodName.str;
        !           366:    }
        !           367:    return NULL;
        !           368: }
        !           369: 
        !           370: /*******/
        !           371: 
        !           372: /****f* REQUEST/XMLRPC_RequestGetMethodName
        !           373:  * NAME
        !           374:  *   XMLRPC_RequestGetMethodName
        !           375:  * SYNOPSIS
        !           376:  *   const char* XMLRPC_RequestGetMethodName(XMLRPC_REQUEST request)
        !           377:  * FUNCTION
        !           378:  *   Get name of method called by this request
        !           379:  * INPUTS
        !           380:  *   request -- previously allocated request struct
        !           381:  * SEE ALSO
        !           382:  *   XMLRPC_RequestNew ()
        !           383:  *   XMLRPC_RequestSetMethodName ()
        !           384:  *   XMLRPC_RequestFree ()
        !           385:  * SOURCE
        !           386:  */
        !           387: const char* XMLRPC_RequestGetMethodName(XMLRPC_REQUEST request) {
        !           388:    return request ? request->methodName.str : NULL;
        !           389: }
        !           390: 
        !           391: /*******/
        !           392: 
        !           393: /****f* REQUEST/XMLRPC_RequestSetRequestType
        !           394:  * NAME
        !           395:  *   XMLRPC_RequestSetRequestType
        !           396:  * SYNOPSIS
        !           397:  *   XMLRPC_REQUEST_TYPE XMLRPC_RequestSetRequestType(XMLRPC_REQUEST request, XMLRPC_REQUEST_TYPE type)
        !           398:  * FUNCTION
        !           399:  *   A request struct may be allocated by a caller or by xmlrpc
        !           400:  *   in response to a request.  This allows setting the
        !           401:  *   request type.
        !           402:  * INPUTS
        !           403:  *   request -- previously allocated request struct
        !           404:  *   type    -- request type [xmlrpc_method_call | xmlrpc_method_response]
        !           405:  * SEE ALSO
        !           406:  *   XMLRPC_RequestNew ()
        !           407:  *   XMLRPC_RequestGetRequestType ()
        !           408:  *   XMLRPC_RequestFree ()
        !           409:  *   XMLRPC_REQUEST_TYPE
        !           410:  * SOURCE
        !           411:  */
        !           412: XMLRPC_REQUEST_TYPE XMLRPC_RequestSetRequestType (XMLRPC_REQUEST request,
        !           413:                                                                                                                                  XMLRPC_REQUEST_TYPE type) {
        !           414:    if(request) {
        !           415:       request->request_type = type;
        !           416:       return request->request_type;
        !           417:    }
        !           418:    return xmlrpc_request_none;
        !           419: }
        !           420: 
        !           421: /*******/
        !           422: 
        !           423: /****f* REQUEST/XMLRPC_RequestGetRequestType
        !           424:  * NAME
        !           425:  *   XMLRPC_RequestGetRequestType
        !           426:  * SYNOPSIS
        !           427:  *   XMLRPC_REQUEST_TYPE XMLRPC_RequestGetRequestType(XMLRPC_REQUEST request)
        !           428:  * FUNCTION
        !           429:  *   A request struct may be allocated by a caller or by xmlrpc
        !           430:  *   in response to a request.  This allows setting the
        !           431:  *   request type.
        !           432:  * INPUTS
        !           433:  *   request -- previously allocated request struct
        !           434:  * RESULT
        !           435:  *   type    -- request type [xmlrpc_method_call | xmlrpc_method_response]
        !           436:  * SEE ALSO
        !           437:  *   XMLRPC_RequestNew ()
        !           438:  *   XMLRPC_RequestSetRequestType ()
        !           439:  *   XMLRPC_RequestFree ()
        !           440:  *   XMLRPC_REQUEST_TYPE
        !           441:  * SOURCE
        !           442:  */
        !           443: XMLRPC_REQUEST_TYPE XMLRPC_RequestGetRequestType(XMLRPC_REQUEST request) {
        !           444:    return request ? request->request_type : xmlrpc_request_none;
        !           445: }
        !           446: 
        !           447: /*******/
        !           448: 
        !           449: 
        !           450: /****f* REQUEST/XMLRPC_RequestSetData
        !           451:  * NAME
        !           452:  *   XMLRPC_RequestSetData
        !           453:  * SYNOPSIS
        !           454:  *   XMLRPC_VALUE XMLRPC_RequestSetData(XMLRPC_REQUEST request, XMLRPC_VALUE data)
        !           455:  * FUNCTION
        !           456:  *   Associates a block of xmlrpc data with the request.  The
        !           457:  *   data is *not* copied.  A pointer is kept.  The caller
        !           458:  *   should be careful not to doubly free the data value,
        !           459:  *   which may optionally be free'd by XMLRPC_RequestFree().
        !           460:  * INPUTS
        !           461:  *   request -- previously allocated request struct
        !           462:  *   data    -- previously allocated data struct
        !           463:  * RESULT
        !           464:  *   XMLRPC_VALUE -- pointer to value stored, or NULL
        !           465:  * SEE ALSO
        !           466:  *   XMLRPC_RequestNew ()
        !           467:  *   XMLRPC_RequestGetData ()
        !           468:  *   XMLRPC_RequestFree ()
        !           469:  *   XMLRPC_REQUEST
        !           470:  *   XMLRPC_VALUE
        !           471:  * SOURCE
        !           472:  */
        !           473: XMLRPC_VALUE XMLRPC_RequestSetData(XMLRPC_REQUEST request, XMLRPC_VALUE data) {
        !           474:    if(request && data) {
        !           475:                if (request->io) {
        !           476:                        XMLRPC_CleanupValue (request->io);
        !           477:                }
        !           478:       request->io = XMLRPC_CopyValue(data);
        !           479:       return request->io;
        !           480:    }
        !           481:    return NULL;
        !           482: }
        !           483: 
        !           484: /*******/
        !           485: 
        !           486: /****f* REQUEST/XMLRPC_RequestGetData
        !           487:  * NAME
        !           488:  *   XMLRPC_RequestGetData
        !           489:  * SYNOPSIS
        !           490:  *   XMLRPC_VALUE XMLRPC_RequestGetData(XMLRPC_REQUEST request)
        !           491:  * FUNCTION
        !           492:  *   Returns data associated with request, if any.
        !           493:  * INPUTS
        !           494:  *   request -- previously allocated request struct
        !           495:  * RESULT
        !           496:  *   XMLRPC_VALUE -- pointer to value stored, or NULL
        !           497:  * SEE ALSO
        !           498:  *   XMLRPC_RequestNew ()
        !           499:  *   XMLRPC_RequestSetData ()
        !           500:  *   XMLRPC_RequestFree ()
        !           501:  *   XMLRPC_REQUEST
        !           502:  *   XMLRPC_VALUE
        !           503:  * SOURCE
        !           504:  */
        !           505: XMLRPC_VALUE XMLRPC_RequestGetData(XMLRPC_REQUEST request) {
        !           506:    return request ? request->io : NULL;
        !           507: }
        !           508: 
        !           509: /*******/
        !           510: 
        !           511: /****f* REQUEST/XMLRPC_RequestSetError
        !           512:  * NAME
        !           513:  *   XMLRPC_RequestSetError
        !           514:  * SYNOPSIS
        !           515:  *   XMLRPC_VALUE XMLRPC_RequestSetError(XMLRPC_REQUEST request, XMLRPC_VALUE error)
        !           516:  * FUNCTION
        !           517:  *   Associates a block of xmlrpc data, representing an error
        !           518:  *   condition, with the request. 
        !           519:  * INPUTS
        !           520:  *   request -- previously allocated request struct
        !           521:  *   error   -- previously allocated error code or struct
        !           522:  * RESULT
        !           523:  *   XMLRPC_VALUE -- pointer to value stored, or NULL
        !           524:  * NOTES
        !           525:  *   This is a private function for usage by internals only.
        !           526:  * SEE ALSO
        !           527:  *   XMLRPC_RequestGetError ()
        !           528:  * SOURCE
        !           529:  */
        !           530: XMLRPC_VALUE XMLRPC_RequestSetError (XMLRPC_REQUEST request, XMLRPC_VALUE error) {
        !           531:        if (request && error) {
        !           532:                if (request->error) {
        !           533:                        XMLRPC_CleanupValue (request->error);
        !           534:                }
        !           535:                request->error = XMLRPC_CopyValue (error);
        !           536:                return request->error;
        !           537:        }
        !           538:        return NULL;
        !           539: }
        !           540: 
        !           541: /*******/
        !           542: 
        !           543: /****f* REQUEST/XMLRPC_RequestGetError
        !           544:  * NAME
        !           545:  *   XMLRPC_RequestGetError
        !           546:  * SYNOPSIS
        !           547:  *   XMLRPC_VALUE XMLRPC_RequestGetError(XMLRPC_REQUEST request)
        !           548:  * FUNCTION
        !           549:  *   Returns error data associated with request, if any.
        !           550:  * INPUTS
        !           551:  *   request -- previously allocated request struct
        !           552:  * RESULT
        !           553:  *   XMLRPC_VALUE -- pointer to error value stored, or NULL
        !           554:  * NOTES
        !           555:  *   This is a private function for usage by internals only.
        !           556:  * SEE ALSO
        !           557:  *   XMLRPC_RequestSetError ()
        !           558:  *   XMLRPC_RequestFree ()
        !           559:  * SOURCE
        !           560:  */
        !           561: XMLRPC_VALUE XMLRPC_RequestGetError (XMLRPC_REQUEST request) {
        !           562:        return request ? request->error : NULL;
        !           563: }
        !           564: 
        !           565: /*******/
        !           566: 
        !           567: 
        !           568: /****f* REQUEST/XMLRPC_RequestSetOutputOptions
        !           569:  * NAME
        !           570:  *   XMLRPC_RequestSetOutputOptions
        !           571:  * SYNOPSIS
        !           572:  *   XMLRPC_REQUEST_OUTPUT_OPTIONS XMLRPC_RequestSetOutputOptions(XMLRPC_REQUEST request, XMLRPC_REQUEST_OUTPUT_OPTIONS output)
        !           573:  * FUNCTION
        !           574:  *   Sets output options used for generating XML. The output struct
        !           575:  *   is copied, and may be freed by the caller.
        !           576:  * INPUTS
        !           577:  *   request -- previously allocated request struct
        !           578:  *   output  -- output options struct initialized by caller
        !           579:  * RESULT
        !           580:  *   XMLRPC_REQUEST_OUTPUT_OPTIONS -- pointer to value stored, or NULL
        !           581:  * SEE ALSO
        !           582:  *   XMLRPC_RequestNew ()
        !           583:  *   XMLRPC_RequestGetOutputOptions ()
        !           584:  *   XMLRPC_RequestFree ()
        !           585:  *   XMLRPC_REQUEST
        !           586:  *   XMLRPC_REQUEST_OUTPUT_OPTIONS
        !           587:  * SOURCE
        !           588:  */
        !           589: XMLRPC_REQUEST_OUTPUT_OPTIONS XMLRPC_RequestSetOutputOptions(XMLRPC_REQUEST request, XMLRPC_REQUEST_OUTPUT_OPTIONS output) {
        !           590:    if(request && output) {
        !           591:                memcpy (&request->output, output,
        !           592:                                  sizeof (STRUCT_XMLRPC_REQUEST_OUTPUT_OPTIONS));
        !           593:       return &request->output;
        !           594:    }
        !           595:    return NULL;
        !           596: }
        !           597: 
        !           598: /*******/
        !           599: 
        !           600: 
        !           601: /****f* REQUEST/XMLRPC_RequestGetOutputOptions
        !           602:  * NAME
        !           603:  *   XMLRPC_RequestGetOutputOptions
        !           604:  * SYNOPSIS
        !           605:  *   XMLRPC_REQUEST_OUTPUT_OPTIONS XMLRPC_RequestGetOutputOptions(XMLRPC_REQUEST request)
        !           606:  * FUNCTION
        !           607:  *   Gets a pointer to output options used for generating XML.
        !           608:  * INPUTS
        !           609:  *   request -- previously allocated request struct
        !           610:  * RESULT
        !           611:  *   XMLRPC_REQUEST_OUTPUT_OPTIONS -- pointer to options stored, or NULL
        !           612:  * SEE ALSO
        !           613:  *   XMLRPC_RequestNew ()
        !           614:  *   XMLRPC_RequestSetOutputOptions ()
        !           615:  *   XMLRPC_RequestFree ()
        !           616:  *   XMLRPC_REQUEST
        !           617:  *   XMLRPC_REQUEST_OUTPUT_OPTIONS
        !           618:  * SOURCE
        !           619:  */
        !           620: XMLRPC_REQUEST_OUTPUT_OPTIONS XMLRPC_RequestGetOutputOptions(XMLRPC_REQUEST request) {
        !           621:    return request ? &request->output : NULL;
        !           622: }
        !           623: 
        !           624: /*******/
        !           625: 
        !           626: /*-*************************
        !           627: * End XMLRPC_REQUEST funcs *
        !           628: ***************************/
        !           629: 
        !           630: 
        !           631: /*-***************************
        !           632: * Begin Serializiation funcs *
        !           633: *****************************/
        !           634: 
        !           635: /****f* SERIALIZE/XMLRPC_VALUE_ToXML
        !           636:  * NAME
        !           637:  *   XMLRPC_VALUE_ToXML
        !           638:  * SYNOPSIS
        !           639:  *   char* XMLRPC_VALUE_ToXML(XMLRPC_VALUE val)
        !           640:  * FUNCTION
        !           641:  *   encode XMLRPC_VALUE into XML buffer.  Note that the generated
        !           642:  *   buffer will not contain a methodCall.
        !           643:  * INPUTS
        !           644:  *   val -- previously allocated XMLRPC_VALUE
        !           645:  *   buf_len -- length of returned buffer, if not null
        !           646:  * RESULT
        !           647:  *   char* -- newly allocated buffer containing XML. 
        !           648:  *   It is the caller's responsibility to free it.
        !           649:  * SEE ALSO
        !           650:  *   XMLRPC_REQUEST_ToXML ()
        !           651:  *   XMLRPC_VALUE_FromXML ()
        !           652:  *   XMLRPC_Free ()
        !           653:  *   XMLRPC_VALUE
        !           654:  * SOURCE
        !           655:  */
        !           656: char* XMLRPC_VALUE_ToXML(XMLRPC_VALUE val, int* buf_len) {
        !           657:    xml_element *root_elem = XMLRPC_VALUE_to_xml_element(val);
        !           658:    char* pRet = NULL;
        !           659: 
        !           660:    if(root_elem) {
        !           661:       pRet = xml_elem_serialize_to_string(root_elem, NULL, buf_len);
        !           662:       xml_elem_free(root_elem);
        !           663:    }
        !           664:    return pRet;
        !           665: }
        !           666: 
        !           667: /*******/
        !           668: 
        !           669: /****f* SERIALIZE/XMLRPC_REQUEST_ToXML
        !           670:  * NAME
        !           671:  *   XMLRPC_REQUEST_ToXML
        !           672:  * SYNOPSIS
        !           673:  *   char* XMLRPC_REQUEST_ToXML(XMLRPC_REQUEST request)
        !           674:  * FUNCTION
        !           675:  *   encode XMLRPC_REQUEST into XML buffer
        !           676:  * INPUTS
        !           677:  *   request -- previously allocated XMLRPC_REQUEST
        !           678:  *   buf_len -- size of returned buf, if not null
        !           679:  * RESULT
        !           680:  *   char* -- newly allocated buffer containing XML. 
        !           681:  *   It is the caller's responsibility to free it.
        !           682:  * SEE ALSO
        !           683:  *   XMLRPC_REQUEST_ToXML ()
        !           684:  *   XMLRPC_REQUEST_FromXML ()
        !           685:  *   XMLRPC_Free ()
        !           686:  *   XMLRPC_VALUE_ToXML ()
        !           687:  *   XMLRPC_REQUEST
        !           688:  * SOURCE
        !           689:  */
        !           690: char* XMLRPC_REQUEST_ToXML(XMLRPC_REQUEST request, int* buf_len) {
        !           691:       char* pRet = NULL;
        !           692:        if (request) {
        !           693:                xml_element *root_elem = NULL;
        !           694:                if (request->output.version == xmlrpc_version_simple) {
        !           695:                        root_elem = DANDARPC_REQUEST_to_xml_element (request);
        !           696:                }
        !           697:                else if (request->output.version == xmlrpc_version_1_0 ||
        !           698:                                        request->output.version == xmlrpc_version_none) {
        !           699:                        root_elem = XMLRPC_REQUEST_to_xml_element (request);
        !           700:                }
        !           701:                else if (request->output.version == xmlrpc_version_soap_1_1) {
        !           702:                        root_elem = SOAP_REQUEST_to_xml_element (request);
        !           703:                }
        !           704: 
        !           705:       if(root_elem) {
        !           706:                        pRet =
        !           707:                        xml_elem_serialize_to_string (root_elem,
        !           708:                                                                                                        &request->output.xml_elem_opts,
        !           709:                                                                                                        buf_len);
        !           710:          xml_elem_free(root_elem);
        !           711:       }
        !           712:    }
        !           713:        return pRet;
        !           714: }
        !           715: 
        !           716: /*******/
        !           717: 
        !           718: /****f* SERIALIZE/XMLRPC_VALUE_FromXML
        !           719:  * NAME
        !           720:  *   XMLRPC_VALUE_FromXML
        !           721:  * SYNOPSIS
        !           722:  *   XMLRPC_VALUE XMLRPC_VALUE_FromXML(const char* in_buf, int le
        !           723:  * FUNCTION
        !           724:  *   Retrieve XMLRPC_VALUE from XML buffer. Note that this will
        !           725:  *   ignore any methodCall.  See XMLRPC_REQUEST_FromXML
        !           726:  * INPUTS
        !           727:  *   in_buf -- character buffer containing XML
        !           728:  *   len    -- length of buffer
        !           729:  * RESULT
        !           730:  *   XMLRPC_VALUE -- newly allocated data, or NULL if error. Should
        !           731:  *   be free'd by caller.
        !           732:  * SEE ALSO
        !           733:  *   XMLRPC_VALUE_ToXML ()
        !           734:  *   XMLRPC_REQUEST_FromXML ()
        !           735:  *   XMLRPC_VALUE
        !           736:  * SOURCE
        !           737:  */
        !           738: XMLRPC_VALUE XMLRPC_VALUE_FromXML (const char *in_buf, int len, XMLRPC_REQUEST_INPUT_OPTIONS in_options) {
        !           739:    XMLRPC_VALUE xResponse = NULL;
        !           740:    XMLRPC_REQUEST req = XMLRPC_REQUEST_FromXML(in_buf, len, in_options);
        !           741: 
        !           742:    if(req) {
        !           743:       xResponse = req->io;
        !           744:       XMLRPC_RequestFree(req, 0);
        !           745:    }
        !           746:    return xResponse;
        !           747: }
        !           748: 
        !           749: /*******/
        !           750: 
        !           751: /* map parser errors to standard xml-rpc errors */
        !           752: static XMLRPC_VALUE map_expat_errors(XML_ELEM_ERROR error) {
        !           753:    XMLRPC_VALUE xReturn = NULL;
        !           754:    if(error) {
        !           755:       XMLRPC_ERROR_CODE code;
        !           756:       char buf[1024];
        !           757:       snprintf(buf, sizeof(buf), 
        !           758:                "error occurred at line %ld, column %ld, byte index %ld", 
        !           759:                                         error->line, error->column, error->byte_index);
        !           760: 
        !           761:       /* expat specific errors */
        !           762:       switch(error->parser_code) {
        !           763:       case XML_ERROR_UNKNOWN_ENCODING:
        !           764:          code = xmlrpc_error_parse_unknown_encoding;
        !           765:          break;
        !           766:       case XML_ERROR_INCORRECT_ENCODING:
        !           767:          code = xmlrpc_error_parse_bad_encoding;
        !           768:          break;
        !           769:       default:
        !           770:          code = xmlrpc_error_parse_xml_syntax;
        !           771:          break;
        !           772:       }
        !           773:       xReturn = XMLRPC_UtilityCreateFault(code, buf);
        !           774:    }
        !           775:    return xReturn;
        !           776: }
        !           777: 
        !           778: /****f* SERIALIZE/XMLRPC_REQUEST_FromXML
        !           779:  * NAME
        !           780:  *   XMLRPC_REQUEST_FromXML
        !           781:  * SYNOPSIS
        !           782:  *   XMLRPC_REQUEST XMLRPC_REQUEST_FromXML(const char* in_buf, int le
        !           783:  * FUNCTION
        !           784:  *   Retrieve XMLRPC_REQUEST from XML buffer
        !           785:  * INPUTS
        !           786:  *   in_buf -- character buffer containing XML
        !           787:  *   len    -- length of buffer
        !           788:  * RESULT
        !           789:  *   XMLRPC_REQUEST -- newly allocated data, or NULL if error. Should
        !           790:  *   be free'd by caller.
        !           791:  * SEE ALSO
        !           792:  *   XMLRPC_REQUEST_ToXML ()
        !           793:  *   XMLRPC_VALUE_FromXML ()
        !           794:  *   XMLRPC_REQUEST
        !           795:  * SOURCE
        !           796:  */
        !           797: XMLRPC_REQUEST XMLRPC_REQUEST_FromXML (const char *in_buf, int len, 
        !           798:                                                                                                        XMLRPC_REQUEST_INPUT_OPTIONS in_options) {
        !           799:    XMLRPC_REQUEST request = XMLRPC_RequestNew();
        !           800:    STRUCT_XML_ELEM_ERROR error = {0};
        !           801: 
        !           802:    if(request) {
        !           803:                xml_element *root_elem =
        !           804:                xml_elem_parse_buf (in_buf, len,
        !           805:                                                                  (in_options ? &in_options->xml_elem_opts : NULL),
        !           806:                                                                  &error);
        !           807: 
        !           808:       if(root_elem) {
        !           809:          if(!strcmp(root_elem->name, "simpleRPC")) {
        !           810:             request->output.version = xmlrpc_version_simple;
        !           811:             xml_element_to_DANDARPC_REQUEST(request, root_elem);
        !           812:          }
        !           813:                        else if (!strcmp (root_elem->name, "SOAP-ENV:Envelope")) {
        !           814:                                request->output.version = xmlrpc_version_soap_1_1;
        !           815:                                xml_element_to_SOAP_REQUEST (request, root_elem);
        !           816:                        }
        !           817:          else {
        !           818:             request->output.version = xmlrpc_version_1_0;
        !           819:             xml_element_to_XMLRPC_REQUEST(request, root_elem);
        !           820:          }
        !           821:          xml_elem_free(root_elem);
        !           822:       }
        !           823:       else {
        !           824:          if(error.parser_error) {
        !           825:                                XMLRPC_RequestSetError (request, map_expat_errors (&error));
        !           826:          }
        !           827:       }
        !           828:    }
        !           829: 
        !           830:    return request;
        !           831: }
        !           832: 
        !           833: /*******/
        !           834: 
        !           835: /*-************************
        !           836: * End Serialization Funcs *
        !           837: **************************/
        !           838: 
        !           839: 
        !           840: 
        !           841: /****f* VALUE/XMLRPC_CreateValueEmpty
        !           842:  * NAME
        !           843:  *   XMLRPC_CreateValueEmpty
        !           844:  * SYNOPSIS
        !           845:  *   XMLRPC_VALUE XMLRPC_CreateValueEmpty ()
        !           846:  * FUNCTION
        !           847:  *   Create an XML value to be used/modified elsewhere.
        !           848:  * INPUTS
        !           849:  * RESULT
        !           850:  *   XMLRPC_VALUE.  The new value, or NULL on failure.
        !           851:  * SEE ALSO
        !           852:  *   XMLRPC_CleanupValue ()
        !           853:  *   XMLRPC_VALUE
        !           854:  * SOURCE
        !           855:  */
        !           856: XMLRPC_VALUE XMLRPC_CreateValueEmpty() {
        !           857:    XMLRPC_VALUE v = calloc(1, sizeof(STRUCT_XMLRPC_VALUE));
        !           858:    if(v) {
        !           859: #ifdef XMLRPC_DEBUG_REFCOUNT
        !           860:                printf ("calloc'd 0x%x\n", v);
        !           861: #endif
        !           862:       v->type = xmlrpc_empty;
        !           863:       simplestring_init(&v->id);
        !           864:       simplestring_init(&v->str);
        !           865:    }
        !           866:    return v;
        !           867: }
        !           868: 
        !           869: /*******/
        !           870: 
        !           871: /****f* VALUE/XMLRPC_SetValueID_Case
        !           872:  * NAME
        !           873:  *   XMLRPC_SetValueID_Case
        !           874:  * SYNOPSIS
        !           875:  *   const char *XMLRPC_SetValueID_Case(XMLRPC_VALUE value, const char* id, int len, XMLRPC_CASE id_case)
        !           876:  * FUNCTION
        !           877:  *   Assign an ID (key) to an XMLRPC value.
        !           878:  * INPUTS
        !           879:  *   value     The xml value who's ID we will set.
        !           880:  *   id        The desired new id.
        !           881:  *   len       length of id string if known, or 0 if unknown.
        !           882:  *   id_case   one of XMLRPC_CASE
        !           883:  * RESULT
        !           884:  *   const char*  pointer to the newly allocated id string, or NULL
        !           885:  * SEE ALSO
        !           886:  *   XMLRPC_SetValueID ()
        !           887:  *   XMLRPC_GetValueID ()
        !           888:  *   XMLRPC_VALUE
        !           889:  *   XMLRPC_CASE
        !           890:  * SOURCE
        !           891:  */
        !           892: const char *XMLRPC_SetValueID_Case(XMLRPC_VALUE value, const char* id, int len, XMLRPC_CASE id_case) {
        !           893:    const char* pRetval = NULL;
        !           894:    if(value) {
        !           895:       if(id) {
        !           896:          simplestring_clear(&value->id);
        !           897:          (len > 0) ? simplestring_addn(&value->id, id, len) :
        !           898:                      simplestring_add(&value->id, id);
        !           899: 
        !           900:          /* upper or lower case string in place if required. could be a seperate func. */
        !           901:          if(id_case == xmlrpc_case_lower || id_case == xmlrpc_case_upper) {
        !           902:             int i;
        !           903:             for(i = 0; i < value->id.len; i++) {
        !           904:                                        value->id.str[i] =
        !           905:                                        (id_case ==
        !           906:                                         xmlrpc_case_lower) ? tolower (value->id.
        !           907:                                                                                                                         str[i]) : toupper (value->
        !           908:                                                                                                                                                                          id.
        !           909:                                                                                                                                                                          str[i]);
        !           910:             }
        !           911:          }
        !           912: 
        !           913:          pRetval = value->id.str;
        !           914: 
        !           915: #ifdef XMLRPC_DEBUG_REFCOUNT
        !           916:          printf("set value id: %s\n", pRetval);
        !           917: #endif 
        !           918:       }
        !           919:    }
        !           920: 
        !           921:    return pRetval;
        !           922: }
        !           923: 
        !           924: /*******/
        !           925: 
        !           926: 
        !           927: /****f* VALUE/XMLRPC_SetValueString
        !           928:  * NAME
        !           929:  *   XMLRPC_SetValueString
        !           930:  * SYNOPSIS
        !           931:  *   const char *XMLRPC_SetValueString(XMLRPC_VALUE value, const char* val, int len)
        !           932:  * FUNCTION
        !           933:  *   Assign a string value to an XMLRPC_VALUE, and set it to type xmlrpc_string
        !           934:  * INPUTS
        !           935:  *   value     The xml value who's ID we will set.
        !           936:  *   val        The desired new string val.
        !           937:  *   len       length of val string if known, or 0 if unknown.
        !           938:  * RESULT
        !           939:  *   const char*  pointer to the newly allocated value string, or NULL
        !           940:  * SEE ALSO
        !           941:  *   XMLRPC_GetValueString ()
        !           942:  *   XMLRPC_VALUE
        !           943:  *   XMLRPC_VALUE_TYPE
        !           944:  * SOURCE
        !           945:  */
        !           946: const char *XMLRPC_SetValueString(XMLRPC_VALUE value, const char* val, int len) {
        !           947:    char *pRetval = NULL;
        !           948:    if(value && val) {
        !           949:       simplestring_clear(&value->str);
        !           950:       (len > 0) ? simplestring_addn(&value->str, val, len) :
        !           951:                   simplestring_add(&value->str, val);
        !           952:       value->type = xmlrpc_string;
        !           953:       pRetval = (char *)value->str.str;
        !           954:    }
        !           955: 
        !           956:    return pRetval;
        !           957: }
        !           958: 
        !           959: /*******/
        !           960: 
        !           961: /****f* VALUE/XMLRPC_SetValueInt
        !           962:  * NAME
        !           963:  *   XMLRPC_SetValueInt
        !           964:  * SYNOPSIS
        !           965:  *   void XMLRPC_SetValueInt(XMLRPC_VALUE value, int val)
        !           966:  * FUNCTION
        !           967:  *   Assign an int value to an XMLRPC_VALUE, and set it to type xmlrpc_int
        !           968:  * INPUTS
        !           969:  *   value     The xml value who's ID we will set.
        !           970:  *   val        The desired new integer value
        !           971:  * RESULT
        !           972:  * SEE ALSO
        !           973:  *   XMLRPC_GetValueInt ()
        !           974:  *   XMLRPC_VALUE
        !           975:  *   XMLRPC_VALUE_TYPE
        !           976:  * SOURCE
        !           977:  */
        !           978: void XMLRPC_SetValueInt(XMLRPC_VALUE value, int val) {
        !           979:    if(value) {
        !           980:       value->type = xmlrpc_int;
        !           981:       value->i = val;
        !           982:    }
        !           983: }
        !           984: 
        !           985: /*******/
        !           986: 
        !           987: /****f* VALUE/XMLRPC_SetValueBoolean
        !           988:  * NAME
        !           989:  *   XMLRPC_SetValueBoolean
        !           990:  * SYNOPSIS
        !           991:  *   void XMLRPC_SetValueBoolean(XMLRPC_VALUE value, int val)
        !           992:  * FUNCTION
        !           993:  *   Assign a boolean value to an XMLRPC_VALUE, and set it to type xmlrpc_boolean
        !           994:  * INPUTS
        !           995:  *   value     The xml value who's value we will set.
        !           996:  *   val        The desired new boolean value. [0 | 1]
        !           997:  * RESULT
        !           998:  * SEE ALSO
        !           999:  *   XMLRPC_GetValueBoolean ()
        !          1000:  *   XMLRPC_VALUE
        !          1001:  *   XMLRPC_VALUE_TYPE
        !          1002:  * SOURCE
        !          1003:  */
        !          1004: void XMLRPC_SetValueBoolean(XMLRPC_VALUE value, int val) {
        !          1005:    if(value) {
        !          1006:       value->type = xmlrpc_boolean;
        !          1007:       value->i = val ? 1 : 0;
        !          1008:    }
        !          1009: }
        !          1010: 
        !          1011: /*******/
        !          1012: 
        !          1013: 
        !          1014: /****f* VECTOR/XMLRPC_SetIsVector
        !          1015:  * NAME
        !          1016:  *   XMLRPC_SetIsVector
        !          1017:  * SYNOPSIS
        !          1018:  *   int XMLRPC_SetIsVector(XMLRPC_VALUE value, XMLRPC_VECTOR_TYPE type)
        !          1019:  * FUNCTION
        !          1020:  *   Set the XMLRPC_VALUE to be a vector (list) type.  The vector may be one of
        !          1021:  *   [xmlrpc_array | xmlrpc_struct | xmlrpc_mixed].  An array has only index values.
        !          1022:  *   A struct has key/val pairs.  Mixed allows both index and key/val combinations. 
        !          1023:  * INPUTS
        !          1024:  *   value     The xml value who's vector type we will set
        !          1025:  *   type      New type of vector as enumerated by XMLRPC_VECTOR_TYPE
        !          1026:  * RESULT
        !          1027:  *   int       1 if successful, 0 otherwise
        !          1028:  * SEE ALSO
        !          1029:  *   XMLRPC_GetValueType ()
        !          1030:  *   XMLRPC_GetVectorType ()
        !          1031:  *   XMLRPC_VALUE
        !          1032:  *   XMLRPC_VECTOR_TYPE
        !          1033:  *   XMLRPC_VALUE_TYPE
        !          1034:  * SOURCE
        !          1035:  */
        !          1036: int XMLRPC_SetIsVector(XMLRPC_VALUE value, XMLRPC_VECTOR_TYPE type) {
        !          1037:    int bSuccess = 0;
        !          1038: 
        !          1039:        if (value) {
        !          1040:                /* we can change the type so long as nothing is currently stored. */
        !          1041:                if(value->type == xmlrpc_vector) {
        !          1042:                        if(value->v) {
        !          1043:                                if(!Q_Size(value->v->q)) {
        !          1044:                                        value->v->type = type;
        !          1045:                                }
        !          1046:                        }
        !          1047:                }
        !          1048:                else {
        !          1049:       value->v = calloc(1, sizeof(STRUCT_XMLRPC_VECTOR));
        !          1050:       if(value->v) {
        !          1051:          value->v->q = (queue*)malloc(sizeof(queue));
        !          1052:          if(value->v->q) {
        !          1053:             Q_Init(value->v->q);
        !          1054:             value->v->type = type;
        !          1055:             value->type = xmlrpc_vector;
        !          1056:             bSuccess = 1;
        !          1057:          }
        !          1058:       }
        !          1059:    }
        !          1060:        }
        !          1061: 
        !          1062:    return bSuccess;
        !          1063: }
        !          1064: 
        !          1065: /*******/
        !          1066: 
        !          1067: /****f* VECTOR/XMLRPC_CreateVector
        !          1068:  * NAME
        !          1069:  *   XMLRPC_CreateVector
        !          1070:  * SYNOPSIS
        !          1071:  *   XMLRPC_VALUE XMLRPC_CreateVector(const char* id, XMLRPC_VECTOR_TYPE type)
        !          1072:  * FUNCTION
        !          1073:  *   Create a new vector and optionally set an id.
        !          1074:  * INPUTS
        !          1075:  *   id        The id of the vector, or NULL
        !          1076:  *   type      New type of vector as enumerated by XMLRPC_VECTOR_TYPE
        !          1077:  * RESULT
        !          1078:  *   XMLRPC_VALUE  The new vector, or NULL on failure.
        !          1079:  * SEE ALSO
        !          1080:  *   XMLRPC_CreateValueEmpty ()
        !          1081:  *   XMLRPC_SetIsVector ()
        !          1082:  *   XMLRPC_GetValueType ()
        !          1083:  *   XMLRPC_GetVectorType ()
        !          1084:  *   XMLRPC_VALUE
        !          1085:  *   XMLRPC_VECTOR_TYPE
        !          1086:  *   XMLRPC_VALUE_TYPE
        !          1087:  * SOURCE
        !          1088:  */
        !          1089: XMLRPC_VALUE XMLRPC_CreateVector(const char* id, XMLRPC_VECTOR_TYPE type) {
        !          1090:    XMLRPC_VALUE val = NULL;
        !          1091: 
        !          1092:    val = XMLRPC_CreateValueEmpty();
        !          1093:    if(val) {
        !          1094:       if(XMLRPC_SetIsVector(val, type)) {
        !          1095:          if(id) {
        !          1096:             const char *pSVI = NULL;
        !          1097: 
        !          1098:             pSVI = XMLRPC_SetValueID(val, id, 0);
        !          1099:             if(NULL == pSVI) {
        !          1100:                val = NULL;
        !          1101:             }
        !          1102:          }
        !          1103:       }
        !          1104:       else {
        !          1105:          val = NULL;
        !          1106:       }
        !          1107:    }
        !          1108:    return val;
        !          1109: }
        !          1110: 
        !          1111: /*******/
        !          1112: 
        !          1113: 
        !          1114: /* Not yet implemented.
        !          1115:  *
        !          1116:  * This should use a hash to determine if a given target id has already
        !          1117:  * been appended.  
        !          1118:  *
        !          1119:  * Alternately, it could walk the entire vector, but that could be quite
        !          1120:  * slow for very large lists.
        !          1121:  */
        !          1122: static int isDuplicateEntry(XMLRPC_VALUE target, XMLRPC_VALUE source) {
        !          1123:    return 0;
        !          1124: }
        !          1125: 
        !          1126: /****f* VECTOR/XMLRPC_AddValueToVector
        !          1127:  * NAME
        !          1128:  *   XMLRPC_AddValueToVector
        !          1129:  * SYNOPSIS
        !          1130:  *   int XMLRPC_AddValueToVector(XMLRPC_VALUE target, XMLRPC_VALUE source)
        !          1131:  * FUNCTION
        !          1132:  *   Add (append) an existing XMLRPC_VALUE to a vector.
        !          1133:  * INPUTS
        !          1134:  *   target    The target vector
        !          1135:  *   source    The source value to append
        !          1136:  * RESULT
        !          1137:  *   int       1 if successful, else 0
        !          1138:  * SEE ALSO
        !          1139:  *   XMLRPC_AddValuesToVector ()
        !          1140:  *   XMLRPC_VectorGetValueWithID_Case ()
        !          1141:  *   XMLRPC_VALUE
        !          1142:  * NOTES
        !          1143:  *   The function will fail and return 0 if an attempt is made to add
        !          1144:  *   a value with an ID into a vector of type xmlrpc_vector_array. Such
        !          1145:  *   values can only be added to xmlrpc_vector_struct.
        !          1146:  * SOURCE
        !          1147:  */
        !          1148: int XMLRPC_AddValueToVector(XMLRPC_VALUE target, XMLRPC_VALUE source) {
        !          1149:    if(target && source) {
        !          1150:       if(target->type == xmlrpc_vector && target->v && 
        !          1151:          target->v->q && target->v->type != xmlrpc_vector_none) {
        !          1152: 
        !          1153:          /* guard against putting value of unknown type into vector */
        !          1154:          switch(source->type) {
        !          1155:             case xmlrpc_empty:
        !          1156:             case xmlrpc_base64:
        !          1157:             case xmlrpc_boolean:
        !          1158:             case xmlrpc_datetime:
        !          1159:             case xmlrpc_double:
        !          1160:             case xmlrpc_int:
        !          1161:             case xmlrpc_string:
        !          1162:             case xmlrpc_vector:
        !          1163:                /* Guard against putting a key/val pair into an array vector */
        !          1164:                if( !(source->id.len && target->v->type == xmlrpc_vector_array) ) {
        !          1165:                                        if (isDuplicateEntry (target, source)
        !          1166:                                                 || Q_PushTail (target->v->q, XMLRPC_CopyValue (source))) {
        !          1167:                      return 1;
        !          1168:                   }
        !          1169:                }
        !          1170:                else {
        !          1171:                                        /* fprintf (stderr,
        !          1172:                                                                "xmlrpc: attempted to add key/val pair to vector of type array\n"); */
        !          1173:                }
        !          1174:                break;
        !          1175:             default:
        !          1176:                                /* fprintf (stderr,
        !          1177:                                                        "xmlrpc: attempted to add value of unknown type to vector\n"); */
        !          1178:                break;
        !          1179:          }
        !          1180:       }
        !          1181:    }
        !          1182:    return 0;
        !          1183: }
        !          1184: 
        !          1185: /*******/
        !          1186: 
        !          1187: 
        !          1188: /****f* VECTOR/XMLRPC_AddValuesToVector
        !          1189:  * NAME
        !          1190:  *   XMLRPC_AddValuesToVector
        !          1191:  * SYNOPSIS
        !          1192:  *   XMLRPC_AddValuesToVector ( target, val1, val2, val3, val(n), 0 )
        !          1193:  *   XMLRPC_AddValuesToVector( XMLRPC_VALUE, ... )
        !          1194:  * FUNCTION
        !          1195:  *   Add (append) a series of existing XMLRPC_VALUE to a vector.
        !          1196:  * INPUTS
        !          1197:  *   target    The target vector
        !          1198:  *   ...       The source value(s) to append.  The last item *must* be 0.
        !          1199:  * RESULT
        !          1200:  *   int       1 if successful, else 0
        !          1201:  * SEE ALSO
        !          1202:  *   XMLRPC_AddValuesToVector ()
        !          1203:  *   XMLRPC_VectorGetValueWithID_Case ()
        !          1204:  *   XMLRPC_VALUE
        !          1205:  * NOTES
        !          1206:  *   This function may actually return failure after it has already modified
        !          1207:  *     or added items to target.  You can not trust the state of target
        !          1208:  *     if this function returns failure.
        !          1209:  * SOURCE
        !          1210:  */
        !          1211: int XMLRPC_AddValuesToVector(XMLRPC_VALUE target, ...) {
        !          1212:    int iRetval = 0;
        !          1213: 
        !          1214:    if(target) {
        !          1215:       if(target->type == xmlrpc_vector) {
        !          1216:          XMLRPC_VALUE v = NULL;
        !          1217:          va_list vl;
        !          1218: 
        !          1219:          va_start(vl, target);
        !          1220: 
        !          1221:          do {
        !          1222:             v = va_arg(vl, XMLRPC_VALUE);
        !          1223:             if(v) {
        !          1224:                if(!XMLRPC_AddValueToVector(target, v)) {
        !          1225:                   iRetval = 0;
        !          1226:                   break;
        !          1227:                }
        !          1228:             }
        !          1229:                        }
        !          1230:                        while (v);
        !          1231: 
        !          1232:          va_end(vl);
        !          1233: 
        !          1234:          if(NULL == v) {
        !          1235:             iRetval = 1;
        !          1236:          }
        !          1237:       }
        !          1238:    }
        !          1239:    return iRetval;
        !          1240: }
        !          1241: 
        !          1242: /*******/
        !          1243: 
        !          1244: 
        !          1245: /****f* VECTOR/XMLRPC_VectorGetValueWithID_Case
        !          1246:  * NAME
        !          1247:  *   XMLRPC_VectorGetValueWithID_Case
        !          1248:  * SYNOPSIS
        !          1249:  *   XMLRPC_VALUE XMLRPC_VectorGetValueWithID_Case(XMLRPC_VALUE vector, const char* id, XMLRPC_CASE_COMPARISON id_case)
        !          1250:  * FUNCTION
        !          1251:  *   Get value from vector matching id (key)
        !          1252:  * INPUTS
        !          1253:  *   vector    The source vector
        !          1254:  *   id        The key to find
        !          1255:  *   id_case   Rule for how to match key
        !          1256:  * RESULT
        !          1257:  *   int       1 if successful, else 0
        !          1258:  * SEE ALSO
        !          1259:  *   XMLRPC_SetValueID_Case ()
        !          1260:  *   XMLRPC_VALUE
        !          1261:  *   XMLRPC_CASE_COMPARISON
        !          1262:  * SOURCE
        !          1263:  */
        !          1264: XMLRPC_VALUE XMLRPC_VectorGetValueWithID_Case (XMLRPC_VALUE vector, const char *id,
        !          1265:                                                                                                                          XMLRPC_CASE_COMPARISON id_case) {
        !          1266:    if(vector && vector->v && vector->v->q) {
        !          1267:        q_iter qi = Q_Iter_Head_F(vector->v->q);
        !          1268: 
        !          1269:        while(qi) {
        !          1270:           XMLRPC_VALUE xIter = Q_Iter_Get_F(qi);
        !          1271:           if(xIter && xIter->id.str) {
        !          1272:              if(id_case == xmlrpc_case_sensitive) {
        !          1273:                 if(!strcmp(xIter->id.str, id)) {
        !          1274:                    return xIter;
        !          1275:                 }
        !          1276:              }
        !          1277:              else if(id_case == xmlrpc_case_insensitive) {
        !          1278:                 if(!strcasecmp(xIter->id.str, id)) {
        !          1279:                    return xIter;
        !          1280:                 }
        !          1281:              }
        !          1282:           }
        !          1283:           qi = Q_Iter_Next_F(qi);
        !          1284:        }
        !          1285:    }
        !          1286:    return NULL;
        !          1287: }
        !          1288: 
        !          1289: /*******/
        !          1290: 
        !          1291: 
        !          1292: int XMLRPC_VectorRemoveValue(XMLRPC_VALUE vector, XMLRPC_VALUE value) {
        !          1293:    if(vector && vector->v && vector->v->q && value) {
        !          1294:        q_iter qi = Q_Iter_Head_F(vector->v->q);
        !          1295: 
        !          1296:        while(qi) {
        !          1297:           XMLRPC_VALUE xIter = Q_Iter_Get_F(qi);
        !          1298:           if(xIter == value) {
        !          1299:              XMLRPC_CleanupValue(xIter);
        !          1300:              Q_Iter_Del(vector->v->q, qi);
        !          1301:              return 1;
        !          1302:           }
        !          1303:           qi = Q_Iter_Next_F(qi);
        !          1304:        }
        !          1305:    }
        !          1306:    return 0;
        !          1307: }
        !          1308: 
        !          1309: 
        !          1310: /****f* VALUE/XMLRPC_CreateValueString
        !          1311:  * NAME
        !          1312:  *   XMLRPC_CreateValueString
        !          1313:  * SYNOPSIS
        !          1314:  *   XMLRPC_VALUE XMLRPC_CreateValueString(const char* id, const char* val, int len)
        !          1315:  * FUNCTION
        !          1316:  *   Create an XMLRPC_VALUE, and assign a string to it
        !          1317:  * INPUTS
        !          1318:  *   id        The id of the value, or NULL
        !          1319:  *   val       The desired new string val.
        !          1320:  *   len       length of val string if known, or 0 if unknown.
        !          1321:  * RESULT
        !          1322:  *   newly allocated XMLRPC_VALUE, or NULL
        !          1323:  * SEE ALSO
        !          1324:  *   XMLRPC_GetValueString ()
        !          1325:  *   XMLRPC_CreateValueEmpty ()
        !          1326:  *   XMLRPC_VALUE
        !          1327:  *   XMLRPC_VALUE_TYPE
        !          1328:  * SOURCE
        !          1329:  */
        !          1330: XMLRPC_VALUE XMLRPC_CreateValueString(const char* id, const char* val, int len) {
        !          1331:    XMLRPC_VALUE value = NULL;
        !          1332:    if(val) {
        !          1333:       value = XMLRPC_CreateValueEmpty();
        !          1334:       if(value) {
        !          1335:          XMLRPC_SetValueString(value, val, len);
        !          1336:          if(id) {
        !          1337:             XMLRPC_SetValueID(value, id, 0);
        !          1338:          }
        !          1339:       }
        !          1340:    }
        !          1341:    return value;
        !          1342: }
        !          1343: 
        !          1344: /*******/
        !          1345: 
        !          1346: /****f* VALUE/XMLRPC_CreateValueInt
        !          1347:  * NAME
        !          1348:  *   XMLRPC_CreateValueInt
        !          1349:  * SYNOPSIS
        !          1350:  *   XMLRPC_VALUE XMLRPC_CreateValueInt(const char* id, int i)
        !          1351:  * FUNCTION
        !          1352:  *   Create an XMLRPC_VALUE, and assign an int to it
        !          1353:  * INPUTS
        !          1354:  *   id        The id of the value, or NULL
        !          1355:  *   i         The desired new int val.
        !          1356:  * RESULT
        !          1357:  *   newly allocated XMLRPC_VALUE, or NULL
        !          1358:  * SEE ALSO
        !          1359:  *   XMLRPC_GetValueInt ()
        !          1360:  *   XMLRPC_CreateValueEmpty ()
        !          1361:  *   XMLRPC_VALUE
        !          1362:  *   XMLRPC_VALUE_TYPE
        !          1363:  * SOURCE
        !          1364:  */
        !          1365: XMLRPC_VALUE XMLRPC_CreateValueInt(const char* id, int i) {
        !          1366:    XMLRPC_VALUE val = XMLRPC_CreateValueEmpty();
        !          1367:    if(val) {
        !          1368:       XMLRPC_SetValueInt(val, i);
        !          1369:       if(id) {
        !          1370:          XMLRPC_SetValueID(val, id, 0);
        !          1371:       }
        !          1372:    }
        !          1373:    return val;
        !          1374: }
        !          1375: 
        !          1376: /*******/
        !          1377: 
        !          1378: /****f* VALUE/XMLRPC_CreateValueBoolean
        !          1379:  * NAME
        !          1380:  *   XMLRPC_CreateValueBoolean
        !          1381:  * SYNOPSIS
        !          1382:  *   XMLRPC_VALUE XMLRPC_CreateValueBoolean(const char* id, int i)
        !          1383:  * FUNCTION
        !          1384:  *   Create an XMLRPC_VALUE, and assign an int to it
        !          1385:  * INPUTS
        !          1386:  *   id        The id of the value, or NULL
        !          1387:  *   i         The desired new int val.
        !          1388:  * RESULT
        !          1389:  *   newly allocated XMLRPC_VALUE, or NULL
        !          1390:  * SEE ALSO
        !          1391:  *   XMLRPC_GetValueBoolean ()
        !          1392:  *   XMLRPC_CreateValueEmpty ()
        !          1393:  *   XMLRPC_VALUE
        !          1394:  *   XMLRPC_VALUE_TYPE
        !          1395:  * SOURCE
        !          1396:  */
        !          1397: XMLRPC_VALUE XMLRPC_CreateValueBoolean(const char* id, int i) {
        !          1398:    XMLRPC_VALUE val = XMLRPC_CreateValueEmpty();
        !          1399:    if(val) {
        !          1400:       XMLRPC_SetValueBoolean(val, i);
        !          1401:       if(id) {
        !          1402:          XMLRPC_SetValueID(val, id, 0);
        !          1403:       }
        !          1404:    }
        !          1405:    return val;
        !          1406: }
        !          1407: 
        !          1408: /*******/
        !          1409: 
        !          1410: 
        !          1411: /****f* VALUE/XMLRPC_CleanupValue
        !          1412:  * NAME
        !          1413:  *   XMLRPC_CleanupValue
        !          1414:  * SYNOPSIS
        !          1415:  *   void XMLRPC_CleanupValue(XMLRPC_VALUE value)
        !          1416:  * FUNCTION
        !          1417:  *   Frees all memory allocated for an XMLRPC_VALUE and any of its children (if a vector)
        !          1418:  * INPUTS
        !          1419:  *   value     The id of the value to be cleaned up.
        !          1420:  * RESULT
        !          1421:  *   void
        !          1422:  * NOTES
        !          1423:  *   Normally this function will be called for the topmost vector, thus free-ing
        !          1424:  *   all children.  If a child of a vector is free'd first, results are undefined.
        !          1425:  *   Failure to call this function *will* cause memory leaks.
        !          1426:  *
        !          1427:  *   Also, this function is implemented using reference counting.  Thus a value
        !          1428:  *   may be added and freed from multiple parents so long as a reference is added
        !          1429:  *   first using XMLRPC_CopyValue()
        !          1430:  * SEE ALSO
        !          1431:  *   XMLRPC_RequestFree ()
        !          1432:  *   XMLRPC_CreateValueEmpty ()
        !          1433:  *   XMLRPC_CopyValue()
        !          1434:  *   XMLRPC_VALUE
        !          1435:  * SOURCE
        !          1436:  */
        !          1437: void XMLRPC_CleanupValue(XMLRPC_VALUE value) {
        !          1438:    if(value) {
        !          1439:       if(value->iRefCount > 0) {
        !          1440:          value->iRefCount --;
        !          1441:       }
        !          1442: 
        !          1443: #ifdef XMLRPC_DEBUG_REFCOUNT
        !          1444:       if(value->id.str) {
        !          1445:                        printf ("decremented refcount of %s, now %i\n", value->id.str,
        !          1446:                                          value->iRefCount);
        !          1447:       }
        !          1448:       else {
        !          1449:                        printf ("decremented refcount of 0x%x, now %i\n", value,
        !          1450:                                          value->iRefCount);
        !          1451:       }
        !          1452: #endif
        !          1453: 
        !          1454:       if(value->type == xmlrpc_vector) {
        !          1455:          if(value->v) {
        !          1456:             if(value->iRefCount == 0) {
        !          1457:                XMLRPC_VALUE cur = (XMLRPC_VALUE)Q_Head(value->v->q);
        !          1458:                while( cur ) {
        !          1459:                   XMLRPC_CleanupValue(cur);
        !          1460:    
        !          1461:                   /* Make sure some idiot didn't include a vector as a child of itself
        !          1462:                    * and thus it would have already free'd these.
        !          1463:                    */
        !          1464:                   if(value->v && value->v->q) {
        !          1465:                      cur = Q_Next(value->v->q);
        !          1466:                   }
        !          1467:                   else {
        !          1468:                      break;
        !          1469:                   }
        !          1470:                }
        !          1471: 
        !          1472:                Q_Destroy(value->v->q);
        !          1473:                my_free(value->v->q);
        !          1474:                my_free(value->v);
        !          1475:             }
        !          1476:          }
        !          1477:       }
        !          1478: 
        !          1479: 
        !          1480:       if(value->iRefCount == 0) {
        !          1481: 
        !          1482:          /* guard against freeing invalid types */
        !          1483:          switch(value->type) {
        !          1484:             case xmlrpc_empty:
        !          1485:             case xmlrpc_base64:
        !          1486:             case xmlrpc_boolean:
        !          1487:             case xmlrpc_datetime:
        !          1488:             case xmlrpc_double:
        !          1489:             case xmlrpc_int:
        !          1490:             case xmlrpc_string:
        !          1491:             case xmlrpc_vector:
        !          1492: #ifdef XMLRPC_DEBUG_REFCOUNT
        !          1493:                if(value->id.str) {
        !          1494:                   printf("free'd %s\n", value->id.str);
        !          1495:                }
        !          1496:                else {
        !          1497:                   printf("free'd 0x%x\n", value);
        !          1498:                }
        !          1499: #endif 
        !          1500:                simplestring_free(&value->id);
        !          1501:                simplestring_free(&value->str);
        !          1502: 
        !          1503:                memset(value, 0, sizeof(STRUCT_XMLRPC_VALUE));
        !          1504:                my_free(value);
        !          1505:                break;
        !          1506:             default:
        !          1507:                                /* fprintf (stderr,
        !          1508:                                                        "xmlrpc: attempted to free value of invalid type\n"); */
        !          1509:                break;
        !          1510:          }
        !          1511:       }
        !          1512:    }
        !          1513: }
        !          1514: 
        !          1515: /*******/
        !          1516: 
        !          1517: 
        !          1518: /****f* VALUE/XMLRPC_SetValueDateTime
        !          1519:  * NAME
        !          1520:  *   XMLRPC_SetValueDateTime
        !          1521:  * SYNOPSIS
        !          1522:  *   void XMLRPC_SetValueDateTime(XMLRPC_VALUE value, time_t time)
        !          1523:  * FUNCTION
        !          1524:  *   Assign time value to XMLRPC_VALUE
        !          1525:  * INPUTS
        !          1526:  *   value     The target XMLRPC_VALUE
        !          1527:  *   time      The desired new unix time value (time_t)
        !          1528:  * RESULT
        !          1529:  *   void
        !          1530:  * SEE ALSO
        !          1531:  *   XMLRPC_GetValueDateTime ()
        !          1532:  *   XMLRPC_SetValueDateTime_ISO8601 ()
        !          1533:  *   XMLRPC_CreateValueDateTime ()
        !          1534:  *   XMLRPC_VALUE
        !          1535:  * SOURCE
        !          1536:  */
        !          1537: void XMLRPC_SetValueDateTime(XMLRPC_VALUE value, time_t time) {
        !          1538:    if(value) {
        !          1539:       char timeBuf[30];
        !          1540:       value->type = xmlrpc_datetime;
        !          1541:       value->i = time;
        !          1542: 
        !          1543:       timeBuf[0] = 0;
        !          1544: 
        !          1545:       date_to_ISO8601(time, timeBuf, sizeof(timeBuf));
        !          1546: 
        !          1547:       if(timeBuf[0]) {
        !          1548:          XMLRPC_SetValueDateTime_ISO8601 (value, timeBuf);
        !          1549:       }
        !          1550:    }
        !          1551: }
        !          1552: 
        !          1553: /*******/
        !          1554: 
        !          1555: /****f* VALUE/XMLRPC_CopyValue
        !          1556:  * NAME
        !          1557:  *   XMLRPC_CopyValue
        !          1558:  * SYNOPSIS
        !          1559:  *   XMLRPC_VALUE XMLRPC_CopyValue(XMLRPC_VALUE value)
        !          1560:  * FUNCTION
        !          1561:  *   Make a copy (reference) of an XMLRPC_VALUE
        !          1562:  * INPUTS
        !          1563:  *   value     The target XMLRPC_VALUE
        !          1564:  * RESULT
        !          1565:  *   XMLRPC_VALUE -- address of the copy
        !          1566:  * SEE ALSO
        !          1567:  *   XMLRPC_CleanupValue ()
        !          1568:  *   XMLRPC_DupValueNew ()
        !          1569:  * NOTES
        !          1570:  *   This function is implemented via reference counting, so the
        !          1571:  *   returned value is going to be the same as the passed in value.
        !          1572:  *   The value must be freed the same number of times it is copied
        !          1573:  *   or there will be a memory leak.
        !          1574:  * SOURCE
        !          1575:  */
        !          1576: XMLRPC_VALUE XMLRPC_CopyValue(XMLRPC_VALUE value) {
        !          1577:    if(value) {
        !          1578:       value->iRefCount ++;
        !          1579: #ifdef XMLRPC_DEBUG_REFCOUNT
        !          1580:       if(value->id.str) {
        !          1581:                        printf ("incremented refcount of %s, now %i\n", value->id.str,
        !          1582:                                          value->iRefCount);
        !          1583:                }
        !          1584:                else {
        !          1585:                        printf ("incremented refcount of 0x%x, now %i\n", value,
        !          1586:                                          value->iRefCount);
        !          1587:       }
        !          1588: #endif
        !          1589:    }
        !          1590:    return value;
        !          1591: }
        !          1592: 
        !          1593: /*******/
        !          1594: 
        !          1595: 
        !          1596: /****f* VALUE/XMLRPC_DupValueNew
        !          1597:  * NAME
        !          1598:  *   XMLRPC_DupValueNew
        !          1599:  * SYNOPSIS
        !          1600:  *   XMLRPC_VALUE XMLRPC_DupValueNew(XMLRPC_VALUE value)
        !          1601:  * FUNCTION
        !          1602:  *   Make a duplicate (non reference) of an XMLRPC_VALUE with newly allocated mem.
        !          1603:  * INPUTS
        !          1604:  *   value     The source XMLRPC_VALUE to duplicate
        !          1605:  * RESULT
        !          1606:  *   XMLRPC_VALUE -- address of the duplicate value
        !          1607:  * SEE ALSO
        !          1608:  *   XMLRPC_CleanupValue ()
        !          1609:  *   XMLRPC_CopyValue ()
        !          1610:  * NOTES
        !          1611:  *   Use this when function when you need to modify the contents of
        !          1612:  *   the copied value seperately from the original.
        !          1613:  *   
        !          1614:  *   this function is recursive, thus the value and all of its children
        !          1615:  *   (if any) will be duplicated.
        !          1616:  * SOURCE
        !          1617:  */
        !          1618: XMLRPC_VALUE XMLRPC_DupValueNew (XMLRPC_VALUE xSource) {
        !          1619:        XMLRPC_VALUE xReturn = NULL;
        !          1620:        if (xSource) {
        !          1621:                xReturn = XMLRPC_CreateValueEmpty ();
        !          1622:                if (xSource->id.len) {
        !          1623:                        XMLRPC_SetValueID (xReturn, xSource->id.str, xSource->id.len);
        !          1624:                }
        !          1625: 
        !          1626:                switch (xSource->type) {
        !          1627:                case xmlrpc_int:
        !          1628:                case xmlrpc_boolean:
        !          1629:                        XMLRPC_SetValueInt (xReturn, xSource->i);
        !          1630:                        break;
        !          1631:                case xmlrpc_string:
        !          1632:                case xmlrpc_base64:
        !          1633:                        XMLRPC_SetValueString (xReturn, xSource->str.str, xSource->str.len);
        !          1634:                        break;
        !          1635:                case xmlrpc_datetime:
        !          1636:                        XMLRPC_SetValueDateTime (xReturn, xSource->i);
        !          1637:                        break;
        !          1638:                case xmlrpc_double:
        !          1639:                        XMLRPC_SetValueDouble (xReturn, xSource->d);
        !          1640:                        break;
        !          1641:                case xmlrpc_vector:
        !          1642:                        {
        !          1643:                                q_iter qi = Q_Iter_Head_F (xSource->v->q);
        !          1644:                                XMLRPC_SetIsVector (xReturn, xSource->v->type);
        !          1645: 
        !          1646:                                while (qi) {
        !          1647:                                        XMLRPC_VALUE xIter = Q_Iter_Get_F (qi);
        !          1648:                                        XMLRPC_AddValueToVector (xReturn, XMLRPC_DupValueNew (xIter));
        !          1649:                                        qi = Q_Iter_Next_F (qi);
        !          1650:                                }
        !          1651:                        }
        !          1652:                        break;
        !          1653:                default:
        !          1654:                        break;
        !          1655:                }
        !          1656:        }
        !          1657:        return xReturn;
        !          1658: }
        !          1659: 
        !          1660: /*******/
        !          1661: 
        !          1662: 
        !          1663: 
        !          1664: /****f* VALUE/XMLRPC_CreateValueDateTime
        !          1665:  * NAME
        !          1666:  *   XMLRPC_CreateValueDateTime
        !          1667:  * SYNOPSIS
        !          1668:  *   XMLRPC_VALUE XMLRPC_CreateValueDateTime(const char* id, time_t time)
        !          1669:  * FUNCTION
        !          1670:  *   Create new datetime value from time_t
        !          1671:  * INPUTS
        !          1672:  *   id        id of the new value, or NULL
        !          1673:  *   time      The desired unix time value (time_t)
        !          1674:  * RESULT
        !          1675:  *   void
        !          1676:  * SEE ALSO
        !          1677:  *   XMLRPC_GetValueDateTime ()
        !          1678:  *   XMLRPC_SetValueDateTime ()
        !          1679:  *   XMLRPC_CreateValueDateTime_ISO8601 ()
        !          1680:  *   XMLRPC_VALUE
        !          1681:  * SOURCE
        !          1682:  */
        !          1683: XMLRPC_VALUE XMLRPC_CreateValueDateTime(const char* id, time_t time) {
        !          1684:    XMLRPC_VALUE val = XMLRPC_CreateValueEmpty();
        !          1685:    if(val) {
        !          1686:       XMLRPC_SetValueDateTime(val, time);
        !          1687:       if(id) {
        !          1688:          XMLRPC_SetValueID(val, id, 0);
        !          1689:       }
        !          1690:    }
        !          1691:    return val;
        !          1692: }
        !          1693: 
        !          1694: /*******/
        !          1695: 
        !          1696: 
        !          1697: /****f* VALUE/XMLRPC_SetValueDateTime_ISO8601
        !          1698:  * NAME
        !          1699:  *   XMLRPC_SetValueDateTime_ISO8601
        !          1700:  * SYNOPSIS
        !          1701:  *   void XMLRPC_SetValueDateTime_ISO8601(XMLRPC_VALUE value, const char* s)
        !          1702:  * FUNCTION
        !          1703:  *   Set datetime value from IS08601 encoded string
        !          1704:  * INPUTS
        !          1705:  *   value     The target XMLRPC_VALUE
        !          1706:  *   s         The desired new time value
        !          1707:  * RESULT
        !          1708:  *   void                                
        !          1709:  * BUGS
        !          1710:  *   This function currently attempts to convert the time string to a valid unix time
        !          1711:  *   value before passing it. Behavior when the string is invalid or out of range
        !          1712:  *   is not well defined, but will probably result in Jan 1, 1970 (0) being passed.
        !          1713:  * SEE ALSO
        !          1714:  *   XMLRPC_GetValueDateTime_ISO8601 ()
        !          1715:  *   XMLRPC_CreateValueDateTime_ISO8601 ()
        !          1716:  *   XMLRPC_CreateValueDateTime ()
        !          1717:  *   XMLRPC_VALUE
        !          1718:  * SOURCE
        !          1719:  */
        !          1720: void XMLRPC_SetValueDateTime_ISO8601(XMLRPC_VALUE value, const char* s) {
        !          1721:    if(value) {
        !          1722:       time_t time_val = 0;
        !          1723:       if(s) {
        !          1724:          value->type = xmlrpc_datetime;
        !          1725:          date_from_ISO8601(s, &time_val);
        !          1726:          value->i = time_val;
        !          1727:          simplestring_clear(&value->str);
        !          1728:          simplestring_add(&value->str, s);
        !          1729:       }
        !          1730:    }
        !          1731: }
        !          1732: 
        !          1733: /*******/
        !          1734: 
        !          1735: /****f* VALUE/XMLRPC_CreateValueDateTime_ISO8601
        !          1736:  * NAME
        !          1737:  *   XMLRPC_CreateValueDateTime_ISO8601
        !          1738:  * SYNOPSIS
        !          1739:  *   XMLRPC_VALUE XMLRPC_CreateValueDateTime_ISO8601(const char* id, const char *s)
        !          1740:  * FUNCTION
        !          1741:  *   Create datetime value from IS08601 encoded string
        !          1742:  * INPUTS
        !          1743:  *   id        The id of the new value, or NULL
        !          1744:  *   s         The desired new time value
        !          1745:  * RESULT
        !          1746:  *   newly allocated XMLRPC_VALUE, or NULL if no value created.                                
        !          1747:  * BUGS
        !          1748:  *   See XMLRPC_SetValueDateTime_ISO8601 ()
        !          1749:  * SEE ALSO
        !          1750:  *   XMLRPC_GetValueDateTime_ISO8601 ()
        !          1751:  *   XMLRPC_SetValueDateTime_ISO8601 ()
        !          1752:  *   XMLRPC_CreateValueDateTime ()
        !          1753:  *   XMLRPC_VALUE
        !          1754:  * SOURCE
        !          1755:  */
        !          1756: XMLRPC_VALUE XMLRPC_CreateValueDateTime_ISO8601(const char* id, const char *s) {
        !          1757:    XMLRPC_VALUE val = XMLRPC_CreateValueEmpty();
        !          1758:    if(val) {
        !          1759:       XMLRPC_SetValueDateTime_ISO8601(val, s);
        !          1760:       if(id) {
        !          1761:          XMLRPC_SetValueID(val, id, 0);
        !          1762:       }
        !          1763:    }
        !          1764:    return val;
        !          1765: }
        !          1766: 
        !          1767: /*******/
        !          1768: 
        !          1769: 
        !          1770: /****f* VALUE/XMLRPC_SetValueBase64
        !          1771:  * NAME
        !          1772:  *   XMLRPC_SetValueBase64
        !          1773:  * SYNOPSIS
        !          1774:  *   void XMLRPC_SetValueBase64(XMLRPC_VALUE value, const char* s, int len)
        !          1775:  * FUNCTION
        !          1776:  *   Set base64 value.  Base64 is useful for transferring binary data, such as an image.
        !          1777:  * INPUTS
        !          1778:  *   value     The target XMLRPC_VALUE
        !          1779:  *   s         The desired new binary value
        !          1780:  *   len       The length of s, or NULL. If buffer is not null terminated, len *must* be passed.
        !          1781:  * RESULT
        !          1782:  *   void                                
        !          1783:  * NOTES
        !          1784:  *   Data is set/stored/retrieved as passed in, but is base64 encoded for XML transfer, and
        !          1785:  *   decoded on the other side.  This is transparent to the caller.
        !          1786:  * SEE ALSO
        !          1787:  *   XMLRPC_GetValueBase64 ()
        !          1788:  *   XMLRPC_CreateValueBase64 ()
        !          1789:  *   XMLRPC_VALUE
        !          1790:  * SOURCE
        !          1791:  */
        !          1792: void XMLRPC_SetValueBase64(XMLRPC_VALUE value, const char* s, int len) {
        !          1793:    if(value && s) {
        !          1794:       simplestring_clear(&value->str);
        !          1795:       (len > 0) ? simplestring_addn(&value->str, s, len) :
        !          1796:                   simplestring_add(&value->str, s);
        !          1797:       value->type = xmlrpc_base64;
        !          1798:    }
        !          1799: }
        !          1800: 
        !          1801: /*******/
        !          1802: 
        !          1803: 
        !          1804: /****f* VALUE/XMLRPC_CreateValueBase64
        !          1805:  * NAME
        !          1806:  *   XMLRPC_CreateValueBase64
        !          1807:  * SYNOPSIS
        !          1808:  *   XMLRPC_VALUE XMLRPC_CreateValueBase64(const char* id, const char* s, int len)
        !          1809:  * FUNCTION
        !          1810:  *   Create base64 value.  Base64 is useful for transferring binary data, such as an image.
        !          1811:  * INPUTS
        !          1812:  *   id        id of the new value, or NULL
        !          1813:  *   s         The desired new binary value
        !          1814:  *   len       The length of s, or NULL. If buffer is not null terminated, len *must* be passed.
        !          1815:  * RESULT
        !          1816:  *   newly allocated XMLRPC_VALUE, or NULL if error
        !          1817:  * NOTES
        !          1818:  *   See XMLRPC_SetValueBase64 ()
        !          1819:  * SEE ALSO
        !          1820:  *   XMLRPC_GetValueBase64 ()
        !          1821:  *   XMLRPC_SetValueBase64 ()
        !          1822:  *   XMLRPC_VALUE
        !          1823:  * SOURCE
        !          1824:  */
        !          1825: XMLRPC_VALUE XMLRPC_CreateValueBase64(const char* id, const char* s, int len) {
        !          1826:    XMLRPC_VALUE val = XMLRPC_CreateValueEmpty();
        !          1827:    if(val) {
        !          1828:       XMLRPC_SetValueBase64(val, s, len);
        !          1829:       if(id) {
        !          1830:          XMLRPC_SetValueID(val, id, 0);
        !          1831:       }
        !          1832:    }
        !          1833:    return val;
        !          1834: }
        !          1835: 
        !          1836: /*******/
        !          1837: 
        !          1838: /****f* VALUE/XMLRPC_SetValueDouble
        !          1839:  * NAME
        !          1840:  *   XMLRPC_SetValueDouble
        !          1841:  * SYNOPSIS
        !          1842:  *   void XMLRPC_SetValueDouble(XMLRPC_VALUE value, double val)
        !          1843:  * FUNCTION
        !          1844:  *   Set double (floating point) value.
        !          1845:  * INPUTS
        !          1846:  *   value     The target XMLRPC_VALUE
        !          1847:  *   val       The desired new double value
        !          1848:  * RESULT
        !          1849:  *   void                                
        !          1850:  * SEE ALSO
        !          1851:  *   XMLRPC_GetValueDouble ()
        !          1852:  *   XMLRPC_CreateValueDouble ()
        !          1853:  *   XMLRPC_VALUE
        !          1854:  * SOURCE
        !          1855:  */
        !          1856: void XMLRPC_SetValueDouble(XMLRPC_VALUE value, double val) {
        !          1857:    if(value) {
        !          1858:       value->type = xmlrpc_double;
        !          1859:       value->d = val;
        !          1860:    }
        !          1861: }
        !          1862: 
        !          1863: /*******/
        !          1864: 
        !          1865: /****f* VALUE/XMLRPC_CreateValueDouble
        !          1866:  * NAME
        !          1867:  *   XMLRPC_CreateValueDouble
        !          1868:  * SYNOPSIS
        !          1869:  *   XMLRPC_VALUE XMLRPC_CreateValueDouble(const char* id, double d)
        !          1870:  * FUNCTION
        !          1871:  *   Create double (floating point) value.
        !          1872:  * INPUTS
        !          1873:  *   id        id of the newly created value, or NULL
        !          1874:  *   d         The desired new double value
        !          1875:  * RESULT
        !          1876:  *   void                                
        !          1877:  * SEE ALSO
        !          1878:  *   XMLRPC_GetValueDouble ()
        !          1879:  *   XMLRPC_CreateValueDouble ()
        !          1880:  *   XMLRPC_VALUE
        !          1881:  * SOURCE
        !          1882:  */
        !          1883: XMLRPC_VALUE XMLRPC_CreateValueDouble(const char* id, double d) {
        !          1884:    XMLRPC_VALUE val = XMLRPC_CreateValueEmpty();
        !          1885:    if(val) {
        !          1886:       XMLRPC_SetValueDouble(val, d);
        !          1887:       if(id) {
        !          1888:          XMLRPC_SetValueID(val, id, 0);
        !          1889:       }
        !          1890:    }
        !          1891:    return val;
        !          1892: }
        !          1893: 
        !          1894: /*******/
        !          1895: 
        !          1896: /****f* VALUE/XMLRPC_GetValueString
        !          1897:  * NAME
        !          1898:  *   XMLRPC_GetValueString
        !          1899:  * SYNOPSIS
        !          1900:  *   const char* XMLRPC_GetValueString(XMLRPC_VALUE value)
        !          1901:  * FUNCTION
        !          1902:  *   retrieve string value
        !          1903:  * INPUTS
        !          1904:  *   value     source XMLRPC_VALUE of type xmlrpc_string
        !          1905:  * RESULT
        !          1906:  *   void                                
        !          1907:  * SEE ALSO
        !          1908:  *   XMLRPC_SetValueString ()
        !          1909:  *   XMLRPC_GetValueType ()
        !          1910:  *   XMLRPC_VALUE
        !          1911:  * SOURCE
        !          1912:  */
        !          1913: const char* XMLRPC_GetValueString(XMLRPC_VALUE value) {
        !          1914:     return ((value && value->type == xmlrpc_string) ? value->str.str : 0);
        !          1915: }
        !          1916: 
        !          1917: /*******/
        !          1918: 
        !          1919: /****f* VALUE/XMLRPC_GetValueStringLen
        !          1920:  * NAME
        !          1921:  *   XMLRPC_GetValueStringLen
        !          1922:  * SYNOPSIS
        !          1923:  *   int XMLRPC_GetValueStringLen(XMLRPC_VALUE value)
        !          1924:  * FUNCTION
        !          1925:  *   determine length of string value
        !          1926:  * INPUTS
        !          1927:  *   value     XMLRPC_VALUE of type xmlrpc_string 
        !          1928:  * RESULT
        !          1929:  *   length of string, or 0
        !          1930:  * NOTES
        !          1931:  * SEE ALSO
        !          1932:  *   XMLRPC_SetValueString ()
        !          1933:  *   XMLRPC_GetValueString ()
        !          1934:  * SOURCE
        !          1935:  */
        !          1936: int XMLRPC_GetValueStringLen(XMLRPC_VALUE value) {
        !          1937:     return ((value) ? value->str.len : 0);
        !          1938: }
        !          1939: 
        !          1940: /*******/
        !          1941: 
        !          1942: /****f* VALUE/XMLRPC_GetValueInt
        !          1943:  * NAME
        !          1944:  *   XMLRPC_GetValueInt
        !          1945:  * SYNOPSIS
        !          1946:  *   int XMLRPC_GetValueInt(XMLRPC_VALUE value)
        !          1947:  * FUNCTION
        !          1948:  *   retrieve integer value.
        !          1949:  * INPUTS
        !          1950:  *   value     XMLRPC_VALUE of type xmlrpc_int 
        !          1951:  * RESULT
        !          1952:  *   integer value or 0 if value is not valid int
        !          1953:  * NOTES
        !          1954:  *   use XMLRPC_GetValueType () to be sure if 0 is real return value or not
        !          1955:  * SEE ALSO
        !          1956:  *   XMLRPC_SetValueInt ()
        !          1957:  *   XMLRPC_CreateValueInt ()
        !          1958:  * SOURCE
        !          1959:  */
        !          1960: int XMLRPC_GetValueInt(XMLRPC_VALUE value) {
        !          1961:     return ((value && value->type == xmlrpc_int) ? value->i : 0);
        !          1962: }
        !          1963: 
        !          1964: /*******/
        !          1965: 
        !          1966: /****f* VALUE/XMLRPC_GetValueBoolean
        !          1967:  * NAME
        !          1968:  *   XMLRPC_GetValueBoolean
        !          1969:  * SYNOPSIS
        !          1970:  *   int XMLRPC_GetValueBoolean(XMLRPC_VALUE value)
        !          1971:  * FUNCTION
        !          1972:  *   retrieve boolean value.
        !          1973:  * INPUTS
        !          1974:  *   XMLRPC_VALUE of type xmlrpc_boolean
        !          1975:  * RESULT
        !          1976:  *   boolean value or 0 if value is not valid boolean
        !          1977:  * NOTES
        !          1978:  *   use XMLRPC_GetValueType() to be sure if 0 is real value or not
        !          1979:  * SEE ALSO
        !          1980:  *   XMLRPC_SetValueBoolean ()
        !          1981:  *   XMLRPC_CreateValueBoolean ()
        !          1982:  * SOURCE
        !          1983:  */
        !          1984: int XMLRPC_GetValueBoolean(XMLRPC_VALUE value) {
        !          1985:     return ((value && value->type == xmlrpc_boolean) ? value->i : 0);
        !          1986: }
        !          1987: 
        !          1988: /*******/
        !          1989: 
        !          1990: /****f* VALUE/XMLRPC_GetValueDouble
        !          1991:  * NAME
        !          1992:  *   XMLRPC_GetValueDouble
        !          1993:  * SYNOPSIS
        !          1994:  *   double XMLRPC_GetValueDouble(XMLRPC_VALUE value)
        !          1995:  * FUNCTION
        !          1996:  *   retrieve double value
        !          1997:  * INPUTS
        !          1998:  *   XMLRPC_VALUE of type xmlrpc_double
        !          1999:  * RESULT
        !          2000:  *   double value or 0 if value is not valid double.
        !          2001:  * NOTES
        !          2002:  *   use XMLRPC_GetValueType() to be sure if 0 is real value or not
        !          2003:  * SEE ALSO
        !          2004:  *   XMLRPC_SetValueDouble ()
        !          2005:  *   XMLRPC_CreateValueDouble ()
        !          2006:  * SOURCE
        !          2007:  */
        !          2008: double XMLRPC_GetValueDouble(XMLRPC_VALUE value) {
        !          2009:     return ((value && value->type == xmlrpc_double) ? value->d : 0);
        !          2010: }
        !          2011: 
        !          2012: /*******/
        !          2013: 
        !          2014: /****f* VALUE/XMLRPC_GetValueBase64
        !          2015:  * NAME
        !          2016:  *   XMLRPC_GetValueBase64
        !          2017:  * SYNOPSIS
        !          2018:  *   const char* XMLRPC_GetValueBase64(XMLRPC_VALUE value)
        !          2019:  * FUNCTION
        !          2020:  *   retrieve binary value
        !          2021:  * INPUTS
        !          2022:  *   XMLRPC_VALUE of type xmlrpc_base64
        !          2023:  * RESULT
        !          2024:  *   pointer to binary value or 0 if value is not valid.
        !          2025:  * SEE ALSO
        !          2026:  *   XMLRPC_SetValueBase64 ()
        !          2027:  *   XMLRPC_CreateValueBase64 ()
        !          2028:  * NOTES
        !          2029:  *   Call XMLRPC_GetValueStringLen() to retrieve real length of binary data.  strlen()
        !          2030:  *   will not be accurate, as returned data may contain embedded nulls.
        !          2031:  * SOURCE
        !          2032:  */
        !          2033: const char* XMLRPC_GetValueBase64(XMLRPC_VALUE value) {
        !          2034:     return ((value && value->type == xmlrpc_base64) ? value->str.str : 0);
        !          2035: }
        !          2036: 
        !          2037: /*******/
        !          2038: 
        !          2039: /****f* VALUE/XMLRPC_GetValueDateTime
        !          2040:  * NAME
        !          2041:  *   XMLRPC_GetValueDateTime
        !          2042:  * SYNOPSIS
        !          2043:  *   time_t XMLRPC_GetValueDateTime(XMLRPC_VALUE value)
        !          2044:  * FUNCTION
        !          2045:  *   retrieve time_t value
        !          2046:  * INPUTS
        !          2047:  *   XMLRPC_VALUE of type xmlrpc_datetime
        !          2048:  * RESULT
        !          2049:  *   time_t value or 0 if value is not valid datetime.
        !          2050:  * NOTES
        !          2051:  *   use XMLRPC_GetValueType() to be sure if 0 is real value or not
        !          2052:  * SEE ALSO
        !          2053:  *   XMLRPC_SetValueDateTime ()
        !          2054:  *   XMLRPC_GetValueDateTime_ISO8601 ()
        !          2055:  *   XMLRPC_CreateValueDateTime ()
        !          2056:  * SOURCE
        !          2057:  */
        !          2058: time_t XMLRPC_GetValueDateTime(XMLRPC_VALUE value) {
        !          2059:     return (time_t)((value && value->type == xmlrpc_datetime) ? value->i : 0);
        !          2060: }
        !          2061: 
        !          2062: /*******/
        !          2063: 
        !          2064: /****f* VALUE/XMLRPC_GetValueDateTime_IOS8601
        !          2065:  * NAME
        !          2066:  *   XMLRPC_GetValueDateTime_IOS8601
        !          2067:  * SYNOPSIS
        !          2068:  *   const char* XMLRPC_GetValueDateTime_IOS8601(XMLRPC_VALUE value)
        !          2069:  * FUNCTION
        !          2070:  *   retrieve ISO8601 formatted time value
        !          2071:  * INPUTS
        !          2072:  *   XMLRPC_VALUE of type xmlrpc_datetime
        !          2073:  * RESULT
        !          2074:  *   const char* value or 0 if value is not valid datetime.
        !          2075:  * SEE ALSO
        !          2076:  *   XMLRPC_SetValueDateTime_IOS8601 ()
        !          2077:  *   XMLRPC_GetValueDateTime ()
        !          2078:  *   XMLRPC_CreateValueDateTime_IOS8601 ()
        !          2079:  * SOURCE
        !          2080:  */
        !          2081: const char* XMLRPC_GetValueDateTime_ISO8601(XMLRPC_VALUE value) {
        !          2082:     return ((value && value->type == xmlrpc_datetime) ? value->str.str : 0);
        !          2083: }
        !          2084: 
        !          2085: /*******/
        !          2086: 
        !          2087: /* Get ID (key) of value or NULL */
        !          2088: /****f* VALUE/XMLRPC_GetValueID
        !          2089:  * NAME
        !          2090:  *   XMLRPC_GetValueID
        !          2091:  * SYNOPSIS
        !          2092:  *   const char* XMLRPC_GetValueID(XMLRPC_VALUE value)
        !          2093:  * FUNCTION
        !          2094:  *   retrieve id (key) of value
        !          2095:  * INPUTS
        !          2096:  *   XMLRPC_VALUE of any type
        !          2097:  * RESULT
        !          2098:  *   const char* pointer to id of value, or NULL
        !          2099:  * NOTES
        !          2100:  * SEE ALSO
        !          2101:  *   XMLRPC_SetValueID()
        !          2102:  *   XMLRPC_CreateValueEmpty()
        !          2103:  * SOURCE
        !          2104:  */
        !          2105: const char* XMLRPC_GetValueID(XMLRPC_VALUE value) {
        !          2106:     return (const char*)((value && value->id.len) ? value->id.str : 0);
        !          2107: }
        !          2108: 
        !          2109: /*******/
        !          2110: 
        !          2111: 
        !          2112: /****f* VECTOR/XMLRPC_VectorSize
        !          2113:  * NAME
        !          2114:  *   XMLRPC_VectorSize
        !          2115:  * SYNOPSIS
        !          2116:  *   int XMLRPC_VectorSize(XMLRPC_VALUE value)
        !          2117:  * FUNCTION
        !          2118:  *   retrieve size of vector
        !          2119:  * INPUTS
        !          2120:  *   XMLRPC_VALUE of type xmlrpc_vector
        !          2121:  * RESULT
        !          2122:  *   count of items in vector
        !          2123:  * NOTES
        !          2124:  *   This is a cheap operation even on large vectors.  Vector size is 
        !          2125:  *   maintained by queue during add/remove ops.
        !          2126:  * SEE ALSO
        !          2127:  *   XMLRPC_AddValueToVector ()
        !          2128:  * SOURCE
        !          2129:  */
        !          2130: int XMLRPC_VectorSize(XMLRPC_VALUE value) {
        !          2131:    int size = 0;
        !          2132:    if(value && value->type == xmlrpc_vector && value->v) {
        !          2133:       size = Q_Size(value->v->q);
        !          2134:    }
        !          2135:    return size;
        !          2136: }
        !          2137: 
        !          2138: /*******/
        !          2139: 
        !          2140: /****f* VECTOR/XMLRPC_VectorRewind
        !          2141:  * NAME
        !          2142:  *   XMLRPC_VectorRewind
        !          2143:  * SYNOPSIS
        !          2144:  *   XMLRPC_VALUE XMLRPC_VectorRewind(XMLRPC_VALUE value)
        !          2145:  * FUNCTION
        !          2146:  *   reset vector to first item
        !          2147:  * INPUTS
        !          2148:  *   XMLRPC_VALUE of type xmlrpc_vector
        !          2149:  * RESULT
        !          2150:  *   first XMLRPC_VALUE in list, or NULL if empty or error.
        !          2151:  * NOTES
        !          2152:  *   Be careful to rewind any vector passed in to you if you expect to
        !          2153:  *   iterate through the entire list.
        !          2154:  * SEE ALSO
        !          2155:  *   XMLRPC_VectorNext ()
        !          2156:  * SOURCE
        !          2157:  */
        !          2158: XMLRPC_VALUE XMLRPC_VectorRewind(XMLRPC_VALUE value) {
        !          2159:    XMLRPC_VALUE xReturn = NULL;
        !          2160:    if(value && value->type == xmlrpc_vector && value->v) {
        !          2161:       xReturn = (XMLRPC_VALUE)Q_Head(value->v->q);
        !          2162:    }
        !          2163:    return xReturn;
        !          2164: }
        !          2165: 
        !          2166: /*******/
        !          2167: 
        !          2168: /****f* VECTOR/XMLRPC_VectorNext
        !          2169:  * NAME
        !          2170:  *   XMLRPC_VectorNext
        !          2171:  * SYNOPSIS
        !          2172:  *   XMLRPC_VALUE XMLRPC_VectorNext(XMLRPC_VALUE value)
        !          2173:  * FUNCTION
        !          2174:  *   Iterate vector to next item in list.
        !          2175:  * INPUTS
        !          2176:  *   XMLRPC_VALUE of type xmlrpc_vector
        !          2177:  * RESULT
        !          2178:  *   Next XMLRPC_VALUE in vector, or NULL if at end.
        !          2179:  * NOTES
        !          2180:  * SEE ALSO
        !          2181:  *   XMLRPC_VectorRewind ()
        !          2182:  * SOURCE
        !          2183:  */
        !          2184: XMLRPC_VALUE XMLRPC_VectorNext(XMLRPC_VALUE value) {
        !          2185:    XMLRPC_VALUE xReturn = NULL;
        !          2186:    if(value && value->type == xmlrpc_vector && value->v) {
        !          2187:       xReturn = (XMLRPC_VALUE)Q_Next(value->v->q);
        !          2188:    }
        !          2189:    return xReturn;
        !          2190: }
        !          2191: 
        !          2192: /*******/
        !          2193: 
        !          2194: /****f* VALUE/XMLRPC_GetValueType
        !          2195:  * NAME
        !          2196:  *   XMLRPC_GetValueType
        !          2197:  * SYNOPSIS
        !          2198:  *   XMLRPC_VALUE_TYPE XMLRPC_GetValueType(XMLRPC_VALUE value)
        !          2199:  * FUNCTION
        !          2200:  *   determine data type of the XMLRPC_VALUE
        !          2201:  * INPUTS
        !          2202:  *   XMLRPC_VALUE target of query
        !          2203:  * RESULT
        !          2204:  *   data type of value as enumerated by XMLRPC_VALUE_TYPE
        !          2205:  * NOTES
        !          2206:  *   all values are of type xmlrpc_empty until set.
        !          2207:  *   Deprecated for public use.  See XMLRPC_GetValueTypeEasy
        !          2208:  * SEE ALSO
        !          2209:  *   XMLRPC_SetValue*
        !          2210:  *   XMLRPC_CreateValue*
        !          2211:  *   XMLRPC_Append*
        !          2212:  *   XMLRPC_GetValueTypeEasy ()
        !          2213:  * SOURCE
        !          2214:  */
        !          2215: XMLRPC_VALUE_TYPE XMLRPC_GetValueType(XMLRPC_VALUE value) {
        !          2216:    return value ? value->type : xmlrpc_empty;
        !          2217: }
        !          2218: 
        !          2219: /*******/
        !          2220: 
        !          2221: /* Vector type accessor */
        !          2222: /****f* VALUE/XMLRPC_GetVectorType
        !          2223:  * NAME
        !          2224:  *   XMLRPC_GetVectorType
        !          2225:  * SYNOPSIS
        !          2226:  *   XMLRPC_VECTOR_TYPE XMLRPC_GetVectorType(XMLRPC_VALUE value)
        !          2227:  * FUNCTION
        !          2228:  *   determine vector type of the XMLRPC_VALUE
        !          2229:  * INPUTS
        !          2230:  *   XMLRPC_VALUE of type xmlrpc_vector
        !          2231:  * RESULT
        !          2232:  *   vector type of value as enumerated by XMLRPC_VECTOR_TYPE.
        !          2233:  *   xmlrpc_none if not a value.
        !          2234:  * NOTES
        !          2235:  *   xmlrpc_none is returned if value is not a vector
        !          2236:  *   Deprecated for public use.  See XMLRPC_GetValueTypeEasy
        !          2237:  * SEE ALSO
        !          2238:  *   XMLRPC_SetIsVector ()
        !          2239:  *   XMLRPC_GetValueType ()
        !          2240:  *   XMLRPC_GetValueTypeEasy ()
        !          2241:  * SOURCE
        !          2242:  */
        !          2243: XMLRPC_VECTOR_TYPE XMLRPC_GetVectorType(XMLRPC_VALUE value) {
        !          2244:    return(value && value->v) ? value->v->type : xmlrpc_none;
        !          2245: }
        !          2246: 
        !          2247: /*******/
        !          2248: 
        !          2249: /****f* VALUE/XMLRPC_GetValueTypeEasy
        !          2250:  * NAME
        !          2251:  *   XMLRPC_GetValueTypeEasy
        !          2252:  * SYNOPSIS
        !          2253:  *   XMLRPC_VALUE_TYPE_EASY XMLRPC_GetValueTypeEasy(XMLRPC_VALUE value)
        !          2254:  * FUNCTION
        !          2255:  *   determine data type of the XMLRPC_VALUE. includes vector types.
        !          2256:  * INPUTS
        !          2257:  *   XMLRPC_VALUE target of query
        !          2258:  * RESULT
        !          2259:  *   data type of value as enumerated by XMLRPC_VALUE_TYPE_EASY
        !          2260:  *   xmlrpc_type_none if not a value.
        !          2261:  * NOTES
        !          2262:  *   all values are of type xmlrpc_type_empty until set. 
        !          2263:  * SEE ALSO
        !          2264:  *   XMLRPC_SetValue*
        !          2265:  *   XMLRPC_CreateValue*
        !          2266:  *   XMLRPC_Append*
        !          2267:  * SOURCE
        !          2268:  */
        !          2269: XMLRPC_VALUE_TYPE_EASY XMLRPC_GetValueTypeEasy (XMLRPC_VALUE value) {
        !          2270:        if (value) {
        !          2271:                switch (value->type) {
        !          2272:                case xmlrpc_vector:
        !          2273:                        switch (value->v->type) {
        !          2274:                        case xmlrpc_vector_none:
        !          2275:                                return xmlrpc_type_none;
        !          2276:                        case xmlrpc_vector_struct:
        !          2277:                                return xmlrpc_type_struct;
        !          2278:                        case xmlrpc_vector_mixed:
        !          2279:                                return xmlrpc_type_mixed;
        !          2280:                        case xmlrpc_vector_array:
        !          2281:                                return xmlrpc_type_array;
        !          2282:                        }
        !          2283:                default:
        !          2284:                        /* evil cast, but we know they are the same */
        !          2285:                        return(XMLRPC_VALUE_TYPE_EASY) value->type;
        !          2286:                }
        !          2287:        }
        !          2288:        return xmlrpc_none;
        !          2289: }
        !          2290: 
        !          2291: /*******/
        !          2292: 
        !          2293: 
        !          2294: 
        !          2295: /*-*******************
        !          2296: * Begin Server Funcs *
        !          2297: *********************/
        !          2298: 
        !          2299: 
        !          2300: /****f* VALUE/XMLRPC_ServerCreate
        !          2301:  * NAME
        !          2302:  *   XMLRPC_ServerCreate
        !          2303:  * SYNOPSIS
        !          2304:  *   XMLRPC_SERVER XMLRPC_ServerCreate()
        !          2305:  * FUNCTION
        !          2306:  *   Allocate/Init XMLRPC Server Resources.
        !          2307:  * INPUTS
        !          2308:  *   none
        !          2309:  * RESULT
        !          2310:  *   newly allocated XMLRPC_SERVER
        !          2311:  * NOTES
        !          2312:  * SEE ALSO
        !          2313:  *   XMLRPC_ServerDestroy ()
        !          2314:  *   XMLRPC_GetGlobalServer ()
        !          2315:  * SOURCE
        !          2316:  */
        !          2317: XMLRPC_SERVER XMLRPC_ServerCreate() {
        !          2318:    XMLRPC_SERVER server = calloc(1, sizeof(STRUCT_XMLRPC_SERVER));
        !          2319:    if(server) {
        !          2320:       Q_Init(&server->methodlist);
        !          2321:       Q_Init(&server->docslist);
        !          2322: 
        !          2323:       /* register system methods */
        !          2324:       xsm_register(server);
        !          2325:    }
        !          2326:    return server;
        !          2327: }
        !          2328: 
        !          2329: /*******/
        !          2330: 
        !          2331: /* Return global server.  Not locking! Not Thread Safe! */
        !          2332: /****f* VALUE/XMLRPC_GetGlobalServer
        !          2333:  * NAME
        !          2334:  *   XMLRPC_GetGlobalServer
        !          2335:  * SYNOPSIS
        !          2336:  *   XMLRPC_SERVER XMLRPC_GetGlobalServer()
        !          2337:  * FUNCTION
        !          2338:  *   Allocates a global (process-wide) server, or returns pointer if pre-existing.
        !          2339:  * INPUTS
        !          2340:  *   none
        !          2341:  * RESULT
        !          2342:  *   pointer to global server, or 0 if error.
        !          2343:  * NOTES
        !          2344:  *   ***WARNING*** This function is not thread safe.  It is included only for the very lazy.
        !          2345:  *   Multi-threaded programs that use this may experience problems.
        !          2346:  * BUGS
        !          2347:  *   There is currently no way to cleanup the global server gracefully.
        !          2348:  * SEE ALSO
        !          2349:  *   XMLRPC_ServerCreate ()
        !          2350:  * SOURCE
        !          2351:  */
        !          2352: XMLRPC_SERVER XMLRPC_GetGlobalServer() {
        !          2353:    static XMLRPC_SERVER xsServer = 0;
        !          2354:    if(!xsServer) {
        !          2355:       xsServer = XMLRPC_ServerCreate();
        !          2356:    }
        !          2357:    return xsServer;
        !          2358: }
        !          2359: 
        !          2360: /*******/
        !          2361: 
        !          2362: /****f* VALUE/XMLRPC_ServerDestroy
        !          2363:  * NAME
        !          2364:  *   XMLRPC_ServerDestroy
        !          2365:  * SYNOPSIS
        !          2366:  *   void XMLRPC_ServerDestroy(XMLRPC_SERVER server)
        !          2367:  * FUNCTION
        !          2368:  *   Free Server Resources
        !          2369:  * INPUTS
        !          2370:  *   server     The server to be free'd
        !          2371:  * RESULT
        !          2372:  *   void
        !          2373:  * NOTES
        !          2374:  *   This frees the server struct and any methods that have been added.
        !          2375:  * SEE ALSO
        !          2376:  *   XMLRPC_ServerCreate ()
        !          2377:  * SOURCE
        !          2378:  */
        !          2379: void XMLRPC_ServerDestroy(XMLRPC_SERVER server) {
        !          2380:    if(server) {
        !          2381:       doc_method* dm = Q_Head(&server->docslist);
        !          2382:       server_method* sm = Q_Head(&server->methodlist);
        !          2383:       while( dm ) {
        !          2384:          my_free(dm);
        !          2385:          dm = Q_Next(&server->docslist);
        !          2386:       }
        !          2387:       while( sm ) {
        !          2388:          if(sm->name) {
        !          2389:             my_free(sm->name);
        !          2390:          }
        !          2391:          if(sm->desc) {
        !          2392:             XMLRPC_CleanupValue(sm->desc);
        !          2393:          }
        !          2394:          my_free(sm);
        !          2395:          sm = Q_Next(&server->methodlist);
        !          2396:       }
        !          2397:       if(server->xIntrospection) {
        !          2398:          XMLRPC_CleanupValue(server->xIntrospection);
        !          2399:       }
        !          2400: 
        !          2401:       Q_Destroy(&server->methodlist);
        !          2402:       Q_Destroy(&server->docslist);
        !          2403:       my_free(server);
        !          2404:    }
        !          2405: }
        !          2406: 
        !          2407: /*******/
        !          2408: 
        !          2409: 
        !          2410: /****f* VALUE/XMLRPC_ServerRegisterMethod
        !          2411:  * NAME
        !          2412:  *   XMLRPC_ServerRegisterMethod
        !          2413:  * SYNOPSIS
        !          2414:  *   void XMLRPC_ServerRegisterMethod(XMLRPC_SERVER server, const char *name, XMLRPC_Callback cb)
        !          2415:  * FUNCTION
        !          2416:  *   Register new XMLRPC method with server
        !          2417:  * INPUTS
        !          2418:  *   server     The XMLRPC_SERVER to register the method with
        !          2419:  *   name       public name of the method
        !          2420:  *   cb         C function that implements the method
        !          2421:  * RESULT
        !          2422:  *   int  - 1 if success, else 0
        !          2423:  * NOTES
        !          2424:  *   A C function must be registered for every "method" that the server recognizes.  The
        !          2425:  *   method name is equivalent to <methodCall><name> method name </name></methodCall> in the
        !          2426:  *   XML syntax.
        !          2427:  * SEE ALSO
        !          2428:  *   XMLRPC_ServerFindMethod ()
        !          2429:  *   XMLRPC_ServerCallMethod ()
        !          2430:  * SOURCE
        !          2431:  */
        !          2432: int XMLRPC_ServerRegisterMethod(XMLRPC_SERVER server, const char *name, XMLRPC_Callback cb) {
        !          2433:    if(server && name && cb) {
        !          2434: 
        !          2435:       server_method* sm = malloc(sizeof(server_method));
        !          2436:       
        !          2437:       if(sm) {
        !          2438:          sm->name = strdup(name);
        !          2439:          sm->method = cb;
        !          2440:          sm->desc = NULL;
        !          2441: 
        !          2442:          return Q_PushTail(&server->methodlist, sm);
        !          2443:       }
        !          2444:    }
        !          2445:    return 0;
        !          2446: }
        !          2447: 
        !          2448: /*******/
        !          2449: 
        !          2450: server_method* find_method(XMLRPC_SERVER server, const char* name) {
        !          2451:    server_method* sm;
        !          2452: 
        !          2453:    q_iter qi = Q_Iter_Head_F(&server->methodlist);
        !          2454: 
        !          2455:    while( qi ) {
        !          2456:       sm = Q_Iter_Get_F(qi);
        !          2457:       if(sm && !strcmp(sm->name, name)) {
        !          2458:          return sm;
        !          2459:       }
        !          2460:       qi = Q_Iter_Next_F(qi);
        !          2461:    }
        !          2462:    return NULL;
        !          2463: }
        !          2464: 
        !          2465: 
        !          2466: const char* type_to_str(XMLRPC_VALUE_TYPE type, XMLRPC_VECTOR_TYPE vtype) {
        !          2467:     switch(type) {
        !          2468:        case xmlrpc_none:
        !          2469:           return "none";
        !          2470:        case xmlrpc_empty:
        !          2471:           return "empty";
        !          2472:        case xmlrpc_base64:
        !          2473:           return "base64";
        !          2474:        case xmlrpc_boolean:
        !          2475:           return "boolean";
        !          2476:        case xmlrpc_datetime:
        !          2477:           return "datetime";
        !          2478:        case xmlrpc_double:
        !          2479:           return "double";
        !          2480:        case xmlrpc_int:
        !          2481:           return "int";
        !          2482:        case xmlrpc_string:
        !          2483:           return "string";
        !          2484:        case xmlrpc_vector:
        !          2485:           switch(vtype) {
        !          2486:              case xmlrpc_vector_none:
        !          2487:                 return "none";
        !          2488:              case xmlrpc_vector_array:
        !          2489:                 return "array";
        !          2490:              case xmlrpc_vector_mixed:
        !          2491:                 return "mixed vector (struct)";
        !          2492:              case xmlrpc_vector_struct:
        !          2493:                 return "struct";
        !          2494:           }
        !          2495:     }
        !          2496:     return "unknown";
        !          2497: }
        !          2498: 
        !          2499: /****f* VALUE/XMLRPC_ServerFindMethod
        !          2500:  * NAME
        !          2501:  *   XMLRPC_ServerFindMethod
        !          2502:  * SYNOPSIS
        !          2503:  *   XMLRPC_Callback XMLRPC_ServerFindMethod(XMLRPC_SERVER server, const char* callName)
        !          2504:  * FUNCTION
        !          2505:  *   retrieve C callback associated with a given method name.
        !          2506:  * INPUTS       
        !          2507:  *   server     The XMLRPC_SERVER the method is registered with
        !          2508:  *   callName   the method to find
        !          2509:  * RESULT
        !          2510:  *   previously registered XMLRPC_Callback, or NULL
        !          2511:  * NOTES
        !          2512:  *   Typically, this is used to determine if a requested method exists, without actually calling it.
        !          2513:  * SEE ALSO
        !          2514:  *   XMLRPC_ServerCallMethod ()
        !          2515:  *   XMLRPC_ServerRegisterMethod ()
        !          2516:  * SOURCE
        !          2517:  */
        !          2518: XMLRPC_Callback XMLRPC_ServerFindMethod(XMLRPC_SERVER server, const char* callName) {
        !          2519:    if(server && callName) {
        !          2520:       q_iter qi = Q_Iter_Head_F(&server->methodlist);
        !          2521:       while( qi ) {
        !          2522:          server_method* sm = Q_Iter_Get_F(qi);
        !          2523:          if(sm && !strcmp(sm->name, callName)) {
        !          2524:             return sm->method;
        !          2525:          }
        !          2526:          qi = Q_Iter_Next_F(qi);
        !          2527:       }
        !          2528:    }
        !          2529:    return NULL;
        !          2530: }
        !          2531: 
        !          2532: /*******/
        !          2533: 
        !          2534: 
        !          2535: /* Call method specified in request */
        !          2536: /****f* VALUE/XMLRPC_ServerCallMethod
        !          2537:  * NAME
        !          2538:  *   XMLRPC_ServerCallMethod
        !          2539:  * SYNOPSIS
        !          2540:  *   XMLRPC_VALUE XMLRPC_ServerCallMethod(XMLRPC_SERVER server, XMLRPC_REQUEST request, void* userData)
        !          2541:  * FUNCTION
        !          2542:  *
        !          2543:  * INPUTS
        !          2544:  *   server     The XMLRPC_SERVER the method is registered with
        !          2545:  *   request    the request to handle
        !          2546:  *   userData   any additional data to pass to the C callback, or NULL
        !          2547:  * RESULT
        !          2548:  *   XMLRPC_VALUE allocated by the callback, or NULL
        !          2549:  * NOTES
        !          2550:  *   It is typically the caller's responsibility to free the returned value.
        !          2551:  *
        !          2552:  *   Often the caller will want to serialize the result as XML, via 
        !          2553:  *   XMLRPC_VALUE_To_XML () or XMLRPC_REQUEST_To_XML ()
        !          2554:  * SEE ALSO
        !          2555:  *   XMLRPC_ServerFindMethod ()
        !          2556:  *   XMLRPC_ServerRegisterMethod ()
        !          2557:  *   XMLRPC_CleanupValue ()
        !          2558:  * SOURCE
        !          2559:  */
        !          2560: XMLRPC_VALUE XMLRPC_ServerCallMethod(XMLRPC_SERVER server, XMLRPC_REQUEST request, void* userData) {
        !          2561:    XMLRPC_VALUE xReturn = NULL;
        !          2562: 
        !          2563:    /* check for error set during request parsing / generation */
        !          2564:    if(request && request->error) {
        !          2565:       xReturn = XMLRPC_CopyValue(request->error);
        !          2566:    }
        !          2567:        else if (server && request) {
        !          2568:                XMLRPC_Callback cb =
        !          2569:                XMLRPC_ServerFindMethod (server, request->methodName.str);
        !          2570:       if(cb) {
        !          2571:          xReturn = cb(server, request, userData);
        !          2572:       }
        !          2573:       else {
        !          2574:                        xReturn =
        !          2575:                        XMLRPC_UtilityCreateFault (xmlrpc_error_unknown_method,
        !          2576:                                                                                                request->methodName.str);
        !          2577:       }
        !          2578:    }
        !          2579:    return xReturn;
        !          2580: }
        !          2581: 
        !          2582: /*******/
        !          2583: 
        !          2584: /*-*****************
        !          2585: * End server funcs *
        !          2586: *******************/
        !          2587: 
        !          2588: 
        !          2589: /*-***********************************
        !          2590: * Begin XMLRPC General Options funcs *
        !          2591: *************************************/
        !          2592: 
        !          2593: /* For options used by XMLRPC_VALUE funcs that otherwise do not have
        !          2594:  * parameters for options.  Kind of gross.  :(
        !          2595:  */
        !          2596: typedef struct _xmlrpc_options {
        !          2597:    XMLRPC_CASE id_case;
        !          2598:    XMLRPC_CASE_COMPARISON id_case_compare;
        !          2599: }
        !          2600: STRUCT_XMLRPC_OPTIONS, *XMLRPC_OPTIONS;
        !          2601: 
        !          2602: static XMLRPC_OPTIONS XMLRPC_GetDefaultOptions() {
        !          2603:    static STRUCT_XMLRPC_OPTIONS options = {
        !          2604:       xmlrpc_case_exact,
        !          2605:       xmlrpc_case_sensitive
        !          2606:    };
        !          2607:    return &options;
        !          2608: }
        !          2609: 
        !          2610: /****f* VALUE/XMLRPC_GetDefaultIdCase
        !          2611:  * NAME
        !          2612:  *   XMLRPC_GetDefaultIdCase
        !          2613:  * SYNOPSIS
        !          2614:  *   XMLRPC_CASE XMLRPC_GetDefaultIdCase()
        !          2615:  * FUNCTION
        !          2616:  *   Gets default case options used by XMLRPC_VALUE funcs
        !          2617:  * INPUTS
        !          2618:  *   none
        !          2619:  * RESULT
        !          2620:  *   XMLRPC_CASE
        !          2621:  * BUGS
        !          2622:  *   Nasty and gross.  Should be server specific, but that requires changing all
        !          2623:  *  the XMLRPC_VALUE api's.
        !          2624:  * SEE ALSO
        !          2625:  *   XMLRPC_SetDefaultIdCase ()
        !          2626:  * SOURCE
        !          2627:  */
        !          2628: XMLRPC_CASE XMLRPC_GetDefaultIdCase() {
        !          2629:    XMLRPC_OPTIONS options = XMLRPC_GetDefaultOptions();
        !          2630:    return options->id_case;
        !          2631: }
        !          2632: 
        !          2633: /*******/
        !          2634: 
        !          2635: /****f* VALUE/XMLRPC_SetDefaultIdCase
        !          2636:  * NAME
        !          2637:  *   XMLRPC_SetDefaultIdCase
        !          2638:  * SYNOPSIS
        !          2639:  *   XMLRPC_CASE XMLRPC_SetDefaultIdCase(XMLRPC_CASE id_case)
        !          2640:  * FUNCTION
        !          2641:  *   Sets default case options used by XMLRPC_VALUE funcs
        !          2642:  * INPUTS
        !          2643:  *   id_case   case options as enumerated by XMLRPC_CASE
        !          2644:  * RESULT
        !          2645:  *   XMLRPC_CASE -- newly set option
        !          2646:  * BUGS
        !          2647:  *   Nasty and gross.  Should be server specific, but that requires changing all
        !          2648:  *  the XMLRPC_VALUE api's.
        !          2649:  * SEE ALSO
        !          2650:  *   XMLRPC_GetDefaultIdCase ()
        !          2651:  * SOURCE
        !          2652:  */
        !          2653: XMLRPC_CASE XMLRPC_SetDefaultIdCase(XMLRPC_CASE id_case) {
        !          2654:    XMLRPC_OPTIONS options = XMLRPC_GetDefaultOptions();
        !          2655:    options->id_case = id_case;
        !          2656:    return options->id_case;
        !          2657: }
        !          2658: 
        !          2659: /*******/
        !          2660: 
        !          2661: /****f* VALUE/XMLRPC_GetDefaultIdCaseComparison
        !          2662:  * NAME
        !          2663:  *   XMLRPC_GetDefaultIdCaseComparison
        !          2664:  * SYNOPSIS
        !          2665:  *   XMLRPC_CASE XMLRPC_GetDefaultIdCaseComparison( )
        !          2666:  * FUNCTION
        !          2667:  *   Gets default case comparison options used by XMLRPC_VALUE funcs
        !          2668:  * INPUTS
        !          2669:  *   none
        !          2670:  * RESULT
        !          2671:  *   XMLRPC_CASE_COMPARISON default
        !          2672:  * BUGS
        !          2673:  *   Nasty and gross.  Should be server specific, but that requires changing all
        !          2674:  *  the XMLRPC_VALUE api's.
        !          2675:  * SEE ALSO
        !          2676:  *   XMLRPC_SetDefaultIdCaseComparison ()
        !          2677:  * SOURCE
        !          2678:  */
        !          2679: XMLRPC_CASE_COMPARISON XMLRPC_GetDefaultIdCaseComparison() {
        !          2680:    XMLRPC_OPTIONS options = XMLRPC_GetDefaultOptions();
        !          2681:    return options->id_case_compare;
        !          2682: }
        !          2683: 
        !          2684: /*******/
        !          2685: 
        !          2686: /****f* VALUE/XMLRPC_SetDefaultIdCaseComparison
        !          2687:  * NAME
        !          2688:  *   XMLRPC_SetDefaultIdCaseComparison
        !          2689:  * SYNOPSIS
        !          2690:  *   XMLRPC_CASE XMLRPC_SetDefaultIdCaseComparison( XMLRPC_CASE_COMPARISON id_case_compare )
        !          2691:  * FUNCTION
        !          2692:  *   Gets default case comparison options used by XMLRPC_VALUE funcs
        !          2693:  * INPUTS
        !          2694:  *   id_case_compare  case comparison rule to set as default
        !          2695:  * RESULT
        !          2696:  *   XMLRPC_CASE_COMPARISON newly set default
        !          2697:  * BUGS
        !          2698:  *   Nasty and gross.  Should be server specific, but that requires changing all
        !          2699:  *  the XMLRPC_VALUE api's.
        !          2700:  * SEE ALSO
        !          2701:  *   XMLRPC_GetDefaultIdCaseComparison ()
        !          2702:  * SOURCE
        !          2703:  */
        !          2704: XMLRPC_CASE_COMPARISON XMLRPC_SetDefaultIdCaseComparison(XMLRPC_CASE_COMPARISON id_case_compare) {
        !          2705:    XMLRPC_OPTIONS options = XMLRPC_GetDefaultOptions();
        !          2706:    options->id_case_compare = id_case_compare;
        !          2707:    return options->id_case_compare;
        !          2708: }
        !          2709: 
        !          2710: /*******/
        !          2711: 
        !          2712: /*-*********************************
        !          2713: * End XMLRPC General Options funcs *
        !          2714: ***********************************/
        !          2715: 
        !          2716: 
        !          2717: /*-******************
        !          2718: * Fault API funcs   *
        !          2719: ********************/
        !          2720: 
        !          2721: /****f* UTILITY/XMLRPC_UtilityCreateFault
        !          2722:  * NAME
        !          2723:  *   XMLRPC_UtilityCreateFault
        !          2724:  * SYNOPSIS
        !          2725:  *   XMLRPC_VALUE XMLRPC_UtilityCreateFault( int fault_code, const char* fault_string )
        !          2726:  * FUNCTION
        !          2727:  *   generates a struct containing a string member with id "faultString" and an int member
        !          2728:  *   with id "faultCode". When using the xmlrpc xml serialization, these will be translated
        !          2729:  *   to <fault><value><struct>... format.
        !          2730:  * INPUTS
        !          2731:  *   fault_code     application specific error code. can be 0.
        !          2732:  *   fault_string   application specific error string.  cannot be null.
        !          2733:  * RESULT
        !          2734:  *   XMLRPC_VALUE a newly created struct vector representing the error, or null on error.
        !          2735:  * NOTES
        !          2736:  *   This is a utility function. xmlrpc "faults" are not directly represented in this xmlrpc
        !          2737:  *   API or data structures. It is the author's view, that this API is intended for simple
        !          2738:  *   data types, and a "fault" is a complex data type consisting of multiple simple data
        !          2739:  *   types.  This function is provided for convenience only, the same result could be
        !          2740:  *   achieved directly by the application.
        !          2741:  *
        !          2742:  *   This function now supports some "standardized" fault codes, as specified at.
        !          2743:  *   http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php.
        !          2744:  *   If one of these fault codes is received, the description string will automatically
        !          2745:  *   be prefixed with a standard error string and 2 newlines.  
        !          2746:  *
        !          2747:  *   The actual transformation between this complex type and the xml "<fault>" element takes
        !          2748:  *   place in the xmlrpc to xml serialization layer.  This step is not performed when using the
        !          2749:  *   simplerpc serialization, meaning that there will be no "<fault>" element in that
        !          2750:  *   serialization. There will simply be a standard struct with 2 child elements.  
        !          2751:  *   imho, the "<fault>" element is unnecessary and/or out of place as part of the standard API.
        !          2752:  *
        !          2753:  * SOURCE
        !          2754:  */
        !          2755: XMLRPC_VALUE XMLRPC_UtilityCreateFault(int fault_code, const char* fault_string) {
        !          2756:    XMLRPC_VALUE xOutput = NULL;
        !          2757: 
        !          2758:    char* string = NULL;
        !          2759:    simplestring description;
        !          2760:    simplestring_init(&description);
        !          2761: 
        !          2762:    switch (fault_code) {
        !          2763:        case xmlrpc_error_parse_xml_syntax:
        !          2764:                string = xmlrpc_error_parse_xml_syntax_str;
        !          2765:                break;
        !          2766:        case xmlrpc_error_parse_unknown_encoding:
        !          2767:                string = xmlrpc_error_parse_unknown_encoding_str;
        !          2768:                break;
        !          2769:        case xmlrpc_error_parse_bad_encoding:
        !          2770:                string = xmlrpc_error_parse_bad_encoding_str;
        !          2771:                break;
        !          2772:        case xmlrpc_error_invalid_xmlrpc:
        !          2773:                string = xmlrpc_error_invalid_xmlrpc_str;
        !          2774:                break;
        !          2775:        case xmlrpc_error_unknown_method:
        !          2776:                string = xmlrpc_error_unknown_method_str;
        !          2777:                break;
        !          2778:        case xmlrpc_error_invalid_params:
        !          2779:                string = xmlrpc_error_invalid_params_str;
        !          2780:                break;
        !          2781:        case xmlrpc_error_internal_server:
        !          2782:                string = xmlrpc_error_internal_server_str;
        !          2783:                break;
        !          2784:        case xmlrpc_error_application:
        !          2785:                string = xmlrpc_error_application_str;
        !          2786:                break;
        !          2787:        case xmlrpc_error_system:
        !          2788:                string = xmlrpc_error_system_str;
        !          2789:                break;
        !          2790:        case xmlrpc_error_transport:
        !          2791:                string = xmlrpc_error_transport_str;
        !          2792:                break;
        !          2793:    }
        !          2794: 
        !          2795:    simplestring_add(&description, string);
        !          2796: 
        !          2797:    if(string && fault_string) {
        !          2798:       simplestring_add(&description, "\n\n");
        !          2799:    }
        !          2800:    simplestring_add(&description, fault_string);
        !          2801: 
        !          2802: 
        !          2803:    if(description.len) {
        !          2804:       xOutput = XMLRPC_CreateVector(NULL, xmlrpc_vector_struct);
        !          2805: 
        !          2806:                XMLRPC_VectorAppendString (xOutput, "faultString", description.str,
        !          2807:                                                                                        description.len);
        !          2808:       XMLRPC_VectorAppendInt(xOutput, "faultCode", fault_code);
        !          2809:    }
        !          2810: 
        !          2811:    simplestring_free(&description);
        !          2812: 
        !          2813:    return xOutput;
        !          2814: }
        !          2815: 
        !          2816: /*******/
        !          2817: 
        !          2818: 
        !          2819: /****f* FAULT/XMLRPC_ValueIsFault
        !          2820:  * NAME
        !          2821:  *   XMLRPC_ValueIsFault
        !          2822:  * SYNOPSIS
        !          2823:  *   int XMLRPC_ValueIsFault (XMLRPC_VALUE value)
        !          2824:  * FUNCTION
        !          2825:  *   Determines if a value encapsulates a fault "object"
        !          2826:  * INPUTS
        !          2827:  *   value  any XMLRPC_VALUE
        !          2828:  * RESULT
        !          2829:  *   1 if it is a fault, else 0
        !          2830:  * SEE ALSO
        !          2831:  *   XMLRPC_ResponseIsFault ()
        !          2832:  * SOURCE
        !          2833:  */
        !          2834: int XMLRPC_ValueIsFault (XMLRPC_VALUE value) {
        !          2835:    if( XMLRPC_VectorGetValueWithID(value, "faultCode") &&
        !          2836:        XMLRPC_VectorGetValueWithID(value, "faultString") ) {
        !          2837:       return 1;
        !          2838:    }
        !          2839:    return 0;
        !          2840: }
        !          2841: /*******/
        !          2842: 
        !          2843: 
        !          2844: /****f* FAULT/XMLRPC_ResponseIsFault
        !          2845:  * NAME
        !          2846:  *   XMLRPC_ResponseIsFault
        !          2847:  * SYNOPSIS
        !          2848:  *   int XMLRPC_ResponseIsFault (XMLRPC_REQUEST response)
        !          2849:  * FUNCTION
        !          2850:  *   Determines if a response contains an encapsulated fault "object"
        !          2851:  * INPUTS
        !          2852:  *   value  any XMLRPC_REQUEST. typically of type xmlrpc_request_response
        !          2853:  * RESULT
        !          2854:  *   1 if it contains a fault, else 0
        !          2855:  * SEE ALSO
        !          2856:  *   XMLRPC_ValueIsFault ()
        !          2857:  * SOURCE
        !          2858:  */
        !          2859: int XMLRPC_ResponseIsFault(XMLRPC_REQUEST response) {
        !          2860:    return XMLRPC_ValueIsFault( XMLRPC_RequestGetData(response) );
        !          2861: }
        !          2862: 
        !          2863: /*******/
        !          2864: 
        !          2865: /****f* FAULT/XMLRPC_GetValueFaultCode
        !          2866:  * NAME
        !          2867:  *   XMLRPC_GetValueFaultCode
        !          2868:  * SYNOPSIS
        !          2869:  *   int XMLRPC_GetValueFaultCode (XMLRPC_VALUE value)
        !          2870:  * FUNCTION
        !          2871:  *   returns fault code from a struct, if any
        !          2872:  * INPUTS
        !          2873:  *   value  XMLRPC_VALUE of type xmlrpc_vector_struct.
        !          2874:  * RESULT
        !          2875:  *   fault code, else 0.
        !          2876:  * BUGS
        !          2877:  *   impossible to distinguish faultCode == 0 from faultCode not present.
        !          2878:  * SEE ALSO
        !          2879:  *   XMLRPC_GetResponseFaultCode ()
        !          2880:  * SOURCE
        !          2881:  */
        !          2882: int XMLRPC_GetValueFaultCode (XMLRPC_VALUE value) {
        !          2883:    return XMLRPC_VectorGetIntWithID(value, "faultCode");
        !          2884: }
        !          2885: 
        !          2886: /*******/
        !          2887: 
        !          2888: /****f* FAULT/XMLRPC_GetResponseFaultCode
        !          2889:  * NAME
        !          2890:  *   XMLRPC_GetResponseFaultCode
        !          2891:  * SYNOPSIS
        !          2892:  *   int XMLRPC_GetResponseFaultCode(XMLRPC_REQUEST response)
        !          2893:  * FUNCTION
        !          2894:  *   returns fault code from a response, if any
        !          2895:  * INPUTS
        !          2896:  *   response  XMLRPC_REQUEST. typically of type xmlrpc_request_response.
        !          2897:  * RESULT
        !          2898:  *   fault code, else 0.
        !          2899:  * BUGS
        !          2900:  *   impossible to distinguish faultCode == 0 from faultCode not present.
        !          2901:  * SEE ALSO
        !          2902:  *   XMLRPC_GetValueFaultCode ()
        !          2903:  * SOURCE
        !          2904:  */
        !          2905: int XMLRPC_GetResponseFaultCode(XMLRPC_REQUEST response) {
        !          2906:    return XMLRPC_GetValueFaultCode( XMLRPC_RequestGetData(response) );
        !          2907: }
        !          2908: 
        !          2909: /*******/
        !          2910: 
        !          2911: 
        !          2912: /****f* FAULT/XMLRPC_GetValueFaultString
        !          2913:  * NAME
        !          2914:  *   XMLRPC_GetValueFaultString
        !          2915:  * SYNOPSIS
        !          2916:  *   const char* XMLRPC_GetValueFaultString (XMLRPC_VALUE value)
        !          2917:  * FUNCTION
        !          2918:  *   returns fault string from a struct, if any
        !          2919:  * INPUTS
        !          2920:  *   value  XMLRPC_VALUE of type xmlrpc_vector_struct.
        !          2921:  * RESULT
        !          2922:  *   fault string, else 0.
        !          2923:  * SEE ALSO
        !          2924:  *   XMLRPC_GetResponseFaultString ()
        !          2925:  * SOURCE
        !          2926:  */
        !          2927: const char* XMLRPC_GetValueFaultString (XMLRPC_VALUE value) {
        !          2928:    return XMLRPC_VectorGetStringWithID(value, "faultString");
        !          2929: }
        !          2930: 
        !          2931: /*******/
        !          2932: 
        !          2933: /****f* FAULT/XMLRPC_GetResponseFaultString
        !          2934:  * NAME
        !          2935:  *   XMLRPC_GetResponseFaultString
        !          2936:  * SYNOPSIS
        !          2937:  *   const char* XMLRPC_GetResponseFaultString (XMLRPC_REQUEST response)
        !          2938:  * FUNCTION
        !          2939:  *   returns fault string from a response, if any
        !          2940:  * INPUTS
        !          2941:  *   response  XMLRPC_REQUEST. typically of type xmlrpc_request_response.
        !          2942:  * RESULT
        !          2943:  *   fault string, else 0.
        !          2944:  * SEE ALSO
        !          2945:  *   XMLRPC_GetValueFaultString ()
        !          2946:  * SOURCE
        !          2947:  */
        !          2948: const char* XMLRPC_GetResponseFaultString (XMLRPC_REQUEST response) {
        !          2949:    return XMLRPC_GetValueFaultString( XMLRPC_RequestGetData(response) );
        !          2950: }
        !          2951: 
        !          2952: /*******/
        !          2953: 
        !          2954: 
        !          2955: /*-******************
        !          2956: * Utility API funcs *
        !          2957: ********************/
        !          2958: 
        !          2959: 
        !          2960: /****f* UTILITY/XMLRPC_Free
        !          2961:  * NAME
        !          2962:  *   XMLRPC_Free
        !          2963:  * SYNOPSIS
        !          2964:  *   void XMLRPC_Free(void* mem)
        !          2965:  * FUNCTION
        !          2966:  *   frees a block of memory allocated by xmlrpc. 
        !          2967:  * INPUTS
        !          2968:  *   mem    memory to free
        !          2969:  * RESULT
        !          2970:  *   void
        !          2971:  * NOTES
        !          2972:  *   Useful for OS's where memory must be free'd
        !          2973:  *   in the same library in which it is allocated.
        !          2974:  * SOURCE
        !          2975:  */
        !          2976: void XMLRPC_Free(void* mem) {
        !          2977:    my_free(mem);
        !          2978: }
        !          2979: 
        !          2980: /*******/
        !          2981: 
        !          2982: 
        !          2983: /****f* UTILITY/XMLRPC_GetVersionString
        !          2984:  * NAME
        !          2985:  *   XMLRPC_GetVersionString
        !          2986:  * SYNOPSIS
        !          2987:  *   const char* XMLRPC_GetVersionString()
        !          2988:  * FUNCTION
        !          2989:  *   returns library version string
        !          2990:  * INPUTS
        !          2991:  *   
        !          2992:  * RESULT
        !          2993:  *   const char* 
        !          2994:  * NOTES
        !          2995:  * SOURCE
        !          2996:  */
        !          2997: const char*  XMLRPC_GetVersionString() {
        !          2998:    return XMLRPC_VERSION_STR;
        !          2999: }
        !          3000: 
        !          3001: /*******/
        !          3002: 
        !          3003: 
        !          3004: /*-**********************
        !          3005: * End Utility API funcs *
        !          3006: ************************/

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>