546d263f3afd2e568a6afff7de782471b5d22443
[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_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
78 using namespace WrtDB;
79 using namespace Jobs::Exceptions;
80
81 namespace // anonymous
82 {
83 const char * const CONFIG_XML = "config.xml";
84 const char * const WITH_OSP_XML = "res/wgt/config.xml";
85
86 //allowed: a-z, A-Z, 0-9
87 const char* REG_TIZENID_PATTERN = "^[a-zA-Z0-9]{10}.{1,}$";
88 const char* REG_NAME_PATTERN = "^[a-zA-Z0-9._-]{1,}$";
89 const size_t PACKAGE_ID_LENGTH = 10;
90
91 static const DPL::String SETTING_VALUE_ENCRYPTION = L"encryption";
92 static const DPL::String SETTING_VALUE_ENCRYPTION_ENABLE = L"enable";
93 static const DPL::String SETTING_VALUE_ENCRYPTION_DISABLE = L"disable";
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 if (m_result == ConfigureResult::Failed_NotSupportRDSUpdate) {
144             ThrowMsg(Jobs::WidgetInstall::Exceptions::NotSupportRDSUpdate,
145                     "RDS update failed");
146         } else {
147             ThrowMsg(Jobs::WidgetInstall::Exceptions::NotAllowed,
148                     "widget installation or update not allowed!");
149         }
150     }
151
152   public:
153     InstallerTaskFail(ConfigureResult result) :
154         DPL::TaskDecl<InstallerTaskFail>(this),
155         m_result(result)
156     {
157         AddStep(&InstallerTaskFail::StepFail);
158     }
159 };
160
161 JobWidgetInstall::JobWidgetInstall(
162     std::string const &widgetPath,
163     const WidgetInstallationStruct &
164     installerStruct) :
165     Job(Installation),
166     JobContextBase<WidgetInstallationStruct>(installerStruct),
167     m_exceptionCaught(Jobs::Exceptions::Success)
168 {
169     m_installerContext.mode = m_jobStruct.m_installMode;
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         AddTask(new TaskManifestFile(m_installerContext));
201         if (m_installerContext.widgetConfig.packagingType ==
202             PKG_TYPE_HYBRID_WEB_APP)
203         {
204             AddTask(new TaskInstallOspsvc(m_installerContext));
205         }
206         AddTask(new TaskCertificates(m_installerContext));
207         AddTask(new TaskDatabase(m_installerContext));
208         AddTask(new TaskAceCheck(m_installerContext));
209         AddTask(new TaskSmack(m_installerContext));
210     } else if (result == ConfigureResult::Updated) {
211         LogInfo("Configure installation updated");
212         LogInfo("Widget Update");
213         m_installerContext.job->SetProgressFlag(true);
214
215         if (m_installerContext.mode.command ==
216             InstallMode::Command::REINSTALL)
217         {
218             AddTask(new TaskPrepareReinstall(m_installerContext));
219         }
220
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             AddTask(new TaskFileManipulation(m_installerContext));
248         }
249
250         AddTask(new TaskManifestFile(m_installerContext));
251         if (m_installerContext.widgetConfig.packagingType ==
252             PKG_TYPE_HYBRID_WEB_APP)
253         {
254             AddTask(new TaskInstallOspsvc(m_installerContext));
255         }
256         AddTask(new TaskCertificates(m_installerContext));
257         AddTask(new TaskDatabase(m_installerContext));
258         AddTask(new TaskAceCheck(m_installerContext));
259         //TODO: remove widgetHandle from this task and move before database task
260         // by now widget handle is needed in ace check
261         // Any error in acecheck while update will break widget
262         AddTask(new TaskSmack(m_installerContext));
263         AddTask(new TaskRemoveBackupFiles(m_installerContext));
264     } else if (result == ConfigureResult::Deferred) {
265         // Installation is deferred
266         LogInfo("Configure installation deferred");
267
268         AddTask(new InstallerTaskFail(result));
269     } else if (result >= ConfigureResult::Failed &&
270             result <= ConfigureResult::Failed_DrmError) {
271         // Installation is not allowed to proceed due to widget update policy
272         LogWarning("Configure installation failed!");
273
274         AddTask(new InstallerTaskFail(result));
275     } else {
276         Assert(false && "Invalid configure result!");
277     }
278 }
279
280 ConfigureResult JobWidgetInstall::PrePareInstallation(
281     const std::string &widgetPath)
282 {
283     ConfigureResult result;
284     m_needEncryption = false;
285
286     Try
287     {
288         std::string tempDir;
289         if (m_installerContext.mode.extension == InstallMode::ExtensionType::DIR) {
290             std::ostringstream tempPathBuilder;
291             tempPathBuilder << WrtDB::GlobalConfig::GetUserInstalledWidgetPath();
292             tempPathBuilder << WrtDB::GlobalConfig::GetTmpDirPath();
293             tempPathBuilder << "/";
294             tempPathBuilder << widgetPath;
295             tempDir = tempPathBuilder.str();;
296         } else {
297             tempDir =
298                 Jobs::WidgetInstall::createTempPath(
299                         m_installerContext.mode.rootPath ==
300                             InstallMode::RootPath::RO);
301         }
302
303         m_isDRM = isDRMWidget(widgetPath);
304         if (true == m_isDRM) {
305             LogDebug("decrypt DRM widget");
306             if (DecryptDRMWidget(widgetPath, tempDir)) {
307                 LogDebug("Failed decrypt DRM widget");
308                 return ConfigureResult::Failed_DrmError;
309             }
310         }
311
312         LogDebug("widgetPath:" << widgetPath);
313
314         m_installerContext.widgetConfig.packagingType =
315             checkPackageType(widgetPath, tempDir);
316         ConfigParserData configData = getWidgetDataFromXML(
317                 widgetPath,
318                 tempDir,
319                 m_installerContext.widgetConfig.packagingType,
320                 m_isDRM,
321                 m_installerContext.mode.command == InstallMode::Command::REINSTALL);
322         LogDebug("widget packaging type : " <<
323                  m_installerContext.widgetConfig.packagingType.pkgType);
324
325         setTizenId(configData);
326         setApplicationType(configData);
327         m_needEncryption = detectResourceEncryption(configData);
328         setInstallLocationType(configData);
329
330         // Configure installation
331         result = ConfigureInstallation(widgetPath, configData, tempDir);
332     }
333     Catch(Exceptions::ExtractFileFailed)
334     {
335         LogError("Failed to create temporary path for widget");
336         result = ConfigureResult::Failed_InvalidConfig;
337     }
338
339     return result;
340 }
341
342 void JobWidgetInstall::setTizenId(
343     const WrtDB::ConfigParserData &configInfo)
344 {
345     bool shouldMakeAppid = false;
346     using namespace PackageManager;
347     if (!!configInfo.tizenAppId) {
348         LogDebug("Setting tizenAppId provided in config.xml: " <<
349                  configInfo.tizenAppId);
350
351         m_installerContext.widgetConfig.tzAppid = *configInfo.tizenAppId;
352         //check package id.
353         if (!!configInfo.tizenPkgId) {
354             LogDebug("Setting tizenPkgId provided in config.xml: " <<
355                      configInfo.tizenPkgId);
356
357             m_installerContext.widgetConfig.tzPkgid = *configInfo.tizenPkgId;
358         } else {
359             DPL::String appid = *configInfo.tizenAppId;
360             if (appid.length() > PACKAGE_ID_LENGTH) {
361                 m_installerContext.widgetConfig.tzPkgid =
362                     appid.substr(0, PACKAGE_ID_LENGTH);
363             } else {
364                 //old version appid only has 10byte random character is able to install for a while.
365                 //this case appid equal pkgid.
366                 m_installerContext.widgetConfig.tzPkgid =
367                     *configInfo.tizenAppId;
368                 shouldMakeAppid = true;
369             }
370         }
371     } else {
372         shouldMakeAppid = true;
373         TizenPkgId pkgId = WidgetDAOReadOnly::generatePkgId();
374         LogDebug("Checking if pkg id is unique");
375         while (true) {
376             if (!validateTizenPackageID(pkgId)) {
377                 //path exist, chose another one
378                 pkgId = WidgetDAOReadOnly::generatePkgId();
379                 continue;
380             }
381             break;
382         }
383         m_installerContext.widgetConfig.tzPkgid = pkgId;
384         LogInfo("tizen_id name was generated by WRT: " <<
385                 m_installerContext.widgetConfig.tzPkgid);
386     }
387
388     if (shouldMakeAppid == true) {
389         DPL::OptionalString name;
390         DPL::OptionalString defaultLocale = configInfo.defaultlocale;
391
392         FOREACH(localizedData, configInfo.localizedDataSet)
393         {
394             Locale i = localizedData->first;
395             if (!!defaultLocale) {
396                 if (defaultLocale == i) {
397                     name = localizedData->second.name;
398                     break;
399                 }
400             } else {
401                 name = localizedData->second.name;
402                 break;
403             }
404         }
405         regex_t regx;
406         if (regcomp(&regx, REG_NAME_PATTERN, REG_NOSUB | REG_EXTENDED) != 0) {
407             LogDebug("Regcomp failed");
408         }
409
410         LogDebug("Name : " << name);
411         if (!name || (regexec(&regx, DPL::ToUTF8String(*name).c_str(),
412                               static_cast<size_t>(0), NULL, 0) != REG_NOERROR))
413         {
414             // TODO : generate name move to wrt-commons
415             std::string allowedString("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
416             std::ostringstream genName;
417             struct timeval tv;
418             gettimeofday(&tv, NULL);
419             unsigned int seed = time(NULL) + tv.tv_usec;
420
421             genName << "_" << allowedString[rand_r(&seed) % allowedString.length()];
422             name = DPL::FromUTF8String(genName.str());
423             LogDebug("name was generated by WRT");
424         }
425         regfree(&regx);
426         LogDebug("Name : " << name);
427         std::ostringstream genid;
428         genid << m_installerContext.widgetConfig.tzPkgid << "." << name;
429         LogDebug("tizen appid was generated by WRT : " << genid.str());
430
431         DPL::OptionalString appid = DPL::FromUTF8String(genid.str());
432         NormalizeAndTrimSpaceString(appid);
433         m_installerContext.widgetConfig.tzAppid = *appid;
434     }
435
436     // send start signal of pkgmgr
437     getInstallerStruct().pkgmgrInterface->setPkgname(DPL::ToUTF8String(
438                                                          m_installerContext.
439                                                              widgetConfig.
440                                                              tzPkgid));
441     LogInfo("Tizen App Id : " << m_installerContext.widgetConfig.tzAppid);
442     LogInfo("Tizen Pkg Id : " << m_installerContext.widgetConfig.tzPkgid);
443     LogInfo("W3C Widget GUID : " << m_installerContext.widgetConfig.guid);
444 }
445
446 void JobWidgetInstall::configureWidgetLocation(const std::string & widgetPath,
447                                                const std::string& tempPath)
448 {
449     m_installerContext.locations =
450         WidgetLocation(DPL::ToUTF8String(m_installerContext.widgetConfig.
451                                              tzPkgid),
452                        widgetPath, tempPath,
453                        m_installerContext.widgetConfig.packagingType,
454                        m_installerContext.mode.rootPath ==
455                            InstallMode::RootPath::RO);
456     m_installerContext.locations->registerAppid(
457         DPL::ToUTF8String(m_installerContext.widgetConfig.tzAppid));
458
459     LogInfo("widgetSource " << widgetPath);
460 }
461
462 ConfigureResult JobWidgetInstall::ConfigureInstallation(
463     const std::string &widgetSource,
464     const WrtDB::ConfigParserData &configData,
465     const std::string &tempPath)
466 {
467     ConfigureResult result = ConfigureResult::Failed;
468     WidgetUpdateInfo update;
469
470     // checking installed web application
471     Try {
472         // checking existing application is installed
473         WidgetDAOReadOnly dao(m_installerContext.widgetConfig.tzAppid);
474         // no excpetion means, it isn't update mode
475         getInstallerStruct().pkgmgrInterface->sendSignal(
476                 PKGMGR_START_KEY,
477                 PKGMGR_START_UPDATE);
478
479         update = detectWidgetUpdate(configData,
480                                     m_installerContext.widgetConfig.tzAppid);
481         result = checkWidgetUpdate(update);
482         if (result != ConfigureResult::Updated) {
483             // Already installed TizenAppId. return failed
484             return ConfigureResult::Failed_AlreadyInstalled;
485         }
486         if (!checkSupportRDSUpdate(configData)) {
487             return ConfigureResult::Failed_NotSupportRDSUpdate;
488         }
489         m_installerContext.isUpdateMode = true;
490     }
491     Catch(WidgetDAOReadOnly::Exception::WidgetNotExist) {
492         result = ConfigureResult::Ok;
493         getInstallerStruct().pkgmgrInterface->sendSignal(
494                 PKGMGR_START_KEY,
495                 PKGMGR_START_INSTALL);
496         m_installerContext.isUpdateMode = false;
497
498         if (!validateTizenApplicationID(
499             m_installerContext.widgetConfig.tzAppid))
500         {
501             LogError("tizen application ID is already used");
502             return ConfigureResult::Failed_InvalidConfig;
503         }
504         if (!validateTizenPackageID(m_installerContext.widgetConfig.tzPkgid)) {
505             LogError("tizen package ID is already used");
506             return ConfigureResult::Failed_AlreadyInstalled;
507         }
508     }
509
510     configureWidgetLocation(widgetSource, tempPath);
511
512     // Init installer context
513     m_installerContext.installStep = InstallerContext::INSTALL_START;
514     m_installerContext.job = this;
515     m_installerContext.widgetConfig.shareHref = std::string();
516
517     return result;
518 }
519
520 bool JobWidgetInstall::validateTizenApplicationID(
521     const WrtDB::TizenAppId &tizenAppId)
522 {
523     LogInfo("tizen application ID = [" << tizenAppId << "]");
524
525     regex_t reg;
526     if (regcomp(&reg, REG_TIZENID_PATTERN, REG_NOSUB | REG_EXTENDED) != 0) {
527         LogDebug("Regcomp failed");
528     }
529
530     if (regexec(&reg, DPL::ToUTF8String(tizenAppId).c_str(), 0, NULL, 0)
531         == REG_NOMATCH)
532     {
533         regfree(&reg);
534         return false;
535     }
536     regfree(&reg);
537     return true;
538 }
539
540 bool JobWidgetInstall::validateTizenPackageID(
541     const WrtDB::TizenPkgId &tizenPkgId)
542 {
543     std::string pkgId = DPL::ToUTF8String(tizenPkgId);
544
545     std::string installPath =
546         std::string(GlobalConfig::GetUserInstalledWidgetPath()) +
547         "/" + pkgId;
548     std::string preinstallPath =
549         std::string(GlobalConfig::GetUserPreloadedWidgetPath()) +
550         "/" + pkgId;
551
552     struct stat dirStat;
553     if ((stat(installPath.c_str(), &dirStat) == 0) ||
554         (stat(preinstallPath.c_str(), &dirStat) == 0))
555     {
556         return false;
557     }
558     return true;
559 }
560
561 ConfigureResult JobWidgetInstall::checkWidgetUpdate(
562     const WidgetUpdateInfo &update)
563 {
564     if (update.existingVersion.IsNull() || update.incomingVersion.IsNull()) {
565         return ConfigureResult::Failed;
566     }
567
568     LogInfo("existing version = '" << update.existingVersion);
569     LogInfo("incoming version = '" << update.incomingVersion);
570     LogInfo("Tizen AppID = " << update.tzAppId);
571
572     // Check running state
573     bool isRunning = false;
574     int ret =
575         app_manager_is_running(DPL::ToUTF8String(update.tzAppId).c_str(),
576                                &isRunning);
577     if (APP_MANAGER_ERROR_NONE != ret) {
578         LogError("Fail to get running state");
579         return ConfigureResult::Failed_WidgetRunning;
580     }
581
582     if (true == isRunning) {
583         // get app_context for running application
584         // app_context must be released with app_context_destroy
585         app_context_h appCtx = NULL;
586         ret =
587             app_manager_get_app_context(
588                 DPL::ToUTF8String(update.tzAppId).c_str(),
589                 &appCtx);
590         if (APP_MANAGER_ERROR_NONE != ret) {
591             LogError("Fail to get app_context");
592             return ConfigureResult::Failed_WidgetRunning;
593         }
594
595         // terminate app_context_h
596         ret = app_manager_terminate_app(appCtx);
597         if (APP_MANAGER_ERROR_NONE != ret) {
598             LogError("Fail to terminate running application");
599             app_context_destroy(appCtx);
600             return ConfigureResult::Failed_WidgetRunning;
601         } else {
602             app_context_destroy(appCtx);
603             // app_manager_terminate_app isn't sync API
604             // wait until application isn't running (50ms * 100)
605             bool isStillRunning = true;
606             int checkingloop = 100;
607             struct timespec duration = { 0, 50 * 1000 * 1000 };
608             while (--checkingloop >= 0) {
609                 nanosleep(&duration, NULL);
610                 int ret =
611                     app_manager_is_running(
612                         DPL::ToUTF8String(update.tzAppId).c_str(),
613                         &isStillRunning);
614                 if (APP_MANAGER_ERROR_NONE != ret) {
615                     LogError("Fail to get running state");
616                     return ConfigureResult::Failed_WidgetRunning;
617                 }
618                 if (!isStillRunning) {
619                     break;
620                 }
621             }
622             if (isStillRunning) {
623                 LogError("Fail to terminate running application");
624                 return ConfigureResult::Failed_WidgetRunning;
625             }
626             LogInfo("terminate application");
627         }
628     }
629
630     m_installerContext.widgetConfig.tzAppid = update.tzAppId;
631
632     if (!!update.existingVersion ||
633             m_installerContext.mode.extension ==
634             InstallMode::ExtensionType::DIR) {
635         return ConfigureResult::Updated;
636     }
637
638     return ConfigureResult::Failed;
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
773     OptionalWidgetVersion optVersion;
774     DPL::OptionalString version = dao.getVersion();
775     if (!version.IsNull()) {
776         optVersion = OptionalWidgetVersion(WidgetVersion(*version));
777     }
778
779     return WidgetUpdateInfo(
780         dao.getTzAppId(),
781         optVersion,
782         incomingVersion);
783 }
784
785 void JobWidgetInstall::SendProgress()
786 {
787     using namespace PackageManager;
788     if (GetProgressFlag() != false) {
789         if (getInstallerStruct().progressCallback != NULL) {
790             // send progress signal of pkgmgr
791             std::ostringstream percent;
792             percent << static_cast<int>(GetProgressPercent());
793             getInstallerStruct().pkgmgrInterface->sendSignal(
794                 PKGMGR_PROGRESS_KEY,
795                 percent.str());
796
797             LogDebug("Call widget install progressCallbak");
798             getInstallerStruct().progressCallback(
799                 getInstallerStruct().userParam,
800                 GetProgressPercent(),
801                 GetProgressDescription());
802         }
803     }
804 }
805
806 void JobWidgetInstall::SendProgressIconPath(const std::string &path)
807 {
808     using namespace PackageManager;
809     if (GetProgressFlag() != false) {
810         if (getInstallerStruct().progressCallback != NULL) {
811             // send progress signal of pkgmgr
812             getInstallerStruct().pkgmgrInterface->sendSignal(
813                 PKGMGR_ICON_PATH,
814                 path);
815         }
816     }
817 }
818
819 void JobWidgetInstall::SendFinishedSuccess()
820 {
821     using namespace PackageManager;
822     // TODO : sync should move to separate task.
823     sync();
824
825     if (INSTALL_LOCATION_TYPE_EXTERNAL == m_installerContext.locationType) {
826         if (m_installerContext.isUpdateMode) {
827             WidgetInstallToExtSingleton::Instance().postUpgrade(true);
828         } else {
829             WidgetInstallToExtSingleton::Instance().postInstallation(true);
830         }
831         WidgetInstallToExtSingleton::Instance().deinitialize();
832     }
833
834     // remove widget install information file
835     unlink(m_installerContext.installInfo.c_str());
836
837     //inform widget info
838     JobWidgetInstall::displayWidgetInfo();
839
840     TizenAppId& tizenId = m_installerContext.widgetConfig.tzAppid;
841
842     // send signal of pkgmgr
843     getInstallerStruct().pkgmgrInterface->sendSignal(
844         PKGMGR_END_KEY,
845         PKGMGR_END_SUCCESS);
846
847     LogDebug("Call widget install successfinishedCallback");
848     getInstallerStruct().finishedCallback(getInstallerStruct().userParam,
849                                           DPL::ToUTF8String(
850                                               tizenId), Jobs::Exceptions::Success);
851 }
852
853 void JobWidgetInstall::SendFinishedFailure()
854 {
855     using namespace PackageManager;
856     // remove widget install information file
857     unlink(m_installerContext.installInfo.c_str());
858
859     LogError("Error number: " << m_exceptionCaught);
860     LogError("Message: " << m_exceptionMessage);
861     TizenAppId & tizenId = m_installerContext.widgetConfig.tzAppid;
862
863     LogDebug("Call widget install failure finishedCallback");
864     std::stringstream errorNum;
865     errorNum << m_exceptionCaught;
866
867     // send signal of pkgmgr
868     getInstallerStruct().pkgmgrInterface->sendSignal(
869         PKGMGR_ERROR,
870         errorNum.str());
871
872     getInstallerStruct().pkgmgrInterface->sendSignal(
873         PKGMGR_END_KEY,
874         PKGMGR_END_FAILURE);
875
876     getInstallerStruct().finishedCallback(getInstallerStruct().userParam,
877                                           DPL::ToUTF8String(
878                                               tizenId), m_exceptionCaught);
879 }
880
881 void JobWidgetInstall::SaveExceptionData(const Jobs::JobExceptionBase &e)
882 {
883     m_exceptionCaught = static_cast<Jobs::Exceptions::Type>(e.getParam());
884     m_exceptionMessage = e.GetMessage();
885 }
886
887 void JobWidgetInstall::displayWidgetInfo()
888 {
889     WidgetDAOReadOnly dao(m_installerContext.widgetConfig.tzAppid);
890
891     std::ostringstream out;
892     WidgetLocalizedInfo localizedInfo =
893         W3CFileLocalization::getLocalizedInfo(dao.getTzAppId());
894
895     out << std::endl <<
896     "===================================== INSTALLED WIDGET INFO =========" \
897     "============================";
898     out << std::endl << "Name:                        " << localizedInfo.name;
899     out << std::endl << "AppId:                     " << dao.getTzAppId();
900     WidgetSize size = dao.getPreferredSize();
901     out << std::endl << "Width:                       " << size.width;
902     out << std::endl << "Height:                      " << size.height;
903     out << std::endl << "Start File:                  " <<
904     W3CFileLocalization::getStartFile(dao.getTzAppId());
905     out << std::endl << "Version:                     " << dao.getVersion();
906     out << std::endl << "Licence:                     " <<
907     localizedInfo.license;
908     out << std::endl << "Licence Href:                " <<
909     localizedInfo.licenseHref;
910     out << std::endl << "Description:                 " <<
911     localizedInfo.description;
912     out << std::endl << "Widget Id:                   " << dao.getGUID();
913     out << std::endl << "Widget recognized:           " << dao.isRecognized();
914     out << std::endl << "Widget distributor signed:   " <<
915     dao.isDistributorSigned();
916     out << std::endl << "Widget trusted:              " << dao.isTrusted();
917
918     OptionalWidgetIcon icon = W3CFileLocalization::getIcon(dao.getTzAppId());
919     DPL::OptionalString iconSrc =
920         !!icon ? icon->src : DPL::OptionalString::Null;
921     out << std::endl << "Icon:                        " << iconSrc;
922
923     out << std::endl << "Preferences:";
924     {
925         PropertyDAOReadOnly::WidgetPreferenceList list = dao.getPropertyList();
926         FOREACH(it, list)
927         {
928             out << std::endl << "  Key:                       " <<
929             it->key_name;
930             out << std::endl << "      Readonly:              " <<
931             it->readonly;
932         }
933     }
934
935     out << std::endl << "Features:";
936     {
937         WidgetFeatureSet list = dao.getFeaturesList();
938         FOREACH(it, list)
939         {
940             out << std::endl << "  Name:                      " << it->name;
941         }
942     }
943
944     out << std::endl;
945
946     LogInfo(out.str());
947 }
948
949 WrtDB::PackagingType JobWidgetInstall::checkPackageType(
950     const std::string &widgetSource,
951     const std::string &tempPath)
952 {
953     // Check installation type (direcotory/ or config.xml or widget.wgt)
954     if (m_installerContext.mode.extension == InstallMode::ExtensionType::DIR) {
955         LogDebug("Install directly from directory");
956         return PKG_TYPE_DIRECTORY_WEB_APP;
957     }
958     if (hasExtension(widgetSource, XML_EXTENSION)) {
959         LogInfo("Hosted app installation");
960         return PKG_TYPE_HOSTED_WEB_APP;
961     }
962
963     if (m_isDRM) {
964         std::string configFile = tempPath + "/" + CONFIG_XML;
965         if (WrtUtilFileExists(configFile)) {
966             return PKG_TYPE_NOMAL_WEB_APP;
967         }
968
969         configFile = tempPath + "/" + WITH_OSP_XML;
970         if (WrtUtilFileExists(configFile)) {
971             return PKG_TYPE_HYBRID_WEB_APP;
972         }
973     } else {
974         std::unique_ptr<DPL::ZipInput> zipFile;
975
976         Try
977         {
978             // Open zip file
979             zipFile.reset(new DPL::ZipInput(widgetSource));
980         }
981         Catch(DPL::ZipInput::Exception::OpenFailed)
982         {
983             LogDebug("Failed to open widget package");
984             return PKG_TYPE_UNKNOWN;
985         }
986         Catch(DPL::ZipInput::Exception::SeekFileFailed)
987         {
988             LogError("Failed to seek widget package file");
989             return PKG_TYPE_UNKNOWN;
990         }
991
992         Try
993         {
994             // Open config.xml file in package root
995             std::unique_ptr<DPL::ZipInput::File> configFile(
996                 zipFile->OpenFile(CONFIG_XML));
997             return PKG_TYPE_NOMAL_WEB_APP;
998         }
999         Catch(DPL::ZipInput::Exception::OpenFileFailed)
1000         {
1001             LogDebug("Could not find config.xml");
1002         }
1003
1004         Try
1005         {
1006             // Open config.xml file in package root
1007             std::unique_ptr<DPL::ZipInput::File> configFile(
1008                 zipFile->OpenFile(WITH_OSP_XML));
1009
1010             return PKG_TYPE_HYBRID_WEB_APP;
1011         }
1012         Catch(DPL::ZipInput::Exception::OpenFileFailed)
1013         {
1014             LogDebug("Could not find wgt/config.xml");
1015             return PKG_TYPE_UNKNOWN;
1016         }
1017     }
1018
1019     return PKG_TYPE_UNKNOWN;
1020 }
1021
1022 void JobWidgetInstall::setApplicationType(
1023     const WrtDB::ConfigParserData &configInfo)
1024 {
1025     FOREACH(iterator, configInfo.nameSpaces) {
1026         LogInfo("namespace = [" << *iterator << "]");
1027         AppType currentAppType = APP_TYPE_UNKNOWN;
1028
1029         if (*iterator == ConfigurationNamespace::W3CWidgetNamespaceName) {
1030             continue;
1031         } else if (
1032             *iterator ==
1033             ConfigurationNamespace::WacWidgetNamespaceNameForLinkElement ||
1034             *iterator ==
1035             ConfigurationNamespace::WacWidgetNamespaceName)
1036         {
1037             currentAppType = APP_TYPE_WAC20;
1038         } else if (*iterator ==
1039                    ConfigurationNamespace::TizenWebAppNamespaceName)
1040         {
1041             currentAppType = APP_TYPE_TIZENWEBAPP;
1042         }
1043
1044         if (m_installerContext.widgetConfig.webAppType ==
1045             APP_TYPE_UNKNOWN)
1046         {
1047             m_installerContext.widgetConfig.webAppType = currentAppType;
1048         } else if (m_installerContext.widgetConfig.webAppType ==
1049                    currentAppType)
1050         {
1051             continue;
1052         } else {
1053             ThrowMsg(Exceptions::WidgetConfigFileInvalid,
1054                      "Config.xml has more than one namespace");
1055         }
1056     }
1057
1058     // If there is no define, type set to WAC 2.0
1059     if (m_installerContext.widgetConfig.webAppType == APP_TYPE_UNKNOWN) {
1060         m_installerContext.widgetConfig.webAppType = APP_TYPE_WAC20;
1061     }
1062
1063     LogInfo("type = [" <<
1064             m_installerContext.widgetConfig.webAppType.getApptypeToString() <<
1065             "]");
1066 }
1067
1068 bool JobWidgetInstall::detectResourceEncryption(
1069     const WrtDB::ConfigParserData &configData)
1070 {
1071     FOREACH(it, configData.settingsList)
1072     {
1073         if (it->m_name == SETTING_VALUE_ENCRYPTION &&
1074             it->m_value == SETTING_VALUE_ENCRYPTION_ENABLE)
1075         {
1076             LogDebug("resource need encryption");
1077             return true;
1078         }
1079     }
1080     return false;
1081 }
1082
1083 void JobWidgetInstall::setInstallLocationType(
1084     const WrtDB::ConfigParserData & configData)
1085 {
1086     m_installerContext.locationType = INSTALL_LOCATION_TYPE_NOMAL;
1087     if (m_installerContext.mode.installTime != InstallMode::InstallTime::PRELOAD) {
1088         FOREACH(it, configData.settingsList) {
1089             if (it->m_name == SETTING_VALUE_INSTALLTOEXT_NAME &&
1090                 it->m_value ==
1091                 SETTING_VALUE_INSTALLTOEXT_PREPER_EXT)
1092             {
1093                 LogDebug("This widget will be installed to sd card");
1094                 m_installerContext.locationType =
1095                     INSTALL_LOCATION_TYPE_EXTERNAL;
1096             }
1097         }
1098     }
1099 }
1100
1101 bool JobWidgetInstall::isDRMWidget(std::string /*widgetPath*/)
1102 {
1103     /* TODO */
1104     return false;
1105 }
1106
1107 bool JobWidgetInstall::DecryptDRMWidget(std::string /*widgetPath*/,
1108                                         std::string /*destPath*/)
1109 {
1110     /* TODO */
1111     return false;
1112 }
1113
1114 bool JobWidgetInstall::checkSupportRDSUpdate(const WrtDB::ConfigParserData
1115         &configInfo)
1116 {
1117     if (m_installerContext.mode.command ==
1118             InstallMode::Command::REINSTALL)
1119     {
1120         DPL::String configValue = SETTING_VALUE_ENCRYPTION_DISABLE;
1121         DPL::String dbValue = SETTING_VALUE_ENCRYPTION_DISABLE;
1122
1123         WidgetDAOReadOnly dao(m_installerContext.widgetConfig.tzAppid);
1124         WrtDB::WidgetSettings widgetSettings;
1125         dao.getWidgetSettings(widgetSettings);
1126
1127         FOREACH(it, widgetSettings) {
1128             if (it->settingName == SETTING_VALUE_ENCRYPTION) {
1129                 dbValue = it->settingValue;
1130             }
1131         }
1132
1133         FOREACH(data, configInfo.settingsList)
1134         {
1135             if (data->m_name == SETTING_VALUE_ENCRYPTION) 
1136             {
1137                 configValue = data->m_value;
1138             }
1139         }
1140         if (configValue != dbValue) {
1141             LogError("Not Support RDS mode because of encryption setting");
1142             return false;
1143         }
1144     }
1145
1146     return true;
1147 }
1148 } //namespace WidgetInstall
1149 } //namespace Jobs