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