initial load of upstream version 1.06.32
[xmlrpc-c] / tools / xmlrpc_transport / xmlrpc_transport.c
1 /* Transport some XML to a server and get the response back, as if doing
2    an XML-RPC call.
3 */
4
5 #define _GNU_SOURCE
6
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include <string.h>
10
11 #include "config.h"  /* information about this build environment */
12 #include "casprintf.h"
13 #include "mallocvar.h"
14 #include "cmdline_parser.h"
15
16 #include "xmlrpc-c/base.h"
17 #include "xmlrpc-c/client.h"
18
19 #define NAME "xmlrpc_transport command line program"
20 #define VERSION "1.0"
21
22 struct cmdlineInfo {
23     const char *  url;
24     const char *  username;
25     const char *  password;
26     const char *  transport;
27         /* Name of XML transport he wants to use.  NULL if he has no 
28            preference.
29         */
30 };
31
32
33
34 static void 
35 die_if_fault_occurred (xmlrpc_env * const envP) {
36     if (envP->fault_occurred) {
37         fprintf(stderr, "Error: %s (%d)\n",
38                 envP->fault_string, envP->fault_code);
39         exit(1);
40     }
41 }
42
43
44
45 static void GNU_PRINTF_ATTR(2,3)
46 setError(xmlrpc_env * const envP, const char format[], ...) {
47     va_list args;
48     const char * faultString;
49
50     va_start(args, format);
51
52     cvasprintf(&faultString, format, args);
53     va_end(args);
54
55     xmlrpc_env_set_fault(envP, XMLRPC_INTERNAL_ERROR, faultString);
56
57     strfree(faultString);
58 }
59       
60
61
62 static void
63 processArguments(xmlrpc_env *         const envP,
64                  cmdlineParser        const cp,
65                  struct cmdlineInfo * const cmdlineP) {
66
67     if (cmd_argumentCount(cp) < 1)
68         setError(envP, "Not enough arguments.  Need a URL.");
69     else {
70         cmdlineP->url = cmd_getArgument(cp, 0);
71     }
72 }
73
74
75
76 static void
77 parseCommandLine(xmlrpc_env *         const envP,
78                  int                  const argc,
79                  const char **        const argv,
80                  struct cmdlineInfo * const cmdlineP) {
81
82     cmdlineParser const cp = cmd_createOptionParser();
83
84     const char * error;
85
86     cmd_defineOption(cp, "transport", OPTTYPE_STRING);
87     cmd_defineOption(cp, "username",  OPTTYPE_STRING);
88     cmd_defineOption(cp, "password",  OPTTYPE_STRING);
89
90     cmd_processOptions(cp, argc, argv, &error);
91
92     if (error) {
93         setError(envP, "Command syntax error.  %s", error);
94         strfree(error);
95     } else {
96         cmdlineP->username  = cmd_getOptionValueString(cp, "username");
97         cmdlineP->password  = cmd_getOptionValueString(cp, "password");
98
99         if (cmdlineP->username && !cmdlineP->password)
100             setError(envP, "When you specify -username, you must also "
101                      "specify -password.");
102         else {
103             cmdlineP->transport = cmd_getOptionValueString(cp, "transport");
104             
105             processArguments(envP, cp, cmdlineP);
106         }
107     }
108     cmd_destroyOptionParser(cp);
109 }
110
111
112
113 static void
114 freeCmdline(struct cmdlineInfo const cmdline) {
115
116     strfree(cmdline.url);
117     if (cmdline.username)
118         strfree(cmdline.username);
119     if (cmdline.password)
120         strfree(cmdline.password);
121     if (cmdline.transport)
122         strfree(cmdline.transport);
123 }
124
125
126
127 static void
128 computeUrl(const char *  const urlArg,
129            const char ** const urlP) {
130
131     if (strstr(urlArg, "://") != 0) {
132         *urlP = strdup(urlArg);
133     } else {
134         casprintf(urlP, "http://%s/RPC2", urlArg);
135     }        
136 }
137
138
139
140 static void
141 doCall(xmlrpc_env *               const envP,
142        const char *               const transport,
143        const xmlrpc_server_info * const serverInfoP,
144        xmlrpc_mem_block *         const callXmlP,
145        xmlrpc_mem_block **        const respXmlPP) {
146     
147     struct xmlrpc_clientparms clientparms;
148
149     clientparms.transport = transport;
150
151     clientparms.transportparmsP = NULL;
152     clientparms.transportparm_size = 0;
153
154     xmlrpc_client_init2(envP, XMLRPC_CLIENT_NO_FLAGS, NAME, VERSION, 
155                         &clientparms, XMLRPC_CPSIZE(transportparm_size));
156     if (!envP->fault_occurred) {
157         xmlrpc_client_transport_call(envP, NULL, serverInfoP,
158                                      callXmlP, respXmlPP);
159         
160         xmlrpc_client_cleanup();
161     }
162 }
163
164
165
166 static void
167 createServerInfo(xmlrpc_env *          const envP,
168                  const char *          const serverUrl,
169                  const char *          const userName,
170                  const char *          const password,
171                  xmlrpc_server_info ** const serverInfoPP) {
172
173     xmlrpc_server_info * serverInfoP;
174
175     serverInfoP = xmlrpc_server_info_new(envP, serverUrl);
176     if (!envP->fault_occurred) {
177         if (userName) {
178             xmlrpc_server_info_set_basic_auth(
179                 envP, serverInfoP, userName, password);
180         }
181     }
182     *serverInfoPP = serverInfoP;
183 }
184
185
186
187 static void
188 readFile(xmlrpc_env *        const envP,
189          FILE *              const ifP,
190          xmlrpc_mem_block ** const fileContentsPP) {
191
192     xmlrpc_mem_block * fileContentsP;
193
194     fileContentsP = XMLRPC_MEMBLOCK_NEW(char, envP, 0);
195
196     while (!envP->fault_occurred && !feof(ifP)) {
197         char buffer[4096];
198         size_t bytesRead;
199         
200         bytesRead = fread(buffer, 1, sizeof(buffer), ifP);
201         XMLRPC_MEMBLOCK_APPEND(char, envP, 
202                                fileContentsP, buffer, bytesRead);
203     }
204     if (envP->fault_occurred)
205         XMLRPC_MEMBLOCK_FREE(char, fileContentsP);
206
207     *fileContentsPP = fileContentsP;
208 }
209
210
211
212 static void
213 writeFile(xmlrpc_env *       const envP,
214           FILE *             const ofP,
215           xmlrpc_mem_block * const fileContentsP) {
216
217     size_t totalWritten;
218
219     totalWritten = 0;
220
221     while (!envP->fault_occurred &&
222            totalWritten < XMLRPC_MEMBLOCK_SIZE(char, fileContentsP)) {
223         size_t bytesWritten;
224
225         bytesWritten = fwrite(
226             XMLRPC_MEMBLOCK_CONTENTS(char, fileContentsP) + totalWritten,
227             1,
228             XMLRPC_MEMBLOCK_SIZE(char, fileContentsP) - totalWritten,
229             ofP);
230
231         if (bytesWritten < 1)
232             xmlrpc_env_set_fault_formatted(
233                 envP, XMLRPC_INTERNAL_ERROR,
234                 "Error writing output");
235
236         totalWritten -= bytesWritten;
237     }
238 }
239
240
241
242 int 
243 main(int           const argc, 
244      const char ** const argv) {
245
246     struct cmdlineInfo cmdline;
247     xmlrpc_env env;
248     xmlrpc_mem_block * callXmlP;
249     xmlrpc_mem_block * respXmlP;
250     const char * url;
251     xmlrpc_server_info * serverInfoP;
252
253     xmlrpc_env_init(&env);
254
255     parseCommandLine(&env, argc, argv, &cmdline);
256     die_if_fault_occurred(&env);
257
258     computeUrl(cmdline.url, &url);
259
260     createServerInfo(&env, url, cmdline.username, cmdline.password,
261                      &serverInfoP);
262     die_if_fault_occurred(&env);
263
264     fprintf(stderr, "Reading call data from Standard Input...\n");
265
266     readFile(&env, stdin, &callXmlP);
267     die_if_fault_occurred(&env);
268
269     fprintf(stderr, "Making call...\n");
270
271     doCall(&env, cmdline.transport, serverInfoP, callXmlP,
272            &respXmlP);
273     die_if_fault_occurred(&env);
274
275     fprintf(stderr, "Writing response data to Standard Output\n");
276     writeFile(&env, stdout, respXmlP);
277     die_if_fault_occurred(&env);
278
279     XMLRPC_MEMBLOCK_FREE(char, callXmlP);
280     XMLRPC_MEMBLOCK_FREE(char, respXmlP);
281     
282     strfree(url);
283
284     freeCmdline(cmdline);
285
286     xmlrpc_env_clean(&env);
287     
288     return 0;
289 }