/* Transport some XML to a server and get the response back, as if doing an XML-RPC call. */ #define _XOPEN_SOURCE 600 /* Make sure strdup() is in */ #include #include #include #include "xmlrpc_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; }