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