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