|
MythTV
0.26-pre
|
00001 00002 // Program Name: upnpdevice.cpp 00003 // Created : Oct. 24, 2005 00004 // 00005 // Purpose : UPnp Device Description parser/generator 00006 // 00007 // Copyright (c) 2005 David Blain <dblain@mythtv.org> 00008 // 00009 // Licensed under the GPL v2 or later, see COPYING for details 00010 // 00012 00013 #include "upnp.h" 00014 #include "upnpdevice.h" 00015 #include "httpcomms.h" 00016 #include "mythlogging.h" 00017 #include "mythversion.h" // for MYTH_BINARY_VERSION 00018 00019 // MythDB 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; // Debugging only 00029 00032 // 00033 // UPnpDeviceDesc Class Implementation 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 // FIXME: Using this causes crashes 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 // Open Supplied XML uPnp Description file. 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 // XML Document Loaded... now parse it into the UPnpDevice Hierarchy 00097 // -------------------------------------------------------------- 00098 00099 return Load( doc ); 00100 } 00101 00103 // 00105 00106 bool UPnpDeviceDesc::Load( const QDomDocument &xmlDevDesc ) 00107 { 00108 // -------------------------------------------------------------- 00109 // Parse XML into the UPnpDevice Hierarchy 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 // TODO: make this table driven (using offset within structure) 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 // Not one of the expected element names... add to extra list. 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 // Basically if it appears to be an IPv6 IP surround the IP with [] 00343 // otherwise don't bother 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 // Only override the root device 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 // XBox 360 needs specific values in the Device Description. 00393 // 00394 // -=>TODO: This should be externalized in a more generic/extension 00395 // kind of way. 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 // MythTV Custom information 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 // -=>TODO: Hack to handle one element with attributes... need to 00431 // handle attributes in a more generic way. 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 // Output Any Icons. 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 // Output any Services 00469 // ---------------------------------------------------------------------- 00470 00471 if (pDevice->m_listServices.count() > 0) 00472 { 00473 // ------------------------------------------------------------------ 00474 // -=>TODO: As a temporary fix don't expose the MSRR service unless we 00475 // as an XBox360 or Windows MediaPlayer. 00476 // 00477 // There is a problem with a DSM-520 with firmware 1.04 and 00478 // the Denon AVR-4306 receiver. 00479 // 00480 // If the MSRR Service is exposed, it won't let us browse 00481 // any media content. 00482 // 00483 // Need to find out real fix and remove this code. 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 // Output any Embedded Devices 00515 // ---------------------------------------------------------------------- 00516 00517 // -=>Note: XBMC can't handle sub-devices, it's UserAgent is blank. 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 // Check for matching Service 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 // Check Embedded Devices for a Match 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 // Check Embedded Devices for a Match 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, // ms 00647 3, // retries 00648 0, // redirects 00649 false, // allow gzip 00650 NULL, // login 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 // Get HostName 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 // UPnpDevice Class Implementation 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 // remove trailing newline 00864 if (ret.right(1)=="\n") 00865 ret = ret.left(ret.length()-1); 00866 00867 // add any padding as necessary 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 }
1.7.6.1