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