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>