Move wgt-backend implementation from app-installers
[platform/core/appfw/wgt-backend.git] / src / wgt / step / step_parse.cc
1 /* 2014, Copyright © Intel Coporation, license APACHE-2.0, see LICENSE file */
2 // Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3 // Use of this source code is governed by a apache 2.0 license that can be
4 // found in the LICENSE file.
5
6 #include "wgt/step/step_parse.h"
7
8 #include <common/app_installer.h>
9 #include <common/installer_context.h>
10 #include <common/step/step.h>
11 #include <common/utils/glist_range.h>
12 #include <manifest_handlers/account_handler.h>
13 #include <manifest_handlers/app_control_handler.h>
14 #include <manifest_handlers/application_icons_handler.h>
15 #include <manifest_handlers/application_manifest_constants.h>
16 #include <manifest_handlers/background_category_handler.h>
17 #include <manifest_handlers/category_handler.h>
18 #include <manifest_handlers/content_handler.h>
19 #include <manifest_handlers/metadata_handler.h>
20 #include <manifest_handlers/service_handler.h>
21 #include <manifest_handlers/setting_handler.h>
22 #include <manifest_handlers/tizen_application_handler.h>
23 #include <manifest_handlers/widget_handler.h>
24
25 #include <pkgmgr/pkgmgr_parser.h>
26
27 #include <string.h>
28
29 #include <chrono>
30 #include <cstdio>
31 #include <cstdlib>
32 #include <memory>
33 #include <set>
34 #include <string>
35 #include <vector>
36
37 #include "wgt/wgt_backend_data.h"
38
39 namespace {
40
41 const std::string kManifestVersion = "1.0.0";
42 const char kTizenPackageXmlNamespace[] = "http://tizen.org/ns/packages";
43
44 GList* GenerateMetadataListX(const wgt::parse::MetaDataInfo& meta_info) {
45   GList* list = nullptr;
46   for (auto& meta : meta_info.metadata()) {
47     metadata_x* new_meta =
48         static_cast<metadata_x*>(calloc(1, sizeof(metadata_x)));
49     new_meta->key = strdup(meta.first.c_str());
50     if (!meta.second.empty())
51       new_meta->value = strdup(meta.second.c_str());
52     list = g_list_append(list, new_meta);
53   }
54   return list;
55 }
56
57 void SetApplicationXDefaults(application_x* application) {
58   application->ambient_support = strdup("false");
59   application->effectimage_type = strdup("image");
60   application->enabled = strdup("true");
61   application->guestmode_visibility = strdup("true");
62   application->hwacceleration = strdup("default");
63   application->indicatordisplay = strdup("true");
64   application->launchcondition = strdup("false");
65   application->permission_type = strdup("normal");
66   application->process_pool = strdup("false");
67   application->recentimage = strdup("false");
68   application->screenreader = strdup("use-system-setting");
69   application->submode = strdup("false");
70   application->support_disable = strdup("false");
71   application->taskmanage = strdup("true");
72   application->ui_gadget = strdup("false");
73 }
74
75 }  // namespace
76
77 namespace wgt {
78 namespace parse {
79
80 namespace app_keys = wgt::application_widget_keys;
81 namespace sc = std::chrono;
82
83 StepParse::StepParse(common_installer::InstallerContext* context,
84                      bool check_start_file)
85     : Step(context),
86       check_start_file_(check_start_file) {
87 }
88
89 std::set<std::string> StepParse::ExtractPrivileges(
90     std::shared_ptr<const PermissionsInfo> perm_info) const {
91   return perm_info->GetAPIPermissions();
92 }
93
94 const std::string& StepParse::GetPackageVersion(
95      const std::string& manifest_version) {
96   if (!manifest_version.empty())
97     return manifest_version;
98   return kManifestVersion;
99 }
100
101 bool StepParse::FillInstallationInfo(manifest_x* manifest) {
102   manifest->root_path = strdup(
103       (context_->root_application_path.get() / manifest->package).c_str());
104   manifest->installed_time =
105       strdup(std::to_string(sc::system_clock::to_time_t(
106           sc::system_clock::now())).c_str());
107   return true;
108 }
109
110 bool StepParse::FillIconPaths(manifest_x* manifest) {
111   std::shared_ptr<const ApplicationIconsInfo> icons_info =
112       std::static_pointer_cast<const ApplicationIconsInfo>(
113           parser_->GetManifestData(app_keys::kIconsKey));
114   if (icons_info.get()) {
115     for (auto& application_icon : icons_info->icons()) {
116       icon_x* icon = reinterpret_cast<icon_x*> (calloc(1, sizeof(icon_x)));
117       icon->text = strdup(application_icon.path().c_str());
118       icon->lang = strdup(DEFAULT_LOCALE);
119       manifest->icon = g_list_append(manifest->icon, icon);
120     }
121   }
122   return true;
123 }
124
125 bool StepParse::FillWidgetInfo(manifest_x* manifest) {
126   std::shared_ptr<const WidgetInfo> wgt_info =
127       std::static_pointer_cast<const WidgetInfo>(parser_->GetManifestData(
128           app_keys::kWidgetKey));
129   if (!wgt_info.get()) {
130     LOG(ERROR) << "Widget info manifest data has not been found.";
131     return false;
132   }
133
134   const std::string& version = wgt_info->version();
135
136   manifest->ns = strdup(kTizenPackageXmlNamespace);
137   manifest->version = strdup(GetPackageVersion(version).c_str());
138
139   for (auto& item : wgt_info->description_set()) {
140     description_x* description = reinterpret_cast<description_x*>
141         (calloc(1, sizeof(description_x)));
142     description->text = strdup(item.second.c_str());
143     description->lang = !item.first.empty() ?
144         strdup(item.first.c_str()) : strdup(DEFAULT_LOCALE);
145     manifest->description = g_list_append(manifest->description, description);
146   }
147
148   for (auto& item : wgt_info->name_set()) {
149     label_x* label = reinterpret_cast<label_x*>(calloc(1, sizeof(label_x)));
150     label->name = strdup(item.second.c_str());
151     label->text = strdup(item.second.c_str());
152     label->lang = !item.first.empty() ?
153         strdup(item.first.c_str()) : strdup(DEFAULT_LOCALE);
154     manifest->label = g_list_append(manifest->label, label);
155   }
156
157   manifest->type = strdup("wgt");
158   manifest->appsetting = strdup("false");
159   manifest->nodisplay_setting = strdup("false");
160
161   // For wgt package use the long name
162   for (auto& item : wgt_info->name_set()) {
163     application_x* app =
164         reinterpret_cast<application_x*>(manifest->application->data);
165     label_x* label = reinterpret_cast<label_x*>(calloc(1, sizeof(label_x)));
166     label->name = strdup(item.second.c_str());
167     label->text = strdup(item.second.c_str());
168     label->lang = !item.first.empty() ?
169         strdup(item.first.c_str()) : strdup(DEFAULT_LOCALE);
170     app->label = g_list_append(app->label, label);
171   }
172
173   author_x* author = reinterpret_cast<author_x*>(calloc(1, sizeof(author_x)));
174   if (!wgt_info->author().empty())
175     author->text = strdup(wgt_info->author().c_str());
176   if (!wgt_info->author_email().empty())
177     author->email = strdup(wgt_info->author_email().c_str());
178   if (!wgt_info->author_href().empty())
179     author->href = strdup(wgt_info->author_href().c_str());
180   author->lang = strdup(DEFAULT_LOCALE);
181   manifest->author = g_list_append(manifest->author, author);
182
183   std::shared_ptr<const SettingInfo> settings_info =
184       std::static_pointer_cast<const SettingInfo>(
185           parser_->GetManifestData(
186               wgt::application_widget_keys::kTizenSettingKey));
187   if (settings_info) {
188     switch (settings_info->install_location()) {
189     case wgt::parse::SettingInfo::InstallLocation::AUTO: {
190       manifest->installlocation = strdup("auto");
191       break;
192     }
193     case wgt::parse::SettingInfo::InstallLocation::INTERNAL: {
194       manifest->installlocation = strdup("internal-only");
195       break;
196     }
197     case wgt::parse::SettingInfo::InstallLocation::EXTERNAL: {
198       manifest->installlocation = strdup("prefer-external");
199       break;
200     }
201     }
202   } else {
203     manifest->installlocation = strdup("auto");
204   }
205
206   return true;
207 }
208
209 bool StepParse::FillUIApplicationInfo(manifest_x* manifest) {
210   std::shared_ptr<const TizenApplicationInfo> app_info =
211       std::static_pointer_cast<const TizenApplicationInfo>(
212           parser_->GetManifestData(app_keys::kTizenApplicationKey));
213   if (!app_info) {
214     LOG(ERROR) << "Application info manifest data has not been found.";
215     return false;
216   }
217   // application data
218   application_x* application = reinterpret_cast<application_x*>(
219       calloc(1, sizeof(application_x)));
220   application->component_type = strdup("uiapp");
221   application->mainapp = strdup("true");
222   application->nodisplay = strdup("false");
223   application->multiple = strdup("false");
224   application->appid = strdup(app_info->id().c_str());
225   SetApplicationXDefaults(application);
226   application->package = strdup(app_info->package().c_str());
227
228   application->exec =
229       strdup((context_->root_application_path.get() / app_info->package()
230               / "bin" / application->appid).c_str());
231   application->type = strdup("webapp");
232   application->onboot = strdup("false");
233   application->autorestart = strdup("false");
234
235   application->launch_mode = strdup(app_info->launch_mode().c_str());
236   if (manifest->icon) {
237     icon_x* icon = reinterpret_cast<icon_x*>(manifest->icon->data);
238     icon_x* app_icon = reinterpret_cast<icon_x*>(calloc(1, sizeof(icon_x)));
239     app_icon->text = strdup(icon->text);
240     app_icon->lang = strdup(icon->lang);
241     application->icon = g_list_append(application->icon, app_icon);
242   }
243   manifest->application = g_list_append(manifest->application, application);
244
245   manifest->package = strdup(app_info->package().c_str());
246   manifest->mainapp_id = strdup(app_info->id().c_str());
247   return true;
248 }
249
250 bool StepParse::FillServiceApplicationInfo(manifest_x* manifest) {
251   std::shared_ptr<const ServiceList> service_list =
252       std::static_pointer_cast<const ServiceList>(
253           parser_->GetManifestData(app_keys::kTizenServiceKey));
254   if (!service_list)
255     return true;
256   for (auto& service_info : service_list->services) {
257     application_x* application = reinterpret_cast<application_x*>
258         (calloc(1, sizeof(application_x)));
259     application->component_type = strdup("svcapp");
260     application->mainapp = strdup("false");
261     application->nodisplay = strdup("false");
262     application->multiple = strdup("false");
263     application->appid = strdup(service_info.id().c_str());
264     application->exec =
265         strdup((context_->root_application_path.get() / manifest->package
266                 / "bin" / application->appid).c_str());
267     application->type = strdup("webapp");
268     application->onboot =
269         service_info.on_boot() ? strdup("true") : strdup("false");
270     application->autorestart =
271         service_info.auto_restart() ? strdup("true") : strdup("false");
272     SetApplicationXDefaults(application);
273     application->package = strdup(manifest->package);
274
275     for (auto& pair : service_info.names()) {
276       label_x* label = reinterpret_cast<label_x*>(calloc(1, sizeof(label_x)));
277       label->lang = !pair.first.empty() ?
278           strdup(pair.first.c_str()) : strdup(DEFAULT_LOCALE);
279       label->name = strdup(pair.second.c_str());
280       label->text = strdup(pair.second.c_str());
281       application->label = g_list_append(application->label, label);
282     }
283
284     if (!service_info.icon().empty()) {
285       icon_x* icon = reinterpret_cast<icon_x*>(calloc(1, sizeof(icon_x)));
286       icon->text = strdup(service_info.icon().c_str());
287       icon->lang = strdup(DEFAULT_LOCALE);
288       application->icon = g_list_append(application->icon, icon);
289     }
290
291     // TODO(t.iwanek): what about description, how is it different from name?
292
293     for (auto& category : service_info.categories()) {
294       application->category = g_list_append(application->category,
295                                             strdup(category.c_str()));
296     }
297
298     for (auto& pair : service_info.metadata_set()) {
299       metadata_x* item = reinterpret_cast<metadata_x*>(
300           calloc(1, sizeof(metadata_x)));
301       item->key = strdup(pair.first.c_str());
302       if (!pair.second.empty())
303         item->value = strdup(pair.second.c_str());
304       application->metadata = g_list_append(application->metadata, item);
305     }
306
307     manifest->application = g_list_append(manifest->application, application);
308   }
309   return true;
310 }
311
312 bool StepParse::FillBackgroundCategoryInfo(manifest_x* manifest) {
313   auto manifest_data = parser_->GetManifestData(
314       app_keys::kTizenBackgroundCategoryKey);
315   std::shared_ptr<const BackgroundCategoryInfoList> bc_list =
316       std::static_pointer_cast<const BackgroundCategoryInfoList>(manifest_data);
317
318   if (!bc_list)
319     return true;
320
321   application_x* app =
322       reinterpret_cast<application_x*>(manifest->application->data);
323
324   for (auto& background_category : bc_list->background_categories) {
325     app->background_category = g_list_append(
326         app->background_category, strdup(background_category.value().c_str()));
327   }
328
329   return true;
330 }
331
332 bool StepParse::FillAppControl(manifest_x* manifest) {
333   std::shared_ptr<const AppControlInfoList> app_info_list =
334       std::static_pointer_cast<const AppControlInfoList>(
335           parser_->GetManifestData(app_keys::kTizenApplicationAppControlsKey));
336
337   application_x* app =
338       reinterpret_cast<application_x*>(manifest->application->data);
339   if (app_info_list) {
340     for (const auto& control : app_info_list->controls) {
341       appcontrol_x* app_control =
342           static_cast<appcontrol_x*>(calloc(1, sizeof(appcontrol_x)));
343       app_control->operation = strdup(control.operation().c_str());
344       app_control->mime = strdup(control.mime().c_str());
345       app_control->uri = strdup(control.uri().c_str());
346       app->appcontrol = g_list_append(app->appcontrol, app_control);
347     }
348   }
349   return true;
350 }
351
352 bool StepParse::FillPrivileges(manifest_x* manifest) {
353   std::shared_ptr<const PermissionsInfo> perm_info =
354       std::static_pointer_cast<const PermissionsInfo>(parser_->GetManifestData(
355           app_keys::kTizenPermissionsKey));
356   std::set<std::string> privileges;
357   if (perm_info)
358     privileges = ExtractPrivileges(perm_info);
359
360   for (auto& priv : privileges) {
361     manifest->privileges =
362         g_list_append(manifest->privileges, strdup(priv.c_str()));
363   }
364   return true;
365 }
366
367 bool StepParse::FillCategories(manifest_x* manifest) {
368   std::shared_ptr<const CategoryInfoList> category_info =
369       std::static_pointer_cast<const CategoryInfoList>(parser_->GetManifestData(
370           app_keys::kTizenCategoryKey));
371   if (!category_info)
372     return true;
373
374   application_x* app =
375       reinterpret_cast<application_x*>(manifest->application->data);
376   // there is one app atm
377   for (auto& category : category_info->categories) {
378     app->category = g_list_append(app->category, strdup(category.c_str()));
379   }
380   return true;
381 }
382
383 bool StepParse::FillMetadata(manifest_x* manifest) {
384   std::shared_ptr<const MetaDataInfo> meta_info =
385       std::static_pointer_cast<const MetaDataInfo>(parser_->GetManifestData(
386           app_keys::kTizenMetaDataKey));
387   if (!meta_info)
388     return true;
389
390   for (application_x* app : GListRange<application_x*>(manifest->application)) {
391     app->metadata = GenerateMetadataListX(*meta_info);
392   }
393   return true;
394 }
395
396 bool StepParse::FillAccounts(manifest_x* manifest) {
397   std::shared_ptr<const AccountInfo> account_info =
398       std::static_pointer_cast<const AccountInfo>(parser_->GetManifestData(
399           app_keys::kAccountKey));
400   if (!account_info)
401     return true;
402   common_installer::AccountInfo info;
403   for (auto& account : account_info->accounts()) {
404     common_installer::SingleAccountInfo single_info;
405     single_info.capabilities = account.capabilities;
406     single_info.icon_paths = account.icon_paths;
407     single_info.multiple_account_support = account.multiple_account_support;
408     single_info.names = account.names;
409     // wgt can contain only one app so this assumes mainapp_id is valid here
410     single_info.appid = manifest->mainapp_id;
411     info.set_account(single_info);
412   }
413   context_->manifest_plugins_data.get().account_info.set(info);
414   return true;
415 }
416
417 bool StepParse::FillExtraManifestInfo(manifest_x* manifest) {
418   return FillAccounts(manifest);
419 }
420
421 bool StepParse::FillManifestX(manifest_x* manifest) {
422   if (!FillIconPaths(manifest))
423     return false;
424   if (!FillUIApplicationInfo(manifest))
425     return false;
426   if (!FillWidgetInfo(manifest))
427     return false;
428   if (!FillInstallationInfo(manifest))
429     return false;
430   if (!FillPrivileges(manifest))
431     return false;
432   if (!FillAppControl(manifest))
433     return false;
434   if (!FillCategories(manifest))
435     return false;
436   if (!FillMetadata(manifest))
437     return false;
438   // TODO(t.iwanek): fix adding ui application element
439   // for now adding application service is added here because rest of code
440   // assumes that there is one application at manifest->application
441   // so this must execute last
442   if (!FillServiceApplicationInfo(manifest))
443     return false;
444   if (!FillBackgroundCategoryInfo(manifest))
445     return false;
446   if (!FillExtraManifestInfo(manifest))
447     return false;
448   return true;
449 }
450
451 bool StepParse::LocateConfigFile() {
452   return StepParse::Check(context_->unpacked_dir_path.get());
453 }
454
455 common_installer::Step::Status StepParse::process() {
456   if (!LocateConfigFile()) {
457     LOG(ERROR) << "No config.xml";
458     return common_installer::Step::Status::ERROR;
459   }
460
461   parser_.reset(new wgt::parse::WidgetConfigParser());
462   if (!parser_->ParseManifest(config_)) {
463     LOG(ERROR) << "[Parse] Parse failed. " <<  parser_->GetErrorMessage();
464     return common_installer::Step::Status::ERROR;
465   }
466   if (check_start_file_) {
467     if (!parser_->HasValidStartFile()) {
468       LOG(ERROR) << parser_->GetErrorMessage();
469       return common_installer::Step::Status::ERROR;
470     }
471     if (!parser_->HasValidServicesStartFiles()) {
472       LOG(ERROR) << parser_->GetErrorMessage();
473       return common_installer::Step::Status::ERROR;
474     }
475   }
476
477   manifest_x* manifest =
478       static_cast<manifest_x*>(calloc(1, sizeof(manifest_x)));
479   if (!FillManifestX(manifest)) {
480     LOG(ERROR) << "[Parse] Storing manifest_x failed. "
481                <<  parser_->GetErrorMessage();
482     return common_installer::Step::Status::ERROR;
483   }
484
485   // Copy data from ManifestData to InstallerContext
486   std::shared_ptr<const TizenApplicationInfo> info =
487       std::static_pointer_cast<const TizenApplicationInfo>(
488           parser_->GetManifestData(
489               wgt::application_widget_keys::kTizenApplicationKey));
490   std::shared_ptr<const WidgetInfo> wgt_info =
491       std::static_pointer_cast<const WidgetInfo>(
492           parser_->GetManifestData(
493               wgt::application_widget_keys::kTizenWidgetKey));
494
495   std::string name;
496   const auto& name_set = wgt_info->name_set();
497   if (name_set.find("") != name_set.end())
498     name = name_set.find("")->second;
499   if (name_set.begin() != name_set.end())
500     name = name_set.begin()->second;
501
502   std::string short_name;
503   const auto& short_name_set = wgt_info->short_name_set();
504   if (short_name_set.find("") != short_name_set.end())
505     short_name = short_name_set.find("")->second;
506   if (short_name_set.begin() != short_name_set.end())
507     short_name = short_name_set.begin()->second;
508
509   const std::string& package_version = wgt_info->version();
510   const std::string& required_api_version = info->required_version();
511
512   manifest->api_version = strdup(required_api_version.c_str());
513   context_->pkgid.set(manifest->package);
514
515   // write pkgid for recovery file
516   if (context_->recovery_info.get().recovery_file) {
517     context_->recovery_info.get().recovery_file->set_pkgid(manifest->package);
518     context_->recovery_info.get().recovery_file->WriteAndCommitFileContent();
519   }
520
521   std::shared_ptr<const PermissionsInfo> perm_info =
522       std::static_pointer_cast<const PermissionsInfo>(
523           parser_->GetManifestData(
524               wgt::application_widget_keys::kTizenPermissionsKey));
525   parser::PermissionSet permissions;
526   if (perm_info)
527      permissions = perm_info->GetAPIPermissions();
528
529   std::unique_ptr<WgtBackendData> backend_data(new WgtBackendData());
530
531   std::shared_ptr<const SettingInfo> settings_info =
532       std::static_pointer_cast<const SettingInfo>(
533           parser_->GetManifestData(
534               wgt::application_widget_keys::kTizenSettingKey));
535   if (settings_info)
536     backend_data->settings.set(*settings_info);
537
538   context_->backend_data.set(backend_data.release());
539
540   LOG(DEBUG) << " Read data -[ ";
541   LOG(DEBUG) << "App id: " << info->id();
542   LOG(DEBUG) << "  package     = " <<  info->package();
543   LOG(DEBUG) << "  id          = " <<  info->id();
544   LOG(DEBUG) << "  name        = " <<  name;
545   LOG(DEBUG) << "  short_name  = " <<  short_name;
546   LOG(DEBUG) << "  aplication version     = " <<  package_version;
547   LOG(DEBUG) << "  api_version = " <<  info->required_version();
548   LOG(DEBUG) << "  launch_mode = " <<  info->launch_mode();
549   LOG(DEBUG) << "  privileges -[";
550   for (const auto& p : permissions) {
551     LOG(DEBUG) << "    " << p;
552   }
553   LOG(DEBUG) << "  ]-";
554   LOG(DEBUG) << "]-";
555
556   context_->manifest_data.set(manifest);
557   return common_installer::Step::Status::OK;
558 }
559
560 bool StepParse::Check(const boost::filesystem::path& widget_path) {
561   boost::filesystem::path config = widget_path;
562   config /= "config.xml";
563
564   LOG(DEBUG) << "config.xml path: " << config;
565
566   if (!boost::filesystem::exists(config))
567     return false;
568
569   config_ = config;
570   return true;
571 }
572
573 }  // namespace parse
574 }  // namespace wgt