1 /*
2   This file is part of libXMLRPC - a C library for xml-encoded function calls.
3 
4   Author: Dan Libby (dan@libby.com)
5   Epinions.com may be contacted at feedback@epinions-inc.com
6 */
7 
8 /*
9   Copyright 2000 Epinions, Inc.
10 
11   Subject to the following 3 conditions, Epinions, Inc.  permits you, free
12   of charge, to (a) use, copy, distribute, modify, perform and display this
13   software and associated documentation files (the "Software"), and (b)
14   permit others to whom the Software is furnished to do so as well.
15 
16   1) The above copyright notice and this permission notice shall be included
17   without modification in all copies or substantial portions of the
18   Software.
19 
20   2) THE SOFTWARE IS PROVIDED "AS IS", WITHOUT ANY WARRANTY OR CONDITION OF
21   ANY KIND, EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION ANY
22   IMPLIED WARRANTIES OF ACCURACY, MERCHANTABILITY, FITNESS FOR A PARTICULAR
23   PURPOSE OR NONINFRINGEMENT.
24 
25   3) IN NO EVENT SHALL EPINIONS, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
26   SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OR LOST PROFITS ARISING OUT
27   OF OR IN CONNECTION WITH THE SOFTWARE (HOWEVER ARISING, INCLUDING
28   NEGLIGENCE), EVEN IF EPINIONS, INC.  IS AWARE OF THE POSSIBILITY OF SUCH
29   DAMAGES.
30 
31 */
32 
33 #include <string.h>
34 #include <stdlib.h>
35 #include "xml_to_dandarpc.h"
36 #include "base64.h"
37 
38 /* list of tokens used in vocab */
39 #define ELEM_METHODCALL     "methodCall"
40 #define ELEM_METHODNAME     "methodName"
41 #define ELEM_METHODRESPONSE "methodResponse"
42 #define ELEM_ROOT           "simpleRPC"
43 
44 #define ATTR_ARRAY          "array"
45 #define ATTR_BASE64         "base64"
46 #define ATTR_BOOLEAN        "boolean"
47 #define ATTR_DATETIME       "dateTime.iso8601"
48 #define ATTR_DOUBLE         "double"
49 #define ATTR_ID             "id"
50 #define ATTR_INT            "int"
51 #define ATTR_MIXED          "mixed"
52 #define ATTR_SCALAR         "scalar"
53 #define ATTR_STRING         "string"
54 #define ATTR_STRUCT         "struct"
55 #define ATTR_TYPE           "type"
56 #define ATTR_VECTOR         "vector"
57 #define ATTR_VERSION        "version"
58 
59 #define VAL_VERSION_0_9     "0.9"
60 
61 
xml_element_to_DANDARPC_REQUEST_worker(XMLRPC_REQUEST request,XMLRPC_VALUE xCurrent,xml_element * el)62 XMLRPC_VALUE xml_element_to_DANDARPC_REQUEST_worker(XMLRPC_REQUEST request, XMLRPC_VALUE xCurrent, xml_element* el) {
63    if(!xCurrent) {
64       xCurrent = XMLRPC_CreateValueEmpty();
65    }
66 
67    if(el->name) {
68       const char* id = NULL;
69       const char* type = NULL;
70       xml_element_attr* attr_iter = Q_Head(&el->attrs);
71 
72       while(attr_iter) {
73          if(!strcmp(attr_iter->key, ATTR_ID)) {
74             id = attr_iter->val;
75          }
76          if(!strcmp(attr_iter->key, ATTR_TYPE)) {
77             type = attr_iter->val;
78          }
79          attr_iter = Q_Next(&el->attrs);
80       }
81 
82       if(id) {
83          XMLRPC_SetValueID_Case(xCurrent, id, 0, xmlrpc_case_exact);
84       }
85 
86       if(!strcmp(el->name, ATTR_SCALAR)) {
87          if(!type || !strcmp(type, ATTR_STRING)) {
88             XMLRPC_SetValueString(xCurrent, el->text.str, el->text.len);
89          }
90          else if(!strcmp(type, ATTR_INT)) {
91             XMLRPC_SetValueInt(xCurrent, atoi(el->text.str));
92          }
93          else if(!strcmp(type, ATTR_BOOLEAN)) {
94             XMLRPC_SetValueBoolean(xCurrent, atoi(el->text.str));
95          }
96          else if(!strcmp(type, ATTR_DOUBLE)) {
97             XMLRPC_SetValueDouble(xCurrent, atof(el->text.str));
98          }
99          else if(!strcmp(type, ATTR_DATETIME)) {
100             XMLRPC_SetValueDateTime_ISO8601(xCurrent, el->text.str);
101          }
102          else if(!strcmp(type, ATTR_BASE64)) {
103             struct buffer_st buf;
104             base64_decode_xmlrpc(&buf, el->text.str, el->text.len);
105             XMLRPC_SetValueBase64(xCurrent, buf.data, buf.offset);
106             buffer_delete(&buf);
107          }
108       }
109       else if(!strcmp(el->name, ATTR_VECTOR)) {
110          xml_element* iter = (xml_element*)Q_Head(&el->children);
111 
112          if(!type || !strcmp(type, ATTR_MIXED)) {
113             XMLRPC_SetIsVector(xCurrent, xmlrpc_vector_mixed);
114          }
115          else if(!strcmp(type, ATTR_ARRAY)) {
116 				XMLRPC_SetIsVector(xCurrent, xmlrpc_vector_array);
117          }
118          else if(!strcmp(type, ATTR_STRUCT)) {
119             XMLRPC_SetIsVector(xCurrent, xmlrpc_vector_struct);
120          }
121          while( iter ) {
122             XMLRPC_VALUE xNext = XMLRPC_CreateValueEmpty();
123             xml_element_to_DANDARPC_REQUEST_worker(request, xNext, iter);
124             XMLRPC_AddValueToVector(xCurrent, xNext);
125             iter = (xml_element*)Q_Next(&el->children);
126          }
127       }
128       else {
129          xml_element* iter = (xml_element*)Q_Head(&el->children);
130          while( iter ) {
131             xml_element_to_DANDARPC_REQUEST_worker(request, xCurrent, iter);
132             iter = (xml_element*)Q_Next(&el->children);
133          }
134 
135          if(!strcmp(el->name, ELEM_METHODCALL)) {
136             if(request) {
137                XMLRPC_RequestSetRequestType(request, xmlrpc_request_call);
138             }
139          }
140          else if(!strcmp(el->name, ELEM_METHODRESPONSE)) {
141             if(request) {
142                XMLRPC_RequestSetRequestType(request, xmlrpc_request_response);
143             }
144          }
145          else if(!strcmp(el->name, ELEM_METHODNAME)) {
146             if(request) {
147                XMLRPC_RequestSetMethodName(request, el->text.str);
148             }
149          }
150       }
151    }
152    return xCurrent;
153 }
154 
xml_element_to_DANDARPC_VALUE(xml_element * el)155 XMLRPC_VALUE xml_element_to_DANDARPC_VALUE(xml_element* el)
156 {
157    return xml_element_to_DANDARPC_REQUEST_worker(NULL, NULL, el);
158 }
159 
xml_element_to_DANDARPC_REQUEST(XMLRPC_REQUEST request,xml_element * el)160 XMLRPC_VALUE xml_element_to_DANDARPC_REQUEST(XMLRPC_REQUEST request, xml_element* el)
161 {
162    if(request) {
163       return XMLRPC_RequestSetData(request, xml_element_to_DANDARPC_REQUEST_worker(request, NULL, el));
164    }
165    return NULL;
166 }
167 
DANDARPC_to_xml_element_worker(XMLRPC_REQUEST request,XMLRPC_VALUE node)168 xml_element* DANDARPC_to_xml_element_worker(XMLRPC_REQUEST request, XMLRPC_VALUE node) {
169 #define BUF_SIZE 512
170    xml_element* root = NULL;
171    if(node) {
172       char buf[BUF_SIZE];
173       const char* id = XMLRPC_GetValueID(node);
174       XMLRPC_VALUE_TYPE type = XMLRPC_GetValueType(node);
175       XMLRPC_REQUEST_OUTPUT_OPTIONS output = XMLRPC_RequestGetOutputOptions(request);
176       int bNoAddType = (type == xmlrpc_string && request && output && output->xml_elem_opts.verbosity == xml_elem_no_white_space);
177       xml_element* elem_val = xml_elem_new();
178       const char* pAttrType = NULL;
179 
180       xml_element_attr* attr_type = bNoAddType ? NULL : emalloc(sizeof(xml_element_attr));
181 
182       if(attr_type) {
183          attr_type->key = estrdup(ATTR_TYPE);
184          attr_type->val = 0;
185          Q_PushTail(&elem_val->attrs, attr_type);
186       }
187 
188       elem_val->name = (type == xmlrpc_vector) ? estrdup(ATTR_VECTOR) : estrdup(ATTR_SCALAR);
189 
190       if(id && *id) {
191          xml_element_attr* attr_id = emalloc(sizeof(xml_element_attr));
192          if(attr_id) {
193             attr_id->key = estrdup(ATTR_ID);
194             attr_id->val = estrdup(id);
195             Q_PushTail(&elem_val->attrs, attr_id);
196          }
197       }
198 
199       switch(type) {
200          case xmlrpc_string:
201             pAttrType = ATTR_STRING;
202             simplestring_addn(&elem_val->text, XMLRPC_GetValueString(node), XMLRPC_GetValueStringLen(node));
203             break;
204          case xmlrpc_int:
205             pAttrType = ATTR_INT;
206             snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueInt(node));
207             simplestring_add(&elem_val->text, buf);
208             break;
209          case xmlrpc_boolean:
210             pAttrType = ATTR_BOOLEAN;
211             snprintf(buf, BUF_SIZE, "%i", XMLRPC_GetValueBoolean(node));
212             simplestring_add(&elem_val->text, buf);
213             break;
214          case xmlrpc_double:
215             pAttrType = ATTR_DOUBLE;
216             snprintf(buf, BUF_SIZE, "%f", XMLRPC_GetValueDouble(node));
217             simplestring_add(&elem_val->text, buf);
218             break;
219          case xmlrpc_datetime:
220             pAttrType = ATTR_DATETIME;
221             simplestring_add(&elem_val->text, XMLRPC_GetValueDateTime_ISO8601(node));
222             break;
223          case xmlrpc_base64:
224             {
225                struct buffer_st buf;
226                pAttrType = ATTR_BASE64;
227                base64_encode_xmlrpc(&buf, XMLRPC_GetValueBase64(node), XMLRPC_GetValueStringLen(node));
228                simplestring_addn(&elem_val->text, buf.data, buf.offset );
229                buffer_delete(&buf);
230             }
231             break;
232          case xmlrpc_vector:
233             {
234                XMLRPC_VECTOR_TYPE my_type = XMLRPC_GetVectorType(node);
235                XMLRPC_VALUE xIter = XMLRPC_VectorRewind(node);
236 
237                switch(my_type) {
238                   case xmlrpc_vector_array:
239                      pAttrType = ATTR_ARRAY;
240                      break;
241                   case xmlrpc_vector_mixed:
242                      pAttrType = ATTR_MIXED;
243                      break;
244                   case xmlrpc_vector_struct:
245                      pAttrType = ATTR_STRUCT;
246                      break;
247                   default:
248                      break;
249                }
250 
251                /* recurse through sub-elements */
252                while( xIter ) {
253                   xml_element* next_el = DANDARPC_to_xml_element_worker(request, xIter);
254                   if(next_el) {
255                      Q_PushTail(&elem_val->children, next_el);
256                   }
257                   xIter = XMLRPC_VectorNext(node);
258                }
259             }
260             break;
261          default:
262             break;
263       }
264       if(pAttrType && attr_type && !bNoAddType) {
265          attr_type->val = estrdup(pAttrType);
266       }
267       root = elem_val;
268    }
269    return root;
270 }
271 
DANDARPC_VALUE_to_xml_element(XMLRPC_VALUE node)272 xml_element* DANDARPC_VALUE_to_xml_element(XMLRPC_VALUE node) {
273    return DANDARPC_to_xml_element_worker(NULL, node);
274 }
275 
DANDARPC_REQUEST_to_xml_element(XMLRPC_REQUEST request)276 xml_element* DANDARPC_REQUEST_to_xml_element(XMLRPC_REQUEST request) {
277    xml_element* wrapper = NULL;
278    xml_element* root = NULL;
279    if(request) {
280       XMLRPC_REQUEST_TYPE request_type = XMLRPC_RequestGetRequestType(request);
281       const char* pStr = NULL;
282       xml_element_attr* version = emalloc(sizeof(xml_element_attr));
283       version->key = estrdup(ATTR_VERSION);
284       version->val = estrdup(VAL_VERSION_0_9);
285 
286       wrapper = xml_elem_new();
287 
288       if(request_type == xmlrpc_request_response) {
289          pStr = ELEM_METHODRESPONSE;
290       }
291       else if(request_type == xmlrpc_request_call) {
292          pStr = ELEM_METHODCALL;
293       }
294       if(pStr) {
295          wrapper->name = estrdup(pStr);
296       }
297 
298       root = xml_elem_new();
299       root->name = estrdup(ELEM_ROOT);
300       Q_PushTail(&root->attrs, version);
301       Q_PushTail(&root->children, wrapper);
302 
303       pStr = XMLRPC_RequestGetMethodName(request);
304 
305       if(pStr) {
306          xml_element* method = xml_elem_new();
307          method->name = estrdup(ELEM_METHODNAME);
308          simplestring_add(&method->text, pStr);
309          Q_PushTail(&wrapper->children, method);
310       }
311       Q_PushTail(&wrapper->children,
312                  DANDARPC_to_xml_element_worker(request, XMLRPC_RequestGetData(request)));
313    }
314    return root;
315 }
316