Merge pull request #121 from Dima73/timer
[openblackhole/openblackhole-enigma2.git] / lib / network / xmlrpc.cpp
1 #ifndef DISABLE_NETWORK
2
3 #include <lib/network/xmlrpc.h>
4 #include <lib/base/estring.h>
5
6
7 static std::map<std::string, int (*)(std::vector<eXMLRPCVariant>&, ePtrList<eXMLRPCVariant>&)> rpcproc;
8
9 void eXMLRPCVariant::zero()
10 {
11         _struct=0;
12         _array=0;
13         _i4=0;
14         _boolean=0;
15         _string=0;
16         _double=0;
17 //      _datetime=0;
18 //      _base64=0;
19 }
20
21 eXMLRPCVariant::eXMLRPCVariant(std::map<std::string,eXMLRPCVariant*> *__struct)
22 {
23         zero();
24         _struct=__struct;
25 }
26
27 eXMLRPCVariant::eXMLRPCVariant(std::vector<eXMLRPCVariant> *__array)
28 {
29         zero();
30         _array=__array;
31 }
32
33 eXMLRPCVariant::eXMLRPCVariant(__s32 *__i4)
34 {
35         zero();
36         _i4=__i4;
37 }
38
39 eXMLRPCVariant::eXMLRPCVariant(bool *__boolean)
40 {
41         zero();
42         _boolean=__boolean;
43 }
44
45 eXMLRPCVariant::eXMLRPCVariant(std::string *__string)
46 {
47         zero();
48         _string=__string;
49 }
50
51 eXMLRPCVariant::eXMLRPCVariant(double *__double)
52 {
53         zero();
54         _double=__double;
55 }
56
57 /*eXMLRPCVariant::eXMLRPCVariant(QDateTime *__datetime)
58 {
59         zero();
60         _datetime=__datetime;
61 } */
62
63 /*eXMLRPCVariant::eXMLRPCVariant(QByteArray *__base64)
64 {
65         zero();
66         _base64=__base64;
67 } */
68
69 eXMLRPCVariant::eXMLRPCVariant(const eXMLRPCVariant &c)
70 {
71         zero();
72         if (c._i4)
73                 _i4=new int(*c._i4);
74         if (c._boolean)
75                 _boolean=new bool(*c._boolean);
76         if (c._string)
77                 _string=new std::string(*c._string);
78         if (c._double)
79                 _double=new double(*c._double);
80         // datetime, base64
81         if (c._struct)
82         {
83                 _struct=new std::map<std::string,eXMLRPCVariant*>;
84                 for (std::map<std::string,eXMLRPCVariant*>::iterator b(c._struct->begin()); b != c._struct->end(); ++b)
85                         _struct->insert(std::pair<std::string,eXMLRPCVariant*>(b->first, new eXMLRPCVariant(*b->second)));
86         }
87         if (c._array)
88                 _array = new std::vector<eXMLRPCVariant>(*c._array);
89 }
90
91 eXMLRPCVariant::~eXMLRPCVariant()
92 {
93         if (_struct)
94         {
95                 for (std::map<std::string,eXMLRPCVariant*>::iterator i(_struct->begin()); i != _struct->end(); ++i)
96                         delete i->second;
97
98                 delete _struct;
99         }
100         if (_array)
101                 delete _array;
102         if (_i4)
103                 delete _i4;
104         if (_boolean)
105                 delete _boolean;
106         if (_string)
107                 delete _string;
108         if (_double)
109                 delete _string;
110 /*      if (_datetime)
111                 delete _datetime;*/
112 /*      if (_base64)
113                 delete _base64;*/
114 }
115
116 std::map<std::string,eXMLRPCVariant*> *eXMLRPCVariant::getStruct()
117 {
118         return _struct;
119 }
120
121 std::vector<eXMLRPCVariant> *eXMLRPCVariant::getArray()
122 {
123         return _array;
124 }
125
126 __s32 *eXMLRPCVariant::getI4()
127 {
128         return _i4;
129 }
130
131 bool *eXMLRPCVariant::getBoolean()
132 {
133         return _boolean;
134 }
135
136 std::string *eXMLRPCVariant::getString()
137 {
138         return _string;
139 }
140
141 double *eXMLRPCVariant::getDouble()
142 {
143         return _double;
144 }
145
146 /*QDateTime *eXMLRPCVariant::getDatetime()
147 {
148         return _datetime;
149 } */
150
151 /*QByteArray *eXMLRPCVariant::getBase64()
152 {
153         return _base64;
154 } */
155
156 void eXMLRPCVariant::toXML(std::string &result)
157 {
158         if (getArray())
159         {
160                 static std::string s1("<value><array><data>");
161                 result+=s1;
162                 for (unsigned int i=0; i<getArray()->size(); i++)
163                 {
164                         static std::string s("  ");
165                         result+=s;
166                         (*getArray())[i].toXML(result);
167                         static std::string s1("\n");
168                         result+=s1;
169                 }
170                 static std::string s2("</data></array></value>\n");
171                 result+=s2;
172         } else if (getStruct())
173         {
174                 static std::string s1("<value><struct>");
175                 result+=s1;
176                 for (std::map<std::string,eXMLRPCVariant*>::iterator i(_struct->begin()); i != _struct->end(); ++i)
177                 {
178                         static std::string s1("  <member><name>");
179                         result+=s1;
180                         result+=i->first;
181                         static std::string s2("</name>");
182                         result+=s2;
183                         i->second->toXML(result);
184                         static std::string s3("</member>\n");
185                         result+=s3;
186                 }
187                 static std::string s2("</struct></value>\n");
188                 result+=s2;
189         } else if (getI4())
190         {
191                 static std::string s1("<value><i4>");
192                 result+=s1;
193                 result+=getNum(*getI4());
194                 static std::string s2("</i4></value>");
195                 result+=s2;
196         } else if (getBoolean())
197         {
198                 static std::string s0("<value><boolean>0</boolean></value>");
199                 static std::string s1("<value><boolean>1</boolean></value>");
200                 result+=(*getBoolean())?s1:s0;
201         } else if (getString())
202         {
203                 static std::string s1("<value><string>");
204                 static std::string s2("</string></value>");
205                 result+=s1;
206                 result+=*getString();
207                 result+=s2;
208         } else if (getDouble())
209         {
210 //              result+=std::string().sprintf("<value><double>%lf</double></value>", *getDouble());
211 #warning double support removed
212         }       else
213                 eFatal("[eXMLRPCVariant] couldn't append");
214 }
215
216 static eXMLRPCVariant *fromXML(XMLTreeNode *n)
217 {
218         if (strcmp(n->GetType(), "value"))
219                 return 0;
220         n=n->GetChild();
221         const char *data=n->GetData();
222         if (!data)
223                 data="";
224         if ((!strcmp(n->GetType(), "i4")) || (!strcmp(n->GetType(), "int")))
225                 return new eXMLRPCVariant(new int(atoi(data)));
226         else if (!strcmp(n->GetType(), "boolean"))
227                 return new eXMLRPCVariant(new bool(atoi(data)));
228         else if (!strcmp(n->GetType(), "string"))
229                 return new eXMLRPCVariant(new std::string(data));
230         else if (!strcmp(n->GetType(), "double"))
231                 return new eXMLRPCVariant(new double(atof(data)));
232         else if (!strcmp(n->GetType(), "struct")) {
233                 std::map<std::string,eXMLRPCVariant*> *s=new std::map<std::string,eXMLRPCVariant*>;
234                 for (n=n->GetChild(); n; n=n->GetNext())
235                 {
236                         if (strcmp(data, "member"))
237                         {
238                                 delete s;
239                                 return 0;
240                         }
241                         std::string name("");
242                         eXMLRPCVariant *value;
243                         for (XMLTreeNode *v=n->GetChild(); v; v=v->GetNext())
244                         {
245                                 if (!strcmp(v->GetType(), "name"))
246                                         name=std::string(v->GetData());
247                                 else if (!strcmp(v->GetType(), "value"))
248                                         value=fromXML(v);
249                         }
250                         if ((!value) || name.empty())
251                         {
252                                 delete s;
253                                 return 0;
254                         }
255                         s->INSERT(name,value);
256                 }
257                 return new eXMLRPCVariant(s);
258         } else if (!strcmp(n->GetType(), "array"))
259         {
260                 ePtrList<eXMLRPCVariant> l;
261                 #warning autodelete removed
262 //              l.setAutoDelete(true);
263                 n=n->GetChild();
264                 if (strcmp(data, "data"))
265                         return 0;
266                 for (n=n->GetChild(); n; n=n->GetNext())
267                         if (!strcmp(n->GetType(), "value"))
268                         {
269                                 eXMLRPCVariant *value=fromXML(n);
270                                 if (!value)
271                                         return 0;
272                                 l.push_back(value);
273                         }
274
275                 return new eXMLRPCVariant( l.getVector() );
276         }
277         eDebug("[eXMLRPCVariant] couldn't convert %s", n->GetType());
278         return 0;
279 }
280
281 eXMLRPCResponse::eXMLRPCResponse(eHTTPConnection *c):
282         eHTTPDataSource(c), parser("ISO-8859-1")
283 {
284         // size etc. setzen aber erst NACH data-phase
285         connection->localstate=eHTTPConnection::stateWait;
286 }
287
288 eXMLRPCResponse::~eXMLRPCResponse()
289 {
290 }
291
292 int eXMLRPCResponse::doCall()
293 {
294         eDebug("[eXMLRPCResponse] doing call");
295         result="";
296                 // get method name
297         std::string methodName("");
298
299         if (connection->remote_header["Content-Type"]!="text/xml")
300         {
301                 eDebug("[eXMLRPCResponse] remote header failure (%s != text/xml)", (connection->remote_header["Content-Type"]).c_str());
302                 return -3;
303         }
304
305         XMLTreeNode *methodCall=parser.RootNode();
306         if (!methodCall)
307         {
308                 eDebug("[eXMLRPCResponse] empty xml");
309                 return -1;
310         }
311         if (strcmp(methodCall->GetType(), "methodCall"))
312         {
313                 eDebug("[eXMLRPCResponse] no methodCall found");
314                 return -2;
315         }
316
317         ePtrList<eXMLRPCVariant> params;
318 //      params.setAutoDelete(true);
319 #warning params autodelete remove
320
321         for (XMLTreeNode *c=methodCall->GetChild(); c; c=c->GetNext())
322         {
323                 if (!strcmp(c->GetType(), "methodName"))
324                         methodName=std::string(c->GetData());
325                 else if (!strcmp(c->GetType(), "params"))
326                 {
327                         for (XMLTreeNode *p=c->GetChild(); p; p=p->GetNext())
328                                 if (!strcmp(p->GetType(), "param"))
329                                         params.push_back(fromXML(p->GetChild()));
330                 } else
331                 {
332                         eDebug("[eXMLRPCResponse] unknown stuff found");
333                         return 0;
334                 }
335         }
336
337         if (methodName.empty())
338         {
339                 eDebug("[eXMLRPCResponse] no methodName found!");
340                 return -3;
341         }
342
343         eDebug("[eXMLRPCResponse] methodName: %s", methodName.c_str() );
344
345         result="<?xml version=\"1.0\"?>\n"
346                 "<methodResponse>";
347
348         ePtrList<eXMLRPCVariant> ret;
349 //      ret.setAutoDelete(true);
350 #warning autodelete removed
351
352         int (*proc)(std::vector<eXMLRPCVariant>&, ePtrList<eXMLRPCVariant> &)=rpcproc[methodName];
353         int fault;
354
355         std::vector<eXMLRPCVariant>* v = params.getVector();
356
357         if (!proc)
358         {
359                 fault=1;
360                 xmlrpc_fault(ret, -1, "called method not present");
361         } else
362                 fault=proc( *v , ret);
363
364         delete v;
365
366         eDebug("[eXMLRPCResponse] converting to text...");
367
368         if (fault)
369         {
370                 result+="<fault>\n";
371                 ret.current()->toXML(result);
372                 result+="</fault>\n";
373         } else
374         {
375                 result+="<params>\n";
376                 for (ePtrList<eXMLRPCVariant>::iterator i(ret); i != ret.end(); ++i)
377                 {
378                         result+="<param>";
379                         i->toXML(result);
380                         result+="</param>";
381                 }
382                 result+="</params>";
383         }
384         result+="</methodResponse>";
385         char buffer[10];
386         snprintf(buffer, 10, "%d", size=result.length());
387         wptr=0;
388         connection->local_header["Content-Type"]="text/xml";
389         connection->local_header["Content-Length"]=buffer;
390         connection->code=200;
391         connection->code_descr="OK";
392         connection->localstate=eHTTPConnection::stateResponse;
393         return 0;
394 }
395
396 int eXMLRPCResponse::doWrite(int hm)
397 {
398         int tw=size-wptr;
399         if (tw>hm)
400                 tw=hm;
401         if (tw<=0)
402                 return -1;
403         connection->writeBlock(result.c_str()+wptr, tw);
404         wptr+=tw;
405         return size > wptr ? 1 : -1;
406 }
407
408 void eXMLRPCResponse::haveData(void *data, int len)
409 {
410         if (result)
411                 return;
412         int err=0;
413
414         if (!parser.Parse((char*)data, len, !len))
415         {
416                 char temp[len+1];
417                 temp[len]=0;
418                 memcpy(temp, data, len);
419                 eDebug("[eXMLRPCResponse] %s: %s", temp, parser.ErrorString(parser.GetErrorCode()));
420                 err=1;
421         }
422
423         if ((!err) && (!len))
424                 err=doCall();
425
426         if (err)
427         {
428                 connection->code=400;
429                 connection->code_descr="Bad request";
430                 char buffer[10];
431                 snprintf(buffer, 10, "%d", size=result.length());
432                 wptr=0;
433                 connection->local_header["Content-Type"]="text/html";
434                 connection->local_header["Content-Length"]=buffer;
435                 result.sprintf("XMLRPC error %d\n", err);
436                 connection->localstate=eHTTPConnection::stateResponse;
437         }
438 }
439
440 void xmlrpc_initialize(eHTTPD *httpd)
441 {
442         httpd->addResolver(new eHTTPXMLRPCResolver);
443 }
444
445 void xmlrpc_addMethod(const std::string& methodName, int (*proc)(std::vector<eXMLRPCVariant>&, ePtrList<eXMLRPCVariant>&))
446 {
447         rpcproc[methodName]=proc;
448 }
449
450 void xmlrpc_fault(ePtrList<eXMLRPCVariant> &res, int faultCode, std::string faultString)
451 {
452         std::map<std::string,eXMLRPCVariant*> *s=new std::map<std::string,eXMLRPCVariant*>;
453         s->INSERT("faultCode", new eXMLRPCVariant(new __s32(faultCode)));
454         s->INSERT("faultString", new eXMLRPCVariant(new std::string(faultString)));
455         res.push_back(new eXMLRPCVariant(s));
456 }
457
458 int xmlrpc_checkArgs(const std::string& args, std::vector<eXMLRPCVariant> &parm, ePtrList<eXMLRPCVariant> &res)
459 {
460         if (parm.size() != args.length())
461         {
462                 xmlrpc_fault(res, -500, std::string().sprintf("parameter count mismatch (found %d, expected %d)", parm.size(), args.length()));
463                 return 1;
464         }
465
466         for (unsigned int i=0; i<args.length(); i++)
467         {
468                 switch (args[i])
469                 {
470                 case 'i':
471                         if (parm[i].getI4())
472                                 continue;
473                         break;
474                 case 'b':
475                         if (parm[i].getBoolean())
476                                 continue;
477                         break;
478                 case 's':
479                         if (parm[i].getString())
480                                 continue;
481                         break;
482                 case 'd':
483                         if (parm[i].getDouble())
484                                 continue;
485                         break;
486 /*              case 't':
487                         if (parm[i].getDatetime())
488                                 continue;
489                         break;
490                 case '6':
491                         if (parm[i].getBase64())
492                                 continue;
493                         break;*/
494                 case '$':
495                         if (parm[i].getStruct())
496                                 continue;
497                         break;
498                 case 'a':
499                         if (parm[i].getArray())
500                                 continue;
501                         break;
502                 }
503                 xmlrpc_fault(res, -501, std::string().sprintf("parameter type mismatch, expected %c as #%d", args[i], i));
504                 return 1;
505         }
506         return 0;
507 }
508
509 eHTTPXMLRPCResolver::eHTTPXMLRPCResolver()
510 {
511 }
512
513 eHTTPDataSource *eHTTPXMLRPCResolver::getDataSource(const std::string& request, const std::string& path, eHTTPConnection *conn)
514 {
515         if ((path=="/RPC2") && (request=="POST"))
516                 return new eXMLRPCResponse(conn);
517         if ((path=="/SID2") && (request=="POST"))
518                 return new eXMLRPCResponse(conn);
519         return 0;
520 }
521
522 #endif //DISABLE_NETWORK