diff options
author | Andy Cedilnik <andy.cedilnik@kitware.com> | 2005-02-22 18:08:27 (GMT) |
---|---|---|
committer | Andy Cedilnik <andy.cedilnik@kitware.com> | 2005-02-22 18:08:27 (GMT) |
commit | b9b4ea0f7bbf0313d8aa5e354ee56f912969763c (patch) | |
tree | ba5e857cda91949be14f508e6df490e1e2176f40 /Utilities/cmxmlrpc/xmlrpc_registry.c | |
parent | bfcb4b693763bb11f841094d2ca9852a64e5d33b (diff) | |
download | CMake-b9b4ea0f7bbf0313d8aa5e354ee56f912969763c.zip CMake-b9b4ea0f7bbf0313d8aa5e354ee56f912969763c.tar.gz CMake-b9b4ea0f7bbf0313d8aa5e354ee56f912969763c.tar.bz2 |
ENH: Initial import
Diffstat (limited to 'Utilities/cmxmlrpc/xmlrpc_registry.c')
-rw-r--r-- | Utilities/cmxmlrpc/xmlrpc_registry.c | 829 |
1 files changed, 829 insertions, 0 deletions
diff --git a/Utilities/cmxmlrpc/xmlrpc_registry.c b/Utilities/cmxmlrpc/xmlrpc_registry.c new file mode 100644 index 0000000..41e5ac1 --- /dev/null +++ b/Utilities/cmxmlrpc/xmlrpc_registry.c @@ -0,0 +1,829 @@ +/* Copyright (C) 2001 by First Peer, Inc. All rights reserved. +** Copyright (C) 2001 by Eric Kidd. All rights reserved. +** Copyright (C) 2001 by Luke Howard. All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +** SUCH DAMAGE. */ + +#include "xmlrpc_config.h" + +#include <stdlib.h> +#include <string.h> + +#include "xmlrpc.h" +#include "xmlrpc_server.h" +#include "xmlrpc_int.h" + +/*========================================================================= +** XML-RPC Server Method Registry +**========================================================================= +** A method registry maintains a list of functions, and handles +** dispatching. To build an XML-RPC server, just add a communications +** protocol. :-) +*/ + +static void +install_system_methods (xmlrpc_env *env, xmlrpc_registry *registry); + +xmlrpc_registry * +xmlrpc_registry_new(xmlrpc_env *env) { + + xmlrpc_value *methods; + xmlrpc_registry *registry; + int registry_valid; + + XMLRPC_ASSERT_ENV_OK(env); + + /* Error-handling preconditions. */ + methods = NULL; + registry = NULL; + registry_valid = 0; + + /* Allocate our memory. */ + methods = xmlrpc_struct_new(env); + XMLRPC_FAIL_IF_FAULT(env); + registry = (xmlrpc_registry*) malloc(sizeof(xmlrpc_registry)); + XMLRPC_FAIL_IF_NULL(registry, env, XMLRPC_INTERNAL_ERROR, + "Could not allocate memory for registry"); + + /* Set everything up. */ + registry->_introspection_enabled = 1; + registry->_methods = methods; + registry->_default_method = NULL; + registry->_preinvoke_method = NULL; + registry_valid = 1; + + /* Install our system methods. */ + install_system_methods(env, registry); + XMLRPC_FAIL_IF_FAULT(env); + + cleanup: + if (env->fault_occurred) { + if (registry_valid) { + xmlrpc_registry_free(registry); + } else { + if (methods) + xmlrpc_DECREF(methods); + if (registry) + free(registry); + } + return NULL; + } + return registry; +} + + + +void +xmlrpc_registry_free(xmlrpc_registry * registry) { + + XMLRPC_ASSERT_PTR_OK(registry); + XMLRPC_ASSERT(registry->_methods != XMLRPC_BAD_POINTER); + + xmlrpc_DECREF(registry->_methods); + registry->_methods = XMLRPC_BAD_POINTER; + if (registry->_default_method != NULL) + xmlrpc_DECREF(registry->_default_method); + if (registry->_preinvoke_method != NULL) + xmlrpc_DECREF(registry->_preinvoke_method); + free(registry); +} + + + +/*========================================================================= +** xmlrpc_registry_disable_introspection +**========================================================================= +** See xmlrpc.h for more documentation. +*/ + +void +xmlrpc_registry_disable_introspection(xmlrpc_registry * registry) { + XMLRPC_ASSERT_PTR_OK(registry); + registry->_introspection_enabled = 0; +} + + + +/*========================================================================= +** xmlrpc_registry_add_method +**========================================================================= +** See xmlrpc.h for more documentation. +*/ + +void +xmlrpc_registry_add_method(xmlrpc_env *env, + xmlrpc_registry *registry, + const char *host, + const char *method_name, + xmlrpc_method method, + void *user_data) { + + xmlrpc_registry_add_method_w_doc (env, registry, host, method_name, + method, user_data, "?", + "No help is available for this method."); +} + + + +void +xmlrpc_registry_add_method_w_doc(xmlrpc_env *env, + xmlrpc_registry *registry, + const char *host, + const char *method_name, + xmlrpc_method method, + void *user_data, + const char *signature, + const char *help) { + xmlrpc_value *method_info; + + XMLRPC_ASSERT_ENV_OK(env); + XMLRPC_ASSERT_PTR_OK(registry); + XMLRPC_ASSERT(host == NULL); + XMLRPC_ASSERT_PTR_OK(method_name); + XMLRPC_ASSERT_PTR_OK(method); + + /* Error-handling preconditions. */ + method_info = NULL; + + /* Store our method and user data into our hash table. */ + method_info = xmlrpc_build_value(env, "(ppss)", (void*) method, user_data, + signature, help); + XMLRPC_FAIL_IF_FAULT(env); + xmlrpc_struct_set_value(env, registry->_methods, method_name, method_info); + XMLRPC_FAIL_IF_FAULT(env); + + cleanup: + if (method_info) + xmlrpc_DECREF(method_info); + +} + + + +/*========================================================================= +** xmlrpc_registry_set_default_method +**========================================================================= +** See xmlrpc.h for more documentation. +*/ + +void +xmlrpc_registry_set_default_method(xmlrpc_env *env, + xmlrpc_registry *registry, + xmlrpc_default_method handler, + void *user_data) { + xmlrpc_value *method_info; + + XMLRPC_ASSERT_ENV_OK(env); + XMLRPC_ASSERT_PTR_OK(registry); + XMLRPC_ASSERT_PTR_OK(handler); + + /* Error-handling preconditions. */ + method_info = NULL; + + /* Store our method and user data into our hash table. */ + method_info = xmlrpc_build_value(env, "(pp)", (void*) handler, user_data); + XMLRPC_FAIL_IF_FAULT(env); + + /* Dispose of any pre-existing default method and install ours. */ + if (registry->_default_method) + xmlrpc_DECREF(registry->_default_method); + registry->_default_method = method_info; + +cleanup: + if (env->fault_occurred) { + if (method_info) + xmlrpc_DECREF(method_info); + } +} + + + +/*========================================================================= +** xmlrpc_registry_set_preinvoke_method +**========================================================================= +** See xmlrpc.h for more documentation. +*/ + +void +xmlrpc_registry_set_preinvoke_method(xmlrpc_env *env, + xmlrpc_registry *registry, + xmlrpc_preinvoke_method handler, + void *user_data) { + xmlrpc_value *method_info; + + XMLRPC_ASSERT_ENV_OK(env); + XMLRPC_ASSERT_PTR_OK(registry); + XMLRPC_ASSERT_PTR_OK(handler); + + /* Error-handling preconditions. */ + method_info = NULL; + + /* Store our method and user data into our hash table. */ + method_info = xmlrpc_build_value(env, "(pp)", (void*) handler, user_data); + XMLRPC_FAIL_IF_FAULT(env); + + /* Dispose of any pre-existing preinvoke method and install ours. */ + if (registry->_preinvoke_method) + xmlrpc_DECREF(registry->_preinvoke_method); + registry->_preinvoke_method = method_info; + + cleanup: + if (env->fault_occurred) { + if (method_info) + xmlrpc_DECREF(method_info); + } +} + + + +/*========================================================================= +** dispatch_call +**========================================================================= +** An internal method which actually does the dispatch. This may get +** prettified and exported at some point in the future. +*/ + +static void +callPreinvokeMethodIfAny(xmlrpc_env * const envP, + xmlrpc_registry * const registryP, + const char * const methodName, + xmlrpc_value * const paramArrayP) { + + /* Get the preinvoke method, if it is set. */ + if (registryP->_preinvoke_method) { + xmlrpc_preinvoke_method preinvoke_method; + void * user_data; + + xmlrpc_parse_value(envP, registryP->_preinvoke_method, "(pp)", + &preinvoke_method, &user_data); + if (!envP->fault_occurred) + (*preinvoke_method)(envP, methodName, + paramArrayP, user_data); + } +} + + + +static void +callDefaultMethod(xmlrpc_env * const envP, + xmlrpc_value * const defaultMethodInfo, + const char * const methodName, + xmlrpc_value * const paramArrayP, + xmlrpc_value ** const resultPP) { + + xmlrpc_default_method default_method; + void * user_data; + + xmlrpc_parse_value(envP, defaultMethodInfo, "(pp)", + &default_method, &user_data); + + if (!envP->fault_occurred) + *resultPP = (*default_method)(envP, NULL, methodName, + paramArrayP, user_data); +} + + + +static void +callNamedMethod(xmlrpc_env * const envP, + xmlrpc_value * const methodInfo, + xmlrpc_value * const paramArrayP, + xmlrpc_value ** const resultPP) { + + xmlrpc_method method; + void * user_data; + + xmlrpc_parse_value(envP, methodInfo, "(pp*)", &method, &user_data); + if (!envP->fault_occurred) + *resultPP = (*method)(envP, paramArrayP, user_data); +} + + + +static void +dispatch_call(xmlrpc_env * const envP, + xmlrpc_registry * const registryP, + const char * const methodName, + xmlrpc_value * const paramArrayP, + xmlrpc_value ** const resultPP) { + + callPreinvokeMethodIfAny(envP, registryP, methodName, paramArrayP); + if (!envP->fault_occurred) { + xmlrpc_value * method_info; + + /* Look up the method info for the named method. */ + xmlrpc_struct_find_value(envP, registryP->_methods, + methodName, &method_info); + if (!envP->fault_occurred) { + if (method_info) + callNamedMethod(envP, method_info, paramArrayP, resultPP); + else { + if (registryP->_default_method) + callDefaultMethod(envP, registryP->_default_method, + methodName, paramArrayP, + resultPP); + else { + /* No matching method, and no default. */ + xmlrpc_env_set_fault_formatted( + envP, XMLRPC_NO_SUCH_METHOD_ERROR, + "Method '%s' not defined", methodName); + } + } + } + } + /* For backward compatibility, for sloppy users: */ + if (envP->fault_occurred) + *resultPP = NULL; +} + + + +/*========================================================================= +** xmlrpc_registry_process_call +**========================================================================= +** +*/ + +xmlrpc_mem_block * +xmlrpc_registry_process_call(xmlrpc_env * const envP, + xmlrpc_registry * const registryP, + const char * const host ATTR_UNUSED, + const char * const xml_data, + size_t const xml_len) { + + xmlrpc_mem_block * output; + + XMLRPC_ASSERT_ENV_OK(envP); + XMLRPC_ASSERT_PTR_OK(xml_data); + + xmlrpc_traceXml("XML-RPC CALL", xml_data, xml_len); + + /* Allocate our output buffer. + ** If this fails, we need to die in a special fashion. */ + output = XMLRPC_MEMBLOCK_NEW(char, envP, 0); + if (!envP->fault_occurred) { + const char * methodName; + xmlrpc_value * paramArray; + xmlrpc_env fault; + + xmlrpc_env_init(&fault); + + xmlrpc_parse_call(&fault, xml_data, xml_len, + &methodName, ¶mArray); + + if (!fault.fault_occurred) { + xmlrpc_value * result; + + dispatch_call(&fault, registryP, methodName, paramArray, &result); + + if (!fault.fault_occurred) { + xmlrpc_serialize_response(envP, output, result); + + /* A comment here used to say that + xmlrpc_serialize_response() could fail and "leave + stuff in the buffer." Don't know what that means, + but it sounds like something that needs to be + fixed. The old code aborted the program here if + xmlrpc_serialize_repsonse() failed. 04.11.17 + */ + xmlrpc_DECREF(result); + } + xmlrpc_strfree(methodName); + xmlrpc_DECREF(paramArray); + } + if (!envP->fault_occurred && fault.fault_occurred) + xmlrpc_serialize_fault(envP, output, &fault); + + xmlrpc_env_clean(&fault); + + if (envP->fault_occurred) + XMLRPC_MEMBLOCK_FREE(char, output); + else + xmlrpc_traceXml("XML-RPC RESPONSE", + XMLRPC_MEMBLOCK_CONTENTS(char, output), + XMLRPC_MEMBLOCK_SIZE(char, output)); + } + return output; +} + + + +/*========================================================================= +** system.multicall +**========================================================================= +** Low-tech support for transparent, boxed methods. +*/ + +static char *multicall_help = +"Process an array of calls, and return an array of results. Calls should " +"be structs of the form {'methodName': string, 'params': array}. Each " +"result will either be a single-item array containg the result value, or " +"a struct of the form {'faultCode': int, 'faultString': string}. This " +"is useful when you need to make lots of small calls without lots of " +"round trips."; + +static xmlrpc_value * +call_one_method(xmlrpc_env *env, xmlrpc_registry *registry, + xmlrpc_value *method_info) { + + xmlrpc_value *result_val, *result; + char *method_name; + xmlrpc_value *param_array; + + /* Error-handling preconditions. */ + result = result_val = NULL; + + /* Extract our method name and parameters. */ + xmlrpc_parse_value(env, method_info, "{s:s,s:A,*}", + "methodName", &method_name, + "params", ¶m_array); + XMLRPC_FAIL_IF_FAULT(env); + + /* Watch out for a deep recursion attack. */ + if (strcmp(method_name, "system.multicall") == 0) + XMLRPC_FAIL(env, XMLRPC_REQUEST_REFUSED_ERROR, + "Recursive system.multicall strictly forbidden"); + + /* Perform the call. */ + dispatch_call(env, registry, method_name, param_array, &result_val); + XMLRPC_FAIL_IF_FAULT(env); + + /* Build our one-item result array. */ + result = xmlrpc_build_value(env, "(V)", result_val); + XMLRPC_FAIL_IF_FAULT(env); + + cleanup: + if (result_val) + xmlrpc_DECREF(result_val); + if (env->fault_occurred) { + if (result) + xmlrpc_DECREF(result); + return NULL; + } + return result; +} + + + +static xmlrpc_value * +system_multicall(xmlrpc_env *env, + xmlrpc_value *param_array, + void *user_data) { + + xmlrpc_registry *registry; + xmlrpc_value *methlist, *methinfo, *results, *result; + size_t size, i; + xmlrpc_env env2; + + XMLRPC_ASSERT_ENV_OK(env); + XMLRPC_ASSERT_VALUE_OK(param_array); + XMLRPC_ASSERT_PTR_OK(user_data); + + /* Error-handling preconditions. */ + results = result = NULL; + xmlrpc_env_init(&env2); + + /* Turn our arguments into something more useful. */ + registry = (xmlrpc_registry*) user_data; + xmlrpc_parse_value(env, param_array, "(A)", &methlist); + XMLRPC_FAIL_IF_FAULT(env); + + /* Create an empty result list. */ + results = xmlrpc_build_value(env, "()"); + XMLRPC_FAIL_IF_FAULT(env); + + /* Loop over our input list, calling each method in turn. */ + size = xmlrpc_array_size(env, methlist); + XMLRPC_ASSERT_ENV_OK(env); + for (i = 0; i < size; i++) { + methinfo = xmlrpc_array_get_item(env, methlist, i); + XMLRPC_ASSERT_ENV_OK(env); + + /* Call our method. */ + xmlrpc_env_clean(&env2); + xmlrpc_env_init(&env2); + result = call_one_method(&env2, registry, methinfo); + + /* Turn any fault into a structure. */ + if (env2.fault_occurred) { + XMLRPC_ASSERT(result == NULL); + result = + xmlrpc_build_value(env, "{s:i,s:s}", + "faultCode", (xmlrpc_int32) env2.fault_code, + "faultString", env2.fault_string); + XMLRPC_FAIL_IF_FAULT(env); + } + + /* Append this method result to our master array. */ + xmlrpc_array_append_item(env, results, result); + xmlrpc_DECREF(result); + result = NULL; + XMLRPC_FAIL_IF_FAULT(env); + } + + cleanup: + xmlrpc_env_clean(&env2); + if (result) + xmlrpc_DECREF(result); + if (env->fault_occurred) { + if (results) + xmlrpc_DECREF(results); + return NULL; + } + return results; +} + + + +/*========================================================================= +** system.listMethods +**========================================================================= +** List all available methods by name. +*/ + +static char *listMethods_help = +"Return an array of all available XML-RPC methods on this server."; + +static xmlrpc_value * +system_listMethods(xmlrpc_env *env, + xmlrpc_value *param_array, + void *user_data) { + + xmlrpc_registry *registry; + xmlrpc_value *method_names, *method_name, *method_info; + size_t size, i; + + XMLRPC_ASSERT_ENV_OK(env); + XMLRPC_ASSERT_VALUE_OK(param_array); + XMLRPC_ASSERT_PTR_OK(user_data); + + /* Error-handling preconditions. */ + method_names = NULL; + + /* Turn our arguments into something more useful. */ + registry = (xmlrpc_registry*) user_data; + xmlrpc_parse_value(env, param_array, "()"); + XMLRPC_FAIL_IF_FAULT(env); + + /* Make sure we're allowed to introspect. */ + if (!registry->_introspection_enabled) + XMLRPC_FAIL(env, XMLRPC_INTROSPECTION_DISABLED_ERROR, + "Introspection disabled for security reasons"); + + /* Iterate over all the methods in the registry, adding their names + ** to a list. */ + method_names = xmlrpc_build_value(env, "()"); + XMLRPC_FAIL_IF_FAULT(env); + size = xmlrpc_struct_size(env, registry->_methods); + XMLRPC_FAIL_IF_FAULT(env); + for (i = 0; i < size; i++) { + xmlrpc_struct_get_key_and_value(env, registry->_methods, i, + &method_name, &method_info); + XMLRPC_FAIL_IF_FAULT(env); + xmlrpc_array_append_item(env, method_names, method_name); + XMLRPC_FAIL_IF_FAULT(env); + } + + cleanup: + if (env->fault_occurred) { + if (method_names) + xmlrpc_DECREF(method_names); + return NULL; + } + return method_names; +} + + + +/*========================================================================= +** system.methodHelp +**========================================================================= +** Get the help string for a particular method. +*/ + +static char *methodHelp_help = +"Given the name of a method, return a help string."; + +static xmlrpc_value * +system_methodHelp(xmlrpc_env *env, + xmlrpc_value *param_array, + void *user_data) { + + xmlrpc_registry *registry; + char *method_name; + xmlrpc_value *ignored1, *ignored2, *ignored3, *help; + + XMLRPC_ASSERT_ENV_OK(env); + XMLRPC_ASSERT_VALUE_OK(param_array); + XMLRPC_ASSERT_PTR_OK(user_data); + + /* Turn our arguments into something more useful. */ + registry = (xmlrpc_registry*) user_data; + xmlrpc_parse_value(env, param_array, "(s)", &method_name); + XMLRPC_FAIL_IF_FAULT(env); + + /* Make sure we're allowed to introspect. */ + if (!registry->_introspection_enabled) + XMLRPC_FAIL(env, XMLRPC_INTROSPECTION_DISABLED_ERROR, + "Introspection disabled for security reasons"); + + /* Get our documentation string. */ + xmlrpc_parse_value(env, registry->_methods, "{s:(VVVV*),*}", + method_name, &ignored1, &ignored2, &ignored3, &help); + XMLRPC_FAIL_IF_FAULT(env); + + cleanup: + if (env->fault_occurred) + return NULL; + xmlrpc_INCREF(help); + return help; +} + + + +/*========================================================================= +** system.methodSignature +**========================================================================= +** Return an array of arrays describing possible signatures for this +** method. +** +** XXX - This is the ugliest function in the entire library. +*/ + +static char *methodSignature_help = +"Given the name of a method, return an array of legal signatures. " +"Each signature is an array of strings. The first item of each signature " +"is the return type, and any others items are parameter types."; + +static char *bad_sig_str = +"Application has incorrect method signature information"; + +#define BAD_SIG(env) \ + XMLRPC_FAIL((env), XMLRPC_INTERNAL_ERROR, bad_sig_str); + +static xmlrpc_value * +system_methodSignature(xmlrpc_env *env, + xmlrpc_value *param_array, + void *user_data) { + + xmlrpc_registry *registry; + char *method_name; + xmlrpc_value *ignored1, *ignored2, *ignored3; + xmlrpc_value *item, *current, *result; + int at_sig_start; + char *sig, *code; + + XMLRPC_ASSERT_ENV_OK(env); + XMLRPC_ASSERT_VALUE_OK(param_array); + XMLRPC_ASSERT_PTR_OK(user_data); + + /* Error-handling preconditions. */ + item = current = result = NULL; + + /* Turn our arguments into something more useful. */ + registry = (xmlrpc_registry*) user_data; + xmlrpc_parse_value(env, param_array, "(s)", &method_name); + XMLRPC_FAIL_IF_FAULT(env); + + /* Make sure we're allowed to introspect. */ + if (!registry->_introspection_enabled) + XMLRPC_FAIL(env, XMLRPC_INTROSPECTION_DISABLED_ERROR, + "Introspection disabled for security reasons"); + + /* Get our signature string. */ + xmlrpc_parse_value(env, registry->_methods, "{s:(VVsV*),*}", + method_name, &ignored1, &ignored2, &sig, &ignored3); + XMLRPC_FAIL_IF_FAULT(env); + + if (sig[0] == '?' && sig[1] == '\0') { + /* No signature supplied. */ + result = xmlrpc_build_value(env, "s", "undef"); + XMLRPC_FAIL_IF_FAULT(env); + } else { + /* Build an array of arrays. */ + current = xmlrpc_build_value(env, "()"); + XMLRPC_FAIL_IF_FAULT(env); + result = xmlrpc_build_value(env, "(V)", current); + XMLRPC_FAIL_IF_FAULT(env); + at_sig_start = 1; + + do { + next_loop: + + /* Process the current code. */ + switch (*(sig++)) { + case 'i': code = "int"; break; + case 'b': code = "boolean"; break; + case 'd': code = "double"; break; + case 's': code = "string"; break; + case '8': code = "dateTime.iso8601"; break; + case '6': code = "base64"; break; + case 'S': code = "struct"; break; + case 'A': code = "array"; break; + + case ',': + /* Start a new signature array. */ + if (at_sig_start) + BAD_SIG(env); + xmlrpc_DECREF(current); + current = xmlrpc_build_value(env, "()"); + XMLRPC_FAIL_IF_FAULT(env); + xmlrpc_array_append_item(env, result, current); + XMLRPC_FAIL_IF_FAULT(env); + at_sig_start = 1; + goto next_loop; + + default: + BAD_SIG(env); + } + + /* Append the appropriate string to our current signature. */ + item = xmlrpc_build_value(env, "s", code); + XMLRPC_FAIL_IF_FAULT(env); + xmlrpc_array_append_item(env, current, item); + xmlrpc_DECREF(item); + item = NULL; + XMLRPC_FAIL_IF_FAULT(env); + + /* Advance to the next code, and skip over ':' if necessary. */ + if (at_sig_start) { + if (*sig != ':') + BAD_SIG(env); + sig++; + at_sig_start = 0; + } + + } while (*sig != '\0'); + } + + cleanup: + if (item) + xmlrpc_DECREF(item); + if (current) + xmlrpc_DECREF(current); + if (env->fault_occurred) { + if (result) + xmlrpc_DECREF(result); + return NULL; + } + return result; +} + + + +/*========================================================================= +** install_system_methods +**========================================================================= +** Install the standard methods under system.*. +** This particular function is highly experimental, and may disappear +** without warning. +*/ + +static void +install_system_methods(xmlrpc_env *env, xmlrpc_registry *registry) { + + xmlrpc_registry_add_method_w_doc(env, registry, NULL, + "system.listMethods", + &system_listMethods, registry, + "A:", listMethods_help); + XMLRPC_FAIL_IF_FAULT(env); + xmlrpc_registry_add_method_w_doc(env, registry, NULL, + "system.methodSignature", + &system_methodSignature, registry, + "A:s", methodSignature_help); + XMLRPC_FAIL_IF_FAULT(env); + xmlrpc_registry_add_method_w_doc(env, registry, NULL, + "system.methodHelp", + &system_methodHelp, registry, + "s:s", methodHelp_help); + XMLRPC_FAIL_IF_FAULT(env); + xmlrpc_registry_add_method_w_doc(env, registry, NULL, + "system.multicall", + &system_multicall, registry, + "A:A", multicall_help); + XMLRPC_FAIL_IF_FAULT(env); + + cleanup: + return; +} |