2 * Copyright (C) 2005-2012 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 "settings/GUIDialogLockSettings.h"
29 #include "settings/GUIDialogProfileSettings.h"
31 #include "settings/Settings.h"
32 #include "settings/GUISettings.h"
33 #include "guilib/GUIWindowManager.h"
35 #include "guilib/LocalizeStrings.h"
36 #include "utils/log.h"
38 CGUIPassword::CGUIPassword(void)
40 iMasterLockRetriesLeft = -1;
43 CGUIPassword::~CGUIPassword(void)
46 bool CGUIPassword::IsItemUnlocked(CFileItem* pItem, const CStdString &strType)
48 // \brief Tests if the user is allowed to access the share folder
49 // \param pItem The share folder item to access
50 // \param strType The type of share being accessed, e.g. "music", "video", etc. See CSettings::UpdateSources()
51 // \return If access is granted, returns \e true
52 if (g_settings.GetMasterProfile().getLockMode() == LOCK_MODE_EVERYONE)
55 while (pItem->m_iHasLock > 1)
57 CStdString strLockCode = pItem->m_strLockCode;
58 CStdString strLabel = pItem->GetLabel();
59 int iResult = 0; // init to user succeeded state, doing this to optimize switch statement below
60 char buffer[33]; // holds 32 places plus sign character
61 if(g_passwordManager.bMasterUser)// Check if we are the MasterUser!
67 if (0 != g_guiSettings.GetInt("masterlock.maxretries") && pItem->m_iBadPwdCount >= g_guiSettings.GetInt("masterlock.maxretries"))
68 { // user previously exhausted all retries, show access denied error
69 CGUIDialogOK::ShowAndGetInput(12345, 12346, 0, 0);
72 // show the appropriate lock dialog
73 CStdString strHeading = "";
74 if (pItem->m_bIsFolder)
75 strHeading = g_localizeStrings.Get(12325);
77 strHeading = g_localizeStrings.Get(12348);
79 iResult = VerifyPassword(pItem->m_iLockMode, strLockCode, strHeading);
84 { // user canceled out
90 // password entry succeeded
91 pItem->m_iBadPwdCount = 0;
92 pItem->m_iHasLock = 1;
93 g_passwordManager.LockSource(strType,strLabel,false);
94 sprintf(buffer,"%i",pItem->m_iBadPwdCount);
95 g_settings.UpdateSource(strType, strLabel, "badpwdcount", buffer);
96 g_settings.SaveSources();
101 // password entry failed
102 if (0 != g_guiSettings.GetInt("masterlock.maxretries"))
103 pItem->m_iBadPwdCount++;
104 sprintf(buffer,"%i",pItem->m_iBadPwdCount);
105 g_settings.UpdateSource(strType, strLabel, "badpwdcount", buffer);
106 g_settings.SaveSources();
111 // this should never happen, but if it does, do nothing
120 bool CGUIPassword::CheckStartUpLock()
122 // prompt user for mastercode if the mastercode was set b4 or by xml
123 int iVerifyPasswordResult = -1;
124 CStdString strHeader = g_localizeStrings.Get(20075);
125 if (iMasterLockRetriesLeft == -1)
126 iMasterLockRetriesLeft = g_guiSettings.GetInt("masterlock.maxretries");
127 if (g_passwordManager.iMasterLockRetriesLeft == 0) g_passwordManager.iMasterLockRetriesLeft = 1;
128 CStdString strPassword = g_settings.GetMasterProfile().getLockCode();
129 if (g_settings.GetMasterProfile().getLockMode() == 0)
130 iVerifyPasswordResult = 0;
133 for (int i=1; i <= g_passwordManager.iMasterLockRetriesLeft; i++)
135 iVerifyPasswordResult = VerifyPassword(g_settings.GetMasterProfile().getLockMode(), strPassword, strHeader);
136 if (iVerifyPasswordResult != 0 )
138 CStdString strLabel,strLabel1;
139 strLabel1 = g_localizeStrings.Get(12343);
140 int iLeft = g_passwordManager.iMasterLockRetriesLeft-i;
141 strLabel.Format("%i %s",iLeft,strLabel1.c_str());
143 // PopUp OK and Display: MasterLock mode has changed but no no Mastercode has been set!
144 CGUIDialogOK::ShowAndGetInput(20076, 12367, 12368, strLabel);
147 i=g_passwordManager.iMasterLockRetriesLeft;
151 if (iVerifyPasswordResult == 0)
153 g_passwordManager.iMasterLockRetriesLeft = g_guiSettings.GetInt("masterlock.maxretries");
154 return true; // OK The MasterCode Accepted! XBMC Can Run!
158 CApplicationMessenger::Get().Shutdown(); // Turn off the box
163 bool CGUIPassword::SetMasterLockMode(bool bDetails)
165 CProfile* profile = g_settings.GetProfile(0);
168 CProfile::CLock locks = profile->GetLocks();
169 if (CGUIDialogLockSettings::ShowAndGetLock(locks, 12360, true, bDetails))
171 profile->SetLocks(locks);
178 bool CGUIPassword::IsProfileLockUnlocked(int iProfile)
181 return IsProfileLockUnlocked(iProfile,bDummy,true);
184 bool CGUIPassword::IsProfileLockUnlocked(int iProfile, bool& bCanceled, bool prompt)
186 if (g_passwordManager.bMasterUser)
188 int iProfileToCheck=iProfile;
190 iProfileToCheck = g_settings.GetCurrentProfileIndex();
191 if (iProfileToCheck == 0)
192 return IsMasterLockUnlocked(prompt,bCanceled);
195 CProfile *profile = g_settings.GetProfile(iProfileToCheck);
200 return (profile->getLockMode() == LOCK_MODE_EVERYONE);
202 if (profile->getDate().IsEmpty() &&
203 (g_settings.GetMasterProfile().getLockMode() == LOCK_MODE_EVERYONE ||
204 profile->getLockMode() == LOCK_MODE_EVERYONE))
206 // user hasn't set a password and this is the first time they've used this account
207 // so prompt for password/settings
208 if (CGUIDialogProfileSettings::ShowForProfile(iProfileToCheck, true))
212 if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE)
213 return CheckLock(profile->getLockMode(),profile->getLockCode(),20095,bCanceled);
219 bool CGUIPassword::IsMasterLockUnlocked(bool bPromptUser)
222 return IsMasterLockUnlocked(bPromptUser,bDummy);
225 bool CGUIPassword::IsMasterLockUnlocked(bool bPromptUser, bool& bCanceled)
228 if (iMasterLockRetriesLeft == -1)
229 iMasterLockRetriesLeft = g_guiSettings.GetInt("masterlock.maxretries");
230 if ((LOCK_MODE_EVERYONE < g_settings.GetMasterProfile().getLockMode() && !bMasterUser) && !bPromptUser)
231 // not unlocked, but calling code doesn't want to prompt user
234 if (g_passwordManager.bMasterUser || g_settings.GetMasterProfile().getLockMode() == LOCK_MODE_EVERYONE)
237 if (iMasterLockRetriesLeft == 0)
239 UpdateMasterLockRetryCount(false);
243 // no, unlock since we are allowed to prompt
244 int iVerifyPasswordResult = -1;
245 CStdString strHeading = g_localizeStrings.Get(20075);
246 CStdString strPassword = g_settings.GetMasterProfile().getLockCode();
247 iVerifyPasswordResult = VerifyPassword(g_settings.GetMasterProfile().getLockMode(), strPassword, strHeading);
248 if (1 == iVerifyPasswordResult)
249 UpdateMasterLockRetryCount(false);
251 if (0 != iVerifyPasswordResult)
257 // user successfully entered mastercode
258 UpdateMasterLockRetryCount(true);
262 void CGUIPassword::UpdateMasterLockRetryCount(bool bResetCount)
264 // \brief Updates Master Lock status.
265 // \param bResetCount masterlock retry counter is zeroed if true, or incremented and displays an Access Denied dialog if false.
268 // Bad mastercode entered
269 if (0 < g_guiSettings.GetInt("masterlock.maxretries"))
271 // We're keeping track of how many bad passwords are entered
272 if (1 < g_passwordManager.iMasterLockRetriesLeft)
274 // user still has at least one retry after decrementing
275 g_passwordManager.iMasterLockRetriesLeft--;
279 // user has run out of retry attempts
280 g_passwordManager.iMasterLockRetriesLeft = 0;
281 // Tell the user they ran out of retry attempts
282 CGUIDialogOK::ShowAndGetInput(12345, 12346, 0, 0);
286 CStdString dlgLine1 = "";
287 if (0 < g_passwordManager.iMasterLockRetriesLeft)
288 dlgLine1.Format("%d %s", g_passwordManager.iMasterLockRetriesLeft, g_localizeStrings.Get(12343));
289 CGUIDialogOK::ShowAndGetInput(20075, 12345, dlgLine1, 0);
292 g_passwordManager.iMasterLockRetriesLeft = g_guiSettings.GetInt("masterlock.maxretries"); // user entered correct mastercode, reset retries to max allowed
295 bool CGUIPassword::CheckLock(LockType btnType, const CStdString& strPassword, int iHeading)
298 return CheckLock(btnType,strPassword,iHeading,bDummy);
301 bool CGUIPassword::CheckLock(LockType btnType, const CStdString& strPassword, int iHeading, bool& bCanceled)
304 if (btnType == LOCK_MODE_EVERYONE || strPassword.Equals("-") ||
305 g_settings.GetMasterProfile().getLockMode() == LOCK_MODE_EVERYONE || g_passwordManager.bMasterUser)
308 int iVerifyPasswordResult = -1;
309 CStdString strHeading = g_localizeStrings.Get(iHeading);
310 iVerifyPasswordResult = VerifyPassword(btnType, strPassword, strHeading);
312 if (iVerifyPasswordResult == -1)
315 return (iVerifyPasswordResult==0);
318 bool CGUIPassword::CheckMenuLock(int iWindowID)
320 bool bCheckPW = false;
321 int iSwitch = iWindowID;
323 // check if a settings subcategory was called from other than settings window
324 if (iWindowID >= WINDOW_SCREEN_CALIBRATION && iWindowID <= WINDOW_SETTINGS_APPEARANCE)
326 int iCWindowID = g_windowManager.GetActiveWindow();
327 if (iCWindowID != WINDOW_SETTINGS_MENU && (iCWindowID < WINDOW_SCREEN_CALIBRATION || iCWindowID > WINDOW_SETTINGS_APPEARANCE))
328 iSwitch = WINDOW_SETTINGS_MENU;
331 if (iWindowID == WINDOW_MUSIC_FILES)
332 if (g_windowManager.GetActiveWindow() == WINDOW_MUSIC_NAV)
333 iSwitch = WINDOW_HOME;
335 if (iWindowID == WINDOW_MUSIC_NAV)
336 if (g_windowManager.GetActiveWindow() == WINDOW_HOME)
337 iSwitch = WINDOW_MUSIC_FILES;
339 if (iWindowID == WINDOW_VIDEO_NAV)
340 if (g_windowManager.GetActiveWindow() == WINDOW_HOME)
341 iSwitch = WINDOW_VIDEO_FILES;
343 if (iWindowID == WINDOW_VIDEO_FILES)
344 if (g_windowManager.GetActiveWindow() == WINDOW_VIDEO_NAV)
345 iSwitch = WINDOW_HOME;
349 case WINDOW_SETTINGS_MENU: // Settings
350 bCheckPW = g_settings.GetCurrentProfile().settingsLocked();
352 case WINDOW_ADDON_BROWSER: // Addons
353 bCheckPW = g_settings.GetCurrentProfile().addonmanagerLocked();
355 case WINDOW_FILES: // Files
356 bCheckPW = g_settings.GetCurrentProfile().filesLocked();
358 case WINDOW_PROGRAMS: // Programs
359 bCheckPW = g_settings.GetCurrentProfile().programsLocked();
361 case WINDOW_MUSIC_FILES: // Music
362 bCheckPW = g_settings.GetCurrentProfile().musicLocked();
364 case WINDOW_VIDEO_FILES: // Video
365 bCheckPW = g_settings.GetCurrentProfile().videoLocked();
367 case WINDOW_PICTURES: // Pictures
368 bCheckPW = g_settings.GetCurrentProfile().picturesLocked();
370 case WINDOW_SETTINGS_PROFILES:
378 return IsMasterLockUnlocked(true); //Now let's check the PW if we need!
383 bool CGUIPassword::LockSource(const CStdString& strType, const CStdString& strName, bool bState)
385 VECSOURCES* pShares = g_settings.GetSourcesFromType(strType);
386 bool bResult = false;
387 for (IVECSOURCES it=pShares->begin();it != pShares->end();++it)
389 if (it->strName == strName)
391 if (it->m_iHasLock > 0)
393 it->m_iHasLock = bState?2:1;
399 CGUIMessage msg(GUI_MSG_NOTIFY_ALL,0,0,GUI_MSG_UPDATE_SOURCES);
400 g_windowManager.SendThreadMessage(msg);
405 void CGUIPassword::LockSources(bool lock)
407 // lock or unlock all sources (those with locks)
408 const char* strType[5] = {"programs","music","video","pictures","files"};
409 for (int i=0;i<5;++i)
411 VECSOURCES *shares = g_settings.GetSourcesFromType(strType[i]);
412 for (IVECSOURCES it=shares->begin();it != shares->end();++it)
413 if (it->m_iLockMode != LOCK_MODE_EVERYONE)
414 it->m_iHasLock = lock ? 2 : 1;
416 CGUIMessage msg(GUI_MSG_NOTIFY_ALL,0,0,GUI_MSG_UPDATE_SOURCES);
417 g_windowManager.SendThreadMessage(msg);
420 void CGUIPassword::RemoveSourceLocks()
422 // remove lock from all sources
423 const char* strType[5] = {"programs","music","video","pictures","files"};
424 for (int i=0;i<5;++i)
426 VECSOURCES *shares = g_settings.GetSourcesFromType(strType[i]);
427 for (IVECSOURCES it=shares->begin();it != shares->end();++it)
428 if (it->m_iLockMode != LOCK_MODE_EVERYONE) // remove old info
431 it->m_iLockMode = LOCK_MODE_EVERYONE;
432 g_settings.UpdateSource(strType[i],it->strName,"lockmode","0"); // removes locks from xml
435 g_settings.SaveSources();
436 CGUIMessage msg(GUI_MSG_NOTIFY_ALL,0,0, GUI_MSG_UPDATE_SOURCES);
437 g_windowManager.SendThreadMessage(msg);
440 bool CGUIPassword::IsDatabasePathUnlocked(const CStdString& strPath, VECSOURCES& vecSources)
442 if (g_passwordManager.bMasterUser || g_settings.GetMasterProfile().getLockMode() == LOCK_MODE_EVERYONE)
445 // try to find the best matching source
447 int iIndex = CUtil::GetMatchingSource(strPath, vecSources, bName);
449 if (iIndex > -1 && iIndex < (int)vecSources.size())
450 if (vecSources[iIndex].m_iHasLock < 2)
456 int CGUIPassword::VerifyPassword(LockType btnType, const CStdString& strPassword, const CStdString& strHeading)
458 int iVerifyPasswordResult;
461 case LOCK_MODE_NUMERIC:
462 iVerifyPasswordResult = CGUIDialogNumeric::ShowAndVerifyPassword(const_cast<CStdString&>(strPassword), strHeading, 0);
464 case LOCK_MODE_GAMEPAD:
465 iVerifyPasswordResult = CGUIDialogGamepad::ShowAndVerifyPassword(const_cast<CStdString&>(strPassword), strHeading, 0);
467 case LOCK_MODE_QWERTY:
468 iVerifyPasswordResult = CGUIKeyboardFactory::ShowAndVerifyPassword(const_cast<CStdString&>(strPassword), strHeading, 0);
470 default: // must not be supported, treat as unlocked
471 iVerifyPasswordResult = 0;
475 return iVerifyPasswordResult;