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