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