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