78a901db5089b53d6cbee19a4ab68cd74d293954
[platform/core/appfw/app-installers.git] / src / common / plugins / category_plugin.cc
1 // Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
2 // Use of this source code is governed by an apache-2.0 license that can be
3 // found in the LICENSE file.
4
5 #include "common/plugins/category_plugin.h"
6
7 #include <pkgmgr-info.h>
8 #include <pkgmgr_parser.h>
9
10 #include <algorithm>
11 #include <map>
12 #include <vector>
13
14 #include "common/utils/glist_range.h"
15
16 namespace {
17
18 std::string GetCategoryName(const std::string& url) {
19   return url.substr(url.find_last_of('/') + 1);
20 }
21
22 void ClearCategoryDetail(gpointer data) {
23   __category_t* category = reinterpret_cast<__category_t*>(data);
24   free(const_cast<char*>(category->name));
25   free(category);
26 }
27
28 }  // namespace
29
30 namespace common_installer {
31
32 const char CategoryPlugin::kType[] = "category";
33
34 std::unique_ptr<CategoryPlugin> CategoryPlugin::Create(
35     const PluginInfo& plugin_info) {
36   std::unique_ptr<CategoryPlugin> plugin(new CategoryPlugin(plugin_info));
37   if (!plugin->Load())
38     return nullptr;
39   return plugin;
40 }
41
42 bool CategoryPlugin::AddPluginInfo(manifest_x* manifest, const char* appid) {
43   plugin_x* plugin = static_cast<plugin_x*>(calloc(1, sizeof(plugin_x)));
44   if (!plugin) {
45     LOG(ERROR) << "out of memory";
46     return false;
47   }
48   plugin->pkgid = strdup(manifest->package);
49   plugin->appid = strdup(appid);
50   plugin->plugin_type = strdup(plugin_info_.type().c_str());
51   plugin->plugin_name = strdup(plugin_info_.name().c_str());
52   manifest->plugin = g_list_append(manifest->plugin, plugin);
53   return true;
54 }
55
56 std::string CategoryPlugin::GetFunctionName(ActionType action) const {
57   static std::map<ActionType, std::string> names {
58     {ActionType::Install,  "PKGMGR_CATEGORY_PARSER_PLUGIN_INSTALL"},
59     {ActionType::Upgrade,  "PKGMGR_CATEGORY_PARSER_PLUGIN_UPGRADE"},
60     {ActionType::Uninstall,  "PKGMGR_CATEGORY_PARSER_PLUGIN_UNINSTALL"},
61     {ActionType::RecoverInstall, "PKGMGR_CATEGORY_PARSER_PLUGIN_RECOVERINSTALL"},   // NOLINT
62     {ActionType::RecoverUpgrade, "PKGMGR_CATEGORY_PARSER_PLUGIN_RECOVERUPGRADE"},   // NOLINT
63     {ActionType::RecoverUninstall, "PKGMGR_CATEGORY_PARSER_PLUGIN_RECOVERUNINSTALL"},   // NOLINT
64     {ActionType::Clean, "PKGMGR_CATEGORY_PARSER_PLUGIN_CLEAN"},
65     {ActionType::Undo, "PKGMGR_CATEGORY_PARSER_PLUGIN_UNDO"},
66     {ActionType::Removed, "PKGMGR_CATEGORY_PARSER_PLUGIN_REMOVED"},
67   };
68
69   auto pos = names.find(action);
70   if (pos == names.end()) {
71     LOG(INFO) << "Function name not defined";
72     return "";
73   }
74   return pos->second;
75 }
76
77 bool CategoryPlugin::Run(xmlDocPtr /*doc_ptr*/, manifest_x* manifest,
78          ActionType action_type) {
79   std::string name;
80   std::string tag = GetCategoryName(plugin_info_.name());
81   if (tag.empty())
82     return false;
83
84   std::vector<std::string> appid_list;
85   if (action_type == ActionType::Upgrade) {
86     if (pkgmgrinfo_plugininfo_foreach_plugininfo(manifest->package,
87         CategoryPlugin::kType,
88         plugin_info_.name().c_str(),
89         [](const char*, const char* appid, const char*,
90             const char*, void* user_data) -> int {
91           auto* list =
92               static_cast<std::vector<std::string>*>(user_data);
93           list->emplace_back(std::string(appid));
94           return PMINFO_R_OK;
95         },
96         &appid_list) != PMINFO_R_OK) {
97       LOG(ERROR) << "Failed to get previous execution info";
98       return false;
99     }
100     std::sort(appid_list.begin(), appid_list.end());
101   }
102
103   for (application_x* app : GListRange<application_x*>(manifest->application)) {
104     // pack all categories starting with key to list that will
105     // be sent to the plugin.
106     // e.g. all http://tizen.org/category/antivirus/*
107     //   will be packed for http://tizen.org/category/antivirus
108     GList* category_list = nullptr;
109     for (const char* category : GListRange<char*>(app->category)) {
110       const std::string& sub_key_prefix = plugin_info_.name();
111       if (std::string(category).find(sub_key_prefix) == 0) {
112         __category_t* c = reinterpret_cast<__category_t*>(
113             calloc(1, sizeof(__category_t)));
114         if (!c) {
115           LOG(ERROR) << "Out of memory";
116           g_list_free_full(category_list, &ClearCategoryDetail);
117           return false;
118         }
119         c->name = strdup(category);
120         if (!c->name) {
121           LOG(ERROR) << "Out of memory";
122           free(c);
123           g_list_free_full(category_list, &ClearCategoryDetail);
124           return false;
125         }
126         category_list = g_list_append(category_list, c);
127       }
128     }
129
130     // skip application if it has no given category
131     if (!category_list) {
132       if (action_type != ActionType::Upgrade)
133         continue;
134       auto iter = std::lower_bound(appid_list.begin(), appid_list.end(),
135                                      app->appid);
136       if (iter != appid_list.end() && *iter == app->appid) {
137         name = GetFunctionName(ActionType::Removed);
138         iter = appid_list.erase(iter);
139         category_list = nullptr;
140       } else {
141         continue;
142       }
143     } else {
144       name = GetFunctionName(action_type);
145       if (!AddPluginInfo(manifest, app->appid)) {
146         g_list_free_full(category_list, &ClearCategoryDetail);
147         return false;
148       }
149       auto iter = std::lower_bound(appid_list.begin(), appid_list.end(),
150                                      app->appid);
151       if (iter != appid_list.end() && *iter == app->appid)
152         appid_list.erase(iter);
153     }
154     int result = 0;
155     Exec(name, &result, manifest->package, app->appid, category_list);
156     if (result) {
157       LOG(ERROR) << "Function: " << name << " of plugin "
158                  << plugin_info_.path() << " failed";
159       g_list_free_full(category_list, &ClearCategoryDetail);
160       return false;
161     }
162     g_list_free_full(category_list, &ClearCategoryDetail);
163   }
164
165   if (action_type != ActionType::Upgrade)
166     return true;
167
168   name = GetFunctionName(ActionType::Removed);
169   for (const auto& appid : appid_list) {
170     int result = 0;
171     Exec(name, &result, manifest->package, appid, nullptr);
172     if (result) {
173       LOG(ERROR) << "Function: " << name << " of plugin "
174                 << plugin_info_.path() << " failed";
175       return false;
176     }
177   }
178   return true;
179 }
180
181 }  // namespace common_installer