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