Merge pull request #206 from cptspiff/remove-convutils
[vuplus_xbmc] / xbmc / GUIPassword.cpp
1 /*
2  *      Copyright (C) 2005-2008 Team XBMC
3  *      http://www.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, write to
17  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18  *  http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21
22 #include "GUIPassword.h"
23 #include "GUIUserMessages.h"
24 #include "Application.h"
25 #include "dialogs/GUIDialogGamepad.h"
26 #include "dialogs/GUIDialogKeyboard.h"
27 #include "dialogs/GUIDialogNumeric.h"
28 #include "dialogs/GUIDialogOK.h"
29 #include "settings/GUIDialogLockSettings.h"
30 #include "settings/GUIDialogProfileSettings.h"
31 #include "Util.h"
32 #include "URL.h"
33 #include "settings/Settings.h"
34 #include "settings/GUISettings.h"
35 #include "guilib/GUIWindowManager.h"
36 #include "FileItem.h"
37 #include "guilib/LocalizeStrings.h"
38 #include "utils/log.h"
39
40 CGUIPassword::CGUIPassword(void)
41 {
42   iMasterLockRetriesLeft = -1;
43   bMasterUser = false;
44 }
45 CGUIPassword::~CGUIPassword(void)
46 {}
47
48 bool CGUIPassword::IsItemUnlocked(CFileItem* pItem, const CStdString &strType)
49 {
50   // \brief Tests if the user is allowed to access the share folder
51   // \param pItem The share folder item to access
52   // \param strType The type of share being accessed, e.g. "music", "video", etc. See CSettings::UpdateSources()
53   // \return If access is granted, returns \e true
54   if (g_settings.GetMasterProfile().getLockMode() == LOCK_MODE_EVERYONE)
55     return true;
56
57   while (pItem->m_iHasLock > 1)
58   {
59     CStdString strLockCode = pItem->m_strLockCode;
60     CStdString strLabel = pItem->GetLabel();
61     int iResult = 0;  // init to user succeeded state, doing this to optimize switch statement below
62     char buffer[33]; // holds 32 places plus sign character
63     if(g_passwordManager.bMasterUser)// Check if we are the MasterUser!
64     {
65       iResult = 0;
66     }
67     else
68     {
69       if (0 != g_guiSettings.GetInt("masterlock.maxretries") && pItem->m_iBadPwdCount >= g_guiSettings.GetInt("masterlock.maxretries"))
70       { // user previously exhausted all retries, show access denied error
71         CGUIDialogOK::ShowAndGetInput(12345, 12346, 0, 0);
72         return false;
73       }
74       // show the appropriate lock dialog
75       CStdString strHeading = "";
76       if (pItem->m_bIsFolder)
77         strHeading = g_localizeStrings.Get(12325);
78       else
79         strHeading = g_localizeStrings.Get(12348);
80
81       iResult = VerifyPassword(pItem->m_iLockMode, strLockCode, strHeading);
82     }
83     switch (iResult)
84     {
85     case -1:
86       { // user canceled out
87         return false;
88         break;
89       }
90     case 0:
91       {
92         // password entry succeeded
93         pItem->m_iBadPwdCount = 0;
94         pItem->m_iHasLock = 1;
95         g_passwordManager.LockSource(strType,strLabel,false);
96         sprintf(buffer,"%i",pItem->m_iBadPwdCount);
97         g_settings.UpdateSource(strType, strLabel, "badpwdcount", buffer);
98         g_settings.SaveSources();
99         break;
100       }
101     case 1:
102       {
103         // password entry failed
104         if (0 != g_guiSettings.GetInt("masterlock.maxretries"))
105           pItem->m_iBadPwdCount++;
106         sprintf(buffer,"%i",pItem->m_iBadPwdCount);
107         g_settings.UpdateSource(strType, strLabel, "badpwdcount", buffer);
108         g_settings.SaveSources();
109         break;
110       }
111     default:
112       {
113         // this should never happen, but if it does, do nothing
114         return false;
115         break;
116       }
117     }
118   }
119   return true;
120 }
121
122 bool CGUIPassword::CheckStartUpLock()
123 {
124   // prompt user for mastercode if the mastercode was set b4 or by xml
125   int iVerifyPasswordResult = -1;
126   CStdString strHeader = g_localizeStrings.Get(20075);
127   if (iMasterLockRetriesLeft == -1)
128     iMasterLockRetriesLeft = g_guiSettings.GetInt("masterlock.maxretries");
129   if (g_passwordManager.iMasterLockRetriesLeft == 0) g_passwordManager.iMasterLockRetriesLeft = 1;
130   CStdString strPassword = g_settings.GetMasterProfile().getLockCode();
131   if (g_settings.GetMasterProfile().getLockMode() == 0)
132     iVerifyPasswordResult = 0;
133   else
134   {
135     for (int i=1; i <= g_passwordManager.iMasterLockRetriesLeft; i++)
136     {
137       iVerifyPasswordResult = VerifyPassword(g_settings.GetMasterProfile().getLockMode(), strPassword, strHeader);
138       if (iVerifyPasswordResult != 0 )
139       {
140         CStdString strLabel,strLabel1;
141         strLabel1 = g_localizeStrings.Get(12343);
142         int iLeft = g_passwordManager.iMasterLockRetriesLeft-i;
143         strLabel.Format("%i %s",iLeft,strLabel1.c_str());
144
145         // PopUp OK and Display: MasterLock mode has changed but no no Mastercode has been set!
146         CGUIDialogOK::ShowAndGetInput(20076, 12367, 12368, strLabel);
147       }
148       else
149         i=g_passwordManager.iMasterLockRetriesLeft;
150     }
151   }
152
153   if (iVerifyPasswordResult == 0)
154   {
155     g_passwordManager.iMasterLockRetriesLeft = g_guiSettings.GetInt("masterlock.maxretries");
156     return true;  // OK The MasterCode Accepted! XBMC Can Run!
157   }
158   else
159   {
160     g_application.getApplicationMessenger().Shutdown(); // Turn off the box
161     return false;
162   }
163 }
164
165 bool CGUIPassword::SetMasterLockMode(bool bDetails)
166 {
167   CProfile* profile = g_settings.GetProfile(0);
168   if (profile)
169   {
170     CProfile::CLock locks = profile->GetLocks();
171     if (CGUIDialogLockSettings::ShowAndGetLock(locks, 12360, true, bDetails))
172     {
173       profile->SetLocks(locks);
174       return true;
175     }
176   }
177   return false;
178 }
179
180 bool CGUIPassword::IsProfileLockUnlocked(int iProfile)
181 {
182   bool bDummy;
183   return IsProfileLockUnlocked(iProfile,bDummy,true);
184 }
185
186 bool CGUIPassword::IsProfileLockUnlocked(int iProfile, bool& bCanceled, bool prompt)
187 {
188   if (g_passwordManager.bMasterUser)
189     return true;
190   int iProfileToCheck=iProfile;
191   if (iProfile == -1)
192     iProfileToCheck = g_settings.GetCurrentProfileIndex();
193   if (iProfileToCheck == 0)
194     return IsMasterLockUnlocked(prompt,bCanceled);
195   else
196   {
197     CProfile *profile = g_settings.GetProfile(iProfileToCheck);
198     if (!profile)
199       return false;
200
201     if (!prompt)
202       return (profile->getLockMode() == LOCK_MODE_EVERYONE);
203
204     if (profile->getDate().IsEmpty() &&
205        (g_settings.GetMasterProfile().getLockMode() == LOCK_MODE_EVERYONE ||
206         profile->getLockMode() == LOCK_MODE_EVERYONE))
207     {
208       // user hasn't set a password and this is the first time they've used this account
209       // so prompt for password/settings
210       if (CGUIDialogProfileSettings::ShowForProfile(iProfileToCheck, true))
211         return true;
212     }
213     else
214        if (g_settings.GetMasterProfile().getLockMode() != LOCK_MODE_EVERYONE)
215         return CheckLock(profile->getLockMode(),profile->getLockCode(),20095,bCanceled);
216   }
217
218   return true;
219 }
220
221 bool CGUIPassword::IsMasterLockUnlocked(bool bPromptUser)
222 {
223   bool bDummy;
224   return IsMasterLockUnlocked(bPromptUser,bDummy);
225 }
226
227 bool CGUIPassword::IsMasterLockUnlocked(bool bPromptUser, bool& bCanceled)
228 {
229   bCanceled = false;
230   if (iMasterLockRetriesLeft == -1)
231     iMasterLockRetriesLeft = g_guiSettings.GetInt("masterlock.maxretries");
232   if ((LOCK_MODE_EVERYONE < g_settings.GetMasterProfile().getLockMode() && !bMasterUser) && !bPromptUser)
233     // not unlocked, but calling code doesn't want to prompt user
234     return false;
235
236   if (g_passwordManager.bMasterUser || g_settings.GetMasterProfile().getLockMode() == LOCK_MODE_EVERYONE)
237     return true;
238
239   if (iMasterLockRetriesLeft == 0)
240   {
241     UpdateMasterLockRetryCount(false);
242     return false;
243   }
244
245   // no, unlock since we are allowed to prompt
246   int iVerifyPasswordResult = -1;
247   CStdString strHeading = g_localizeStrings.Get(20075);
248   CStdString strPassword = g_settings.GetMasterProfile().getLockCode();
249   iVerifyPasswordResult = VerifyPassword(g_settings.GetMasterProfile().getLockMode(), strPassword, strHeading);
250   if (1 == iVerifyPasswordResult)
251     UpdateMasterLockRetryCount(false);
252
253   if (0 != iVerifyPasswordResult)
254   {
255     bCanceled = true;
256     return false;
257   }
258
259   // user successfully entered mastercode
260   UpdateMasterLockRetryCount(true);
261   return true;
262 }
263
264 void CGUIPassword::UpdateMasterLockRetryCount(bool bResetCount)
265 {
266   // \brief Updates Master Lock status.
267   // \param bResetCount masterlock retry counter is zeroed if true, or incremented and displays an Access Denied dialog if false.
268   if (!bResetCount)
269   {
270     // Bad mastercode entered
271     if (0 < g_guiSettings.GetInt("masterlock.maxretries"))
272     {
273       // We're keeping track of how many bad passwords are entered
274       if (1 < g_passwordManager.iMasterLockRetriesLeft)
275       {
276         // user still has at least one retry after decrementing
277         g_passwordManager.iMasterLockRetriesLeft--;
278       }
279       else
280       {
281         // user has run out of retry attempts
282         g_passwordManager.iMasterLockRetriesLeft = 0;
283         // Tell the user they ran out of retry attempts
284         CGUIDialogOK::ShowAndGetInput(12345, 12346, 0, 0);
285         return ;
286       }
287     }
288     CStdString dlgLine1 = "";
289     if (0 < g_passwordManager.iMasterLockRetriesLeft)
290       dlgLine1.Format("%d %s", g_passwordManager.iMasterLockRetriesLeft, g_localizeStrings.Get(12343));
291     CGUIDialogOK::ShowAndGetInput(20075, 12345, dlgLine1, 0);
292   }
293   else
294     g_passwordManager.iMasterLockRetriesLeft = g_guiSettings.GetInt("masterlock.maxretries"); // user entered correct mastercode, reset retries to max allowed
295 }
296
297 bool CGUIPassword::CheckLock(LockType btnType, const CStdString& strPassword, int iHeading)
298 {
299   bool bDummy;
300   return CheckLock(btnType,strPassword,iHeading,bDummy);
301 }
302
303 bool CGUIPassword::CheckLock(LockType btnType, const CStdString& strPassword, int iHeading, bool& bCanceled)
304 {
305   bCanceled = false;
306   if (btnType == LOCK_MODE_EVERYONE || strPassword.Equals("-")        ||
307       g_settings.GetMasterProfile().getLockMode() == LOCK_MODE_EVERYONE || g_passwordManager.bMasterUser)
308     return true;
309
310   int iVerifyPasswordResult = -1;
311   CStdString strHeading = g_localizeStrings.Get(iHeading);
312   iVerifyPasswordResult = VerifyPassword(btnType, strPassword, strHeading);
313
314   if (iVerifyPasswordResult == -1)
315     bCanceled = true;
316
317   return (iVerifyPasswordResult==0);
318 }
319
320 bool CGUIPassword::CheckMenuLock(int iWindowID)
321 {
322   bool bCheckPW         = false;
323   int iSwitch = iWindowID;
324
325   // check if a settings subcategory was called from other than settings window
326   if (iWindowID >= WINDOW_SCREEN_CALIBRATION && iWindowID <= WINDOW_SETTINGS_APPEARANCE)
327   {
328     int iCWindowID = g_windowManager.GetActiveWindow();
329     if (iCWindowID != WINDOW_SETTINGS_MENU && (iCWindowID < WINDOW_SCREEN_CALIBRATION || iCWindowID > WINDOW_SETTINGS_APPEARANCE))
330       iSwitch = WINDOW_SETTINGS_MENU;
331   }
332
333   if (iWindowID == WINDOW_MUSIC_FILES)
334     if (g_windowManager.GetActiveWindow() == WINDOW_MUSIC_NAV)
335       iSwitch = WINDOW_HOME;
336
337   if (iWindowID == WINDOW_MUSIC_NAV)
338     if (g_windowManager.GetActiveWindow() == WINDOW_HOME)
339       iSwitch = WINDOW_MUSIC_FILES;
340
341   if (iWindowID == WINDOW_VIDEO_NAV)
342     if (g_windowManager.GetActiveWindow() == WINDOW_HOME)
343       iSwitch = WINDOW_VIDEO_FILES;
344
345   if (iWindowID == WINDOW_VIDEO_FILES)
346     if (g_windowManager.GetActiveWindow() == WINDOW_VIDEO_NAV)
347       iSwitch = WINDOW_HOME;
348
349   switch (iSwitch)
350   {
351     case WINDOW_SETTINGS_MENU:  // Settings
352       bCheckPW = g_settings.GetCurrentProfile().settingsLocked();
353       break;
354     case WINDOW_ADDON_BROWSER:  // Addons
355       bCheckPW = g_settings.GetCurrentProfile().addonmanagerLocked();
356       break;
357     case WINDOW_FILES:          // Files
358       bCheckPW = g_settings.GetCurrentProfile().filesLocked();
359       break;
360     case WINDOW_PROGRAMS:       // Programs
361       bCheckPW = g_settings.GetCurrentProfile().programsLocked();
362       break;
363     case WINDOW_MUSIC_FILES:    // Music
364       bCheckPW = g_settings.GetCurrentProfile().musicLocked();
365       break;
366     case WINDOW_VIDEO_FILES:    // Video
367       bCheckPW = g_settings.GetCurrentProfile().videoLocked();
368       break;
369     case WINDOW_PICTURES:       // Pictures
370       bCheckPW = g_settings.GetCurrentProfile().picturesLocked();
371       break;
372     case WINDOW_SETTINGS_PROFILES:
373       bCheckPW = true;
374       break;
375     default:
376       bCheckPW = false;
377       break;
378   }
379   if (bCheckPW)
380     return IsMasterLockUnlocked(true); //Now let's check the PW if we need!
381   else
382     return true;
383 }
384
385 bool CGUIPassword::LockSource(const CStdString& strType, const CStdString& strName, bool bState)
386 {
387   VECSOURCES* pShares = g_settings.GetSourcesFromType(strType);
388   bool bResult = false;
389   for (IVECSOURCES it=pShares->begin();it != pShares->end();++it)
390   {
391     if (it->strName == strName)
392     {
393       if (it->m_iHasLock > 0)
394       {
395         it->m_iHasLock = bState?2:1;
396         bResult = true;
397       }
398       break;
399     }
400   }
401   CGUIMessage msg(GUI_MSG_NOTIFY_ALL,0,0,GUI_MSG_UPDATE_SOURCES);
402   g_windowManager.SendThreadMessage(msg);
403
404   return bResult;
405 }
406
407 void CGUIPassword::LockSources(bool lock)
408 {
409   // lock or unlock all sources (those with locks)
410   const char* strType[5] = {"programs","music","video","pictures","files"};
411   for (int i=0;i<5;++i)
412   {
413     VECSOURCES *shares = g_settings.GetSourcesFromType(strType[i]);
414     for (IVECSOURCES it=shares->begin();it != shares->end();++it)
415       if (it->m_iLockMode != LOCK_MODE_EVERYONE)
416         it->m_iHasLock = lock ? 2 : 1;
417   }
418   CGUIMessage msg(GUI_MSG_NOTIFY_ALL,0,0,GUI_MSG_UPDATE_SOURCES);
419   g_windowManager.SendThreadMessage(msg);
420 }
421
422 void CGUIPassword::RemoveSourceLocks()
423 {
424   // remove lock from all sources
425   const char* strType[5] = {"programs","music","video","pictures","files"};
426   for (int i=0;i<5;++i)
427   {
428     VECSOURCES *shares = g_settings.GetSourcesFromType(strType[i]);
429     for (IVECSOURCES it=shares->begin();it != shares->end();++it)
430       if (it->m_iLockMode != LOCK_MODE_EVERYONE) // remove old info
431       {
432         it->m_iHasLock = 0;
433         it->m_iLockMode = LOCK_MODE_EVERYONE;
434         g_settings.UpdateSource(strType[i],it->strName,"lockmode","0"); // removes locks from xml
435       }
436   }
437   g_settings.SaveSources();
438   CGUIMessage msg(GUI_MSG_NOTIFY_ALL,0,0, GUI_MSG_UPDATE_SOURCES);
439   g_windowManager.SendThreadMessage(msg);
440 }
441
442 bool CGUIPassword::IsDatabasePathUnlocked(const CStdString& strPath, VECSOURCES& vecSources)
443 {
444   if (g_passwordManager.bMasterUser || g_settings.GetMasterProfile().getLockMode() == LOCK_MODE_EVERYONE)
445     return true;
446
447   // try to find the best matching source
448   bool bName = false;
449   int iIndex = CUtil::GetMatchingSource(strPath, vecSources, bName);
450
451   if (iIndex > -1 && iIndex < (int)vecSources.size())
452     if (vecSources[iIndex].m_iHasLock < 2)
453       return true;
454
455   return false;
456 }
457
458 int CGUIPassword::VerifyPassword(LockType btnType, const CStdString& strPassword, const CStdString& strHeading)
459 {
460   int iVerifyPasswordResult;
461   switch (btnType)
462   {
463   case LOCK_MODE_NUMERIC:
464     iVerifyPasswordResult = CGUIDialogNumeric::ShowAndVerifyPassword(const_cast<CStdString&>(strPassword), strHeading, 0);
465     break;
466   case LOCK_MODE_GAMEPAD:
467     iVerifyPasswordResult = CGUIDialogGamepad::ShowAndVerifyPassword(const_cast<CStdString&>(strPassword), strHeading, 0);
468     break;
469   case LOCK_MODE_QWERTY:
470     iVerifyPasswordResult = CGUIDialogKeyboard::ShowAndVerifyPassword(const_cast<CStdString&>(strPassword), strHeading, 0);
471     break;
472   default:   // must not be supported, treat as unlocked
473     iVerifyPasswordResult = 0;
474     break;
475   }
476
477   return iVerifyPasswordResult;
478 }
479