initial load of upstream version 1.06.32
[xmlrpc-c] / tools / xmlrpc_transport / xmlrpc_transport.c
diff --git a/tools/xmlrpc_transport/xmlrpc_transport.c b/tools/xmlrpc_transport/xmlrpc_transport.c
new file mode 100644 (file)
index 0000000..ad0c7de
--- /dev/null
@@ -0,0 +1,289 @@
+/* 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;
+}