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