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