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