/*************************************************************************** * Copyright (C) 2005 by Christof Donat * * cdonat@gmx.de * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "transaction.h" #include "xmlparser.h" #include "httpclient.h" #include #include #include #include #include #include #include #include #include #include using boost::lexical_cast; using boost::bad_lexical_cast; using namespace xmlParser; Transaction::Transaction(vector options) : abstractcommandlineparser::CmdLineParser(options), m_nextAttributeValue(""), m_globalFault(false), m_currentCall(0) { if(!this->m_parseSuccessful) return; vector >& calls = m_parsed->m_call; for( vector >::iterator c = calls.begin(); c != calls.end(); c++ ) { shared_ptr call = *c; vector >::iterator orderhere = call->m_order.end(); if( call->m_globalOrderIndex >= 0 ) orderhere = call->m_order.begin()+call->m_globalOrderIndex; call->m_order.insert( orderhere, m_parsed->m_globalOrder.begin(), m_parsed->m_globalOrder.end() ); call->m_where.insert( call->m_where.end(), m_parsed->m_only.begin(), m_parsed->m_only.end() ); call->m_set.insert( call->m_set.end(), m_parsed->m_setall.begin(), m_parsed->m_setall.end() ); call->m_unset.insert( call->m_unset.end(), m_parsed->m_unsetall.begin(), m_parsed->m_unsetall.end() ); if( m_parsed->m_ignoreerrors ) call->m_ignoreerror = true; } }; void Transaction::operator()(shared_ptr cfgfile) { class { public: void post(string &url) { GenericHttpClient * client = createHttpClient(url); m_response = client->post(m_request); }; void execCall(Transaction *t, string &username, string &url, shared_ptr cfgfile) { m_request = t->getParsed()->toXML(username,cfgfile); Logger::log(Logger::XML,"--XML request--\n"+m_request+"\n---"); this->post(url); ResponseParser parse; if( !parse(m_response, t) ) Logger::log(Logger::XML,"parse error"); Logger::log(Logger::XML,"response parsed:"); if(Logger::XML && Logger::levels[Logger::level]) logNode(t->m_docelem,0); } void logNode(Node* node, int ind) { Text *text; Element *elm; string indent = ""; for( int j = 0; j < ind; j++ ) indent += " "; string attributes; switch(node->m_type) { case ELEMENT: elm = (Element*)node; for(map::iterator i = elm->m_attributes.begin(); i != elm->m_attributes.end(); i++) attributes += " "+(i->first)+"=\""+(i->second)+"\""; Logger::log(Logger::XML,indent+"<"+elm->m_name+attributes+">"); for( vector::iterator i = elm->m_nodes.begin(); i != elm->m_nodes.end(); i++ ) logNode(*i,ind+1); Logger::log(Logger::XML,indent+"m_name+">"); break; case TEXT: text = (Text*)node; Logger::log(Logger::XML,indent+text->m_content); break; } } private: int connectToHost(const string hostname, const int port) const { int sock; struct sockaddr_in server_addr; server_addr.sin_family = AF_INET; if( (server_addr.sin_addr.s_addr = inet_addr(hostname.c_str())) == INADDR_NONE ) { struct hostent* hp = gethostbyname(hostname.c_str()); if( hp == 0 ) { string msg = Logger::getMessageFormatString(Logger::CantResolveHostname); boost::format fmt(msg); fmt % hostname; Logger::log(Logger::FATAL,fmt.str()); exit(1); } bcopy(hp->h_addr, (char*) &server_addr.sin_addr, hp->h_length); } server_addr.sin_port = htons(port); if( (sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0 ) { Logger::log(Logger::FATAL,Logger::getMessageFormatString(Logger::CantOpenSocket)); exit(1); } if( connect(sock, (struct sockaddr*) &server_addr, sizeof(server_addr)) < 0 ) { string msg = Logger::getMessageFormatString(Logger::CantConnetcToHost); boost::format fmt(msg); fmt % hostname % port; Logger::log(Logger::FATAL,fmt.str()); close(sock); exit(1); } return sock; } string m_request; string m_response; } XMLRPCrequest; string username = ""; ConfigFileParser::config cfg = cfgfile->getConfig(username); string url = cfg.server; username = this->getUser(); cfg = cfgfile->getConfig(username); if( cfg.server != "" ) url = cfg.server; Logger::log(Logger::DEBUG,"now I know which Config to use"); XMLRPCrequest.execCall(this,username,url,cfgfile); } // XML Parser stuff Element* Transaction::stepin(int count,Element* value) { if( count<= 0 ) return value; for( ; count > 0; count-- ) if(value->m_nodes[0]->m_type == xmlParser::ELEMENT ) value = (Element*)value->m_nodes[0]; return value; } string Transaction::getContent(Element* value) { while( value->m_nodes.size() > 0 && value->m_nodes[0]->m_type == xmlParser::ELEMENT ) value = (Element*)value->m_nodes[0]; if( value->m_nodes.size() > 0 ) { Text* txt = (Text*)value->m_nodes[0]; if( value->m_name == "boolean") { int b = boost::lexical_cast(replaceEntities(txt->m_content)); return (b == 0)?"false":"true"; } else if( value->m_name == "dateTime.iso8601") { string datestring = replaceEntities(txt->m_content); string year = datestring.substr(0,4); string month = datestring.substr(4,2); string day = datestring.substr(6,2); string hour = datestring.substr(9,2); string minute= datestring.substr(12,2); string second= datestring.substr(15,2); return day+"."+month+"."+year+" "+hour+":"+minute+":"+second; } else if( value->m_name == "base64") { string encoded = replaceEntities(txt->m_content); string decoded; char next = '\0'; int shift = 0; while( encoded.size() ) { int d = encoded[0]; encoded = encoded.substr(1,encoded.size()-1); if ( d >= 'A' && d <= 'Z') d -= 'A'; else if ( d >= 'a' && d <= 'z') d = (d-'a')+26; else if ( d >= '0' && d <= '9') d = (d-'0')+52; else if ( d == '+') d = 62; else if ( d == '/') d = 63; else continue; next += d << shift; if( !shift ) { decoded += (char)(next&255); next = next >> 8; } shift = (shift-2)%8; } if( shift ) decoded += next; return decoded; } else { return replaceEntities(txt->m_content); } } return string(""); } void Transaction::handleElem(Element * elem) { if( m_tagstack.size() == 0 ) { m_docelem = elem; return; } Element *array, *data; int tab = 8; switch( m_tagstack.size() ) { case 6: // fill next call if(elem->m_name != "value" ) break; array = (Element*)(elem->m_nodes[0]); if( array->m_name == "struct" ) { map errorstruct; if(array->m_nodes.size() != 0) for(vector::iterator n = array->m_nodes.begin(); n != array->m_nodes.end(); n++) { Element* member = (Element*)(*n); if(member->m_nodes.size() >= 2) { Element *name, *value; name = (Element*)member->m_nodes[0]; if( name->m_name == "value" ) { value = name; name = (Element*)member->m_nodes[1]; } else value = (Element*)member->m_nodes[1]; while( name->m_nodes.size() > 0 && name->m_nodes[0]->m_type == xmlParser::ELEMENT ) name = (Element*)name->m_nodes[0]; while( value->m_nodes.size() > 0 && value->m_nodes[0]->m_type == xmlParser::ELEMENT ) value = (Element*)value->m_nodes[0]; if( value->m_nodes.size() > 0 && name->m_nodes.size() > 0 ) { string namtxt = getContent(name); string valtxt = getContent(value); errorstruct[namtxt] = valtxt; } } } string msg = Logger::getMessageFormatString(Logger::ServerErrorCode); int errnum = boost::lexical_cast(errorstruct["errorcode"]); string errorstring = Logger::getErrnoMessage(errnum); if( errorstring != "" ) errorstruct["errorstring"] = errorstring; boost::format fmt(msg); fmt % errorstruct["errorcode"] % errorstruct["errorstring"]; Logger::log(Logger::ERROR,fmt.str()); break; } data = (Element*)(array->m_nodes[0]); if(data->m_nodes.size() != 0) { vector headlines; int tabpos = 0; vector tabstops; Element* headlinesdata = stepin(3,data); if( m_parsed->m_call[m_currentCall]->m_display == "" ) { if(headlinesdata->m_nodes.size() != 0) for(vector::iterator in = headlinesdata->m_nodes.begin(); in != headlinesdata->m_nodes.end(); in++) { string output = ""; if((*in)->m_type == xmlParser::ELEMENT ) { output = getContent((Element*)(*in)); } else { Text* txt = (Text*)(*in); output = replaceEntities(txt->m_content); } std::cout << output; tabstops.push_back(tabpos); tabpos += output.length(); if( in+1 != headlinesdata->m_nodes.end() )do { std::cout << " "; tabpos++; } while( tabpos % tab ); } std::cout << "\n"; for(;tabpos;tabpos--) std::cout << "-"; std::cout << "\n"; } else { if(headlinesdata->m_nodes.size() != 0) for(vector::iterator in = headlinesdata->m_nodes.begin(); in != headlinesdata->m_nodes.end(); in++) { string headline = getContent((Element*)(*in)); if( headline != "" ) headlines.push_back( headline ); } } Element* contentvalue; if(data->m_nodes[1]->m_type == xmlParser::ELEMENT ) contentvalue = (Element*)data->m_nodes[1]; else contentvalue = data; Element* contentdata = stepin(2,contentvalue); if(contentdata->m_nodes.size() != 0) for(vector::iterator n = contentdata->m_nodes.begin(); n != contentdata->m_nodes.end(); n++) { if( m_parsed->m_call[m_currentCall]->m_display == "" ) { tabpos = 0; int i = 0; Element* innerdata = stepin(2,(Element*)(*n)); if(innerdata->m_nodes.size() != 0) for(vector::iterator in = innerdata->m_nodes.begin(); in != innerdata->m_nodes.end(); in++) { string oputput = getContent((Element*)(*in)); while( tabpos < tabstops[i] ) { std::cout << " "; tabpos++; } std::cout << oputput; tabpos += oputput.length(); i++; } std::cout << "\n"; } else { map values; int i = 0; Element* innerdata = stepin(2,(Element*)(*n)); if(innerdata->m_nodes.size() != 0) for(vector::iterator in = innerdata->m_nodes.begin(); in != innerdata->m_nodes.end(); in++) { string oputput = getContent((Element*)(*in)); if( oputput != "" ) { values[headlines[i]] = oputput; i++; } } std::cout << m_parsed->m_call[m_currentCall]->evalDisplay(values); } } } m_currentCall++; break; default: break; } m_tagstack.top().m_nodes.push_back(elem); } void Transaction::handleGlobalFaultElem(xmlParser::Element * elem) { if( m_tagstack.size() == 0 ) { m_docelem = elem; return; } Text *txt; switch( m_tagstack.size() ) { case 5: if(elem->m_name == "value" ) Logger::log(Logger::FATAL,getContent(elem)); break; default: break; } m_tagstack.top().m_nodes.push_back(elem); } string Transaction::replaceEntities(const string &input) { string rval; for( string::const_iterator i = input.begin(); i != input.end(); i++ ) { if( *i != '&' ) rval += *i; else { string tmp; int j; for( j = 1; *(i+j) != ';' && i+j != input.end(); j++ ) tmp += *(i+j); if( *(i+j) != ';' ) { rval += "&"; continue; } if( tmp == "amp" ) { rval += "&"; i+=j; } else if( tmp == "gt" ) { rval += ">"; i+=j; } else if( tmp == "lt" ) { rval += "<"; i+=j; } else if( tmp == "quot" ) { rval += "\""; i+=j; } else if( tmp == "apos" ) { rval += "'"; i+=j; } else if( tmp[0] == '#' ) { if( tmp[1] != 'x' ) { wchar_t value[2]; value[0] = lexical_cast(tmp.substr(1)); value[1] = 0; char u[255]; bzero(u,255); wcstombs(u,value,254); rval += u; i+=j; } else { wchar_t value[2]; value[0] = 0; value[1] = 0; if ( tmp[2] >= '0' && tmp[2] <= '9' ) value[0] = tmp[2]-'0'; else if( tmp[2] >= 'a' && tmp[2] <= 'f' ) value[0] = tmp[2]-'a'; else if( tmp[2] >= 'A' && tmp[2] <= 'F' ) value[0] = tmp[2]-'A'; else { rval += "&"; continue;} value[0] = value[0] << 4; if ( tmp[3] >= '0' && tmp[3] <= '9' ) value[0] += tmp[3]-'0'; else if( tmp[3] >= 'a' && tmp[3] <= 'f' ) value[0] += tmp[3]-'a'; else if( tmp[3] >= 'A' && tmp[3] <= 'F' ) value[0] += tmp[3]-'A'; else { rval += "&"; continue; } char u[255]; bzero(u,255); wcstombs(u,value,254); rval += u; i+=j; } } else { rval += "&"; } } } return rval; } bool Transaction::operator()(int type, string content) { string tmp; Element elem, currentelem; Text text; switch( type ) { case responseParserHook::ELEMENT: break; case responseParserHook::ATTRIBUTE: m_nextAttributeList[content] = m_nextAttributeValue; m_nextAttributeValue = ""; break; case responseParserHook::TEXT: if( m_tagstack.size() ) { m_tagstack.top().m_nodes.push_back(new Text(content)); } else return false; break; case responseParserHook::CDATA: if( m_tagstack.size() ) { m_tagstack.top().m_nodes.push_back(new Text(content)); } else return false; break; case responseParserHook::PROCESSING_INSTRUCTION: if( m_nextAttributeList["version"] != "1.0" || content != "xml" ) return false; tmp = ""; for(map::iterator i = m_nextAttributeList.begin(); i != m_nextAttributeList.end(); i++) tmp += " "+(i->first)+"="+(i->second); m_nextAttributeList.clear(); break; case responseParserHook::COMMENT: break; case responseParserHook::DOCUMENT: break; case responseParserHook::START_ELEMENT: if(m_tagstack.size() == 1 && content == "fault") m_globalFault = true; elem = Element(content,m_nextAttributeList,vector()); m_nextAttributeList.clear(); m_tagstack.push(elem); break; case responseParserHook::END_ELEMENT: currentelem = m_tagstack.top(); m_tagstack.pop(); if( currentelem.m_name != content ) { return false; } if( !m_globalFault ) handleElem(new Element(currentelem)); else handleGlobalFaultElem(new Element(currentelem)); break; case responseParserHook::EMPTY_ELEMENT: if(m_tagstack.size() == 1 && content == "fault") m_globalFault = true; if( !m_globalFault ) handleElem(new Element(content,m_nextAttributeList,vector())); else handleGlobalFaultElem(new Element(content,m_nextAttributeList,vector())); m_nextAttributeList.clear(); break; case responseParserHook::ATTRIBUTE_VALUE: m_nextAttributeValue = content; break; default: string msg = Logger::getMessageFormatString(Logger::UnknownCallbackInXMLParser); boost::format fmt(msg); fmt % type % content; Logger::log(Logger::FATAL,fmt.str()); break; } return true; }