MythTV  master
upnpdevice.cpp
Go to the documentation of this file.
1 // Program Name: upnpdevice.cpp
3 // Created : Oct. 24, 2005
4 //
5 // Purpose : UPnp Device Description parser/generator
6 //
7 // Copyright (c) 2005 David Blain <dblain@mythtv.org>
8 //
9 // Licensed under the GPL v2 or later, see COPYING for details
10 //
12 
13 #include "upnp.h"
14 #include "upnpdevice.h"
15 #include "mythdownloadmanager.h"
16 #include "mythlogging.h"
17 #include "mythversion.h" // for MYTH_BINARY_VERSION
18 #include "mythcorecontext.h"
19 
20 // MythDB
21 #include "mythdb.h"
22 
23 #include <unistd.h> // for gethostname
24 
25 #include <QFile>
26 #include <QTextStream>
27 #include <QHostAddress>
28 
29 int DeviceLocation::g_nAllocated = 0; // Debugging only
30 
33 //
34 // UPnpDeviceDesc Class Implementation
35 //
38 
40 //
42 
43 bool UPnpDeviceDesc::Load( const QString &sFileName )
44 {
45  // ----------------------------------------------------------------------
46  // Open Supplied XML uPnp Description file.
47  // ----------------------------------------------------------------------
48 
49  QDomDocument doc ( "upnp" );
50  QFile file( sFileName );
51 
52  if ( !file.open( QIODevice::ReadOnly ) )
53  return false;
54 
55  QString sErrMsg;
56  int nErrLine = 0;
57  int nErrCol = 0;
58  bool bSuccess = doc.setContent( &file, false,
59  &sErrMsg, &nErrLine, &nErrCol );
60 
61  file.close();
62 
63  if (!bSuccess)
64  {
65  LOG(VB_GENERAL, LOG_ERR,
66  QString("UPnpDeviceDesc::Load - Error parsing: %1 "
67  "at line: %2 column: %3")
68  .arg(sFileName) .arg(nErrLine)
69  .arg(nErrCol));
70  LOG(VB_GENERAL, LOG_ERR,
71  QString("UPnpDeviceDesc::Load - Error Msg: %1" ) .arg(sErrMsg));
72  return false;
73  }
74 
75  // --------------------------------------------------------------
76  // XML Document Loaded... now parse it into the UPnpDevice Hierarchy
77  // --------------------------------------------------------------
78 
79  return Load( doc );
80 }
81 
83 //
85 
86 bool UPnpDeviceDesc::Load( const QDomDocument &xmlDevDesc )
87 {
88  // --------------------------------------------------------------
89  // Parse XML into the UPnpDevice Hierarchy
90  // --------------------------------------------------------------
91 
92  QDomNode oNode = xmlDevDesc.documentElement();
93 
94  _InternalLoad( oNode.namedItem( "device" ), &m_rootDevice );
95 
96  return true;
97 }
98 
100 //
102 
103 void UPnpDeviceDesc::_InternalLoad( QDomNode oNode, UPnpDevice *pCurDevice )
104 {
105  QString pin = GetMythDB()->GetSetting( "SecurityPin", "");
106  pCurDevice->m_securityPin = !(pin.isEmpty() || pin == "0000");
107 
108  for ( oNode = oNode.firstChild();
109  !oNode.isNull();
110  oNode = oNode.nextSibling() )
111  {
112  QDomElement e = oNode.toElement();
113 
114  if (e.isNull())
115  continue;
116 
117  // TODO: make this table driven (using offset within structure)
118  if ( e.tagName() == "deviceType" )
119  SetStrValue( e, pCurDevice->m_sDeviceType);
120  else if ( e.tagName() == "friendlyName" )
121  SetStrValue( e, pCurDevice->m_sFriendlyName );
122  else if ( e.tagName() == "manufacturer" )
123  SetStrValue( e, pCurDevice->m_sManufacturer );
124  else if ( e.tagName() == "manufacturerURL" )
125  SetStrValue( e, pCurDevice->m_sManufacturerURL );
126  else if ( e.tagName() == "modelDescription" )
127  SetStrValue( e, pCurDevice->m_sModelDescription);
128  else if ( e.tagName() == "modelName" )
129  SetStrValue( e, pCurDevice->m_sModelName );
130  else if ( e.tagName() == "modelNumber" )
131  SetStrValue( e, pCurDevice->m_sModelNumber );
132  else if ( e.tagName() == "modelURL" )
133  SetStrValue( e, pCurDevice->m_sModelURL );
134  else if ( e.tagName() == "serialNumber" )
135  SetStrValue( e, pCurDevice->m_sSerialNumber );
136  else if ( e.tagName() == "UPC" )
137  SetStrValue( e, pCurDevice->m_sUPC );
138  else if ( e.tagName() == "presentationURL" )
139  SetStrValue( e, pCurDevice->m_sPresentationURL );
140  else if ( e.tagName() == "UDN" )
141  SetStrValue( e, pCurDevice->m_sUDN );
142  else if ( e.tagName() == "iconList" )
143  ProcessIconList( oNode, pCurDevice );
144  else if ( e.tagName() == "serviceList" )
145  ProcessServiceList( oNode, pCurDevice );
146  else if ( e.tagName() == "deviceList" )
147  ProcessDeviceList ( oNode, pCurDevice );
148  else if ( e.tagName() == "mythtv:X_secure" )
149  SetBoolValue( e, pCurDevice->m_securityPin );
150  else if ( e.tagName() == "mythtv:X_protocol" )
151  SetStrValue( e, pCurDevice->m_protocolVersion );
152  else
153  {
154  // Not one of the expected element names... add to extra list.
155  QString sValue = "";
156  SetStrValue( e, sValue );
157  NameValue node = NameValue(e.tagName(), sValue);
158  QDomNamedNodeMap attributes = e.attributes();
159  for (int i = 0; i < attributes.size(); i++)
160  {
161  node.AddAttribute(attributes.item(i).nodeName(),
162  attributes.item(i).nodeValue(),
163  true); // TODO Check whether all attributes are in fact requires for the device xml
164  }
165  pCurDevice->m_lstExtra.push_back(node);
166  }
167  }
168 }
169 
171 //
173 
174 void UPnpDeviceDesc::ProcessIconList( const QDomNode& oListNode, UPnpDevice *pDevice )
175 {
176  for ( QDomNode oNode = oListNode.firstChild();
177  !oNode.isNull();
178  oNode = oNode.nextSibling() )
179  {
180  QDomElement e = oNode.toElement();
181 
182  if (e.isNull())
183  continue;
184 
185  if ( e.tagName() == "icon" )
186  {
187  UPnpIcon *pIcon = new UPnpIcon();
188  pDevice->m_listIcons.append( pIcon );
189 
190  SetStrValue( e.namedItem( "mimetype" ), pIcon->m_sMimeType );
191  SetNumValue( e.namedItem( "width" ), pIcon->m_nWidth );
192  SetNumValue( e.namedItem( "height" ), pIcon->m_nHeight );
193  SetNumValue( e.namedItem( "depth" ), pIcon->m_nDepth );
194  SetStrValue( e.namedItem( "url" ), pIcon->m_sURL );
195  }
196  }
197 }
198 
200 //
202 
203 void UPnpDeviceDesc::ProcessServiceList( const QDomNode& oListNode, UPnpDevice *pDevice )
204 {
205  for ( QDomNode oNode = oListNode.firstChild();
206  !oNode.isNull();
207  oNode = oNode.nextSibling() )
208  {
209  QDomElement e = oNode.toElement();
210 
211  if (e.isNull())
212  continue;
213 
214  if ( e.tagName() == "service" )
215  {
216  UPnpService *pService = new UPnpService();
217  pDevice->m_listServices.append( pService );
218 
219  SetStrValue(e.namedItem( "serviceType" ), pService->m_sServiceType);
220  SetStrValue(e.namedItem( "serviceId" ), pService->m_sServiceId);
221  SetStrValue(e.namedItem( "SCPDURL" ), pService->m_sSCPDURL);
222  SetStrValue(e.namedItem( "controlURL" ), pService->m_sControlURL);
223  SetStrValue(e.namedItem( "eventSubURL" ), pService->m_sEventSubURL);
224 
225  LOG(VB_UPNP, LOG_INFO,
226  QString("ProcessServiceList adding service : %1 : %2 :")
227  .arg(pService->m_sServiceType)
228  .arg(pService->m_sServiceId));
229  }
230  }
231 }
232 
234 //
236 
237 void UPnpDeviceDesc::ProcessDeviceList( const QDomNode& oListNode,
238  UPnpDevice *pDevice )
239 {
240  for ( QDomNode oNode = oListNode.firstChild();
241  !oNode.isNull();
242  oNode = oNode.nextSibling() )
243  {
244  QDomElement e = oNode.toElement();
245 
246  if (e.isNull())
247  continue;
248 
249  if ( e.tagName() == "device")
250  {
251  UPnpDevice *pNewDevice = new UPnpDevice();
252  pDevice->m_listDevices.append( pNewDevice );
253  _InternalLoad( e, pNewDevice );
254  }
255  }
256 }
257 
260 void UPnpDeviceDesc::SetStrValue( const QDomNode &n, QString &sValue )
261 {
262  if (!n.isNull())
263  {
264  QDomText oText = n.firstChild().toText();
265 
266  if (!oText.isNull())
267  sValue = oText.nodeValue();
268  }
269 }
270 
273 void UPnpDeviceDesc::SetNumValue( const QDomNode &n, int &nValue )
274 {
275  if (!n.isNull())
276  {
277  QDomText oText = n.firstChild().toText();
278 
279  if (!oText.isNull())
280  nValue = oText.nodeValue().toInt();
281  }
282 }
283 
284 void UPnpDeviceDesc::SetBoolValue( const QDomNode &n, bool &nValue )
285 {
286  if (!n.isNull())
287  {
288  QDomText oText = n.firstChild().toText();
289 
290  if (!oText.isNull())
291  {
292  QString s = oText.nodeValue();
293  nValue = (s == "yes" || s == "true" || (s.toInt() != 0));
294  }
295  }
296 }
297 
299 //
301 
302 QString UPnpDeviceDesc::GetValidXML( const QString &sBaseAddress, int nPort )
303 {
304  QString sXML;
305  QTextStream os( &sXML, QIODevice::WriteOnly );
306 
307  GetValidXML( sBaseAddress, nPort, os );
308  os << flush;
309  return( sXML );
310 }
311 
313 //
315 
317  const QString &/*sBaseAddress*/, int /*nPort*/,
318  QTextStream &os, const QString &sUserAgent )
319 {
320 #if 0
321  os.setEncoding( QTextStream::UnicodeUTF8 );
322 #endif
323  os << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
324  "<root xmlns=\"urn:schemas-upnp-org:device-1-0\" "
325  " xmlns:mythtv=\"mythtv.org\">\n"
326  "<specVersion>\n"
327  "<major>1</major>\n"
328  "<minor>0</minor>\n"
329  "</specVersion>\n";
330 
331  OutputDevice( os, &m_rootDevice, sUserAgent );
332 
333  os << "</root>\n";
334  os << flush;
335 }
336 
338 //
340 
341 void UPnpDeviceDesc::OutputDevice( QTextStream &os,
342  UPnpDevice *pDevice,
343  const QString &sUserAgent )
344 {
345  if (pDevice == nullptr)
346  return;
347 
348  QString sFriendlyName = QString( "%1: %2" )
349  .arg( GetHostName() )
350  .arg( pDevice->m_sFriendlyName );
351 
352  // ----------------------------------------------------------------------
353  // Only override the root device
354  // ----------------------------------------------------------------------
355 
356  if (pDevice == &m_rootDevice)
357  sFriendlyName = UPnp::GetConfiguration()->GetValue( "UPnP/FriendlyName",
358  sFriendlyName );
359 
360  os << "<device>\n";
361  os << FormatValue( "deviceType" , pDevice->m_sDeviceType );
362  os << FormatValue( "friendlyName" , sFriendlyName );
363 
364  // ----------------------------------------------------------------------
365  // XBox 360 needs specific values in the Device Description.
366  //
367  // -=>TODO: This should be externalized in a more generic/extension
368  // kind of way.
369  // ----------------------------------------------------------------------
370 
371  bool bIsXbox360 =
372  sUserAgent.startsWith(QString("Xbox/2.0"), Qt::CaseInsensitive) ||
373  sUserAgent.startsWith(QString("Mozilla/4.0"), Qt::CaseInsensitive);
374 
375  os << FormatValue( "manufacturer" , pDevice->m_sManufacturer );
376  os << FormatValue( "modelURL" , pDevice->m_sModelURL );
377 
378  // HACK
379 // if ( bIsXbox360 )
380 // {
381 // os << FormatValue( "modelName" ,
382 // "Windows Media Connect Compatible (MythTV)");
383 // }
384 // else
385 // {
386  os << FormatValue( "modelName" , pDevice->m_sModelName );
387 // }
388 
389  os << FormatValue( "manufacturerURL" , pDevice->m_sManufacturerURL );
390  os << FormatValue( "modelDescription" , pDevice->m_sModelDescription);
391  os << FormatValue( "modelNumber" , pDevice->m_sModelNumber );
392  os << FormatValue( "serialNumber" , pDevice->m_sSerialNumber );
393  os << FormatValue( "UPC" , pDevice->m_sUPC );
394  os << FormatValue( "presentationURL" , pDevice->m_sPresentationURL );
395 
396  // MythTV Custom information
397  os << FormatValue( "mythtv:X_secure" ,
398  pDevice->m_securityPin ? "true" : "false");
399  os << FormatValue( "mythtv:X_protocol", pDevice->m_protocolVersion );
400 
401  NameValues::const_iterator nit = pDevice->m_lstExtra.begin();
402  for (; nit != pDevice->m_lstExtra.end(); ++nit)
403  {
404  os << FormatValue( (*nit) );
405  }
406 
407  // ----------------------------------------------------------------------
408  // Output Any Icons.
409  // ----------------------------------------------------------------------
410 
411  if (pDevice->m_listIcons.count() > 0)
412  {
413  os << "<iconList>\n";
414 
415  UPnpIconList::const_iterator it = pDevice->m_listIcons.begin();
416  for (; it != pDevice->m_listIcons.end(); ++it)
417  {
418  os << "<icon>\n";
419  os << FormatValue( "mimetype", (*it)->m_sMimeType );
420  os << FormatValue( "width" , (*it)->m_nWidth );
421  os << FormatValue( "height" , (*it)->m_nHeight );
422  os << FormatValue( "depth" , (*it)->m_nDepth );
423  os << FormatValue( "url" , (*it)->m_sURL );
424  os << "</icon>\n";
425  }
426  os << "</iconList>\n";
427  }
428 
429  os << FormatValue( "UDN" , pDevice->GetUDN() );
430 
431  // ----------------------------------------------------------------------
432  // Output any Services
433  // ----------------------------------------------------------------------
434 
435  if (pDevice->m_listServices.count() > 0)
436  {
437  // ------------------------------------------------------------------
438  // -=>TODO: As a temporary fix don't expose the MSRR service unless we
439  // as an XBox360 or Windows MediaPlayer.
440  //
441  // There is a problem with a DSM-520 with firmware 1.04 and
442  // the Denon AVR-4306 receiver.
443  //
444  // If the MSRR Service is exposed, it won't let us browse
445  // any media content.
446  //
447  // Need to find out real fix and remove this code.
448  // ------------------------------------------------------------------
449 
450 #if 0
451  bool bDSM = sUserAgent.startsWith("INTEL_NMPR/2.1 DLNADOC/1.00", false);
452 #endif
453 
454  os << "<serviceList>\n";
455 
456  UPnpServiceList::const_iterator it = pDevice->m_listServices.begin();
457  for (; it != pDevice->m_listServices.end(); ++it)
458  {
459  if (!bIsXbox360 && (*it)->m_sServiceType.startsWith(
460  "urn:microsoft.com:service:X_MS_MediaReceiverRegistrar",
461  Qt::CaseInsensitive))
462  {
463  continue;
464  }
465 
466  os << "<service>\n";
467  os << FormatValue( "serviceType", (*it)->m_sServiceType );
468  os << FormatValue( "serviceId" , (*it)->m_sServiceId );
469  os << FormatValue( "SCPDURL" , (*it)->m_sSCPDURL );
470  os << FormatValue( "controlURL" , (*it)->m_sControlURL );
471  os << FormatValue( "eventSubURL", (*it)->m_sEventSubURL );
472  os << "</service>\n";
473  }
474  os << "</serviceList>\n";
475  }
476 
477  // ----------------------------------------------------------------------
478  // Output any Embedded Devices
479  // ----------------------------------------------------------------------
480 
481  if (pDevice->m_listDevices.count() > 0)
482  {
483  os << "<deviceList>";
484 
485  UPnpDeviceList::iterator it;
486  for ( it = pDevice->m_listDevices.begin();
487  it != pDevice->m_listDevices.end();
488  ++it )
489  {
490  UPnpDevice *pEmbeddedDevice = (*it);
491  OutputDevice( os, pEmbeddedDevice );
492  }
493  os << "</deviceList>";
494  }
495  os << "</device>\n";
496  os << flush;
497 }
498 
500 //
502 
504 {
505  QString sStr;
506 
507  QString sAttributes;
508  NameValues::iterator it;
509  for (it = node.m_pAttributes->begin(); it != node.m_pAttributes->end(); ++it)
510  {
511  sAttributes += QString(" %1='%2'").arg((*it).m_sName).arg((*it).m_sValue);
512  }
513  sStr = QString("<%1%2>%3</%1>\n").arg(node.m_sName).arg(sAttributes).arg(node.m_sValue);
514 
515  return( sStr );
516 }
517 
519 //
521 
522 QString UPnpDeviceDesc::FormatValue( const QString &sName,
523  const QString &sValue )
524 {
525  QString sStr;
526 
527  if (sValue.length() > 0)
528  sStr = QString("<%1>%2</%1>\n") .arg(sName) .arg(sValue);
529 
530  return( sStr );
531 }
532 
534 
535 QString UPnpDeviceDesc::FormatValue( const QString &sName, int nValue )
536 {
537  return( QString("<%1>%2</%1>\n") .arg(sName) .arg(nValue) );
538 }
539 
541 //
543 
544 QString UPnpDeviceDesc::FindDeviceUDN( UPnpDevice *pDevice, QString sST )
545 {
546  // Ignore device version, UPnP is backwards compatible
547  if (sST.section(':', 0, -2) == pDevice->m_sDeviceType.section(':', 0, -2))
548  return pDevice->GetUDN();
549 
550  if (sST.section(':', 0, -2) == pDevice->GetUDN().section(':', 0, -2))
551  return sST;
552 
553  // ----------------------------------------------------------------------
554  // Check for matching Service
555  // ----------------------------------------------------------------------
556 
557  UPnpServiceList::const_iterator sit = pDevice->m_listServices.begin();
558  for (; sit != pDevice->m_listServices.end(); ++sit)
559  {
560  // Ignore the service version, UPnP is backwards compatible
561  if (sST.section(':', 0, -2) == (*sit)->m_sServiceType.section(':', 0, -2))
562  return pDevice->GetUDN();
563  }
564 
565  // ----------------------------------------------------------------------
566  // Check Embedded Devices for a Match
567  // ----------------------------------------------------------------------
568 
569  UPnpDeviceList::const_iterator dit = pDevice->m_listDevices.begin();
570  for (; dit != pDevice->m_listDevices.end(); ++dit)
571  {
572  QString sUDN = FindDeviceUDN( *dit, sST );
573  if (sUDN.length() > 0)
574  return sUDN;
575  }
576 
577  return "";
578 }
579 
581 //
583 
584 UPnpDevice *UPnpDeviceDesc::FindDevice( const QString &sURI )
585 {
586  return FindDevice( &m_rootDevice, sURI );
587 }
588 
590 //
592 
594  const QString &sURI )
595 {
596  // Ignore device version, UPnP is backwards compatible
597  if ( sURI.section(':', 0, -2) == pDevice->m_sDeviceType.section(':', 0, -2) )
598  return pDevice;
599 
600  // ----------------------------------------------------------------------
601  // Check Embedded Devices for a Match
602  // ----------------------------------------------------------------------
603 
604  UPnpDeviceList::iterator dit = pDevice->m_listDevices.begin();
605  for (; dit != pDevice->m_listDevices.end(); ++dit)
606  {
607  UPnpDevice *pFound = FindDevice(*dit, sURI);
608 
609  if (pFound != nullptr)
610  return pFound;
611  }
612 
613  return nullptr;
614 }
615 
617 //
619 
621 {
622  UPnpDeviceDesc *pDevice = nullptr;
623 
624  LOG(VB_UPNP, LOG_DEBUG, QString("UPnpDeviceDesc::Retrieve( %1 )")
625  .arg(sURL));
626 
627  QByteArray buffer;
628 
629  bool ok = GetMythDownloadManager()->download(sURL, &buffer);
630 
631  QString sXml(buffer);
632 
633  if (ok && sXml.startsWith( QString("<?xml") ))
634  {
635  QString sErrorMsg;
636 
637  QDomDocument xml( "upnp" );
638 
639  if ( xml.setContent( sXml, false, &sErrorMsg ))
640  {
641  pDevice = new UPnpDeviceDesc();
642  pDevice->Load( xml );
643  pDevice->m_HostUrl = sURL;
644  pDevice->m_sHostName = pDevice->m_HostUrl.host();
645  }
646  else
647  {
648  LOG(VB_UPNP, LOG_ERR,
649  QString("Error parsing device description xml [%1]")
650  .arg(sErrorMsg));
651  }
652  }
653  else
654  {
655  LOG(VB_UPNP, LOG_ERR, QString("Invalid response '%1'").arg(sXml));
656  }
657 
658  return pDevice;
659 }
660 
662 //
664 
666 {
667  if (m_sHostName.length() == 0)
668  {
669  // Get HostName
670 
671  char localHostName[1024];
672 
673  if (gethostname(localHostName, 1024))
674  LOG(VB_GENERAL, LOG_ERR,
675  "UPnpDeviceDesc: Error, could not determine host name." + ENO);
676 
677  return UPnp::GetConfiguration()->GetValue("Settings/HostName",
678  QString(localHostName));
679  }
680 
681  return m_sHostName;
682 }
683 
686 //
687 // UPnpDevice Class Implementation
688 //
691 
693  m_sModelNumber(MYTH_BINARY_VERSION),
694  m_sSerialNumber(MYTH_SOURCE_VERSION),
695  m_securityPin(false),
696  m_protocolVersion(MYTH_PROTO_VERSION)
697 {
698 
699 // FIXME: UPnPDevice is created via the static initialisation of UPnPDeviceDesc
700 // in upnp.cpp ln 21. This means it's created before the core context is
701 // even intialised so we can't use settings, or any 'core' methods to
702 // help in populating the Device metadata. That is why the URLs below
703 // are relative, not absolute since at this stage we can't determine
704 // which IP or port to use!
705 
706 // NOTE: The icons are defined here and not in devicemaster.xml because they
707 // are also used for the MediaRenderer device and other possible future
708 // devices too.
709 
710  // Large PNG Icon
711  UPnpIcon *pngIconLrg = new UPnpIcon();
712  pngIconLrg->m_nDepth = 24;
713  pngIconLrg->m_nHeight = 120;
714  pngIconLrg->m_nWidth = 120;
715  pngIconLrg->m_sMimeType = "image/png";
716  pngIconLrg->m_sURL = "/images/icons/upnp_large_icon.png";
717  m_listIcons.append(pngIconLrg);
718 
719  // Large JPG Icon
720  UPnpIcon *jpgIconLrg = new UPnpIcon();
721  jpgIconLrg->m_nDepth = 24;
722  jpgIconLrg->m_nHeight = 120;
723  jpgIconLrg->m_nWidth = 120;
724  jpgIconLrg->m_sMimeType = "image/jpeg";
725  jpgIconLrg->m_sURL = "/images/icons/upnp_large_icon.jpg";
726  m_listIcons.append(jpgIconLrg);
727 
728  // Small PNG Icon
729  UPnpIcon *pngIconSm = new UPnpIcon();
730  pngIconSm->m_nDepth = 24;
731  pngIconSm->m_nHeight = 48;
732  pngIconSm->m_nWidth = 48;
733  pngIconSm->m_sMimeType = "image/png";
734  pngIconSm->m_sURL = "/images/icons/upnp_small_icon.png";
735  m_listIcons.append(pngIconSm);
736 
737  // Small JPG Icon
738  UPnpIcon *jpgIconSm = new UPnpIcon();
739  jpgIconSm->m_nDepth = 24;
740  jpgIconSm->m_nHeight = 48;
741  jpgIconSm->m_nWidth = 48;
742  jpgIconSm->m_sMimeType = "image/jpeg";
743  jpgIconSm->m_sURL = "/images/icons/upnp_small_icon.jpg";
744  m_listIcons.append(jpgIconSm);
745 }
746 
748 {
749  while (!m_listIcons.empty())
750  {
751  delete m_listIcons.back();
752  m_listIcons.pop_back();
753  }
754  while (!m_listServices.empty())
755  {
756  delete m_listServices.back();
757  m_listServices.pop_back();
758  }
759  while (!m_listDevices.empty())
760  {
761  delete m_listDevices.back();
762  m_listDevices.pop_back();
763  }
764 }
765 
766 QString UPnpDevice::GetUDN(void) const
767 {
768  if (m_sUDN.isEmpty())
769  m_sUDN = "uuid:" + LookupUDN( m_sDeviceType );
770 
771  return m_sUDN;
772 }
773 
775 {
776  map["name"] = m_sFriendlyName;
777  map["modelname"] = m_sModelName;
778  map["modelnumber"] = m_sModelNumber;
779  map["modelurl"] = m_sModelURL;
780  map["modeldescription"] = m_sModelDescription;
781  map["manufacturer"] = m_sManufacturer;
782  map["manufacturerurl"] = m_sManufacturerURL;
783  map["devicetype"] = m_sDeviceType;
784  map["serialnumber"] = m_sSerialNumber;
785  map["UDN"] = m_sUDN;
786  map["UPC"] = m_sUPC;
787  map["protocolversion"] = m_protocolVersion;
788 }
789 
790 UPnpService UPnpDevice::GetService(const QString &urn, bool *found) const
791 {
792  UPnpService srv;
793 
794  bool done = false;
795 
796  UPnpServiceList::const_iterator it = m_listServices.begin();
797  for (; it != m_listServices.end(); ++it)
798  {
799  // Ignore the service version
800  if ((*it)->m_sServiceType.section(':', 0, -2) == urn.section(':', 0, -2))
801  {
802  srv = **it;
803  done = true;
804  break;
805  }
806  }
807 
808  if (!done)
809  {
810  UPnpDeviceList::const_iterator dit = m_listDevices.begin();
811  for (; dit != m_listDevices.end() && !done; ++dit)
812  srv = (*dit)->GetService(urn, &done);
813  }
814 
815  if (found)
816  *found = done;
817 
818  return srv;
819 }
820 
821 QString UPnpDevice::toString(uint padding) const
822 {
823  QString ret =
824  QString("UPnP Device\n"
825  "===========\n"
826  "deviceType: %1\n"
827  "friendlyName: %2\n"
828  "manufacturer: %3\n"
829  "manufacturerURL: %4\n"
830  "modelDescription: %5\n"
831  "modelName: %6\n"
832  "modelNumber: %7\n"
833  "modelURL: %8\n")
834  .arg(m_sDeviceType )
835  .arg(m_sFriendlyName )
836  .arg(m_sManufacturer )
837  .arg(m_sManufacturerURL )
838  .arg(m_sModelDescription)
839  .arg(m_sModelName )
840  .arg(m_sModelNumber )
841  .arg(m_sModelURL ) +
842  QString("serialNumber: %1\n"
843  "UPC: %2\n"
844  "presentationURL: %3\n"
845  "UDN: %4\n")
846  .arg(m_sSerialNumber )
847  .arg(m_sUPC )
848  .arg(m_sPresentationURL )
849  .arg(m_sUDN );
850 
851  if (!m_lstExtra.empty())
852  {
853  NameValues::const_iterator it = m_lstExtra.begin();
854  ret += "Extra key value pairs\n";
855  for (; it != m_lstExtra.end(); ++it)
856  {
857  ret += (*it).m_sName;
858  ret += ":";
859  int int_padding = 18 - ((*it).m_sName.length() + 1);
860  for (int i = 0; i < int_padding; i++)
861  ret += " ";
862  ret += QString("%1\n").arg((*it).m_sValue);
863  }
864  }
865 
866  if (!m_listIcons.empty())
867  {
868  ret += "Icon List:\n";
869  UPnpIconList::const_iterator it = m_listIcons.begin();
870  for (; it != m_listIcons.end(); ++it)
871  ret += (*it)->toString(padding+2) + "\n";
872  }
873 
874  if (!m_listServices.empty())
875  {
876  ret += "Service List:\n";
877  UPnpServiceList::const_iterator it = m_listServices.begin();
878  for (; it != m_listServices.end(); ++it)
879  ret += (*it)->toString(padding+2) + "\n";
880  }
881 
882  if (!m_listDevices.empty())
883  {
884  ret += "Device List:\n";
885  UPnpDeviceList::const_iterator it = m_listDevices.begin();
886  for (; it != m_listDevices.end(); ++it)
887  ret += (*it)->toString(padding+2) + "\n";
888  ret += "\n";
889  }
890 
891  // remove trailing newline
892  if (ret.endsWith("\n"))
893  ret = ret.left(ret.length()-1);
894 
895  // add any padding as necessary
896  if (padding)
897  {
898  QString pad;
899  for (uint i = 0; i < padding; i++)
900  pad += " ";
901  ret = pad + ret.replace("\n", QString("\n%1").arg(pad));
902  }
903 
904  return ret;
905 }
UPnpDevice * FindDevice(const QString &sURI)
Definition: upnpdevice.cpp:584
QString LookupUDN(const QString &sDeviceType)
Definition: upnputil.cpp:45
void OutputDevice(QTextStream &os, UPnpDevice *pDevice, const QString &sUserAgent="")
Definition: upnpdevice.cpp:341
virtual int GetValue(const QString &sSetting, int Default)=0
NameValues * m_pAttributes
Definition: upnputil.h:54
UPnpDeviceDesc()=default
int m_nWidth
Definition: upnpdevice.h:49
static UPnpDeviceDesc * Retrieve(QString &sURL)
Definition: upnpdevice.cpp:620
void ProcessServiceList(const QDomNode &oListNode, UPnpDevice *pDevice)
Definition: upnpdevice.cpp:203
int m_nHeight
Definition: upnpdevice.h:50
void toMap(InfoMap &map)
Definition: upnpdevice.cpp:774
QString m_sURL
Definition: upnpdevice.h:47
unsigned int uint
Definition: compat.h:140
QString m_sModelURL
Definition: upnpdevice.h:106
UPnpServiceList m_listServices
Definition: upnpdevice.h:119
QString m_sEventSubURL
Definition: upnpdevice.h:75
QString m_sMimeType
Definition: upnpdevice.h:48
QString GetUDN(void) const
Definition: upnpdevice.cpp:766
void _InternalLoad(QDomNode oNode, UPnpDevice *pCurDevice)
Definition: upnpdevice.cpp:103
QString m_sManufacturerURL
Definition: upnpdevice.h:102
QString GetHostName()
Definition: upnpdevice.cpp:665
VERBOSE_PREAMBLE false
Definition: verbosedefs.h:85
QString m_sHostName
Definition: upnpdevice.h:149
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
QString FindDeviceUDN(UPnpDevice *pDevice, QString sST)
Definition: upnpdevice.cpp:544
UPnpDevice m_rootDevice
Definition: upnpdevice.h:148
void SetBoolValue(const QDomNode &n, bool &nValue)
Definition: upnpdevice.cpp:284
MythDownloadManager * GetMythDownloadManager(void)
Gets the pointer to the MythDownloadManager singleton.
QString toString(uint padding=0) const
Definition: upnpdevice.cpp:821
bool download(const QString &url, const QString &dest, const bool reload=false)
Downloads a URL to a file in blocking mode.
#define MYTH_PROTO_VERSION
Increment this whenever the MythTV network protocol changes.
Definition: mythversion.h:48
QString m_sPresentationURL
Definition: upnpdevice.h:109
QString m_sServiceType
Definition: upnpdevice.h:71
QString m_sUDN
Definition: upnpdevice.h:110
QString m_sName
Definition: upnputil.h:50
static Configuration * GetConfiguration()
Definition: upnp.cpp:71
QString m_sModelNumber
Definition: upnpdevice.h:105
#define ENO
This can be appended to the LOG args with "+".
Definition: mythlogging.h:99
QString m_sUPC
Definition: upnpdevice.h:108
void SetNumValue(const QDomNode &n, int &nValue)
Sets nValue param to n.firstChild().toText().nodeValue(), iff neither n.isNull() nor n....
Definition: upnpdevice.cpp:273
QString FormatValue(const NameValue &node)
Definition: upnpdevice.cpp:503
NameValues m_lstExtra
Definition: upnpdevice.h:112
QString m_sModelDescription
Definition: upnpdevice.h:103
QString GetSetting(const QString &_key, const QString &defaultval)
Definition: mythdb.cpp:362
UPnpDeviceList m_listDevices
Definition: upnpdevice.h:120
static int g_nAllocated
Definition: upnpdevice.h:207
QString m_sDeviceType
Definition: upnpdevice.h:99
void ProcessDeviceList(const QDomNode &oListNode, UPnpDevice *pDevice)
Definition: upnpdevice.cpp:237
QString m_sModelName
Definition: upnpdevice.h:104
bool m_securityPin
MythTV specific information.
Definition: upnpdevice.h:115
QString m_sManufacturer
Definition: upnpdevice.h:101
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
QString m_sValue
Definition: upnputil.h:51
void SetStrValue(const QDomNode &n, QString &sValue)
Sets sValue param to n.firstChild().toText().nodeValue(), iff neither n.isNull() nor n....
Definition: upnpdevice.cpp:260
QString m_sControlURL
Definition: upnpdevice.h:74
UPnpIconList m_listIcons
Definition: upnpdevice.h:118
#define MYTH_BINARY_VERSION
Update this whenever the plug-in ABI changes.
Definition: mythversion.h:16
QString m_sFriendlyName
Definition: upnpdevice.h:100
QString m_sServiceId
Definition: upnpdevice.h:72
int m_nDepth
Definition: upnpdevice.h:51
bool Load(const QString &sFileName)
Definition: upnpdevice.cpp:43
MythDB * GetMythDB(void)
Definition: mythdb.cpp:46
QString m_sSCPDURL
Definition: upnpdevice.h:73
void AddAttribute(const QString &name, const QString &value, bool required)
Definition: upnputil.h:127
UPnpService GetService(const QString &urn, bool *found=nullptr) const
Definition: upnpdevice.cpp:790
QString m_sSerialNumber
Definition: upnpdevice.h:107
void GetValidXML(const QString &sBaseAddress, int nPort, QTextStream &os, const QString &sUserAgent="")
Definition: upnpdevice.cpp:316
QString m_protocolVersion
Definition: upnpdevice.h:116
void ProcessIconList(const QDomNode &oListNode, UPnpDevice *pDevice)
Definition: upnpdevice.cpp:174