1 /*
2  *  Copyright (C) 2005-2018 Team Kodi
3  *  This file is part of Kodi - https://kodi.tv
4  *
5  *  SPDX-License-Identifier: GPL-2.0-or-later
6  *  See LICENSES/README.md for more information.
7  */
8 
9 #include "FileBrowser.h"
10 
11 #include "URL.h"
12 #include "addons/binary-addons/AddonDll.h"
13 #include "addons/kodi-dev-kit/include/kodi/gui/dialogs/FileBrowser.h"
14 #include "dialogs/GUIDialogFileBrowser.h"
15 #include "settings/MediaSourceSettings.h"
16 #include "storage/MediaManager.h"
17 #include "utils/URIUtils.h"
18 #include "utils/log.h"
19 
20 namespace ADDON
21 {
22 
Init(AddonGlobalInterface * addonInterface)23 void Interface_GUIDialogFileBrowser::Init(AddonGlobalInterface* addonInterface)
24 {
25   addonInterface->toKodi->kodi_gui->dialogFileBrowser =
26       new AddonToKodiFuncTable_kodi_gui_dialogFileBrowser();
27 
28   addonInterface->toKodi->kodi_gui->dialogFileBrowser->show_and_get_directory =
29       show_and_get_directory;
30   addonInterface->toKodi->kodi_gui->dialogFileBrowser->show_and_get_file = show_and_get_file;
31   addonInterface->toKodi->kodi_gui->dialogFileBrowser->show_and_get_file_from_dir =
32       show_and_get_file_from_dir;
33   addonInterface->toKodi->kodi_gui->dialogFileBrowser->show_and_get_file_list =
34       show_and_get_file_list;
35   addonInterface->toKodi->kodi_gui->dialogFileBrowser->show_and_get_source = show_and_get_source;
36   addonInterface->toKodi->kodi_gui->dialogFileBrowser->show_and_get_image = show_and_get_image;
37   addonInterface->toKodi->kodi_gui->dialogFileBrowser->show_and_get_image_list =
38       show_and_get_image_list;
39   addonInterface->toKodi->kodi_gui->dialogFileBrowser->clear_file_list = clear_file_list;
40 }
41 
DeInit(AddonGlobalInterface * addonInterface)42 void Interface_GUIDialogFileBrowser::DeInit(AddonGlobalInterface* addonInterface)
43 {
44   delete addonInterface->toKodi->kodi_gui->dialogFileBrowser;
45 }
46 
show_and_get_directory(KODI_HANDLE kodiBase,const char * shares,const char * heading,const char * path_in,char ** path_out,bool write_only)47 bool Interface_GUIDialogFileBrowser::show_and_get_directory(KODI_HANDLE kodiBase,
48                                                             const char* shares,
49                                                             const char* heading,
50                                                             const char* path_in,
51                                                             char** path_out,
52                                                             bool write_only)
53 {
54   CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
55   if (!addon)
56   {
57     CLog::Log(LOGERROR, "Interface_GUIDialogFileBrowser::{} - invalid data", __func__);
58     return false;
59   }
60 
61   if (!shares || !heading || !path_in || !path_out)
62   {
63     CLog::Log(LOGERROR,
64               "Interface_GUIDialogFileBrowser::{} - invalid handler data (shares='{}', "
65               "heading='{}', path_in='{}', path_out='{}') on addon '{}'",
66               __func__, static_cast<const void*>(shares), static_cast<const void*>(heading),
67               static_cast<const void*>(path_in), static_cast<void*>(path_out), addon->ID());
68     return false;
69   }
70 
71   std::string strPath = path_in;
72 
73   VECSOURCES vecShares;
74   GetVECShares(vecShares, shares, strPath);
75   bool bRet = CGUIDialogFileBrowser::ShowAndGetDirectory(vecShares, heading, strPath, write_only);
76   if (bRet)
77     *path_out = strdup(strPath.c_str());
78   return bRet;
79 }
80 
show_and_get_file(KODI_HANDLE kodiBase,const char * shares,const char * mask,const char * heading,const char * path_in,char ** path_out,bool use_thumbs,bool use_file_directories)81 bool Interface_GUIDialogFileBrowser::show_and_get_file(KODI_HANDLE kodiBase,
82                                                        const char* shares,
83                                                        const char* mask,
84                                                        const char* heading,
85                                                        const char* path_in,
86                                                        char** path_out,
87                                                        bool use_thumbs,
88                                                        bool use_file_directories)
89 {
90   CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
91   if (!addon)
92   {
93     CLog::Log(LOGERROR, "Interface_GUIDialogFileBrowser::{} - invalid data", __func__);
94     return false;
95   }
96 
97   if (!shares || !mask || !heading || !path_in || !path_out)
98   {
99     CLog::Log(LOGERROR,
100               "Interface_GUIDialogFileBrowser::{} - invalid handler data (shares='{}', mask='{}', "
101               "heading='{}', path_in='{}', path_out='{}') on addon '{}'",
102               __func__, static_cast<const void*>(shares), static_cast<const void*>(mask),
103               static_cast<const void*>(heading), static_cast<const void*>(path_in),
104               static_cast<void*>(path_out), addon->ID());
105     return false;
106   }
107 
108   std::string strPath = path_in;
109 
110   VECSOURCES vecShares;
111   GetVECShares(vecShares, shares, strPath);
112   bool bRet = CGUIDialogFileBrowser::ShowAndGetFile(vecShares, mask, heading, strPath, use_thumbs,
113                                                     use_file_directories);
114   if (bRet)
115     *path_out = strdup(strPath.c_str());
116   return bRet;
117 }
118 
show_and_get_file_from_dir(KODI_HANDLE kodiBase,const char * directory,const char * mask,const char * heading,const char * path_in,char ** path_out,bool use_thumbs,bool use_file_directories,bool single_list)119 bool Interface_GUIDialogFileBrowser::show_and_get_file_from_dir(KODI_HANDLE kodiBase,
120                                                                 const char* directory,
121                                                                 const char* mask,
122                                                                 const char* heading,
123                                                                 const char* path_in,
124                                                                 char** path_out,
125                                                                 bool use_thumbs,
126                                                                 bool use_file_directories,
127                                                                 bool single_list)
128 {
129   CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
130   if (!addon)
131   {
132     CLog::Log(LOGERROR, "Interface_GUIDialogFileBrowser::{} - invalid data", __func__);
133     return false;
134   }
135 
136   if (!directory || !mask || !heading || !path_in || !path_out)
137   {
138     CLog::Log(LOGERROR,
139               "Interface_GUIDialogFileBrowser::{} - invalid handler data (directory='{}', "
140               "mask='{}', heading='{}', path_in='{}', path_out='{}') on addon '{}'",
141               __func__, static_cast<const void*>(directory), static_cast<const void*>(mask),
142               static_cast<const void*>(heading), static_cast<const void*>(path_in),
143               static_cast<void*>(path_out), addon->ID());
144     return false;
145   }
146 
147   std::string strPath = path_in;
148   bool bRet = CGUIDialogFileBrowser::ShowAndGetFile(directory, mask, heading, strPath, use_thumbs,
149                                                     use_file_directories, single_list);
150   if (bRet)
151     *path_out = strdup(strPath.c_str());
152   return bRet;
153 }
154 
show_and_get_file_list(KODI_HANDLE kodiBase,const char * shares,const char * mask,const char * heading,char *** file_list,unsigned int * entries,bool use_thumbs,bool use_file_directories)155 bool Interface_GUIDialogFileBrowser::show_and_get_file_list(KODI_HANDLE kodiBase,
156                                                             const char* shares,
157                                                             const char* mask,
158                                                             const char* heading,
159                                                             char*** file_list,
160                                                             unsigned int* entries,
161                                                             bool use_thumbs,
162                                                             bool use_file_directories)
163 {
164   CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
165   if (!addon)
166   {
167     CLog::Log(LOGERROR, "Interface_GUIDialogFileBrowser::{} - invalid data", __func__);
168     return false;
169   }
170 
171   if (!shares || !mask || !heading || !file_list || !entries)
172   {
173     CLog::Log(LOGERROR,
174               "Interface_GUIDialogFileBrowser::{} - invalid handler data (shares='{}', mask='{}', "
175               "heading='{}', file_list='{}', entries='{}') on addon '{}'",
176               __func__, static_cast<const void*>(shares), static_cast<const void*>(mask),
177               static_cast<const void*>(heading), static_cast<void*>(file_list),
178               static_cast<void*>(entries), addon->ID());
179     return false;
180   }
181 
182   VECSOURCES vecShares;
183   GetVECShares(vecShares, shares, "");
184 
185   std::vector<std::string> pathsInt;
186   bool bRet = CGUIDialogFileBrowser::ShowAndGetFileList(vecShares, mask, heading, pathsInt,
187                                                         use_thumbs, use_file_directories);
188   if (bRet)
189   {
190     *entries = pathsInt.size();
191     *file_list = static_cast<char**>(malloc(*entries * sizeof(char*)));
192     for (unsigned int i = 0; i < *entries; ++i)
193       (*file_list)[i] = strdup(pathsInt[i].c_str());
194   }
195   else
196     *entries = 0;
197   return bRet;
198 }
199 
show_and_get_source(KODI_HANDLE kodiBase,const char * path_in,char ** path_out,bool allowNetworkShares,const char * additionalShare,const char * strType)200 bool Interface_GUIDialogFileBrowser::show_and_get_source(KODI_HANDLE kodiBase,
201                                                          const char* path_in,
202                                                          char** path_out,
203                                                          bool allowNetworkShares,
204                                                          const char* additionalShare,
205                                                          const char* strType)
206 {
207   CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
208   if (!addon)
209   {
210     CLog::Log(LOGERROR, "Interface_GUIDialogFileBrowser::{} - invalid data", __func__);
211     return false;
212   }
213 
214   if (!strType || !additionalShare || !path_in || !path_out)
215   {
216     CLog::Log(LOGERROR,
217               "Interface_GUIDialogFileBrowser::{} - invalid handler data (additionalShare='{}', "
218               "strType='{}', path_in='{}', path_out='{}') on addon '{}'",
219               __func__, static_cast<const void*>(additionalShare),
220               static_cast<const void*>(strType), static_cast<const void*>(path_in),
221               static_cast<void*>(path_out), addon->ID());
222     return false;
223   }
224 
225   std::string strPath = path_in;
226 
227   VECSOURCES vecShares;
228   if (additionalShare)
229     GetVECShares(vecShares, additionalShare, strPath);
230   bool bRet =
231       CGUIDialogFileBrowser::ShowAndGetSource(strPath, allowNetworkShares, &vecShares, strType);
232   if (bRet)
233     *path_out = strdup(strPath.c_str());
234   return bRet;
235 }
236 
show_and_get_image(KODI_HANDLE kodiBase,const char * shares,const char * heading,const char * path_in,char ** path_out)237 bool Interface_GUIDialogFileBrowser::show_and_get_image(KODI_HANDLE kodiBase,
238                                                         const char* shares,
239                                                         const char* heading,
240                                                         const char* path_in,
241                                                         char** path_out)
242 {
243   CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
244   if (!addon)
245   {
246     CLog::Log(LOGERROR, "Interface_GUIDialogFileBrowser::{} - invalid data", __func__);
247     return false;
248   }
249 
250   if (!shares || !heading)
251   {
252     CLog::Log(LOGERROR,
253               "Interface_GUIDialogFileBrowser::{} - invalid handler data (shares='{}', "
254               "heading='{}') on addon '{}'",
255               __func__, static_cast<const void*>(shares), static_cast<const void*>(heading),
256               addon->ID());
257     return false;
258   }
259 
260   std::string strPath = path_in;
261 
262   VECSOURCES vecShares;
263   GetVECShares(vecShares, shares, strPath);
264   bool bRet = CGUIDialogFileBrowser::ShowAndGetImage(vecShares, heading, strPath);
265   if (bRet)
266     *path_out = strdup(strPath.c_str());
267   return bRet;
268 }
269 
show_and_get_image_list(KODI_HANDLE kodiBase,const char * shares,const char * heading,char *** file_list,unsigned int * entries)270 bool Interface_GUIDialogFileBrowser::show_and_get_image_list(KODI_HANDLE kodiBase,
271                                                              const char* shares,
272                                                              const char* heading,
273                                                              char*** file_list,
274                                                              unsigned int* entries)
275 {
276   CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
277   if (!addon)
278   {
279     CLog::Log(LOGERROR, "Interface_GUIDialogFileBrowser::{} - invalid data", __func__);
280     return false;
281   }
282 
283   if (!shares || !heading || !file_list || !entries)
284   {
285     CLog::Log(LOGERROR,
286               "Interface_GUIDialogFileBrowser::{} - invalid handler data (shares='{}', "
287               "heading='{}', file_list='{}', entries='{}') on addon '{}'",
288               __func__, static_cast<const void*>(shares), static_cast<const void*>(heading),
289               static_cast<void*>(file_list), static_cast<void*>(entries), addon->ID());
290     return false;
291   }
292 
293   VECSOURCES vecShares;
294   GetVECShares(vecShares, shares, "");
295 
296   std::vector<std::string> pathsInt;
297   bool bRet = CGUIDialogFileBrowser::ShowAndGetImageList(vecShares, heading, pathsInt);
298   if (bRet)
299   {
300     *entries = pathsInt.size();
301     *file_list = static_cast<char**>(malloc(*entries * sizeof(char*)));
302     for (unsigned int i = 0; i < *entries; ++i)
303       (*file_list)[i] = strdup(pathsInt[i].c_str());
304   }
305   else
306     *entries = 0;
307   return bRet;
308 }
309 
clear_file_list(KODI_HANDLE kodiBase,char *** file_list,unsigned int entries)310 void Interface_GUIDialogFileBrowser::clear_file_list(KODI_HANDLE kodiBase,
311                                                      char*** file_list,
312                                                      unsigned int entries)
313 {
314   CAddonDll* addon = static_cast<CAddonDll*>(kodiBase);
315   if (!addon)
316   {
317     CLog::Log(LOGERROR, "Interface_GUIDialogFileBrowser::{} - invalid data", __func__);
318     return;
319   }
320 
321   if (*file_list)
322   {
323     for (unsigned int i = 0; i < entries; ++i)
324       free((*file_list)[i]);
325     free(*file_list);
326     *file_list = nullptr;
327   }
328   else
329   {
330 
331     CLog::Log(LOGERROR,
332               "Interface_GUIDialogFileBrowser::{} - invalid handler data (file_list='{}') on "
333               "addon '{}'",
334               __func__, static_cast<void*>(file_list), addon->ID());
335   }
336 }
337 
GetVECShares(VECSOURCES & vecShares,const std::string & strShares,const std::string & strPath)338 void Interface_GUIDialogFileBrowser::GetVECShares(VECSOURCES& vecShares,
339                                                   const std::string& strShares,
340                                                   const std::string& strPath)
341 {
342   std::size_t found;
343   found = strShares.find("local");
344   if (found != std::string::npos)
345     CServiceBroker::GetMediaManager().GetLocalDrives(vecShares);
346   found = strShares.find("network");
347   if (found != std::string::npos)
348     CServiceBroker::GetMediaManager().GetNetworkLocations(vecShares);
349   found = strShares.find("removable");
350   if (found != std::string::npos)
351     CServiceBroker::GetMediaManager().GetRemovableDrives(vecShares);
352   found = strShares.find("programs");
353   if (found != std::string::npos)
354   {
355     VECSOURCES* sources = CMediaSourceSettings::GetInstance().GetSources("programs");
356     if (sources != nullptr)
357       vecShares.insert(vecShares.end(), sources->begin(), sources->end());
358   }
359   found = strShares.find("files");
360   if (found != std::string::npos)
361   {
362     VECSOURCES* sources = CMediaSourceSettings::GetInstance().GetSources("files");
363     if (sources != nullptr)
364       vecShares.insert(vecShares.end(), sources->begin(), sources->end());
365   }
366   found = strShares.find("music");
367   if (found != std::string::npos)
368   {
369     VECSOURCES* sources = CMediaSourceSettings::GetInstance().GetSources("music");
370     if (sources != nullptr)
371       vecShares.insert(vecShares.end(), sources->begin(), sources->end());
372   }
373   found = strShares.find("video");
374   if (found != std::string::npos)
375   {
376     VECSOURCES* sources = CMediaSourceSettings::GetInstance().GetSources("video");
377     if (sources != nullptr)
378       vecShares.insert(vecShares.end(), sources->begin(), sources->end());
379   }
380   found = strShares.find("pictures");
381   if (found != std::string::npos)
382   {
383     VECSOURCES* sources = CMediaSourceSettings::GetInstance().GetSources("pictures");
384     if (sources != nullptr)
385       vecShares.insert(vecShares.end(), sources->begin(), sources->end());
386   }
387 
388   if (vecShares.empty())
389   {
390     CMediaSource share;
391     std::string basePath = strPath;
392     std::string tempPath;
393     while (URIUtils::GetParentPath(basePath, tempPath))
394       basePath = tempPath;
395     share.strPath = basePath;
396     // don't include the user details in the share name
397     CURL url(share.strPath);
398     share.strName = url.GetWithoutUserDetails();
399     vecShares.push_back(share);
400   }
401 }
402 
403 } /* namespace ADDON */
404