MythTV  master
parentalcontrols.cpp
Go to the documentation of this file.
1 #include <map>
2 
3 #include "libmyth/mythcontext.h"
4 #include "libmythbase/mythdate.h"
8 
9 #include "parentalcontrols.h"
10 
11 namespace
12 {
13  ParentalLevel::Level boundedParentalLevel(ParentalLevel::Level pl)
14  {
15  if (pl < ParentalLevel::plNone)
16  return ParentalLevel::plNone;
17  if (pl > ParentalLevel::plHigh)
18  return ParentalLevel::plHigh;
19 
20  return pl;
21  }
22 
23  ParentalLevel::Level nextParentalLevel(ParentalLevel::Level cpl)
24  {
25  ParentalLevel::Level rpl(cpl);
26  switch (cpl)
27  {
29  rpl = ParentalLevel::plLowest; break;
31  rpl = ParentalLevel::plLow; break;
33  rpl = ParentalLevel::plMedium; break;
36  rpl = ParentalLevel::plHigh; break;
37  }
38 
39  return boundedParentalLevel(rpl);
40  }
41 
42  ParentalLevel::Level prevParentalLevel(ParentalLevel::Level cpl)
43  {
44  ParentalLevel::Level rpl(cpl);
45  switch (cpl)
46  {
48  rpl = ParentalLevel::plNone; break;
51  rpl = ParentalLevel::plLowest; break;
53  rpl = ParentalLevel::plLow; break;
55  rpl = ParentalLevel::plMedium; break;
56  }
57 
58  return boundedParentalLevel(rpl);
59  }
60 
61  ParentalLevel::Level toParentalLevel(int pl)
62  {
63  return boundedParentalLevel(static_cast<ParentalLevel::Level>(pl));
64  }
65 }
66 
68 {
69 }
70 
72 {
73  m_level = toParentalLevel(pl);
74 }
75 
77 {
78  *this = rhs;
79 }
80 
82 {
83  if (&rhs != this)
84  {
85  m_level = rhs.m_level;
86  m_hitlimit = rhs.m_hitlimit;
87  }
88 
89  return *this;
90 }
91 
93 {
94  m_level = boundedParentalLevel(pl);
95  return *this;
96 }
97 
99 {
100  Level last = m_level;
101  m_level = nextParentalLevel(m_level);
102  if (m_level == last)
103  m_hitlimit = true;
104  return *this;
105 }
106 
108 {
109  m_level = toParentalLevel(m_level + amount);
110  return *this;
111 }
112 
114 {
115  Level prev = m_level;
116  m_level = prevParentalLevel(m_level);
117  if (m_level == prev)
118  m_hitlimit = true;
119  return *this;
120 }
121 
123 {
124  m_level = toParentalLevel(m_level - amount);
125  return *this;
126 }
127 
129 {
130  return m_level;
131 }
132 
133 bool operator!=(const ParentalLevel &lhs, const ParentalLevel &rhs)
134 {
135  return lhs.GetLevel() != rhs.GetLevel();
136 }
137 
138 bool operator==(const ParentalLevel &lhs, const ParentalLevel &rhs)
139 {
140  return lhs.GetLevel() == rhs.GetLevel();
141 }
142 
143 bool operator<(const ParentalLevel &lhs, const ParentalLevel &rhs)
144 {
145  return lhs.GetLevel() < rhs.GetLevel();
146 }
147 
148 bool operator>(const ParentalLevel &lhs, const ParentalLevel &rhs)
149 {
150  return lhs.GetLevel() > rhs.GetLevel();
151 }
152 
153 bool operator<=(const ParentalLevel &lhs, const ParentalLevel &rhs)
154 {
155  return lhs.GetLevel() <= rhs.GetLevel();
156 }
157 
158 bool operator>=(const ParentalLevel &lhs, const ParentalLevel &rhs)
159 {
160  return lhs.GetLevel() >= rhs.GetLevel();
161 }
162 
163 namespace
164 {
165  class PasswordManager
166  {
167  private:
168  using pws = std::map<ParentalLevel::Level, QString>;
169 
170  public:
171  void Add(ParentalLevel::Level level, const QString &password)
172  {
173  m_passwords.insert(pws::value_type(level, password));
174  }
175 
176  QStringList AtOrAbove(ParentalLevel::Level level)
177  {
178  QStringList ret;
179  for (ParentalLevel i = level;
180  i <= ParentalLevel::plHigh && i.good(); ++i)
181  {
182  auto p = m_passwords.find(i.GetLevel());
183  if (p != m_passwords.end() && !p->second.isEmpty())
184  ret.push_back(p->second);
185  }
186 
187  return ret;
188  }
189 
190  QString FirstAtOrBelow(ParentalLevel::Level level)
191  {
192  QString ret;
193  for (ParentalLevel i = level;
194  i >= ParentalLevel::plLow && i.good(); --i)
195  {
196  auto p = m_passwords.find(i.GetLevel());
197  if (p != m_passwords.end() && !p->second.isEmpty())
198  {
199  ret = p->second;
200  break;
201  }
202  }
203 
204  return ret;
205  }
206 
207  private:
208  pws m_passwords;
209  };
210 }
211 
212 class ParentalLevelChangeCheckerPrivate : public QObject
213 {
214  Q_OBJECT
215 
216  public:
217  explicit ParentalLevelChangeCheckerPrivate(QObject *lparent) : QObject(lparent)
218  {
220  gCoreContext->GetSetting("VideoAdminPassword"));
222  gCoreContext->GetSetting("VideoAdminPasswordThree"));
224  gCoreContext->GetSetting("VideoAdminPasswordTwo"));
225 
226  m_passwordOK = false;
229  }
230 
232  {
233  m_fromLevel = fromLevel;
234  m_toLevel = toLevel;
235  if (DoCheck())
236  {
237  emit SigDone(true, toLevel);
238  }
239  }
240 
241  signals:
242  // NOLINTNEXTLINE(readability-inconsistent-declaration-parameter-name)
243  void SigDone(bool passwordValid, ParentalLevel::Level toLevel);
244 
245  private:
246  // returns true if no completion is required
247  bool DoCheck()
248  {
249  ParentalLevel which_level(m_toLevel);
250 
251  // No password for level 1 and you can always switch down from your
252  // current level.
253  if (which_level == ParentalLevel::plLowest ||
254  which_level <= ParentalLevel(m_fromLevel))
255  return true;
256 
257  // If there isn't a password at the current level, and
258  // none of the levels below, we are done.
259  // The assumption is that if you password protected lower levels,
260  // and a higher level does not have a password it is something
261  // you've overlooked (rather than intended).
262  if (m_pm.FirstAtOrBelow(which_level.GetLevel()).isEmpty())
263  return true;
264 
265  // See if we recently (and successfully) asked for a password
266  QString last_time_stamp = gCoreContext->GetSetting("VideoPasswordTime");
267  int last_parent_lvl = gCoreContext->GetNumSetting("VideoPasswordLevel",
268  -1);
269 
270  if (last_time_stamp.isEmpty() || last_parent_lvl == -1)
271  {
272  LOG(VB_GENERAL, LOG_ERR,
273  QString("%1: Could not read password/pin time "
274  "stamp. This is only an issue if it "
275  "happens repeatedly.").arg(__FILE__));
276  }
277  else
278  {
279  QDateTime curr_time = MythDate::current();
280  QDateTime last_time = MythDate::fromString(last_time_stamp);
281 
282  if (ParentalLevel(last_parent_lvl) >= which_level &&
283  last_time.secsTo(curr_time) < 120)
284  {
285  // Two minute window
286  last_time_stamp = curr_time.toString(Qt::ISODate);
287  gCoreContext->SaveSetting("VideoPasswordTime", last_time_stamp);
288  return true;
289  }
290  }
291 
292  m_validPasswords = m_pm.AtOrAbove(which_level.GetLevel());
293 
294  // If there isn't a password for this level or higher levels, treat
295  // the next lower password as valid. This is only done so people
296  // cannot lock themselves out of the setup.
297  if (m_validPasswords.empty())
298  {
299  QString pw = m_pm.FirstAtOrBelow(which_level.GetLevel());
300  if (!pw.isEmpty())
301  m_validPasswords.push_back(pw);
302  }
303 
304  // There are no suitable passwords.
305  if (m_validPasswords.empty())
306  return true;
307 
308  // If we got here, there is a password, and there's no backing down.
309  m_passwordOK = false;
310  MythScreenStack *popupStack =
311  GetMythMainWindow()->GetStack("popup stack");
312 
313  auto *pwd = new MythTextInputDialog(popupStack,
314  tr("Parental PIN:"), FilterNone, true);
315 
316  connect(pwd, &MythTextInputDialog::haveResult,
319 
320  if (pwd->Create())
321  popupStack->AddScreen(pwd, false);
322 
323  return false;
324  }
325 
326  private slots:
327  void OnPasswordEntered(const QString& password)
328  {
329  m_passwordOK = false;
330 
331  for (const auto& valid_pwd : std::as_const(m_validPasswords))
332  {
333  if (password != valid_pwd)
334  continue;
335 
336  m_passwordOK = true;
337  QString time_stamp = MythDate::current_iso_string();
338 
339  gCoreContext->SaveSetting("VideoPasswordTime", time_stamp);
340  gCoreContext->SaveSetting("VideoPasswordLevel", m_toLevel);
341 
342  return;
343  }
344  }
345 
347  {
349  }
350 
351  private:
355  PasswordManager m_pm;
356  QStringList m_validPasswords;
357 };
358 
360 {
364 }
365 
367  ParentalLevel::Level toLevel)
368 {
369  m_private->Check(fromLevel, toLevel);
370 }
371 
373  ParentalLevel::Level newLevel)
374 {
375  emit SigResultReady(passwordValid, newLevel);
376 }
377 
378 #include "parentalcontrols.moc"
FilterNone
@ FilterNone
Definition: mythuitextedit.h:21
ParentalLevel::plLowest
@ plLowest
Definition: parentalcontrols.h:12
operator==
bool operator==(const ParentalLevel &lhs, const ParentalLevel &rhs)
Definition: parentalcontrols.cpp:138
parentalcontrols.h
mythscreenstack.h
operator>
bool operator>(const ParentalLevel &lhs, const ParentalLevel &rhs)
Definition: parentalcontrols.cpp:148
ParentalLevel::plMedium
@ plMedium
Definition: parentalcontrols.h:12
ParentalLevel::plHigh
@ plHigh
Definition: parentalcontrols.h:13
ParentalLevel::plLow
@ plLow
Definition: parentalcontrols.h:12
mythdialogbox.h
MythScreenStack
Definition: mythscreenstack.h:16
ParentalLevelChangeCheckerPrivate::m_pm
PasswordManager m_pm
Definition: parentalcontrols.cpp:355
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
ParentalLevelChangeCheckerPrivate::SigDone
void SigDone(bool passwordValid, ParentalLevel::Level toLevel)
ParentalLevel::m_level
Level m_level
Definition: parentalcontrols.h:32
ParentalLevelChangeCheckerPrivate::ParentalLevelChangeCheckerPrivate
ParentalLevelChangeCheckerPrivate(QObject *lparent)
Definition: parentalcontrols.cpp:217
ParentalLevelChangeChecker::m_private
class ParentalLevelChangeCheckerPrivate * m_private
Definition: parentalcontrols.h:59
MythTextInputDialog::haveResult
void haveResult(QString)
ParentalLevelChangeCheckerPrivate::Check
void Check(ParentalLevel::Level fromLevel, ParentalLevel::Level toLevel)
Definition: parentalcontrols.cpp:231
MythDate::current
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:14
operator>=
bool operator>=(const ParentalLevel &lhs, const ParentalLevel &rhs)
Definition: parentalcontrols.cpp:158
ParentalLevelChangeCheckerPrivate::DoCheck
bool DoCheck()
Definition: parentalcontrols.cpp:247
ParentalLevelChangeChecker::ParentalLevelChangeChecker
ParentalLevelChangeChecker()
Definition: parentalcontrols.cpp:359
mythdate.h
ParentalLevel::plNone
@ plNone
Definition: parentalcontrols.h:12
operator!=
bool operator!=(const ParentalLevel &lhs, const ParentalLevel &rhs)
Definition: parentalcontrols.cpp:133
ParentalLevel::Level
Level
Definition: parentalcontrols.h:12
hardwareprofile.config.p
p
Definition: config.py:33
ParentalLevelChangeCheckerPrivate::OnPasswordExit
void OnPasswordExit()
Definition: parentalcontrols.cpp:346
ParentalLevelChangeCheckerPrivate
Definition: parentalcontrols.cpp:212
ParentalLevel::ParentalLevel
ParentalLevel(Level pl)
Definition: parentalcontrols.cpp:67
ParentalLevel::operator=
ParentalLevel & operator=(const ParentalLevel &rhs)
Definition: parentalcontrols.cpp:81
ParentalLevelChangeCheckerPrivate::m_passwordOK
bool m_passwordOK
Definition: parentalcontrols.cpp:352
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:55
operator<=
bool operator<=(const ParentalLevel &lhs, const ParentalLevel &rhs)
Definition: parentalcontrols.cpp:153
ParentalLevelChangeChecker::SigResultReady
void SigResultReady(bool passwordValid, ParentalLevel::Level newLevel)
MythCoreContext::GetNumSetting
int GetNumSetting(const QString &key, int defaultval=0)
Definition: mythcorecontext.cpp:912
MythDate::fromString
QDateTime fromString(const QString &dtstr)
Converts kFilename && kISODate formats to QDateTime.
Definition: mythdate.cpp:34
operator<
bool operator<(const ParentalLevel &lhs, const ParentalLevel &rhs)
Definition: parentalcontrols.cpp:143
ParentalLevelChangeChecker::Check
void Check(ParentalLevel::Level fromLevel, ParentalLevel::Level toLevel)
Definition: parentalcontrols.cpp:366
ParentalLevelChangeChecker::OnResultReady
void OnResultReady(bool passwordValid, ParentalLevel::Level newLevel)
Definition: parentalcontrols.cpp:372
ParentalLevel
Definition: parentalcontrols.h:9
ParentalLevel::operator+=
ParentalLevel & operator+=(int amount)
Definition: parentalcontrols.cpp:107
MythDate::ISODate
@ ISODate
Default UTC.
Definition: mythdate.h:17
mythcontext.h
GetMythMainWindow
MythMainWindow * GetMythMainWindow(void)
Definition: mythmainwindow.cpp:104
ParentalLevelChangeCheckerPrivate::m_validPasswords
QStringList m_validPasswords
Definition: parentalcontrols.cpp:356
MythDate::current_iso_string
QString current_iso_string(bool stripped)
Returns current Date and Time in UTC as a string.
Definition: mythdate.cpp:22
ParentalLevel::m_hitlimit
bool m_hitlimit
Definition: parentalcontrols.h:33
MythScreenType::Exiting
void Exiting()
MythMainWindow::GetStack
MythScreenStack * GetStack(const QString &Stackname)
Definition: mythmainwindow.cpp:323
ParentalLevel::operator-=
ParentalLevel & operator-=(int amount)
Definition: parentalcontrols.cpp:122
MythTextInputDialog
Dialog prompting the user to enter a text string.
Definition: mythdialogbox.h:314
MythCoreContext::SaveSetting
void SaveSetting(const QString &key, int newValue)
Definition: mythcorecontext.cpp:881
ParentalLevelChangeCheckerPrivate::m_toLevel
ParentalLevel::Level m_toLevel
Definition: parentalcontrols.cpp:354
ParentalLevel::operator--
ParentalLevel & operator--()
Definition: parentalcontrols.cpp:113
mythmainwindow.h
ParentalLevelChangeCheckerPrivate::m_fromLevel
ParentalLevel::Level m_fromLevel
Definition: parentalcontrols.cpp:353
MythScreenStack::AddScreen
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Definition: mythscreenstack.cpp:52
ParentalLevel::GetLevel
Level GetLevel() const
Definition: parentalcontrols.cpp:128
ParentalLevelChangeCheckerPrivate::OnPasswordEntered
void OnPasswordEntered(const QString &password)
Definition: parentalcontrols.cpp:327
MythCoreContext::GetSetting
QString GetSetting(const QString &key, const QString &defaultval="")
Definition: mythcorecontext.cpp:898
ParentalLevel::operator++
ParentalLevel & operator++()
Definition: parentalcontrols.cpp:98