initial load of upstream version 1.06.32
[xmlrpc-c] / src / system_method.c
1 /* Copyright information is at end of file */
2
3 #include "xmlrpc_config.h"
4
5 #include <assert.h>
6 #include <stdlib.h>
7 #include <string.h>
8
9 #include "xmlrpc-c/base_int.h"
10 #include "xmlrpc-c/string_int.h"
11 #include "xmlrpc-c/base.h"
12 #include "xmlrpc-c/server.h"
13 #include "registry.h"
14
15 #include "system_method.h"
16
17
18 struct systemMethodReg {
19 /*----------------------------------------------------------------------------
20    Information needed to register a system method
21 -----------------------------------------------------------------------------*/
22     const char *  const methodName;
23     xmlrpc_method const methodFunction;
24     const char *  const signatureString;
25     const char *  const helpText;
26 };
27
28
29
30 void 
31 xmlrpc_registry_disable_introspection(xmlrpc_registry * const registryP) {
32
33     XMLRPC_ASSERT_PTR_OK(registryP);
34
35     registryP->_introspection_enabled = false;
36 }
37
38
39
40 static void
41 translateTypeSpecifierToName(xmlrpc_env *  const envP,
42                              char          const typeSpecifier,
43                              const char ** const typeNameP) {
44
45     switch (typeSpecifier) {
46     case 'i': *typeNameP = "int";              break;
47     case 'b': *typeNameP = "boolean";          break;
48     case 'd': *typeNameP = "double";           break;
49     case 's': *typeNameP = "string";           break;
50     case '8': *typeNameP = "dateTime.iso8601"; break;
51     case '6': *typeNameP = "base64";           break;
52     case 'S': *typeNameP = "struct";           break;
53     case 'A': *typeNameP = "array";            break;
54     case 'n': *typeNameP = "nil";              break;
55     default:
56         xmlrpc_faultf(envP, 
57                       "Method registry contains invalid signature "
58                       "data.  It contains the type specifier '%c'",
59                       typeSpecifier);
60     }
61 }
62                 
63
64
65 static void
66 parseOneTypeSpecifier(xmlrpc_env *   const envP,
67                       const char *   const startP,
68                       xmlrpc_value * const signatureP,
69                       const char **  const nextP) {
70 /*----------------------------------------------------------------------------
71    Parse one type specifier at 'startP' within a signature string.
72
73    Add the appropriate item for it to the array 'signatureP'.
74
75    Return as *nextP the location the signature string just past the
76    type specifier, and also past the colon that comes after the 
77    type specifier for a return value.
78 -----------------------------------------------------------------------------*/
79     const char * typeName;
80     const char * cursorP;
81
82     cursorP = startP;
83                 
84     translateTypeSpecifierToName(envP, *cursorP, &typeName);
85     
86     if (!envP->fault_occurred) {
87         xmlrpc_value * typeP;
88         int sigArraySize;
89         
90         /* Append the appropriate string to the signature. */
91         typeP = xmlrpc_string_new(envP, typeName);
92         xmlrpc_array_append_item(envP, signatureP, typeP);
93         xmlrpc_DECREF(typeP);
94         
95         ++cursorP; /* move past the type specifier */
96         
97         sigArraySize = xmlrpc_array_size(envP, signatureP);
98         if (!envP->fault_occurred) {
99             if (sigArraySize == 1) {
100                 /* We parsed off the result type, so we should now
101                    see the colon that separates the result type from
102                    the parameter types
103                 */
104                 if (*cursorP != ':')
105                     xmlrpc_faultf(envP, "No colon (':') after "
106                                   "the result type specifier");
107                 else
108                     ++cursorP;
109             }
110         }
111     }
112     *nextP = cursorP;
113 }
114
115
116
117 static void
118 parseOneSignature(xmlrpc_env *    const envP,
119                   const char *    const startP,
120                   xmlrpc_value ** const signaturePP,
121                   const char **   const nextP) {
122 /*----------------------------------------------------------------------------
123    Parse one signature from the signature string that starts at 'startP'.
124
125    Return that signature as an array xmlrpc_value pointer
126    *signaturePP.  The array has one element for the return value,
127    followed by one element for each parameter described in the
128    signature.  That element is a string naming the return value or
129    parameter type, e.g. "int".
130
131    Return as *nextP the location in the signature string of the next
132    signature (i.e. right after the next comma).  If there is no next
133    signature (the string ends before any comma), make it point to the
134    terminating NUL.
135 -----------------------------------------------------------------------------*/
136     xmlrpc_value * signatureP;
137
138     signatureP = xmlrpc_array_new(envP);  /* Start with empty array */
139     if (!envP->fault_occurred) {
140         const char * cursorP;
141
142         cursorP = startP;  /* start at the beginning */
143
144         while (!envP->fault_occurred && *cursorP != ',' && *cursorP != '\0')
145             parseOneTypeSpecifier(envP, cursorP, signatureP, &cursorP);
146
147         if (!envP->fault_occurred) {
148             if (xmlrpc_array_size(envP, signatureP) < 1)
149                 xmlrpc_faultf(envP, "empty signature (a signature "
150                               "must have at least  return value type)");
151             if (*cursorP != '\0') {
152                 assert(*cursorP == ',');
153                 ++cursorP;
154             }
155             *nextP = cursorP;
156         }
157         if (envP->fault_occurred)
158             xmlrpc_DECREF(signatureP);
159         else
160             *signaturePP = signatureP;
161     }
162 }    
163
164
165
166 void
167 xmlrpc_buildSignatureArray(xmlrpc_env *    const envP,
168                            const char *    const sigListString,
169                            xmlrpc_value ** const resultPP) {
170 /*----------------------------------------------------------------------------
171   Turn the signature string 'sig' (e.g. "ii,s") into an array
172   as *resultP.  The array contains one element for each signature in
173   the string.  (Signatures are separated by commas.  The "ii,s" example
174   is two signatures: "ii" and "s").  Each element is itself an array
175   as described under parseOneSignature().
176 -----------------------------------------------------------------------------*/
177     xmlrpc_value * signatureListP;
178
179     signatureListP = xmlrpc_array_new(envP);
180     if (!envP->fault_occurred) {
181         if (sigListString == NULL || xmlrpc_streq(sigListString, "?")) {
182             /* No signatures -- leave the array empty */
183         } else {
184             const char * cursorP;
185             
186             cursorP = &sigListString[0];
187             
188             while (!envP->fault_occurred && *cursorP != '\0') {
189                 xmlrpc_value * signatureP;
190                 
191                 parseOneSignature(envP, cursorP, &signatureP, &cursorP);
192                 
193                 /* cursorP now points at next signature in the list or the
194                    terminating NUL.
195                 */
196                 
197                 if (!envP->fault_occurred) {
198                     xmlrpc_array_append_item(envP, signatureListP, signatureP);
199                     xmlrpc_DECREF(signatureP);
200                 }
201             }
202             if (!envP->fault_occurred) {
203                 unsigned int const arraySize = 
204                     xmlrpc_array_size(envP, signatureListP);
205                 XMLRPC_ASSERT_ENV_OK(envP);
206                 if (arraySize < 1)
207                     xmlrpc_faultf(envP, "Signature string is empty.");
208             }
209         }
210         if (envP->fault_occurred)
211             xmlrpc_DECREF(signatureListP);
212     }
213     *resultPP = signatureListP;
214 }
215
216
217
218 /*=========================================================================
219   system.multicall
220 =========================================================================*/
221
222 static xmlrpc_value *
223 call_one_method(xmlrpc_env *env, xmlrpc_registry *registry,
224                 xmlrpc_value *method_info) {
225
226     xmlrpc_value *result_val, *result;
227     char *method_name;
228     xmlrpc_value *param_array;
229
230     /* Error-handling preconditions. */
231     result = result_val = NULL;
232     
233     /* Extract our method name and parameters. */
234     xmlrpc_parse_value(env, method_info, "{s:s,s:A,*}",
235                        "methodName", &method_name,
236                        "params", &param_array);
237     XMLRPC_FAIL_IF_FAULT(env);
238
239     /* Watch out for a deep recursion attack. */
240     if (strcmp(method_name, "system.multicall") == 0)
241         XMLRPC_FAIL(env, XMLRPC_REQUEST_REFUSED_ERROR,
242                     "Recursive system.multicall strictly forbidden");
243     
244     /* Perform the call. */
245     xmlrpc_dispatchCall(env, registry, method_name, param_array, &result_val);
246     XMLRPC_FAIL_IF_FAULT(env);
247     
248     /* Build our one-item result array. */
249     result = xmlrpc_build_value(env, "(V)", result_val);
250     XMLRPC_FAIL_IF_FAULT(env);
251     
252  cleanup:
253     if (result_val)
254         xmlrpc_DECREF(result_val);
255     if (env->fault_occurred) {
256         if (result)
257             xmlrpc_DECREF(result);
258         return NULL;
259     }
260     return result;
261 }
262
263
264
265 static xmlrpc_value *
266 system_multicall(xmlrpc_env *env,
267                  xmlrpc_value *param_array,
268                  void *user_data) {
269
270     xmlrpc_registry *registry;
271     xmlrpc_value *methlist, *methinfo, *results, *result;
272     size_t size, i;
273     xmlrpc_env env2;
274
275     XMLRPC_ASSERT_ENV_OK(env);
276     XMLRPC_ASSERT_VALUE_OK(param_array);
277     XMLRPC_ASSERT_PTR_OK(user_data);
278
279     /* Error-handling preconditions. */
280     results = result = NULL;
281     xmlrpc_env_init(&env2);
282     
283     /* Turn our arguments into something more useful. */
284     registry = (xmlrpc_registry*) user_data;
285     xmlrpc_parse_value(env, param_array, "(A)", &methlist);
286     XMLRPC_FAIL_IF_FAULT(env);
287
288     /* Create an empty result list. */
289     results = xmlrpc_build_value(env, "()");
290     XMLRPC_FAIL_IF_FAULT(env);
291
292     /* Loop over our input list, calling each method in turn. */
293     size = xmlrpc_array_size(env, methlist);
294     XMLRPC_ASSERT_ENV_OK(env);
295     for (i = 0; i < size; i++) {
296         methinfo = xmlrpc_array_get_item(env, methlist, i);
297         XMLRPC_ASSERT_ENV_OK(env);
298         
299         /* Call our method. */
300         xmlrpc_env_clean(&env2);
301         xmlrpc_env_init(&env2);
302         result = call_one_method(&env2, registry, methinfo);
303         
304         /* Turn any fault into a structure. */
305         if (env2.fault_occurred) {
306             XMLRPC_ASSERT(result == NULL);
307             result = 
308                 xmlrpc_build_value(env, "{s:i,s:s}",
309                                    "faultCode", (xmlrpc_int32) env2.fault_code,
310                                    "faultString", env2.fault_string);
311             XMLRPC_FAIL_IF_FAULT(env);
312         }
313         
314         /* Append this method result to our master array. */
315         xmlrpc_array_append_item(env, results, result);
316         xmlrpc_DECREF(result);
317         result = NULL;
318         XMLRPC_FAIL_IF_FAULT(env);
319     }
320
321  cleanup:
322     xmlrpc_env_clean(&env2);
323     if (result)
324         xmlrpc_DECREF(result);
325     if (env->fault_occurred) {
326         if (results)
327             xmlrpc_DECREF(results);
328         return NULL;
329     }
330     return results;
331 }
332
333
334
335 static struct systemMethodReg const multicall = {
336     "system.multicall",
337     &system_multicall,
338     "A:A",
339     "Process an array of calls, and return an array of results.  Calls should "
340     "be structs of the form {'methodName': string, 'params': array}. Each "
341     "result will either be a single-item array containg the result value, or "
342     "a struct of the form {'faultCode': int, 'faultString': string}.  This "
343     "is useful when you need to make lots of small calls without lots of "
344     "round trips.",
345 };
346
347
348 /*=========================================================================
349    system.listMethods
350 =========================================================================*/
351
352
353
354 static xmlrpc_value *
355 system_listMethods(xmlrpc_env *env,
356                    xmlrpc_value *param_array,
357                    void *user_data) {
358
359     xmlrpc_registry *registry;
360     xmlrpc_value *method_names, *method_name, *method_info;
361     size_t size, i;
362
363     XMLRPC_ASSERT_ENV_OK(env);
364     XMLRPC_ASSERT_VALUE_OK(param_array);
365     XMLRPC_ASSERT_PTR_OK(user_data);
366
367     /* Error-handling preconditions. */
368     method_names = NULL;
369
370     /* Turn our arguments into something more useful. */
371     registry = (xmlrpc_registry*) user_data;
372     xmlrpc_parse_value(env, param_array, "()");
373     XMLRPC_FAIL_IF_FAULT(env);
374     
375     /* Make sure we're allowed to introspect. */
376     if (!registry->_introspection_enabled)
377         XMLRPC_FAIL(env, XMLRPC_INTROSPECTION_DISABLED_ERROR,
378                     "Introspection disabled for security reasons");
379     
380     /* Iterate over all the methods in the registry, adding their names
381     ** to a list. */
382     method_names = xmlrpc_build_value(env, "()");
383     XMLRPC_FAIL_IF_FAULT(env);
384     size = xmlrpc_struct_size(env, registry->_methods);
385     XMLRPC_FAIL_IF_FAULT(env);
386     for (i = 0; i < size; i++) {
387         xmlrpc_struct_get_key_and_value(env, registry->_methods, i,
388                                         &method_name, &method_info);
389         XMLRPC_FAIL_IF_FAULT(env);
390         xmlrpc_array_append_item(env, method_names, method_name);
391         XMLRPC_FAIL_IF_FAULT(env);
392     }
393
394  cleanup:
395     if (env->fault_occurred) {
396         if (method_names)
397             xmlrpc_DECREF(method_names);
398         return NULL;
399     }
400     return method_names;
401 }
402
403 static struct systemMethodReg const listMethods = {
404     "system.listMethods",
405     &system_listMethods,
406     "A:",
407     "Return an array of all available XML-RPC methods on this server.",
408 };
409
410
411
412 /*=========================================================================
413   system.methodHelp
414 =========================================================================*/
415
416 static xmlrpc_value *
417 system_methodHelp(xmlrpc_env *env,
418                   xmlrpc_value *param_array,
419                   void *user_data) {
420
421     xmlrpc_registry *registry;
422     char *method_name;
423     xmlrpc_value *ignored1, *ignored2, *ignored3, *help;
424
425     XMLRPC_ASSERT_ENV_OK(env);
426     XMLRPC_ASSERT_VALUE_OK(param_array);
427     XMLRPC_ASSERT_PTR_OK(user_data);
428
429     /* Turn our arguments into something more useful. */
430     registry = (xmlrpc_registry*) user_data;
431     xmlrpc_parse_value(env, param_array, "(s)", &method_name);
432     XMLRPC_FAIL_IF_FAULT(env);
433     
434     /* Make sure we're allowed to introspect. */
435     if (!registry->_introspection_enabled)
436         XMLRPC_FAIL(env, XMLRPC_INTROSPECTION_DISABLED_ERROR,
437                     "Introspection disabled for security reasons");
438     
439     /* Get our documentation string. */
440     xmlrpc_parse_value(env, registry->_methods, "{s:(VVVV*),*}",
441                        method_name, &ignored1, &ignored2, &ignored3, &help);
442     XMLRPC_FAIL_IF_FAULT(env);
443     
444  cleanup:
445     if (env->fault_occurred)
446         return NULL;
447     xmlrpc_INCREF(help);
448     return help;
449 }
450
451
452 static struct systemMethodReg const methodHelp = {
453     "system.methodHelp",
454     &system_methodHelp,
455     "s:s",
456     "Given the name of a method, return a help string.",
457 };
458
459
460
461 static void
462 getMethodInfo(xmlrpc_env *      const envP,
463               xmlrpc_registry * const registryP,
464               const char *      const methodName,
465               xmlrpc_value **   const methodInfoPP) {
466 /*----------------------------------------------------------------------------
467    Look up the method info for the named method.  Method info
468    is an array (ppss):
469 -----------------------------------------------------------------------------*/
470     xmlrpc_env env;
471     xmlrpc_value * methodInfoP;
472     
473     xmlrpc_env_init(&env);
474     
475     /* We can't use xmlrpc_struct_find_value() here because it isn't
476        thread-safe (it manipulates the reference count) and servers
477        sometimes call system methods from multiple threads at once.
478     */
479     methodInfoP = xmlrpc_struct_get_value(
480         &env, registryP->_methods, methodName);
481     
482     if (env.fault_occurred) {
483         if (env.fault_code == XMLRPC_INDEX_ERROR)
484             xmlrpc_env_set_fault_formatted(
485                 envP, XMLRPC_NO_SUCH_METHOD_ERROR,
486                 "Method '%s' does not exist", methodName);
487         else
488             xmlrpc_faultf(envP, "Unable to look up method named '%s' in the "
489                           "registry.  %s", methodName, env.fault_string);
490     } else
491         *methodInfoPP = methodInfoP;
492
493     xmlrpc_env_clean(&env);
494 }
495
496
497
498 /*=========================================================================
499   system.methodSignature
500 ==========================================================================*/
501
502 static void
503 buildNoSigSuppliedResult(xmlrpc_env *    const envP,
504                          xmlrpc_value ** const resultPP) {
505
506     xmlrpc_env env;
507
508     xmlrpc_env_init(&env);
509
510     *resultPP = xmlrpc_string_new(&env, "undef");
511     if (env.fault_occurred)
512         xmlrpc_faultf(envP, "Unable to construct 'undef'.  %s",
513                       env.fault_string);
514
515     xmlrpc_env_clean(&env);
516 }
517     
518
519
520 static void
521 makeSigListCopy(xmlrpc_env *    const envP,
522                 xmlrpc_value *  const oldP,
523                 xmlrpc_value ** const newPP) {
524
525     xmlrpc_value * newP;
526
527     newP = xmlrpc_array_new(envP);
528
529     if (!envP->fault_occurred) {
530         unsigned int const size = xmlrpc_array_size(envP, oldP);
531         if (!envP->fault_occurred) {
532             unsigned int i;
533             for (i = 0; i < size; ++i) {
534                 /* We can't use xmlrpc_array_read_item() here because
535                    it isn't thread-safe (it manipulates the reference count)
536                    an servers sometimes call system methods from multiple
537                    threads at once.
538                 */
539                 xmlrpc_value * const itemP =
540                     xmlrpc_array_get_item(envP, oldP, i);
541                 xmlrpc_array_append_item(envP, newP, itemP);
542             }
543         }                
544     }
545     *newPP = newP;
546 }
547
548
549
550 static void
551 getSignatureList(xmlrpc_env *      const envP,
552                  xmlrpc_registry * const registryP,
553                  const char *      const methodName,
554                  xmlrpc_value **   const signatureListPP) {
555 /*----------------------------------------------------------------------------
556   Get the signature list array for method named 'methodName' from registry
557   'registryP'.
558
559   If there is no signature information for the method in the registry,
560   return *signatureListPP == NULL.
561
562   Nonexistent method is considered a failure.
563 -----------------------------------------------------------------------------*/
564     xmlrpc_value * methodInfoP;
565
566     getMethodInfo(envP, registryP, methodName, &methodInfoP);
567     if (!envP->fault_occurred) {
568         xmlrpc_env env;
569         xmlrpc_value * signatureListP;
570         
571         xmlrpc_env_init(&env);
572         
573         /* We can't use xmlrpc_array_read_item() because it isn't thread
574            safe (it manipulates the reference count) and servers sometimes
575            run system methods from multiple threads at once.
576         */
577         signatureListP = xmlrpc_array_get_item(&env, methodInfoP, 2);
578
579         if (env.fault_occurred)
580             xmlrpc_faultf(envP, "Failed to read signature list "
581                           "from method info array.  %s",
582                           env.fault_string);
583         else {
584             int arraySize;
585
586             arraySize = xmlrpc_array_size(&env, signatureListP);
587             if (env.fault_occurred)
588                 xmlrpc_faultf(envP, "xmlrpc_array_size() on signature "
589                               "list array failed!  %s", env.fault_string);
590             else {
591                 if (arraySize == 0)
592                     *signatureListPP = NULL;
593                 else {
594                     makeSigListCopy(envP, signatureListP, signatureListPP);
595                 }
596             }
597         }
598         xmlrpc_env_clean(&env);
599     }
600 }
601
602
603
604 static xmlrpc_value *
605 system_methodSignature(xmlrpc_env *   const envP,
606                        xmlrpc_value * const paramArrayP,
607                        void *         const userData) {
608
609     xmlrpc_registry * const registryP = (xmlrpc_registry *) userData;
610
611     xmlrpc_value * retvalP;
612     const char * methodName;
613     xmlrpc_env env;
614
615     XMLRPC_ASSERT_ENV_OK(envP);
616     XMLRPC_ASSERT_VALUE_OK(paramArrayP);
617     XMLRPC_ASSERT_PTR_OK(userData);
618
619     xmlrpc_env_init(&env);
620
621     /* Turn our arguments into something more useful. */
622     xmlrpc_decompose_value(&env, paramArrayP, "(s)", &methodName);
623     if (env.fault_occurred)
624         xmlrpc_env_set_fault_formatted(
625             envP, env.fault_code,
626             "Invalid parameter list.  %s", env.fault_string);
627     else {
628         if (!registryP->_introspection_enabled)
629             xmlrpc_env_set_fault(envP, XMLRPC_INTROSPECTION_DISABLED_ERROR,
630                                  "Introspection disabled on this server");
631         else {
632             xmlrpc_value * signatureListP;
633
634             getSignatureList(envP, registryP, methodName, &signatureListP);
635
636             if (!envP->fault_occurred) {
637                 if (signatureListP)
638                     retvalP = signatureListP;
639                 else
640                     buildNoSigSuppliedResult(envP, &retvalP);
641             }
642         }
643         xmlrpc_strfree(methodName);
644     }
645     xmlrpc_env_clean(&env);
646
647     return retvalP;
648 }
649
650
651
652 static struct systemMethodReg const methodSignature = {
653     "system.methodSignature",
654     &system_methodSignature,
655     "A:s",
656     "Given the name of a method, return an array of legal signatures. "
657     "Each signature is an array of strings.  The first item of each signature "
658     "is the return type, and any others items are parameter types.",
659 };
660
661
662
663
664 /*=========================================================================
665   system.shutdown
666 ==========================================================================*/
667
668 static xmlrpc_value *
669 system_shutdown(xmlrpc_env *   const envP,
670                 xmlrpc_value * const paramArrayP,
671                 void *         const userData) {
672     
673     xmlrpc_registry * const registryP = (xmlrpc_registry *) userData;
674
675     xmlrpc_value * retvalP;
676     const char * comment;
677     xmlrpc_env env;
678
679     XMLRPC_ASSERT_ENV_OK(envP);
680     XMLRPC_ASSERT_VALUE_OK(paramArrayP);
681     XMLRPC_ASSERT_PTR_OK(userData);
682
683     xmlrpc_env_init(&env);
684
685     retvalP = NULL;  /* quiet compiler warning */
686
687     /* Turn our arguments into something more useful. */
688     xmlrpc_decompose_value(&env, paramArrayP, "(s)", &comment);
689     if (env.fault_occurred)
690         xmlrpc_env_set_fault_formatted(
691             envP, env.fault_code,
692             "Invalid parameter list.  %s", env.fault_string);
693     else {
694         if (!registryP->_shutdown_server_fn)
695             xmlrpc_env_set_fault(
696                 envP, 0, "This server program is not capable of "
697                 "shutting down");
698         else {
699             registryP->_shutdown_server_fn(
700                 &env, registryP->_shutdown_context, comment);
701
702             if (env.fault_occurred)
703                 xmlrpc_env_set_fault(envP, env.fault_code, env.fault_string);
704             else {
705                 retvalP = xmlrpc_int_new(&env, 0);
706                 
707                 if (env.fault_occurred)
708                     xmlrpc_faultf(envP,
709                                   "Failed to construct return value.  %s",
710                                   env.fault_string);
711             }
712         }
713         xmlrpc_strfree(comment);
714     }
715     xmlrpc_env_clean(&env);
716
717     return retvalP;
718 }
719
720
721
722 static struct systemMethodReg const shutdown = {
723     "system.shutdown",
724     &system_shutdown,
725     "i:s",
726     "Shut down the server.  Return code is always zero.",
727 };
728
729
730
731 /*============================================================================
732   Installer of system methods
733 ============================================================================*/
734
735 static void
736 registerSystemMethod(xmlrpc_env *           const envP,
737                      xmlrpc_registry *      const registryP,
738                      struct systemMethodReg const methodReg) {
739
740     xmlrpc_env env;
741     xmlrpc_env_init(&env);
742     
743     xmlrpc_registry_add_method_w_doc(
744         &env, registryP, NULL, methodReg.methodName,
745         methodReg.methodFunction, registryP,
746         methodReg.signatureString, methodReg.helpText);
747     
748     if (env.fault_occurred)
749         xmlrpc_faultf(envP, "Failed to register '%s' system method.  %s",
750                       methodReg.methodName, env.fault_string);
751     
752     xmlrpc_env_clean(&env);
753 }
754
755
756
757 void
758 xmlrpc_installSystemMethods(xmlrpc_env *      const envP,
759                             xmlrpc_registry * const registryP) {
760 /*----------------------------------------------------------------------------
761    Install the built-in methods (system.*) into registry 'registryP'.
762 -----------------------------------------------------------------------------*/
763     if (!envP->fault_occurred)
764         registerSystemMethod(envP, registryP, listMethods);
765
766     if (!envP->fault_occurred) 
767         registerSystemMethod(envP, registryP, methodSignature);
768
769     if (!envP->fault_occurred)
770         registerSystemMethod(envP, registryP, methodHelp);
771
772     if (!envP->fault_occurred)
773         registerSystemMethod(envP, registryP, multicall);
774
775     if (!envP->fault_occurred)
776         registerSystemMethod(envP, registryP, shutdown);
777 }
778
779
780
781 /* Copyright (C) 2001 by First Peer, Inc. All rights reserved.
782 ** Copyright (C) 2001 by Eric Kidd. All rights reserved.
783 ** Copyright (C) 2001 by Luke Howard. All rights reserved.
784 **
785 ** Redistribution and use in source and binary forms, with or without
786 ** modification, are permitted provided that the following conditions
787 ** are met:
788 ** 1. Redistributions of source code must retain the above copyright
789 **    notice, this list of conditions and the following disclaimer.
790 ** 2. Redistributions in binary form must reproduce the above copyright
791 **    notice, this list of conditions and the following disclaimer in the
792 **    documentation and/or other materials provided with the distribution.
793 ** 3. The name of the author may not be used to endorse or promote products
794 **    derived from this software without specific prior written permission. 
795 **  
796 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
797 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
798 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
799 ** ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
800 ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
801 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
802 ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
803 ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
804 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
805 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
806 ** SUCH DAMAGE. */
807