MythTV  0.26-pre
upnpdevice.cpp
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends