[PVR][Estuary] Timer settings dialog: Show client name in timer type selection dialog...
[xbmc.git] / xbmc / filesystem / Directory.cpp
blob5436fd9d8ab40979db6cf5650f6149de2e1595a4
1 /*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "Directory.h"
11 #include "DirectoryCache.h"
12 #include "DirectoryFactory.h"
13 #include "FileDirectoryFactory.h"
14 #include "FileItem.h"
15 #include "PasswordManager.h"
16 #include "ServiceBroker.h"
17 #include "URL.h"
18 #include "commons/Exception.h"
19 #include "dialogs/GUIDialogBusy.h"
20 #include "guilib/GUIWindowManager.h"
21 #include "messaging/ApplicationMessenger.h"
22 #include "settings/Settings.h"
23 #include "settings/SettingsComponent.h"
24 #include "utils/Job.h"
25 #include "utils/JobManager.h"
26 #include "utils/URIUtils.h"
27 #include "utils/log.h"
29 using namespace XFILE;
30 using namespace std::chrono_literals;
32 #define TIME_TO_BUSY_DIALOG 500
34 class CGetDirectory
36 private:
38 struct CResult
40 CResult(const CURL& dir, const CURL& listDir) : m_event(true), m_dir(dir), m_listDir(listDir), m_result(false) {}
41 CEvent m_event;
42 CFileItemList m_list;
43 CURL m_dir;
44 CURL m_listDir;
45 bool m_result;
48 struct CGetJob
49 : CJob
51 CGetJob(std::shared_ptr<IDirectory>& imp
52 , std::shared_ptr<CResult>& result)
53 : m_result(result)
54 , m_imp(imp)
56 public:
57 bool DoWork() override
59 m_result->m_list.SetURL(m_result->m_listDir);
60 m_result->m_result = m_imp->GetDirectory(m_result->m_dir, m_result->m_list);
61 m_result->m_event.Set();
62 return m_result->m_result;
65 std::shared_ptr<CResult> m_result;
66 std::shared_ptr<IDirectory> m_imp;
69 public:
71 CGetDirectory(std::shared_ptr<IDirectory>& imp, const CURL& dir, const CURL& listDir)
72 : m_result(new CResult(dir, listDir))
74 m_id = CServiceBroker::GetJobManager()->AddJob(new CGetJob(imp, m_result), nullptr,
75 CJob::PRIORITY_HIGH);
76 if (m_id == 0)
78 CGetJob job(imp, m_result);
79 job.DoWork();
82 ~CGetDirectory() { CServiceBroker::GetJobManager()->CancelJob(m_id); }
84 CEvent& GetEvent()
86 return m_result->m_event;
89 bool Wait(unsigned int timeout)
91 return m_result->m_event.Wait(std::chrono::milliseconds(timeout));
94 bool GetDirectory(CFileItemList& list)
96 /* if it was not finished or failed, return failure */
97 if (!m_result->m_event.Wait(0ms) || !m_result->m_result)
99 list.Clear();
100 return false;
103 list.Copy(m_result->m_list);
104 return true;
106 std::shared_ptr<CResult> m_result;
107 unsigned int m_id;
111 CDirectory::CDirectory() = default;
113 CDirectory::~CDirectory() = default;
115 bool CDirectory::GetDirectory(const std::string& strPath, CFileItemList &items, const std::string &strMask, int flags)
117 CHints hints;
118 hints.flags = flags;
119 hints.mask = strMask;
120 const CURL pathToUrl(strPath);
121 return GetDirectory(pathToUrl, items, hints);
124 bool CDirectory::GetDirectory(const std::string& strPath,
125 const std::shared_ptr<IDirectory>& pDirectory,
126 CFileItemList& items,
127 const std::string& strMask,
128 int flags)
130 CHints hints;
131 hints.flags = flags;
132 hints.mask = strMask;
133 const CURL pathToUrl(strPath);
134 return GetDirectory(pathToUrl, pDirectory, items, hints);
137 bool CDirectory::GetDirectory(const std::string& strPath, CFileItemList &items, const CHints &hints)
139 const CURL pathToUrl(strPath);
140 return GetDirectory(pathToUrl, items, hints);
143 bool CDirectory::GetDirectory(const CURL& url, CFileItemList &items, const std::string &strMask, int flags)
145 CHints hints;
146 hints.flags = flags;
147 hints.mask = strMask;
148 return GetDirectory(url, items, hints);
151 bool CDirectory::GetDirectory(const CURL& url, CFileItemList &items, const CHints &hints)
153 CURL realURL = URIUtils::SubstitutePath(url);
154 std::shared_ptr<IDirectory> pDirectory(CDirectoryFactory::Create(realURL));
155 return CDirectory::GetDirectory(url, pDirectory, items, hints);
158 bool CDirectory::GetDirectory(const CURL& url,
159 const std::shared_ptr<IDirectory>& pDirectory,
160 CFileItemList& items,
161 const CHints& hints)
165 CURL realURL = URIUtils::SubstitutePath(url);
166 if (!pDirectory)
167 return false;
169 // check our cache for this path
170 if (g_directoryCache.GetDirectory(realURL.Get(), items, (hints.flags & DIR_FLAG_READ_CACHE) == DIR_FLAG_READ_CACHE))
171 items.SetURL(url);
172 else
174 // need to clear the cache (in case the directory fetch fails)
175 // and (re)fetch the folder
176 if (!(hints.flags & DIR_FLAG_BYPASS_CACHE))
177 g_directoryCache.ClearDirectory(realURL.Get());
179 pDirectory->SetFlags(hints.flags);
181 bool result = false;
182 CURL authUrl = realURL;
184 while (!result)
186 const std::string pathToUrl(url.Get());
188 // don't change auth if it's set explicitly
189 if (CPasswordManager::GetInstance().IsURLSupported(authUrl) && authUrl.GetUserName().empty())
190 CPasswordManager::GetInstance().AuthenticateURL(authUrl);
192 items.SetURL(url);
193 result = pDirectory->GetDirectory(authUrl, items);
195 if (!result)
197 // @TODO ProcessRequirements() can bring up the keyboard input dialog
198 // filesystem must not depend on GUI
199 if (CServiceBroker::GetAppMessenger()->IsProcessThread() &&
200 pDirectory->ProcessRequirements())
202 authUrl.SetDomain("");
203 authUrl.SetUserName("");
204 authUrl.SetPassword("");
205 continue;
208 CLog::Log(LOGERROR, "{} - Error getting {}", __FUNCTION__, url.GetRedacted());
209 return false;
213 // hide credentials if necessary
214 if (CPasswordManager::GetInstance().IsURLSupported(realURL))
216 bool hide = false;
217 // for explicitly credentials
218 if (!realURL.GetUserName().empty())
220 // credentials was changed i.e. were stored in the password
221 // manager, in this case we can hide them from an item URL,
222 // otherwise we have to keep credentials in an item URL
223 if ( realURL.GetUserName() != authUrl.GetUserName()
224 || realURL.GetPassWord() != authUrl.GetPassWord()
225 || realURL.GetDomain() != authUrl.GetDomain())
227 hide = true;
230 else
232 // hide credentials in any other cases
233 hide = true;
236 if (hide)
238 for (int i = 0; i < items.Size(); ++i)
240 CFileItemPtr item = items[i];
241 CURL itemUrl = item->GetURL();
242 itemUrl.SetDomain("");
243 itemUrl.SetUserName("");
244 itemUrl.SetPassword("");
245 item->SetPath(itemUrl.Get());
250 // cache the directory, if necessary
251 if (!(hints.flags & DIR_FLAG_BYPASS_CACHE))
252 g_directoryCache.SetDirectory(realURL.Get(), items, pDirectory->GetCacheType(url));
255 // now filter for allowed files
256 if (!pDirectory->AllowAll())
258 pDirectory->SetMask(hints.mask);
259 for (int i = 0; i < items.Size(); ++i)
261 CFileItemPtr item = items[i];
262 if (!item->m_bIsFolder && !pDirectory->IsAllowed(item->GetURL()))
264 items.Remove(i);
265 i--; // don't confuse loop
269 // filter hidden files
270 //! @todo we shouldn't be checking the gui setting here, callers should use getHidden instead
271 if (!CServiceBroker::GetSettingsComponent()->GetSettings()->GetBool(CSettings::SETTING_FILELISTS_SHOWHIDDEN) && !(hints.flags & DIR_FLAG_GET_HIDDEN))
273 for (int i = 0; i < items.Size(); ++i)
275 if (items[i]->GetProperty("file:hidden").asBoolean())
277 items.Remove(i);
278 i--; // don't confuse loop
283 // Should any of the files we read be treated as a directory?
284 // Disable for database folders, as they already contain the extracted items
285 if (!(hints.flags & DIR_FLAG_NO_FILE_DIRS) && !items.IsMusicDb() && !items.IsVideoDb() && !items.IsSmartPlayList())
286 FilterFileDirectories(items, hints.mask);
288 // Correct items for path substitution
289 const std::string pathToUrl(url.Get());
290 const std::string pathToUrl2(realURL.Get());
291 if (pathToUrl != pathToUrl2)
293 for (int i = 0; i < items.Size(); ++i)
295 CFileItemPtr item = items[i];
296 item->SetPath(URIUtils::SubstitutePath(item->GetPath(), true));
300 return true;
302 XBMCCOMMONS_HANDLE_UNCHECKED
303 catch (...) { CLog::Log(LOGERROR, "{} - Unhandled exception", __FUNCTION__); }
304 CLog::Log(LOGERROR, "{} - Error getting {}", __FUNCTION__, url.GetRedacted());
305 return false;
308 bool CDirectory::Create(const std::string& strPath)
310 const CURL pathToUrl(strPath);
311 return Create(pathToUrl);
314 bool CDirectory::Create(const CURL& url)
318 CURL realURL = URIUtils::SubstitutePath(url);
320 if (CPasswordManager::GetInstance().IsURLSupported(realURL) && realURL.GetUserName().empty())
321 CPasswordManager::GetInstance().AuthenticateURL(realURL);
323 std::unique_ptr<IDirectory> pDirectory(CDirectoryFactory::Create(realURL));
324 if (pDirectory)
325 if(pDirectory->Create(realURL))
326 return true;
328 XBMCCOMMONS_HANDLE_UNCHECKED
329 catch (...) { CLog::Log(LOGERROR, "{} - Unhandled exception", __FUNCTION__); }
330 CLog::Log(LOGERROR, "{} - Error creating {}", __FUNCTION__, url.GetRedacted());
331 return false;
334 bool CDirectory::Exists(const std::string& strPath, bool bUseCache /* = true */)
336 const CURL pathToUrl(strPath);
337 return Exists(pathToUrl, bUseCache);
340 bool CDirectory::Exists(const CURL& url, bool bUseCache /* = true */)
344 CURL realURL = URIUtils::SubstitutePath(url);
345 if (bUseCache)
347 bool bPathInCache;
348 std::string realPath(realURL.Get());
349 URIUtils::AddSlashAtEnd(realPath);
350 if (g_directoryCache.FileExists(realPath, bPathInCache))
351 return true;
352 if (bPathInCache)
353 return false;
356 if (CPasswordManager::GetInstance().IsURLSupported(realURL) && realURL.GetUserName().empty())
357 CPasswordManager::GetInstance().AuthenticateURL(realURL);
359 std::unique_ptr<IDirectory> pDirectory(CDirectoryFactory::Create(realURL));
360 if (pDirectory)
361 return pDirectory->Exists(realURL);
363 XBMCCOMMONS_HANDLE_UNCHECKED
364 catch (...) { CLog::Log(LOGERROR, "{} - Unhandled exception", __FUNCTION__); }
365 CLog::Log(LOGERROR, "{} - Error checking for {}", __FUNCTION__, url.GetRedacted());
366 return false;
369 bool CDirectory::Remove(const std::string& strPath)
371 const CURL pathToUrl(strPath);
372 return Remove(pathToUrl);
375 bool CDirectory::RemoveRecursive(const std::string& strPath)
377 return RemoveRecursive(CURL{ strPath });
380 bool CDirectory::Remove(const CURL& url)
384 CURL realURL = URIUtils::SubstitutePath(url);
385 CURL authUrl = realURL;
386 if (CPasswordManager::GetInstance().IsURLSupported(authUrl) && authUrl.GetUserName().empty())
387 CPasswordManager::GetInstance().AuthenticateURL(authUrl);
389 std::unique_ptr<IDirectory> pDirectory(CDirectoryFactory::Create(realURL));
390 if (pDirectory)
391 if(pDirectory->Remove(authUrl))
393 g_directoryCache.ClearFile(realURL.Get());
394 return true;
397 XBMCCOMMONS_HANDLE_UNCHECKED
398 catch (...) { CLog::Log(LOGERROR, "{} - Unhandled exception", __FUNCTION__); }
399 CLog::Log(LOGERROR, "{} - Error removing {}", __FUNCTION__, url.GetRedacted());
400 return false;
403 bool CDirectory::RemoveRecursive(const CURL& url)
407 CURL realURL = URIUtils::SubstitutePath(url);
408 CURL authUrl = realURL;
409 if (CPasswordManager::GetInstance().IsURLSupported(authUrl) && authUrl.GetUserName().empty())
410 CPasswordManager::GetInstance().AuthenticateURL(authUrl);
412 std::unique_ptr<IDirectory> pDirectory(CDirectoryFactory::Create(realURL));
413 if (pDirectory)
414 if(pDirectory->RemoveRecursive(authUrl))
416 g_directoryCache.ClearFile(realURL.Get());
417 return true;
420 XBMCCOMMONS_HANDLE_UNCHECKED
421 catch (...) { CLog::Log(LOGERROR, "{} - Unhandled exception", __FUNCTION__); }
422 CLog::Log(LOGERROR, "{} - Error removing {}", __FUNCTION__, url.GetRedacted());
423 return false;
426 void CDirectory::FilterFileDirectories(CFileItemList &items, const std::string &mask,
427 bool expandImages)
429 for (int i=0; i< items.Size(); ++i)
431 CFileItemPtr pItem=items[i];
432 auto mode = expandImages && pItem->IsDiscImage() ? EFILEFOLDER_TYPE_ONBROWSE : EFILEFOLDER_TYPE_ALWAYS;
433 if (!pItem->m_bIsFolder && pItem->IsFileFolder(mode))
435 std::unique_ptr<IFileDirectory> pDirectory(CFileDirectoryFactory::Create(pItem->GetURL(),pItem.get(),mask));
436 if (pDirectory)
437 pItem->m_bIsFolder = true;
438 else
439 if (pItem->m_bIsFolder)
441 items.Remove(i);
442 i--; // don't confuse loop