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