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 #include <QHostInfo>
29 
30 #if QT_VERSION < QT_VERSION_CHECK(5,14,0)
31  #define QT_FLUSH flush
32 #else
33  #define QT_FLUSH Qt::flush
34 #endif
35 
36 int DeviceLocation::g_nAllocated = 0; // Debugging only
37 
40 //
41 // UPnpDeviceDesc Class Implementation
42 //
45 
47 //
49 
50 bool UPnpDeviceDesc::Load( const QString &sFileName )
51 {
52  // ----------------------------------------------------------------------
53  // Open Supplied XML uPnp Description file.
54  // ----------------------------------------------------------------------
55 
56  QDomDocument doc ( "upnp" );
57  QFile file( sFileName );
58 
59  if ( !file.open( QIODevice::ReadOnly ) )
60  return false;
61 
62  QString sErrMsg;
63  int nErrLine = 0;
64  int nErrCol = 0;
65  bool bSuccess = doc.setContent( &file, false,
66  &sErrMsg, &nErrLine, &nErrCol );
67 
68  file.close();
69 
70  if (!bSuccess)
71  {
72  LOG(VB_GENERAL, LOG_ERR,
73  QString("UPnpDeviceDesc::Load - Error parsing: %1 "
74  "at line: %2 column: %3")
75  .arg(sFileName) .arg(nErrLine)
76  .arg(nErrCol));
77  LOG(VB_GENERAL, LOG_ERR,
78  QString("UPnpDeviceDesc::Load - Error Msg: %1" ) .arg(sErrMsg));
79  return false;
80  }
81 
82  // --------------------------------------------------------------
83  // XML Document Loaded... now parse it into the UPnpDevice Hierarchy
84  // --------------------------------------------------------------
85 
86  return Load( doc );
87 }
88 
90 //
92 
93 bool UPnpDeviceDesc::Load( const QDomDocument &xmlDevDesc )
94 {
95  // --------------------------------------------------------------
96  // Parse XML into the UPnpDevice Hierarchy
97  // --------------------------------------------------------------
98 
99  QDomNode oNode = xmlDevDesc.documentElement();
100 
101  InternalLoad( oNode.namedItem( "device" ), &m_rootDevice );
102 
103  return true;
104 }
105 
107 //
109 
110 void UPnpDeviceDesc::InternalLoad( QDomNode oNode, UPnpDevice *pCurDevice )
111 {
112  QString pin = GetMythDB()->GetSetting( "SecurityPin", "");
113  pCurDevice->m_securityPin = !(pin.isEmpty() || pin == "0000");
114 
115  for ( oNode = oNode.firstChild();
116  !oNode.isNull();
117  oNode = oNode.nextSibling() )
118  {
119  QDomElement e = oNode.toElement();
120 
121  if (e.isNull())
122  continue;
123 
124  // TODO: make this table driven (using offset within structure)
125  if ( e.tagName() == "deviceType" )
126  SetStrValue( e, pCurDevice->m_sDeviceType);
127  else if ( e.tagName() == "friendlyName" )
128  SetStrValue( e, pCurDevice->m_sFriendlyName );
129  else if ( e.tagName() == "manufacturer" )
130  SetStrValue( e, pCurDevice->m_sManufacturer );
131  else if ( e.tagName() == "manufacturerURL" )
132  SetStrValue( e, pCurDevice->m_sManufacturerURL );
133  else if ( e.tagName() == "modelDescription" )
134  SetStrValue( e, pCurDevice->m_sModelDescription);
135  else if ( e.tagName() == "modelName" )
136  SetStrValue( e, pCurDevice->m_sModelName );
137  else if ( e.tagName() == "modelNumber" )
138  SetStrValue( e, pCurDevice->m_sModelNumber );
139  else if ( e.tagName() == "modelURL" )
140  SetStrValue( e, pCurDevice->m_sModelURL );
141  else if ( e.tagName() == "serialNumber" )
142  SetStrValue( e, pCurDevice->m_sSerialNumber );
143  else if ( e.tagName() == "UPC" )
144  SetStrValue( e, pCurDevice->m_sUPC );
145  else if ( e.tagName() == "presentationURL" )
146  SetStrValue( e, pCurDevice->m_sPresentationURL );
147  else if ( e.tagName() == "UDN" )
148  SetStrValue( e, pCurDevice->m_sUDN );
149  else if ( e.tagName() == "iconList" )
150  ProcessIconList( oNode, pCurDevice );
151  else if ( e.tagName() == "serviceList" )
152  ProcessServiceList( oNode, pCurDevice );
153  else if ( e.tagName() == "deviceList" )
154  ProcessDeviceList ( oNode, pCurDevice );
155  else if ( e.tagName() == "mythtv:X_secure" )
156  SetBoolValue( e, pCurDevice->m_securityPin );
157  else if ( e.tagName() == "mythtv:X_protocol" )
158  SetStrValue( e, pCurDevice->m_protocolVersion );
159  else
160  {
161  // Not one of the expected element names... add to extra list.
162  QString sValue = "";
163  SetStrValue( e, sValue );
164  NameValue node = NameValue(e.tagName(), sValue);
165  QDomNamedNodeMap attributes = e.attributes();
166  for (int i = 0; i < attributes.size(); i++)
167  {
168  node.AddAttribute(attributes.item(i).nodeName(),
169  attributes.item(i).nodeValue(),
170  true); // TODO Check whether all attributes are in fact requires for the device xml
171  }
172  pCurDevice->m_lstExtra.push_back(node);
173  }
174  }
175 }
176 
178 //
180 
181 void UPnpDeviceDesc::ProcessIconList( const QDomNode& oListNode, UPnpDevice *pDevice )
182 {
183  for ( QDomNode oNode = oListNode.firstChild();
184  !oNode.isNull();
185  oNode = oNode.nextSibling() )
186  {
187  QDomElement e = oNode.toElement();
188 
189  if (e.isNull())
190  continue;
191 
192  if ( e.tagName() == "icon" )
193  {
194  auto *pIcon = new UPnpIcon();
195  pDevice->m_listIcons.append( pIcon );
196 
197  SetStrValue( e.namedItem( "mimetype" ), pIcon->m_sMimeType );
198  SetNumValue( e.namedItem( "width" ), pIcon->m_nWidth );
199  SetNumValue( e.namedItem( "height" ), pIcon->m_nHeight );
200  SetNumValue( e.namedItem( "depth" ), pIcon->m_nDepth );
201  SetStrValue( e.namedItem( "url" ), pIcon->m_sURL );
202  }
203  }
204 }
205 
207 //
209 
210 void UPnpDeviceDesc::ProcessServiceList( const QDomNode& oListNode, UPnpDevice *pDevice )
211 {
212  for ( QDomNode oNode = oListNode.firstChild();
213  !oNode.isNull();
214  oNode = oNode.nextSibling() )
215  {
216  QDomElement e = oNode.toElement();
217 
218  if (e.isNull())
219  continue;
220 
221  if ( e.tagName() == "service" )
222  {
223  auto *pService = new UPnpService();
224  pDevice->m_listServices.append( pService );
225 
226  SetStrValue(e.namedItem( "serviceType" ), pService->m_sServiceType);
227  SetStrValue(e.namedItem( "serviceId" ), pService->m_sServiceId);
228  SetStrValue(e.namedItem( "SCPDURL" ), pService->m_sSCPDURL);
229  SetStrValue(e.namedItem( "controlURL" ), pService->m_sControlURL);
230  SetStrValue(e.namedItem( "eventSubURL" ), pService->m_sEventSubURL);
231 
232  LOG(VB_UPNP, LOG_INFO,
233  QString("ProcessServiceList adding service : %1 : %2 :")
234  .arg(pService->m_sServiceType)
235  .arg(pService->m_sServiceId));
236  }
237  }
238 }
239 
241 //
243 
244 void UPnpDeviceDesc::ProcessDeviceList( const QDomNode& oListNode,
245  UPnpDevice *pDevice )
246 {
247  for ( QDomNode oNode = oListNode.firstChild();
248  !oNode.isNull();
249  oNode = oNode.nextSibling() )
250  {
251  QDomElement e = oNode.toElement();
252 
253  if (e.isNull())
254  continue;
255 
256  if ( e.tagName() == "device")
257  {
258  auto *pNewDevice = new UPnpDevice();
259  pDevice->m_listDevices.append( pNewDevice );
260  InternalLoad( e, pNewDevice );
261  }
262  }
263 }
264 
267 void UPnpDeviceDesc::SetStrValue( const QDomNode &n, QString &sValue )
268 {
269  if (!n.isNull())
270  {
271  QDomText oText = n.firstChild().toText();
272 
273  if (!oText.isNull())
274  sValue = oText.nodeValue();
275  }
276 }
277 
280 void UPnpDeviceDesc::SetNumValue( const QDomNode &n, int &nValue )
281 {
282  if (!n.isNull())
283  {
284  QDomText oText = n.firstChild().toText();
285 
286  if (!oText.isNull())
287  nValue = oText.nodeValue().toInt();
288  }
289 }
290 
291 void UPnpDeviceDesc::SetBoolValue( const QDomNode &n, bool &nValue )
292 {
293  if (!n.isNull())
294  {
295  QDomText oText = n.firstChild().toText();
296 
297  if (!oText.isNull())
298  {
299  QString s = oText.nodeValue();
300  nValue = (s == "yes" || s == "true" || (s.toInt() != 0));
301  }
302  }
303 }
304 
306 //
308 
309 QString UPnpDeviceDesc::GetValidXML( const QString &sBaseAddress, int nPort )
310 {
311  QString sXML;
312  QTextStream os( &sXML, QIODevice::WriteOnly );
313 
314  GetValidXML( sBaseAddress, nPort, os );
315  os << QT_FLUSH;
316  return( sXML );
317 }
318 
320 //
322 
324  const QString &/*sBaseAddress*/, int /*nPort*/,
325  QTextStream &os, const QString &sUserAgent )
326 {
327 #if 0
328  os.setEncoding( QTextStream::UnicodeUTF8 );
329 #endif
330  os << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
331  "<root xmlns=\"urn:schemas-upnp-org:device-1-0\" "
332  " xmlns:mythtv=\"mythtv.org\">\n"
333  "<specVersion>\n"
334  "<major>1</major>\n"
335  "<minor>0</minor>\n"
336  "</specVersion>\n";
337 
338  OutputDevice( os, &m_rootDevice, sUserAgent );
339 
340  os << "</root>\n";
341  os << QT_FLUSH;
342 }
343 
345 //
347 
348 void UPnpDeviceDesc::OutputDevice( QTextStream &os,
349  UPnpDevice *pDevice,
350  const QString &sUserAgent )
351 {
352  if (pDevice == nullptr)
353  return;
354 
355  QString sFriendlyName = QString( "%1: %2" )
356  .arg( GetHostName() )
357  .arg( pDevice->m_sFriendlyName );
358 
359  // ----------------------------------------------------------------------
360  // Only override the root device
361  // ----------------------------------------------------------------------
362 
363  if (pDevice == &m_rootDevice)
364  sFriendlyName = UPnp::GetConfiguration()->GetValue( "UPnP/FriendlyName",
365  sFriendlyName );
366 
367  os << "<device>\n";
368  os << FormatValue( "deviceType" , pDevice->m_sDeviceType );
369  os << FormatValue( "friendlyName" , sFriendlyName );
370 
371  // ----------------------------------------------------------------------
372  // XBox 360 needs specific values in the Device Description.
373  //
374  // -=>TODO: This should be externalized in a more generic/extension
375  // kind of way.
376  // ----------------------------------------------------------------------
377 
378  bool bIsXbox360 =
379  sUserAgent.startsWith(QString("Xbox/2.0"), Qt::CaseInsensitive) ||
380  sUserAgent.startsWith(QString("Mozilla/4.0"), Qt::CaseInsensitive);
381 
382  os << FormatValue( "manufacturer" , pDevice->m_sManufacturer );
383  os << FormatValue( "modelURL" , pDevice->m_sModelURL );
384 
385  // HACK
386 // if ( bIsXbox360 )
387 // {
388 // os << FormatValue( "modelName" ,
389 // "Windows Media Connect Compatible (MythTV)");
390 // }
391 // else
392 // {
393  os << FormatValue( "modelName" , pDevice->m_sModelName );
394 // }
395 
396  os << FormatValue( "manufacturerURL" , pDevice->m_sManufacturerURL );
397  os << FormatValue( "modelDescription" , pDevice->m_sModelDescription);
398  os << FormatValue( "modelNumber" , pDevice->m_sModelNumber );
399  os << FormatValue( "serialNumber" , pDevice->m_sSerialNumber );
400  os << FormatValue( "UPC" , pDevice->m_sUPC );
401  os << FormatValue( "presentationURL" , pDevice->m_sPresentationURL );
402 
403  // MythTV Custom information
404  os << FormatValue( "mythtv:X_secure" ,
405  pDevice->m_securityPin ? "true" : "false");
406  os << FormatValue( "mythtv:X_protocol", pDevice->m_protocolVersion );
407 
408  for (const auto & nit : qAsConst(pDevice->m_lstExtra))
409  {
410  os << FormatValue( nit );
411  }
412 
413  // ----------------------------------------------------------------------
414  // Output Any Icons.
415  // ----------------------------------------------------------------------
416 
417  if (pDevice->m_listIcons.count() > 0)
418  {
419  os << "<iconList>\n";
420 
421  for (auto *icon : qAsConst(pDevice->m_listIcons))
422  {
423  os << "<icon>\n";
424  os << FormatValue( "mimetype", icon->m_sMimeType );
425  os << FormatValue( "width" , icon->m_nWidth );
426  os << FormatValue( "height" , icon->m_nHeight );
427  os << FormatValue( "depth" , icon->m_nDepth );
428  os << FormatValue( "url" , icon->m_sURL );
429  os << "</icon>\n";
430  }
431  os << "</iconList>\n";
432  }
433 
434  os << FormatValue( "UDN" , pDevice->GetUDN() );
435 
436  // ----------------------------------------------------------------------
437  // Output any Services
438  // ----------------------------------------------------------------------
439 
440  if (pDevice->m_listServices.count() > 0)
441  {
442  // ------------------------------------------------------------------
443  // -=>TODO: As a temporary fix don't expose the MSRR service unless we
444  // as an XBox360 or Windows MediaPlayer.
445  //
446  // There is a problem with a DSM-520 with firmware 1.04 and
447  // the Denon AVR-4306 receiver.
448  //
449  // If the MSRR Service is exposed, it won't let us browse
450  // any media content.
451  //
452  // Need to find out real fix and remove this code.
453  // ------------------------------------------------------------------
454 
455 #if 0
456  bool bDSM = sUserAgent.startsWith("INTEL_NMPR/2.1 DLNADOC/1.00", false);
457 #endif
458 
459  os << "<serviceList>\n";
460 
461  for (auto *service : qAsConst(pDevice->m_listServices))
462  {
463  if (!bIsXbox360 && service->m_sServiceType.startsWith(
464  "urn:microsoft.com:service:X_MS_MediaReceiverRegistrar",
465  Qt::CaseInsensitive))
466  {
467  continue;
468  }
469 
470  os << "<service>\n";
471  os << FormatValue( "serviceType", service->m_sServiceType );
472  os << FormatValue( "serviceId" , service->m_sServiceId );
473  os << FormatValue( "SCPDURL" , service->m_sSCPDURL );
474  os << FormatValue( "controlURL" , service->m_sControlURL );
475  os << FormatValue( "eventSubURL", service->m_sEventSubURL );
476  os << "</service>\n";
477  }
478  os << "</serviceList>\n";
479  }
480 
481  // ----------------------------------------------------------------------
482  // Output any Embedded Devices
483  // ----------------------------------------------------------------------
484 
485  if (pDevice->m_listDevices.count() > 0)
486  {
487  os << "<deviceList>";
488 
489  UPnpDeviceList::iterator it;
490  for ( it = pDevice->m_listDevices.begin();
491  it != pDevice->m_listDevices.end();
492  ++it )
493  {
494  UPnpDevice *pEmbeddedDevice = (*it);
495  OutputDevice( os, pEmbeddedDevice );
496  }
497  os << "</deviceList>";
498  }
499  os << "</device>\n";
500  os << QT_FLUSH;
501 }
502 
504 //
506 
508 {
509  QString sStr;
510 
511  QString sAttributes;
512  NameValues::iterator it;
513  for (it = node.m_pAttributes->begin(); it != node.m_pAttributes->end(); ++it)
514  {
515  sAttributes += QString(" %1='%2'").arg((*it).m_sName).arg((*it).m_sValue);
516  }
517  sStr = QString("<%1%2>%3</%1>\n").arg(node.m_sName).arg(sAttributes).arg(node.m_sValue);
518 
519  return( sStr );
520 }
521 
523 //
525 
526 QString UPnpDeviceDesc::FormatValue( const QString &sName,
527  const QString &sValue )
528 {
529  QString sStr;
530 
531  if (sValue.length() > 0)
532  sStr = QString("<%1>%2</%1>\n") .arg(sName) .arg(sValue);
533 
534  return( sStr );
535 }
536 
538 
539 QString UPnpDeviceDesc::FormatValue( const QString &sName, int nValue )
540 {
541  return( QString("<%1>%2</%1>\n") .arg(sName) .arg(nValue) );
542 }
543 
545 //
547 
548 QString UPnpDeviceDesc::FindDeviceUDN( UPnpDevice *pDevice, QString sST )
549 {
550  // Ignore device version, UPnP is backwards compatible
551  if (sST.section(':', 0, -2) == pDevice->m_sDeviceType.section(':', 0, -2))
552  return pDevice->GetUDN();
553 
554  if (sST.section(':', 0, -2) == pDevice->GetUDN().section(':', 0, -2))
555  return sST;
556 
557  // ----------------------------------------------------------------------
558  // Check for matching Service
559  // ----------------------------------------------------------------------
560 
561  for (auto sit = pDevice->m_listServices.cbegin();
562  sit != pDevice->m_listServices.cend(); ++sit)
563  {
564  // Ignore the service version, UPnP is backwards compatible
565  if (sST.section(':', 0, -2) == (*sit)->m_sServiceType.section(':', 0, -2))
566  return pDevice->GetUDN();
567  }
568 
569  // ----------------------------------------------------------------------
570  // Check Embedded Devices for a Match
571  // ----------------------------------------------------------------------
572 
573  for (auto *device : qAsConst(pDevice->m_listDevices))
574  {
575  QString sUDN = FindDeviceUDN( device, sST );
576  if (sUDN.length() > 0)
577  return sUDN;
578  }
579 
580  return "";
581 }
582 
584 //
586 
587 UPnpDevice *UPnpDeviceDesc::FindDevice( const QString &sURI )
588 {
589  return FindDevice( &m_rootDevice, sURI );
590 }
591 
593 //
595 
597  const QString &sURI )
598 {
599  // Ignore device version, UPnP is backwards compatible
600  if ( sURI.section(':', 0, -2) == pDevice->m_sDeviceType.section(':', 0, -2) )
601  return pDevice;
602 
603  // ----------------------------------------------------------------------
604  // Check Embedded Devices for a Match
605  // ----------------------------------------------------------------------
606 
607  for (const auto & dev : qAsConst(pDevice->m_listDevices))
608  {
609  UPnpDevice *pFound = FindDevice(dev, sURI);
610 
611  if (pFound != nullptr)
612  return pFound;
613  }
614 
615  return nullptr;
616 }
617 
619 //
621 
623 {
624  UPnpDeviceDesc *pDevice = nullptr;
625 
626  LOG(VB_UPNP, LOG_DEBUG, QString("UPnpDeviceDesc::Retrieve( %1 )")
627  .arg(sURL));
628 
629  QByteArray buffer;
630 
631  bool ok = GetMythDownloadManager()->download(sURL, &buffer);
632 
633  QString sXml(buffer);
634 
635  if (ok && sXml.startsWith( QString("<?xml") ))
636  {
637  QString sErrorMsg;
638 
639  QDomDocument xml( "upnp" );
640 
641  if ( xml.setContent( sXml, false, &sErrorMsg ))
642  {
643  pDevice = new UPnpDeviceDesc();
644  pDevice->Load( xml );
645  pDevice->m_hostUrl = sURL;
646  pDevice->m_sHostName = pDevice->m_hostUrl.host();
647  }
648  else
649  {
650  LOG(VB_UPNP, LOG_ERR,
651  QString("Error parsing device description xml [%1]")
652  .arg(sErrorMsg));
653  }
654  }
655  else
656  {
657  LOG(VB_UPNP, LOG_ERR, QString("Invalid response '%1'").arg(sXml));
658  }
659 
660  return pDevice;
661 }
662 
664 //
666 
668 {
669  if (m_sHostName.length() == 0)
670  {
671  // Get HostName
672 
673  QString localHostName = QHostInfo::localHostName();
674  if (localHostName.isEmpty())
675  LOG(VB_GENERAL, LOG_ERR,
676  "UPnpDeviceDesc: Error, could not determine host name." + ENO);
677 
678  return UPnp::GetConfiguration()->GetValue("Settings/HostName",
679  localHostName);
680  }
681 
682  return m_sHostName;
683 }
684 
687 //
688 // UPnpDevice Class Implementation
689 //
692 
694  m_sModelNumber(MYTH_BINARY_VERSION),
695  m_sSerialNumber(GetMythSourceVersion()),
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  auto *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  auto *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  auto *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  auto *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 
774 void UPnpDevice::toMap(InfoMap &map) const
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  for (auto *service : qAsConst(m_listServices))
797  {
798  // Ignore the service version
799  if (service->m_sServiceType.section(':', 0, -2) == urn.section(':', 0, -2))
800  {
801  srv = *service;
802  done = true;
803  break;
804  }
805  }
806 
807  if (!done)
808  {
809  UPnpDeviceList::const_iterator dit = m_listDevices.begin();
810  for (; dit != m_listDevices.end() && !done; ++dit)
811  srv = (*dit)->GetService(urn, &done);
812  }
813 
814  if (found)
815  *found = done;
816 
817  return srv;
818 }
819 
820 QString UPnpDevice::toString(uint padding) const
821 {
822  QString ret =
823  QString("UPnP Device\n"
824  "===========\n"
825  "deviceType: %1\n"
826  "friendlyName: %2\n"
827  "manufacturer: %3\n"
828  "manufacturerURL: %4\n"
829  "modelDescription: %5\n"
830  "modelName: %6\n"
831  "modelNumber: %7\n"
832  "modelURL: %8\n")
833  .arg(m_sDeviceType )
834  .arg(m_sFriendlyName )
835  .arg(m_sManufacturer )
836  .arg(m_sManufacturerURL )
837  .arg(m_sModelDescription)
838  .arg(m_sModelName )
839  .arg(m_sModelNumber )
840  .arg(m_sModelURL ) +
841  QString("serialNumber: %1\n"
842  "UPC: %2\n"
843  "presentationURL: %3\n"
844  "UDN: %4\n")
845  .arg(m_sSerialNumber )
846  .arg(m_sUPC )
847  .arg(m_sPresentationURL )
848  .arg(m_sUDN );
849 
850  if (!m_lstExtra.empty())
851  {
852  ret += "Extra key value pairs\n";
853  for (const auto & extra : qAsConst(m_lstExtra))
854  {
855  ret += extra.m_sName;
856  ret += ":";
857  int int_padding = 18 - (extra.m_sName.length() + 1);
858  for (int i = 0; i < int_padding; i++)
859  ret += " ";
860  ret += QString("%1\n").arg(extra.m_sValue);
861  }
862  }
863 
864  if (!m_listIcons.empty())
865  {
866  ret += "Icon List:\n";
867  for (auto *icon : qAsConst(m_listIcons))
868  ret += icon->toString(padding+2) + "\n";
869  }
870 
871  if (!m_listServices.empty())
872  {
873  ret += "Service List:\n";
874  for (auto *service : qAsConst(m_listServices))
875  ret += service->toString(padding+2) + "\n";
876  }
877 
878  if (!m_listDevices.empty())
879  {
880  ret += "Device List:\n";
881  for (auto *device : qAsConst(m_listDevices))
882  ret += device->toString(padding+2) + "\n";
883  ret += "\n";
884  }
885 
886  // remove trailing newline
887  if (ret.endsWith("\n"))
888  ret = ret.left(ret.length()-1);
889 
890  // add any padding as necessary
891  if (padding)
892  {
893  QString pad;
894  for (uint i = 0; i < padding; i++)
895  pad += " ";
896  ret = pad + ret.replace("\n", QString("\n%1").arg(pad));
897  }
898 
899  return ret;
900 }
UPnpDevice::m_sModelURL
QString m_sModelURL
Definition: upnpdevice.h:110
NameValue
Definition: upnputil.h:53
e
QDomElement e
Definition: mythplugins/mytharchive/mytharchivehelper/main.cpp:1420
UPnpDevice::~UPnpDevice
~UPnpDevice()
Definition: upnpdevice.cpp:747
DeviceLocation::g_nAllocated
static int g_nAllocated
Definition: upnpdevice.h:211
UPnpDevice::m_sManufacturer
QString m_sManufacturer
Definition: upnpdevice.h:105
UPnpDevice::m_listIcons
UPnpIconList m_listIcons
Definition: upnpdevice.h:122
ENO
#define ENO
This can be appended to the LOG args with "+".
Definition: mythlogging.h:72
upnpdevice.h
UPnpDeviceDesc::UPnpDeviceDesc
UPnpDeviceDesc()=default
UPnpDeviceDesc::GetValidXML
void GetValidXML(const QString &sBaseAddress, int nPort, QTextStream &os, const QString &sUserAgent="")
Definition: upnpdevice.cpp:323
UPnpDeviceDesc::GetHostName
QString GetHostName() const
Definition: upnpdevice.cpp:667
UPnpDeviceDesc::Retrieve
static UPnpDeviceDesc * Retrieve(QString &sURL)
Definition: upnpdevice.cpp:622
UPnpDeviceDesc::InternalLoad
void InternalLoad(QDomNode oNode, UPnpDevice *pCurDevice)
Definition: upnpdevice.cpp:110
mythdb.h
NameValue::m_sName
QString m_sName
Definition: upnputil.h:55
doc
QDomDocument doc("MYTHARCHIVEITEM")
UPnpDevice::m_listServices
UPnpServiceList m_listServices
Definition: upnpdevice.h:123
UPnpDevice::GetService
UPnpService GetService(const QString &urn, bool *found=nullptr) const
Definition: upnpdevice.cpp:790
UPnpDevice::m_sUPC
QString m_sUPC
Definition: upnpdevice.h:112
UPnpDevice::toString
QString toString(uint padding=0) const
Definition: upnpdevice.cpp:820
UPnpDeviceDesc
Definition: upnpdevice.h:149
arg
arg(title).arg(filename).arg(doDelete))
UPnpDevice::m_sDeviceType
QString m_sDeviceType
Definition: upnpdevice.h:103
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:23
UPnpDeviceDesc::FindDeviceUDN
QString FindDeviceUDN(UPnpDevice *pDevice, QString sST)
Definition: upnpdevice.cpp:548
GetMythDB
MythDB * GetMythDB(void)
Definition: mythdb.cpp:45
build_compdb.file
file
Definition: build_compdb.py:55
UPnpDevice::m_sUDN
QString m_sUDN
Definition: upnpdevice.h:114
mythversion.h
InfoMap
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
UPnpDeviceDesc::ProcessServiceList
static void ProcessServiceList(const QDomNode &oListNode, UPnpDevice *pDevice)
Definition: upnpdevice.cpp:210
LookupUDN
QString LookupUDN(const QString &sDeviceType)
Definition: upnputil.cpp:45
NameValue::AddAttribute
void AddAttribute(const QString &name, const QString &value, bool required)
Definition: upnputil.h:129
UPnpDeviceDesc::m_rootDevice
UPnpDevice m_rootDevice
Definition: upnpdevice.h:152
UPnpDeviceDesc::SetBoolValue
static void SetBoolValue(const QDomNode &n, bool &nValue)
Definition: upnpdevice.cpp:291
upnp.h
UPnpDevice::toMap
void toMap(InfoMap &map) const
Definition: upnpdevice.cpp:774
UPnpDevice::m_sModelName
QString m_sModelName
Definition: upnpdevice.h:108
mythlogging.h
UPnpDevice::m_securityPin
bool m_securityPin
MythTV specific information.
Definition: upnpdevice.h:119
UPnpDeviceDesc::m_sHostName
QString m_sHostName
Definition: upnpdevice.h:153
UPnpDevice::m_sModelNumber
QString m_sModelNumber
Definition: upnpdevice.h:109
UPnpDevice::m_lstExtra
NameValues m_lstExtra
Definition: upnpdevice.h:116
UPnpIcon
Definition: upnpdevice.h:49
UPnpDevice::m_sSerialNumber
QString m_sSerialNumber
Definition: upnpdevice.h:111
UPnpDevice::m_listDevices
UPnpDeviceList m_listDevices
Definition: upnpdevice.h:124
UPnpDeviceDesc::FormatValue
static QString FormatValue(const NameValue &node)
Definition: upnpdevice.cpp:507
MythDownloadManager::download
bool download(const QString &url, const QString &dest, bool reload=false)
Downloads a URL to a file in blocking mode.
Definition: mythdownloadmanager.cpp:430
UPnpDevice
Definition: upnpdevice.h:100
UPnpDevice::m_sFriendlyName
QString m_sFriendlyName
Definition: upnpdevice.h:104
UPnpDeviceDesc::m_hostUrl
QUrl m_hostUrl
Definition: upnpdevice.h:154
uint
unsigned int uint
Definition: compat.h:140
UPnpDevice::UPnpDevice
UPnpDevice()
Definition: upnpdevice.cpp:693
MYTH_BINARY_VERSION
#define MYTH_BINARY_VERSION
Update this whenever the plug-in ABI changes.
Definition: mythversion.h:15
MYTH_PROTO_VERSION
#define MYTH_PROTO_VERSION
Increment this whenever the MythTV network protocol changes.
Definition: mythversion.h:47
UPnpDeviceDesc::ProcessDeviceList
void ProcessDeviceList(const QDomNode &oListNode, UPnpDevice *pDevice)
Definition: upnpdevice.cpp:244
NameValue::m_pAttributes
NameValues * m_pAttributes
Definition: upnputil.h:59
UPnpService
Definition: upnpdevice.h:73
UPnpDeviceDesc::SetNumValue
static void SetNumValue(const QDomNode &n, int &nValue)
Sets nValue param to n.firstChild().toText().nodeValue(), iff neither n.isNull() nor n....
Definition: upnpdevice.cpp:280
mythcorecontext.h
MythDB::GetSetting
QString GetSetting(const QString &_key, const QString &defaultval)
Definition: mythdb.cpp:369
UPnpDeviceDesc::Load
bool Load(const QString &sFileName)
Definition: upnpdevice.cpp:50
QT_FLUSH
#define QT_FLUSH
Definition: upnpdevice.cpp:33
UPnpDevice::m_sModelDescription
QString m_sModelDescription
Definition: upnpdevice.h:107
Configuration::GetValue
virtual int GetValue(const QString &sSetting, int Default)=0
UPnpDevice::m_sManufacturerURL
QString m_sManufacturerURL
Definition: upnpdevice.h:106
UPnpDevice::m_protocolVersion
QString m_protocolVersion
Definition: upnpdevice.h:120
UPnpDeviceDesc::SetStrValue
static void SetStrValue(const QDomNode &n, QString &sValue)
Sets sValue param to n.firstChild().toText().nodeValue(), iff neither n.isNull() nor n....
Definition: upnpdevice.cpp:267
UPnp::GetConfiguration
static Configuration * GetConfiguration()
Definition: upnp.cpp:84
GetMythSourceVersion
const char * GetMythSourceVersion()
Definition: mythcoreutil.cpp:313
UPnpDeviceDesc::FindDevice
UPnpDevice * FindDevice(const QString &sURI)
Definition: upnpdevice.cpp:587
UPnpDevice::GetUDN
QString GetUDN(void) const
Definition: upnpdevice.cpp:766
UPnpDevice::m_sPresentationURL
QString m_sPresentationURL
Definition: upnpdevice.h:113
UPnpDeviceDesc::ProcessIconList
static void ProcessIconList(const QDomNode &oListNode, UPnpDevice *pDevice)
Definition: upnpdevice.cpp:181
mythdownloadmanager.h
NameValue::m_sValue
QString m_sValue
Definition: upnputil.h:56
GetMythDownloadManager
MythDownloadManager * GetMythDownloadManager(void)
Gets the pointer to the MythDownloadManager singleton.
Definition: mythdownloadmanager.cpp:145
UPnpDeviceDesc::OutputDevice
void OutputDevice(QTextStream &os, UPnpDevice *pDevice, const QString &sUserAgent="")
Definition: upnpdevice.cpp:348