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