1 /*
2  *  Copyright (C) 2005-2020 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 #pragma once
10 
11 #include <map>
12 #include <memory>
13 #include <string>
14 #include <vector>
15 
16 namespace ADDON
17 {
18 
19 class AddonVersion;
20 class CAddonDatabase;
21 class CAddonMgr;
22 class CRepository;
23 class IAddon;
24 enum class AddonCheckType;
25 
26 enum class CheckAddonPath
27 {
28   YES,
29   NO,
30 };
31 
32 /**
33  * Struct - CAddonWithUpdate
34  */
35 struct CAddonWithUpdate
36 {
37   std::shared_ptr<IAddon> m_installed;
38   std::shared_ptr<IAddon> m_update;
39 };
40 
41 /**
42  * Class - CAddonRepos
43  * Reads information about installed official/third party repos and their contained add-ons from the database.
44  * Used to check for updates for installed add-ons and dependencies while obeying permission rules.
45  * Note that this class is not responsible for refreshing the repo data stored in the database.
46  */
47 class CAddonRepos
48 {
49 public:
CAddonRepos(const CAddonMgr & addonMgr)50   CAddonRepos(const CAddonMgr& addonMgr) : m_addonMgr(addonMgr){};
51 
52   /*!
53    * \brief Load the map of all available addon versions in any installed repository
54    * \param database reference to the database to load addons from
55    * \return true on success, false otherwise
56    */
57   bool LoadAddonsFromDatabase(const CAddonDatabase& database);
58 
59   /*!
60    * \brief Load the map of all available versions of an addonId in any installed repository
61    * \param database reference to the database to load addons from
62    * \param addonId the addon id we want to retrieve versions for
63    * \return true on success, false otherwise
64    */
65   bool LoadAddonsFromDatabase(const CAddonDatabase& database, const std::string& addonId);
66 
67   /*!
68    * \brief Load the map of all available versions in one installed repository
69    * \param database reference to the database to load addons from
70    * \param repoAddon pointer to the repo we want to retrieve versions from
71    *        note this is of type AddonPtr, not RepositoryPtr
72    * \return true on success, false otherwise
73    */
74   bool LoadAddonsFromDatabase(const CAddonDatabase& database,
75                               const std::shared_ptr<IAddon>& repoAddon);
76 
77   /*!
78    * \brief Build the list of addons to be updated depending on defined rules
79    *        or the list of outdated addons
80    * \param installed vector of all addons installed on the system that are
81    *        checked for an update
82    * \param[in] addonCheckType build list of OUTDATED or UPDATES
83    * \param[out] result list of addon versions that are going to be installed
84    *             or are outdated
85    */
86   void BuildUpdateOrOutdatedList(const std::vector<std::shared_ptr<IAddon>>& installed,
87                                  std::vector<std::shared_ptr<IAddon>>& result,
88                                  AddonCheckType addonCheckType) const;
89 
90 
91   /*!
92    * \brief Build the list of outdated addons and their available updates.
93    * \param installed vector of all addons installed on the system that are
94    *        checked for an update
95    * \param[out] addonsWithUpdate target map
96    */
97   void BuildAddonsWithUpdateList(const std::vector<std::shared_ptr<IAddon>>& installed,
98                                  std::map<std::string, CAddonWithUpdate>& addonsWithUpdate) const;
99 
100   /*!
101    * \brief Checks if the origin-repository of a given addon is defined as official repo
102    *        and can also verify if the origin-path (e.g. https://mirrors.kodi.tv ...)
103    *        is matching
104    * \note if this function is called on locally installed add-ons, for instance when populating
105    *       'My add-ons', the local installation path is returned as origin.
106    *       thus parameter CheckAddonPath::NO needs to be passed in such cases
107    * \param addon pointer to addon to be checked
108    * \param checkAddonPath also check origin path
109    * \return true if the repository id of a given addon is defined as official
110    *         and the addons origin matches the defined official origin of the repo id
111    */
112   static bool IsFromOfficialRepo(const std::shared_ptr<IAddon>& addon,
113                                  CheckAddonPath checkAddonPath);
114 
115   /*!
116    * \brief Checks if the passed in repository is defined as official repo
117    *        which includes ORIGIN_SYSTEM
118    * \param repoId repository id to check
119    * \return true if the repository id is defined as official, false otherwise
120    */
121   static bool IsOfficialRepo(const std::string& repoId);
122 
123   /*!
124    * \brief Check if an update is available for a single addon
125    * \param addon that is checked for an update
126    * \param[out] update pointer to the found update
127    * \return true if an installable update was found, false otherwise
128    */
129   bool DoAddonUpdateCheck(const std::shared_ptr<IAddon>& addon,
130                           std::shared_ptr<IAddon>& update) const;
131 
132   /*!
133    * \brief Retrieves the latest version of an addon from all installed repositories
134    *        follows addon origin restriction rules
135    * \param addonId addon id we're looking the latest version for
136    * \param[out] addon pointer to the found addon
137    * \return true if a version was found, false otherwise
138    */
139   bool GetLatestAddonVersionFromAllRepos(const std::string& addonId,
140                                          std::shared_ptr<IAddon>& addon) const;
141 
142   /*!
143    * \brief Retrieves the latest official versions of addons to vector.
144    *        Private versions are added obeying updateMode.
145    *        (either OFFICIAL_ONLY or ANY_REPOSITORY)
146    * \param[out] addonList retrieved addon list in a vector
147    */
148   void GetLatestAddonVersions(std::vector<std::shared_ptr<IAddon>>& addonList) const;
149 
150   /*!
151    * \brief Retrieves the latest official versions of addons to vector.
152    *        Private versions (latest per repository) are added obeying updateMode.
153    *        (either OFFICIAL_ONLY or ANY_REPOSITORY)
154    * \param[out] addonList retrieved addon list in a vector
155    */
156   void GetLatestAddonVersionsFromAllRepos(std::vector<std::shared_ptr<IAddon>>& addonList) const;
157 
158   /*!
159    * \brief Find a dependency to install during an addon install or update
160    *        If the dependency cannot be found in official versions we look in the
161    *        installing/updating addon's (the parent's) origin repository
162    * \param dependsId addon id of the dependency we're looking for
163    * \param parentRepoId origin repository of the dependee
164    * \param [out] dependencyToInstall pointer to the found dependency, only use
165    *              if function returns true
166    * \param [out] repoForDep the repository that dependency will install from finally
167    * \return true if the dependency was found, false otherwise
168    */
169   bool FindDependency(const std::string& dependsId,
170                       const std::string& parentRepoId,
171                       std::shared_ptr<IAddon>& dependencyToInstall,
172                       std::shared_ptr<CRepository>& repoForDep) const;
173 
174   /*!
175    * \brief Find a dependency addon in the repository of its parent
176    * \param dependsId addon id of the dependency we're looking for
177    * \param parentRepoId origin repository of the dependee
178    * \param [out] dependencyToInstall pointer to the found dependency, only use
179    *              if function returns true
180    * \return true if the dependency was found, false otherwise
181    */
182   bool FindDependencyByParentRepo(const std::string& dependsId,
183                                   const std::string& parentRepoId,
184                                   std::shared_ptr<IAddon>& dependencyToInstall) const;
185 
186   /*!
187    * \brief Build compatible versions list based on the contents of m_allAddons
188    * \note content of m_allAddons depends on the preceding call to @ref LoadAddonsFromDatabase()
189    * \param[out] compatibleVersions target vector to be filled
190    */
191   void BuildCompatibleVersionsList(std::vector<std::shared_ptr<IAddon>>& compatibleVersions) const;
192 
193 private:
194   /*!
195    * \brief Load the map of addons
196    * \note this function should only by called from publicly exposed wrappers
197    * \return true on success, false otherwise
198    */
199   bool LoadAddonsFromDatabase(const CAddonDatabase& database,
200                               const std::string& addonId,
201                               const std::shared_ptr<IAddon>& repoAddon);
202 
203   /*!
204    * \brief Looks up an addon in a given repository map and
205    *        checks if an update is available
206    * \param addonToCheck the addon we want to find and version check
207    * \param map the repository map we want to check against
208    * \param[out] pointer to the found update. if the addon is
209    *              up-to-date on our system, this param will return 'nullptr'
210    * \return true if the addon was found in the desired map,
211    *         either up-to-date or newer version.
212    *         false if the addon does NOT exist in the map
213    */
214   bool FindAddonAndCheckForUpdate(const std::shared_ptr<IAddon>& addonToCheck,
215                                   const std::map<std::string, std::shared_ptr<IAddon>>& map,
216                                   std::shared_ptr<IAddon>& update) const;
217 
218   /*!
219    * \brief Sets up latest version maps from scratch
220    */
221   void SetupLatestVersionMaps();
222 
223   /*!
224    * \brief Adds the latest version of an addon to the desired map
225    * \param addonToAdd the addon whose latest version should be added
226    * \param map target map, e.g. latestOfficialVersions or latestPrivateVersions
227    */
228   void AddAddonIfLatest(const std::shared_ptr<IAddon>& addonToAdd,
229                         std::map<std::string, std::shared_ptr<IAddon>>& map) const;
230 
231   /*!
232    * \brief Adds the latest version of an addon to the desired map per repository
233    *        used to populate 'latestVersionsByRepo'
234    * \param repoId the repository that addon comes from
235    * \param addonToAdd the addon whose latest version should be added
236    * \param map target map, latestVersionsByRepo
237    */
238   void AddAddonIfLatest(
239       const std::string& repoId,
240       const std::shared_ptr<IAddon>& addonToAdd,
241       std::map<std::string, std::map<std::string, std::shared_ptr<IAddon>>>& map) const;
242 
243   /*!
244    * \brief Looks up an addon entry in a specific map
245    * \param addonId addon we want to retrieve
246    * \param map the map we're looking into for the wanted addon
247    * \param[out] addon pointer to the found addon, only use when function returns true
248    * \return true if the addon was found in the map, false otherwise
249    */
250   bool GetLatestVersionByMap(const std::string& addonId,
251                              const std::map<std::string, std::shared_ptr<IAddon>>& map,
252                              std::shared_ptr<IAddon>& addon) const;
253 
254   const CAddonMgr& m_addonMgr;
255 
256   std::vector<std::shared_ptr<IAddon>> m_allAddons;
257 
258   std::map<std::string, std::shared_ptr<IAddon>> m_latestOfficialVersions;
259   std::map<std::string, std::shared_ptr<IAddon>> m_latestPrivateVersions;
260   std::map<std::string, std::map<std::string, std::shared_ptr<IAddon>>> m_latestVersionsByRepo;
261   std::map<std::string, std::multimap<std::string, std::shared_ptr<IAddon>>> m_addonsByRepoMap;
262 };
263 
264 }; /* namespace ADDON */
265