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