MythTV  master
backendselect.cpp
Go to the documentation of this file.
1 // -*- Mode: c++ -*-
2 
3 #include <QEventLoop>
4 
10 #include "libmythui/mythuibutton.h"
14 
15 #include "backendselect.h"
16 
18  MythScreenStack *parent, DatabaseParams *params,
19  Configuration *pConfig, bool exitOnFinish) :
20  MythScreenType(parent, "BackEnd Selection"),
21  m_dbParams(params), m_pConfig(pConfig), m_exitOnFinish(exitOnFinish)
22 {
23  if (exitOnFinish)
24  {
25  m_loop = new QEventLoop();
26  }
27 }
28 
30 {
32 
33  ItemMap::iterator it;
34  for (it = m_devices.begin(); it != m_devices.end(); ++it)
35  {
36  if (*it)
37  (*it)->DecrRef();
38  }
39 
40  m_devices.clear();
41 
42  if (m_exitOnFinish)
43  {
44  delete m_loop;
45  }
46 }
47 
49  DatabaseParams *dbParams, Configuration *pConfig)
50 {
53  if (!mainStack)
54  return ret;
55 
56  auto *backendSettings =
57  new BackendSelection(mainStack, dbParams, pConfig, true);
58 
59  if (backendSettings->Create())
60  {
61  mainStack->AddScreen(backendSettings, false);
62  backendSettings->m_loop->exec();
63  ret = backendSettings->m_backendDecision;
64  mainStack->PopScreen(backendSettings, false);
65  }
66  else
67  delete backendSettings;
68 
69  return ret;
70 }
71 
73 {
74  if (!LoadWindowFromXML("config-ui.xml", "backendselection", this))
75  return false;
76 
77  m_backendList = dynamic_cast<MythUIButtonList*>(GetChild("backends"));
78  m_saveButton = dynamic_cast<MythUIButton*>(GetChild("save"));
79  m_cancelButton = dynamic_cast<MythUIButton*>(GetChild("cancel"));
80  m_manualButton = dynamic_cast<MythUIButton*>(GetChild("manual"));
81 
83  this, qOverload<MythUIButtonListItem *>(&BackendSelection::Accept));
84 
88  this, qOverload<>(&BackendSelection::Accept));
89 
92 
93  return true;
94 }
95 
97 {
98  if (!item)
99  return;
100 
101  auto *dev = item->GetData().value<DeviceLocation *>();
102  if (!dev)
103  {
104  Cancel();
105  LOG(VB_GENERAL, LOG_ERR,
106  "Could not get device details from UI element?");
107  return;
108  }
109 
110  if (ConnectBackend(dev))
111  {
112  if (m_pConfig)
113  {
114  if (!m_pinCode.isEmpty())
117  m_pConfig->Save();
118  }
120  }
121 }
122 
124 {
126 
127  if (!item)
128  return;
129 
130  Accept(item);
131 }
132 
133 
135 {
136  if (!dev)
137  return;
138 
139  QString usn = dev->m_sUSN;
140 
141  m_mutex.lock();
142 
143  // The devices' USN should be unique. Don't add if it is already there:
144  if (m_devices.find(usn) == m_devices.end())
145  {
146  dev->IncrRef();
147  m_devices.insert(usn, dev);
148 
149  m_mutex.unlock();
150 
151  InfoMap infomap;
152  dev->GetDeviceDetail(infomap);
153 
154  // We only want the version number, not the library version info
155  infomap["version"] = infomap["modelnumber"].section('.', 0, 1);
156 
157  auto *item = new MythUIButtonListItem(m_backendList, infomap["modelname"],
158  QVariant::fromValue(dev));
159  item->SetTextFromMap(infomap);
160 
161  bool protoMatch = (infomap["protocolversion"] == MYTH_PROTO_VERSION);
162 
163  QString status = "good";
164  if (!protoMatch)
165  status = "protocolmismatch";
166 
167  // TODO: Not foolproof but if we can't get device details then it's
168  // probably because we could not connect to port 6544 - firewall?
169  // Maybe we can replace this with a more specific check
170  if (infomap["modelname"].isEmpty())
171  status = "blocked";
172 
173  item->DisplayState(status, "connection");
174 
175  bool needPin = dev->NeedSecurityPin();
176  item->DisplayState(needPin ? "yes" : "no", "securitypin");
177  }
178  else
179  m_mutex.unlock();
180 }
181 
187 {
188  QString message;
189 
190  m_usn = dev->m_sUSN;
191 
192  MythXMLClient client( dev->m_sLocation );
193 
194  UPnPResultCode stat = client.GetConnectionInfo(m_pinCode, m_dbParams, message);
195 
196  QString backendName = dev->GetFriendlyName();
197 
198  if (backendName == "<Unknown>")
199  backendName = dev->m_sLocation;
200 
201  switch (stat)
202  {
203  case UPnPResult_Success:
204  LOG(VB_UPNP, LOG_INFO,
205  QString("ConnectBackend() - success. New hostname: %1")
206  .arg(m_dbParams->m_dbHostName));
207  return true;
208 
210  LOG(VB_GENERAL, LOG_ERR, QString("Need Human: %1").arg(message));
211  ShowOkPopup(message);
212 
213  if (TryDBfromURL("", dev->m_sLocation))
214  return true;
215 
216  break;
217 
219  LOG(VB_GENERAL, LOG_ERR,
220  QString("Access denied for %1. Wrong PIN?")
221  .arg(backendName));
223  break;
224 
225  default:
226  LOG(VB_GENERAL, LOG_ERR,
227  QString("GetConnectionInfo() failed for %1 : %2")
228  .arg(backendName, message));
229  ShowOkPopup(message);
230  }
231 
232  // Back to the list, so the user can choose a different backend:
234  return false;
235 }
236 
238 {
240 }
241 
243 {
244  SSDP::AddListener(this);
246 }
247 
249 {
251  if (pEntries)
252  {
253  EntryMap ourMap;
254  pEntries->GetEntryMap(ourMap);
255  pEntries->DecrRef();
256 
257  for (auto * devLoc : qAsConst(ourMap))
258  {
259  AddItem(devLoc);
260  devLoc->DecrRef();
261  }
262  }
263 }
264 
266 {
268 }
269 
270 void BackendSelection::RemoveItem(const QString& USN_)
271 {
272  m_mutex.lock();
273 
274  ItemMap::iterator it = m_devices.find(USN_);
275 
276  if (it != m_devices.end())
277  {
278  if (*it)
279  (*it)->DecrRef();
280  m_devices.erase(it);
281  }
282 
283  m_mutex.unlock();
284 }
285 
286 bool BackendSelection::TryDBfromURL(const QString &error, const QString& URL)
287 {
288  if (ShowOkPopup(error + tr("Shall I attempt to connect to this"
289  " host with default database parameters?")))
290  {
291  static const QRegularExpression re {"http[s]?://([^:/]+)",
292  QRegularExpression::CaseInsensitiveOption};
293  QRegularExpressionMatch match = re.match(URL);
294  if (match.hasMatch())
295  {
296  m_dbParams->m_dbHostName = match.captured(1);
297  return true;
298  }
299  }
300 
301  return false;
302 }
303 
304 void BackendSelection::customEvent(QEvent *event)
305 {
306  if (event->type() == MythEvent::MythEventMessage)
307  {
308  auto *me = dynamic_cast<MythEvent *>(event);
309  if (me == nullptr)
310  return;
311 
312  const QString& message = me->Message();
313  const QString& URI = me->ExtraData(0);
314  const QString& URN = me->ExtraData(1);
315  const QString& URL = me->ExtraData(2);
316 
317 
318  LOG(VB_UPNP, LOG_DEBUG,
319  QString("BackendSelection::customEvent(%1, %2, %3, %4)")
320  .arg(message, URI, URN, URL));
321 
322  if (message.startsWith("SSDP_ADD") &&
323  URI.startsWith("urn:schemas-mythtv-org:device:MasterMediaServer:"))
324  {
325  DeviceLocation *devLoc = SSDP::Find(URI, URN);
326  if (devLoc)
327  {
328  AddItem(devLoc);
329  devLoc->DecrRef();
330  }
331  }
332  else if (message.startsWith("SSDP_REMOVE"))
333  {
334  //-=>Note: This code will never get executed until
335  // SSDPCache is changed to handle NotifyRemove correctly
336  RemoveItem(URN);
337  }
338  }
339  else if (event->type() == DialogCompletionEvent::kEventType)
340  {
341  auto *dce = dynamic_cast<DialogCompletionEvent*>(event);
342  if (!dce)
343  return;
344 
345  QString resultid = dce->GetId();
346 
347  if (resultid == "password")
348  {
349  m_pinCode = dce->GetResultText();
350  Accept();
351  }
352  }
353 }
354 
356 {
357  QString message = tr("Please enter the backend access PIN");
358 
359  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
360 
361  auto *pwDialog = new MythTextInputDialog(popupStack, message,
362  FilterNone, true);
363 
364  if (pwDialog->Create())
365  {
366  pwDialog->SetReturnEvent(this, "password");
367  popupStack->AddScreen(pwDialog);
368  }
369  else
370  delete pwDialog;
371 }
372 
374 {
376 }
377 
379 {
381 
382  if (m_exitOnFinish)
383  m_loop->quit();
384  else
386 }
MythUIButton::Clicked
void Clicked()
BackendSelection::m_dbParams
DatabaseParams * m_dbParams
Definition: backendselect.h:74
MythScreenType::LoadInBackground
void LoadInBackground(const QString &message="")
Definition: mythscreentype.cpp:286
MythMainWindow::GetMainStack
MythScreenStack * GetMainStack()
Definition: mythmainwindow.cpp:315
BackendSelection::Cancel
void Cancel(void)
Linked to 'Cancel' button.
Definition: backendselect.cpp:237
BackendSelection::Close
void Close(void) override
Definition: backendselect.cpp:373
MythEvent::MythEventMessage
static Type MythEventMessage
Definition: mythevent.h:79
MythUIButtonList::GetItemCurrent
MythUIButtonListItem * GetItemCurrent() const
Definition: mythuibuttonlist.cpp:1587
DatabaseParams::m_dbHostName
QString m_dbHostName
database server
Definition: mythdbparams.h:22
FilterNone
@ FilterNone
Definition: mythuitextedit.h:21
DialogCompletionEvent::GetId
QString GetId()
Definition: mythdialogbox.h:52
error
static void error(const char *str,...)
Definition: vbi.cpp:36
ReferenceCounter::DecrRef
virtual int DecrRef(void)
Decrements reference count and deletes on 0.
Definition: referencecounter.cpp:125
SSDP::PerformSearch
void PerformSearch(const QString &sST, std::chrono::seconds timeout=2s)
Definition: ssdp.cpp:202
BackendSelection::Init
void Init(void) override
Used after calling Load() to assign data to widgets and other UI initilisation which is prohibited in...
Definition: backendselect.cpp:248
BackendSelection::m_mutex
QMutex m_mutex
Definition: backendselect.h:87
MythScreenType::Close
virtual void Close()
Definition: mythscreentype.cpp:386
BackendSelection::m_pConfig
Configuration * m_pConfig
Definition: backendselect.h:75
BackendSelection::customEvent
void customEvent(QEvent *event) override
Definition: backendselect.cpp:304
DatabaseParams
Structure containing the basic Database parameters.
Definition: mythdbparams.h:10
MythUIType::GetChild
MythUIType * GetChild(const QString &name) const
Get a named child of this UIType.
Definition: mythuitype.cpp:133
MythXMLClient
Definition: mythxmlclient.h:31
DialogCompletionEvent::kEventType
static Type kEventType
Definition: mythdialogbox.h:57
MythEvent
This class is used as a container for messages.
Definition: mythevent.h:16
mythxmlclient.h
BackendSelection::AddItem
void AddItem(DeviceLocation *dev)
Definition: backendselect.cpp:134
mythdialogbox.h
MythScreenStack
Definition: mythscreenstack.h:16
SSDP::Find
static SSDPCacheEntries * Find(const QString &sURI)
Definition: ssdp.h:132
DeviceLocation::GetFriendlyName
QString GetFriendlyName(void)
Definition: upnpdevice.h:278
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MythScreenType
Screen in which all other widgets are contained and rendered.
Definition: mythscreentype.h:45
mythuistatetype.h
SSDPCacheEntries::GetEntryMap
void GetEntryMap(EntryMap &map)
Returns a copy of the EntryMap.
Definition: ssdpcache.cpp:93
DeviceLocation
Definition: upnpdevice.h:210
SSDPCache::Instance
static SSDPCache * Instance()
Definition: ssdpcache.cpp:245
BackendSelection::m_exitOnFinish
bool m_exitOnFinish
Definition: backendselect.h:76
mythuibuttonlist.h
MythEvent::Message
const QString & Message() const
Definition: mythevent.h:65
mythversion.h
BackendSelection::m_devices
ItemMap m_devices
Definition: backendselect.h:77
UPnPResult_HumanInterventionRequired
@ UPnPResult_HumanInterventionRequired
Definition: upnp.h:46
InfoMap
QHash< QString, QString > InfoMap
Definition: mythtypes.h:15
DeviceLocation::NeedSecurityPin
bool NeedSecurityPin(void)
Definition: upnpdevice.h:316
SSDP::Instance
static SSDP * Instance()
Definition: ssdp.cpp:55
MythUIButtonListItem
Definition: mythuibuttonlist.h:41
MYTH_PROTO_VERSION
static constexpr const char * MYTH_PROTO_VERSION
Increment this whenever the MythTV network protocol changes.
Definition: mythversion.h:47
Configuration::SetValue
virtual void SetValue(const QString &sSetting, int value)=0
mythlogging.h
DeviceLocation::m_sUSN
QString m_sUSN
Definition: upnpdevice.h:235
MythUIButtonList::itemClicked
void itemClicked(MythUIButtonListItem *item)
BackendSelection::CloseWithDecision
void CloseWithDecision(Decision d)
Definition: backendselect.cpp:378
MythScreenType::SetFocusWidget
bool SetFocusWidget(MythUIType *widget=nullptr)
Definition: mythscreentype.cpp:118
SSDPCache::Find
SSDPCacheEntries * Find(const QString &sURI)
Finds the SSDPCacheEntries in the cache, returns nullptr when absent.
Definition: ssdpcache.cpp:301
BackendSelection::kCancelConfigure
@ kCancelConfigure
Definition: backendselect.h:44
BackendSelection::RemoveItem
void RemoveItem(const QString &USN)
Definition: backendselect.cpp:270
MythScreenType::BuildFocusList
void BuildFocusList(void)
Definition: mythscreentype.cpp:206
BackendSelection::Manual
void Manual(void)
Linked to 'Configure Manually' button.
Definition: backendselect.cpp:265
DeviceLocation::m_sLocation
QString m_sLocation
Definition: upnpdevice.h:236
MythUIButton
A single button widget.
Definition: mythuibutton.h:21
BackendSelection::kAcceptConfigure
@ kAcceptConfigure
Definition: backendselect.h:45
EntryMap
QMap< QString, DeviceLocation * > EntryMap
Key == Unique Service Name (USN)
Definition: ssdpcache.h:29
BackendSelection::m_pinCode
QString m_pinCode
Definition: backendselect.h:84
BackendSelection::Accept
void Accept(void)
Definition: backendselect.cpp:123
BackendSelection::m_saveButton
MythUIButton * m_saveButton
Definition: backendselect.h:81
kBackendURI
const QString kBackendURI
Definition: backendselect.h:20
MythUIButtonListItem::GetData
QVariant GetData()
Definition: mythuibuttonlist.cpp:3665
SSDPCacheEntries
Definition: ssdpcache.h:35
UPnPResult_ActionNotAuthorized
@ UPnPResult_ActionNotAuthorized
Definition: upnp.h:48
BackendSelection::ConnectBackend
bool ConnectBackend(DeviceLocation *dev)
Attempt UPnP connection to a backend device, get its DB details.
Definition: backendselect.cpp:186
BackendSelection::~BackendSelection
~BackendSelection() override
Definition: backendselect.cpp:29
BackendSelection::m_backendList
MythUIButtonList * m_backendList
Definition: backendselect.h:79
BackendSelection::m_usn
QString m_usn
Definition: backendselect.h:85
BackendSelection::TryDBfromURL
bool TryDBfromURL(const QString &error, const QString &URL)
Definition: backendselect.cpp:286
BackendSelection::m_backendDecision
Decision m_backendDecision
Definition: backendselect.h:89
BackendSelection::Create
bool Create(void) override
Definition: backendselect.cpp:72
Configuration
Definition: configuration.h:21
XMLParseBase::LoadWindowFromXML
static bool LoadWindowFromXML(const QString &xmlfile, const QString &windowname, MythUIType *parent)
Definition: xmlparsebase.cpp:695
BackendSelection::PromptForPassword
void PromptForPassword(void)
Definition: backendselect.cpp:355
Configuration::Save
virtual bool Save(void)=0
BackendSelection::kManualConfigure
@ kManualConfigure
Definition: backendselect.h:43
DialogCompletionEvent
Event dispatched from MythUI modal dialogs to a listening class containing a result of some form.
Definition: mythdialogbox.h:41
BackendSelection::Decision
Decision
Definition: backendselect.h:41
configuration.h
MythScreenStack::PopScreen
virtual void PopScreen(MythScreenType *screen=nullptr, bool allowFade=true, bool deleteScreen=true)
Definition: mythscreenstack.cpp:84
kDefaultUSN
const QString kDefaultUSN
Definition: backendselect.h:25
GetMythMainWindow
MythMainWindow * GetMythMainWindow(void)
Definition: mythmainwindow.cpp:102
BackendSelection::Prompt
static Decision Prompt(DatabaseParams *dbParams, Configuration *pConfig)
Definition: backendselect.cpp:48
MythXMLClient::GetConnectionInfo
UPnPResultCode GetConnectionInfo(const QString &sPin, DatabaseParams *pParams, QString &sMsg)
Definition: mythxmlclient.cpp:35
mythuibutton.h
BackendSelection::Load
void Load(void) override
Load data which will ultimately be displayed on-screen or used to determine what appears on-screen (S...
Definition: backendselect.cpp:242
MythMainWindow::GetStack
MythScreenStack * GetStack(const QString &Stackname)
Definition: mythmainwindow.cpp:320
BackendSelection::m_loop
QEventLoop * m_loop
Definition: backendselect.h:90
kDefaultPIN
const QString kDefaultPIN
Definition: backendselect.h:24
BackendSelection::m_cancelButton
MythUIButton * m_cancelButton
Definition: backendselect.h:82
SSDP::AddListener
static void AddListener(QObject *listener)
Definition: ssdp.h:127
BackendSelection::m_manualButton
MythUIButton * m_manualButton
Definition: backendselect.h:80
UPnPResult_Success
@ UPnPResult_Success
Definition: upnp.h:37
backendselect.h
d
static const iso6937table * d
Definition: iso6937tables.cpp:1025
MythTextInputDialog
Dialog prompting the user to enter a text string.
Definition: mythdialogbox.h:314
MythUIButtonList
List widget, displays list items in a variety of themeable arrangements and can trigger signals when ...
Definition: mythuibuttonlist.h:191
ReferenceCounter::IncrRef
virtual int IncrRef(void)
Increments reference count.
Definition: referencecounter.cpp:101
BackendSelection::BackendSelection
BackendSelection(MythScreenStack *parent, DatabaseParams *params, Configuration *pConfig, bool exitOnFinish=false)
Definition: backendselect.cpp:17
mythmainwindow.h
MythScreenStack::AddScreen
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Definition: mythscreenstack.cpp:50
ShowOkPopup
MythConfirmationDialog * ShowOkPopup(const QString &message, bool showCancel)
Non-blocking version of MythPopupBox::showOkPopup()
Definition: mythdialogbox.cpp:563
SSDP::RemoveListener
static void RemoveListener(QObject *listener)
Definition: ssdp.h:129
UPnPResultCode
UPnPResultCode
Definition: upnp.h:35
DeviceLocation::GetDeviceDetail
void GetDeviceDetail(InfoMap &map)
Definition: upnpdevice.h:305