change some returning error-codes
[platform/core/appfw/wgt-backend.git] / src / wgt / step / step_generate_xml.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_generate_xml.h"
7
8 #include <boost/filesystem/path.hpp>
9 #include <boost/system/error_code.hpp>
10
11 #include <common/utils/file_util.h>
12 #include <common/utils/glist_range.h>
13
14 #include <libxml/parser.h>
15 #include <libxml/xmlreader.h>
16 #include <pkgmgr-info.h>
17 #include <pkgmgr_parser.h>
18 #include <tzplatform_config.h>
19 #include <unistd.h>
20
21 #include <cassert>
22 #include <cstring>
23 #include <string>
24
25
26 namespace bs = boost::system;
27 namespace bf = boost::filesystem;
28
29 namespace {
30
31 void WriteUIApplicationAttributes(
32     xmlTextWriterPtr writer, application_x *app) {
33   xmlTextWriterWriteAttribute(writer, BAD_CAST "taskmanage",
34       BAD_CAST "true");
35   if (app->nodisplay)
36     xmlTextWriterWriteAttribute(writer, BAD_CAST "nodisplay",
37         BAD_CAST app->nodisplay);
38   if (app->multiple)
39     xmlTextWriterWriteAttribute(writer, BAD_CAST "multiple",
40         BAD_CAST app->multiple);
41   if (app->launch_mode && strlen(app->launch_mode))
42     xmlTextWriterWriteAttribute(writer, BAD_CAST "launch_mode",
43         BAD_CAST app->launch_mode);
44   if (app->ui_gadget && strlen(app->ui_gadget))
45     xmlTextWriterWriteAttribute(writer, BAD_CAST "ui-gadget",
46         BAD_CAST app->ui_gadget);
47   if (app->submode && strlen(app->submode))
48     xmlTextWriterWriteAttribute(writer, BAD_CAST "submode",
49         BAD_CAST app->submode);
50   if (app->submode_mainid && strlen(app->submode_mainid))
51     xmlTextWriterWriteAttribute(writer, BAD_CAST "submode-mainid",
52         BAD_CAST app->submode_mainid);
53   if (app->indicatordisplay && strlen(app->indicatordisplay))
54     xmlTextWriterWriteAttribute(writer, BAD_CAST "indicatordisplay",
55         BAD_CAST app->indicatordisplay);
56   if (app->portraitimg && strlen(app->portraitimg))
57     xmlTextWriterWriteAttribute(writer, BAD_CAST "portrait-effectimage",
58         BAD_CAST app->portraitimg);
59   if (app->landscapeimg && strlen(app->landscapeimg))
60     xmlTextWriterWriteAttribute(writer, BAD_CAST "landscape-effectimage",
61         BAD_CAST app->landscapeimg);
62   if (app->effectimage_type && strlen(app->effectimage_type))
63     xmlTextWriterWriteAttribute(writer, BAD_CAST "effectimage-type",
64         BAD_CAST app->effectimage_type);
65   if (app->hwacceleration && strlen(app->hwacceleration))
66     xmlTextWriterWriteAttribute(writer, BAD_CAST "hwacceleration",
67         BAD_CAST app->hwacceleration);
68 }
69
70 void WriteServiceApplicationAttributes(
71     xmlTextWriterPtr writer, application_x *app) {
72   xmlTextWriterWriteAttribute(writer, BAD_CAST "auto-restart",
73       BAD_CAST(app->autorestart ? app->autorestart : "false"));
74   xmlTextWriterWriteAttribute(writer, BAD_CAST "on-boot",
75       BAD_CAST(app->onboot ? app->onboot : "false"));
76   xmlTextWriterWriteAttribute(writer, BAD_CAST "taskmanage",
77       BAD_CAST "false");
78 }
79
80 void WriteWidgetApplicationAttributes(
81     xmlTextWriterPtr writer, application_x *app) {
82   if (app->nodisplay)
83     xmlTextWriterWriteAttribute(writer, BAD_CAST "nodisplay",
84         BAD_CAST app->nodisplay);
85   if (app->multiple)
86     xmlTextWriterWriteAttribute(writer, BAD_CAST "multiple",
87         BAD_CAST app->multiple);
88 }
89
90 }  // namespace
91
92 namespace wgt {
93 namespace pkgmgr {
94
95 common_installer::Step::Status StepGenerateXml::GenerateApplicationCommonXml(
96     application_x* app, xmlTextWriterPtr writer, AppCompType type) {
97   xmlTextWriterWriteAttribute(writer, BAD_CAST "appid", BAD_CAST app->appid);
98
99   // binary is a symbolic link named <appid> and is located in <pkgid>/<appid>
100   bf::path exec_path = context_->pkg_path.get()
101       / bf::path("bin") / bf::path(app->appid);
102   xmlTextWriterWriteAttribute(writer, BAD_CAST "exec",
103                               BAD_CAST exec_path.string().c_str());
104   if (app->type)
105     xmlTextWriterWriteAttribute(writer, BAD_CAST "type", BAD_CAST app->type);
106   else
107     xmlTextWriterWriteAttribute(writer, BAD_CAST "type", BAD_CAST "capp");
108
109   if (app->process_pool && strlen(app->process_pool))
110     xmlTextWriterWriteAttribute(writer, BAD_CAST "process-pool",
111                                 BAD_CAST app->process_pool);
112   // app-specific attributes
113   switch (type) {
114   case AppCompType::UIAPP:
115     WriteServiceApplicationAttributes(writer, app);
116     break;
117   case AppCompType::SVCAPP:
118     WriteUIApplicationAttributes(writer, app);
119     break;
120   case AppCompType::WIDGETAPP:
121     WriteWidgetApplicationAttributes(writer, app);
122     break;
123   }
124
125   for (label_x* label : GListRange<label_x*>(app->label)) {
126     xmlTextWriterStartElement(writer, BAD_CAST "label");
127     if (label->lang && strcmp(DEFAULT_LOCALE, label->lang) != 0) {
128       xmlTextWriterWriteAttribute(writer, BAD_CAST "xml:lang",
129                                   BAD_CAST label->lang);
130     }
131     xmlTextWriterWriteString(writer, BAD_CAST label->name);
132     xmlTextWriterEndElement(writer);
133   }
134
135   // icon is renamed to <appid.png>
136   if (app->icon) {
137     icon_x* iconx = reinterpret_cast<icon_x*>(app->icon->data);
138     bf::path app_icon = context_->pkg_path.get();
139     // TODO(t.iwanek): type should not be used here
140     if (context_->pkg_type.get() == "wgt") {
141       app_icon /= "res/wgt";
142     } else {
143       app_icon /= "shared/res";
144     }
145     app_icon /= iconx->text;
146     bf::path icon = app->appid;
147     if (app_icon.has_extension())
148       icon += app_icon.extension();
149     else
150       icon += bf::path(".png");
151
152     if (bf::exists(app_icon)) {
153       xmlTextWriterWriteFormatElement(writer, BAD_CAST "icon",
154                                           "%s", BAD_CAST icon.c_str());
155     }
156   } else {
157     // Default icon setting is role of the platform
158     LOG(DEBUG) << "Icon was not found in package";
159   }
160
161   for (image_x* image : GListRange<image_x*>(app->image)) {
162     xmlTextWriterStartElement(writer, BAD_CAST "image");
163     xmlTextWriterWriteAttribute(writer, BAD_CAST "name",
164         BAD_CAST image->name);
165     if (image->lang && strcmp(DEFAULT_LOCALE, image->lang) != 0) {
166       xmlTextWriterWriteAttribute(writer, BAD_CAST "xml:lang",
167
168                                   BAD_CAST image->lang);
169     }
170     if (image->section)
171       xmlTextWriterWriteAttribute(writer, BAD_CAST "section",
172                                   BAD_CAST image->section);
173     xmlTextWriterEndElement(writer);
174   }
175
176   for (appcontrol_x* appc : GListRange<appcontrol_x*>(app->appcontrol)) {
177     xmlTextWriterStartElement(writer, BAD_CAST "app-control");
178
179     if (appc->operation) {
180       xmlTextWriterStartElement(writer, BAD_CAST "operation");
181       xmlTextWriterWriteAttribute(writer, BAD_CAST "name",
182           BAD_CAST appc->operation);
183       xmlTextWriterEndElement(writer);
184     }
185
186     if (appc->uri) {
187       xmlTextWriterStartElement(writer, BAD_CAST "uri");
188       xmlTextWriterWriteAttribute(writer, BAD_CAST "name",
189           BAD_CAST appc->uri);
190       xmlTextWriterEndElement(writer);
191     }
192
193     if (appc->mime) {
194       xmlTextWriterStartElement(writer, BAD_CAST "mime");
195       xmlTextWriterWriteAttribute(writer, BAD_CAST "name",
196           BAD_CAST appc->mime);
197       xmlTextWriterEndElement(writer);
198     }
199
200     xmlTextWriterEndElement(writer);
201   }
202
203   for (datacontrol_x* datacontrol :
204        GListRange<datacontrol_x*>(app->datacontrol)) {
205     xmlTextWriterStartElement(writer, BAD_CAST "datacontrol");
206     if (datacontrol->access) {
207       xmlTextWriterWriteAttribute(writer, BAD_CAST "access",
208           BAD_CAST datacontrol->access);
209     }
210     if (datacontrol->providerid) {
211       xmlTextWriterWriteAttribute(writer, BAD_CAST "providerid",
212           BAD_CAST datacontrol->providerid);
213     }
214     if (datacontrol->type) {
215       xmlTextWriterWriteAttribute(writer, BAD_CAST "type",
216           BAD_CAST datacontrol->type);
217     }
218     xmlTextWriterEndElement(writer);
219   }
220
221   for (metadata_x* meta : GListRange<metadata_x*>(app->metadata)) {
222     xmlTextWriterStartElement(writer, BAD_CAST "metadata");
223     xmlTextWriterWriteAttribute(writer, BAD_CAST "key",
224         BAD_CAST meta->key);
225     if (meta->value)
226       xmlTextWriterWriteAttribute(writer, BAD_CAST "value",
227           BAD_CAST meta->value);
228     xmlTextWriterEndElement(writer);
229   }
230
231   for (const char* category : GListRange<char*>(app->category)) {
232     xmlTextWriterStartElement(writer, BAD_CAST "category");
233     xmlTextWriterWriteAttribute(writer, BAD_CAST "name", BAD_CAST category);
234     xmlTextWriterEndElement(writer);
235   }
236
237   for (const char* background_category : GListRange<char*>(
238       app->background_category)) {
239     xmlTextWriterStartElement(writer, BAD_CAST "background-category");
240     xmlTextWriterWriteAttribute(writer, BAD_CAST "value",
241         BAD_CAST background_category);
242     xmlTextWriterEndElement(writer);
243   }
244
245   return Step::Status::OK;
246 }
247
248 common_installer::Step::Status StepGenerateXml::precheck() {
249   if (!context_->manifest_data.get()) {
250     LOG(ERROR) << "manifest_data attribute is empty";
251     return Step::Status::INVALID_VALUE;
252   }
253   if (context_->pkgid.get().empty()) {
254     LOG(ERROR) << "pkgid attribute is empty";
255     return Step::Status::PACKAGE_NOT_FOUND;   }
256
257   if (!context_->manifest_data.get()->application) {
258     LOG(ERROR) << "No application in package";
259     return Step::Status::INVALID_VALUE;
260   }
261   // TODO(p.sikorski) check context_->uid.get()
262
263   return Step::Status::OK;
264 }
265
266 common_installer::Step::Status StepGenerateXml::process() {
267   bf::path xml_path = bf::path(getUserManifestPath(context_->uid.get()))
268       / bf::path(context_->pkgid.get());
269   xml_path += ".xml";
270   context_->xml_path.set(xml_path.string());
271
272   bs::error_code error;
273   if (!bf::exists(xml_path.parent_path(), error)) {
274     if (!common_installer::CreateDir(xml_path.parent_path())) {
275       LOG(ERROR) <<
276           "Directory for manifest xml is missing and cannot be created";
277       return Status::MANIFEST_ERROR;
278     }
279   }
280
281   xmlTextWriterPtr writer;
282
283   writer = xmlNewTextWriterFilename(context_->xml_path.get().c_str(), 0);
284   if (!writer) {
285     LOG(ERROR) << "Failed to create new file";
286     return Step::Status::MANIFEST_ERROR;
287   }
288
289   xmlTextWriterStartDocument(writer, nullptr, nullptr, nullptr);
290
291   xmlTextWriterSetIndent(writer, 1);
292
293   // add manifest Element
294   xmlTextWriterStartElement(writer, BAD_CAST "manifest");
295
296   xmlTextWriterWriteAttribute(writer, BAD_CAST "xmlns",
297       BAD_CAST "http://tizen.org/ns/packages");
298   xmlTextWriterWriteAttribute(writer, BAD_CAST "package",
299       BAD_CAST context_->manifest_data.get()->package);
300   xmlTextWriterWriteAttribute(writer, BAD_CAST "type",
301       BAD_CAST context_->manifest_data.get()->type);
302   xmlTextWriterWriteAttribute(writer, BAD_CAST "version",
303       BAD_CAST context_->manifest_data.get()->version);
304   xmlTextWriterWriteAttribute(writer, BAD_CAST "api-version",
305       BAD_CAST context_->manifest_data.get()->api_version);
306   xmlTextWriterWriteAttribute(writer, BAD_CAST "nodisplay-setting",
307       BAD_CAST context_->manifest_data.get()->nodisplay_setting);
308
309   for (label_x* label :
310        GListRange<label_x*>(context_->manifest_data.get()->label)) {
311     xmlTextWriterStartElement(writer, BAD_CAST "label");
312     if (label->lang && strcmp(DEFAULT_LOCALE, label->lang) != 0) {
313       xmlTextWriterWriteAttribute(writer, BAD_CAST "xml:lang",
314                                   BAD_CAST label->lang);
315     }
316     xmlTextWriterWriteString(writer, BAD_CAST label->name);
317     xmlTextWriterEndElement(writer);
318   }
319
320   for (author_x* author :
321        GListRange<author_x*>(context_->manifest_data.get()->author)) {
322     xmlTextWriterStartElement(writer, BAD_CAST "author");
323     if (author->email && strlen(author->email)) {
324       xmlTextWriterWriteAttribute(writer, BAD_CAST "email",
325                                   BAD_CAST author->email);
326     }
327     if (author->href && strlen(author->href)) {
328       xmlTextWriterWriteAttribute(writer, BAD_CAST "href",
329                                   BAD_CAST author->href);
330     }
331     xmlTextWriterWriteString(writer, BAD_CAST author->text);
332     xmlTextWriterEndElement(writer);
333   }
334
335   for (description_x* description :
336        GListRange<description_x*>(context_->manifest_data.get()->description)) {
337     xmlTextWriterStartElement(writer, BAD_CAST "description");
338     if (description->lang && strcmp(DEFAULT_LOCALE, description->lang) != 0) {
339       xmlTextWriterWriteAttribute(writer, BAD_CAST "xml:lang",
340                                   BAD_CAST description->lang);
341     }
342     xmlTextWriterWriteString(writer, BAD_CAST description->text);
343     xmlTextWriterEndElement(writer);
344   }
345
346   // add application
347   for (application_x* app :
348        GListRange<application_x*>(context_->manifest_data.get()->application)) {
349     AppCompType type;
350     if (strcmp(app->component_type, "uiapp") == 0) {
351       type = AppCompType::UIAPP;
352       xmlTextWriterStartElement(writer, BAD_CAST "ui-application");
353     } else if (strcmp(app->component_type, "svcapp") == 0) {
354       type = AppCompType::SVCAPP;
355       xmlTextWriterStartElement(writer, BAD_CAST "service-application");
356     } else if (strcmp(app->component_type, "widgetapp") == 0) {
357       type = AppCompType::WIDGETAPP;
358       xmlTextWriterStartElement(writer, BAD_CAST "widget-application");
359     } else {
360       LOG(ERROR) << "Unknown application component_type";
361       xmlFreeTextWriter(writer);
362       return Status::ERROR;
363     }
364     GenerateApplicationCommonXml(app, writer, type);
365     xmlTextWriterEndElement(writer);
366   }
367
368   // add privilege element
369   if (context_->manifest_data.get()->privileges) {
370     xmlTextWriterStartElement(writer, BAD_CAST "privileges");
371     for (const char* priv :
372          GListRange<char*>(context_->manifest_data.get()->privileges)) {
373       xmlTextWriterWriteFormatElement(writer, BAD_CAST "privilege",
374         "%s", BAD_CAST priv);
375     }
376     xmlTextWriterEndElement(writer);
377   }
378
379   const auto& accounts =
380       context_->manifest_plugins_data.get().account_info.get().accounts();
381   if (!accounts.empty()) {
382     xmlTextWriterStartElement(writer, BAD_CAST "account");
383     // add account info
384     for (auto& account : accounts) {
385       xmlTextWriterStartElement(writer, BAD_CAST "account-provider");
386
387       xmlTextWriterWriteAttribute(writer, BAD_CAST "appid",
388                                   BAD_CAST account.appid.c_str());
389
390       if (!account.providerid.empty())
391         xmlTextWriterWriteAttribute(writer, BAD_CAST "providerid",
392                                     BAD_CAST account.providerid.c_str());
393
394       if (account.multiple_account_support)
395         xmlTextWriterWriteAttribute(writer,
396                                     BAD_CAST "multiple-accounts-support",
397                                     BAD_CAST "true");
398       for (auto& icon_pair : account.icon_paths) {
399         xmlTextWriterStartElement(writer, BAD_CAST "icon");
400         if (icon_pair.first == "AccountSmall")
401           xmlTextWriterWriteAttribute(writer, BAD_CAST "section",
402                                       BAD_CAST "account-small");
403         else
404           xmlTextWriterWriteAttribute(writer, BAD_CAST "section",
405                                       BAD_CAST "account");
406         xmlTextWriterWriteString(writer, BAD_CAST icon_pair.second.c_str());
407         xmlTextWriterEndElement(writer);
408       }
409
410       for (auto& name_pair : account.names) {
411         xmlTextWriterStartElement(writer, BAD_CAST "label");
412         if (!name_pair.second.empty())
413           xmlTextWriterWriteAttribute(writer, BAD_CAST "xml:lang",
414                                       BAD_CAST name_pair.second.c_str());
415         xmlTextWriterWriteString(writer, BAD_CAST name_pair.first.c_str());
416         xmlTextWriterEndElement(writer);
417       }
418
419       for (auto& capability : account.capabilities) {
420         xmlTextWriterWriteFormatElement(writer, BAD_CAST "capability",
421           "%s", BAD_CAST capability.c_str());
422       }
423
424       xmlTextWriterEndElement(writer);
425     }
426     xmlTextWriterEndElement(writer);
427   }
428
429   for (const char* profile :
430        GListRange<char*>(context_->manifest_data.get()->deviceprofile)) {
431     xmlTextWriterStartElement(writer, BAD_CAST "profile");
432     xmlTextWriterWriteAttribute(writer, BAD_CAST "name",
433                                 BAD_CAST profile);
434     xmlTextWriterEndElement(writer);
435   }
436
437   const auto& shortcuts =
438       context_->manifest_plugins_data.get().shortcut_info.get();
439   if (!shortcuts.empty()) {
440     xmlTextWriterStartElement(writer, BAD_CAST "shortcut-list");
441     for (auto& shortcut : shortcuts) {
442       xmlTextWriterStartElement(writer, BAD_CAST "shortcut");
443       if (!shortcut.app_id.empty())
444         xmlTextWriterWriteAttribute(writer, BAD_CAST "appid",
445                                     BAD_CAST shortcut.app_id.c_str());
446       if (!shortcut.app_id.empty())
447         xmlTextWriterWriteAttribute(writer, BAD_CAST "extra_data",
448                                     BAD_CAST shortcut.extra_data.c_str());
449       if (!shortcut.app_id.empty())
450         xmlTextWriterWriteAttribute(writer, BAD_CAST "extra_key",
451                                     BAD_CAST shortcut.extra_key.c_str());
452       if (!shortcut.icon.empty()) {
453         xmlTextWriterStartElement(writer, BAD_CAST "icon");
454         xmlTextWriterWriteString(writer, BAD_CAST shortcut.icon.c_str());
455         xmlTextWriterEndElement(writer);
456       }
457       for (auto& label : shortcut.labels) {
458         xmlTextWriterStartElement(writer, BAD_CAST "label");
459         if (!label.first.empty())
460           xmlTextWriterWriteAttribute(writer, BAD_CAST "xml:lang",
461                                       BAD_CAST label.first.c_str());
462         xmlTextWriterWriteString(writer, BAD_CAST label.second.c_str());
463         xmlTextWriterEndElement(writer);
464       }
465       xmlTextWriterEndElement(writer);
466     }
467     xmlTextWriterEndElement(writer);
468   }
469
470   xmlTextWriterEndElement(writer);
471
472   xmlTextWriterEndDocument(writer);
473   xmlFreeTextWriter(writer);
474
475   if (pkgmgr_parser_check_manifest_validation(
476       context_->xml_path.get().c_str()) != 0) {
477     LOG(ERROR) << "Manifest is not valid";
478     return Step::Status::MANIFEST_ERROR;
479   }
480
481   LOG(DEBUG) << "Successfully create manifest xml "
482       << context_->xml_path.get();
483   return Status::OK;
484 }
485
486 common_installer::Step::Status StepGenerateXml::undo() {
487   bs::error_code error;
488   if (bf::exists(context_->xml_path.get()))
489     bf::remove_all(context_->xml_path.get(), error);
490   return Status::OK;
491 }
492
493 }  // namespace pkgmgr
494 }  // namespace wgt