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