trunk 20080912
[gitenigma.git] / lib / system / xmlrpc.cpp
blob1ec2204798d7332a507c0fe1550fff411c5886f1
1 #ifndef DISABLE_NETWORK
3 #include <lib/system/xmlrpc.h>
5 #include <lib/dvb/dvb.h>
6 #include <lib/dvb/edvb.h>
8 static std::map<eString, int (*)(std::vector<eXMLRPCVariant>&, ePtrList<eXMLRPCVariant>&)> rpcproc;
10 eXMLRPCVariant::eXMLRPCVariant(const eXMLRPCVariant &c)
11 :type(c.type)
13 switch ( type )
15 case STRUCT:
16 if ( c._struct )
17 _struct=new std::map<eString,eXMLRPCVariant*>;
18 for (std::map<eString,eXMLRPCVariant*>::iterator b(c._struct->begin()); b != c._struct->end(); ++b)
19 _struct->insert(std::pair<eString,eXMLRPCVariant*>(b->first, new eXMLRPCVariant(*b->second)));
20 break;
21 case ARRAY:
22 if (c._array)
23 _array = new std::vector<eXMLRPCVariant>(*c._array);
24 break;
25 case I4:
26 if (c._i4)
27 _i4=new int(*c._i4);
28 break;
29 case BOOLEAN:
30 if (c._boolean)
31 _boolean=new bool(*c._boolean);
32 break;
33 case STRING:
34 if (c._string)
35 _string=new eString(*c._string);
36 break;
37 case DOUBLE:
38 if (c._double)
39 _double=new double(*c._double);
40 break;
44 eXMLRPCVariant::~eXMLRPCVariant()
46 switch ( type )
48 case STRUCT:
49 for (std::map<eString,eXMLRPCVariant*>::iterator i(_struct->begin()); i != _struct->end(); ++i)
50 delete i->second;
51 delete _struct;
52 break;
53 case ARRAY:
54 delete _array;
55 break;
56 case I4:
57 delete _i4;
58 break;
59 case BOOLEAN:
60 delete _boolean;
61 break;
62 case STRING:
63 delete _string;
64 break;
65 case DOUBLE:
66 delete _double;
67 break;
71 void eXMLRPCVariant::toXML(eString &result)
73 switch (type)
75 case ARRAY:
77 static eString s1("<value><array><data>");
78 result+=s1;
79 for (unsigned int i=0; i<getArray()->size(); i++)
81 static eString s(" ");
82 result+=s;
83 (*getArray())[i].toXML(result);
84 static eString s1("\n");
85 result+=s1;
87 static eString s2("</data></array></value>\n");
88 result+=s2;
89 break;
91 case STRUCT:
93 static eString s1("<value><struct>");
94 result+=s1;
95 for (std::map<eString,eXMLRPCVariant*>::iterator i(_struct->begin()); i != _struct->end(); ++i)
97 static eString s1(" <member><name>");
98 result+=s1;
99 result+=i->first;
100 static eString s2("</name>");
101 result+=s2;
102 i->second->toXML(result);
103 static eString s3("</member>\n");
104 result+=s3;
106 static eString s2("</struct></value>\n");
107 result+=s2;
108 break;
110 case I4:
112 static eString s1("<value><i4>");
113 result+=s1;
114 result+=eString().setNum(*getI4());
115 static eString s2("</i4></value>");
116 result+=s2;
117 break;
119 case BOOLEAN:
121 static eString s0("<value><boolean>0</boolean></value>");
122 static eString s1("<value><boolean>1</boolean></value>");
123 result+=(*getBoolean())?s1:s0;
124 break;
126 case STRING:
128 static eString s1("<value><string>");
129 static eString s2("</string></value>");
130 result+=s1;
131 result+=*getString();
132 result+=s2;
133 break;
135 case DOUBLE:
137 result+=eString().sprintf("<value><double>%lf</double></value>", *getDouble());
142 static eXMLRPCVariant *fromXML(XMLTreeNode *n)
144 if (strcmp(n->GetType(), "value"))
145 return 0;
146 n=n->GetChild();
147 const char *data=n->GetData();
148 if (!data)
149 data="";
150 if ((!strcmp(n->GetType(), "i4")) || (!strcmp(n->GetType(), "int")))
151 return new eXMLRPCVariant(new int(atoi(data)));
152 else if (!strcmp(n->GetType(), "boolean"))
153 return new eXMLRPCVariant(new bool(atoi(data)));
154 else if (!strcmp(n->GetType(), "string"))
155 return new eXMLRPCVariant(new eString(data));
156 else if (!strcmp(n->GetType(), "double"))
157 return new eXMLRPCVariant(new double(atof(data)));
158 else if (!strcmp(n->GetType(), "struct")) {
159 std::map<eString,eXMLRPCVariant*> *s=new std::map<eString,eXMLRPCVariant*>;
160 for (n=n->GetChild(); n; n=n->GetNext())
162 if (strcmp(data, "member"))
164 delete s;
165 return 0;
167 eString name=0;
168 eXMLRPCVariant *value;
169 for (XMLTreeNode *v=n->GetChild(); v; v=v->GetNext())
171 if (!strcmp(v->GetType(), "name"))
172 name=eString(v->GetData());
173 else if (!strcmp(v->GetType(), "value"))
174 value=fromXML(v);
176 if ((!value) || (!name))
178 delete s;
179 return 0;
181 s->INSERT(name,value);
183 return new eXMLRPCVariant(s);
184 } else if (!strcmp(n->GetType(), "array"))
186 ePtrList<eXMLRPCVariant> l;
187 l.setAutoDelete(true);
188 n=n->GetChild();
189 if (strcmp(data, "data"))
190 return 0;
191 for (n=n->GetChild(); n; n=n->GetNext())
192 if (!strcmp(n->GetType(), "value"))
194 eXMLRPCVariant *value=fromXML(n);
195 if (!value)
196 return 0;
197 l.push_back(value);
200 return new eXMLRPCVariant( l.getVector() );
202 eDebug("couldn't convert %s", n->GetType());
203 return 0;
206 eXMLRPCResponse::eXMLRPCResponse(eHTTPConnection *c):
207 eHTTPDataSource(c), parser("ISO-8859-1")
209 // size etc. setzen aber erst NACH data-phase
210 connection->localstate=eHTTPConnection::stateWait;
213 eXMLRPCResponse::~eXMLRPCResponse()
217 int eXMLRPCResponse::doCall()
219 eDebug("doing call");
220 result="";
221 // get method name
222 eString methodName=0;
224 if (connection->remote_header["Content-Type"]!="text/xml")
226 eDebug("remote header failure (%s != text/xml)", (connection->remote_header["Content-Type"]).c_str());
227 return -3;
230 XMLTreeNode *methodCall=parser.RootNode();
231 if (!methodCall)
233 eDebug("empty xml");
234 return -1;
236 if (strcmp(methodCall->GetType(), "methodCall"))
238 eDebug("no methodCall found");
239 return -2;
242 ePtrList<eXMLRPCVariant> params;
243 params.setAutoDelete(true);
245 for (XMLTreeNode *c=methodCall->GetChild(); c; c=c->GetNext())
247 if (!strcmp(c->GetType(), "methodName"))
248 methodName=eString(c->GetData());
249 else if (!strcmp(c->GetType(), "params"))
251 for (XMLTreeNode *p=c->GetChild(); p; p=p->GetNext())
252 if (!strcmp(p->GetType(), "param"))
253 params.push_back(fromXML(p->GetChild()));
254 } else
256 eDebug("unknown stuff found");
257 return 0;
261 if (!methodName)
263 eDebug("no methodName found!");
264 return -3;
267 eDebug("methodName: %s", methodName.c_str() );
269 result="<?xml version=\"1.0\"?>\n"
270 "<methodResponse>";
272 ePtrList<eXMLRPCVariant> ret;
273 ret.setAutoDelete(true);
275 int (*proc)(std::vector<eXMLRPCVariant>&, ePtrList<eXMLRPCVariant> &)=rpcproc[methodName];
276 int fault;
278 std::vector<eXMLRPCVariant>* v = params.getVector();
280 if (!proc)
282 fault=1;
283 xmlrpc_fault(ret, -1, "called method not present");
284 } else
285 fault=proc( *v , ret);
287 delete v;
289 eDebug("converting to text...");
291 if (fault)
293 result+="<fault>\n";
294 ret.current()->toXML(result);
295 result+="</fault>\n";
296 } else
298 result+="<params>\n";
299 for (ePtrList<eXMLRPCVariant>::iterator i(ret); i != ret.end(); ++i)
301 result+="<param>";
302 i->toXML(result);
303 result+="</param>";
305 result+="</params>";
307 result+="</methodResponse>";
308 char buffer[10];
309 snprintf(buffer, 10, "%d", size=result.length());
310 wptr=0;
311 connection->local_header["Content-Type"]="text/xml";
312 connection->local_header["Content-Length"]=buffer;
313 connection->code=200;
314 connection->code_descr="OK";
315 connection->localstate=eHTTPConnection::stateResponse;
316 return 0;
319 int eXMLRPCResponse::doWrite(int hm)
321 int tw=size-wptr;
322 if (tw>hm)
323 tw=hm;
324 if (tw<=0)
325 return -1;
326 connection->writeBlock(result.c_str()+wptr, tw);
327 wptr+=tw;
328 return size > wptr ? 1 : -1;
331 void eXMLRPCResponse::haveData(void *data, int len)
333 if (result)
334 return;
335 int err=0;
337 if (!parser.Parse((char*)data, len, !len))
339 char temp[len+1];
340 temp[len]=0;
341 memcpy(temp, data, len);
342 eDebug("%s: %s", temp, parser.ErrorString(parser.GetErrorCode()));
343 err=1;
346 if ((!err) && (!len))
347 err=doCall();
349 if (err)
351 eDebug("schade: %d", err);
352 connection->code=400;
353 connection->code_descr="Bad request";
354 char buffer[10];
355 snprintf(buffer, 10, "%d", size=result.length());
356 wptr=0;
357 connection->local_header["Content-Type"]="text/html";
358 connection->local_header["Content-Length"]=buffer;
359 result.sprintf("XMLRPC error %d\n", err);
360 connection->localstate=eHTTPConnection::stateResponse;
364 void xmlrpc_addMethod(eString methodName, int (*proc)(std::vector<eXMLRPCVariant>&, ePtrList<eXMLRPCVariant>&))
366 rpcproc[methodName]=proc;
369 void xmlrpc_fault(ePtrList<eXMLRPCVariant> &res, int faultCode, eString faultString)
371 std::map<eString,eXMLRPCVariant*> *s=new std::map<eString,eXMLRPCVariant*>;
372 s->INSERT("faultCode", new eXMLRPCVariant(new __s32(faultCode)));
373 s->INSERT("faultString", new eXMLRPCVariant(new eString(faultString)));
374 res.push_back(new eXMLRPCVariant(s));
377 int xmlrpc_checkArgs(eString args, std::vector<eXMLRPCVariant> &parm, ePtrList<eXMLRPCVariant> &res)
379 if (parm.size() != args.length())
381 xmlrpc_fault(res, -500, eString().sprintf("parameter count mismatch (found %d, expected %d)", parm.size(), args.length()));
382 return 1;
385 for (unsigned int i=0; i<args.length(); i++)
387 switch (args[i])
389 case 'i':
390 if (parm[i].getI4())
391 continue;
392 break;
393 case 'b':
394 if (parm[i].getBoolean())
395 continue;
396 break;
397 case 's':
398 if (parm[i].getString())
399 continue;
400 break;
401 case 'd':
402 if (parm[i].getDouble())
403 continue;
404 break;
405 /* case 't':
406 if (parm[i].getDatetime())
407 continue;
408 break;
409 case '6':
410 if (parm[i].getBase64())
411 continue;
412 break;*/
413 case '$':
414 if (parm[i].getStruct())
415 continue;
416 break;
417 case 'a':
418 if (parm[i].getArray())
419 continue;
420 break;
422 xmlrpc_fault(res, -501, eString().sprintf("parameter type mismatch, expected %c as #%d", args[i], i));
423 return 1;
425 return 0;
428 eHTTPXMLRPCResolver::eHTTPXMLRPCResolver()
432 eHTTPDataSource *eHTTPXMLRPCResolver::getDataSource(eString request, eString path, eHTTPConnection *conn)
434 if ((path=="/RPC2") && (request=="POST"))
435 return new eXMLRPCResponse(conn);
436 if ((path=="/SID2") && (request=="POST"))
437 return new eXMLRPCResponse(conn);
438 return 0;
441 #endif //DISABLE_NETWORK