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