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