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