00001 #include <map>
00002
00003 #include <mythtv/mythcontext.h>
00004 #include <mythtv/uitypes.h>
00005
00006 #include "parentalcontrols.h"
00007
00008 namespace
00009 {
00010
00011 ParentalLevel::Level boundedParentalLevel(ParentalLevel::Level pl)
00012 {
00013 if (pl < ParentalLevel::plNone)
00014 return ParentalLevel::plNone;
00015 else if (pl > ParentalLevel::plHigh)
00016 return ParentalLevel::plHigh;
00017
00018 return pl;
00019 }
00020
00021 ParentalLevel::Level nextParentalLevel(ParentalLevel::Level cpl)
00022 {
00023 ParentalLevel::Level rpl(cpl);
00024 switch (cpl)
00025 {
00026 case ParentalLevel::plNone: { rpl = ParentalLevel::plLowest; break; }
00027 case ParentalLevel::plLowest: { rpl = ParentalLevel::plLow; break; }
00028 case ParentalLevel::plLow: { rpl = ParentalLevel::plMedium; break; }
00029 case ParentalLevel::plMedium: { rpl = ParentalLevel::plHigh; break; }
00030 case ParentalLevel::plHigh: { rpl = ParentalLevel::plHigh; break; }
00031 }
00032
00033 return boundedParentalLevel(rpl);
00034 }
00035
00036 ParentalLevel::Level prevParentalLevel(ParentalLevel::Level cpl)
00037 {
00038 ParentalLevel::Level rpl(cpl);
00039 switch (cpl)
00040 {
00041 case ParentalLevel::plNone: { rpl = ParentalLevel::plNone; break; }
00042 case ParentalLevel::plLowest: { rpl = ParentalLevel::plLowest; break; }
00043 case ParentalLevel::plLow: { rpl = ParentalLevel::plLowest; break; }
00044 case ParentalLevel::plMedium: { rpl = ParentalLevel::plLow; break; }
00045 case ParentalLevel::plHigh: { rpl = ParentalLevel::plMedium; break; }
00046 }
00047
00048 return boundedParentalLevel(rpl);
00049 }
00050
00051 ParentalLevel::Level toParentalLevel(int pl)
00052 {
00053 return boundedParentalLevel(static_cast<ParentalLevel::Level>(pl));
00054 }
00055
00056 }
00057
00058 ParentalLevel::ParentalLevel(ParentalLevel::Level pl) : m_pl(pl),
00059 m_hitlimit(false)
00060 {
00061 }
00062
00063 ParentalLevel::ParentalLevel(int pl) : m_hitlimit(false)
00064 {
00065 m_pl = toParentalLevel(pl);
00066 }
00067
00068 ParentalLevel::ParentalLevel(const ParentalLevel &rhs) : m_hitlimit(false)
00069 {
00070 *this = rhs;
00071 }
00072
00073 ParentalLevel &ParentalLevel::operator=(const ParentalLevel &rhs)
00074 {
00075 if (&rhs != this)
00076 {
00077 m_pl = rhs.m_pl;
00078 }
00079 return *this;
00080 }
00081
00082 ParentalLevel &ParentalLevel::operator=(Level pl)
00083 {
00084 m_pl = boundedParentalLevel(pl);
00085 return *this;
00086 }
00087
00088 ParentalLevel &ParentalLevel::operator++()
00089 {
00090 Level last = m_pl;
00091 m_pl = nextParentalLevel(m_pl);
00092 if (m_pl == last)
00093 m_hitlimit = true;
00094 return *this;
00095 }
00096
00097 ParentalLevel &ParentalLevel::operator+=(int amount)
00098 {
00099 m_pl = toParentalLevel(m_pl + amount);
00100 return *this;
00101 }
00102
00103 ParentalLevel &ParentalLevel::operator--()
00104 {
00105 Level prev = m_pl;
00106 m_pl = prevParentalLevel(m_pl);
00107 if (m_pl == prev)
00108 m_hitlimit = true;
00109 return *this;
00110 }
00111
00112 ParentalLevel &ParentalLevel::operator-=(int amount)
00113 {
00114 m_pl = toParentalLevel(m_pl - amount);
00115 return *this;
00116 }
00117
00118 ParentalLevel::Level ParentalLevel::GetLevel() const
00119 {
00120 return m_pl;
00121 }
00122
00123 bool operator!=(const ParentalLevel &lhs, const ParentalLevel &rhs)
00124 {
00125 return lhs.GetLevel() != rhs.GetLevel();
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
00154
00155 class MythMultiPasswordDialog : public MythDialog
00156 {
00157 Q_OBJECT
00158 public:
00159 MythMultiPasswordDialog(const QString &message, const QStringList &pwlist,
00160 MythMainWindow *lparent, const char *lname = 0);
00161
00162 private slots:
00163 void checkPassword(const QString &password);
00164
00165 protected:
00166 ~MythMultiPasswordDialog();
00167 void keyPressEvent(QKeyEvent *e);
00168
00169 private:
00170 MythLineEdit *m_passwordEditor;
00171 QStringList m_passwords;
00172 };
00173
00174 MythMultiPasswordDialog::MythMultiPasswordDialog(const QString &message,
00175 const QStringList &pwlist,
00176 MythMainWindow *lparent,
00177 const char *lname) :
00178 MythDialog(lparent, lname, false), m_passwords(pwlist)
00179 {
00180 int textWidth = fontMetrics().width(message);
00181 int totalWidth = textWidth + 175;
00182
00183 gContext->GetScreenSettings(screenwidth, wmult, screenheight, hmult);
00184 setGeometry((screenwidth - 250) / 2,
00185 (screenheight - 50) / 2, totalWidth, 50);
00186
00187 QFrame *outside_border = new QFrame(this);
00188 outside_border->setGeometry(0, 0, totalWidth, 50);
00189 outside_border->setFrameStyle(QFrame::Panel | QFrame::Raised);
00190 outside_border->setLineWidth(4);
00191
00192 QLabel *message_label = new QLabel(message, this);
00193 message_label->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
00194 message_label->setGeometry(15, 10, textWidth, 30);
00195 message_label->setBackgroundOrigin(ParentOrigin);
00196
00197 m_passwordEditor = new MythLineEdit(this);
00198 m_passwordEditor->setEchoMode(QLineEdit::Password);
00199 m_passwordEditor->setGeometry(textWidth + 20, 10, 135, 30);
00200 m_passwordEditor->setBackgroundOrigin(ParentOrigin);
00201 m_passwordEditor->setAllowVirtualKeyboard(false);
00202 connect(m_passwordEditor, SIGNAL(textChanged(const QString &)),
00203 this, SLOT(checkPassword(const QString &)));
00204
00205 setActiveWindow();
00206 m_passwordEditor->setFocus();
00207 }
00208
00209 void MythMultiPasswordDialog::keyPressEvent(QKeyEvent *e)
00210 {
00211 QStringList actions;
00212 if (gContext->GetMainWindow()->TranslateKeyPress("qt", e, actions))
00213 {
00214 bool handled = false;
00215 for (unsigned int i = 0; i < actions.size() && !handled; i++)
00216 {
00217 QString action = actions[i];
00218 if (action == "ESCAPE")
00219 {
00220 handled = true;
00221 MythDialog::keyPressEvent(e);
00222 }
00223 }
00224 }
00225 }
00226
00227 void MythMultiPasswordDialog::checkPassword(const QString &password)
00228 {
00229 for (QStringList::iterator p = m_passwords.begin(); p != m_passwords.end();
00230 ++p)
00231 {
00232 if (password == *p)
00233 accept();
00234 }
00235 }
00236
00237 MythMultiPasswordDialog::~MythMultiPasswordDialog()
00238 {
00239 }
00240
00242
00243 namespace
00244 {
00245
00246 class PasswordManager
00247 {
00248 private:
00249 typedef std::map<ParentalLevel::Level, QString> pws;
00250
00251 public:
00252 void Add(ParentalLevel::Level level, const QString &password)
00253 {
00254 m_passwords.insert(pws::value_type(level, password));
00255 }
00256
00257 QStringList AtOrAbove(ParentalLevel::Level level)
00258 {
00259 QStringList ret;
00260 for (ParentalLevel i = level;
00261 i <= ParentalLevel::plHigh && i.good(); ++i)
00262 {
00263 pws::const_iterator p = m_passwords.find(i.GetLevel());
00264 if (p != m_passwords.end() && p->second.length())
00265 ret.push_back(p->second);
00266 }
00267
00268 return ret;
00269 }
00270
00271 QString FirstAtOrBelow(ParentalLevel::Level level)
00272 {
00273 QString ret;
00274 for (ParentalLevel i = level;
00275 i >= ParentalLevel::plLow && i.good(); --i)
00276 {
00277 pws::const_iterator p = m_passwords.find(i.GetLevel());
00278 if (p != m_passwords.end() && p->second.length())
00279 {
00280 ret = p->second;
00281 break;
00282 }
00283 }
00284
00285 return ret;
00286 }
00287
00288 private:
00289 pws m_passwords;
00290 };
00291
00292 }
00293
00294 bool checkParentPassword(ParentalLevel::Level to_level,
00295 ParentalLevel::Level current)
00296 {
00297 PasswordManager pm;
00298 pm.Add(ParentalLevel::plHigh, gContext->GetSetting("VideoAdminPassword"));
00299 pm.Add(ParentalLevel::plMedium,
00300 gContext->GetSetting("VideoAdminPasswordThree"));
00301 pm.Add(ParentalLevel::plLow, gContext->GetSetting("VideoAdminPasswordTwo"));
00302
00303 ParentalLevel which_level(to_level);
00304
00305
00306
00307 if (which_level == ParentalLevel::plLowest ||
00308 which_level <= ParentalLevel(current))
00309 return true;
00310
00311
00312
00313
00314
00315
00316 if (!pm.FirstAtOrBelow(which_level.GetLevel()).length())
00317 return true;
00318
00319
00320 QString last_time_stamp = gContext->GetSetting("VideoPasswordTime");
00321 int last_parent_lvl = gContext->GetNumSetting("VideoPasswordLevel", -1);
00322
00323 if (!last_time_stamp.length() || last_parent_lvl == -1)
00324 {
00325 VERBOSE(VB_IMPORTANT,
00326 QString("%1: Could not read password/pin time "
00327 "stamp. This is only an issue if it "
00328 "happens repeatedly.").arg(__FILE__));
00329 }
00330 else
00331 {
00332 QDateTime curr_time = QDateTime::currentDateTime();
00333 QDateTime last_time =
00334 QDateTime::fromString(last_time_stamp, Qt::ISODate);
00335
00336 if (ParentalLevel(last_parent_lvl) >= which_level &&
00337 last_time.secsTo(curr_time) < 120)
00338 {
00339
00340 last_time_stamp = curr_time.toString(Qt::ISODate);
00341 gContext->SetSetting("VideoPasswordTime", last_time_stamp);
00342 gContext->SaveSetting("VideoPasswordTime", last_time_stamp);
00343 return true;
00344 }
00345 }
00346
00347 QStringList valid_passwords = pm.AtOrAbove(which_level.GetLevel());
00348
00349
00350
00351
00352 if (!valid_passwords.size())
00353 {
00354 QString pw = pm.FirstAtOrBelow(which_level.GetLevel());
00355 if (pw.length())
00356 valid_passwords.push_back(pw);
00357 }
00358
00359
00360 if (!valid_passwords.size())
00361 return true;
00362
00363
00364 MythMultiPasswordDialog *pwd =
00365 new MythMultiPasswordDialog(QObject::tr("Parental Pin:"),
00366 valid_passwords,
00367 gContext->GetMainWindow());
00368 bool ok = (kDialogCodeRejected != pwd->exec());
00369 pwd->deleteLater();
00370
00371 if (ok)
00372 {
00373 last_time_stamp = QDateTime::currentDateTime().toString(Qt::ISODate);
00374
00375 gContext->SetSetting("VideoPasswordTime", last_time_stamp);
00376 gContext->SaveSetting("VideoPasswordTime", last_time_stamp);
00377
00378 gContext->SetSetting("VideoPasswordLevel",
00379 QString::number(which_level.GetLevel()));
00380 gContext->SaveSetting("VideoPasswordLevel", which_level.GetLevel());
00381
00382 return true;
00383 }
00384
00385 return false;
00386 }
00387
00388 #include "parentalcontrols.moc"