Fix keymap.
[vuplus_xbmc] / xbmc / GUIPassword.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://xbmc.org
4  *
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)
8  *  any later version.
9  *
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.
14  *
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/>.
18  *
19  */
20
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"
31 #include "Util.h"
32 #include "settings/MediaSourceSettings.h"
33 #include "settings/Settings.h"
34 #include "guilib/GUIWindowManager.h"
35 #include "FileItem.h"
36 #include "guilib/LocalizeStrings.h"
37 #include "utils/log.h"
38 #include "utils/StringUtils.h"
39 #include "view/ViewStateSettings.h"
40
41 CGUIPassword::CGUIPassword(void)
42 {
43   iMasterLockRetriesLeft = -1;
44   bMasterUser = false;
45 }
46 CGUIPassword::~CGUIPassword(void)
47 {}
48
49 bool CGUIPassword::IsItemUnlocked(CFileItem* pItem, const CStdString &strType)
50 {
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)
56     return true;
57
58   while (pItem->m_iHasLock > 1)
59   {
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!
65     {
66       iResult = 0;
67     }
68     else
69     {
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);
73         return false;
74       }
75       // show the appropriate lock dialog
76       CStdString strHeading = "";
77       if (pItem->m_bIsFolder)
78         strHeading = g_localizeStrings.Get(12325);
79       else
80         strHeading = g_localizeStrings.Get(12348);
81
82       iResult = VerifyPassword(pItem->m_iLockMode, strLockCode, strHeading);
83     }
84     switch (iResult)
85     {
86     case -1:
87       { // user canceled out
88         return false;
89         break;
90       }
91     case 0:
92       {
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();
100         break;
101       }
102     case 1:
103       {
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();
110         break;
111       }
112     default:
113       {
114         // this should never happen, but if it does, do nothing
115         return false;
116         break;
117       }
118     }
119   }
120   return true;
121 }
122
123 bool CGUIPassword::CheckStartUpLock()
124 {
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;
134   else
135   {
136     for (int i=1; i <= g_passwordManager.iMasterLockRetriesLeft; i++)
137     {
138       iVerifyPasswordResult = VerifyPassword(CProfilesManager::Get().GetMasterProfile().getLockMode(), strPassword, strHeader);
139       if (iVerifyPasswordResult != 0 )
140       {
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());
145
146         // PopUp OK and Display: MasterLock mode has changed but no no Mastercode has been set!
147         CGUIDialogOK::ShowAndGetInput(20076, 12367, 12368, strLabel);
148       }
149       else
150         i=g_passwordManager.iMasterLockRetriesLeft;
151     }
152   }
153
154   if (iVerifyPasswordResult == 0)
155   {
156     g_passwordManager.iMasterLockRetriesLeft = CSettings::Get().GetInt("masterlock.maxretries");
157     return true;  // OK The MasterCode Accepted! XBMC Can Run!
158   }
159   else
160   {
161     CApplicationMessenger::Get().Shutdown(); // Turn off the box
162     return false;
163   }
164 }
165
166 bool CGUIPassword::SetMasterLockMode(bool bDetails)
167 {
168   CProfile* profile = CProfilesManager::Get().GetProfile(0);
169   if (profile)
170   {
171     CProfile::CLock locks = profile->GetLocks();
172     if (CGUIDialogLockSettings::ShowAndGetLock(locks, 12360, true, bDetails))
173     {
174       profile->SetLocks(locks);
175       return true;
176     }
177   }
178   return false;
179 }
180
181 bool CGUIPassword::IsProfileLockUnlocked(int iProfile)
182 {
183   bool bDummy;
184   return IsProfileLockUnlocked(iProfile,bDummy,true);
185 }
186
187 bool CGUIPassword::IsProfileLockUnlocked(int iProfile, bool& bCanceled, bool prompt)
188 {
189   if (g_passwordManager.bMasterUser)
190     return true;
191   int iProfileToCheck=iProfile;
192   if (iProfile == -1)
193     iProfileToCheck = CProfilesManager::Get().GetCurrentProfileIndex();
194   if (iProfileToCheck == 0)
195     return IsMasterLockUnlocked(prompt,bCanceled);
196   else
197   {
198     CProfile *profile = CProfilesManager::Get().GetProfile(iProfileToCheck);
199     if (!profile)
200       return false;
201
202     if (!prompt)
203       return (profile->getLockMode() == LOCK_MODE_EVERYONE);
204
205     if (profile->getDate().empty() &&
206        (CProfilesManager::Get().GetMasterProfile().getLockMode() == LOCK_MODE_EVERYONE ||
207         profile->getLockMode() == LOCK_MODE_EVERYONE))
208     {
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))
212         return true;
213     }
214     else
215        if (CProfilesManager::Get().GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE)
216         return CheckLock(profile->getLockMode(),profile->getLockCode(),20095,bCanceled);
217   }
218
219   return true;
220 }
221
222 bool CGUIPassword::IsMasterLockUnlocked(bool bPromptUser)
223 {
224   bool bDummy;
225   return IsMasterLockUnlocked(bPromptUser,bDummy);
226 }
227
228 bool CGUIPassword::IsMasterLockUnlocked(bool bPromptUser, bool& bCanceled)
229 {
230   bCanceled = false;
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
235     return false;
236
237   if (g_passwordManager.bMasterUser || CProfilesManager::Get().GetMasterProfile().getLockMode() == LOCK_MODE_EVERYONE)
238     return true;
239
240   if (iMasterLockRetriesLeft == 0)
241   {
242     UpdateMasterLockRetryCount(false);
243     return false;
244   }
245
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);
253
254   if (0 != iVerifyPasswordResult)
255   {
256     bCanceled = true;
257     return false;
258   }
259
260   // user successfully entered mastercode
261   UpdateMasterLockRetryCount(true);
262   return true;
263 }
264
265 void CGUIPassword::UpdateMasterLockRetryCount(bool bResetCount)
266 {
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.
269   if (!bResetCount)
270   {
271     // Bad mastercode entered
272     if (0 < CSettings::Get().GetInt("masterlock.maxretries"))
273     {
274       // We're keeping track of how many bad passwords are entered
275       if (1 < g_passwordManager.iMasterLockRetriesLeft)
276       {
277         // user still has at least one retry after decrementing
278         g_passwordManager.iMasterLockRetriesLeft--;
279       }
280       else
281       {
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);
286         return ;
287       }
288     }
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);
295   }
296   else
297     g_passwordManager.iMasterLockRetriesLeft = CSettings::Get().GetInt("masterlock.maxretries"); // user entered correct mastercode, reset retries to max allowed
298 }
299
300 bool CGUIPassword::CheckLock(LockType btnType, const CStdString& strPassword, int iHeading)
301 {
302   bool bDummy;
303   return CheckLock(btnType,strPassword,iHeading,bDummy);
304 }
305
306 bool CGUIPassword::CheckLock(LockType btnType, const CStdString& strPassword, int iHeading, bool& bCanceled)
307 {
308   bCanceled = false;
309   if (btnType == LOCK_MODE_EVERYONE || strPassword.Equals("-")        ||
310       CProfilesManager::Get().GetMasterProfile().getLockMode() == LOCK_MODE_EVERYONE || g_passwordManager.bMasterUser)
311     return true;
312
313   int iVerifyPasswordResult = -1;
314   CStdString strHeading = g_localizeStrings.Get(iHeading);
315   iVerifyPasswordResult = VerifyPassword(btnType, strPassword, strHeading);
316
317   if (iVerifyPasswordResult == -1)
318     bCanceled = true;
319
320   return (iVerifyPasswordResult==0);
321 }
322
323 bool CGUIPassword::CheckSettingLevelLock(const SettingLevel& level, bool enforce /*=false*/)
324 {
325   LOCK_LEVEL::SETTINGS_LOCK lockLevel = CProfilesManager::Get().GetCurrentProfile().settingsLockLevel();
326   
327   if (lockLevel == LOCK_LEVEL::NONE)
328     return true;
329   
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
337   
338   else if (lockLevel == LOCK_LEVEL::ALL)
339     return IsMasterLockUnlocked(true);
340   else if ((int)lockLevel-1 <= (short)level)
341   {
342     if (enforce)
343       return IsMasterLockUnlocked(true);
344     else if (!IsMasterLockUnlocked(false))
345     {
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);
349     }
350   }
351   return true;
352
353 }
354
355 bool IsSettingsWindow(int iWindowID)
356 {
357   return (iWindowID >= WINDOW_SCREEN_CALIBRATION && iWindowID <= WINDOW_SETTINGS_MYPVR)
358        || iWindowID == WINDOW_SKIN_SETTINGS;
359 }
360
361 bool CGUIPassword::CheckMenuLock(int iWindowID)
362 {
363   bool bCheckPW         = false;
364   int iSwitch = iWindowID;
365
366   // check if a settings subcategory was called from other than settings window
367   if (IsSettingsWindow(iWindowID))
368   {
369     int iCWindowID = g_windowManager.GetActiveWindow();
370     if (iCWindowID != WINDOW_SETTINGS_MENU && !IsSettingsWindow(iCWindowID))
371       iSwitch = WINDOW_SETTINGS_MENU;
372   }
373
374   if (iWindowID == WINDOW_MUSIC_FILES)
375     if (g_windowManager.GetActiveWindow() == WINDOW_MUSIC_NAV)
376       iSwitch = WINDOW_HOME;
377
378   if (iWindowID == WINDOW_MUSIC_NAV)
379     if (g_windowManager.GetActiveWindow() == WINDOW_HOME)
380       iSwitch = WINDOW_MUSIC_FILES;
381
382   if (iWindowID == WINDOW_VIDEO_NAV)
383     if (g_windowManager.GetActiveWindow() == WINDOW_HOME)
384       iSwitch = WINDOW_VIDEO_FILES;
385
386   if (iWindowID == WINDOW_VIDEO_FILES)
387     if (g_windowManager.GetActiveWindow() == WINDOW_VIDEO_NAV)
388       iSwitch = WINDOW_HOME;
389
390   switch (iSwitch)
391   {
392     case WINDOW_SETTINGS_MENU:  // Settings
393       return CheckSettingLevelLock(CViewStateSettings::Get().GetSettingLevel());
394       break;
395     case WINDOW_ADDON_BROWSER:  // Addons
396       bCheckPW = CProfilesManager::Get().GetCurrentProfile().addonmanagerLocked();
397       break;
398     case WINDOW_FILES:          // Files
399       bCheckPW = CProfilesManager::Get().GetCurrentProfile().filesLocked();
400       break;
401     case WINDOW_PROGRAMS:       // Programs
402       bCheckPW = CProfilesManager::Get().GetCurrentProfile().programsLocked();
403       break;
404     case WINDOW_MUSIC_FILES:    // Music
405       bCheckPW = CProfilesManager::Get().GetCurrentProfile().musicLocked();
406       break;
407     case WINDOW_VIDEO_FILES:    // Video
408       bCheckPW = CProfilesManager::Get().GetCurrentProfile().videoLocked();
409       break;
410     case WINDOW_PICTURES:       // Pictures
411       bCheckPW = CProfilesManager::Get().GetCurrentProfile().picturesLocked();
412       break;
413     case WINDOW_SETTINGS_PROFILES:
414       bCheckPW = true;
415       break;
416     default:
417       bCheckPW = false;
418       break;
419   }
420   if (bCheckPW)
421     return IsMasterLockUnlocked(true); //Now let's check the PW if we need!
422   else
423     return true;
424 }
425
426 bool CGUIPassword::LockSource(const CStdString& strType, const CStdString& strName, bool bState)
427 {
428   VECSOURCES* pShares = CMediaSourceSettings::Get().GetSources(strType);
429   bool bResult = false;
430   for (IVECSOURCES it=pShares->begin();it != pShares->end();++it)
431   {
432     if (it->strName == strName)
433     {
434       if (it->m_iHasLock > 0)
435       {
436         it->m_iHasLock = bState?2:1;
437         bResult = true;
438       }
439       break;
440     }
441   }
442   CGUIMessage msg(GUI_MSG_NOTIFY_ALL,0,0,GUI_MSG_UPDATE_SOURCES);
443   g_windowManager.SendThreadMessage(msg);
444
445   return bResult;
446 }
447
448 void CGUIPassword::LockSources(bool lock)
449 {
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)
453   {
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;
458   }
459   CGUIMessage msg(GUI_MSG_NOTIFY_ALL,0,0,GUI_MSG_UPDATE_SOURCES);
460   g_windowManager.SendThreadMessage(msg);
461 }
462
463 void CGUIPassword::RemoveSourceLocks()
464 {
465   // remove lock from all sources
466   const char* strType[5] = {"programs","music","video","pictures","files"};
467   for (int i=0;i<5;++i)
468   {
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
472       {
473         it->m_iHasLock = 0;
474         it->m_iLockMode = LOCK_MODE_EVERYONE;
475         CMediaSourceSettings::Get().UpdateSource(strType[i], it->strName, "lockmode", "0"); // removes locks from xml
476       }
477   }
478   CMediaSourceSettings::Get().Save();
479   CGUIMessage msg(GUI_MSG_NOTIFY_ALL,0,0, GUI_MSG_UPDATE_SOURCES);
480   g_windowManager.SendThreadMessage(msg);
481 }
482
483 bool CGUIPassword::IsDatabasePathUnlocked(const CStdString& strPath, VECSOURCES& vecSources)
484 {
485   if (g_passwordManager.bMasterUser || CProfilesManager::Get().GetMasterProfile().getLockMode() == LOCK_MODE_EVERYONE)
486     return true;
487
488   // try to find the best matching source
489   bool bName = false;
490   int iIndex = CUtil::GetMatchingSource(strPath, vecSources, bName);
491
492   if (iIndex > -1 && iIndex < (int)vecSources.size())
493     if (vecSources[iIndex].m_iHasLock < 2)
494       return true;
495
496   return false;
497 }
498
499 void CGUIPassword::OnSettingAction(const CSetting *setting)
500 {
501   if (setting == NULL)
502     return;
503
504   const std::string &settingId = setting->GetId();
505   if (settingId == "masterlock.lockcode")
506     SetMasterLockMode();
507 }
508
509 int CGUIPassword::VerifyPassword(LockType btnType, const CStdString& strPassword, const CStdString& strHeading)
510 {
511   int iVerifyPasswordResult;
512   switch (btnType)
513   {
514   case LOCK_MODE_NUMERIC:
515     iVerifyPasswordResult = CGUIDialogNumeric::ShowAndVerifyPassword(const_cast<CStdString&>(strPassword), strHeading, 0);
516     break;
517   case LOCK_MODE_GAMEPAD:
518     iVerifyPasswordResult = CGUIDialogGamepad::ShowAndVerifyPassword(const_cast<CStdString&>(strPassword), strHeading, 0);
519     break;
520   case LOCK_MODE_QWERTY:
521     iVerifyPasswordResult = CGUIKeyboardFactory::ShowAndVerifyPassword(const_cast<CStdString&>(strPassword), strHeading, 0);
522     break;
523   default:   // must not be supported, treat as unlocked
524     iVerifyPasswordResult = 0;
525     break;
526   }
527
528   return iVerifyPasswordResult;
529 }
530