843 lines
21 KiB
C
843 lines
21 KiB
C
/* Make an XML-RPC call.
|
|
|
|
User specifies details of the call on the command line.
|
|
|
|
We print the result on Standard Output.
|
|
|
|
Example:
|
|
|
|
$ xmlrpc http://localhost:8080/RPC2 sample.add i/3 i/5
|
|
Result:
|
|
Integer: 8
|
|
|
|
$ xmlrpc localhost:8080 sample.add i/3 i/5
|
|
Result:
|
|
Integer: 8
|
|
|
|
This is just the beginnings of this program. It should be extended
|
|
to deal with all types of parameters and results.
|
|
|
|
An example of a good syntax for parameters would be:
|
|
|
|
$ xmlrpc http://www.oreillynet.com/meerkat/xml-rpc/server.php \
|
|
meerkat.getItems \
|
|
struct/{search:linux,descriptions:i/76,time_period:12hour}
|
|
Result:
|
|
Array:
|
|
Struct:
|
|
title: String: DatabaseJournal: OpenEdge-Based Finance ...
|
|
link: String: http://linuxtoday.com/news_story.php3?ltsn=...
|
|
description: String: "Finance application with embedded ...
|
|
Struct:
|
|
title: ...
|
|
link: ...
|
|
description: ...
|
|
|
|
*/
|
|
|
|
#define _GNU_SOURCE
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include "config.h" /* information about this build environment */
|
|
#include "casprintf.h"
|
|
#include "mallocvar.h"
|
|
#include "cmdline_parser.h"
|
|
|
|
#include "xmlrpc-c/base.h"
|
|
#include "xmlrpc-c/client.h"
|
|
|
|
#define NAME "xmlrpc command line program"
|
|
#define VERSION "1.0"
|
|
|
|
struct cmdlineInfo {
|
|
const char * url;
|
|
const char * username;
|
|
const char * password;
|
|
const char * methodName;
|
|
unsigned int paramCount;
|
|
const char ** params;
|
|
/* Array of parameters, in order. Has 'paramCount' entries. */
|
|
const char * transport;
|
|
/* Name of XML transport he wants to use. NULL if he has no
|
|
preference.
|
|
*/
|
|
const char * curlinterface;
|
|
/* "network interface" parameter for the Curl transport. (Not
|
|
valid if 'transport' names a non-Curl transport).
|
|
*/
|
|
xmlrpc_bool curlnoverifypeer;
|
|
xmlrpc_bool curlnoverifyhost;
|
|
const char * curluseragent;
|
|
};
|
|
|
|
|
|
|
|
static void
|
|
die_if_fault_occurred (xmlrpc_env * const envP) {
|
|
if (envP->fault_occurred) {
|
|
fprintf(stderr, "Error: %s (%d)\n",
|
|
envP->fault_string, envP->fault_code);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void GNU_PRINTF_ATTR(2,3)
|
|
setError(xmlrpc_env * const envP, const char format[], ...) {
|
|
va_list args;
|
|
const char * faultString;
|
|
|
|
va_start(args, format);
|
|
|
|
cvasprintf(&faultString, format, args);
|
|
va_end(args);
|
|
|
|
xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR, faultString);
|
|
|
|
strfree(faultString);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
processArguments(xmlrpc_env * const envP,
|
|
cmdlineParser const cp,
|
|
struct cmdlineInfo * const cmdlineP) {
|
|
|
|
if (cmd_argumentCount(cp) < 2)
|
|
setError(envP, "Not enough arguments. Need at least a URL and "
|
|
"method name.");
|
|
else {
|
|
unsigned int i;
|
|
|
|
cmdlineP->url = cmd_getArgument(cp, 0);
|
|
cmdlineP->methodName = cmd_getArgument(cp, 1);
|
|
cmdlineP->paramCount = cmd_argumentCount(cp) - 2;
|
|
MALLOCARRAY(cmdlineP->params, cmdlineP->paramCount);
|
|
for (i = 0; i < cmdlineP->paramCount; ++i)
|
|
cmdlineP->params[i] = cmd_getArgument(cp, i+2);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
chooseTransport(xmlrpc_env * const envP ATTR_UNUSED,
|
|
cmdlineParser const cp,
|
|
const char ** const transportPP) {
|
|
|
|
const char * transportOpt = cmd_getOptionValueString(cp, "transport");
|
|
|
|
if (transportOpt) {
|
|
*transportPP = transportOpt;
|
|
} else {
|
|
if (cmd_optionIsPresent(cp, "curlinterface") ||
|
|
cmd_optionIsPresent(cp, "curlnoverifypeer") ||
|
|
cmd_optionIsPresent(cp, "curlnoverifyhost") ||
|
|
cmd_optionIsPresent(cp, "curluseragent"))
|
|
|
|
*transportPP = strdup("curl");
|
|
else
|
|
*transportPP = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
parseCommandLine(xmlrpc_env * const envP,
|
|
int const argc,
|
|
const char ** const argv,
|
|
struct cmdlineInfo * const cmdlineP) {
|
|
|
|
cmdlineParser const cp = cmd_createOptionParser();
|
|
|
|
const char * error;
|
|
|
|
cmd_defineOption(cp, "transport", OPTTYPE_STRING);
|
|
cmd_defineOption(cp, "username", OPTTYPE_STRING);
|
|
cmd_defineOption(cp, "password", OPTTYPE_STRING);
|
|
cmd_defineOption(cp, "curlinterface", OPTTYPE_STRING);
|
|
cmd_defineOption(cp, "curlnoverifypeer", OPTTYPE_STRING);
|
|
cmd_defineOption(cp, "curlnoverifyhost", OPTTYPE_STRING);
|
|
cmd_defineOption(cp, "curluseragent", OPTTYPE_STRING);
|
|
|
|
cmd_processOptions(cp, argc, argv, &error);
|
|
|
|
if (error) {
|
|
setError(envP, "Command syntax error. %s", error);
|
|
strfree(error);
|
|
} else {
|
|
cmdlineP->username = cmd_getOptionValueString(cp, "username");
|
|
cmdlineP->password = cmd_getOptionValueString(cp, "password");
|
|
|
|
if (cmdlineP->username && !cmdlineP->password)
|
|
setError(envP, "When you specify -username, you must also "
|
|
"specify -password.");
|
|
else {
|
|
chooseTransport(envP, cp, &cmdlineP->transport);
|
|
|
|
cmdlineP->curlinterface =
|
|
cmd_getOptionValueString(cp, "curlinterface");
|
|
cmdlineP->curlnoverifypeer =
|
|
cmd_optionIsPresent(cp, "curlnoverifypeer");
|
|
cmdlineP->curlnoverifyhost =
|
|
cmd_optionIsPresent(cp, "curlnoverifyhost");
|
|
cmdlineP->curluseragent =
|
|
cmd_getOptionValueString(cp, "curluseragent");
|
|
|
|
if ((!cmdlineP->transport ||
|
|
strcmp(cmdlineP->transport, "curl") != 0)
|
|
&&
|
|
(cmdlineP->curlinterface ||
|
|
cmdlineP->curlnoverifypeer ||
|
|
cmdlineP->curlnoverifyhost ||
|
|
cmdlineP->curluseragent))
|
|
setError(envP, "You may not specify a Curl transport "
|
|
"option unless you also specify -transport=curl");
|
|
|
|
processArguments(envP, cp, cmdlineP);
|
|
}
|
|
}
|
|
cmd_destroyOptionParser(cp);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
freeCmdline(struct cmdlineInfo const cmdline) {
|
|
|
|
unsigned int i;
|
|
|
|
strfree(cmdline.url);
|
|
strfree(cmdline.methodName);
|
|
if (cmdline.transport)
|
|
strfree(cmdline.transport);
|
|
if (cmdline.curlinterface)
|
|
strfree(cmdline.curlinterface);
|
|
if (cmdline.curluseragent)
|
|
strfree(cmdline.curluseragent);
|
|
if (cmdline.username)
|
|
strfree(cmdline.username);
|
|
if (cmdline.password)
|
|
strfree(cmdline.password);
|
|
for (i = 0; i < cmdline.paramCount; ++i)
|
|
strfree(cmdline.params[i]);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
computeUrl(const char * const urlArg,
|
|
const char ** const urlP) {
|
|
|
|
if (strstr(urlArg, "://") != 0) {
|
|
*urlP = strdup(urlArg);
|
|
} else {
|
|
casprintf(urlP, "http://%s/RPC2", urlArg);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
buildString(xmlrpc_env * const envP,
|
|
const char * const valueString,
|
|
xmlrpc_value ** const paramPP) {
|
|
|
|
*paramPP = xmlrpc_build_value(envP, "s", valueString);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
buildInt(xmlrpc_env * const envP,
|
|
const char * const valueString,
|
|
xmlrpc_value ** const paramPP) {
|
|
|
|
if (strlen(valueString) < 1)
|
|
setError(envP, "Integer argument has nothing after the 'i/'");
|
|
else {
|
|
long value;
|
|
char * tailptr;
|
|
|
|
value = strtol(valueString, &tailptr, 10);
|
|
|
|
if (*tailptr != '\0')
|
|
setError(envP,
|
|
"Integer argument has non-digit crap in it: '%s'",
|
|
tailptr);
|
|
else
|
|
*paramPP = xmlrpc_build_value(envP, "i", value);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
buildBool(xmlrpc_env * const envP,
|
|
const char * const valueString,
|
|
xmlrpc_value ** const paramPP) {
|
|
|
|
if (strcmp(valueString, "t") == 0 ||
|
|
strcmp(valueString, "true") == 0)
|
|
*paramPP = xmlrpc_build_value(envP, "b", 1);
|
|
else if (strcmp(valueString, "f") == 0 ||
|
|
strcmp(valueString, "false") == 0)
|
|
*paramPP = xmlrpc_build_value(envP, "b", 0);
|
|
else
|
|
setError(envP, "Boolean argument has unrecognized value '%s'. "
|
|
"recognized values are 't', 'f', 'true', and 'false'.",
|
|
valueString);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
buildNil(xmlrpc_env * const envP,
|
|
const char * const valueString,
|
|
xmlrpc_value ** const paramPP) {
|
|
|
|
if (strlen(valueString) > 0)
|
|
setError(envP, "Nil argument has something after the 'n/'");
|
|
else {
|
|
*paramPP = xmlrpc_build_value(envP, "n");
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
computeParameter(xmlrpc_env * const envP,
|
|
const char * const paramArg,
|
|
xmlrpc_value ** const paramPP) {
|
|
|
|
if (strncmp(paramArg, "s/", 2) == 0)
|
|
buildString(envP, ¶mArg[2], paramPP);
|
|
else if (strncmp(paramArg, "i/", 2) == 0)
|
|
buildInt(envP, ¶mArg[2], paramPP);
|
|
else if (strncmp(paramArg, "b/", 2) == 0)
|
|
buildBool(envP, ¶mArg[2], paramPP);
|
|
else if (strncmp(paramArg, "n/", 2) == 0)
|
|
buildNil(envP, ¶mArg[2], paramPP);
|
|
else {
|
|
/* It's not in normal type/value format, so we take it to be
|
|
the shortcut string notation
|
|
*/
|
|
buildString(envP, paramArg, paramPP);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
computeParamArray(xmlrpc_env * const envP,
|
|
unsigned int const paramCount,
|
|
const char ** const params,
|
|
xmlrpc_value ** const paramArrayPP) {
|
|
|
|
unsigned int i;
|
|
|
|
xmlrpc_value * paramArrayP;
|
|
|
|
paramArrayP = xmlrpc_build_value(envP, "()");
|
|
|
|
for (i = 0; i < paramCount && !envP->fault_occurred; ++i) {
|
|
xmlrpc_value * paramP;
|
|
|
|
computeParameter(envP, params[i], ¶mP);
|
|
|
|
if (!envP->fault_occurred) {
|
|
xmlrpc_array_append_item(envP, paramArrayP, paramP);
|
|
|
|
xmlrpc_DECREF(paramP);
|
|
}
|
|
}
|
|
*paramArrayPP = paramArrayP;
|
|
}
|
|
|
|
|
|
|
|
/* Forward declaration for recursion */
|
|
static void
|
|
dumpValue(const char * const prefix,
|
|
xmlrpc_value * const valueP);
|
|
|
|
|
|
|
|
static void
|
|
dumpInt(const char * const prefix,
|
|
xmlrpc_value * const valueP) {
|
|
|
|
xmlrpc_env env;
|
|
xmlrpc_int value;
|
|
|
|
xmlrpc_env_init(&env);
|
|
|
|
xmlrpc_parse_value(&env, valueP, "i", &value);
|
|
|
|
if (env.fault_occurred)
|
|
printf("Unable to parse integer in result. %s\n",
|
|
env.fault_string);
|
|
else
|
|
printf("%sInteger: %d\n", prefix, value);
|
|
|
|
xmlrpc_env_clean(&env);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
dumpBool(const char * const prefix,
|
|
xmlrpc_value * const valueP) {
|
|
|
|
xmlrpc_env env;
|
|
xmlrpc_bool value;
|
|
|
|
xmlrpc_env_init(&env);
|
|
|
|
xmlrpc_parse_value(&env, valueP, "b", &value);
|
|
|
|
if (env.fault_occurred)
|
|
printf("Unable to parse boolean in result. %s\n",
|
|
env.fault_string);
|
|
else
|
|
printf("%sBoolean: %s\n", prefix, value ? "TRUE" : "FALSE");
|
|
|
|
xmlrpc_env_clean(&env);
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
dumpDouble(const char * const prefix,
|
|
xmlrpc_value * const valueP) {
|
|
|
|
xmlrpc_env env;
|
|
xmlrpc_double value;
|
|
|
|
xmlrpc_env_init(&env);
|
|
|
|
xmlrpc_parse_value(&env, valueP, "d", &value);
|
|
|
|
if (env.fault_occurred)
|
|
printf("Unable to parse floating point number in result. %s\n",
|
|
env.fault_string);
|
|
else
|
|
printf("%sFloating Point: %f\n", prefix, value);
|
|
|
|
xmlrpc_env_clean(&env);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
dumpDatetime(const char * const prefix,
|
|
xmlrpc_value * const valueP) {
|
|
|
|
printf("%sDon't know how to print datetime value result %p.\n",
|
|
prefix, valueP);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
dumpString(const char * const prefix,
|
|
xmlrpc_value * const valueP) {
|
|
|
|
xmlrpc_env env;
|
|
const char * value;
|
|
|
|
xmlrpc_env_init(&env);
|
|
|
|
xmlrpc_parse_value(&env, valueP, "s", &value);
|
|
|
|
if (env.fault_occurred)
|
|
printf("Unable to parse string in result. %s\n",
|
|
env.fault_string);
|
|
else
|
|
printf("%sString: '%s'\n", prefix, value);
|
|
|
|
xmlrpc_env_clean(&env);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
dumpBase64(const char * const prefix,
|
|
xmlrpc_value * const valueP) {
|
|
|
|
xmlrpc_env env;
|
|
const unsigned char * value;
|
|
size_t length;
|
|
|
|
xmlrpc_env_init(&env);
|
|
|
|
xmlrpc_parse_value(&env, valueP, "6", &value, &length);
|
|
|
|
if (env.fault_occurred)
|
|
printf("Unable to parse base64 bit strnig in result. %s\n",
|
|
env.fault_string);
|
|
else {
|
|
unsigned int i;
|
|
|
|
printf("%sBit string: ", prefix);
|
|
for (i = 0; i < length; ++i)
|
|
printf("%02x", value[i]);
|
|
}
|
|
xmlrpc_env_clean(&env);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
dumpArray(const char * const prefix,
|
|
xmlrpc_value * const arrayP) {
|
|
|
|
xmlrpc_env env;
|
|
unsigned int arraySize;
|
|
|
|
xmlrpc_env_init(&env);
|
|
|
|
XMLRPC_ASSERT_ARRAY_OK(arrayP);
|
|
|
|
arraySize = xmlrpc_array_size(&env, arrayP);
|
|
if (env.fault_occurred)
|
|
printf("Unable to get array size. %s\n", env.fault_string);
|
|
else {
|
|
int const spaceCount = strlen(prefix);
|
|
|
|
unsigned int i;
|
|
const char * blankPrefix;
|
|
|
|
printf("%sArray of %u items:\n", prefix, arraySize);
|
|
|
|
casprintf(&blankPrefix, "%*s", spaceCount, "");
|
|
|
|
for (i = 0; i < arraySize; ++i) {
|
|
xmlrpc_value * valueP;
|
|
|
|
xmlrpc_array_read_item(&env, arrayP, i, &valueP);
|
|
|
|
if (env.fault_occurred)
|
|
printf("Unable to get array item %u\n", i);
|
|
else {
|
|
const char * prefix2;
|
|
|
|
casprintf(&prefix2, "%s Index %2u ", blankPrefix, i);
|
|
dumpValue(prefix2, valueP);
|
|
strfree(prefix2);
|
|
|
|
xmlrpc_DECREF(valueP);
|
|
}
|
|
}
|
|
strfree(blankPrefix);
|
|
}
|
|
xmlrpc_env_clean(&env);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
dumpStructMember(const char * const prefix,
|
|
xmlrpc_value * const structP,
|
|
unsigned int const index) {
|
|
|
|
xmlrpc_env env;
|
|
|
|
xmlrpc_value * keyP;
|
|
xmlrpc_value * valueP;
|
|
|
|
xmlrpc_env_init(&env);
|
|
|
|
xmlrpc_struct_read_member(&env, structP, index, &keyP, &valueP);
|
|
|
|
if (env.fault_occurred)
|
|
printf("Unable to get struct member %u\n", index);
|
|
else {
|
|
int const blankCount = strlen(prefix);
|
|
const char * prefix2;
|
|
const char * blankPrefix;
|
|
|
|
casprintf(&prefix2, "%s Key: ", prefix);
|
|
dumpValue(prefix2, keyP);
|
|
strfree(prefix2);
|
|
|
|
casprintf(&blankPrefix, "%*s", blankCount, "");
|
|
|
|
casprintf(&prefix2, "%s Value: ", blankPrefix);
|
|
dumpValue(prefix2, valueP);
|
|
strfree(prefix2);
|
|
|
|
strfree(blankPrefix);
|
|
|
|
xmlrpc_DECREF(keyP);
|
|
xmlrpc_DECREF(valueP);
|
|
}
|
|
xmlrpc_env_clean(&env);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
dumpStruct(const char * const prefix,
|
|
xmlrpc_value * const structP) {
|
|
|
|
xmlrpc_env env;
|
|
unsigned int structSize;
|
|
|
|
xmlrpc_env_init(&env);
|
|
|
|
structSize = xmlrpc_struct_size(&env, structP);
|
|
if (env.fault_occurred)
|
|
printf("Unable to get struct size. %s\n", env.fault_string);
|
|
else {
|
|
unsigned int i;
|
|
|
|
printf("%sStruct of %u members:\n", prefix, structSize);
|
|
|
|
for (i = 0; i < structSize; ++i) {
|
|
const char * prefix1;
|
|
|
|
if (i == 0)
|
|
prefix1 = strdup(prefix);
|
|
else {
|
|
int const blankCount = strlen(prefix);
|
|
casprintf(&prefix1, "%*s", blankCount, "");
|
|
}
|
|
dumpStructMember(prefix1, structP, i);
|
|
|
|
strfree(prefix1);
|
|
}
|
|
}
|
|
xmlrpc_env_clean(&env);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
dumpCPtr(const char * const prefix,
|
|
xmlrpc_value * const valueP) {
|
|
|
|
xmlrpc_env env;
|
|
const char * value;
|
|
|
|
xmlrpc_env_init(&env);
|
|
|
|
xmlrpc_parse_value(&env, valueP, "p", &value);
|
|
|
|
if (env.fault_occurred)
|
|
printf("Unable to parse C pointer in result. %s\n",
|
|
env.fault_string);
|
|
else
|
|
printf("%sC pointer: '%p'\n", prefix, value);
|
|
|
|
xmlrpc_env_clean(&env);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
dumpNil(const char * const prefix,
|
|
xmlrpc_value * const valueP) {
|
|
|
|
xmlrpc_env env;
|
|
|
|
xmlrpc_env_init(&env);
|
|
|
|
xmlrpc_parse_value(&env, valueP, "n");
|
|
|
|
if (env.fault_occurred)
|
|
printf("Unable to parse nil value in result. %s\n",
|
|
env.fault_string);
|
|
else
|
|
printf("%sNil\n", prefix);
|
|
|
|
xmlrpc_env_clean(&env);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
dumpUnknown(const char * const prefix,
|
|
xmlrpc_value * const valueP) {
|
|
|
|
printf("%sDon't recognize the type of the result: %u.\n",
|
|
prefix, xmlrpc_value_type(valueP));
|
|
printf("%sCan't print it.\n", prefix);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
dumpValue(const char * const prefix,
|
|
xmlrpc_value * const valueP) {
|
|
|
|
switch (xmlrpc_value_type(valueP)) {
|
|
case XMLRPC_TYPE_INT:
|
|
dumpInt(prefix, valueP);
|
|
break;
|
|
case XMLRPC_TYPE_BOOL:
|
|
dumpBool(prefix, valueP);
|
|
break;
|
|
case XMLRPC_TYPE_DOUBLE:
|
|
dumpDouble(prefix, valueP);
|
|
break;
|
|
case XMLRPC_TYPE_DATETIME:
|
|
dumpDatetime(prefix, valueP);
|
|
break;
|
|
case XMLRPC_TYPE_STRING:
|
|
dumpString(prefix, valueP);
|
|
break;
|
|
case XMLRPC_TYPE_BASE64:
|
|
dumpBase64(prefix, valueP);
|
|
break;
|
|
case XMLRPC_TYPE_ARRAY:
|
|
dumpArray(prefix, valueP);
|
|
break;
|
|
case XMLRPC_TYPE_STRUCT:
|
|
dumpStruct(prefix, valueP);
|
|
break;
|
|
case XMLRPC_TYPE_C_PTR:
|
|
dumpCPtr(prefix, valueP);
|
|
break;
|
|
case XMLRPC_TYPE_NIL:
|
|
dumpNil(prefix, valueP);
|
|
break;
|
|
default:
|
|
dumpUnknown(prefix, valueP);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
dumpResult(xmlrpc_value * const resultP) {
|
|
|
|
printf("Result:\n\n");
|
|
|
|
dumpValue("", resultP);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
doCall(xmlrpc_env * const envP,
|
|
const char * const transport,
|
|
const char * const curlinterface,
|
|
xmlrpc_bool const curlnoverifypeer,
|
|
xmlrpc_bool const curlnoverifyhost,
|
|
const char * const curluseragent,
|
|
const xmlrpc_server_info * const serverInfoP,
|
|
const char * const methodName,
|
|
xmlrpc_value * const paramArrayP,
|
|
xmlrpc_value ** const resultPP) {
|
|
|
|
struct xmlrpc_clientparms clientparms;
|
|
|
|
XMLRPC_ASSERT(xmlrpc_value_type(paramArrayP) == XMLRPC_TYPE_ARRAY);
|
|
|
|
clientparms.transport = transport;
|
|
|
|
if (transport && strcmp(transport, "curl") == 0) {
|
|
struct xmlrpc_curl_xportparms * curlXportParmsP;
|
|
MALLOCVAR(curlXportParmsP);
|
|
|
|
curlXportParmsP->network_interface = curlinterface;
|
|
curlXportParmsP->no_ssl_verifypeer = curlnoverifypeer;
|
|
curlXportParmsP->no_ssl_verifyhost = curlnoverifyhost;
|
|
curlXportParmsP->user_agent = curluseragent;
|
|
|
|
clientparms.transportparmsP = (struct xmlrpc_xportparms *)
|
|
curlXportParmsP;
|
|
clientparms.transportparm_size = XMLRPC_CXPSIZE(user_agent);
|
|
} else {
|
|
clientparms.transportparmsP = NULL;
|
|
clientparms.transportparm_size = 0;
|
|
}
|
|
xmlrpc_client_init2(envP, XMLRPC_CLIENT_NO_FLAGS, NAME, VERSION,
|
|
&clientparms, XMLRPC_CPSIZE(transportparm_size));
|
|
if (!envP->fault_occurred) {
|
|
*resultPP = xmlrpc_client_call_server_params(
|
|
envP, serverInfoP, methodName, paramArrayP);
|
|
|
|
xmlrpc_client_cleanup();
|
|
}
|
|
if (clientparms.transportparmsP)
|
|
free(clientparms.transportparmsP);
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
createServerInfo(xmlrpc_env * const envP,
|
|
const char * const serverUrl,
|
|
const char * const userName,
|
|
const char * const password,
|
|
xmlrpc_server_info ** const serverInfoPP) {
|
|
|
|
xmlrpc_server_info * serverInfoP;
|
|
|
|
serverInfoP = xmlrpc_server_info_new(envP, serverUrl);
|
|
if (!envP->fault_occurred) {
|
|
if (userName) {
|
|
xmlrpc_server_info_set_basic_auth(
|
|
envP, serverInfoP, userName, password);
|
|
}
|
|
}
|
|
*serverInfoPP = serverInfoP;
|
|
}
|
|
|
|
|
|
|
|
int
|
|
main(int const argc,
|
|
const char ** const argv) {
|
|
|
|
struct cmdlineInfo cmdline;
|
|
xmlrpc_env env;
|
|
xmlrpc_value * paramArrayP;
|
|
xmlrpc_value * resultP;
|
|
const char * url;
|
|
xmlrpc_server_info * serverInfoP;
|
|
|
|
xmlrpc_env_init(&env);
|
|
|
|
parseCommandLine(&env, argc, argv, &cmdline);
|
|
die_if_fault_occurred(&env);
|
|
|
|
computeUrl(cmdline.url, &url);
|
|
|
|
computeParamArray(&env, cmdline.paramCount, cmdline.params, ¶mArrayP);
|
|
die_if_fault_occurred(&env);
|
|
|
|
createServerInfo(&env, url, cmdline.username, cmdline.password,
|
|
&serverInfoP);
|
|
die_if_fault_occurred(&env);
|
|
|
|
doCall(&env, cmdline.transport, cmdline.curlinterface,
|
|
cmdline.curlnoverifypeer, cmdline.curlnoverifyhost,
|
|
cmdline.curluseragent,
|
|
serverInfoP,
|
|
cmdline.methodName, paramArrayP,
|
|
&resultP);
|
|
die_if_fault_occurred(&env);
|
|
|
|
dumpResult(resultP);
|
|
|
|
strfree(url);
|
|
|
|
xmlrpc_DECREF(resultP);
|
|
|
|
freeCmdline(cmdline);
|
|
|
|
xmlrpc_env_clean(&env);
|
|
|
|
return 0;
|
|
}
|