00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00012
00013 #include <QBuffer>
00014
00015 #include "soapclient.h"
00016
00017 #include "mythlogging.h"
00018 #include "httprequest.h"
00019 #include "upnp.h"
00020
00021 #define LOC QString("SOAPClient: ")
00022
00029 SOAPClient::SOAPClient(const QUrl &url,
00030 const QString &sNamespace,
00031 const QString &sControlPath) :
00032 m_url(url), m_sNamespace(sNamespace), m_sControlPath(sControlPath)
00033 {
00034 }
00035
00036
00041 bool SOAPClient::Init(const QUrl &url,
00042 const QString &sNamespace,
00043 const QString &sControlPath)
00044 {
00045 bool ok = true;
00046 if (sNamespace.isEmpty())
00047 {
00048 ok = false;
00049 LOG(VB_GENERAL, LOG_ERR, LOC + "Init() given blank namespace");
00050 }
00051
00052 QUrl test(url);
00053 test.setPath(sControlPath);
00054 if (!test.isValid())
00055 {
00056 ok = false;
00057 LOG(VB_GENERAL, LOG_ERR, LOC +
00058 QString("Init() given invalid control URL %1")
00059 .arg(test.toString()));
00060 }
00061
00062 if (ok)
00063 {
00064 m_url = url;
00065 m_sNamespace = sNamespace;
00066 m_sControlPath = sControlPath;
00067 }
00068 else
00069 {
00070 m_url = QUrl();
00071 m_sNamespace.clear();
00072 m_sControlPath.clear();
00073 }
00074
00075 return ok;
00076 }
00077
00079 QDomNode SOAPClient::FindNode(
00080 const QString &sName, const QDomNode &baseNode) const
00081 {
00082 QStringList parts = sName.split('/', QString::SkipEmptyParts);
00083 return FindNodeInternal(parts, baseNode);
00084 }
00085
00087 QDomNode SOAPClient::FindNodeInternal(
00088 QStringList &sParts, const QDomNode &curNode) const
00089 {
00090 if (sParts.empty())
00091 return curNode;
00092
00093 QString sName = sParts.front();
00094 sParts.pop_front();
00095
00096 QDomNode child = curNode.namedItem(sName);
00097
00098 if (child.isNull() )
00099 sParts.clear();
00100
00101 return FindNodeInternal(sParts, child);
00102 }
00103
00106 int SOAPClient::GetNodeValue(
00107 const QDomNode &node, const QString &sName, int nDefault) const
00108 {
00109 QString sValue = GetNodeValue(node, sName, QString::number(nDefault));
00110 return sValue.toInt();
00111 }
00112
00115 bool SOAPClient::GetNodeValue(
00116 const QDomNode &node, const QString &sName, bool bDefault) const
00117 {
00118 QString sDefault = (bDefault) ? "true" : "false";
00119 QString sValue = GetNodeValue(node, sName, sDefault);
00120 if (sValue.isEmpty())
00121 return bDefault;
00122
00123 char ret = sValue[0].toAscii();
00124 switch (ret)
00125 {
00126 case 't': case 'T': case 'y': case 'Y': case '1':
00127 return true;
00128 case 'f': case 'F': case 'n': case 'N': case '0':
00129 return false;
00130 default:
00131 return bDefault;
00132 }
00133 }
00134
00137 QString SOAPClient::GetNodeValue(
00138 const QDomNode &node, const QString &sName, const QString &sDefault) const
00139 {
00140 if (node.isNull())
00141 return sDefault;
00142
00143 QString sValue = "";
00144 QDomNode valNode = FindNode(sName, node);
00145
00146 if (!valNode.isNull())
00147 {
00148
00149
00150 QDomText oText = valNode.firstChild().toText();
00151
00152 if (!oText.isNull())
00153 sValue = oText.nodeValue();
00154
00155 return QUrl::fromPercentEncoding(sValue.toUtf8());
00156 }
00157
00158 return sDefault;
00159 }
00160
00179 QDomDocument SOAPClient::SendSOAPRequest(const QString &sMethod,
00180 QStringMap &list,
00181 int &nErrCode,
00182 QString &sErrDesc,
00183 bool bInQtThread)
00184 {
00185 QUrl url(m_url);
00186
00187 url.setPath(m_sControlPath);
00188
00189 nErrCode = UPnPResult_Success;
00190 sErrDesc = "";
00191
00192 QDomDocument xmlResult;
00193 if (m_sNamespace.isEmpty())
00194 {
00195 nErrCode = UPnPResult_MythTV_NoNamespaceGiven;
00196 sErrDesc = "No namespace given";
00197 return xmlResult;
00198 }
00199
00200
00201
00202
00203
00204 QHttpRequestHeader header("POST", sMethod, 1, 0);
00205
00206 header.setValue("CONTENT-TYPE", "text/xml; charset=\"utf-8\"" );
00207 header.setValue("SOAPACTION",
00208 QString("\"%1#%2\"").arg(m_sNamespace).arg(sMethod));
00209
00210
00211
00212
00213
00214 QByteArray aBuffer;
00215 QTextStream os( &aBuffer );
00216
00217 os.setCodec("UTF-8");
00218
00219 os << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n";
00220 os << "<s:Envelope "
00221 " s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\""
00222 " xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\">\r\n";
00223 os << " <s:Body>\r\n";
00224 os << " <u:" << sMethod << " xmlns:u=\"" << m_sNamespace << "\">\r\n";
00225
00226
00227
00228
00229
00230 for (QStringMap::iterator it = list.begin(); it != list.end(); ++it)
00231 {
00232 os << " <" << it.key() << ">";
00233 os << HTTPRequest::Encode( *it );
00234 os << "</" << it.key() << ">\r\n";
00235 }
00236
00237 os << " </u:" << sMethod << ">\r\n";
00238 os << " </s:Body>\r\n";
00239 os << "</s:Envelope>\r\n";
00240
00241 os.flush();
00242
00243
00244
00245
00246
00247 QBuffer buff(&aBuffer);
00248
00249 LOG(VB_UPNP, LOG_DEBUG,
00250 QString("SOAPClient(%1) sending:\n").arg(url.toString()) +
00251 header.toString() + QString("\n%1\n").arg(aBuffer.constData()));
00252
00253 QString sXml =
00254 HttpComms::postHttp(url,
00255 &header,
00256 &buff,
00257 10000,
00258 3,
00259 0,
00260 false,
00261 NULL,
00262 bInQtThread,
00263 QString()
00264
00265 );
00266
00267
00268
00269
00270
00271 LOG(VB_UPNP, LOG_DEBUG, "SOAPClient response:\n" +
00272 QString("%1\n").arg(sXml));
00273
00274
00275
00276 list.clear();
00277
00278 QDomDocument doc;
00279
00280 if (!doc.setContent(sXml, true, &sErrDesc, &nErrCode))
00281 {
00282 LOG(VB_UPNP, LOG_ERR,
00283 QString("SendSOAPRequest( %1 ) - Invalid response from %2")
00284 .arg(sMethod).arg(url.toString()) +
00285 QString("%1: %2").arg(nErrCode).arg(sErrDesc));
00286
00287 return xmlResult;
00288 }
00289
00290
00291
00292
00293
00294 QString sResponseName = sMethod + "Response";
00295 QDomNodeList oNodeList =
00296 doc.elementsByTagNameNS(m_sNamespace, sResponseName);
00297
00298 if (oNodeList.count() == 0)
00299 {
00300
00301
00302
00303
00304 nErrCode = GetNodeValue(
00305 doc, "Envelope/Body/Fault/detail/UPnPError/errorCode", 500);
00306 sErrDesc = GetNodeValue(
00307 doc, "Envelope/Body/Fault/detail/UPnPError/errorDescription", "");
00308 if (sErrDesc.isEmpty())
00309 sErrDesc = QString("Unknown #%1").arg(nErrCode);
00310
00311 QDomNode oNode = FindNode( "Envelope/Body/Fault", doc );
00312
00313 oNode = xmlResult.importNode( oNode, true );
00314 xmlResult.appendChild( oNode );
00315
00316 return xmlResult;
00317 }
00318
00319 QDomNode oMethod = oNodeList.item(0);
00320 if (oMethod.isNull())
00321 return xmlResult;
00322
00323 QDomNode oNode = oMethod.firstChild();
00324 for (; !oNode.isNull(); oNode = oNode.nextSibling())
00325 {
00326 QDomElement e = oNode.toElement();
00327 if (e.isNull())
00328 continue;
00329
00330 QString sName = e.tagName();
00331 QString sValue = "";
00332
00333 QDomText oText = oNode.firstChild().toText();
00334
00335 if (!oText.isNull())
00336 sValue = oText.nodeValue();
00337
00338 list.insert(QUrl::fromPercentEncoding(sName.toUtf8()),
00339 QUrl::fromPercentEncoding(sValue.toUtf8()));
00340 }
00341
00342
00343
00344 oMethod = xmlResult.importNode( oMethod.firstChild(), true );
00345
00346
00347
00348
00349 xmlResult.appendChild( oMethod );
00350
00351 return xmlResult;
00352 }
00353