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