2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
21 #include "GUIPassword.h"
22 #include "GUIUserMessages.h"
23 #include "ApplicationMessenger.h"
24 #include "dialogs/GUIDialogGamepad.h"
25 #include "guilib/GUIKeyboardFactory.h"
26 #include "dialogs/GUIDialogNumeric.h"
27 #include "dialogs/GUIDialogOK.h"
28 #include "profiles/ProfilesManager.h"
29 #include "profiles/dialogs/GUIDialogLockSettings.h"
30 #include "profiles/dialogs/GUIDialogProfileSettings.h"
32 #include "settings/MediaSourceSettings.h"
33 #include "settings/Settings.h"
34 #include "guilib/GUIWindowManager.h"
36 #include "guilib/LocalizeStrings.h"
37 #include "utils/log.h"
38 #include "utils/StringUtils.h"
39 #include "view/ViewStateSettings.h"
41 CGUIPassword::CGUIPassword(void)
43 iMasterLockRetriesLeft = -1;
46 CGUIPassword::~CGUIPassword(void)
49 bool CGUIPassword::IsItemUnlocked(CFileItem* pItem, const CStdString &strType)
51 // \brief Tests if the user is allowed to access the share folder
52 // \param pItem The share folder item to access
53 // \param strType The type of share being accessed, e.g. "music", "video", etc. See CSettings::UpdateSources()
54 // \return If access is granted, returns \e true
55 if (CProfilesManager::Get().GetMasterProfile().getLockMode() == LOCK_MODE_EVERYONE)
58 while (pItem->m_iHasLock > 1)
60 CStdString strLockCode = pItem->m_strLockCode;
61 CStdString strLabel = pItem->GetLabel();
62 int iResult = 0; // init to user succeeded state, doing this to optimize switch statement below
63 char buffer[33]; // holds 32 places plus sign character
64 if(g_passwordManager.bMasterUser)// Check if we are the MasterUser!
70 if (0 != CSettings::Get().GetInt("masterlock.maxretries") && pItem->m_iBadPwdCount >= CSettings::Get().GetInt("masterlock.maxretries"))
71 { // user previously exhausted all retries, show access denied error
72 CGUIDialogOK::ShowAndGetInput(12345, 12346, 0, 0);
75 // show the appropriate lock dialog
76 CStdString strHeading = "";
77 if (pItem->m_bIsFolder)
78 strHeading = g_localizeStrings.Get(12325);
80 strHeading = g_localizeStrings.Get(12348);
82 iResult = VerifyPassword(pItem->m_iLockMode, strLockCode, strHeading);
87 { // user canceled out
93 // password entry succeeded
94 pItem->m_iBadPwdCount = 0;
95 pItem->m_iHasLock = 1;
96 g_passwordManager.LockSource(strType,strLabel,false);
97 sprintf(buffer,"%i",pItem->m_iBadPwdCount);
98 CMediaSourceSettings::Get().UpdateSource(strType, strLabel, "badpwdcount", buffer);
99 CMediaSourceSettings::Get().Save();
104 // password entry failed
105 if (0 != CSettings::Get().GetInt("masterlock.maxretries"))
106 pItem->m_iBadPwdCount++;
107 sprintf(buffer,"%i",pItem->m_iBadPwdCount);
108 CMediaSourceSettings::Get().UpdateSource(strType, strLabel, "badpwdcount", buffer);
109 CMediaSourceSettings::Get().Save();
114 // this should never happen, but if it does, do nothing
123 bool CGUIPassword::CheckStartUpLock()
125 // prompt user for mastercode if the mastercode was set b4 or by xml
126 int iVerifyPasswordResult = -1;
127 CStdString strHeader = g_localizeStrings.Get(20075);
128 if (iMasterLockRetriesLeft == -1)
129 iMasterLockRetriesLeft = CSettings::Get().GetInt("masterlock.maxretries");
130 if (g_passwordManager.iMasterLockRetriesLeft == 0) g_passwordManager.iMasterLockRetriesLeft = 1;
131 CStdString strPassword = CProfilesManager::Get().GetMasterProfile().getLockCode();
132 if (CProfilesManager::Get().GetMasterProfile().getLockMode() == 0)
133 iVerifyPasswordResult = 0;
136 for (int i=1; i <= g_passwordManager.iMasterLockRetriesLeft; i++)
138 iVerifyPasswordResult = VerifyPassword(CProfilesManager::Get().GetMasterProfile().getLockMode(), strPassword, strHeader);
139 if (iVerifyPasswordResult != 0 )
141 CStdString strLabel1;
142 strLabel1 = g_localizeStrings.Get(12343);
143 int iLeft = g_passwordManager.iMasterLockRetriesLeft-i;
144 CStdString strLabel = StringUtils::Format("%i %s", iLeft, strLabel1.c_str());
146 // PopUp OK and Display: MasterLock mode has changed but no no Mastercode has been set!
147 CGUIDialogOK::ShowAndGetInput(20076, 12367, 12368, strLabel);
150 i=g_passwordManager.iMasterLockRetriesLeft;
154 if (iVerifyPasswordResult == 0)
156 g_passwordManager.iMasterLockRetriesLeft = CSettings::Get().GetInt("masterlock.maxretries");
157 return true; // OK The MasterCode Accepted! XBMC Can Run!
161 CApplicationMessenger::Get().Shutdown(); // Turn off the box
166 bool CGUIPassword::SetMasterLockMode(bool bDetails)
168 CProfile* profile = CProfilesManager::Get().GetProfile(0);
171 CProfile::CLock locks = profile->GetLocks();
172 if (CGUIDialogLockSettings::ShowAndGetLock(locks, 12360, true, bDetails))
174 profile->SetLocks(locks);
181 bool CGUIPassword::IsProfileLockUnlocked(int iProfile)
184 return IsProfileLockUnlocked(iProfile,bDummy,true);
187 bool CGUIPassword::IsProfileLockUnlocked(int iProfile, bool& bCanceled, bool prompt)
189 if (g_passwordManager.bMasterUser)
191 int iProfileToCheck=iProfile;
193 iProfileToCheck = CProfilesManager::Get().GetCurrentProfileIndex();
194 if (iProfileToCheck == 0)
195 return IsMasterLockUnlocked(prompt,bCanceled);
198 CProfile *profile = CProfilesManager::Get().GetProfile(iProfileToCheck);
203 return (profile->getLockMode() == LOCK_MODE_EVERYONE);
205 if (profile->getDate().empty() &&
206 (CProfilesManager::Get().GetMasterProfile().getLockMode() == LOCK_MODE_EVERYONE ||
207 profile->getLockMode() == LOCK_MODE_EVERYONE))
209 // user hasn't set a password and this is the first time they've used this account
210 // so prompt for password/settings
211 if (CGUIDialogProfileSettings::ShowForProfile(iProfileToCheck, true))
215 if (CProfilesManager::Get().GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE)
216 return CheckLock(profile->getLockMode(),profile->getLockCode(),20095,bCanceled);
222 bool CGUIPassword::IsMasterLockUnlocked(bool bPromptUser)
225 return IsMasterLockUnlocked(bPromptUser,bDummy);
228 bool CGUIPassword::IsMasterLockUnlocked(bool bPromptUser, bool& bCanceled)
231 if (iMasterLockRetriesLeft == -1)
232 iMasterLockRetriesLeft = CSettings::Get().GetInt("masterlock.maxretries");
233 if ((LOCK_MODE_EVERYONE < CProfilesManager::Get().GetMasterProfile().getLockMode() && !bMasterUser) && !bPromptUser)
234 // not unlocked, but calling code doesn't want to prompt user
237 if (g_passwordManager.bMasterUser || CProfilesManager::Get().GetMasterProfile().getLockMode() == LOCK_MODE_EVERYONE)
240 if (iMasterLockRetriesLeft == 0)
242 UpdateMasterLockRetryCount(false);
246 // no, unlock since we are allowed to prompt
247 int iVerifyPasswordResult = -1;
248 CStdString strHeading = g_localizeStrings.Get(20075);
249 CStdString strPassword = CProfilesManager::Get().GetMasterProfile().getLockCode();
250 iVerifyPasswordResult = VerifyPassword(CProfilesManager::Get().GetMasterProfile().getLockMode(), strPassword, strHeading);
251 if (1 == iVerifyPasswordResult)
252 UpdateMasterLockRetryCount(false);
254 if (0 != iVerifyPasswordResult)
260 // user successfully entered mastercode
261 UpdateMasterLockRetryCount(true);
265 void CGUIPassword::UpdateMasterLockRetryCount(bool bResetCount)
267 // \brief Updates Master Lock status.
268 // \param bResetCount masterlock retry counter is zeroed if true, or incremented and displays an Access Denied dialog if false.
271 // Bad mastercode entered
272 if (0 < CSettings::Get().GetInt("masterlock.maxretries"))
274 // We're keeping track of how many bad passwords are entered
275 if (1 < g_passwordManager.iMasterLockRetriesLeft)
277 // user still has at least one retry after decrementing
278 g_passwordManager.iMasterLockRetriesLeft--;
282 // user has run out of retry attempts
283 g_passwordManager.iMasterLockRetriesLeft = 0;
284 // Tell the user they ran out of retry attempts
285 CGUIDialogOK::ShowAndGetInput(12345, 12346, 0, 0);
289 CStdString dlgLine1 = "";
290 if (0 < g_passwordManager.iMasterLockRetriesLeft)
291 dlgLine1 = StringUtils::Format("%d %s",
292 g_passwordManager.iMasterLockRetriesLeft,
293 g_localizeStrings.Get(12343).c_str());
294 CGUIDialogOK::ShowAndGetInput(20075, 12345, dlgLine1, 0);
297 g_passwordManager.iMasterLockRetriesLeft = CSettings::Get().GetInt("masterlock.maxretries"); // user entered correct mastercode, reset retries to max allowed
300 bool CGUIPassword::CheckLock(LockType btnType, const CStdString& strPassword, int iHeading)
303 return CheckLock(btnType,strPassword,iHeading,bDummy);
306 bool CGUIPassword::CheckLock(LockType btnType, const CStdString& strPassword, int iHeading, bool& bCanceled)
309 if (btnType == LOCK_MODE_EVERYONE || strPassword.Equals("-") ||
310 CProfilesManager::Get().GetMasterProfile().getLockMode() == LOCK_MODE_EVERYONE || g_passwordManager.bMasterUser)
313 int iVerifyPasswordResult = -1;
314 CStdString strHeading = g_localizeStrings.Get(iHeading);
315 iVerifyPasswordResult = VerifyPassword(btnType, strPassword, strHeading);
317 if (iVerifyPasswordResult == -1)
320 return (iVerifyPasswordResult==0);
323 bool CGUIPassword::CheckSettingLevelLock(const SettingLevel& level, bool enforce /*=false*/)
325 LOCK_LEVEL::SETTINGS_LOCK lockLevel = CProfilesManager::Get().GetCurrentProfile().settingsLockLevel();
327 if (lockLevel == LOCK_LEVEL::NONE)
330 //check if we are already in settings and in an level that needs unlocking
331 int windowID = g_windowManager.GetActiveWindow();
332 if ((int)lockLevel-1 <= (short)CViewStateSettings::Get().GetSettingLevel() &&
333 (windowID == WINDOW_SETTINGS_MENU ||
334 (windowID >= WINDOW_SCREEN_CALIBRATION &&
335 windowID <= WINDOW_SETTINGS_MYPVR)))
336 return true; //Already unlocked
338 else if (lockLevel == LOCK_LEVEL::ALL)
339 return IsMasterLockUnlocked(true);
340 else if ((int)lockLevel-1 <= (short)level)
343 return IsMasterLockUnlocked(true);
344 else if (!IsMasterLockUnlocked(false))
346 //Current Setting level is higher than our permission... so lower the viewing level
347 SettingLevel newLevel = (SettingLevel)(short)(lockLevel-2);
348 CViewStateSettings::Get().SetSettingLevel(newLevel);
355 bool IsSettingsWindow(int iWindowID)
357 return (iWindowID >= WINDOW_SCREEN_CALIBRATION && iWindowID <= WINDOW_SETTINGS_MYPVR)
358 || iWindowID == WINDOW_SKIN_SETTINGS;
361 bool CGUIPassword::CheckMenuLock(int iWindowID)
363 bool bCheckPW = false;
364 int iSwitch = iWindowID;
366 // check if a settings subcategory was called from other than settings window
367 if (IsSettingsWindow(iWindowID))
369 int iCWindowID = g_windowManager.GetActiveWindow();
370 if (iCWindowID != WINDOW_SETTINGS_MENU && !IsSettingsWindow(iCWindowID))
371 iSwitch = WINDOW_SETTINGS_MENU;
374 if (iWindowID == WINDOW_MUSIC_FILES)
375 if (g_windowManager.GetActiveWindow() == WINDOW_MUSIC_NAV)
376 iSwitch = WINDOW_HOME;
378 if (iWindowID == WINDOW_MUSIC_NAV)
379 if (g_windowManager.GetActiveWindow() == WINDOW_HOME)
380 iSwitch = WINDOW_MUSIC_FILES;
382 if (iWindowID == WINDOW_VIDEO_NAV)
383 if (g_windowManager.GetActiveWindow() == WINDOW_HOME)
384 iSwitch = WINDOW_VIDEO_FILES;
386 if (iWindowID == WINDOW_VIDEO_FILES)
387 if (g_windowManager.GetActiveWindow() == WINDOW_VIDEO_NAV)
388 iSwitch = WINDOW_HOME;
392 case WINDOW_SETTINGS_MENU: // Settings
393 return CheckSettingLevelLock(CViewStateSettings::Get().GetSettingLevel());
395 case WINDOW_ADDON_BROWSER: // Addons
396 bCheckPW = CProfilesManager::Get().GetCurrentProfile().addonmanagerLocked();
398 case WINDOW_FILES: // Files
399 bCheckPW = CProfilesManager::Get().GetCurrentProfile().filesLocked();
401 case WINDOW_PROGRAMS: // Programs
402 bCheckPW = CProfilesManager::Get().GetCurrentProfile().programsLocked();
404 case WINDOW_MUSIC_FILES: // Music
405 bCheckPW = CProfilesManager::Get().GetCurrentProfile().musicLocked();
407 case WINDOW_VIDEO_FILES: // Video
408 bCheckPW = CProfilesManager::Get().GetCurrentProfile().videoLocked();
410 case WINDOW_PICTURES: // Pictures
411 bCheckPW = CProfilesManager::Get().GetCurrentProfile().picturesLocked();
413 case WINDOW_SETTINGS_PROFILES:
421 return IsMasterLockUnlocked(true); //Now let's check the PW if we need!
426 bool CGUIPassword::LockSource(const CStdString& strType, const CStdString& strName, bool bState)
428 VECSOURCES* pShares = CMediaSourceSettings::Get().GetSources(strType);
429 bool bResult = false;
430 for (IVECSOURCES it=pShares->begin();it != pShares->end();++it)
432 if (it->strName == strName)
434 if (it->m_iHasLock > 0)
436 it->m_iHasLock = bState?2:1;
442 CGUIMessage msg(GUI_MSG_NOTIFY_ALL,0,0,GUI_MSG_UPDATE_SOURCES);
443 g_windowManager.SendThreadMessage(msg);
448 void CGUIPassword::LockSources(bool lock)
450 // lock or unlock all sources (those with locks)
451 const char* strType[5] = {"programs","music","video","pictures","files"};
452 for (int i=0;i<5;++i)
454 VECSOURCES *shares = CMediaSourceSettings::Get().GetSources(strType[i]);
455 for (IVECSOURCES it=shares->begin();it != shares->end();++it)
456 if (it->m_iLockMode != LOCK_MODE_EVERYONE)
457 it->m_iHasLock = lock ? 2 : 1;
459 CGUIMessage msg(GUI_MSG_NOTIFY_ALL,0,0,GUI_MSG_UPDATE_SOURCES);
460 g_windowManager.SendThreadMessage(msg);
463 void CGUIPassword::RemoveSourceLocks()
465 // remove lock from all sources
466 const char* strType[5] = {"programs","music","video","pictures","files"};
467 for (int i=0;i<5;++i)
469 VECSOURCES *shares = CMediaSourceSettings::Get().GetSources(strType[i]);
470 for (IVECSOURCES it=shares->begin();it != shares->end();++it)
471 if (it->m_iLockMode != LOCK_MODE_EVERYONE) // remove old info
474 it->m_iLockMode = LOCK_MODE_EVERYONE;
475 CMediaSourceSettings::Get().UpdateSource(strType[i], it->strName, "lockmode", "0"); // removes locks from xml
478 CMediaSourceSettings::Get().Save();
479 CGUIMessage msg(GUI_MSG_NOTIFY_ALL,0,0, GUI_MSG_UPDATE_SOURCES);
480 g_windowManager.SendThreadMessage(msg);
483 bool CGUIPassword::IsDatabasePathUnlocked(const CStdString& strPath, VECSOURCES& vecSources)
485 if (g_passwordManager.bMasterUser || CProfilesManager::Get().GetMasterProfile().getLockMode() == LOCK_MODE_EVERYONE)
488 // try to find the best matching source
490 int iIndex = CUtil::GetMatchingSource(strPath, vecSources, bName);
492 if (iIndex > -1 && iIndex < (int)vecSources.size())
493 if (vecSources[iIndex].m_iHasLock < 2)
499 void CGUIPassword::OnSettingAction(const CSetting *setting)
504 const std::string &settingId = setting->GetId();
505 if (settingId == "masterlock.lockcode")
509 int CGUIPassword::VerifyPassword(LockType btnType, const CStdString& strPassword, const CStdString& strHeading)
511 int iVerifyPasswordResult;
514 case LOCK_MODE_NUMERIC:
515 iVerifyPasswordResult = CGUIDialogNumeric::ShowAndVerifyPassword(const_cast<CStdString&>(strPassword), strHeading, 0);
517 case LOCK_MODE_GAMEPAD:
518 iVerifyPasswordResult = CGUIDialogGamepad::ShowAndVerifyPassword(const_cast<CStdString&>(strPassword), strHeading, 0);
520 case LOCK_MODE_QWERTY:
521 iVerifyPasswordResult = CGUIKeyboardFactory::ShowAndVerifyPassword(const_cast<CStdString&>(strPassword), strHeading, 0);
523 default: // must not be supported, treat as unlocked
524 iVerifyPasswordResult = 0;
528 return iVerifyPasswordResult;