1 /* Make an XML-RPC call.
3 User specifies details of the call on the command line.
5 We print the result on Standard Output.
9 $ xmlrpc http://localhost:8080/RPC2 sample.add i/3 i/5
13 $ xmlrpc localhost:8080 sample.add i/3 i/5
17 This is just the beginnings of this program. It should be extended
18 to deal with all types of parameters and results.
20 An example of a good syntax for parameters would be:
22 $ xmlrpc http://www.oreillynet.com/meerkat/xml-rpc/server.php \
24 struct/{search:linux,descriptions:i/76,time_period:12hour}
28 title: String: DatabaseJournal: OpenEdge-Based Finance ...
29 link: String: http://linuxtoday.com/news_story.php3?ltsn=...
30 description: String: "Finance application with embedded ...
44 #include "config.h" /* information about this build environment */
45 #include "casprintf.h"
46 #include "mallocvar.h"
47 #include "cmdline_parser.h"
48 #include "dumpvalue.h"
50 #include "xmlrpc-c/base.h"
51 #include "xmlrpc-c/client.h"
53 #define NAME "xmlrpc command line program"
58 const char * username;
59 const char * password;
60 const char * methodName;
61 unsigned int paramCount;
63 /* Array of parameters, in order. Has 'paramCount' entries. */
64 const char * transport;
65 /* Name of XML transport he wants to use. NULL if he has no
68 const char * curlinterface;
69 /* "network interface" parameter for the Curl transport. (Not
70 valid if 'transport' names a non-Curl transport).
72 xmlrpc_bool curlnoverifypeer;
73 xmlrpc_bool curlnoverifyhost;
74 const char * curluseragent;
80 die_if_fault_occurred (xmlrpc_env * const envP) {
81 if (envP->fault_occurred) {
82 fprintf(stderr, "Error: %s (%d)\n",
83 envP->fault_string, envP->fault_code);
90 static void GNU_PRINTF_ATTR(2,3)
91 setError(xmlrpc_env * const envP, const char format[], ...) {
93 const char * faultString;
95 va_start(args, format);
97 cvasprintf(&faultString, format, args);
100 xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR, faultString);
102 strfree(faultString);
108 processArguments(xmlrpc_env * const envP,
109 cmdlineParser const cp,
110 struct cmdlineInfo * const cmdlineP) {
112 if (cmd_argumentCount(cp) < 2)
113 setError(envP, "Not enough arguments. Need at least a URL and "
118 cmdlineP->url = cmd_getArgument(cp, 0);
119 cmdlineP->methodName = cmd_getArgument(cp, 1);
120 cmdlineP->paramCount = cmd_argumentCount(cp) - 2;
121 MALLOCARRAY(cmdlineP->params, cmdlineP->paramCount);
122 for (i = 0; i < cmdlineP->paramCount; ++i)
123 cmdlineP->params[i] = cmd_getArgument(cp, i+2);
130 chooseTransport(xmlrpc_env * const envP ATTR_UNUSED,
131 cmdlineParser const cp,
132 const char ** const transportPP) {
134 const char * transportOpt = cmd_getOptionValueString(cp, "transport");
137 *transportPP = transportOpt;
139 if (cmd_optionIsPresent(cp, "curlinterface") ||
140 cmd_optionIsPresent(cp, "curlnoverifypeer") ||
141 cmd_optionIsPresent(cp, "curlnoverifyhost") ||
142 cmd_optionIsPresent(cp, "curluseragent"))
144 *transportPP = strdup("curl");
153 parseCommandLine(xmlrpc_env * const envP,
155 const char ** const argv,
156 struct cmdlineInfo * const cmdlineP) {
158 cmdlineParser const cp = cmd_createOptionParser();
162 cmd_defineOption(cp, "transport", OPTTYPE_STRING);
163 cmd_defineOption(cp, "username", OPTTYPE_STRING);
164 cmd_defineOption(cp, "password", OPTTYPE_STRING);
165 cmd_defineOption(cp, "curlinterface", OPTTYPE_STRING);
166 cmd_defineOption(cp, "curlnoverifypeer", OPTTYPE_STRING);
167 cmd_defineOption(cp, "curlnoverifyhost", OPTTYPE_STRING);
168 cmd_defineOption(cp, "curluseragent", OPTTYPE_STRING);
170 cmd_processOptions(cp, argc, argv, &error);
173 setError(envP, "Command syntax error. %s", error);
176 cmdlineP->username = cmd_getOptionValueString(cp, "username");
177 cmdlineP->password = cmd_getOptionValueString(cp, "password");
179 if (cmdlineP->username && !cmdlineP->password)
180 setError(envP, "When you specify -username, you must also "
181 "specify -password.");
183 chooseTransport(envP, cp, &cmdlineP->transport);
185 cmdlineP->curlinterface =
186 cmd_getOptionValueString(cp, "curlinterface");
187 cmdlineP->curlnoverifypeer =
188 cmd_optionIsPresent(cp, "curlnoverifypeer");
189 cmdlineP->curlnoverifyhost =
190 cmd_optionIsPresent(cp, "curlnoverifyhost");
191 cmdlineP->curluseragent =
192 cmd_getOptionValueString(cp, "curluseragent");
194 if ((!cmdlineP->transport ||
195 strcmp(cmdlineP->transport, "curl") != 0)
197 (cmdlineP->curlinterface ||
198 cmdlineP->curlnoverifypeer ||
199 cmdlineP->curlnoverifyhost ||
200 cmdlineP->curluseragent))
201 setError(envP, "You may not specify a Curl transport "
202 "option unless you also specify -transport=curl");
204 processArguments(envP, cp, cmdlineP);
207 cmd_destroyOptionParser(cp);
213 freeCmdline(struct cmdlineInfo const cmdline) {
217 strfree(cmdline.url);
218 strfree(cmdline.methodName);
219 if (cmdline.transport)
220 strfree(cmdline.transport);
221 if (cmdline.curlinterface)
222 strfree(cmdline.curlinterface);
223 if (cmdline.curluseragent)
224 strfree(cmdline.curluseragent);
225 if (cmdline.username)
226 strfree(cmdline.username);
227 if (cmdline.password)
228 strfree(cmdline.password);
229 for (i = 0; i < cmdline.paramCount; ++i)
230 strfree(cmdline.params[i]);
236 computeUrl(const char * const urlArg,
237 const char ** const urlP) {
239 if (strstr(urlArg, "://") != 0)
240 casprintf(urlP, "%s", urlArg);
242 casprintf(urlP, "http://%s/RPC2", urlArg);
248 buildString(xmlrpc_env * const envP,
249 const char * const valueString,
250 xmlrpc_value ** const paramPP) {
252 *paramPP = xmlrpc_build_value(envP, "s", valueString);
258 buildInt(xmlrpc_env * const envP,
259 const char * const valueString,
260 xmlrpc_value ** const paramPP) {
262 if (strlen(valueString) < 1)
263 setError(envP, "Integer argument has nothing after the 'i/'");
268 value = strtol(valueString, &tailptr, 10);
270 if (*tailptr != '\0')
272 "Integer argument has non-digit crap in it: '%s'",
275 *paramPP = xmlrpc_build_value(envP, "i", value);
282 buildDouble(xmlrpc_env * const envP,
283 const char * const valueString,
284 xmlrpc_value ** const paramPP) {
286 if (strlen(valueString) < 1)
287 setError(envP, "\"Double\" argument has nothing after the 'd/'");
292 value = strtod(valueString, &tailptr);
294 if (*tailptr != '\0')
296 "\"Double\" argument has non-decimal crap in it: '%s'",
299 *paramPP = xmlrpc_build_value(envP, "d", value);
306 buildBool(xmlrpc_env * const envP,
307 const char * const valueString,
308 xmlrpc_value ** const paramPP) {
310 if (strcmp(valueString, "t") == 0 ||
311 strcmp(valueString, "true") == 0)
312 *paramPP = xmlrpc_build_value(envP, "b", 1);
313 else if (strcmp(valueString, "f") == 0 ||
314 strcmp(valueString, "false") == 0)
315 *paramPP = xmlrpc_build_value(envP, "b", 0);
317 setError(envP, "Boolean argument has unrecognized value '%s'. "
318 "recognized values are 't', 'f', 'true', and 'false'.",
325 buildNil(xmlrpc_env * const envP,
326 const char * const valueString,
327 xmlrpc_value ** const paramPP) {
329 if (strlen(valueString) > 0)
330 setError(envP, "Nil argument has something after the 'n/'");
332 *paramPP = xmlrpc_build_value(envP, "n");
339 computeParameter(xmlrpc_env * const envP,
340 const char * const paramArg,
341 xmlrpc_value ** const paramPP) {
343 if (strncmp(paramArg, "s/", 2) == 0)
344 buildString(envP, ¶mArg[2], paramPP);
345 else if (strncmp(paramArg, "i/", 2) == 0)
346 buildInt(envP, ¶mArg[2], paramPP);
347 else if (strncmp(paramArg, "d/", 2) == 0)
348 buildDouble(envP, ¶mArg[2], paramPP);
349 else if (strncmp(paramArg, "b/", 2) == 0)
350 buildBool(envP, ¶mArg[2], paramPP);
351 else if (strncmp(paramArg, "n/", 2) == 0)
352 buildNil(envP, ¶mArg[2], paramPP);
354 /* It's not in normal type/value format, so we take it to be
355 the shortcut string notation
357 buildString(envP, paramArg, paramPP);
364 computeParamArray(xmlrpc_env * const envP,
365 unsigned int const paramCount,
366 const char ** const params,
367 xmlrpc_value ** const paramArrayPP) {
371 xmlrpc_value * paramArrayP;
373 paramArrayP = xmlrpc_build_value(envP, "()");
375 for (i = 0; i < paramCount && !envP->fault_occurred; ++i) {
376 xmlrpc_value * paramP;
378 computeParameter(envP, params[i], ¶mP);
380 if (!envP->fault_occurred) {
381 xmlrpc_array_append_item(envP, paramArrayP, paramP);
383 xmlrpc_DECREF(paramP);
386 *paramArrayPP = paramArrayP;
392 dumpResult(xmlrpc_value * const resultP) {
394 printf("Result:\n\n");
396 dumpValue("", resultP);
402 doCall(xmlrpc_env * const envP,
403 const char * const transport,
404 const char * const curlinterface,
405 xmlrpc_bool const curlnoverifypeer,
406 xmlrpc_bool const curlnoverifyhost,
407 const char * const curluseragent,
408 const xmlrpc_server_info * const serverInfoP,
409 const char * const methodName,
410 xmlrpc_value * const paramArrayP,
411 xmlrpc_value ** const resultPP) {
413 struct xmlrpc_clientparms clientparms;
415 XMLRPC_ASSERT(xmlrpc_value_type(paramArrayP) == XMLRPC_TYPE_ARRAY);
417 clientparms.transport = transport;
419 if (transport && strcmp(transport, "curl") == 0) {
420 struct xmlrpc_curl_xportparms * curlXportParmsP;
421 MALLOCVAR(curlXportParmsP);
423 curlXportParmsP->network_interface = curlinterface;
424 curlXportParmsP->no_ssl_verifypeer = curlnoverifypeer;
425 curlXportParmsP->no_ssl_verifyhost = curlnoverifyhost;
426 curlXportParmsP->user_agent = curluseragent;
428 clientparms.transportparmsP = (struct xmlrpc_xportparms *)
430 clientparms.transportparm_size = XMLRPC_CXPSIZE(user_agent);
432 clientparms.transportparmsP = NULL;
433 clientparms.transportparm_size = 0;
435 xmlrpc_client_init2(envP, XMLRPC_CLIENT_NO_FLAGS, NAME, VERSION,
436 &clientparms, XMLRPC_CPSIZE(transportparm_size));
437 if (!envP->fault_occurred) {
438 *resultPP = xmlrpc_client_call_server_params(
439 envP, serverInfoP, methodName, paramArrayP);
441 xmlrpc_client_cleanup();
443 if (clientparms.transportparmsP)
444 free(clientparms.transportparmsP);
450 createServerInfo(xmlrpc_env * const envP,
451 const char * const serverUrl,
452 const char * const userName,
453 const char * const password,
454 xmlrpc_server_info ** const serverInfoPP) {
456 xmlrpc_server_info * serverInfoP;
458 serverInfoP = xmlrpc_server_info_new(envP, serverUrl);
459 if (!envP->fault_occurred) {
461 xmlrpc_server_info_set_basic_auth(
462 envP, serverInfoP, userName, password);
465 *serverInfoPP = serverInfoP;
472 const char ** const argv) {
474 struct cmdlineInfo cmdline;
476 xmlrpc_value * paramArrayP;
477 xmlrpc_value * resultP;
479 xmlrpc_server_info * serverInfoP;
481 xmlrpc_env_init(&env);
483 parseCommandLine(&env, argc, argv, &cmdline);
484 die_if_fault_occurred(&env);
486 computeUrl(cmdline.url, &url);
488 computeParamArray(&env, cmdline.paramCount, cmdline.params, ¶mArrayP);
489 die_if_fault_occurred(&env);
491 createServerInfo(&env, url, cmdline.username, cmdline.password,
493 die_if_fault_occurred(&env);
495 doCall(&env, cmdline.transport, cmdline.curlinterface,
496 cmdline.curlnoverifypeer, cmdline.curlnoverifyhost,
497 cmdline.curluseragent,
499 cmdline.methodName, paramArrayP,
501 die_if_fault_occurred(&env);
507 xmlrpc_DECREF(resultP);
509 freeCmdline(cmdline);
511 xmlrpc_env_clean(&env);