00001 #include <map>
00002
00003 #include "mythcontext.h"
00004 #include "mythmainwindow.h"
00005 #include "mythscreenstack.h"
00006 #include "mythdialogbox.h"
00007
00008 #include "parentalcontrols.h"
00009
00010 namespace
00011 {
00012 ParentalLevel::Level boundedParentalLevel(ParentalLevel::Level pl)
00013 {
00014 if (pl < ParentalLevel::plNone)
00015 return ParentalLevel::plNone;
00016 else if (pl > ParentalLevel::plHigh)
00017 return ParentalLevel::plHigh;
00018
00019 return pl;
00020 }
00021
00022 ParentalLevel::Level nextParentalLevel(ParentalLevel::Level cpl)
00023 {
00024 ParentalLevel::Level rpl(cpl);
00025 switch (cpl)
00026 {
00027 case ParentalLevel::plNone:
00028 { rpl = ParentalLevel::plLowest; break; }
00029 case ParentalLevel::plLowest: { rpl = ParentalLevel::plLow; break; }
00030 case ParentalLevel::plLow: { rpl = ParentalLevel::plMedium; break; }
00031 case ParentalLevel::plMedium:
00032 { rpl = ParentalLevel::plHigh; break; }
00033 case ParentalLevel::plHigh: { rpl = ParentalLevel::plHigh; break; }
00034 }
00035
00036 return boundedParentalLevel(rpl);
00037 }
00038
00039 ParentalLevel::Level prevParentalLevel(ParentalLevel::Level cpl)
00040 {
00041 ParentalLevel::Level rpl(cpl);
00042 switch (cpl)
00043 {
00044 case ParentalLevel::plNone: { rpl = ParentalLevel::plNone; break; }
00045 case ParentalLevel::plLowest:
00046 { rpl = ParentalLevel::plLowest; break; }
00047 case ParentalLevel::plLow: { rpl = ParentalLevel::plLowest; break; }
00048 case ParentalLevel::plMedium: { rpl = ParentalLevel::plLow; break; }
00049 case ParentalLevel::plHigh:
00050 { rpl = ParentalLevel::plMedium; break; }
00051 }
00052
00053 return boundedParentalLevel(rpl);
00054 }
00055
00056 ParentalLevel::Level toParentalLevel(int pl)
00057 {
00058 return boundedParentalLevel(static_cast<ParentalLevel::Level>(pl));
00059 }
00060 }
00061
00062 ParentalLevel::ParentalLevel(Level pl) : m_level(pl),
00063 m_hitlimit(false)
00064 {
00065 }
00066
00067 ParentalLevel::ParentalLevel(int pl) : m_hitlimit(false)
00068 {
00069 m_level = toParentalLevel(pl);
00070 }
00071
00072 ParentalLevel::ParentalLevel(const ParentalLevel &rhs) : m_hitlimit(false)
00073 {
00074 *this = rhs;
00075 }
00076
00077 ParentalLevel &ParentalLevel::operator=(const ParentalLevel &rhs)
00078 {
00079 if (&rhs != this)
00080 {
00081 m_level = rhs.m_level;
00082 }
00083
00084 return *this;
00085 }
00086
00087 ParentalLevel &ParentalLevel::operator=(Level pl)
00088 {
00089 m_level = boundedParentalLevel(pl);
00090 return *this;
00091 }
00092
00093 ParentalLevel &ParentalLevel::operator++()
00094 {
00095 Level last = m_level;
00096 m_level = nextParentalLevel(m_level);
00097 if (m_level == last)
00098 m_hitlimit = true;
00099 return *this;
00100 }
00101
00102 ParentalLevel &ParentalLevel::operator+=(int amount)
00103 {
00104 m_level = toParentalLevel(m_level + amount);
00105 return *this;
00106 }
00107
00108 ParentalLevel &ParentalLevel::operator--()
00109 {
00110 Level prev = m_level;
00111 m_level = prevParentalLevel(m_level);
00112 if (m_level == prev)
00113 m_hitlimit = true;
00114 return *this;
00115 }
00116
00117 ParentalLevel &ParentalLevel::operator-=(int amount)
00118 {
00119 m_level = toParentalLevel(m_level - amount);
00120 return *this;
00121 }
00122
00123 ParentalLevel::Level ParentalLevel::GetLevel() const
00124 {
00125 return m_level;
00126 }
00127
00128 bool operator!=(const ParentalLevel &lhs, const ParentalLevel &rhs)
00129 {
00130 return lhs.GetLevel() != rhs.GetLevel();
00131 }
00132
00133 bool operator==(const ParentalLevel &lhs, const ParentalLevel &rhs)
00134 {
00135 return lhs.GetLevel() == rhs.GetLevel();
00136 }
00137
00138 bool operator<(const ParentalLevel &lhs, const ParentalLevel &rhs)
00139 {
00140 return lhs.GetLevel() < rhs.GetLevel();
00141 }
00142
00143 bool operator>(const ParentalLevel &lhs, const ParentalLevel &rhs)
00144 {
00145 return lhs.GetLevel() > rhs.GetLevel();
00146 }
00147
00148 bool operator<=(const ParentalLevel &lhs, const ParentalLevel &rhs)
00149 {
00150 return lhs.GetLevel() <= rhs.GetLevel();
00151 }
00152
00153 bool operator>=(const ParentalLevel &lhs, const ParentalLevel &rhs)
00154 {
00155 return lhs.GetLevel() >= rhs.GetLevel();
00156 }
00157
00158 namespace
00159 {
00160 class PasswordManager
00161 {
00162 private:
00163 typedef std::map<ParentalLevel::Level, QString> pws;
00164
00165 public:
00166 void Add(ParentalLevel::Level level, const QString &password)
00167 {
00168 m_passwords.insert(pws::value_type(level, password));
00169 }
00170
00171 QStringList AtOrAbove(ParentalLevel::Level level)
00172 {
00173 QStringList ret;
00174 for (ParentalLevel i = level;
00175 i <= ParentalLevel::plHigh && i.good(); ++i)
00176 {
00177 pws::const_iterator p = m_passwords.find(i.GetLevel());
00178 if (p != m_passwords.end() && p->second.length())
00179 ret.push_back(p->second);
00180 }
00181
00182 return ret;
00183 }
00184
00185 QString FirstAtOrBelow(ParentalLevel::Level level)
00186 {
00187 QString ret;
00188 for (ParentalLevel i = level;
00189 i >= ParentalLevel::plLow && i.good(); --i)
00190 {
00191 pws::const_iterator p = m_passwords.find(i.GetLevel());
00192 if (p != m_passwords.end() && p->second.length())
00193 {
00194 ret = p->second;
00195 break;
00196 }
00197 }
00198
00199 return ret;
00200 }
00201
00202 private:
00203 pws m_passwords;
00204 };
00205 }
00206
00207 class ParentalLevelChangeCheckerPrivate : public QObject
00208 {
00209 Q_OBJECT
00210
00211 public:
00212 ParentalLevelChangeCheckerPrivate(QObject *lparent) : QObject(lparent)
00213 {
00214 m_pm.Add(ParentalLevel::plHigh,
00215 gCoreContext->GetSetting("VideoAdminPassword"));
00216 m_pm.Add(ParentalLevel::plMedium,
00217 gCoreContext->GetSetting("VideoAdminPasswordThree"));
00218 m_pm.Add(ParentalLevel::plLow,
00219 gCoreContext->GetSetting("VideoAdminPasswordTwo"));
00220
00221 m_passwordOK = false;
00222 }
00223
00224 void Check(ParentalLevel::Level fromLevel, ParentalLevel::Level toLevel)
00225 {
00226 m_fromLevel = fromLevel;
00227 m_toLevel = toLevel;
00228 if (DoCheck())
00229 {
00230 emit SigDone(true, toLevel);
00231 }
00232 }
00233
00234 signals:
00235 void SigDone(bool passwordValid, ParentalLevel::Level toLevel);
00236
00237 private:
00238
00239 bool DoCheck()
00240 {
00241 ParentalLevel which_level(m_toLevel);
00242
00243
00244
00245 if (which_level == ParentalLevel::plLowest ||
00246 which_level <= ParentalLevel(m_fromLevel))
00247 return true;
00248
00249
00250
00251
00252
00253
00254 if (!m_pm.FirstAtOrBelow(which_level.GetLevel()).length())
00255 return true;
00256
00257
00258 QString last_time_stamp = gCoreContext->GetSetting("VideoPasswordTime");
00259 int last_parent_lvl = gCoreContext->GetNumSetting("VideoPasswordLevel",
00260 -1);
00261
00262 if (!last_time_stamp.length() || last_parent_lvl == -1)
00263 {
00264 LOG(VB_GENERAL, LOG_ERR,
00265 QString("%1: Could not read password/pin time "
00266 "stamp. This is only an issue if it "
00267 "happens repeatedly.").arg(__FILE__));
00268 }
00269 else
00270 {
00271 QDateTime curr_time = QDateTime::currentDateTime();
00272 QDateTime last_time =
00273 QDateTime::fromString(last_time_stamp, Qt::ISODate);
00274
00275 if (ParentalLevel(last_parent_lvl) >= which_level &&
00276 last_time.secsTo(curr_time) < 120)
00277 {
00278
00279 last_time_stamp = curr_time.toString(Qt::ISODate);
00280 gCoreContext->SaveSetting("VideoPasswordTime", last_time_stamp);
00281 return true;
00282 }
00283 }
00284
00285 m_validPasswords = m_pm.AtOrAbove(which_level.GetLevel());
00286
00287
00288
00289
00290 if (!m_validPasswords.size())
00291 {
00292 QString pw = m_pm.FirstAtOrBelow(which_level.GetLevel());
00293 if (pw.length())
00294 m_validPasswords.push_back(pw);
00295 }
00296
00297
00298 if (!m_validPasswords.size())
00299 return true;
00300
00301
00302 m_passwordOK = false;
00303 MythScreenStack *popupStack =
00304 GetMythMainWindow()->GetStack("popup stack");
00305
00306 MythTextInputDialog *pwd =
00307 new MythTextInputDialog(popupStack,
00308 QObject::tr("Parental PIN:"), FilterNone, true);
00309
00310 connect(pwd, SIGNAL(haveResult(QString)),
00311 SLOT(OnPasswordEntered(QString)));
00312 connect(pwd, SIGNAL(Exiting()), SLOT(OnPasswordExit()));
00313
00314 if (pwd->Create())
00315 popupStack->AddScreen(pwd, false);
00316
00317 return false;
00318 }
00319
00320 private slots:
00321 void OnPasswordEntered(QString password)
00322 {
00323 m_passwordOK = false;
00324
00325 for (QStringList::iterator p = m_validPasswords.begin();
00326 p != m_validPasswords.end(); ++p)
00327 {
00328 if (password == *p)
00329 {
00330 m_passwordOK = true;
00331 QString time_stamp =
00332 QDateTime::currentDateTime().toString(Qt::ISODate);
00333
00334 gCoreContext->SaveSetting("VideoPasswordTime", time_stamp);
00335 gCoreContext->SaveSetting("VideoPasswordLevel", m_toLevel);
00336
00337 break;
00338 }
00339 }
00340 }
00341
00342 void OnPasswordExit()
00343 {
00344 emit SigDone(m_passwordOK, m_passwordOK ? m_toLevel : m_fromLevel);
00345 }
00346
00347 private:
00348 bool m_passwordOK;
00349 ParentalLevel::Level m_fromLevel;
00350 ParentalLevel::Level m_toLevel;
00351 PasswordManager m_pm;
00352 QStringList m_validPasswords;
00353 };
00354
00355 ParentalLevelChangeChecker::ParentalLevelChangeChecker()
00356 {
00357 m_private = new ParentalLevelChangeCheckerPrivate(this);
00358 connect(m_private, SIGNAL(SigDone(bool, ParentalLevel::Level)),
00359 SLOT(OnResultReady(bool, ParentalLevel::Level)));
00360 }
00361
00362 void ParentalLevelChangeChecker::Check(ParentalLevel::Level fromLevel,
00363 ParentalLevel::Level toLevel)
00364 {
00365 m_private->Check(fromLevel, toLevel);
00366 }
00367
00368 void ParentalLevelChangeChecker::OnResultReady(bool passwordValid,
00369 ParentalLevel::Level newLevel)
00370 {
00371 emit SigResultReady(passwordValid, newLevel);
00372 }
00373
00374 #include "parentalcontrols.moc"