18#include <QHostAddress>
26#include "libmythbase/mythversion.h"
48 QDomDocument doc (
"upnp" );
49 QFile
file( sFileName );
51 if ( !
file.open( QIODevice::ReadOnly ) )
54#if QT_VERSION < QT_VERSION_CHECK(6,5,0)
58 bool bSuccess = doc.setContent( &
file,
false,
59 &sErrMsg, &nErrLine, &nErrCol );
65 LOG(VB_GENERAL, LOG_ERR,
66 QString(
"UPnpDeviceDesc::Load - Error parsing: %1 "
67 "at line: %2 column: %3")
68 .arg(sFileName) .arg(nErrLine)
70 LOG(VB_GENERAL, LOG_ERR,
71 QString(
"UPnpDeviceDesc::Load - Error Msg: %1" ) .arg(sErrMsg));
75 auto parseResult = doc.setContent( &
file );
81 LOG(VB_GENERAL, LOG_ERR,
82 QString(
"UPnpDeviceDesc::Load - Error parsing: %1 "
83 "at line: %2 column: %3")
84 .arg(sFileName) .arg(parseResult.errorLine)
85 .arg(parseResult.errorColumn));
86 LOG(VB_GENERAL, LOG_ERR,
87 QString(
"UPnpDeviceDesc::Load - Error Msg: %1" ) .arg(parseResult.errorMessage));
109 QDomNode oNode = xmlDevDesc.documentElement();
122 QString pin =
GetMythDB()->GetSetting(
"SecurityPin",
"");
123 pCurDevice->
m_securityPin = !(pin.isEmpty() || pin ==
"0000");
125 for ( oNode = oNode.firstChild();
127 oNode = oNode.nextSibling() )
129 QDomElement e = oNode.toElement();
135 if ( e.tagName() ==
"deviceType" )
137 else if ( e.tagName() ==
"friendlyName" )
139 else if ( e.tagName() ==
"manufacturer" )
141 else if ( e.tagName() ==
"manufacturerURL" )
143 else if ( e.tagName() ==
"modelDescription" )
145 else if ( e.tagName() ==
"modelName" )
147 else if ( e.tagName() ==
"modelNumber" )
149 else if ( e.tagName() ==
"modelURL" )
151 else if ( e.tagName() ==
"serialNumber" )
153 else if ( e.tagName() ==
"UPC" )
155 else if ( e.tagName() ==
"presentationURL" )
157 else if ( e.tagName() ==
"UDN" )
159 else if ( e.tagName() ==
"iconList" )
161 else if ( e.tagName() ==
"serviceList" )
163 else if ( e.tagName() ==
"deviceList" )
165 else if ( e.tagName() ==
"mythtv:X_secure" )
167 else if ( e.tagName() ==
"mythtv:X_protocol" )
175 QDomNamedNodeMap attributes = e.attributes();
176 for (
int i = 0; i < attributes.size(); i++)
179 attributes.item(i).nodeValue(),
193 for ( QDomNode oNode = oListNode.firstChild();
195 oNode = oNode.nextSibling() )
197 QDomElement e = oNode.toElement();
202 if ( e.tagName() ==
"icon" )
207 SetStrValue( e.namedItem(
"mimetype" ), pIcon->m_sMimeType );
208 SetNumValue( e.namedItem(
"width" ), pIcon->m_nWidth );
209 SetNumValue( e.namedItem(
"height" ), pIcon->m_nHeight );
210 SetNumValue( e.namedItem(
"depth" ), pIcon->m_nDepth );
211 SetStrValue( e.namedItem(
"url" ), pIcon->m_sURL );
222 for ( QDomNode oNode = oListNode.firstChild();
224 oNode = oNode.nextSibling() )
226 QDomElement e = oNode.toElement();
231 if ( e.tagName() ==
"service" )
236 SetStrValue(e.namedItem(
"serviceType" ), pService->m_sServiceType);
237 SetStrValue(e.namedItem(
"serviceId" ), pService->m_sServiceId);
238 SetStrValue(e.namedItem(
"SCPDURL" ), pService->m_sSCPDURL);
239 SetStrValue(e.namedItem(
"controlURL" ), pService->m_sControlURL);
240 SetStrValue(e.namedItem(
"eventSubURL" ), pService->m_sEventSubURL);
242 LOG(VB_UPNP, LOG_INFO,
243 QString(
"ProcessServiceList adding service : %1 : %2 :")
244 .arg(pService->m_sServiceType,
245 pService->m_sServiceId));
257 for ( QDomNode oNode = oListNode.firstChild();
259 oNode = oNode.nextSibling() )
261 QDomElement e = oNode.toElement();
266 if ( e.tagName() ==
"device")
281 QDomText oText = n.firstChild().toText();
284 sValue = oText.nodeValue();
294 QDomText oText = n.firstChild().toText();
297 nValue = oText.nodeValue().toInt();
305 QDomText oText = n.firstChild().toText();
309 QString s = oText.nodeValue();
310 nValue = (s ==
"yes" || s ==
"true" || (s.toInt() != 0));
322#if QT_VERSION < QT_VERSION_CHECK(6,0,0)
323 QTextStream os( &sXML, QIODevice::WriteOnly );
325 QTextStream os(&sXML, QIODeviceBase::WriteOnly);
338 const QString &,
int ,
339 QTextStream &os,
const QString &sUserAgent )
342 os.setEncoding( QTextStream::UnicodeUTF8 );
344 os <<
"<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
345 "<root xmlns=\"urn:schemas-upnp-org:device-1-0\" "
346 " xmlns:mythtv=\"mythtv.org\">\n"
364 const QString &sUserAgent )
366 if (pDevice ==
nullptr)
369 QString sFriendlyName = QString(
"%1: %2" )
382 os <<
FormatValue(
"friendlyName" , sFriendlyName );
392 sUserAgent.startsWith(QString(
"Xbox/2.0"), Qt::CaseInsensitive) ||
393 sUserAgent.startsWith(QString(
"Mozilla/4.0"), Qt::CaseInsensitive);
421 for (
const auto & nit : std::as_const(pDevice->
m_lstExtra))
432 os <<
"<iconList>\n";
434 for (
auto *icon : std::as_const(pDevice->
m_listIcons))
437 os <<
FormatValue(
"mimetype", icon->m_sMimeType );
444 os <<
"</iconList>\n";
469 bool bDSM = sUserAgent.startsWith(
"INTEL_NMPR/2.1 DLNADOC/1.00",
false);
472 os <<
"<serviceList>\n";
476 if (!bIsXbox360 && service->m_sServiceType.startsWith(
477 "urn:microsoft.com:service:X_MS_MediaReceiverRegistrar",
478 Qt::CaseInsensitive))
484 os <<
FormatValue(
"serviceType", service->m_sServiceType );
485 os <<
FormatValue(
"serviceId" , service->m_sServiceId );
486 os <<
FormatValue(
"SCPDURL" , service->m_sSCPDURL );
487 os <<
FormatValue(
"controlURL" , service->m_sControlURL );
488 os <<
FormatValue(
"eventSubURL", service->m_sEventSubURL );
489 os <<
"</service>\n";
491 os <<
"</serviceList>\n";
500 os <<
"<deviceList>";
502 UPnpDeviceList::iterator it;
510 os <<
"</deviceList>";
525 NameValues::iterator it;
528 sAttributes += QString(
" %1='%2'").arg((*it).m_sName, (*it).m_sValue);
530 sStr = QString(
"<%1%2>%3</%1>\n").arg(node.
m_sName, sAttributes, node.
m_sValue);
540 const QString &sValue )
544 if (sValue.length() > 0)
545 sStr = QString(
"<%1>%2</%1>\n") .arg(sName, sValue);
554 return( QString(
"<%1>%2</%1>\n") .arg(sName) .arg(nValue) );
564 if (sST.section(
':', 0, -2) == pDevice->
m_sDeviceType.section(
':', 0, -2))
567 if (sST.section(
':', 0, -2) == pDevice->
GetUDN().section(
':', 0, -2))
578 if (sST.section(
':', 0, -2) == (*sit)->m_sServiceType.section(
':', 0, -2))
589 if (sUDN.length() > 0)
610 const QString &sURI )
613 if ( sURI.section(
':', 0, -2) == pDevice->
m_sDeviceType.section(
':', 0, -2) )
620 for (
const auto & dev : std::as_const(pDevice->
m_listDevices))
624 if (pFound !=
nullptr)
639 LOG(VB_UPNP, LOG_DEBUG, QString(
"UPnpDeviceDesc::Retrieve( %1 )")
646 QString sXml(buffer);
648 if (ok && sXml.startsWith( QString(
"<?xml") ))
650 QDomDocument xml(
"upnp" );
652#if QT_VERSION < QT_VERSION_CHECK(6,5,0)
654 bool success = xml.setContent( sXml,
false, &sErrorMsg );
656 auto parseResult = xml.setContent( sXml );
657 bool success { parseResult };
658 QString sErrorMsg { parseResult.errorMessage };
663 pDevice->
Load( xml );
669 LOG(VB_UPNP, LOG_ERR,
670 QString(
"Error parsing device description xml [%1]")
676 LOG(VB_UPNP, LOG_ERR, QString(
"Invalid response '%1'").arg(sXml));
692 QString localHostName = QHostInfo::localHostName();
693 if (localHostName.isEmpty())
694 LOG(VB_GENERAL, LOG_ERR,
695 "UPnpDeviceDesc: Error, could not determine host name." +
ENO);
712 m_sModelNumber(MYTH_BINARY_VERSION),
714 m_protocolVersion(MYTH_PROTO_VERSION)
730 pngIconLrg->m_nDepth = 24;
731 pngIconLrg->m_nHeight = 120;
732 pngIconLrg->m_nWidth = 120;
733 pngIconLrg->m_sMimeType =
"image/png";
734 pngIconLrg->m_sURL =
"/images/icons/upnp_large_icon.png";
739 jpgIconLrg->m_nDepth = 24;
740 jpgIconLrg->m_nHeight = 120;
741 jpgIconLrg->m_nWidth = 120;
742 jpgIconLrg->m_sMimeType =
"image/jpeg";
743 jpgIconLrg->m_sURL =
"/images/icons/upnp_large_icon.jpg";
748 pngIconSm->m_nDepth = 24;
749 pngIconSm->m_nHeight = 48;
750 pngIconSm->m_nWidth = 48;
751 pngIconSm->m_sMimeType =
"image/png";
752 pngIconSm->m_sURL =
"/images/icons/upnp_small_icon.png";
757 jpgIconSm->m_nDepth = 24;
758 jpgIconSm->m_nHeight = 48;
759 jpgIconSm->m_nWidth = 48;
760 jpgIconSm->m_sMimeType =
"image/jpeg";
761 jpgIconSm->m_sURL =
"/images/icons/upnp_small_icon.jpg";
817 if (service->m_sServiceType.section(
':', 0, -2) == urn.section(
':', 0, -2))
829 srv = (*dit)->GetService(urn, &done);
841 QString(
"UPnP Device\n"
846 "manufacturerURL: %4\n"
847 "modelDescription: %5\n"
859 QString(
"serialNumber: %1\n"
861 "presentationURL: %3\n"
870 ret +=
"Extra key value pairs\n";
871 for (
const auto & extra : std::as_const(
m_lstExtra))
873 ret += extra.m_sName;
875 int int_padding = 18 - (extra.m_sName.length() + 1);
876 for (
int i = 0; i < int_padding; i++)
878 ret += QString(
"%1\n").arg(extra.m_sValue);
884 ret +=
"Icon List:\n";
886 ret += icon->toString(padding+2) +
"\n";
891 ret +=
"Service List:\n";
893 ret += service->toString(padding+2) +
"\n";
898 ret +=
"Device List:\n";
900 ret += device->toString(padding+2) +
"\n";
905 if (ret.endsWith(
"\n"))
906 ret = ret.left(ret.length()-1);
912 for (
uint i = 0; i < padding; i++)
914 ret = pad + ret.replace(
"\n", QString(
"\n%1").arg(pad));
bool download(const QString &url, const QString &dest, bool reload=false)
Downloads a URL to a file in blocking mode.
NameValues * m_pAttributes
void AddAttribute(const QString &name, const QString &value, bool required)
QString GetHostName() const
void OutputDevice(QTextStream &os, UPnpDevice *pDevice, const QString &sUserAgent="")
void ProcessDeviceList(const QDomNode &oListNode, UPnpDevice *pDevice)
static QString FormatValue(const NameValue &node)
void GetValidXML(const QString &sBaseAddress, int nPort, QTextStream &os, const QString &sUserAgent="")
static void SetNumValue(const QDomNode &n, int &nValue)
Sets nValue param to n.firstChild().toText().nodeValue(), iff neither n.isNull() nor n....
static UPnpDeviceDesc * Retrieve(QString &sURL)
void InternalLoad(QDomNode oNode, UPnpDevice *pCurDevice)
QString FindDeviceUDN(UPnpDevice *pDevice, QString sST)
UPnpDevice * FindDevice(const QString &sURI)
static void ProcessServiceList(const QDomNode &oListNode, UPnpDevice *pDevice)
bool Load(const QString &sFileName)
static void SetStrValue(const QDomNode &n, QString &sValue)
Sets sValue param to n.firstChild().toText().nodeValue(), iff neither n.isNull() nor n....
static void ProcessIconList(const QDomNode &oListNode, UPnpDevice *pDevice)
static void SetBoolValue(const QDomNode &n, bool &nValue)
QString m_sModelDescription
QString GetUDN(void) const
QString m_sPresentationURL
void toMap(InfoMap &map) const
QString m_sManufacturerURL
bool m_securityPin
MythTV specific information.
QString m_protocolVersion
UPnpService GetService(const QString &urn, bool *found=nullptr) const
UPnpServiceList m_listServices
QString toString(uint padding=0) const
UPnpDeviceList m_listDevices
QString GetValue(const QString &setting)
MythDownloadManager * GetMythDownloadManager(void)
Gets the pointer to the MythDownloadManager singleton.
#define ENO
This can be appended to the LOG args with "+".
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
QHash< QString, QString > InfoMap
const char * GetMythSourceVersion()
QString LookupUDN(const QString &sDeviceType)