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