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