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