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