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