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