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