HSAdmin Backend Domains, E-Mail, Datenbanken
Purodha
2013-02-20 4a7e12928010374d76e677c8ec3ea4f5e63e9487
commit | author | age
c64ab5 1 /***************************************************************************
CD 2  *   Copyright (C) 2005 by Christof Donat   *
3  *   cdonat@gmx.de   *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write to the                         *
17  *   Free Software Foundation, Inc.,                                       *
18  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
19  ***************************************************************************/
20
21 #include "transaction.h"
22 #include "xmlparser.h"
23 #include "httpclient.h"
24 #include <boost/lexical_cast.hpp>
25 #include <boost/regex.hpp>
26 #include <boost/format.hpp>
27
28 #include <sys/types.h>
29 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include <arpa/inet.h>
32 #include <netdb.h>
33 #include <errno.h>
34 #include <stdlib.h>
35
36 using boost::lexical_cast;
37 using boost::bad_lexical_cast;
38 using namespace xmlParser;
39
40 Transaction::Transaction(vector<string> options) :
41         abstractcommandlineparser::CmdLineParser<commandline::Parameters,commandline::parsedParameters>(options),
42         m_nextAttributeValue(""),
43         m_globalFault(false),
44         m_currentCall(0) {
45     if(!this->m_parseSuccessful) return;
46     
47     vector<shared_ptr<commandline::callParameter> >& calls = m_parsed->m_call;
48
49     for( vector<shared_ptr<commandline::callParameter> >::iterator c = calls.begin(); c != calls.end(); c++ ) {
50         shared_ptr<commandline::callParameter> call = *c;
51
52         vector<shared_ptr<commandline::orderParameter> >::iterator orderhere = call->m_order.end();
53         if( call->m_globalOrderIndex >= 0 ) orderhere = call->m_order.begin()+call->m_globalOrderIndex;
54
55         call->m_order.insert( orderhere, m_parsed->m_globalOrder.begin(), m_parsed->m_globalOrder.end() );
56         call->m_where.insert( call->m_where.end(), m_parsed->m_only.begin(), m_parsed->m_only.end() );
57         call->m_set.insert( call->m_set.end(), m_parsed->m_setall.begin(), m_parsed->m_setall.end() );
58         call->m_unset.insert( call->m_unset.end(), m_parsed->m_unsetall.begin(), m_parsed->m_unsetall.end() );
59
60         if( m_parsed->m_ignoreerrors ) call->m_ignoreerror = true;
61     }
62 };
63
64 void Transaction::operator()(shared_ptr<ConfigFileParser> cfgfile) {
65
66     class {
67         public:
68         void post(string &url) {
69             GenericHttpClient * client = createHttpClient(url);
70             m_response = client->post(m_request);
71         };
72     
73         void execCall(Transaction *t, string &username, string &url, shared_ptr<ConfigFileParser> cfgfile) {
74             m_request = t->getParsed()->toXML(username,cfgfile);
75             Logger::log(Logger::XML,"--XML request--\n"+m_request+"\n---");
76     
77             this->post(url);
78
79             ResponseParser parse;
80             if( !parse(m_response, t) ) Logger::log(Logger::XML,"parse error");
81             Logger::log(Logger::XML,"response parsed:");
82
83             if(Logger::XML && Logger::levels[Logger::level]) logNode(t->m_docelem,0);
84         }
85
86         void logNode(Node* node, int ind) {
87             Text *text;
88             Element *elm;
89             string indent = "";
90             for( int j = 0; j < ind; j++ ) indent += "    ";
91             string attributes;
92
93             switch(node->m_type) {
94                 case ELEMENT:
95                     elm = (Element*)node;
96                     for(map<string,string>::iterator i = elm->m_attributes.begin(); i != elm->m_attributes.end(); i++)
97                     attributes += " "+(i->first)+"=\""+(i->second)+"\"";
98                     Logger::log(Logger::XML,indent+"<"+elm->m_name+attributes+">");
99                     for( vector<Node*>::iterator i = elm->m_nodes.begin(); i != elm->m_nodes.end(); i++ ) 
100                         logNode(*i,ind+1);
101                     Logger::log(Logger::XML,indent+"</"+elm->m_name+">");
102                     break;
103                 case TEXT:
104                     text = (Text*)node;
105                     Logger::log(Logger::XML,indent+text->m_content);
106                     break;
107             }
108         }
109
110         private:
111         int connectToHost(const string hostname, const int port) const {
112             int sock;
113
114             struct sockaddr_in server_addr;
115             server_addr.sin_family = AF_INET;
116             if( (server_addr.sin_addr.s_addr = inet_addr(hostname.c_str())) == INADDR_NONE ) {
117                 struct hostent* hp = gethostbyname(hostname.c_str());
118                 if( hp == 0 ) {
119                     string msg = Logger::getMessageFormatString(Logger::CantResolveHostname);
120                     boost::format fmt(msg);
121                     fmt % hostname;
122                     Logger::log(Logger::FATAL,fmt.str());
123                     exit(1);
124                 }
125                 bcopy(hp->h_addr, (char*) &server_addr.sin_addr, hp->h_length);
126             }
127             server_addr.sin_port = htons(port);
128             
129             if( (sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0 ) {
130                 Logger::log(Logger::FATAL,Logger::getMessageFormatString(Logger::CantOpenSocket));
131                 exit(1);
132             }
133             if( connect(sock, (struct sockaddr*) &server_addr, sizeof(server_addr)) < 0 ) {
134                 string msg = Logger::getMessageFormatString(Logger::CantConnetcToHost);
135                 boost::format fmt(msg);
136                 fmt % hostname % port;
137                 Logger::log(Logger::FATAL,fmt.str());
138                 close(sock);
139                 exit(1);
140             }
141             return sock;
142         }
143
144         string m_request;
145         string m_response;
146     } XMLRPCrequest;
147
148
149     string username = "";
150     ConfigFileParser::config cfg = cfgfile->getConfig(username);
151     string url = cfg.server;
152     username = this->getUser();
153     cfg = cfgfile->getConfig(username);
154     if( cfg.server != "" ) url = cfg.server;
155
156     Logger::log(Logger::DEBUG,"now I know which Config to use");
157
158     XMLRPCrequest.execCall(this,username,url,cfgfile);
159 }
160
161
162
163 // XML Parser stuff
164 Element* Transaction::stepin(int count,Element* value) {
165     if( count<= 0 ) return value;
166     for( ; count > 0; count-- )
167         if(value->m_nodes[0]->m_type == xmlParser::ELEMENT ) value = (Element*)value->m_nodes[0];
168     return value;
169 }
170
171 string Transaction::getContent(Element* value) {
172     while( value->m_nodes.size() > 0 && value->m_nodes[0]->m_type == xmlParser::ELEMENT ) value = (Element*)value->m_nodes[0];
173
174     if( value->m_nodes.size() > 0 ) {
175         Text* txt = (Text*)value->m_nodes[0];
176
177         if( value->m_name == "boolean") {
178             int b = boost::lexical_cast<int>(replaceEntities(txt->m_content));
179             return (b == 0)?"false":"true";
180         } else if( value->m_name == "dateTime.iso8601") {
181             string datestring = replaceEntities(txt->m_content);
182             string year  = datestring.substr(0,4);
183             string month = datestring.substr(4,2);
184             string day   = datestring.substr(6,2);
185             string hour  = datestring.substr(9,2);
186             string minute= datestring.substr(12,2);
187             string second= datestring.substr(15,2);
188             return day+"."+month+"."+year+" "+hour+":"+minute+":"+second;
189         } else if( value->m_name == "base64") {
190             string encoded = replaceEntities(txt->m_content);
191             string decoded;
192             char next = '\0';
193             int shift = 0;
194             while( encoded.size() ) {
195                 int d = encoded[0];
196                 encoded = encoded.substr(1,encoded.size()-1);
197                 if      ( d >= 'A' && d <= 'Z') d -= 'A';
198                 else if ( d >= 'a' && d <= 'z') d = (d-'a')+26;
199                 else if ( d >= '0' && d <= '9') d = (d-'0')+52;
200                 else if ( d == '+') d = 62;
201                 else if ( d == '/') d = 63;
202                 else continue;
203
204                 next += d << shift;
205                 if( !shift ) { decoded += (char)(next&255); next = next >> 8; }
206
207                 shift = (shift-2)%8;
208             }
209             if( shift ) decoded += next;
210             return decoded;
211         } else {
212             return replaceEntities(txt->m_content);
213         }
214     }
215     return string("");
216 }
217
218 void Transaction::handleElem(Element * elem) {
219     if( m_tagstack.size() == 0 ) {
220         m_docelem = elem;
221         return;
222     }
223
224     Element *array, *data;
225     int tab = 8;
226
227     switch( m_tagstack.size() ) {
228         case 6: // fill next call
229             if(elem->m_name != "value" ) break;
230             array = (Element*)(elem->m_nodes[0]);
231
232             if( array->m_name == "struct" ) {
233                 map<string,string> errorstruct;
234                 if(array->m_nodes.size() != 0) for(vector<Node*>::iterator n = array->m_nodes.begin(); n != array->m_nodes.end(); n++) {
235                     Element* member = (Element*)(*n);
236                     if(member->m_nodes.size() >= 2) {
237                         Element *name, *value;
238                         name = (Element*)member->m_nodes[0];
239                         if( name->m_name == "value" ) {
240                             value = name;
241                             name = (Element*)member->m_nodes[1];
242                         } else
243                             value = (Element*)member->m_nodes[1];
244
245                         while( name->m_nodes.size() > 0 && name->m_nodes[0]->m_type == xmlParser::ELEMENT ) name = (Element*)name->m_nodes[0];
246                         while( value->m_nodes.size() > 0 && value->m_nodes[0]->m_type == xmlParser::ELEMENT ) value = (Element*)value->m_nodes[0];
247                         if( value->m_nodes.size() > 0 && name->m_nodes.size() > 0 ) {
248                             string namtxt = getContent(name);
249                             string valtxt = getContent(value);
250                             errorstruct[namtxt] = valtxt;
251                         }
252                     }
253                 }
254                 string msg = Logger::getMessageFormatString(Logger::ServerErrorCode);
255                 
256                 int errnum = boost::lexical_cast<int>(errorstruct["errorcode"]);
257                 string errorstring = Logger::getErrnoMessage(errnum);
258                 if( errorstring != "" ) errorstruct["errorstring"] = errorstring;
259
260                 boost::format fmt(msg);
261                 fmt % errorstruct["errorcode"] % errorstruct["errorstring"];
262                 Logger::log(Logger::ERROR,fmt.str());
263                 
264                 break;
265             }
266
267             data = (Element*)(array->m_nodes[0]);
268             
269             if(data->m_nodes.size() != 0) {
270                 vector<string> headlines;
271                 int tabpos = 0;
272                 vector<int> tabstops;
273
274                 Element* headlinesdata = stepin(3,data);
275
276                 if( m_parsed->m_call[m_currentCall]->m_display == "" ) {
277                     if(headlinesdata->m_nodes.size() != 0) for(vector<Node*>::iterator in = headlinesdata->m_nodes.begin(); in != headlinesdata->m_nodes.end(); in++) {
278                         string output = "";
279                         if((*in)->m_type == xmlParser::ELEMENT ) {
280                             output = getContent((Element*)(*in));
281                         } else {
282                             Text* txt = (Text*)(*in);
283                             output = replaceEntities(txt->m_content);
284                         }
285                         std::cout << output;
286                         tabstops.push_back(tabpos);
287                         tabpos += output.length();
288                         if( in+1 != headlinesdata->m_nodes.end() )do {
289                             std::cout << " ";
290                             tabpos++;
291                         } while( tabpos % tab );
292                     }
293                     std::cout << "\n";
294                     for(;tabpos;tabpos--) std::cout << "-";
295                     std::cout << "\n";
296                 } else {
297                     if(headlinesdata->m_nodes.size() != 0) for(vector<Node*>::iterator in = headlinesdata->m_nodes.begin(); in != headlinesdata->m_nodes.end(); in++) {
298                         string headline = getContent((Element*)(*in));
299                         if( headline != "" ) headlines.push_back( headline );
300                     }
301                 }
302
303                 
304                 Element* contentvalue;
305                 if(data->m_nodes[1]->m_type == xmlParser::ELEMENT ) contentvalue = (Element*)data->m_nodes[1];
306                 else                                                contentvalue = data;
307                 Element* contentdata = stepin(2,contentvalue);
308
309                 if(contentdata->m_nodes.size() != 0) for(vector<Node*>::iterator n = contentdata->m_nodes.begin(); n != contentdata->m_nodes.end(); n++) {
310                     if( m_parsed->m_call[m_currentCall]->m_display == "" ) {
311                         tabpos = 0;
312                         int i = 0;
313
314                         Element* innerdata = stepin(2,(Element*)(*n));
315                         if(innerdata->m_nodes.size() != 0) for(vector<Node*>::iterator in = innerdata->m_nodes.begin(); in != innerdata->m_nodes.end(); in++) {
316                             string oputput = getContent((Element*)(*in));
317
318                             while( tabpos < tabstops[i] ) { 
319                                 std::cout << " "; tabpos++; 
320                             }
321                             std::cout << oputput;
322                             tabpos += oputput.length();
323                             i++;
324                         }
325                         std::cout << "\n";
326                     } else {
327                         map<string,string> values;
328                         int i = 0;
329
330                         Element* innerdata = stepin(2,(Element*)(*n));
331                         if(innerdata->m_nodes.size() != 0) for(vector<Node*>::iterator in = innerdata->m_nodes.begin(); in != innerdata->m_nodes.end(); in++) {
332                             string oputput = getContent((Element*)(*in));
333
334                             if( oputput != "" ) {
335                                 values[headlines[i]] = oputput;
336                                 i++;
337                             }
338                         }
339                         std::cout << m_parsed->m_call[m_currentCall]->evalDisplay(values);
340                     }
341                 }
342             }
343             m_currentCall++;
344             break;
345         default:
346             break;
347     }
348
349     m_tagstack.top().m_nodes.push_back(elem);
350 }
351
352 void Transaction::handleGlobalFaultElem(xmlParser::Element * elem) {
353     if( m_tagstack.size() == 0 ) {
354         m_docelem = elem;
355         return;
356     }
357
358     Text *txt;
359     switch( m_tagstack.size() ) {
360         case 5:
361             if(elem->m_name == "value" )
362                 Logger::log(Logger::FATAL,getContent(elem));
363             break;
364         default:
365             break;
366     }
367
368     m_tagstack.top().m_nodes.push_back(elem);
369 }
370
371 string Transaction::replaceEntities(const string &input) {
372     string rval;
373     for( string::const_iterator i = input.begin(); i != input.end(); i++ ) {
374         if( *i != '&' ) rval += *i;
375         else {
376             string tmp;
377             int j;
378
379             for( j = 1; *(i+j) != ';' && i+j != input.end(); j++ ) tmp += *(i+j);
380
381             if( *(i+j) != ';' ) { rval += "&"; continue; }
382
383             if( tmp == "amp" ) {
384                 rval += "&";
385                 i+=j;
386             } else if( tmp == "gt" ) {
387                 rval += ">";
388                 i+=j;
389             } else if( tmp == "lt" ) {
390                 rval += "<";
391                 i+=j;
392             } else if( tmp == "quot" ) {
393                 rval += "\"";
394                 i+=j;
395             } else if( tmp == "apos" ) {
396                 rval += "'";
397                 i+=j;
398             } else if( tmp[0] == '#' ) {
399                 if( tmp[1] != 'x' ) {
400                     wchar_t value[2];
401                     value[0] = lexical_cast<int>(tmp.substr(1));
402                     value[1] = 0;
403                     char u[255];
404                     bzero(u,255);
405
406                     wcstombs(u,value,254);
407                     rval += u;
408                     i+=j;
409                 } else {
410                     wchar_t value[2];
411                     value[0] = 0;
412                     value[1] = 0;
413                     if     ( tmp[2] >= '0' && tmp[2] <= '9' ) value[0] = tmp[2]-'0';
414                     else if( tmp[2] >= 'a' && tmp[2] <= 'f' ) value[0] = tmp[2]-'a';
415                     else if( tmp[2] >= 'A' && tmp[2] <= 'F' ) value[0] = tmp[2]-'A';
416                     else { rval += "&"; continue;}
417                     value[0] = value[0] << 4;
418                     if     ( tmp[3] >= '0' && tmp[3] <= '9' ) value[0] += tmp[3]-'0';
419                     else if( tmp[3] >= 'a' && tmp[3] <= 'f' ) value[0] += tmp[3]-'a';
420                     else if( tmp[3] >= 'A' && tmp[3] <= 'F' ) value[0] += tmp[3]-'A';
421                     else { rval += "&"; continue; }
422                     char u[255];
423                     bzero(u,255);
424                     
425                     wcstombs(u,value,254);
426                     rval += u;
427                     i+=j;
428                 }
429             } else {
430                 rval += "&";
431             }
432         }
433     }
434     return rval;
435 }
436
437 bool Transaction::operator()(int type, string content) {
438     string tmp;
439     Element elem, currentelem;
440     Text text;
441
442     switch( type ) {
443         case responseParserHook::ELEMENT:
444             break;
445         case responseParserHook::ATTRIBUTE:
446             m_nextAttributeList[content] = m_nextAttributeValue;
447             m_nextAttributeValue = "";
448             break;
449         case responseParserHook::TEXT:
450             if( m_tagstack.size() ) {
451                 m_tagstack.top().m_nodes.push_back(new Text(content));
452             } else return false;
453             break;
454         case responseParserHook::CDATA:
455             if( m_tagstack.size() ) {
456                 m_tagstack.top().m_nodes.push_back(new Text(content));
457             } else return false;
458             break;
459         case responseParserHook::PROCESSING_INSTRUCTION:
460             if( m_nextAttributeList["version"] != "1.0" || content != "xml" ) return false;
461             tmp = "";
462             for(map<string,string>::iterator i = m_nextAttributeList.begin(); i != m_nextAttributeList.end(); i++)
463                 tmp += " "+(i->first)+"="+(i->second);
464             m_nextAttributeList.clear();
465             break;
466         case responseParserHook::COMMENT:
467             break;
468         case responseParserHook::DOCUMENT:
469             break;
470         case responseParserHook::START_ELEMENT:
471             if(m_tagstack.size() == 1 && content == "fault") m_globalFault = true;
472             elem = Element(content,m_nextAttributeList,vector<Node*>());
473             m_nextAttributeList.clear();
474             m_tagstack.push(elem);
475             break;
476         case responseParserHook::END_ELEMENT:
477             currentelem = m_tagstack.top();
478             m_tagstack.pop();
479             if( currentelem.m_name != content ) {
480                 return false;
481             }
482             if( !m_globalFault ) handleElem(new Element(currentelem));
483             else handleGlobalFaultElem(new Element(currentelem));
484             break;
485         case responseParserHook::EMPTY_ELEMENT:
486             if(m_tagstack.size() == 1 && content == "fault") m_globalFault = true;
487             if( !m_globalFault ) handleElem(new Element(content,m_nextAttributeList,vector<Node*>()));
488             else handleGlobalFaultElem(new Element(content,m_nextAttributeList,vector<Node*>()));
489             m_nextAttributeList.clear();
490             break;
491         case responseParserHook::ATTRIBUTE_VALUE:
492             m_nextAttributeValue = content;
493             break;
494         default:
495             string msg = Logger::getMessageFormatString(Logger::UnknownCallbackInXMLParser);
496             boost::format fmt(msg);
497             fmt % type % content;
498             Logger::log(Logger::FATAL,fmt.str());
499             break;
500     }
501     return true;
502 }