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