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