Annotation of embedaddon/php/ext/xmlrpc/libxmlrpc/xmlrpc.c, revision 1.1.1.2
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:
1.1.1.2 ! misho 34: static const char rcsid[] = "#(@) $Id$";
1.1 misho 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>