ENH: make this work for older versions of OSX
[cmake.git] / Utilities / cmxmlrpc / xmlrpc_registry.c
blobae3b21cd624c351051a010696539541fcdcc45a4
1 /* Copyright (C) 2001 by First Peer, Inc. All rights reserved.
2 ** Copyright (C) 2001 by Eric Kidd. All rights reserved.
3 ** Copyright (C) 2001 by Luke Howard. All rights reserved.
4 **
5 ** Redistribution and use in source and binary forms, with or without
6 ** modification, are permitted provided that the following conditions
7 ** are met:
8 ** 1. Redistributions of source code must retain the above copyright
9 ** notice, this list of conditions and the following disclaimer.
10 ** 2. Redistributions in binary form must reproduce the above copyright
11 ** notice, this list of conditions and the following disclaimer in the
12 ** documentation and/or other materials provided with the distribution.
13 ** 3. The name of the author may not be used to endorse or promote products
14 ** derived from this software without specific prior written permission.
15 **
16 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 ** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 ** SUCH DAMAGE. */
28 #include "xmlrpc_config.h"
30 #include <stdlib.h>
31 #include <string.h>
33 #include "xmlrpc.h"
34 #include "xmlrpc_server.h"
35 #include "xmlrpc_int.h"
37 /*=========================================================================
38 ** XML-RPC Server Method Registry
39 **=========================================================================
40 ** A method registry maintains a list of functions, and handles
41 ** dispatching. To build an XML-RPC server, just add a communications
42 ** protocol. :-)
45 static void
46 install_system_methods (xmlrpc_env *env, xmlrpc_registry *registry);
48 xmlrpc_registry *
49 xmlrpc_registry_new(xmlrpc_env *env) {
51 xmlrpc_value *methods;
52 xmlrpc_registry *registry;
53 int registry_valid;
55 XMLRPC_ASSERT_ENV_OK(env);
57 /* Error-handling preconditions. */
58 registry = NULL;
59 registry_valid = 0;
61 /* Allocate our memory. */
62 methods = xmlrpc_struct_new(env);
63 XMLRPC_FAIL_IF_FAULT(env);
64 registry = (xmlrpc_registry*) malloc(sizeof(xmlrpc_registry));
65 XMLRPC_FAIL_IF_NULL(registry, env, XMLRPC_INTERNAL_ERROR,
66 "Could not allocate memory for registry");
68 /* Set everything up. */
69 registry->_introspection_enabled = 1;
70 registry->_methods = methods;
71 registry->_default_method = NULL;
72 registry->_preinvoke_method = NULL;
73 registry_valid = 1;
75 /* Install our system methods. */
76 install_system_methods(env, registry);
77 XMLRPC_FAIL_IF_FAULT(env);
79 cleanup:
80 if (env->fault_occurred) {
81 if (registry_valid) {
82 xmlrpc_registry_free(registry);
83 } else {
84 if (methods)
85 xmlrpc_DECREF(methods);
86 if (registry)
87 free(registry);
89 return NULL;
91 return registry;
96 void
97 xmlrpc_registry_free(xmlrpc_registry * registry) {
99 XMLRPC_ASSERT_PTR_OK(registry);
100 XMLRPC_ASSERT(registry->_methods != XMLRPC_BAD_POINTER);
102 xmlrpc_DECREF(registry->_methods);
103 registry->_methods = XMLRPC_BAD_POINTER;
104 if (registry->_default_method != NULL)
105 xmlrpc_DECREF(registry->_default_method);
106 if (registry->_preinvoke_method != NULL)
107 xmlrpc_DECREF(registry->_preinvoke_method);
108 free(registry);
113 /*=========================================================================
114 ** xmlrpc_registry_disable_introspection
115 **=========================================================================
116 ** See xmlrpc.h for more documentation.
119 void
120 xmlrpc_registry_disable_introspection(xmlrpc_registry * registry) {
121 XMLRPC_ASSERT_PTR_OK(registry);
122 registry->_introspection_enabled = 0;
127 /*=========================================================================
128 ** xmlrpc_registry_add_method
129 **=========================================================================
130 ** See xmlrpc.h for more documentation.
133 void
134 xmlrpc_registry_add_method(xmlrpc_env *env,
135 xmlrpc_registry *registry,
136 const char *host,
137 const char *method_name,
138 xmlrpc_method method,
139 void *user_data) {
141 xmlrpc_registry_add_method_w_doc (env, registry, host, method_name,
142 method, user_data, "?",
143 "No help is available for this method.");
148 void
149 xmlrpc_registry_add_method_w_doc(xmlrpc_env *env,
150 xmlrpc_registry *registry,
151 const char *host,
152 const char *method_name,
153 xmlrpc_method method,
154 void *user_data,
155 const char *signature,
156 const char *help) {
157 xmlrpc_value *method_info;
159 XMLRPC_ASSERT_ENV_OK(env);
160 XMLRPC_ASSERT_PTR_OK(registry);
161 XMLRPC_ASSERT(host == NULL);
162 XMLRPC_ASSERT_PTR_OK(method_name);
163 XMLRPC_ASSERT_PTR_OK(method);
165 /* Store our method and user data into our hash table. */
166 method_info = xmlrpc_build_value(env, "(ppss)", (void*) method, user_data,
167 signature, help);
168 XMLRPC_FAIL_IF_FAULT(env);
169 xmlrpc_struct_set_value(env, registry->_methods, method_name, method_info);
170 XMLRPC_FAIL_IF_FAULT(env);
172 cleanup:
173 if (method_info)
174 xmlrpc_DECREF(method_info);
180 /*=========================================================================
181 ** xmlrpc_registry_set_default_method
182 **=========================================================================
183 ** See xmlrpc.h for more documentation.
186 void
187 xmlrpc_registry_set_default_method(xmlrpc_env *env,
188 xmlrpc_registry *registry,
189 xmlrpc_default_method handler,
190 void *user_data) {
191 xmlrpc_value *method_info;
193 XMLRPC_ASSERT_ENV_OK(env);
194 XMLRPC_ASSERT_PTR_OK(registry);
195 XMLRPC_ASSERT_PTR_OK(handler);
197 /* Store our method and user data into our hash table. */
198 method_info = xmlrpc_build_value(env, "(pp)", (void*) handler, user_data);
199 XMLRPC_FAIL_IF_FAULT(env);
201 /* Dispose of any pre-existing default method and install ours. */
202 if (registry->_default_method)
203 xmlrpc_DECREF(registry->_default_method);
204 registry->_default_method = method_info;
206 cleanup:
207 if (env->fault_occurred) {
208 if (method_info)
209 xmlrpc_DECREF(method_info);
215 /*=========================================================================
216 ** xmlrpc_registry_set_preinvoke_method
217 **=========================================================================
218 ** See xmlrpc.h for more documentation.
221 void
222 xmlrpc_registry_set_preinvoke_method(xmlrpc_env *env,
223 xmlrpc_registry *registry,
224 xmlrpc_preinvoke_method handler,
225 void *user_data) {
226 xmlrpc_value *method_info;
228 XMLRPC_ASSERT_ENV_OK(env);
229 XMLRPC_ASSERT_PTR_OK(registry);
230 XMLRPC_ASSERT_PTR_OK(handler);
232 /* Store our method and user data into our hash table. */
233 method_info = xmlrpc_build_value(env, "(pp)", (void*) handler, user_data);
234 XMLRPC_FAIL_IF_FAULT(env);
236 /* Dispose of any pre-existing preinvoke method and install ours. */
237 if (registry->_preinvoke_method)
238 xmlrpc_DECREF(registry->_preinvoke_method);
239 registry->_preinvoke_method = method_info;
241 cleanup:
242 if (env->fault_occurred) {
243 if (method_info)
244 xmlrpc_DECREF(method_info);
250 /*=========================================================================
251 ** dispatch_call
252 **=========================================================================
253 ** An internal method which actually does the dispatch. This may get
254 ** prettified and exported at some point in the future.
257 static void
258 callPreinvokeMethodIfAny(xmlrpc_env * const envP,
259 xmlrpc_registry * const registryP,
260 const char * const methodName,
261 xmlrpc_value * const paramArrayP) {
263 /* Get the preinvoke method, if it is set. */
264 if (registryP->_preinvoke_method) {
265 xmlrpc_preinvoke_method preinvoke_method;
266 void * user_data;
268 xmlrpc_parse_value(envP, registryP->_preinvoke_method, "(pp)",
269 &preinvoke_method, &user_data);
270 if (!envP->fault_occurred)
271 (*preinvoke_method)(envP, methodName,
272 paramArrayP, user_data);
278 static void
279 callDefaultMethod(xmlrpc_env * const envP,
280 xmlrpc_value * const defaultMethodInfo,
281 const char * const methodName,
282 xmlrpc_value * const paramArrayP,
283 xmlrpc_value ** const resultPP) {
285 xmlrpc_default_method default_method;
286 void * user_data;
288 xmlrpc_parse_value(envP, defaultMethodInfo, "(pp)",
289 &default_method, &user_data);
291 if (!envP->fault_occurred)
292 *resultPP = (*default_method)(envP, NULL, methodName,
293 paramArrayP, user_data);
298 static void
299 callNamedMethod(xmlrpc_env * const envP,
300 xmlrpc_value * const methodInfo,
301 xmlrpc_value * const paramArrayP,
302 xmlrpc_value ** const resultPP) {
304 xmlrpc_method method;
305 void * user_data;
307 xmlrpc_parse_value(envP, methodInfo, "(pp*)", &method, &user_data);
308 if (!envP->fault_occurred)
309 *resultPP = (*method)(envP, paramArrayP, user_data);
314 static void
315 dispatch_call(xmlrpc_env * const envP,
316 xmlrpc_registry * const registryP,
317 const char * const methodName,
318 xmlrpc_value * const paramArrayP,
319 xmlrpc_value ** const resultPP) {
321 callPreinvokeMethodIfAny(envP, registryP, methodName, paramArrayP);
322 if (!envP->fault_occurred) {
323 xmlrpc_value * method_info;
325 /* Look up the method info for the named method. */
326 xmlrpc_struct_find_value(envP, registryP->_methods,
327 methodName, &method_info);
328 if (!envP->fault_occurred) {
329 if (method_info)
330 callNamedMethod(envP, method_info, paramArrayP, resultPP);
331 else {
332 if (registryP->_default_method)
333 callDefaultMethod(envP, registryP->_default_method,
334 methodName, paramArrayP,
335 resultPP);
336 else {
337 /* No matching method, and no default. */
338 xmlrpc_env_set_fault_formatted(
339 envP, XMLRPC_NO_SUCH_METHOD_ERROR,
340 "Method '%s' not defined", methodName);
345 /* For backward compatibility, for sloppy users: */
346 if (envP->fault_occurred)
347 *resultPP = NULL;
352 /*=========================================================================
353 ** xmlrpc_registry_process_call
354 **=========================================================================
358 xmlrpc_mem_block *
359 xmlrpc_registry_process_call(xmlrpc_env * const envP,
360 xmlrpc_registry * const registryP,
361 const char * const host ATTR_UNUSED,
362 const char * const xml_data,
363 size_t const xml_len) {
365 xmlrpc_mem_block * output;
367 XMLRPC_ASSERT_ENV_OK(envP);
368 XMLRPC_ASSERT_PTR_OK(xml_data);
370 xmlrpc_traceXml("XML-RPC CALL", xml_data, (unsigned int)xml_len);
372 /* Allocate our output buffer.
373 ** If this fails, we need to die in a special fashion. */
374 output = XMLRPC_MEMBLOCK_NEW(char, envP, 0);
375 if (!envP->fault_occurred) {
376 const char * methodName;
377 xmlrpc_value * paramArray;
378 xmlrpc_env fault;
380 xmlrpc_env_init(&fault);
382 xmlrpc_parse_call(&fault, xml_data, xml_len,
383 &methodName, &paramArray);
385 if (!fault.fault_occurred) {
386 xmlrpc_value * result;
388 dispatch_call(&fault, registryP, methodName, paramArray, &result);
390 if (!fault.fault_occurred) {
391 xmlrpc_serialize_response(envP, output, result);
393 /* A comment here used to say that
394 xmlrpc_serialize_response() could fail and "leave
395 stuff in the buffer." Don't know what that means,
396 but it sounds like something that needs to be
397 fixed. The old code aborted the program here if
398 xmlrpc_serialize_repsonse() failed. 04.11.17
400 xmlrpc_DECREF(result);
402 xmlrpc_strfree(methodName);
403 xmlrpc_DECREF(paramArray);
405 if (!envP->fault_occurred && fault.fault_occurred)
406 xmlrpc_serialize_fault(envP, output, &fault);
408 xmlrpc_env_clean(&fault);
410 if (envP->fault_occurred)
411 XMLRPC_MEMBLOCK_FREE(char, output);
412 else
413 xmlrpc_traceXml("XML-RPC RESPONSE",
414 XMLRPC_MEMBLOCK_CONTENTS(char, output),
415 (unsigned int)XMLRPC_MEMBLOCK_SIZE(char, output));
417 return output;
422 /*=========================================================================
423 ** system.multicall
424 **=========================================================================
425 ** Low-tech support for transparent, boxed methods.
428 static char *multicall_help =
429 "Process an array of calls, and return an array of results. Calls should "
430 "be structs of the form {'methodName': string, 'params': array}. Each "
431 "result will either be a single-item array containg the result value, or "
432 "a struct of the form {'faultCode': int, 'faultString': string}. This "
433 "is useful when you need to make lots of small calls without lots of "
434 "round trips.";
436 static xmlrpc_value *
437 call_one_method(xmlrpc_env *env, xmlrpc_registry *registry,
438 xmlrpc_value *method_info) {
440 xmlrpc_value *result_val, *result;
441 char *method_name;
442 xmlrpc_value *param_array;
444 /* Error-handling preconditions. */
445 result = result_val = NULL;
447 /* Extract our method name and parameters. */
448 xmlrpc_parse_value(env, method_info, "{s:s,s:A,*}",
449 "methodName", &method_name,
450 "params", &param_array);
451 XMLRPC_FAIL_IF_FAULT(env);
453 /* Watch out for a deep recursion attack. */
454 if (strcmp(method_name, "system.multicall") == 0)
455 XMLRPC_FAIL(env, XMLRPC_REQUEST_REFUSED_ERROR,
456 "Recursive system.multicall strictly forbidden");
458 /* Perform the call. */
459 dispatch_call(env, registry, method_name, param_array, &result_val);
460 XMLRPC_FAIL_IF_FAULT(env);
462 /* Build our one-item result array. */
463 result = xmlrpc_build_value(env, "(V)", result_val);
464 XMLRPC_FAIL_IF_FAULT(env);
466 cleanup:
467 if (result_val)
468 xmlrpc_DECREF(result_val);
469 if (env->fault_occurred) {
470 if (result)
471 xmlrpc_DECREF(result);
472 return NULL;
474 return result;
479 static xmlrpc_value *
480 system_multicall(xmlrpc_env *env,
481 xmlrpc_value *param_array,
482 void *user_data) {
484 xmlrpc_registry *registry;
485 xmlrpc_value *methlist, *methinfo, *results, *result;
486 size_t size, i;
487 xmlrpc_env env2;
489 XMLRPC_ASSERT_ENV_OK(env);
490 XMLRPC_ASSERT_VALUE_OK(param_array);
491 XMLRPC_ASSERT_PTR_OK(user_data);
493 /* Error-handling preconditions. */
494 results = result = NULL;
495 xmlrpc_env_init(&env2);
497 /* Turn our arguments into something more useful. */
498 registry = (xmlrpc_registry*) user_data;
499 xmlrpc_parse_value(env, param_array, "(A)", &methlist);
500 XMLRPC_FAIL_IF_FAULT(env);
502 /* Create an empty result list. */
503 results = xmlrpc_build_value(env, "()");
504 XMLRPC_FAIL_IF_FAULT(env);
506 /* Loop over our input list, calling each method in turn. */
507 size = xmlrpc_array_size(env, methlist);
508 XMLRPC_ASSERT_ENV_OK(env);
509 for (i = 0; i < size; i++) {
510 methinfo = xmlrpc_array_get_item(env, methlist, (int)i);
511 XMLRPC_ASSERT_ENV_OK(env);
513 /* Call our method. */
514 xmlrpc_env_clean(&env2);
515 xmlrpc_env_init(&env2);
516 result = call_one_method(&env2, registry, methinfo);
518 /* Turn any fault into a structure. */
519 if (env2.fault_occurred) {
520 XMLRPC_ASSERT(result == NULL);
521 result =
522 xmlrpc_build_value(env, "{s:i,s:s}",
523 "faultCode", (xmlrpc_int32) env2.fault_code,
524 "faultString", env2.fault_string);
525 XMLRPC_FAIL_IF_FAULT(env);
528 /* Append this method result to our master array. */
529 xmlrpc_array_append_item(env, results, result);
530 xmlrpc_DECREF(result);
531 result = NULL;
532 XMLRPC_FAIL_IF_FAULT(env);
535 cleanup:
536 xmlrpc_env_clean(&env2);
537 if (result)
538 xmlrpc_DECREF(result);
539 if (env->fault_occurred) {
540 if (results)
541 xmlrpc_DECREF(results);
542 return NULL;
544 return results;
549 /*=========================================================================
550 ** system.listMethods
551 **=========================================================================
552 ** List all available methods by name.
555 static char *listMethods_help =
556 "Return an array of all available XML-RPC methods on this server.";
558 static xmlrpc_value *
559 system_listMethods(xmlrpc_env *env,
560 xmlrpc_value *param_array,
561 void *user_data) {
563 xmlrpc_registry *registry;
564 xmlrpc_value *method_names, *method_name, *method_info;
565 size_t size, i;
567 XMLRPC_ASSERT_ENV_OK(env);
568 XMLRPC_ASSERT_VALUE_OK(param_array);
569 XMLRPC_ASSERT_PTR_OK(user_data);
571 /* Error-handling preconditions. */
572 method_names = NULL;
574 /* Turn our arguments into something more useful. */
575 registry = (xmlrpc_registry*) user_data;
576 xmlrpc_parse_value(env, param_array, "()");
577 XMLRPC_FAIL_IF_FAULT(env);
579 /* Make sure we're allowed to introspect. */
580 if (!registry->_introspection_enabled)
581 XMLRPC_FAIL(env, XMLRPC_INTROSPECTION_DISABLED_ERROR,
582 "Introspection disabled for security reasons");
584 /* Iterate over all the methods in the registry, adding their names
585 ** to a list. */
586 method_names = xmlrpc_build_value(env, "()");
587 XMLRPC_FAIL_IF_FAULT(env);
588 size = xmlrpc_struct_size(env, registry->_methods);
589 XMLRPC_FAIL_IF_FAULT(env);
590 for (i = 0; i < size; i++) {
591 xmlrpc_struct_get_key_and_value(env, registry->_methods, (int)i,
592 &method_name, &method_info);
593 XMLRPC_FAIL_IF_FAULT(env);
594 xmlrpc_array_append_item(env, method_names, method_name);
595 XMLRPC_FAIL_IF_FAULT(env);
598 cleanup:
599 if (env->fault_occurred) {
600 if (method_names)
601 xmlrpc_DECREF(method_names);
602 return NULL;
604 return method_names;
609 /*=========================================================================
610 ** system.methodHelp
611 **=========================================================================
612 ** Get the help string for a particular method.
615 static char *methodHelp_help =
616 "Given the name of a method, return a help string.";
618 static xmlrpc_value *
619 system_methodHelp(xmlrpc_env *env,
620 xmlrpc_value *param_array,
621 void *user_data) {
623 xmlrpc_registry *registry;
624 char *method_name;
625 xmlrpc_value *ignored1, *ignored2, *ignored3, *help;
627 XMLRPC_ASSERT_ENV_OK(env);
628 XMLRPC_ASSERT_VALUE_OK(param_array);
629 XMLRPC_ASSERT_PTR_OK(user_data);
631 /* Turn our arguments into something more useful. */
632 registry = (xmlrpc_registry*) user_data;
633 xmlrpc_parse_value(env, param_array, "(s)", &method_name);
634 XMLRPC_FAIL_IF_FAULT(env);
636 /* Make sure we're allowed to introspect. */
637 if (!registry->_introspection_enabled)
638 XMLRPC_FAIL(env, XMLRPC_INTROSPECTION_DISABLED_ERROR,
639 "Introspection disabled for security reasons");
641 /* Get our documentation string. */
642 xmlrpc_parse_value(env, registry->_methods, "{s:(VVVV*),*}",
643 method_name, &ignored1, &ignored2, &ignored3, &help);
644 XMLRPC_FAIL_IF_FAULT(env);
646 cleanup:
647 if (env->fault_occurred)
648 return NULL;
649 xmlrpc_INCREF(help);
650 return help;
655 /*=========================================================================
656 ** system.methodSignature
657 **=========================================================================
658 ** Return an array of arrays describing possible signatures for this
659 ** method.
661 ** XXX - This is the ugliest function in the entire library.
664 static char *methodSignature_help =
665 "Given the name of a method, return an array of legal signatures. "
666 "Each signature is an array of strings. The first item of each signature "
667 "is the return type, and any others items are parameter types.";
669 static char *bad_sig_str =
670 "Application has incorrect method signature information";
672 #define BAD_SIG(env) \
673 XMLRPC_FAIL((env), XMLRPC_INTERNAL_ERROR, bad_sig_str);
675 static xmlrpc_value *
676 system_methodSignature(xmlrpc_env *env,
677 xmlrpc_value *param_array,
678 void *user_data) {
680 xmlrpc_registry *registry;
681 char *method_name;
682 xmlrpc_value *ignored1, *ignored2, *ignored3;
683 xmlrpc_value *item, *current, *result;
684 int at_sig_start;
685 char *sig, *code = 0;
687 XMLRPC_ASSERT_ENV_OK(env);
688 XMLRPC_ASSERT_VALUE_OK(param_array);
689 XMLRPC_ASSERT_PTR_OK(user_data);
691 /* Error-handling preconditions. */
692 item = current = result = NULL;
694 /* Turn our arguments into something more useful. */
695 registry = (xmlrpc_registry*) user_data;
696 xmlrpc_parse_value(env, param_array, "(s)", &method_name);
697 XMLRPC_FAIL_IF_FAULT(env);
699 /* Make sure we're allowed to introspect. */
700 if (!registry->_introspection_enabled)
701 XMLRPC_FAIL(env, XMLRPC_INTROSPECTION_DISABLED_ERROR,
702 "Introspection disabled for security reasons");
704 /* Get our signature string. */
705 xmlrpc_parse_value(env, registry->_methods, "{s:(VVsV*),*}",
706 method_name, &ignored1, &ignored2, &sig, &ignored3);
707 XMLRPC_FAIL_IF_FAULT(env);
709 if (sig[0] == '?' && sig[1] == '\0') {
710 /* No signature supplied. */
711 result = xmlrpc_build_value(env, "s", "undef");
712 XMLRPC_FAIL_IF_FAULT(env);
713 } else {
714 /* Build an array of arrays. */
715 current = xmlrpc_build_value(env, "()");
716 XMLRPC_FAIL_IF_FAULT(env);
717 result = xmlrpc_build_value(env, "(V)", current);
718 XMLRPC_FAIL_IF_FAULT(env);
719 at_sig_start = 1;
721 do {
722 next_loop:
724 /* Process the current code. */
725 switch (*(sig++)) {
726 case 'i': code = "int"; break;
727 case 'b': code = "boolean"; break;
728 case 'd': code = "double"; break;
729 case 's': code = "string"; break;
730 case '8': code = "dateTime.iso8601"; break;
731 case '6': code = "base64"; break;
732 case 'S': code = "struct"; break;
733 case 'A': code = "array"; break;
735 case ',':
736 /* Start a new signature array. */
737 if (at_sig_start)
738 BAD_SIG(env);
739 xmlrpc_DECREF(current);
740 current = xmlrpc_build_value(env, "()");
741 XMLRPC_FAIL_IF_FAULT(env);
742 xmlrpc_array_append_item(env, result, current);
743 XMLRPC_FAIL_IF_FAULT(env);
744 at_sig_start = 1;
745 goto next_loop;
747 default:
748 BAD_SIG(env);
751 /* Append the appropriate string to our current signature. */
752 item = xmlrpc_build_value(env, "s", code);
753 XMLRPC_FAIL_IF_FAULT(env);
754 xmlrpc_array_append_item(env, current, item);
755 xmlrpc_DECREF(item);
756 item = NULL;
757 XMLRPC_FAIL_IF_FAULT(env);
759 /* Advance to the next code, and skip over ':' if necessary. */
760 if (at_sig_start) {
761 if (*sig != ':')
762 BAD_SIG(env);
763 sig++;
764 at_sig_start = 0;
767 } while (*sig != '\0');
770 cleanup:
771 if (item)
772 xmlrpc_DECREF(item);
773 if (current)
774 xmlrpc_DECREF(current);
775 if (env->fault_occurred) {
776 if (result)
777 xmlrpc_DECREF(result);
778 return NULL;
780 return result;
785 /*=========================================================================
786 ** install_system_methods
787 **=========================================================================
788 ** Install the standard methods under system.*.
789 ** This particular function is highly experimental, and may disappear
790 ** without warning.
793 static void
794 install_system_methods(xmlrpc_env *env, xmlrpc_registry *registry) {
796 xmlrpc_registry_add_method_w_doc(env, registry, NULL,
797 "system.listMethods",
798 &system_listMethods, registry,
799 "A:", listMethods_help);
800 XMLRPC_FAIL_IF_FAULT(env);
801 xmlrpc_registry_add_method_w_doc(env, registry, NULL,
802 "system.methodSignature",
803 &system_methodSignature, registry,
804 "A:s", methodSignature_help);
805 XMLRPC_FAIL_IF_FAULT(env);
806 xmlrpc_registry_add_method_w_doc(env, registry, NULL,
807 "system.methodHelp",
808 &system_methodHelp, registry,
809 "s:s", methodHelp_help);
810 XMLRPC_FAIL_IF_FAULT(env);
811 xmlrpc_registry_add_method_w_doc(env, registry, NULL,
812 "system.multicall",
813 &system_multicall, registry,
814 "A:A", multicall_help);
815 XMLRPC_FAIL_IF_FAULT(env);
817 cleanup:
818 return;