Clean-up wrt-installer command and type
[framework/web/wrt-installer.git] / src / jobs / widget_install / job_widget_install.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 /*
17  * @file    job_widget_install.cpp
18  * @author  Radoslaw Wicik r.wicik@samsung.com
19  * @author  Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
20  * @version 1.0
21  * @brief   Implementation file for main installer task
22  */
23 #include <memory>
24 #include <string>
25 #include <sys/time.h>
26 #include <ctime>
27 #include <cstdlib>
28 #include <limits.h>
29 #include <regex.h>
30
31 #include <dpl/noncopyable.h>
32 #include <dpl/abstract_waitable_input_adapter.h>
33 #include <dpl/abstract_waitable_output_adapter.h>
34 #include <dpl/zip_input.h>
35 #include <dpl/binary_queue.h>
36 #include <dpl/copy.h>
37 #include <dpl/assert.h>
38 #include <dpl/sstream.h>
39 #include <dpl/file_input.h>
40 #include <dpl/utils/wrt_utility.h>
41 #include <dpl/wrt-dao-ro/common_dao_types.h>
42 #include <dpl/wrt-dao-ro/widget_dao_read_only.h>
43 #include <dpl/wrt-dao-ro/global_config.h>
44 #include <dpl/wrt-dao-ro/config_parser_data.h>
45 #include <dpl/wrt-dao-rw/global_dao.h> // TODO remove
46 #include <dpl/localization/w3c_file_localization.h>
47
48 #include <libiriwrapper.h>
49 #include <pkg-manager/pkgmgr_signal.h>
50 #include <app_manager.h>
51 //#include <drm_client.h>
52 #include <drm-oem-intel.h> //temporary code
53
54 #include "root_parser.h"
55 #include "widget_parser.h"
56 #include "parser_runner.h"
57 #include <widget_install/job_widget_install.h>
58 #include <widget_install/task_certify.h>
59 #include <widget_install/task_widget_config.h>
60 #include <widget_install/task_file_manipulation.h>
61 #include <widget_install/task_ace_check.h>
62 #include <widget_install/task_smack.h>
63 #include <widget_install/task_manifest_file.h>
64 #include <widget_install/task_prepare_files.h>
65 #include <widget_install/task_recovery.h>
66 #include <widget_install/task_install_ospsvc.h>
67 #include <widget_install/task_update_files.h>
68 #include <widget_install/task_database.h>
69 #include <widget_install/task_remove_backup.h>
70 #include <widget_install/task_encrypt_resource.h>
71 #include <widget_install/task_certificates.h>
72 #include <widget_install/task_unzip.h>
73 #include <widget_install/task_commons.h>
74
75 #include <widget_install/task_plugins_copy.h>
76
77 #include <widget_install/widget_install_errors.h>
78 #include <widget_install/widget_install_context.h>
79 #include <widget_install_to_external.h>
80
81 using namespace WrtDB;
82 using namespace Jobs::Exceptions;
83
84 namespace // anonymous
85 {
86 const char * const CONFIG_XML = "config.xml";
87 const char * const WITH_OSP_XML = "res/wgt/config.xml";
88
89 //allowed: a-z, A-Z, 0-9
90 const char* REG_TIZENID_PATTERN = "^[a-zA-Z0-9]{10}.{1,}$";
91 const char* REG_NAME_PATTERN = "^[a-zA-Z0-9._-]{1,}$";
92 const size_t PACKAGE_ID_LENGTH = 10;
93
94 static const DPL::String SETTING_VALUE_ENCRYPTION = L"encryption";
95 static const DPL::String SETTING_VALUE_ENCRYPTION_ENABLE = L"enable";
96 const DPL::String SETTING_VALUE_INSTALLTOEXT_NAME =
97     L"install-location-type";
98 const DPL::String SETTING_VALUE_INSTALLTOEXT_PREPER_EXT =
99     L"prefer-external";
100
101 const std::string XML_EXTENSION = ".xml";
102
103 bool hasExtension(const std::string& filename, const std::string& extension)
104 {
105     LogDebug("Looking for extension " << extension << " in: " << filename);
106     size_t fileLen = filename.length();
107     size_t extLen = extension.length();
108     if (fileLen < extLen) {
109         LogError("Filename " << filename << " is shorter than extension "
110                              << extension);
111         return false;
112     }
113     return (0 == filename.compare(fileLen - extLen, extLen, extension));
114 }
115 } // namespace anonymous
116
117 namespace Jobs {
118 namespace WidgetInstall {
119 class InstallerTaskFail :
120     public DPL::TaskDecl<InstallerTaskFail>
121 {
122   private:
123     ConfigureResult m_result;
124
125     void StepFail()
126     {
127         if (m_result == ConfigureResult::Deferred) {
128             ThrowMsg(Jobs::WidgetInstall::Exceptions::Deferred,
129                     "widget installation or update deferred!");
130         } else if (m_result == ConfigureResult::Failed_InvalidConfig) {
131             ThrowMsg(Jobs::WidgetInstall::Exceptions::WidgetConfigFileInvalid,
132                     "invalid config");
133         } else if (m_result == ConfigureResult::Failed_LowerVersion) {
134             ThrowMsg(Jobs::WidgetInstall::Exceptions::PackageLowerVersion,
135                     "package version is lower than installed version");
136         } else if (m_result == ConfigureResult::Failed_AlreadyInstalled) {
137             ThrowMsg(Jobs::WidgetInstall::Exceptions::PackageAlreadyInstalled,
138                     "package is already installed");
139         } else if (m_result == ConfigureResult::Failed_WidgetRunning) {
140             ThrowMsg(Jobs::WidgetInstall::Exceptions::WidgetRunningError,
141                     "widget is running");
142         } else if (m_result == ConfigureResult::Failed_DrmError) {
143             ThrowMsg(Jobs::WidgetInstall::Exceptions::DRMFailed,
144                     "drm failed");
145         } else {
146             ThrowMsg(Jobs::WidgetInstall::Exceptions::NotAllowed,
147                     "widget installation or update not allowed!");
148         }
149     }
150
151   public:
152     InstallerTaskFail(ConfigureResult result) :
153         DPL::TaskDecl<InstallerTaskFail>(this),
154         m_result(result)
155     {
156         AddStep(&InstallerTaskFail::StepFail);
157     }
158 };
159
160 JobWidgetInstall::JobWidgetInstall(
161     std::string const &widgetPath,
162     const WidgetInstallationStruct &
163     installerStruct) :
164     Job(Installation),
165     JobContextBase<WidgetInstallationStruct>(installerStruct),
166     m_exceptionCaught(Jobs::Exceptions::Success)
167 {
168     m_installerContext.m_quiet = m_jobStruct.m_quiet;
169
170     ConfigureResult result = PrePareInstallation(widgetPath);
171
172     if (result == ConfigureResult::Ok) {
173         LogInfo("Configure installation succeeded");
174         m_installerContext.job->SetProgressFlag(true);
175
176         AddTask(new TaskRecovery(m_installerContext));
177
178         // Create installation tasks
179         if (m_installerContext.widgetConfig.packagingType !=
180             WrtDB::PKG_TYPE_DIRECTORY_WEB_APP &&
181             m_installerContext.widgetConfig.packagingType !=
182             WrtDB::PKG_TYPE_HOSTED_WEB_APP &&
183             !m_isDRM)
184         {
185             AddTask(new TaskUnzip(m_installerContext));
186         }
187
188         AddTask(new TaskWidgetConfig(m_installerContext));
189         if (m_installerContext.widgetConfig.packagingType ==
190             WrtDB::PKG_TYPE_HOSTED_WEB_APP)
191         {
192             AddTask(new TaskPrepareFiles(m_installerContext));
193         }
194         AddTask(new TaskCertify(m_installerContext));
195         if (m_needEncryption) {
196             AddTask(new TaskEncryptResource(m_installerContext));
197         }
198
199         AddTask(new TaskFileManipulation(m_installerContext));
200         // TODO: Update progress information for this task
201
202         //This is sort of quick solution, because ACE verdicts are based upon
203         //data from DAO (DB). So AceCheck for now has to be AFTER DbUpdate
204         //task.
205         AddTask(new TaskSmack(m_installerContext));
206
207         AddTask(new TaskManifestFile(m_installerContext));
208         if (m_installerContext.widgetConfig.packagingType ==
209             PKG_TYPE_HYBRID_WEB_APP)
210         {
211             AddTask(new TaskInstallOspsvc(m_installerContext));
212         }
213         AddTask(new TaskCertificates(m_installerContext));
214         AddTask(new TaskPluginsCopy(m_installerContext));
215         AddTask(new TaskDatabase(m_installerContext));
216         AddTask(new TaskAceCheck(m_installerContext));
217     } else if (result == ConfigureResult::Updated) {
218         LogInfo("Configure installation updated");
219         LogInfo("Widget Update");
220         m_installerContext.job->SetProgressFlag(true);
221         if (m_installerContext.widgetConfig.packagingType !=
222             WrtDB::PKG_TYPE_HOSTED_WEB_APP &&
223             m_installerContext.widgetConfig.packagingType !=
224             WrtDB::PKG_TYPE_DIRECTORY_WEB_APP &&
225             !m_isDRM)
226         {
227             AddTask(new TaskUnzip(m_installerContext));
228         }
229
230         AddTask(new TaskWidgetConfig(m_installerContext));
231
232         if (m_installerContext.widgetConfig.packagingType ==
233             WrtDB::PKG_TYPE_HOSTED_WEB_APP)
234         {
235             AddTask(new TaskPrepareFiles(m_installerContext));
236         }
237
238         AddTask(new TaskCertify(m_installerContext));
239         if (m_needEncryption) {
240             AddTask(new TaskEncryptResource(m_installerContext));
241         }
242
243         if (m_installerContext.widgetConfig.packagingType !=
244             WrtDB::PKG_TYPE_DIRECTORY_WEB_APP)
245         {
246             AddTask(new TaskUpdateFiles(m_installerContext));
247         }
248
249         /* TODO : To backup file, save md5 values */
250         AddTask(new TaskSmack(m_installerContext));
251
252         AddTask(new TaskManifestFile(m_installerContext));
253         if (m_installerContext.widgetConfig.packagingType ==
254             PKG_TYPE_HYBRID_WEB_APP)
255         {
256             AddTask(new TaskInstallOspsvc(m_installerContext));
257         }
258         if (m_installerContext.widgetConfig.packagingType !=
259             WrtDB::PKG_TYPE_DIRECTORY_WEB_APP)
260         {
261             AddTask(new TaskRemoveBackupFiles(m_installerContext));
262         }
263         AddTask(new TaskPluginsCopy(m_installerContext));
264         AddTask(new TaskDatabase(m_installerContext));
265         AddTask(new TaskAceCheck(m_installerContext));
266         //TODO: remove widgetHandle from this task and move before database task
267         // by now widget handle is needed in ace check
268         // Any error in acecheck while update will break widget
269     } else if (result == ConfigureResult::Deferred) {
270         // Installation is deferred
271         LogInfo("Configure installation deferred");
272
273         AddTask(new InstallerTaskFail(result));
274     } else if (result >= ConfigureResult::Failed &&
275             result <= ConfigureResult::Failed_DrmError) {
276         // Installation is not allowed to proceed due to widget update policy
277         LogWarning("Configure installation failed!");
278
279         AddTask(new InstallerTaskFail(result));
280     } else {
281         Assert(false && "Invalid configure result!");
282     }
283 }
284
285 ConfigureResult JobWidgetInstall::PrePareInstallation(
286     const std::string &widgetPath)
287 {
288     ConfigureResult result;
289     m_needEncryption = false;
290
291     Try
292     {
293         std::string tempDir =
294             Jobs::WidgetInstall::createTempPath(m_jobStruct.m_installMode == InstallMode::INSTALL_MODE_PRELOAD);
295
296         m_isDRM = isDRMWidget(widgetPath);
297         if (true == m_isDRM) {
298             LogDebug("decrypt DRM widget");
299             if (DecryptDRMWidget(widgetPath, tempDir)) {
300                 LogDebug("Failed decrypt DRM widget");
301                 return ConfigureResult::Failed_DrmError;
302             }
303         }
304
305         LogDebug("widgetPath:" << widgetPath);
306
307         m_installerContext.widgetConfig.packagingType =
308             checkPackageType(widgetPath, tempDir);
309         ConfigParserData configData = getWidgetDataFromXML(
310                 widgetPath,
311                 tempDir,
312                 m_installerContext.widgetConfig.packagingType,
313                 m_isDRM);
314         LogDebug("widget packaging type : " <<
315                  m_installerContext.widgetConfig.packagingType.pkgType);
316
317         setTizenId(configData);
318         setApplicationType(configData);
319         m_needEncryption = detectResourceEncryption(configData);
320         setInstallLocationType(configData);
321
322         // Configure installation
323         result = ConfigureInstallation(widgetPath, configData, tempDir);
324     }
325     Catch(Exceptions::ExtractFileFailed)
326     {
327         LogError("Failed to create temporary path for widget");
328         result = ConfigureResult::Failed_InvalidConfig;
329     }
330
331     return result;
332 }
333
334 void JobWidgetInstall::setTizenId(
335     const WrtDB::ConfigParserData &configInfo)
336 {
337     bool shouldMakeAppid = false;
338     using namespace PackageManager;
339     if (!!configInfo.tizenAppId) {
340         LogDebug("Setting tizenAppId provided in config.xml: " <<
341                  configInfo.tizenAppId);
342
343         m_installerContext.widgetConfig.tzAppid = *configInfo.tizenAppId;
344         //check package id.
345         if (!!configInfo.tizenPkgId) {
346             LogDebug("Setting tizenPkgId provided in config.xml: " <<
347                      configInfo.tizenPkgId);
348
349             m_installerContext.widgetConfig.tzPkgid = *configInfo.tizenPkgId;
350         } else {
351             DPL::String appid = *configInfo.tizenAppId;
352             if (appid.length() > PACKAGE_ID_LENGTH) {
353                 m_installerContext.widgetConfig.tzPkgid =
354                     appid.substr(0, PACKAGE_ID_LENGTH);
355             } else {
356                 //old version appid only has 10byte random character is able to install for a while.
357                 //this case appid equal pkgid.
358                 m_installerContext.widgetConfig.tzPkgid =
359                     *configInfo.tizenAppId;
360                 shouldMakeAppid = true;
361             }
362         }
363     } else {
364         shouldMakeAppid = true;
365         TizenPkgId pkgId = WidgetDAOReadOnly::generatePkgId();
366         LogDebug("Checking if pkg id is unique");
367         while (true) {
368             if (!validateTizenPackageID(pkgId)) {
369                 //path exist, chose another one
370                 pkgId = WidgetDAOReadOnly::generatePkgId();
371                 continue;
372             }
373             break;
374         }
375         m_installerContext.widgetConfig.tzPkgid = pkgId;
376         LogInfo("tizen_id name was generated by WRT: " <<
377                 m_installerContext.widgetConfig.tzPkgid);
378     }
379
380     if (shouldMakeAppid == true) {
381         DPL::OptionalString name;
382         DPL::OptionalString defaultLocale = configInfo.defaultlocale;
383
384         FOREACH(localizedData, configInfo.localizedDataSet)
385         {
386             Locale i = localizedData->first;
387             if (!!defaultLocale) {
388                 if (defaultLocale == i) {
389                     name = localizedData->second.name;
390                     break;
391                 }
392             } else {
393                 name = localizedData->second.name;
394                 break;
395             }
396         }
397         regex_t regx;
398         if (regcomp(&regx, REG_NAME_PATTERN, REG_NOSUB | REG_EXTENDED) != 0) {
399             LogDebug("Regcomp failed");
400         }
401
402         LogDebug("Name : " << name);
403         if (!name || (regexec(&regx, DPL::ToUTF8String(*name).c_str(),
404                               static_cast<size_t>(0), NULL, 0) != REG_NOERROR))
405         {
406             // TODO : generate name move to wrt-commons
407             std::string allowedString("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
408             std::ostringstream genName;
409             struct timeval tv;
410             gettimeofday(&tv, NULL);
411             unsigned int seed = time(NULL) + tv.tv_usec;
412
413             genName << "_" << allowedString[rand_r(&seed) % allowedString.length()];
414             name = DPL::FromUTF8String(genName.str());
415             LogDebug("name was generated by WRT");
416         }
417         regfree(&regx);
418         LogDebug("Name : " << name);
419         std::ostringstream genid;
420         genid << m_installerContext.widgetConfig.tzPkgid << "." << name;
421         LogDebug("tizen appid was generated by WRT : " << genid.str());
422
423         DPL::OptionalString appid = DPL::FromUTF8String(genid.str());
424         NormalizeAndTrimSpaceString(appid);
425         m_installerContext.widgetConfig.tzAppid = *appid;
426     }
427
428     // send start signal of pkgmgr
429     getInstallerStruct().pkgmgrInterface->setPkgname(DPL::ToUTF8String(
430                                                          m_installerContext.
431                                                              widgetConfig.
432                                                              tzPkgid));
433     LogInfo("Tizen App Id : " << m_installerContext.widgetConfig.tzAppid);
434     LogInfo("Tizen Pkg Id : " << m_installerContext.widgetConfig.tzPkgid);
435     LogInfo("W3C Widget GUID : " << m_installerContext.widgetConfig.guid);
436 }
437
438 void JobWidgetInstall::configureWidgetLocation(const std::string & widgetPath,
439                                                const std::string& tempPath)
440 {
441     m_installerContext.locations =
442         WidgetLocation(DPL::ToUTF8String(m_installerContext.widgetConfig.
443                                              tzPkgid),
444                        widgetPath, tempPath,
445                        m_installerContext.widgetConfig.packagingType,
446                        m_installerContext.locationType);
447     m_installerContext.locations->registerAppid(
448         DPL::ToUTF8String(m_installerContext.widgetConfig.tzAppid));
449
450     LogInfo("widgetSource " << widgetPath);
451 }
452
453 ConfigureResult JobWidgetInstall::ConfigureInstallation(
454     const std::string &widgetSource,
455     const WrtDB::ConfigParserData &configData,
456     const std::string &tempPath)
457 {
458     ConfigureResult result = ConfigureResult::Failed;
459     WidgetUpdateInfo update;
460
461     // checking installed web application
462     Try {
463         // checking existing application is installed
464         WidgetDAOReadOnly dao(m_installerContext.widgetConfig.tzAppid);
465         // no excpetion means, it isn't update mode
466         getInstallerStruct().pkgmgrInterface->sendSignal(
467                 PKGMGR_START_KEY,
468                 PKGMGR_START_UPDATE);
469
470         update = detectWidgetUpdate(configData,
471                                     m_installerContext.widgetConfig.tzAppid);
472         result = checkWidgetUpdate(update);
473         if (result != ConfigureResult::Updated) {
474             // Already installed TizenAppId. return failed
475             return ConfigureResult::Failed_AlreadyInstalled;
476         }
477         m_installerContext.isUpdateMode = true;
478     }
479     Catch(WidgetDAOReadOnly::Exception::WidgetNotExist) {
480         result = ConfigureResult::Ok;
481         getInstallerStruct().pkgmgrInterface->sendSignal(
482                 PKGMGR_START_KEY,
483                 PKGMGR_START_INSTALL);
484         m_installerContext.isUpdateMode = false;
485
486         if (!validateTizenApplicationID(
487             m_installerContext.widgetConfig.tzAppid))
488         {
489             LogError("tizen application ID is already used");
490             return ConfigureResult::Failed_InvalidConfig;
491         }
492         if (!validateTizenPackageID(m_installerContext.widgetConfig.tzPkgid)) {
493             LogError("tizen package ID is already used");
494             return ConfigureResult::Failed_AlreadyInstalled;
495         }
496     }
497
498     configureWidgetLocation(widgetSource, tempPath);
499
500     // Init installer context
501     m_installerContext.installStep = InstallerContext::INSTALL_START;
502     m_installerContext.job = this;
503     m_installerContext.widgetConfig.shareHref = std::string();
504
505     return result;
506 }
507
508 bool JobWidgetInstall::validateTizenApplicationID(
509     const WrtDB::TizenAppId &tizenAppId)
510 {
511     LogInfo("tizen application ID = [" << tizenAppId << "]");
512
513     regex_t reg;
514     if (regcomp(&reg, REG_TIZENID_PATTERN, REG_NOSUB | REG_EXTENDED) != 0) {
515         LogDebug("Regcomp failed");
516     }
517
518     if (regexec(&reg, DPL::ToUTF8String(tizenAppId).c_str(), 0, NULL, 0)
519         == REG_NOMATCH)
520     {
521         regfree(&reg);
522         return false;
523     }
524     regfree(&reg);
525     return true;
526 }
527
528 bool JobWidgetInstall::validateTizenPackageID(
529     const WrtDB::TizenPkgId &tizenPkgId)
530 {
531     std::string pkgId = DPL::ToUTF8String(tizenPkgId);
532
533     std::string installPath =
534         std::string(GlobalConfig::GetUserInstalledWidgetPath()) +
535         "/" + pkgId;
536     std::string preinstallPath =
537         std::string(GlobalConfig::GetUserPreloadedWidgetPath()) +
538         "/" + pkgId;
539
540     struct stat dirStat;
541     if ((stat(installPath.c_str(), &dirStat) == 0) ||
542         (stat(preinstallPath.c_str(), &dirStat) == 0))
543     {
544         return false;
545     }
546     return true;
547 }
548
549 ConfigureResult JobWidgetInstall::checkWidgetUpdate(
550     const WidgetUpdateInfo &update)
551 {
552     LogInfo("incoming version = '" << update.incomingVersion);
553     LogInfo("Tizen AppID = " << update.tzAppId);
554
555     // Check running state
556     bool isRunning = false;
557     int retval =
558         app_manager_is_running(DPL::ToUTF8String(update.tzAppId).c_str(),
559                                &isRunning);
560     if (APP_MANAGER_ERROR_NONE != retval || isRunning) {
561         LogError("Fail to get running state");
562         return ConfigureResult::Failed_WidgetRunning;
563     }
564
565     m_installerContext.widgetConfig.tzAppid = update.tzAppId;
566
567     if (isUpperVersion(update.existingVersion, update.incomingVersion) ||
568         m_jobStruct.m_installMode == InstallMode::INSTALL_MODE_DIRECTORY)
569     {
570         LogInfo("Whether widget policy allow proceed ok");
571         return ConfigureResult::Updated;
572     } else {
573         return ConfigureResult::Failed_LowerVersion;
574     }
575
576     return ConfigureResult::Failed;
577 }
578
579 bool JobWidgetInstall::isUpperVersion(
580     const OptionalWidgetVersion &existingVersion,
581     const OptionalWidgetVersion &incomingVersion)
582 {
583     LogInfo("Existing version = '" << *existingVersion);
584     LogInfo("Incoming version = '" << *incomingVersion);
585
586     if (!existingVersion && !incomingVersion) {
587         return false;
588     } else if (!existingVersion && !!incomingVersion) {
589         return false;
590     } else if (!!existingVersion && !incomingVersion) {
591         return true;
592     } else {
593         if (!existingVersion->IsWac() || !incomingVersion->IsWac()) {
594             return false;
595         } else {
596             if (*incomingVersion == *existingVersion) {
597                 return false;
598             } else if (*incomingVersion > *existingVersion) {
599                 return true;
600             } else {
601                 return false;
602             }
603         }
604     }
605 }
606
607 ConfigParserData JobWidgetInstall::getWidgetDataFromXML(
608     const std::string &widgetSource,
609     const std::string &tempPath,
610     WrtDB::PackagingType pkgType,
611     bool isDRM)
612 {
613     // Parse config
614     ParserRunner parser;
615     ConfigParserData configInfo;
616
617     Try
618     {
619         if (pkgType == PKG_TYPE_HOSTED_WEB_APP) {
620             parser.Parse(widgetSource,
621                          ElementParserPtr(
622                              new RootParser<WidgetParser>(configInfo,
623                                                           DPL::FromUTF32String(
624                                                               L"widget"))));
625         } else if (pkgType == PKG_TYPE_DIRECTORY_WEB_APP) {
626             parser.Parse(widgetSource + '/' + WITH_OSP_XML,
627                          ElementParserPtr(
628                              new RootParser<WidgetParser>(
629                                  configInfo,
630                                  DPL::FromUTF32String(L"widget"))));
631         } else {
632             if (!isDRM) {
633                 std::unique_ptr<DPL::ZipInput> zipFile(
634                     new DPL::ZipInput(widgetSource));
635
636                 std::unique_ptr<DPL::ZipInput::File> configFile;
637
638                 // Open config.xml file
639                 if (pkgType == PKG_TYPE_HYBRID_WEB_APP) {
640                     configFile.reset(zipFile->OpenFile(WITH_OSP_XML));
641                 } else {
642                     configFile.reset(zipFile->OpenFile(CONFIG_XML));
643                 }
644
645                 // Extract config
646                 DPL::BinaryQueue buffer;
647                 DPL::AbstractWaitableInputAdapter inputAdapter(configFile.get());
648                 DPL::AbstractWaitableOutputAdapter outputAdapter(&buffer);
649                 DPL::Copy(&inputAdapter, &outputAdapter);
650                 parser.Parse(&buffer,
651                              ElementParserPtr(
652                                  new RootParser<WidgetParser>(configInfo,
653                                                               DPL::
654                                                                   FromUTF32String(
655                                                                   L"widget"))));
656             } else {
657                 // DRM widget
658                 std::string configFile;
659                 if (pkgType == PKG_TYPE_HYBRID_WEB_APP) {
660                     configFile = tempPath + "/" + WITH_OSP_XML;
661                 } else {
662                     configFile = tempPath + "/" + CONFIG_XML;
663                 }
664
665                 parser.Parse(configFile,
666                              ElementParserPtr(
667                                  new RootParser<WidgetParser>(configInfo,
668                                                               DPL::
669                                                                   FromUTF32String(
670                                                                   L"widget"))));
671             }
672         }
673     }
674     Catch(DPL::ZipInput::Exception::OpenFailed)
675     {
676         LogError("Failed to open widget package");
677         return ConfigParserData();
678     }
679     Catch(DPL::ZipInput::Exception::OpenFileFailed)
680     {
681         LogError("Failed to open config.xml file");
682         return ConfigParserData();
683     }
684     Catch(DPL::CopyFailed)
685     {
686         LogError("Failed to extract config.xml file");
687         return ConfigParserData();
688     }
689     Catch(DPL::FileInput::Exception::OpenFailed)
690     {
691         LogError("Failed to open config.xml file");
692         return ConfigParserData();
693     }
694     Catch(ElementParser::Exception::ParseError)
695     {
696         LogError("Failed to parse config.xml file");
697         return ConfigParserData();
698     }
699     Catch(DPL::ZipInput::Exception::SeekFileFailed)
700     {
701         LogError("Failed to seek widget archive - corrupted package?");
702         return ConfigParserData();
703     }
704     return configInfo;
705 }
706
707 WidgetUpdateInfo JobWidgetInstall::detectWidgetUpdate(
708     const ConfigParserData &configInfo,
709     const WrtDB::TizenAppId &tizenId)
710 {
711     LogInfo("Checking up widget package for config.xml...");
712     OptionalWidgetVersion incomingVersion;
713
714     if (!configInfo.version.IsNull()) {
715         incomingVersion =
716             DPL::Optional<WidgetVersion>(
717                 WidgetVersion(*configInfo.version));
718     }
719
720     WidgetDAOReadOnly dao(tizenId);
721     return WidgetUpdateInfo(
722         dao.getTzAppId(),
723         WidgetVersion(*dao.getVersion()),
724         incomingVersion);
725 }
726
727 void JobWidgetInstall::SendProgress()
728 {
729     using namespace PackageManager;
730     if (GetProgressFlag() != false) {
731         if (getInstallerStruct().progressCallback != NULL) {
732             // send progress signal of pkgmgr
733             std::ostringstream percent;
734             percent << static_cast<int>(GetProgressPercent());
735             getInstallerStruct().pkgmgrInterface->sendSignal(
736                 PKGMGR_PROGRESS_KEY,
737                 percent.str());
738
739             LogDebug("Call widget install progressCallbak");
740             getInstallerStruct().progressCallback(
741                 getInstallerStruct().userParam,
742                 GetProgressPercent(),
743                 GetProgressDescription());
744         }
745     }
746 }
747
748 void JobWidgetInstall::SendProgressIconPath(const std::string &path)
749 {
750     using namespace PackageManager;
751     if (GetProgressFlag() != false) {
752         if (getInstallerStruct().progressCallback != NULL) {
753             // send progress signal of pkgmgr
754             getInstallerStruct().pkgmgrInterface->sendSignal(
755                 PKGMGR_ICON_PATH,
756                 path);
757         }
758     }
759 }
760
761 void JobWidgetInstall::SendFinishedSuccess()
762 {
763     using namespace PackageManager;
764     // TODO : sync should move to separate task.
765     sync();
766
767     if (INSTALL_LOCATION_TYPE_EXTERNAL == m_installerContext.locationType) {
768         if (m_installerContext.isUpdateMode) {
769             WidgetInstallToExtSingleton::Instance().postUpgrade(true);
770         } else {
771             WidgetInstallToExtSingleton::Instance().postInstallation(true);
772         }
773         WidgetInstallToExtSingleton::Instance().deinitialize();
774     }
775
776     // remove widget install information file
777     unlink(m_installerContext.installInfo.c_str());
778
779     //inform widget info
780     JobWidgetInstall::displayWidgetInfo();
781
782     TizenAppId& tizenId = m_installerContext.widgetConfig.tzAppid;
783
784     // send signal of pkgmgr
785     getInstallerStruct().pkgmgrInterface->sendSignal(
786         PKGMGR_END_KEY,
787         PKGMGR_END_SUCCESS);
788
789     LogDebug("Call widget install successfinishedCallback");
790     getInstallerStruct().finishedCallback(getInstallerStruct().userParam,
791                                           DPL::ToUTF8String(
792                                               tizenId), Jobs::Exceptions::Success);
793 }
794
795 void JobWidgetInstall::SendFinishedFailure()
796 {
797     using namespace PackageManager;
798     // remove widget install information file
799     unlink(m_installerContext.installInfo.c_str());
800
801     LogError("Error number: " << m_exceptionCaught);
802     LogError("Message: " << m_exceptionMessage);
803     TizenAppId & tizenId = m_installerContext.widgetConfig.tzAppid;
804
805     LogDebug("Call widget install failure finishedCallback");
806     std::stringstream errorNum;
807     errorNum << m_exceptionCaught;
808
809     // send signal of pkgmgr
810     getInstallerStruct().pkgmgrInterface->sendSignal(
811         PKGMGR_ERROR,
812         errorNum.str());
813
814     getInstallerStruct().pkgmgrInterface->sendSignal(
815         PKGMGR_END_KEY,
816         PKGMGR_END_FAILURE);
817
818     getInstallerStruct().finishedCallback(getInstallerStruct().userParam,
819                                           DPL::ToUTF8String(
820                                               tizenId), m_exceptionCaught);
821 }
822
823 void JobWidgetInstall::SaveExceptionData(const Jobs::JobExceptionBase &e)
824 {
825     m_exceptionCaught = static_cast<Jobs::Exceptions::Type>(e.getParam());
826     m_exceptionMessage = e.GetMessage();
827 }
828
829 void JobWidgetInstall::displayWidgetInfo()
830 {
831     WidgetDAOReadOnly dao(m_installerContext.widgetConfig.tzAppid);
832
833     std::ostringstream out;
834     WidgetLocalizedInfo localizedInfo =
835         W3CFileLocalization::getLocalizedInfo(dao.getTzAppId());
836
837     out << std::endl <<
838     "===================================== INSTALLED WIDGET INFO =========" \
839     "============================";
840     out << std::endl << "Name:                        " << localizedInfo.name;
841     out << std::endl << "AppId:                     " << dao.getTzAppId();
842     WidgetSize size = dao.getPreferredSize();
843     out << std::endl << "Width:                       " << size.width;
844     out << std::endl << "Height:                      " << size.height;
845     out << std::endl << "Start File:                  " <<
846     W3CFileLocalization::getStartFile(dao.getTzAppId());
847     out << std::endl << "Version:                     " << dao.getVersion();
848     out << std::endl << "Licence:                     " <<
849     localizedInfo.license;
850     out << std::endl << "Licence Href:                " <<
851     localizedInfo.licenseHref;
852     out << std::endl << "Description:                 " <<
853     localizedInfo.description;
854     out << std::endl << "Widget Id:                   " << dao.getGUID();
855     out << std::endl << "Widget recognized:           " << dao.isRecognized();
856     out << std::endl << "Widget distributor signed:   " <<
857     dao.isDistributorSigned();
858     out << std::endl << "Widget trusted:              " << dao.isTrusted();
859
860     OptionalWidgetIcon icon = W3CFileLocalization::getIcon(dao.getTzAppId());
861     DPL::OptionalString iconSrc =
862         !!icon ? icon->src : DPL::OptionalString::Null;
863     out << std::endl << "Icon:                        " << iconSrc;
864
865     out << std::endl << "Preferences:";
866     {
867         PropertyDAOReadOnly::WidgetPreferenceList list = dao.getPropertyList();
868         FOREACH(it, list)
869         {
870             out << std::endl << "  Key:                       " <<
871             it->key_name;
872             out << std::endl << "      Readonly:              " <<
873             it->readonly;
874         }
875     }
876
877     out << std::endl << "Features:";
878     {
879         WidgetFeatureSet list = dao.getFeaturesList();
880         FOREACH(it, list)
881         {
882             out << std::endl << "  Name:                      " << it->name;
883         }
884     }
885
886     out << std::endl;
887
888     LogInfo(out.str());
889 }
890
891 WrtDB::PackagingType JobWidgetInstall::checkPackageType(
892     const std::string &widgetSource,
893     const std::string &tempPath)
894 {
895     // Check installation type (direcotory/ or config.xml or widget.wgt)
896     if (m_jobStruct.m_installMode == InstallMode::INSTALL_MODE_DIRECTORY)
897     {
898         LogDebug("Install directly from directory");
899         return PKG_TYPE_DIRECTORY_WEB_APP;
900     }
901     if (hasExtension(widgetSource, XML_EXTENSION)) {
902         LogInfo("Hosted app installation");
903         return PKG_TYPE_HOSTED_WEB_APP;
904     }
905
906     if (m_isDRM) {
907         std::string configFile = tempPath + "/" + CONFIG_XML;
908         if (WrtUtilFileExists(configFile)) {
909             return PKG_TYPE_NOMAL_WEB_APP;
910         }
911
912         configFile = tempPath + "/" + WITH_OSP_XML;
913         if (WrtUtilFileExists(configFile)) {
914             return PKG_TYPE_HYBRID_WEB_APP;
915         }
916     } else {
917         std::unique_ptr<DPL::ZipInput> zipFile;
918
919         Try
920         {
921             // Open zip file
922             zipFile.reset(new DPL::ZipInput(widgetSource));
923         }
924         Catch(DPL::ZipInput::Exception::OpenFailed)
925         {
926             LogDebug("Failed to open widget package");
927             return PKG_TYPE_UNKNOWN;
928         }
929         Catch(DPL::ZipInput::Exception::SeekFileFailed)
930         {
931             LogError("Failed to seek widget package file");
932             return PKG_TYPE_UNKNOWN;
933         }
934
935         Try
936         {
937             // Open config.xml file in package root
938             std::unique_ptr<DPL::ZipInput::File> configFile(
939                 zipFile->OpenFile(CONFIG_XML));
940             return PKG_TYPE_NOMAL_WEB_APP;
941         }
942         Catch(DPL::ZipInput::Exception::OpenFileFailed)
943         {
944             LogDebug("Could not find config.xml");
945         }
946
947         Try
948         {
949             // Open config.xml file in package root
950             std::unique_ptr<DPL::ZipInput::File> configFile(
951                 zipFile->OpenFile(WITH_OSP_XML));
952
953             return PKG_TYPE_HYBRID_WEB_APP;
954         }
955         Catch(DPL::ZipInput::Exception::OpenFileFailed)
956         {
957             LogDebug("Could not find wgt/config.xml");
958             return PKG_TYPE_UNKNOWN;
959         }
960     }
961
962     return PKG_TYPE_UNKNOWN;
963 }
964
965 void JobWidgetInstall::setApplicationType(
966     const WrtDB::ConfigParserData &configInfo)
967 {
968     FOREACH(iterator, configInfo.nameSpaces) {
969         LogInfo("namespace = [" << *iterator << "]");
970         AppType currentAppType = APP_TYPE_UNKNOWN;
971
972         if (*iterator == ConfigurationNamespace::W3CWidgetNamespaceName) {
973             continue;
974         } else if (
975             *iterator ==
976             ConfigurationNamespace::WacWidgetNamespaceNameForLinkElement ||
977             *iterator ==
978             ConfigurationNamespace::WacWidgetNamespaceName)
979         {
980             currentAppType = APP_TYPE_WAC20;
981         } else if (*iterator ==
982                    ConfigurationNamespace::TizenWebAppNamespaceName)
983         {
984             currentAppType = APP_TYPE_TIZENWEBAPP;
985         }
986
987         if (m_installerContext.widgetConfig.webAppType ==
988             APP_TYPE_UNKNOWN)
989         {
990             m_installerContext.widgetConfig.webAppType = currentAppType;
991         } else if (m_installerContext.widgetConfig.webAppType ==
992                    currentAppType)
993         {
994             continue;
995         } else {
996             ThrowMsg(Exceptions::WidgetConfigFileInvalid,
997                      "Config.xml has more than one namespace");
998         }
999     }
1000
1001     // If there is no define, type set to WAC 2.0
1002     if (m_installerContext.widgetConfig.webAppType == APP_TYPE_UNKNOWN) {
1003         m_installerContext.widgetConfig.webAppType = APP_TYPE_WAC20;
1004     }
1005
1006     LogInfo("type = [" <<
1007             m_installerContext.widgetConfig.webAppType.getApptypeToString() <<
1008             "]");
1009 }
1010
1011 bool JobWidgetInstall::detectResourceEncryption(
1012     const WrtDB::ConfigParserData &configData)
1013 {
1014     FOREACH(it, configData.settingsList)
1015     {
1016         if (it->m_name == SETTING_VALUE_ENCRYPTION &&
1017             it->m_value == SETTING_VALUE_ENCRYPTION_ENABLE)
1018         {
1019             LogDebug("resource need encryption");
1020             return true;
1021         }
1022     }
1023     return false;
1024 }
1025
1026 void JobWidgetInstall::setInstallLocationType(
1027     const
1028     WrtDB::ConfigParserData &
1029     configData)
1030 {
1031     m_installerContext.locationType = INSTALL_LOCATION_TYPE_NOMAL;
1032
1033     if (m_jobStruct.m_installMode == InstallMode::INSTALL_MODE_PRELOAD) {
1034         m_installerContext.locationType =
1035             INSTALL_LOCATION_TYPE_PRELOAD;
1036     } else {
1037         FOREACH(it, configData.settingsList)
1038         {
1039             if (it->m_name == SETTING_VALUE_INSTALLTOEXT_NAME &&
1040                 it->m_value ==
1041                 SETTING_VALUE_INSTALLTOEXT_PREPER_EXT)
1042             {
1043                 LogDebug("This widget will be installed to sd card");
1044                 m_installerContext.locationType =
1045                     INSTALL_LOCATION_TYPE_EXTERNAL;
1046             }
1047         }
1048     }
1049 }
1050
1051 bool JobWidgetInstall::isDRMWidget(std::string widgetPath)
1052 {
1053     /* TODO :
1054      * drm_bool_type_e is_drm_file = DRM_UNKNOWN;
1055      * int ret = -1;
1056      *
1057      * ret = drm_is_drm_file(widgetPath.c_str(), &is_drm_file);
1058      * if(DRM_RETURN_SUCCESS == ret && DRM_TRUE == is_drm_file) {
1059      */
1060
1061     /* blow code temporary code for drm. */
1062     int ret = drm_oem_intel_isDrmFile(const_cast<char*>(widgetPath.c_str()));
1063     if (1 == ret) {
1064         return true;
1065     } else {
1066         return false;
1067     }
1068 }
1069
1070 bool JobWidgetInstall::DecryptDRMWidget(std::string widgetPath,
1071                                         std::string destPath)
1072 {
1073     /* TODO :
1074      * drm_trusted_sapps_decrypt_package_info_s package_info;
1075      *
1076      * strncpy(package_info.sadcf_filepath, widgetPath.c_str(),
1077      *      sizeof(package_info.sadcf_filepath));
1078      * strncpy(package_info.decrypt_filepath, destPath.c_str(),
1079      *      sizeof(package_info.decrypt_filepath));
1080      *
1081      * drm_trusted_request_type_e requestType =
1082      *  DRM_TRUSTED_REQ_TYPE_SAPPS_DECRYPT_PACKAGE;
1083      *
1084      * int ret = drm_trusted_handle_request(requestType,
1085      *                                   (void *)&package_info, NULL);
1086      * if (DRM_TRUSTED_RETURN_SUCCESS == ret) {
1087      *  return true;
1088      * } else {
1089      *  return false;
1090      * }
1091      */
1092     if (drm_oem_intel_decrypt_package(const_cast<char*>(widgetPath.c_str()),
1093                                       const_cast<char*>(destPath.c_str())) != 0)
1094     {
1095         return true;
1096     } else {
1097         return false;
1098     }
1099 }
1100 } //namespace WidgetInstall
1101 } //namespace Jobs