KNewStuff
soap.cpp
Go to the documentation of this file.
00001 /* 00002 This file is part of KNewStuff2. 00003 Copyright (c) 2007 Josef Spillner <spillner@kde.org> 00004 00005 This library is free software; you can redistribute it and/or 00006 modify it under the terms of the GNU Lesser General Public 00007 License as published by the Free Software Foundation; either 00008 version 2.1 of the License, or (at your option) any later version. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Lesser General Public License for more details. 00014 00015 You should have received a copy of the GNU Lesser General Public 00016 License along with this library. If not, see <http://www.gnu.org/licenses/>. 00017 */ 00018 00019 #include "soap.h" 00020 00021 #include <QtXml/qdom.h> 00022 #include <QtNetwork/QTcpSocket> 00023 #include <QtCore/QRegExp> 00024 00025 #include <kio/job.h> 00026 #include <kurl.h> 00027 #include <kdebug.h> 00028 00029 #include <string.h> // memcpy() 00030 00031 using namespace KNS; 00032 00033 Soap::Soap(QObject* parent) 00034 : QObject(parent) 00035 { 00036 //m_model = canonicaltree; 00037 m_model = soap; 00038 m_socket = NULL; 00039 m_lastjobid = 0; 00040 //m_inprogress = false; 00041 } 00042 00043 Soap::~Soap() 00044 { 00045 } 00046 00047 int Soap::call(const QDomElement& element, const QString &endpoint) 00048 { 00049 //if(m_inprogress) 00050 //{ 00051 // kWarning() << "Discarding SOAP/CTS call!"; 00052 // return; 00053 //} 00054 00055 if (m_model == canonicaltree) { 00056 call_tree(element, endpoint); 00057 // cDxs doesn't support job ids yet 00058 return -1; 00059 } else { 00060 return call_soap(element, endpoint); 00061 } 00062 00063 //m_inprogress = true; 00064 } 00065 00066 void Soap::call_tree(const QDomElement& element, const QString &endpoint) 00067 { 00068 QString s; 00069 00070 s += localname(element); 00071 s += '('; 00072 QDomNodeList l = element.childNodes(); 00073 for (int i = 0; i < l.count(); i++) { 00074 QDomNode tmp = l.item(i); 00075 s += localname(tmp); 00076 s += '('; 00077 s += xpath(tmp, "/"); 00078 s += ')'; 00079 s += '\n'; 00080 } 00081 s += ")\n"; 00082 00083 //kDebug() << "<CanonicalTree>" << s; 00084 00085 QByteArray data = s.toUtf8(); 00086 00087 //kDebug() << "Call(socket)!"; 00088 00089 KUrl url(endpoint); 00090 QString hostname = url.host(); 00091 int port = 30303/*url.port()*/; 00092 00093 m_socket = new QTcpSocket(); 00094 m_socket->connectToHost(hostname, port); 00095 00096 m_socket->write(data, data.size()); 00097 00098 connect(m_socket, 00099 SIGNAL(readyRead()), 00100 SLOT(slotSocket())); 00101 connect(m_socket, 00102 SIGNAL(error(QAbstractSocket::SocketError)), 00103 SLOT(slotSocketError(QAbstractSocket::SocketError))); 00104 00105 m_buffer = QByteArray(); 00106 } 00107 00108 int Soap::call_soap(QDomElement element, const QString &endpoint) 00109 { 00110 //kDebug() << "calling soap"; 00111 KUrl url(endpoint); 00112 00113 QDomDocument doc; 00114 QDomElement env = doc.createElement("SOAP-ENV:Envelope"); 00115 env.setAttribute("xmlns:SOAP-ENV", "http://schemas.xmlsoap.org/soap/envelope/"); 00116 doc.appendChild(env); 00117 QDomElement body = doc.createElement("SOAP-ENV:Body"); 00118 env.appendChild(body); 00119 element.setAttribute("xmlns:ns", "urn:DXS"); 00120 body.appendChild(element); 00121 00122 QString s = doc.toString(); 00123 QByteArray data = s.toUtf8(); 00124 00125 //kDebug() << "HTTP-POST " << url.prettyUrl(); 00126 //kDebug() << "HTTP-POST " << s; 00127 00128 KIO::TransferJob *job; 00129 job = KIO::http_post(url, data, KIO::HideProgressInfo); 00130 int thisjobid = ++m_lastjobid; 00131 m_jobids.insert(job, thisjobid); 00132 job->addMetaData("content-type", "Content-Type: text/xml"); 00133 00134 //kDebug() << "Call!"; 00135 00136 connect(job, 00137 SIGNAL(data(KIO::Job*, const QByteArray&)), 00138 SLOT(slotData(KIO::Job*, const QByteArray&))); 00139 connect(job, 00140 SIGNAL(result(KJob*)), 00141 SLOT(slotResult(KJob*))); 00142 00143 m_buffer = QByteArray(); 00144 return thisjobid; 00145 } 00146 00147 void Soap::slotData(KIO::Job *job, const QByteArray& data) 00148 { 00149 Q_UNUSED(job); 00150 00151 //kDebug() << "Length(before): " << m_buffer.size(); 00152 //kDebug() << "Append-Length: " << data.size(); 00153 00154 int bufferlen = m_buffer.size(); 00155 m_buffer.resize(bufferlen + data.size()); 00156 00157 //m_buffer.append(data); 00158 // FIXME: No memcpy() in Qt??? Really, no qMemCopy()? :-) 00159 memcpy(m_buffer.data() + bufferlen, data.data(), data.size()); 00160 00161 //kDebug() << "Length(after): " << m_buffer.size(); 00162 } 00163 00164 void Soap::slotResult(KJob *job) 00165 { 00166 //kDebug() << "Result!"; 00167 00168 if ((job) && (job->error())) { 00169 //job->showErrorDialog(this); 00170 //kDebug() << "SOAP ERROR!"; 00171 emit signalError(); 00172 return; 00173 } 00174 00175 //kDebug() << "CSTRING: '" << m_buffer << "'"; 00176 00177 int bufferlen = m_buffer.size(); 00178 m_buffer.resize(bufferlen + 1); 00179 m_buffer.data()[bufferlen] = 0; 00180 m_data = QString::fromUtf8(m_buffer); 00181 00182 //kDebug() << "STRING: '" << m_data << "'"; 00183 00184 if (m_model == soap) { 00185 QDomDocument doc; 00186 doc.setContent(m_data); 00187 00188 QDomElement envelope = doc.documentElement(); 00189 QDomNode bodynode = envelope.firstChild(); 00190 QDomNode contentnode = bodynode.firstChild(); 00191 00192 //kDebug() << "(signal) Result!"; 00193 00194 //m_inprogress = false; 00195 emit signalResult(contentnode, m_jobids.value(job)); 00196 m_jobids.remove(job); 00197 } else { 00198 QDomDocument doc; 00199 00200 // FIXME: dummy data 00201 //m_data = QString("GHNSRemovalResponse(ok(true)\nauthorative(true))"); 00202 //kDebug() << m_data; 00203 00204 m_data = m_data.simplified(); 00205 doc = buildtree(doc, doc.documentElement(), m_data); 00206 00207 QDomElement root = doc.documentElement(); 00208 00209 //kDebug() << "(signal) Result!"; 00210 //kDebug() << doc.toString(); 00211 00212 //m_inprogress = false; 00213 emit signalResult(root, -1); 00214 } 00215 } 00216 00217 QString Soap::localname(const QDomNode& node) 00218 { 00219 QDomElement el = node.toElement(); 00220 QString s = el.tagName().section(':', -1); 00221 return s; 00222 } 00223 00224 QList<QDomNode> Soap::directChildNodes(const QDomNode& node, const QString &name) 00225 { 00226 QList<QDomNode> list; 00227 QDomNode n = node.firstChild(); 00228 while (!n.isNull()) { 00229 if ((n.isElement()) && (n.toElement().tagName() == name)) { 00230 list.append(n); 00231 } 00232 00233 n = n.nextSibling(); 00234 } 00235 return list; 00236 } 00237 00238 QString Soap::xpath(const QDomNode& node, const QString &expr) 00239 { 00240 // if(m_model == canonicaltree) 00241 // { 00242 // //QString provider = m_soap->xpath(node, "/SOAP-ENC:Array/provider"); 00243 // expr = expr.section("/", 2); 00244 // // FIXME: Array handling for Canonical Tree Structures? 00245 // kDebug() << "EXPR " << expr; 00246 // } 00247 00248 QDomNode n = node; 00249 const QStringList explist = expr.split('/', QString::SkipEmptyParts); 00250 for (QStringList::const_iterator it = explist.begin(); it != explist.end(); ++it) { 00251 QDomElement el = n.toElement(); 00252 QDomNodeList l = el.elementsByTagName((*it)); 00253 if (!l.size()) { 00254 return QString(); 00255 } 00256 n = l.item(0); 00257 } 00258 QString s = n.toElement().text(); 00259 return s; 00260 } 00261 00262 void Soap::setModel(Model m) 00263 { 00264 m_model = m; 00265 } 00266 00267 void Soap::slotSocketError(QAbstractSocket::SocketError error) 00268 { 00269 Q_UNUSED(error); 00270 00271 //kDebug() << "socket: error"; 00272 00273 delete m_socket; 00274 m_socket = NULL; 00275 00276 //m_inprogress = false; 00277 } 00278 00279 void Soap::slotSocket() 00280 { 00281 //kDebug() << "socket: data"; 00282 00283 QByteArray a; 00284 a.resize(m_socket->bytesAvailable()); 00285 m_socket->read(a.data(), m_socket->bytesAvailable()); 00286 00287 //kDebug() << "DATA" << a; 00288 00289 slotData(NULL, a); 00290 00291 if (m_socket->atEnd()) { 00292 m_socket->close(); 00293 // delete m_socket; 00294 m_socket = NULL; 00295 00296 slotResult(NULL); 00297 } 00298 } 00299 00300 QDomDocument Soap::buildtree(QDomDocument doc, QDomElement cur, const QString& data) 00301 { 00302 int start = -1, end = -1; 00303 int offset = 0; 00304 int stack = 0; 00305 bool quoted = false; 00306 00307 if (data.indexOf('(') == -1) { 00308 QDomText t = doc.createTextNode(data); 00309 cur.appendChild(t); 00310 return doc; 00311 } 00312 00313 for (int i = 0; i < data.length(); i++) { 00314 const QChar c = data.at(i); 00315 if (quoted) { 00316 quoted = false; 00317 continue; 00318 } 00319 if (c == '\\') { 00320 quoted = true; 00321 } else if (c == '(') { 00322 stack++; 00323 if (start == -1) { 00324 start = i; 00325 } 00326 } else if (c == ')') { 00327 stack--; 00328 if ((stack == 0) && (end == -1)) { 00329 end = i; 00330 //kDebug() << "START-END: " << start << "," << end; 00331 QString expression = data.mid(offset, start - offset); 00332 QString sub = data.mid(start + 1, end - start - 1); 00333 expression = expression.trimmed(); 00334 //kDebug() << "EXPR-MAIN " << expression; 00335 //kDebug() << "EXPR-SUB " << sub; 00336 00337 QDomElement elem; 00338 if (cur.isNull()) { 00339 elem = doc.createElement("ns:" + expression); 00340 doc.appendChild(elem); 00341 } else { 00342 elem = doc.createElement(expression); 00343 cur.appendChild(elem); 00344 } 00345 00346 buildtree(doc, elem, sub); 00347 00348 offset = end + 1; 00349 start = -1; 00350 end = -1; 00351 } 00352 } 00353 } 00354 00355 return doc; 00356 } 00357 00358 #include "soap.moc"
KDE 4.6 API Reference