--- /dev/null
+/* Transport some XML to a server and get the response back, as if doing
+ an XML-RPC call.
+*/
+
+#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_transport command line program"
+#define VERSION "1.0"
+
+struct cmdlineInfo {
+ const char * url;
+ const char * username;
+ const char * password;
+ const char * transport;
+ /* Name of XML transport he wants to use. NULL if he has no
+ preference.
+ */
+};
+
+
+
+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) < 1)
+ setError(envP, "Not enough arguments. Need a URL.");
+ else {
+ cmdlineP->url = cmd_getArgument(cp, 0);
+ }
+}
+
+
+
+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_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 {
+ cmdlineP->transport = cmd_getOptionValueString(cp, "transport");
+
+ processArguments(envP, cp, cmdlineP);
+ }
+ }
+ cmd_destroyOptionParser(cp);
+}
+
+
+
+static void
+freeCmdline(struct cmdlineInfo const cmdline) {
+
+ strfree(cmdline.url);
+ if (cmdline.username)
+ strfree(cmdline.username);
+ if (cmdline.password)
+ strfree(cmdline.password);
+ if (cmdline.transport)
+ strfree(cmdline.transport);
+}
+
+
+
+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
+doCall(xmlrpc_env * const envP,
+ const char * const transport,
+ const xmlrpc_server_info * const serverInfoP,
+ xmlrpc_mem_block * const callXmlP,
+ xmlrpc_mem_block ** const respXmlPP) {
+
+ struct xmlrpc_clientparms clientparms;
+
+ clientparms.transport = transport;
+
+ 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) {
+ xmlrpc_client_transport_call(envP, NULL, serverInfoP,
+ callXmlP, respXmlPP);
+
+ xmlrpc_client_cleanup();
+ }
+}
+
+
+
+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;
+}
+
+
+
+static void
+readFile(xmlrpc_env * const envP,
+ FILE * const ifP,
+ xmlrpc_mem_block ** const fileContentsPP) {
+
+ xmlrpc_mem_block * fileContentsP;
+
+ fileContentsP = XMLRPC_MEMBLOCK_NEW(char, envP, 0);
+
+ while (!envP->fault_occurred && !feof(ifP)) {
+ char buffer[4096];
+ size_t bytesRead;
+
+ bytesRead = fread(buffer, 1, sizeof(buffer), ifP);
+ XMLRPC_MEMBLOCK_APPEND(char, envP,
+ fileContentsP, buffer, bytesRead);
+ }
+ if (envP->fault_occurred)
+ XMLRPC_MEMBLOCK_FREE(char, fileContentsP);
+
+ *fileContentsPP = fileContentsP;
+}
+
+
+
+static void
+writeFile(xmlrpc_env * const envP,
+ FILE * const ofP,
+ xmlrpc_mem_block * const fileContentsP) {
+
+ size_t totalWritten;
+
+ totalWritten = 0;
+
+ while (!envP->fault_occurred &&
+ totalWritten < XMLRPC_MEMBLOCK_SIZE(char, fileContentsP)) {
+ size_t bytesWritten;
+
+ bytesWritten = fwrite(
+ XMLRPC_MEMBLOCK_CONTENTS(char, fileContentsP) + totalWritten,
+ 1,
+ XMLRPC_MEMBLOCK_SIZE(char, fileContentsP) - totalWritten,
+ ofP);
+
+ if (bytesWritten < 1)
+ xmlrpc_env_set_fault_formatted(
+ envP, XMLRPC_INTERNAL_ERROR,
+ "Error writing output");
+
+ totalWritten -= bytesWritten;
+ }
+}
+
+
+
+int
+main(int const argc,
+ const char ** const argv) {
+
+ struct cmdlineInfo cmdline;
+ xmlrpc_env env;
+ xmlrpc_mem_block * callXmlP;
+ xmlrpc_mem_block * respXmlP;
+ 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);
+
+ createServerInfo(&env, url, cmdline.username, cmdline.password,
+ &serverInfoP);
+ die_if_fault_occurred(&env);
+
+ fprintf(stderr, "Reading call data from Standard Input...\n");
+
+ readFile(&env, stdin, &callXmlP);
+ die_if_fault_occurred(&env);
+
+ fprintf(stderr, "Making call...\n");
+
+ doCall(&env, cmdline.transport, serverInfoP, callXmlP,
+ &respXmlP);
+ die_if_fault_occurred(&env);
+
+ fprintf(stderr, "Writing response data to Standard Output\n");
+ writeFile(&env, stdout, respXmlP);
+ die_if_fault_occurred(&env);
+
+ XMLRPC_MEMBLOCK_FREE(char, callXmlP);
+ XMLRPC_MEMBLOCK_FREE(char, respXmlP);
+
+ strfree(url);
+
+ freeCmdline(cmdline);
+
+ xmlrpc_env_clean(&env);
+
+ return 0;
+}