From fc2f5b2cd655f1391f2abda1b39e37cdec98a951 Mon Sep 17 00:00:00 2001 From: Felix Domke Date: Fri, 17 Oct 2003 15:35:43 +0000 Subject: Initial revision --- lib/network/xmlrpc.cpp | 518 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 518 insertions(+) create mode 100644 lib/network/xmlrpc.cpp (limited to 'lib/network/xmlrpc.cpp') diff --git a/lib/network/xmlrpc.cpp b/lib/network/xmlrpc.cpp new file mode 100644 index 00000000..a53b50a8 --- /dev/null +++ b/lib/network/xmlrpc.cpp @@ -0,0 +1,518 @@ +#ifndef DISABLE_NETWORK + +#include + + +static std::map&, ePtrList&)> rpcproc; + +void eXMLRPCVariant::zero() +{ + _struct=0; + _array=0; + _i4=0; + _boolean=0; + _string=0; + _double=0; +// _datetime=0; +// _base64=0; +} + +eXMLRPCVariant::eXMLRPCVariant(std::map *__struct) +{ + zero(); + _struct=__struct; +} + +eXMLRPCVariant::eXMLRPCVariant(std::vector *__array) +{ + zero(); + _array=__array; +} + +eXMLRPCVariant::eXMLRPCVariant(__s32 *__i4) +{ + zero(); + _i4=__i4; +} + +eXMLRPCVariant::eXMLRPCVariant(bool *__boolean) +{ + zero(); + _boolean=__boolean; +} + +eXMLRPCVariant::eXMLRPCVariant(eString *__string) +{ + zero(); + _string=__string; +} + +eXMLRPCVariant::eXMLRPCVariant(double *__double) +{ + zero(); + _double=__double; +} + +/*eXMLRPCVariant::eXMLRPCVariant(QDateTime *__datetime) +{ + zero(); + _datetime=__datetime; +} */ + +/*eXMLRPCVariant::eXMLRPCVariant(QByteArray *__base64) +{ + zero(); + _base64=__base64; +} */ + +eXMLRPCVariant::eXMLRPCVariant(const eXMLRPCVariant &c) +{ + zero(); + if (c._i4) + _i4=new int(*c._i4); + if (c._boolean) + _boolean=new bool(*c._boolean); + if (c._string) + _string=new eString(*c._string); + if (c._double) + _double=new double(*c._double); + // datetime, base64 + if (c._struct) + { + _struct=new std::map; + for (std::map::iterator b(c._struct->begin()); b != c._struct->end(); ++b) + _struct->insert(std::pair(b->first, new eXMLRPCVariant(*b->second))); + } + if (c._array) + _array = new std::vector(*c._array); +} + +eXMLRPCVariant::~eXMLRPCVariant() +{ + if (_struct) + { + for (std::map::iterator i(_struct->begin()); i != _struct->end(); ++i) + delete i->second; + + delete _struct; + } + if (_array) + delete _array; + if (_i4) + delete _i4; + if (_boolean) + delete _boolean; + if (_string) + delete _string; + if (_double) + delete _string; +/* if (_datetime) + delete _datetime;*/ +/* if (_base64) + delete _base64;*/ +} + +std::map *eXMLRPCVariant::getStruct() +{ + return _struct; +} + +std::vector *eXMLRPCVariant::getArray() +{ + return _array; +} + +__s32 *eXMLRPCVariant::getI4() +{ + return _i4; +} + +bool *eXMLRPCVariant::getBoolean() +{ + return _boolean; +} + +eString *eXMLRPCVariant::getString() +{ + return _string; +} + +double *eXMLRPCVariant::getDouble() +{ + return _double; +} + +/*QDateTime *eXMLRPCVariant::getDatetime() +{ + return _datetime; +} */ + +/*QByteArray *eXMLRPCVariant::getBase64() +{ + return _base64; +} */ + +void eXMLRPCVariant::toXML(eString &result) +{ + if (getArray()) + { + static eString s1(""); + result+=s1; + for (unsigned int i=0; isize(); i++) + { + static eString s(" "); + result+=s; + (*getArray())[i].toXML(result); + static eString s1("\n"); + result+=s1; + } + static eString s2("\n"); + result+=s2; + } else if (getStruct()) + { + static eString s1(""); + result+=s1; + for (std::map::iterator i(_struct->begin()); i != _struct->end(); ++i) + { + static eString s1(" "); + result+=s1; + result+=i->first; + static eString s2(""); + result+=s2; + i->second->toXML(result); + static eString s3("\n"); + result+=s3; + } + static eString s2("\n"); + result+=s2; + } else if (getI4()) + { + static eString s1(""); + result+=s1; + result+=eString().setNum(*getI4()); + static eString s2(""); + result+=s2; + } else if (getBoolean()) + { + static eString s0("0"); + static eString s1("1"); + result+=(*getBoolean())?s1:s0; + } else if (getString()) + { + static eString s1(""); + static eString s2(""); + result+=s1; + result+=*getString(); + result+=s2; + } else if (getDouble()) + { + result+=eString().sprintf("%lf", *getDouble()); + } else + eFatal("couldn't append"); +} + +static eXMLRPCVariant *fromXML(XMLTreeNode *n) +{ + if (strcmp(n->GetType(), "value")) + return 0; + n=n->GetChild(); + const char *data=n->GetData(); + if (!data) + data=""; + if ((!strcmp(n->GetType(), "i4")) || (!strcmp(n->GetType(), "int"))) + return new eXMLRPCVariant(new int(atoi(data))); + else if (!strcmp(n->GetType(), "boolean")) + return new eXMLRPCVariant(new bool(atoi(data))); + else if (!strcmp(n->GetType(), "string")) + return new eXMLRPCVariant(new eString(data)); + else if (!strcmp(n->GetType(), "double")) + return new eXMLRPCVariant(new double(atof(data))); + else if (!strcmp(n->GetType(), "struct")) { + std::map *s=new std::map; + for (n=n->GetChild(); n; n=n->GetNext()) + { + if (strcmp(data, "member")) + { + delete s; + return 0; + } + eString name=0; + eXMLRPCVariant *value; + for (XMLTreeNode *v=n->GetChild(); v; v=v->GetNext()) + { + if (!strcmp(v->GetType(), "name")) + name=eString(v->GetData()); + else if (!strcmp(v->GetType(), "value")) + value=fromXML(v); + } + if ((!value) || (!name)) + { + delete s; + return 0; + } + s->INSERT(name,value); + } + return new eXMLRPCVariant(s); + } else if (!strcmp(n->GetType(), "array")) + { + ePtrList l; + l.setAutoDelete(true); + n=n->GetChild(); + if (strcmp(data, "data")) + return 0; + for (n=n->GetChild(); n; n=n->GetNext()) + if (!strcmp(n->GetType(), "value")) + { + eXMLRPCVariant *value=fromXML(n); + if (!value) + return 0; + l.push_back(value); + } + + return new eXMLRPCVariant( l.getVector() ); + } + eDebug("couldn't convert %s", n->GetType()); + return 0; +} + +eXMLRPCResponse::eXMLRPCResponse(eHTTPConnection *c): + eHTTPDataSource(c), parser("ISO-8859-1") +{ + // size etc. setzen aber erst NACH data-phase + connection->localstate=eHTTPConnection::stateWait; +} + +eXMLRPCResponse::~eXMLRPCResponse() +{ +} + +int eXMLRPCResponse::doCall() +{ + eDebug("doing call"); + result=""; + // get method name + eString methodName=0; + + if (connection->remote_header["Content-Type"]!="text/xml") + { + eDebug("remote header failure (%s != text/xml)", (connection->remote_header["Content-Type"]).c_str()); + return -3; + } + + XMLTreeNode *methodCall=parser.RootNode(); + if (!methodCall) + { + eDebug("empty xml"); + return -1; + } + if (strcmp(methodCall->GetType(), "methodCall")) + { + eDebug("no methodCall found"); + return -2; + } + + ePtrList params; + params.setAutoDelete(true); + + for (XMLTreeNode *c=methodCall->GetChild(); c; c=c->GetNext()) + { + if (!strcmp(c->GetType(), "methodName")) + methodName=eString(c->GetData()); + else if (!strcmp(c->GetType(), "params")) + { + for (XMLTreeNode *p=c->GetChild(); p; p=p->GetNext()) + if (!strcmp(p->GetType(), "param")) + params.push_back(fromXML(p->GetChild())); + } else + { + eDebug("unknown stuff found"); + return 0; + } + } + + if (!methodName) + { + eDebug("no methodName found!"); + return -3; + } + + eDebug("methodName: %s", methodName.c_str() ); + + result="\n" + ""; + + ePtrList ret; + ret.setAutoDelete(true); + + int (*proc)(std::vector&, ePtrList &)=rpcproc[methodName]; + int fault; + + std::vector* v = params.getVector(); + + if (!proc) + { + fault=1; + xmlrpc_fault(ret, -1, "called method not present"); + } else + fault=proc( *v , ret); + + delete v; + + eDebug("converting to text..."); + + if (fault) + { + result+="\n"; + ret.current()->toXML(result); + result+="\n"; + } else + { + result+="\n"; + for (ePtrList::iterator i(ret); i != ret.end(); ++i) + { + result+=""; + i->toXML(result); + result+=""; + } + result+=""; + } + result+=""; + char buffer[10]; + snprintf(buffer, 10, "%d", size=result.length()); + wptr=0; + connection->local_header["Content-Type"]="text/xml"; + connection->local_header["Content-Length"]=buffer; + connection->code=200; + connection->code_descr="OK"; + connection->localstate=eHTTPConnection::stateResponse; + return 0; +} + +int eXMLRPCResponse::doWrite(int hm) +{ + int tw=size-wptr; + if (tw>hm) + tw=hm; + if (tw<=0) + return -1; + connection->writeBlock(result.c_str()+wptr, tw); + wptr+=tw; + return size > wptr ? 1 : -1; +} + +void eXMLRPCResponse::haveData(void *data, int len) +{ + if (result) + return; + int err=0; + + if (!parser.Parse((char*)data, len, !len)) + { + char temp[len+1]; + temp[len]=0; + memcpy(temp, data, len); + eDebug("%s: %s", temp, parser.ErrorString(parser.GetErrorCode())); + err=1; + } + + if ((!err) && (!len)) + err=doCall(); + + if (err) + { + eDebug("schade: %d", err); + connection->code=400; + connection->code_descr="Bad request"; + char buffer[10]; + snprintf(buffer, 10, "%d", size=result.length()); + wptr=0; + connection->local_header["Content-Type"]="text/html"; + connection->local_header["Content-Length"]=buffer; + result.sprintf("XMLRPC error %d\n", err); + connection->localstate=eHTTPConnection::stateResponse; + } +} + +void xmlrpc_initialize(eHTTPD *httpd) +{ + httpd->addResolver(new eHTTPXMLRPCResolver); +} + +void xmlrpc_addMethod(eString methodName, int (*proc)(std::vector&, ePtrList&)) +{ + rpcproc[methodName]=proc; +} + +void xmlrpc_fault(ePtrList &res, int faultCode, eString faultString) +{ + std::map *s=new std::map; + s->INSERT("faultCode", new eXMLRPCVariant(new __s32(faultCode))); + s->INSERT("faultString", new eXMLRPCVariant(new eString(faultString))); + res.push_back(new eXMLRPCVariant(s)); +} + +int xmlrpc_checkArgs(eString args, std::vector &parm, ePtrList &res) +{ + if (parm.size() != args.length()) + { + xmlrpc_fault(res, -500, eString().sprintf("parameter count mismatch (found %d, expected %d)", parm.size(), args.length())); + return 1; + } + + for (unsigned int i=0; i