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