00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00012
00013 #include "upnp.h"
00014 #include "upnpdevice.h"
00015 #include "httpcomms.h"
00016 #include "mythlogging.h"
00017 #include "mythversion.h"
00018
00019
00020 #include "mythdb.h"
00021
00022 #include <cerrno>
00023
00024 #include <QFile>
00025 #include <QTextStream>
00026 #include <QHostAddress>
00027
00028 int DeviceLocation::g_nAllocated = 0;
00029
00032
00033
00034
00037
00039
00041
00042 UPnpDeviceDesc::UPnpDeviceDesc()
00043 {
00044 LOG(VB_UPNP, LOG_INFO, "UPnpDeviceDesc - Constructor");
00045 }
00046
00048
00050
00051 UPnpDeviceDesc::~UPnpDeviceDesc()
00052 {
00053
00054 #if 0
00055 LOG(VB_UPNP, LOG_INFO, "UPnpDeviceDesc - Destructor");
00056 #endif
00057 }
00058
00060
00062
00063 bool UPnpDeviceDesc::Load( const QString &sFileName )
00064 {
00065
00066
00067
00068
00069 QDomDocument doc ( "upnp" );
00070 QFile file( sFileName );
00071
00072 if ( !file.open( QIODevice::ReadOnly ) )
00073 return false;
00074
00075 QString sErrMsg;
00076 int nErrLine = 0;
00077 int nErrCol = 0;
00078 bool bSuccess = doc.setContent( &file, false,
00079 &sErrMsg, &nErrLine, &nErrCol );
00080
00081 file.close();
00082
00083 if (!bSuccess)
00084 {
00085 LOG(VB_GENERAL, LOG_ERR,
00086 QString("UPnpDeviceDesc::Load - Error parsing: %1 "
00087 "at line: %2 column: %3")
00088 .arg(sFileName) .arg(nErrLine)
00089 .arg(nErrCol));
00090 LOG(VB_GENERAL, LOG_ERR,
00091 QString("UPnpDeviceDesc::Load - Error Msg: %1" ) .arg(sErrMsg));
00092 return false;
00093 }
00094
00095
00096
00097
00098
00099 return Load( doc );
00100 }
00101
00103
00105
00106 bool UPnpDeviceDesc::Load( const QDomDocument &xmlDevDesc )
00107 {
00108
00109
00110
00111
00112 QDomNode oNode = xmlDevDesc.documentElement();
00113
00114 _InternalLoad( oNode.namedItem( "device" ), &m_rootDevice );
00115
00116 return true;
00117 }
00118
00120
00122
00123 void UPnpDeviceDesc::_InternalLoad( QDomNode oNode, UPnpDevice *pCurDevice )
00124 {
00125 QString pin = GetMythDB()->GetSetting( "SecurityPin", "");
00126 pCurDevice->m_securityPin = !(pin.isEmpty() || pin == "0000");
00127
00128 for ( oNode = oNode.firstChild();
00129 !oNode.isNull();
00130 oNode = oNode.nextSibling() )
00131 {
00132 QDomElement e = oNode.toElement();
00133
00134 if (e.isNull())
00135 continue;
00136
00137
00138 if ( e.tagName() == "deviceType" )
00139 SetStrValue( e, pCurDevice->m_sDeviceType);
00140 else if ( e.tagName() == "friendlyName" )
00141 SetStrValue( e, pCurDevice->m_sFriendlyName );
00142 else if ( e.tagName() == "manufacturer" )
00143 SetStrValue( e, pCurDevice->m_sManufacturer );
00144 else if ( e.tagName() == "manufacturerURL" )
00145 SetStrValue( e, pCurDevice->m_sManufacturerURL );
00146 else if ( e.tagName() == "modelDescription" )
00147 SetStrValue( e, pCurDevice->m_sModelDescription);
00148 else if ( e.tagName() == "modelName" )
00149 SetStrValue( e, pCurDevice->m_sModelName );
00150 else if ( e.tagName() == "modelNumber" )
00151 SetStrValue( e, pCurDevice->m_sModelNumber );
00152 else if ( e.tagName() == "modelURL" )
00153 SetStrValue( e, pCurDevice->m_sModelURL );
00154 else if ( e.tagName() == "serialNumber" )
00155 SetStrValue( e, pCurDevice->m_sSerialNumber );
00156 else if ( e.tagName() == "UPC" )
00157 SetStrValue( e, pCurDevice->m_sUPC );
00158 else if ( e.tagName() == "presentationURL" )
00159 SetStrValue( e, pCurDevice->m_sPresentationURL );
00160 else if ( e.tagName() == "UDN" )
00161 SetStrValue( e, pCurDevice->m_sUDN );
00162 else if ( e.tagName() == "iconList" )
00163 ProcessIconList( oNode, pCurDevice );
00164 else if ( e.tagName() == "serviceList" )
00165 ProcessServiceList( oNode, pCurDevice );
00166 else if ( e.tagName() == "deviceList" )
00167 ProcessDeviceList ( oNode, pCurDevice );
00168 else if ( e.tagName() == "mythtv:X_secure" )
00169 SetBoolValue( e, pCurDevice->m_securityPin );
00170 else if ( e.tagName() == "mythtv:X_protocol" )
00171 SetStrValue( e, pCurDevice->m_protocolVersion );
00172 else
00173 {
00174
00175 QString sValue = "";
00176 SetStrValue( e, sValue );
00177 pCurDevice->m_lstExtra.push_back(NameValue(e.tagName(), sValue));
00178 }
00179 }
00180 }
00181
00183
00185
00186 void UPnpDeviceDesc::ProcessIconList( QDomNode oListNode, UPnpDevice *pDevice )
00187 {
00188 for ( QDomNode oNode = oListNode.firstChild();
00189 !oNode.isNull();
00190 oNode = oNode.nextSibling() )
00191 {
00192 QDomElement e = oNode.toElement();
00193
00194 if (e.isNull())
00195 continue;
00196
00197 if ( e.tagName() == "icon" )
00198 {
00199 UPnpIcon *pIcon = new UPnpIcon();
00200 pDevice->m_listIcons.append( pIcon );
00201
00202 SetStrValue( e.namedItem( "mimetype" ), pIcon->m_sMimeType );
00203 SetNumValue( e.namedItem( "width" ), pIcon->m_nWidth );
00204 SetNumValue( e.namedItem( "height" ), pIcon->m_nHeight );
00205 SetNumValue( e.namedItem( "depth" ), pIcon->m_nDepth );
00206 SetStrValue( e.namedItem( "url" ), pIcon->m_sURL );
00207 }
00208 }
00209 }
00210
00212
00214
00215 void UPnpDeviceDesc::ProcessServiceList( QDomNode oListNode, UPnpDevice *pDevice )
00216 {
00217 for ( QDomNode oNode = oListNode.firstChild();
00218 !oNode.isNull();
00219 oNode = oNode.nextSibling() )
00220 {
00221 QDomElement e = oNode.toElement();
00222
00223 if (e.isNull())
00224 continue;
00225
00226 if ( e.tagName() == "service" )
00227 {
00228 UPnpService *pService = new UPnpService();
00229 pDevice->m_listServices.append( pService );
00230
00231 SetStrValue(e.namedItem( "serviceType" ), pService->m_sServiceType);
00232 SetStrValue(e.namedItem( "serviceId" ), pService->m_sServiceId);
00233 SetStrValue(e.namedItem( "SCPDURL" ), pService->m_sSCPDURL);
00234 SetStrValue(e.namedItem( "controlURL" ), pService->m_sControlURL);
00235 SetStrValue(e.namedItem( "eventSubURL" ), pService->m_sEventSubURL);
00236
00237 LOG(VB_UPNP, LOG_INFO,
00238 QString("ProcessServiceList adding service : %1 : %2 :")
00239 .arg(pService->m_sServiceType)
00240 .arg(pService->m_sServiceId));
00241 }
00242 }
00243 }
00244
00246
00248
00249 void UPnpDeviceDesc::ProcessDeviceList( QDomNode oListNode,
00250 UPnpDevice *pDevice )
00251 {
00252 for ( QDomNode oNode = oListNode.firstChild();
00253 !oNode.isNull();
00254 oNode = oNode.nextSibling() )
00255 {
00256 QDomElement e = oNode.toElement();
00257
00258 if (e.isNull())
00259 continue;
00260
00261 if ( e.tagName() == "device")
00262 {
00263 UPnpDevice *pNewDevice = new UPnpDevice();
00264 pDevice->m_listDevices.append( pNewDevice );
00265 _InternalLoad( e, pNewDevice );
00266 }
00267 }
00268 }
00269
00272 void UPnpDeviceDesc::SetStrValue( const QDomNode &n, QString &sValue )
00273 {
00274 if (!n.isNull())
00275 {
00276 QDomText oText = n.firstChild().toText();
00277
00278 if (!oText.isNull())
00279 sValue = oText.nodeValue();
00280 }
00281 }
00282
00285 void UPnpDeviceDesc::SetNumValue( const QDomNode &n, int &nValue )
00286 {
00287 if (!n.isNull())
00288 {
00289 QDomText oText = n.firstChild().toText();
00290
00291 if (!oText.isNull())
00292 nValue = oText.nodeValue().toInt();
00293 }
00294 }
00295
00296 void UPnpDeviceDesc::SetBoolValue( const QDomNode &n, bool &nValue )
00297 {
00298 if (!n.isNull())
00299 {
00300 QDomText oText = n.firstChild().toText();
00301
00302 if (!oText.isNull())
00303 {
00304 QString s = oText.nodeValue();
00305 nValue = (s == "yes" || s == "true" || s.toInt());
00306 }
00307 }
00308 }
00309
00311
00313
00314 QString UPnpDeviceDesc::GetValidXML( const QString &sBaseAddress, int nPort )
00315 {
00316 QString sXML;
00317 QTextStream os( &sXML, QIODevice::WriteOnly );
00318
00319 GetValidXML( sBaseAddress, nPort, os );
00320 os << flush;
00321 return( sXML );
00322 }
00323
00325
00327
00328 void UPnpDeviceDesc::GetValidXML(
00329 const QString &sBaseAddress, int nPort,
00330 QTextStream &os, const QString &sUserAgent )
00331 {
00332 #if 0
00333 os.setEncoding( QTextStream::UnicodeUTF8 );
00334 #endif
00335
00336 QString BaseAddr;
00337 QHostAddress addr(sBaseAddress);
00338
00339 BaseAddr = sBaseAddress;
00340
00341 #if !defined(QT_NO_IPV6)
00342
00343
00344 if (sBaseAddress.contains(":"))
00345 BaseAddr = "[" + sBaseAddress + "]";
00346 #endif
00347
00348 os << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
00349 "<root xmlns=\"urn:schemas-upnp-org:device-1-0\" "
00350 " xmlns:mythtv=\"mythtv.org\">\n"
00351 "<specVersion>\n"
00352 "<major>1</major>\n"
00353 "<minor>0</minor>\n"
00354 "</specVersion>\n"
00355 "<URLBase>http://"
00356 << BaseAddr << ":" << nPort << "/</URLBase>\n";
00357
00358 OutputDevice( os, &m_rootDevice, sUserAgent );
00359
00360 os << "</root>\n";
00361 os << flush;
00362 }
00363
00365
00367
00368 void UPnpDeviceDesc::OutputDevice( QTextStream &os,
00369 UPnpDevice *pDevice,
00370 const QString &sUserAgent )
00371 {
00372 if (pDevice == NULL)
00373 return;
00374
00375 QString sFriendlyName = QString( "%1: %2" )
00376 .arg( GetHostName() )
00377 .arg( pDevice->m_sFriendlyName );
00378
00379
00380
00381
00382
00383 if (pDevice == &m_rootDevice)
00384 sFriendlyName = UPnp::GetConfiguration()->GetValue( "UPnP/FriendlyName",
00385 sFriendlyName );
00386
00387 os << "<device>\n";
00388 os << FormatValue( "deviceType" , pDevice->m_sDeviceType );
00389 os << FormatValue( "friendlyName" , sFriendlyName );
00390
00391
00392
00393
00394
00395
00396
00397
00398 bool bIsXbox360 =
00399 sUserAgent.startsWith(QString("Xbox/2.0"), Qt::CaseInsensitive) ||
00400 sUserAgent.startsWith(QString("Mozilla/4.0"), Qt::CaseInsensitive);
00401
00402 os << FormatValue( "manufacturer" , pDevice->m_sManufacturer );
00403 os << FormatValue( "modelURL" , pDevice->m_sModelURL );
00404
00405 if ( bIsXbox360 )
00406 {
00407 os << FormatValue( "modelName" ,
00408 "Windows Media Connect Compatible (MythTV)");
00409 }
00410 else
00411 {
00412 os << FormatValue( "modelName" , pDevice->m_sModelName );
00413 }
00414
00415 os << FormatValue( "manufacturerURL" , pDevice->m_sManufacturerURL );
00416 os << FormatValue( "modelDescription" , pDevice->m_sModelDescription);
00417 os << FormatValue( "modelNumber" , pDevice->m_sModelNumber );
00418 os << FormatValue( "serialNumber" , pDevice->m_sSerialNumber );
00419 os << FormatValue( "UPC" , pDevice->m_sUPC );
00420 os << FormatValue( "presentationURL" , pDevice->m_sPresentationURL );
00421
00422
00423 os << FormatValue( "mythtv:X_secure" ,
00424 pDevice->m_securityPin ? "true" : "false");
00425 os << FormatValue( "mythtv:X_protocol", pDevice->m_protocolVersion );
00426
00427 NameValues::const_iterator nit = pDevice->m_lstExtra.begin();
00428 for (; nit != pDevice->m_lstExtra.end(); ++nit)
00429 {
00430
00431
00432
00433 if ((*nit).sName == "dlna:X_DLNADOC")
00434 {
00435 os << QString("<dlna:X_DLNADOC xmlns:dlna=\"urn:"
00436 "schemas-dlna-org:device-1-0\">%1"
00437 "</dlna:X_DLNADOC>\n" ).arg((*nit).sValue);
00438 }
00439 else
00440 os << FormatValue( (*nit).sName, (*nit).sValue );
00441 }
00442
00443
00444
00445
00446
00447 if (pDevice->m_listIcons.count() > 0)
00448 {
00449 os << "<iconList>\n";
00450
00451 UPnpIconList::const_iterator it = pDevice->m_listIcons.begin();
00452 for (; it != pDevice->m_listIcons.end(); ++it)
00453 {
00454 os << "<icon>\n";
00455 os << FormatValue( "mimetype", (*it)->m_sMimeType );
00456 os << FormatValue( "width" , (*it)->m_nWidth );
00457 os << FormatValue( "height" , (*it)->m_nHeight );
00458 os << FormatValue( "depth" , (*it)->m_nDepth );
00459 os << FormatValue( "url" , (*it)->m_sURL );
00460 os << "</icon>\n";
00461 }
00462 os << "</iconList>\n";
00463 }
00464
00465 os << FormatValue( "UDN" , pDevice->GetUDN() );
00466
00467
00468
00469
00470
00471 if (pDevice->m_listServices.count() > 0)
00472 {
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486 #if 0
00487 bool bDSM = sUserAgent.startsWith("INTEL_NMPR/2.1 DLNADOC/1.00", false);
00488 #endif
00489
00490 os << "<serviceList>\n";
00491
00492 UPnpServiceList::const_iterator it = pDevice->m_listServices.begin();
00493 for (; it != pDevice->m_listServices.end(); ++it)
00494 {
00495 if (!bIsXbox360 && (*it)->m_sServiceType.startsWith(
00496 "urn:microsoft.com:service:X_MS_MediaReceiverRegistrar",
00497 Qt::CaseInsensitive))
00498 {
00499 continue;
00500 }
00501
00502 os << "<service>\n";
00503 os << FormatValue( "serviceType", (*it)->m_sServiceType );
00504 os << FormatValue( "serviceId" , (*it)->m_sServiceId );
00505 os << FormatValue( "SCPDURL" , (*it)->m_sSCPDURL );
00506 os << FormatValue( "controlURL" , (*it)->m_sControlURL );
00507 os << FormatValue( "eventSubURL", (*it)->m_sEventSubURL );
00508 os << "</service>\n";
00509 }
00510 os << "</serviceList>\n";
00511 }
00512
00513
00514
00515
00516
00517
00518 #if 0
00519 if (sUserAgent.length() > 0)
00520 {
00521 if (pDevice->m_listDevices.count() > 0)
00522 {
00523 os << "<deviceList>";
00524
00525 for ( UPnpDevice *pEmbeddedDevice = pDevice->m_listDevices.first();
00526 pEmbeddedDevice != NULL;
00527 pEmbeddedDevice = pDevice->m_listDevices.next() )
00528 {
00529 OutputDevice( os, pEmbeddedDevice );
00530 }
00531 os << "</deviceList>";
00532 }
00533 }
00534 #endif
00535 os << "</device>\n";
00536 os << flush;
00537 }
00538
00540
00542
00543 QString UPnpDeviceDesc::FormatValue( const QString &sName,
00544 const QString &sValue )
00545 {
00546 QString sStr;
00547
00548 if (sValue.length() > 0)
00549 sStr = QString("<%1>%2</%1>\n") .arg(sName) .arg(sValue);
00550
00551 return( sStr );
00552 }
00553
00555
00556 QString UPnpDeviceDesc::FormatValue( const QString &sName, int nValue )
00557 {
00558 return( QString("<%1>%2</%1>\n") .arg(sName) .arg(nValue) );
00559 }
00560
00562
00564
00565 QString UPnpDeviceDesc::FindDeviceUDN( UPnpDevice *pDevice, QString sST )
00566 {
00567 if (sST == pDevice->m_sDeviceType)
00568 return pDevice->GetUDN();
00569
00570 if (sST == pDevice->GetUDN())
00571 return sST;
00572
00573
00574
00575
00576
00577 UPnpServiceList::const_iterator sit = pDevice->m_listServices.begin();
00578 for (; sit != pDevice->m_listServices.end(); ++sit)
00579 {
00580 if (sST == (*sit)->m_sServiceType)
00581 return pDevice->GetUDN();
00582 }
00583
00584
00585
00586
00587
00588 UPnpDeviceList::const_iterator dit = pDevice->m_listDevices.begin();
00589 for (; dit != pDevice->m_listDevices.end(); ++dit)
00590 {
00591 QString sUDN = FindDeviceUDN( *dit, sST );
00592 if (sUDN.length() > 0)
00593 return sUDN;
00594 }
00595
00596 return "";
00597 }
00598
00600
00602
00603 UPnpDevice *UPnpDeviceDesc::FindDevice( const QString &sURI )
00604 {
00605 return FindDevice( &m_rootDevice, sURI );
00606 }
00607
00609
00611
00612 UPnpDevice *UPnpDeviceDesc::FindDevice( UPnpDevice *pDevice,
00613 const QString &sURI )
00614 {
00615 if ( sURI == pDevice->m_sDeviceType )
00616 return pDevice;
00617
00618
00619
00620
00621
00622 UPnpDeviceList::iterator dit = pDevice->m_listDevices.begin();
00623 for (; dit != pDevice->m_listDevices.end(); ++dit)
00624 {
00625 UPnpDevice *pFound = FindDevice(*dit, sURI);
00626
00627 if (pFound != NULL)
00628 return pFound;
00629 }
00630
00631 return NULL;
00632 }
00633
00635
00637
00638 UPnpDeviceDesc *UPnpDeviceDesc::Retrieve( QString &sURL, bool bInQtThread )
00639 {
00640 UPnpDeviceDesc *pDevice = NULL;
00641
00642 LOG(VB_UPNP, LOG_DEBUG, QString("UPnpDeviceDesc::Retrieve( %1, %2 )")
00643 .arg(sURL) .arg(bInQtThread));
00644
00645 QString sXml = HttpComms::getHttp( sURL,
00646 10000,
00647 3,
00648 0,
00649 false,
00650 NULL,
00651 bInQtThread );
00652
00653 if (sXml.startsWith( QString("<?xml") ))
00654 {
00655 QString sErrorMsg;
00656
00657 QDomDocument xml( "upnp" );
00658
00659 if ( xml.setContent( sXml, false, &sErrorMsg ))
00660 {
00661 pDevice = new UPnpDeviceDesc();
00662 pDevice->Load( xml );
00663 pDevice->m_HostUrl = sURL;
00664 pDevice->m_sHostName = pDevice->m_HostUrl.host();
00665 }
00666 else
00667 {
00668 LOG(VB_UPNP, LOG_ERR,
00669 QString("Error parsing device description xml [%1]")
00670 .arg(sErrorMsg));
00671 }
00672 }
00673 else
00674 {
00675 LOG(VB_UPNP, LOG_ERR, QString("Invalid response '%1'").arg(sXml));
00676 }
00677
00678 return pDevice;
00679 }
00680
00682
00684
00685 QString UPnpDeviceDesc::GetHostName()
00686 {
00687 if (m_sHostName.length() == 0)
00688 {
00689
00690
00691 char localHostName[1024];
00692
00693 if (gethostname(localHostName, 1024))
00694 LOG(VB_GENERAL, LOG_ERR,
00695 "UPnpDeviceDesc: Error, could not determine host name." + ENO);
00696
00697 return UPnp::GetConfiguration()->GetValue("Settings/HostName",
00698 QString(localHostName));
00699 }
00700
00701 return m_sHostName;
00702 }
00703
00706
00707
00708
00711
00712 UPnpDevice::UPnpDevice() :
00713 m_sModelNumber(MYTH_BINARY_VERSION),
00714 m_sSerialNumber(MYTH_SOURCE_VERSION),
00715 m_securityPin(false),
00716 m_protocolVersion(MYTH_PROTO_VERSION)
00717 {
00718 }
00719
00720 UPnpDevice::~UPnpDevice()
00721 {
00722 while (!m_listIcons.empty())
00723 {
00724 delete m_listIcons.back();
00725 m_listIcons.pop_back();
00726 }
00727 while (!m_listServices.empty())
00728 {
00729 delete m_listServices.back();
00730 m_listServices.pop_back();
00731 }
00732 while (!m_listDevices.empty())
00733 {
00734 delete m_listDevices.back();
00735 m_listDevices.pop_back();
00736 }
00737 }
00738
00739 QString UPnpDevice::GetUDN(void) const
00740 {
00741 if (m_sUDN.isEmpty())
00742 m_sUDN = "uuid:" + LookupUDN( m_sDeviceType );
00743
00744 return m_sUDN;
00745 }
00746
00747 void UPnpDevice::toMap(QHash<QString, QString> &map)
00748 {
00749 map["name"] = m_sFriendlyName;
00750 map["modelname"] = m_sModelName;
00751 map["modelnumber"] = m_sModelNumber;
00752 map["modelurl"] = m_sModelURL;
00753 map["modeldescription"] = m_sModelDescription;
00754 map["manufacturer"] = m_sManufacturer;
00755 map["manufacturerurl"] = m_sManufacturerURL;
00756 map["devicetype"] = m_sDeviceType;
00757 map["serialnumber"] = m_sSerialNumber;
00758 map["UDN"] = m_sUDN;
00759 map["UPC"] = m_sUPC;
00760 map["protocolversion"] = m_protocolVersion;
00761 }
00762
00763 UPnpService UPnpDevice::GetService(const QString &urn, bool *found) const
00764 {
00765 UPnpService srv;
00766
00767 bool done = false;
00768
00769 UPnpServiceList::const_iterator it = m_listServices.begin();
00770 for (; it != m_listServices.end(); ++it)
00771 {
00772 if ((*it)->m_sServiceType == urn)
00773 {
00774 srv = **it;
00775 done = true;
00776 break;
00777 }
00778 }
00779
00780 if (!done)
00781 {
00782 UPnpDeviceList::const_iterator dit = m_listDevices.begin();
00783 for (; dit != m_listDevices.end() && !done; ++dit)
00784 srv = (*dit)->GetService(urn, &done);
00785 }
00786
00787 if (found)
00788 *found = done;
00789
00790 return srv;
00791 }
00792
00793 QString UPnpDevice::toString(uint padding) const
00794 {
00795 QString ret =
00796 QString("UPnP Device\n"
00797 "===========\n"
00798 "deviceType: %1\n"
00799 "friendlyName: %2\n"
00800 "manufacturer: %3\n"
00801 "manufacturerURL: %4\n"
00802 "modelDescription: %5\n"
00803 "modelName: %6\n"
00804 "modelNumber: %7\n"
00805 "modelURL: %8\n")
00806 .arg(m_sDeviceType )
00807 .arg(m_sFriendlyName )
00808 .arg(m_sManufacturer )
00809 .arg(m_sManufacturerURL )
00810 .arg(m_sModelDescription)
00811 .arg(m_sModelName )
00812 .arg(m_sModelNumber )
00813 .arg(m_sModelURL ) +
00814 QString("serialNumber: %1\n"
00815 "UPC: %2\n"
00816 "presentationURL: %3\n"
00817 "UDN: %4\n")
00818 .arg(m_sSerialNumber )
00819 .arg(m_sUPC )
00820 .arg(m_sPresentationURL )
00821 .arg(m_sUDN );
00822
00823 if (!m_lstExtra.empty())
00824 {
00825 NameValues::const_iterator it = m_lstExtra.begin();
00826 ret += "Extra key value pairs\n";
00827 for (; it != m_lstExtra.end(); ++it)
00828 {
00829 ret += (*it).sName;
00830 ret += ":";
00831 int int_padding = 18 - ((*it).sName.length() + 1);
00832 for (int i = 0; i < int_padding; i++)
00833 ret += " ";
00834 ret += QString("%1\n").arg((*it).sValue);
00835 }
00836 }
00837
00838 if (!m_listIcons.empty())
00839 {
00840 ret += "Icon List:\n";
00841 UPnpIconList::const_iterator it = m_listIcons.begin();
00842 for (; it != m_listIcons.end(); ++it)
00843 ret += (*it)->toString(padding+2) + "\n";
00844 }
00845
00846 if (!m_listServices.empty())
00847 {
00848 ret += "Service List:\n";
00849 UPnpServiceList::const_iterator it = m_listServices.begin();
00850 for (; it != m_listServices.end(); ++it)
00851 ret += (*it)->toString(padding+2) + "\n";
00852 }
00853
00854 if (!m_listDevices.empty())
00855 {
00856 ret += "Device List:\n";
00857 UPnpDeviceList::const_iterator it = m_listDevices.begin();
00858 for (; it != m_listDevices.end(); ++it)
00859 ret += (*it)->toString(padding+2) + "\n";
00860 ret += "\n";
00861 }
00862
00863
00864 if (ret.right(1)=="\n")
00865 ret = ret.left(ret.length()-1);
00866
00867
00868 if (padding)
00869 {
00870 QString pad;
00871 for (uint i = 0; i < padding; i++)
00872 pad += " ";
00873 ret = pad + ret.replace("\n", QString("\n%1").arg(pad));
00874 }
00875
00876 return ret;
00877 }