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