Revert "Change pkgname to appid for docomo request. PART2"
[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}.[a-zA-Z0-9]{1,}$";
89 const size_t PACKAGE_ID_LENGTH = 10;
90
91 static const DPL::String SETTING_VALUE_ENCRYPTION = L"encryption";
92 static const DPL::String SETTING_VALUE_ENCRYPTION_ENABLE = L"enable";
93 const DPL::String SETTING_VALUE_INSTALLTOEXT_NAME =
94     L"install-location-type";
95 const DPL::String SETTING_VALUE_INSTALLTOEXT_PREPER_EXT =
96     L"prefer-external";
97
98 class InstallerTaskFail :
99     public DPL::TaskDecl<InstallerTaskFail>
100 {
101   private:
102     bool m_deferred;
103
104     void StepFail()
105     {
106         if (m_deferred) {
107             ThrowMsg(Jobs::WidgetInstall::Exceptions::Deferred,
108                      "Widget installation or update deferred!");
109         } else {
110             ThrowMsg(Jobs::WidgetInstall::Exceptions::NotAllowed,
111                      "Widget installation or update not allowed!");
112         }
113     }
114
115   public:
116     InstallerTaskFail(bool deferred) :
117         DPL::TaskDecl<InstallerTaskFail>(this),
118         m_deferred(deferred)
119     {
120         AddStep(&InstallerTaskFail::StepFail);
121     }
122 };
123
124 const std::string XML_EXTENSION = ".xml";
125
126 bool hasExtension(const std::string& filename, const std::string& extension) {
127     LogDebug("Looking for extension " << extension << " in: "  << filename);
128     size_t fileLen = filename.length();
129     size_t extLen = extension.length();
130     if (fileLen < extLen) {
131         LogError("Filename " << filename << " is shorter than extension "
132                  << extension);
133         return false;
134     }
135     return (0 == filename.compare(fileLen-extLen, extLen, extension));
136 }
137
138 bool checkTizenPkgIdExist(const std::string& tizenPkgId) {
139     std::string installPath =
140         std::string(GlobalConfig::GetUserInstalledWidgetPath()) +
141         "/" + tizenPkgId;
142     std::string preinstallPath =
143         std::string(GlobalConfig::GetUserPreloadedWidgetPath()) +
144         "/" + tizenPkgId;
145
146     struct stat dirStat;
147     if ((stat(installPath.c_str(), &dirStat) == 0) &&
148             (stat(preinstallPath.c_str(), &dirStat) == 0)) {
149         return true;
150     }
151     return false;
152 }
153 } // namespace anonymous
154
155 namespace Jobs {
156 namespace WidgetInstall {
157 JobWidgetInstall::JobWidgetInstall(std::string const &widgetPath,
158         const WidgetInstallationStruct &installerStruct) :
159     Job(Installation),
160     JobContextBase<WidgetInstallationStruct>(installerStruct),
161     m_exceptionCaught(Exceptions::Success)
162 {
163     struct timeval tv;
164     gettimeofday(&tv, NULL);
165     srand(time(NULL) + tv.tv_usec);
166
167     m_installerContext.m_quiet = m_jobStruct.m_quiet;
168
169     ConfigureResult result = PrePareInstallation(widgetPath);
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     bool shouldMakeAppid = false;
329     using namespace PackageManager;
330     if(!!configInfo.tizenAppId) {
331         LogDebug("Setting tizenAppId provided in config.xml: " <<
332                 configInfo.tizenAppId);
333
334         m_installerContext.widgetConfig.tzAppid = *configInfo.tizenAppId;
335         //check package id.
336         if(!!configInfo.tizenPkgId) {
337             LogDebug("Setting tizenPkgId provided in config.xml: " <<
338                     configInfo.tizenPkgId);
339
340             m_installerContext.widgetConfig.tzPkgid = *configInfo.tizenPkgId;
341         } else {
342             std::string appid = DPL::ToUTF8String(*configInfo.tizenAppId);
343             if(appid.length() > PACKAGE_ID_LENGTH) {
344                 m_installerContext.widgetConfig.tzPkgid =
345                     DPL::FromUTF8String(appid.substr(PACKAGE_ID_LENGTH));
346             } else {
347                 m_installerContext.widgetConfig.tzPkgid =
348                     *configInfo.tizenAppId;
349             }
350             shouldMakeAppid = true;
351         }
352     } else {
353         shouldMakeAppid = true;
354         TizenPkgId pkgId = WidgetDAOReadOnly::generatePkgId();
355         LogDebug("Checking if pkg id is unique");
356         while (true) {
357             if (checkTizenPkgIdExist(DPL::ToUTF8String(pkgId))) {
358                 //path exist, chose another one
359                 pkgId = WidgetDAOReadOnly::generatePkgId();
360                 continue;
361             }
362             break;
363         }
364         m_installerContext.widgetConfig.tzPkgid = pkgId;
365         LogInfo("tizen_id name was generated by WRT: " <<
366                 m_installerContext.widgetConfig.tzPkgid);
367
368     }
369
370     if(shouldMakeAppid == true) {
371         DPL::OptionalString name;
372         DPL::OptionalString defaultLocale = configInfo.defaultlocale;
373
374         FOREACH(localizedData, configInfo.localizedDataSet)
375         {
376             Locale i = localizedData->first;
377             if (!!defaultLocale) {
378                 if (defaultLocale == i) {
379                     name = localizedData->second.name;
380                     break;
381                 }
382
383             } else {
384                 name = localizedData->second.name;
385                 break;
386             }
387         }
388         if (!!name) {
389             LogDebug("Name : " << name);
390             std::ostringstream appid;
391             appid << m_installerContext.widgetConfig.tzPkgid << "." << name;
392             LogDebug("tizen appid was generated by WRT : " << appid.str());
393             m_installerContext.widgetConfig.tzAppid =
394                 DPL::FromUTF8String(appid.str());
395         } else {
396             m_installerContext.widgetConfig.tzAppid =
397                 m_installerContext.widgetConfig.tzPkgid;
398         }
399     }
400
401     // send start signal of pkgmgr
402     getInstallerStruct().pkgmgrInterface->setPkgname(DPL::ToUTF8String(
403                 m_installerContext.widgetConfig.tzAppid));
404     getInstallerStruct().pkgmgrInterface->sendSignal(
405             PKGMGR_START_KEY,
406             PKGMGR_START_INSTALL);
407
408     LogInfo("Tizen App Id : " << m_installerContext.widgetConfig.tzAppid);
409     LogInfo("Tizen Pkg Id : " << m_installerContext.widgetConfig.tzPkgid);
410     LogInfo("W3C Widget GUID : " << m_installerContext.widgetConfig.guid);
411 }
412
413 void JobWidgetInstall::configureWidgetLocation(const std::string & widgetPath,
414                                                const std::string& tempPath)
415 {
416     m_installerContext.locations =
417         WidgetLocation(DPL::ToUTF8String(m_installerContext.widgetConfig.tzAppid),
418                 widgetPath, tempPath,
419                 m_installerContext.widgetConfig.packagingType,
420                 m_installerContext.locationType);
421
422     LogInfo("widgetSource " << widgetPath);
423 }
424
425 JobWidgetInstall::ConfigureResult JobWidgetInstall::ConfigureInstallation(
426         const std::string &widgetSource,
427         const WrtDB::ConfigParserData &configData,
428         const std::string &tempPath)
429 {
430     WidgetUpdateInfo update = detectWidgetUpdate(configData,
431             m_installerContext.widgetConfig.webAppType,
432             m_installerContext.widgetConfig.tzAppid);
433     ConfigureResult result = checkWidgetUpdate(update);
434
435     // Validate tizenId
436     regex_t reg;
437     if(regcomp(&reg, REG_TIZENID_PATTERN, REG_NOSUB | REG_EXTENDED)!=0){
438         LogDebug("Regcomp failed");
439     }
440
441     if ((regexec(&reg,
442                     DPL::ToUTF8String(m_installerContext.widgetConfig.tzAppid).c_str(),
443                     static_cast<size_t>(0), NULL, 0) != REG_NOERROR) ||
444             (checkTizenPkgIdExist(DPL::ToUTF8String(m_installerContext.widgetConfig.tzPkgid)) &&
445              result != ConfigureResult::Updated))
446     {
447         //it is true when tizenId does not fit REG_TIZENID_PATTERN
448         LogError("tizen_id provided but not proper.");
449         regfree(&reg);
450         return ConfigureResult::Failed;
451     }
452     regfree(&reg);
453
454     configureWidgetLocation(widgetSource, tempPath);
455
456     // Init installer context
457     m_installerContext.installStep = InstallerContext::INSTALL_START;
458     m_installerContext.job = this;
459     m_installerContext.existingWidgetInfo = update.existingWidgetInfo;
460     m_installerContext.widgetConfig.shareHref = std::string();
461
462     return result;
463 }
464
465 JobWidgetInstall::ConfigureResult JobWidgetInstall::checkWidgetUpdate(
466         const WidgetUpdateInfo &update)
467 {
468     LogInfo(
469         "Widget install/update: incoming guid = '" <<
470         update.incomingGUID << "'");
471     LogInfo(
472         "Widget install/update: incoming version = '" <<
473         update.incomingVersion << "'");
474
475     // Check policy
476     WidgetUpdateMode::Type updateTypeCheckBit;
477
478     if (update.existingWidgetInfo.isExist == false) {
479         LogInfo("Widget info does not exist");
480         updateTypeCheckBit = WidgetUpdateMode::NotInstalled;
481     } else {
482         LogInfo("Widget info exists. appid: " <<
483                 update.existingWidgetInfo.tzAppid);
484
485         TizenAppId tzAppid = update.existingWidgetInfo.tzAppid;
486
487         LogInfo("Widget model exists. tizen app id: " << tzAppid);
488
489         // Check running state
490         int retval = APP_MANAGER_ERROR_NONE;
491         bool isRunning = false;
492         retval = app_manager_is_running(DPL::ToUTF8String(tzAppid).c_str(), &isRunning);
493         if (APP_MANAGER_ERROR_NONE != retval) {
494             LogError("Fail to get running state");
495             return ConfigureResult::Failed;
496         }
497
498         if (true == isRunning) {
499             // Must be deferred when update in progress
500             if (m_jobStruct.updateMode == WidgetUpdateMode::PolicyWac) {
501                 LogInfo(
502                     "Widget is already running. Policy is update according to WAC");
503
504                 return ConfigureResult::Deferred;
505             } else {
506                 LogInfo(
507                     "Widget is already running. Policy is not update according to WAC");
508
509                 return ConfigureResult::Failed;
510             }
511         }
512
513         m_installerContext.widgetConfig.tzAppid = tzAppid;
514         OptionalWidgetVersion existingVersion;
515         existingVersion = update.existingWidgetInfo.existingVersion;
516         OptionalWidgetVersion incomingVersion = update.incomingVersion;
517
518         updateTypeCheckBit = CalcWidgetUpdatePolicy(existingVersion,
519                                                     incomingVersion);
520         // Calc proceed flag
521         if ((m_jobStruct.updateMode & updateTypeCheckBit) > 0 ||
522             m_jobStruct.updateMode ==
523                 WidgetUpdateMode::PolicyDirectoryForceInstall)
524         {
525             LogInfo("Whether widget policy allow proceed ok");
526             return ConfigureResult::Updated;
527         }
528         else
529             return ConfigureResult::Failed;
530     }
531     return ConfigureResult::Ok;
532 }
533
534 WidgetUpdateMode::Type JobWidgetInstall::CalcWidgetUpdatePolicy(
535         const OptionalWidgetVersion &existingVersion,
536         const OptionalWidgetVersion &incomingVersion) const
537 {
538     // Widget is installed, check versions
539     if (!existingVersion && !incomingVersion) {
540         return WidgetUpdateMode::ExistingVersionEqual;
541     } else if (!existingVersion && !!incomingVersion) {
542         return WidgetUpdateMode::ExistingVersionNewer;
543     } else if (!!existingVersion && !incomingVersion) {
544         return WidgetUpdateMode::ExistingVersionOlder;
545     } else {
546         LogInfo("Existing widget: version = '" << *existingVersion << "'");
547
548         if (!existingVersion->IsWac() && !incomingVersion->IsWac()) {
549             return WidgetUpdateMode::BothVersionsNotStd;
550         } else if (!existingVersion->IsWac()) {
551             return WidgetUpdateMode::ExistingVersionNotStd;
552         } else if (!incomingVersion->IsWac()) {
553             return WidgetUpdateMode::IncomingVersionNotStd;
554         } else {
555             // Both versions are WAC-comparable. Do compare.
556             if (*incomingVersion == *existingVersion) {
557                 return WidgetUpdateMode::ExistingVersionEqual;
558             } else if (*incomingVersion > *existingVersion) {
559                 return WidgetUpdateMode::ExistingVersionOlder;
560             } else {
561                 return WidgetUpdateMode::ExistingVersionNewer;
562             }
563         }
564     }
565 }
566
567 ConfigParserData JobWidgetInstall::getWidgetDataFromXML(
568         const std::string &widgetSource,
569         const std::string &tempPath,
570         WrtDB::PackagingType pkgType,
571         bool isDRM)
572 {
573     // Parse config
574     ParserRunner parser;
575     ConfigParserData configInfo;
576
577     Try
578     {
579         if (pkgType == PKG_TYPE_HOSTED_WEB_APP) {
580             parser.Parse(widgetSource,
581                     ElementParserPtr(
582                         new RootParser<WidgetParser>(configInfo,
583                             DPL::FromUTF32String(
584                                 L"widget"))));
585         } else if (pkgType == PKG_TYPE_DIRECTORY_WEB_APP) {
586             parser.Parse(widgetSource + '/' + WITH_OSP_XML,
587                          ElementParserPtr(
588                              new RootParser<WidgetParser>(
589                              configInfo,
590                              DPL::FromUTF32String(L"widget"))));
591         } else {
592             if (!isDRM) {
593                 std::unique_ptr<DPL::ZipInput> zipFile(
594                         new DPL::ZipInput(widgetSource));
595
596                 std::unique_ptr<DPL::ZipInput::File> configFile;
597
598                 // Open config.xml file
599                 if (pkgType == PKG_TYPE_HYBRID_WEB_APP) {
600                     configFile.reset(zipFile->OpenFile(WITH_OSP_XML));
601                 } else {
602                     configFile.reset(zipFile->OpenFile(CONFIG_XML));
603                 }
604
605                 // Extract config
606                 DPL::BinaryQueue buffer;
607                 DPL::AbstractWaitableInputAdapter inputAdapter(configFile.get());
608                 DPL::AbstractWaitableOutputAdapter outputAdapter(&buffer);
609                 DPL::Copy(&inputAdapter, &outputAdapter);
610                 parser.Parse(&buffer,
611                         ElementParserPtr(
612                             new RootParser<WidgetParser>(configInfo,
613                                 DPL::FromUTF32String(
614                                     L"widget"))));
615             } else {
616                 // DRM widget
617                 std::string configFile;
618                 if (pkgType == PKG_TYPE_HYBRID_WEB_APP) {
619                     configFile = tempPath + "/" + WITH_OSP_XML;
620                 } else {
621                     configFile = tempPath + "/" + CONFIG_XML;
622                 }
623
624                 parser.Parse(configFile,
625                         ElementParserPtr(
626                             new RootParser<WidgetParser>(configInfo,
627                                 DPL::FromUTF32String(
628                                     L"widget"))));
629             }
630         }
631     }
632     Catch(DPL::ZipInput::Exception::OpenFailed)
633     {
634         LogError("Failed to open widget package");
635         return ConfigParserData();
636     }
637     Catch(DPL::ZipInput::Exception::OpenFileFailed)
638     {
639         LogError("Failed to open config.xml file");
640         return ConfigParserData();
641     }
642     Catch(DPL::CopyFailed)
643     {
644         LogError("Failed to extract config.xml file");
645         return ConfigParserData();
646     }
647     Catch(DPL::FileInput::Exception::OpenFailed)
648     {
649         LogError("Failed to open config.xml file");
650         return ConfigParserData();
651     }
652     Catch(ElementParser::Exception::ParseError)
653     {
654         LogError("Failed to parse config.xml file");
655         return ConfigParserData();
656     }
657     Catch(DPL::ZipInput::Exception::SeekFileFailed)
658     {
659         LogError("Failed to seek widget archive - corrupted package?");
660         return ConfigParserData();
661     }
662     return configInfo;
663 }
664
665 WidgetUpdateInfo JobWidgetInstall::detectWidgetUpdate(
666         const ConfigParserData &configInfo,
667         const WrtDB::WidgetType appType,
668         const WrtDB::TizenAppId &tizenId)
669 {
670     LogInfo("Checking up widget package for config.xml...");
671
672     DPL::OptionalString widgetGUID;
673     OptionalWidgetVersion widgetVersion;
674
675     // Check widget id
676     widgetGUID = configInfo.widget_id;
677
678     if (widgetGUID.IsNull()) {
679         LogWarning("Installed widget has no GUID");
680         return WidgetUpdateInfo();
681     }
682
683     LogDebug("Installed widget GUID: " << *widgetGUID);
684
685     // Locate widget ID with this GUID
686     // Incoming widget version
687     if (!configInfo.version.IsNull()) {
688         widgetVersion =
689             DPL::Optional<WidgetVersion>(
690                 WidgetVersion(*configInfo.version));
691     }
692
693     if (appType == APP_TYPE_WAC20) {
694         Try
695         {
696             // Search widget handle by GUID
697             WidgetDAOReadOnly dao(widgetGUID);
698             return WidgetUpdateInfo(
699                     widgetGUID,
700                     widgetVersion,
701                     WidgetUpdateInfo::ExistingWidgetInfo(
702                         dao.getTzAppId(), dao.getVersion()));
703         }
704         Catch(WidgetDAOReadOnly::Exception::WidgetNotExist)
705         {
706             // GUID isn't installed
707             return WidgetUpdateInfo(
708                     widgetGUID,
709                     widgetVersion,
710                     WidgetUpdateInfo::ExistingWidgetInfo());
711         }
712     } else {
713         Try
714         {
715             // Search widget handle by appId
716             WidgetDAOReadOnly dao(tizenId);
717             return WidgetUpdateInfo(
718                     widgetGUID,
719                     widgetVersion,
720                     WidgetUpdateInfo::ExistingWidgetInfo(
721                         dao.getTzAppId(), dao.getVersion()));
722         }
723         Catch(WidgetDAOReadOnly::Exception::WidgetNotExist)
724         {
725             // GUID isn't installed
726             return WidgetUpdateInfo(
727                     widgetGUID,
728                     widgetVersion,
729                     WidgetUpdateInfo::ExistingWidgetInfo());
730         }
731
732     }
733 }
734
735 void JobWidgetInstall::SendProgress()
736 {
737     using namespace PackageManager;
738     if (GetProgressFlag() != false) {
739         if (getInstallerStruct().progressCallback != NULL) {
740             // send progress signal of pkgmgr
741             std::ostringstream percent;
742             percent << static_cast<int>(GetProgressPercent());
743             getInstallerStruct().pkgmgrInterface->sendSignal(
744                         PKGMGR_PROGRESS_KEY,
745                         percent.str());
746
747             LogDebug("Call widget install progressCallbak");
748             getInstallerStruct().progressCallback(getInstallerStruct().userParam,
749                     GetProgressPercent(),GetProgressDescription());
750         }
751     }
752 }
753
754 void JobWidgetInstall::SendFinishedSuccess()
755 {
756     using namespace PackageManager;
757     // TODO : sync should move to separate task.
758     sync();
759
760
761     if (INSTALL_LOCATION_TYPE_EXTERNAL == m_installerContext.locationType) {
762         if (false == m_installerContext.existingWidgetInfo.isExist) {
763             WidgetInstallToExtSingleton::Instance().postInstallation(true);
764         } else {
765             WidgetInstallToExtSingleton::Instance().postUpgrade(true);
766         }
767         WidgetInstallToExtSingleton::Instance().deinitialize();
768     }
769
770     // remove widget install information file
771     unlink(m_installerContext.installInfo.c_str());
772
773     //inform widget info
774     JobWidgetInstall::displayWidgetInfo();
775
776     TizenAppId& tizenId = m_installerContext.widgetConfig.tzAppid;
777
778     // send signal of pkgmgr
779     getInstallerStruct().pkgmgrInterface->sendSignal(
780                 PKGMGR_END_KEY,
781                 PKGMGR_END_SUCCESS);
782
783     LogDebug("Call widget install successfinishedCallback");
784     getInstallerStruct().finishedCallback(getInstallerStruct().userParam,
785             DPL::ToUTF8String(tizenId), Exceptions::Success);
786 }
787
788 void JobWidgetInstall::SendFinishedFailure()
789 {
790     using namespace PackageManager;
791     // remove widget install information file
792     unlink(m_installerContext.installInfo.c_str());
793
794     LogError("Error in installation step: " << m_exceptionCaught);
795     LogError("Message: " << m_exceptionMessage);
796     TizenAppId & tizenId = m_installerContext.widgetConfig.tzAppid;
797
798     LogDebug("Call widget install failure finishedCallback");
799
800     // send signal of pkgmgr
801     getInstallerStruct().pkgmgrInterface->sendSignal(
802                 PKGMGR_END_KEY,
803                 PKGMGR_END_FAILURE);
804
805     getInstallerStruct().finishedCallback(getInstallerStruct().userParam,
806             DPL::ToUTF8String(tizenId), m_exceptionCaught);
807 }
808
809 void JobWidgetInstall::SaveExceptionData(const Jobs::JobExceptionBase &e)
810 {
811     m_exceptionCaught = static_cast<Exceptions::Type>(e.getParam());
812     m_exceptionMessage = e.GetMessage();
813 }
814
815 void JobWidgetInstall::displayWidgetInfo()
816 {
817     WidgetDAOReadOnly dao(m_installerContext.widgetConfig.tzAppid);
818
819     std::ostringstream out;
820     WidgetLocalizedInfo localizedInfo =
821         W3CFileLocalization::getLocalizedInfo(dao.getTzAppId());
822
823     out << std::endl <<
824         "===================================== INSTALLED WIDGET INFO ========="\
825         "============================";
826     out << std::endl << "Name:                        " << localizedInfo.name;
827     out << std::endl << "AppId:                     " << dao.getTzAppId();
828     WidgetSize size = dao.getPreferredSize();
829     out << std::endl << "Width:                       " << size.width;
830     out << std::endl << "Height:                      " << size.height;
831     out << std::endl << "Start File:                  " <<
832         W3CFileLocalization::getStartFile(dao.getTzAppId());
833     out << std::endl << "Version:                     " << dao.getVersion();
834     out << std::endl << "Licence:                     " <<
835         localizedInfo.license;
836     out << std::endl << "Licence Href:                " <<
837         localizedInfo.licenseHref;
838     out << std::endl << "Description:                 " <<
839         localizedInfo.description;
840     out << std::endl << "Widget Id:                   " << dao.getGUID();
841     out << std::endl << "Widget recognized:           " << dao.isRecognized();
842     out << std::endl << "Widget wac signed:           " << dao.isWacSigned();
843     out << std::endl << "Widget distributor signed:   " <<
844         dao.isDistributorSigned();
845     out << std::endl << "Widget trusted:              " << dao.isTrusted();
846
847     OptionalWidgetIcon icon = W3CFileLocalization::getIcon(dao.getTzAppId());
848     DPL::OptionalString iconSrc = !!icon ? icon->src : DPL::OptionalString::Null;
849     out << std::endl << "Icon:                        " << iconSrc;
850
851     out << std::endl << "Preferences:";
852     {
853         PropertyDAOReadOnly::WidgetPreferenceList list = dao.getPropertyList();
854         FOREACH(it, list)
855         {
856             out << std::endl << "  Key:                       " <<
857                 it->key_name;
858             out << std::endl << "      Readonly:              " <<
859                 it->readonly;
860         }
861     }
862
863     out << std::endl << "Features:";
864     {
865         WidgetFeatureSet list = dao.getFeaturesList();
866         FOREACH(it, list)
867         {
868             out << std::endl << "  Name:                      " << it->name;
869             out << std::endl << "      Required:              " << it->required;
870             out << std::endl << "      Params:";
871         }
872     }
873
874     out << std::endl;
875
876     LogInfo(out.str());
877 }
878
879 WrtDB::PackagingType JobWidgetInstall::checkPackageType(
880         const std::string &widgetSource,
881         const std::string &tempPath)
882 {
883     // Check installation type (direcotory/ or config.xml or widget.wgt)
884     if (WidgetUpdateMode::PolicyDirectoryForceInstall == m_jobStruct.updateMode)
885     {
886         LogDebug("Install directly from directory");
887         return PKG_TYPE_DIRECTORY_WEB_APP;
888     }
889     if (hasExtension(widgetSource, XML_EXTENSION)) {
890         LogInfo("Hosted app installation");
891         return PKG_TYPE_HOSTED_WEB_APP;
892     }
893
894     if (m_isDRM) {
895         std::string configFile = tempPath + "/" + CONFIG_XML;
896         if (WrtUtilFileExists(configFile)) {
897             return PKG_TYPE_NOMAL_WEB_APP;
898         }
899
900         configFile = tempPath + "/" + WITH_OSP_XML;
901         if (WrtUtilFileExists(configFile)) {
902             return PKG_TYPE_HYBRID_WEB_APP;
903         }
904     } else {
905         std::unique_ptr<DPL::ZipInput> zipFile;
906
907         Try
908         {
909             // Open zip file
910             zipFile.reset(new DPL::ZipInput(widgetSource));
911
912         }
913         Catch(DPL::ZipInput::Exception::OpenFailed)
914         {
915             LogDebug("Failed to open widget package");
916             return PKG_TYPE_UNKNOWN;
917         }
918         Catch(DPL::ZipInput::Exception::SeekFileFailed)
919         {
920             LogError("Failed to seek widget package file");
921             return PKG_TYPE_UNKNOWN;
922         }
923
924         Try
925         {
926             // Open config.xml file in package root
927             std::unique_ptr<DPL::ZipInput::File> configFile(
928                     zipFile->OpenFile(CONFIG_XML));
929             return PKG_TYPE_NOMAL_WEB_APP;
930         }
931         Catch(DPL::ZipInput::Exception::OpenFileFailed)
932         {
933             LogDebug("Could not find config.xml");
934         }
935
936         Try
937         {
938             // Open config.xml file in package root
939             std::unique_ptr<DPL::ZipInput::File> configFile(
940                     zipFile->OpenFile(WITH_OSP_XML));
941
942             return PKG_TYPE_HYBRID_WEB_APP;
943         }
944         Catch(DPL::ZipInput::Exception::OpenFileFailed)
945         {
946             LogDebug("Could not find wgt/config.xml");
947             return PKG_TYPE_UNKNOWN;
948         }
949     }
950
951     return PKG_TYPE_UNKNOWN;
952 }
953
954 void JobWidgetInstall::setApplicationType(
955         const WrtDB::ConfigParserData &configInfo)
956 {
957
958     FOREACH(iterator, configInfo.nameSpaces) {
959         LogInfo("namespace = [" << *iterator << "]");
960         AppType currentAppType = APP_TYPE_UNKNOWN;
961
962         if (*iterator == ConfigurationNamespace::W3CWidgetNamespaceName) {
963             continue;
964         } else if (
965             *iterator ==
966             ConfigurationNamespace::WacWidgetNamespaceNameForLinkElement ||
967             *iterator ==
968             ConfigurationNamespace::WacWidgetNamespaceName)
969         {
970             currentAppType = APP_TYPE_WAC20;
971         } else if (*iterator ==
972                 ConfigurationNamespace::TizenWebAppNamespaceName) {
973             currentAppType = APP_TYPE_TIZENWEBAPP;
974         }
975
976         if (m_installerContext.widgetConfig.webAppType ==
977                 APP_TYPE_UNKNOWN) {
978             m_installerContext.widgetConfig.webAppType = currentAppType;
979         } else if (m_installerContext.widgetConfig.webAppType ==
980                 currentAppType) {
981             continue;
982         } else {
983             ThrowMsg(Exceptions::WidgetConfigFileInvalid,
984                      "Config.xml has more than one namespace");
985         }
986     }
987
988     // If there is no define, type set to WAC 2.0
989     if (m_installerContext.widgetConfig.webAppType == APP_TYPE_UNKNOWN) {
990         m_installerContext.widgetConfig.webAppType = APP_TYPE_WAC20;
991     }
992
993     LogInfo("type = [" <<
994             m_installerContext.widgetConfig.webAppType.getApptypeToString() << "]");
995 }
996
997 bool JobWidgetInstall::detectResourceEncryption(const WrtDB::ConfigParserData &configData)
998 {
999     FOREACH(it, configData.settingsList)
1000     {
1001         if (it->m_name == SETTING_VALUE_ENCRYPTION &&
1002                 it->m_value == SETTING_VALUE_ENCRYPTION_ENABLE) {
1003             LogDebug("resource need encryption");
1004             return true;
1005         }
1006     }
1007     return false;
1008 }
1009
1010 void JobWidgetInstall::setInstallLocationType(const
1011         WrtDB::ConfigParserData &configData)
1012 {
1013     m_installerContext.locationType = INSTALL_LOCATION_TYPE_NOMAL;
1014
1015     if (true == m_jobStruct.m_preload) {
1016         m_installerContext.locationType =
1017             INSTALL_LOCATION_TYPE_PRELOAD;
1018     } else {
1019         FOREACH(it, configData.settingsList)
1020         {
1021             if (it->m_name == SETTING_VALUE_INSTALLTOEXT_NAME &&
1022                     it->m_value ==
1023                     SETTING_VALUE_INSTALLTOEXT_PREPER_EXT) {
1024                 LogDebug("This widget will be installed to sd card");
1025                 m_installerContext.locationType =
1026                     INSTALL_LOCATION_TYPE_EXTERNAL;
1027             }
1028         }
1029     }
1030 }
1031
1032 bool JobWidgetInstall::isDRMWidget(std::string widgetPath)
1033 {
1034     /* TODO :
1035     drm_bool_type_e is_drm_file = DRM_UNKNOWN;
1036     int ret = -1;
1037
1038     ret = drm_is_drm_file(widgetPath.c_str(), &is_drm_file);
1039     if(DRM_RETURN_SUCCESS == ret && DRM_TRUE == is_drm_file) {
1040     */
1041
1042     /* blow code temporary code for drm. */
1043     int ret = drm_oem_intel_isDrmFile(const_cast<char*>(widgetPath.c_str()));
1044     if ( 1 == ret) {
1045         return true;
1046     } else {
1047         return false;
1048     }
1049 }
1050
1051 bool JobWidgetInstall::DecryptDRMWidget(std::string widgetPath,
1052         std::string destPath)
1053 {
1054     /* TODO :
1055     drm_trusted_sapps_decrypt_package_info_s package_info;
1056
1057     strncpy(package_info.sadcf_filepath, widgetPath.c_str(),
1058             sizeof(package_info.sadcf_filepath));
1059     strncpy(package_info.decrypt_filepath, destPath.c_str(),
1060             sizeof(package_info.decrypt_filepath));
1061
1062     drm_trusted_request_type_e requestType =
1063         DRM_TRUSTED_REQ_TYPE_SAPPS_DECRYPT_PACKAGE;
1064
1065     int ret = drm_trusted_handle_request(requestType,
1066                                          (void *)&package_info, NULL);
1067     if (DRM_TRUSTED_RETURN_SUCCESS == ret) {
1068         return true;
1069     } else {
1070         return false;
1071     }
1072     */
1073     if (drm_oem_intel_decrypt_package(const_cast<char*>(widgetPath.c_str()),
1074                 const_cast<char*>(destPath.c_str())) != 0) {
1075         return true;
1076     } else {
1077         return false;
1078     }
1079 }
1080
1081 } //namespace WidgetInstall
1082 } //namespace Jobs