[Release]wrt-installer_0.1.6
[framework/web/wrt-installer.git] / src / jobs / widget_install / task_widget_config.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    task_widget_config.cpp
18  * @author  Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
19  * @version 1.0
20  * @brief   Implementation file for installer task widget config
21  */
22
23 #include <sstream>
24 #include <string>
25 #include <sys/stat.h>
26 #include <dirent.h>
27
28 #include <dpl/errno_string.h>
29 #include <dpl/foreach.h>
30 #include <dpl/localization/w3c_file_localization.h>
31 #include <dpl/singleton_impl.h>
32 #include <dpl/utils/mime_type_utils.h>
33 #include <dpl/utils/wrt_global_settings.h>
34 #include <dpl/utils/wrt_utility.h>
35 #include <dpl/wrt-dao-ro/global_config.h>
36 #include <dpl/wrt-dao-rw/feature_dao.h>
37
38 #include <libiriwrapper.h>
39 #include <parser_runner.h>
40 #include <root_parser.h>
41
42 #include <widget_install/job_widget_install.h>
43 #include <widget_install/task_widget_config.h>
44 #include <widget_install/widget_install_context.h>
45 #include <widget_install/widget_install_errors.h>
46 #include <widget_parser.h>
47 #include <wrt_error.h>
48
49 namespace { // anonymous
50 const DPL::String BR = DPL::FromUTF8String("<br>");
51 const std::string WIDGET_NOT_COMPATIBLE = "This widget is "
52                                           "not compatible with WRT.<br><br>";
53 const std::string QUESTION = "Do you want to install it anyway?";
54
55 const char *const DEFAULT_LANGUAGE = "default";
56
57 const char *const WRT_WIDGET_CONFIG_FILE_NAME = "config.xml";
58
59 const std::string WINDGET_INSTALL_NETWORK_ACCESS = "network access";
60 }
61
62 namespace Jobs {
63 namespace WidgetInstall {
64 void InstallerTaskWidgetPopupData::PopupData::addWidgetInfo(
65     const DPL::String &info)
66 {
67     widgetInfo = info;
68 }
69
70 TaskWidgetConfig::TaskWidgetConfig(InstallerContext& installContext) :
71     DPL::TaskDecl<TaskWidgetConfig>(this),
72     WidgetInstallPopup(installContext),
73     m_installContext(installContext)
74 {
75     AddStep(&TaskWidgetConfig::StepProcessConfigurationFile);
76     AddStep(&TaskWidgetConfig::ReadLocaleFolders);
77     AddStep(&TaskWidgetConfig::ProcessLocalizedStartFiles);
78     AddStep(&TaskWidgetConfig::ProcessBackgroundPageFile);
79     AddStep(&TaskWidgetConfig::ProcessLocalizedIcons);
80     AddStep(&TaskWidgetConfig::ProcessWidgetInstalledPath);
81     AddStep(&TaskWidgetConfig::StepVerifyFeatures);
82     AddStep(&TaskWidgetConfig::StepCheckMinVersionInfo);
83
84     if (!GlobalSettings::TestModeEnabled() && !m_installContext.m_quiet) {
85         AddStep(
86             &TaskWidgetConfig::
87                 StepCancelWidgetInstallationAfterVerifyFeatures);
88         AddStep(&TaskWidgetConfig::StepShowWidgetInfo);
89         AddStep(&TaskWidgetConfig::StepCancelWidgetInstallation);
90         AddStep(&TaskWidgetConfig::StepCancelWidgetInstallationAfterMinVersion);
91         AddStep(&TaskWidgetConfig::StepDeletePopupWin);
92     }
93 }
94
95 void TaskWidgetConfig::StepProcessConfigurationFile()
96 {
97     Try
98     {
99         std::string path = m_installContext.locations->getConfigurationDir();
100         LogInfo("path: " << path);
101
102         processFile(path, m_installContext.widgetConfig);
103     }
104     Catch(Exception::ConfigParseFailed)
105     {
106         LogError("Parsing failed.");
107         ReThrow(Exceptions::WidgetConfigFileInvalid);
108     }
109
110     m_installContext.job->UpdateProgress(
111         InstallerContext::INSTALL_WIDGET_CONFIG1,
112         "Parse elements of configuration file and save them");
113 }
114
115 void TaskWidgetConfig::ReadLocaleFolders()
116 {
117     LogDebug("Reading locale");
118     //Adding default locale
119     m_localeFolders.insert(L"");
120
121     std::string localePath =
122         m_installContext.locations->getConfigurationDir() + "/locales";
123     DIR* localeDir = opendir(localePath.c_str());
124     if (!localeDir) {
125         LogDebug("No /locales directory in the widget package.");
126         return;
127     }
128
129     struct dirent* dirent;
130     struct stat statStruct;
131     do {
132         errno = 0;
133         if ((dirent = readdir(localeDir))) {
134             DPL::String dirName = DPL::FromUTF8String(dirent->d_name);
135             std::string absoluteDirName = localePath + "/";
136             absoluteDirName += dirent->d_name;
137
138             if (stat(absoluteDirName.c_str(), &statStruct) != 0) {
139                 LogError("stat() failed with " << DPL::GetErrnoString());
140                 continue;
141             }
142
143             if (S_ISDIR(statStruct.st_mode)) {
144                 //Yes, we ignore current, parent & hidden directories
145                 if (dirName[0] != L'.') {
146                     LogDebug("Adding locale directory \"" << dirName << "\"");
147                     m_localeFolders.insert(dirName);
148                 }
149             }
150         }
151     } while (dirent);
152
153     if (errno != 0) {
154         LogError("readdir() failed with " << DPL::GetErrnoString());
155     }
156
157     if (-1 == TEMP_FAILURE_RETRY(closedir(localeDir))) {
158         LogError("Failed to close dir: " << localePath << " with error: "
159                                          << DPL::GetErrnoString());
160     }
161 }
162
163 void TaskWidgetConfig::ProcessLocalizedStartFiles()
164 {
165     typedef DPL::String S;
166     ProcessStartFile(
167         m_installContext.widgetConfig.configInfo.startFile,
168         m_installContext.widgetConfig.configInfo.
169             startFileContentType,
170         m_installContext.widgetConfig.configInfo.startFileEncoding,
171         true);
172     ProcessStartFile(S(L"index.htm"), S(L"text/html"));
173     ProcessStartFile(S(L"index.html"), S(L"text/html"));
174     ProcessStartFile(S(L"index.svg"), S(L"image/svg+xml"));
175     ProcessStartFile(S(L"index.xhtml"), S(L"application/xhtml+xml"));
176     ProcessStartFile(S(L"index.xht"), S(L"application/xhtml+xml"));
177     // TODO: (l.wrzosek) we need better check if in current locales widget is
178     // valid.
179     FOREACH(it, m_installContext.widgetConfig.localizationData.startFiles) {
180         if (it->propertiesForLocales.size() > 0) {
181             return;
182         }
183     }
184     ThrowMsg(Exceptions::WidgetConfigFileInvalid,
185              L"The Widget has no valid start file");
186 }
187
188 void TaskWidgetConfig::ProcessStartFile(const DPL::OptionalString& path,
189                                         const DPL::OptionalString& type,
190                                         const DPL::OptionalString& encoding,
191                                         bool typeForcedInConfig)
192 {
193     using namespace WrtDB;
194
195     if (!!path) {
196         WidgetRegisterInfo::LocalizedStartFile startFileData;
197         startFileData.path = *path;
198
199         FOREACH(i, m_localeFolders) {
200             DPL::String pathPrefix = *i;
201             if (!pathPrefix.empty()) {
202                 pathPrefix = L"locales/" + pathPrefix + L"/";
203             }
204
205             DPL::String relativePath = pathPrefix + *path;
206             DPL::String absolutePath = DPL::FromUTF8String(
207                     m_installContext.locations->getConfigurationDir()) + L"/" +
208                 relativePath;
209
210             // get property data from packaged app
211             if (WrtUtilFileExists(DPL::ToUTF8String(absolutePath))) {
212                 WidgetRegisterInfo::StartFileProperties startFileProperties;
213                 if (!!type) {
214                     startFileProperties.type = *type;
215                 } else {
216                     startFileProperties.type =
217                         MimeTypeUtils::identifyFileMimeType(absolutePath);
218                 }
219
220                 //proceed only if MIME type is supported
221                 if (MimeTypeUtils::isMimeTypeSupportedForStartFile(
222                         startFileProperties.type))
223                 {
224                     if (!!encoding) {
225                         startFileProperties.encoding = *encoding;
226                     } else {
227                         MimeTypeUtils::MimeAttributes attributes =
228                             MimeTypeUtils::getMimeAttributes(
229                                 startFileProperties.type);
230                         if (attributes.count(L"charset") > 0) {
231                             startFileProperties.encoding =
232                                 attributes[L"charset"];
233                         } else {
234                             startFileProperties.encoding = L"UTF-8";
235                         }
236                     }
237
238                     startFileData.propertiesForLocales[*i] =
239                         startFileProperties;
240                 } else {
241                     //9.1.16.5.content.8
242                     //(there seems to be no similar requirement in .6,
243                     //so let's throw only when mime type is
244                     // provided explcitly in config.xml)
245                     if (typeForcedInConfig) {
246                         ThrowMsg(Exceptions::WidgetConfigFileInvalid,
247                                  "Unsupported MIME type for start file.");
248                     }
249                 }
250             } else {
251                 // set property data for hosted start url
252                 // Hosted start url only support TIZEN WebApp
253                 if (m_installContext.widgetConfig.webAppType ==
254                     APP_TYPE_TIZENWEBAPP)
255                 {
256                     std::string startPath = DPL::ToUTF8String(
257                             startFileData.path);
258
259                     if (strstr(startPath.c_str(),
260                                "http") == startPath.c_str())
261                     {
262                         WidgetRegisterInfo::StartFileProperties
263                             startFileProperties;
264                         if (!!type) {
265                             startFileProperties.type = *type;
266                         }
267                         if (!!encoding) {
268                             startFileProperties.encoding = *encoding;
269                         }
270                         startFileData.propertiesForLocales[*i] =
271                             startFileProperties;
272                     }
273                 }
274             }
275         }
276
277         m_installContext.widgetConfig.localizationData.startFiles.push_back(
278             startFileData);
279     }
280 }
281
282 void TaskWidgetConfig::ProcessBackgroundPageFile()
283 {
284     if (!!m_installContext.widgetConfig.configInfo.backgroundPage) {
285         // check whether file exists
286         DPL::String backgroundPagePath = DPL::FromUTF8String(
287                 m_installContext.locations->getConfigurationDir()) + L"/" +
288             *m_installContext.widgetConfig.configInfo.backgroundPage;
289         //if no then cancel installation
290         if (!WrtUtilFileExists(DPL::ToUTF8String(backgroundPagePath))) {
291             ThrowMsg(Exceptions::WidgetConfigFileInvalid,
292                      L"Given background page file not found in archive");
293         }
294     }
295 }
296
297 void TaskWidgetConfig::ProcessLocalizedIcons()
298 {
299     using namespace WrtDB;
300     ProcessIcon(ConfigParserData::Icon(L"icon.svg"));
301     ProcessIcon(ConfigParserData::Icon(L"icon.ico"));
302     ProcessIcon(ConfigParserData::Icon(L"icon.png"));
303     ProcessIcon(ConfigParserData::Icon(L"icon.gif"));
304     ProcessIcon(ConfigParserData::Icon(L"icon.jpg"));
305
306     FOREACH(i, m_installContext.widgetConfig.configInfo.iconsList)
307     {
308         ProcessIcon(*i);
309     }
310 }
311
312 void TaskWidgetConfig::ProcessIcon(const WrtDB::ConfigParserData::Icon& icon)
313 {
314     LogInfo("enter");
315     bool isAnyIconValid = false;
316     //In case a default filename is passed as custom filename in config.xml, we
317     //need to keep a set of already processed filenames to avoid icon
318     // duplication
319     //in database.
320
321     using namespace WrtDB;
322
323     if (m_processedIconSet.count(icon.src) > 0) {
324         return;
325     }
326     m_processedIconSet.insert(icon.src);
327
328     LocaleSet localesAvailableForIcon;
329
330     FOREACH(i, m_localeFolders)
331     {
332         DPL::String pathPrefix = *i;
333         if (!pathPrefix.empty()) {
334             pathPrefix = L"locales/" + pathPrefix + L"/";
335         }
336
337         DPL::String relativePath = pathPrefix + icon.src;
338         DPL::String absolutePath = DPL::FromUTF8String(
339                 m_installContext.locations->getConfigurationDir()) + L"/" +
340             relativePath;
341
342         if (WrtUtilFileExists(DPL::ToUTF8String(absolutePath))) {
343             DPL::String type = MimeTypeUtils::identifyFileMimeType(absolutePath);
344
345             if (MimeTypeUtils::isMimeTypeSupportedForIcon(type)) {
346                 isAnyIconValid = true;
347                 localesAvailableForIcon.insert(*i);
348                 LogInfo("Icon absolutePath :" << absolutePath <<
349                         ", assigned locale :" << *i << ", type: " << type);
350             }
351         }
352     }
353
354     if (isAnyIconValid) {
355         WidgetRegisterInfo::LocalizedIcon localizedIcon(icon,
356                                                         localesAvailableForIcon);
357         m_installContext.widgetConfig.localizationData.icons.push_back(
358             localizedIcon);
359     }
360 }
361
362 void TaskWidgetConfig::ProcessWidgetInstalledPath()
363 {
364     LogDebug("ProcessWidgetInstalledPath");
365     m_installContext.widgetConfig.widgetInstalledPath =
366         DPL::FromUTF8String(
367             m_installContext.locations->getPackageInstallationDir());
368 }
369
370 void TaskWidgetConfig::StepCancelWidgetInstallationAfterVerifyFeatures()
371 {
372     LogDebug("StepCancelWidgetInstallationAfterVerifyFeatures");
373     if (InfoPopupButton::WRT_POPUP_BUTTON_CANCEL == m_installCancel) {
374         m_installCancel = WRT_POPUP_BUTTON;
375         destroyPopup();
376         ThrowMsg(Exceptions::WidgetConfigFileInvalid, "Widget not allowed");
377     }
378 }
379
380 void TaskWidgetConfig::StepCancelWidgetInstallation()
381 {
382     if (InfoPopupButton::WRT_POPUP_BUTTON_CANCEL == m_installCancel) {
383         m_installCancel = WRT_POPUP_BUTTON;
384         destroyPopup();
385         ThrowMsg(Exceptions::NotAllowed, "Widget not allowed");
386     }
387 }
388
389 void TaskWidgetConfig::StepCancelWidgetInstallationAfterMinVersion()
390 {
391     if (InfoPopupButton::WRT_POPUP_BUTTON_CANCEL == m_installCancel) {
392         m_installCancel = WRT_POPUP_BUTTON;
393         destroyPopup();
394         ThrowMsg(Exceptions::NotAllowed, "WRT version incompatible.");
395     }
396 }
397
398 void TaskWidgetConfig::createInstallPopup(PopupType type,
399                                           const std::string &label)
400 {
401     m_installContext.job->Pause();
402     if (m_popup) {
403         destroyPopup();
404     }
405
406     bool ret = createPopup();
407     if (ret) {
408         loadPopup(type, label);
409         showPopup();
410     }
411 }
412
413 void TaskWidgetConfig::StepDeletePopupWin()
414 {
415     destroyPopup();
416 }
417
418 void TaskWidgetConfig::StepShowWidgetInfo()
419 {
420     if (!m_popupData.widgetInfo.empty()) {
421         std::string label = DPL::ToUTF8String(m_popupData.widgetInfo);
422         createInstallPopup(PopupType::WIDGET_FEATURE_INFO, label);
423         m_installContext.job->UpdateProgress(
424             InstallerContext::INSTALL_WIDGET_CONFIG2,
425             "Show Widget Info Finished");
426     }
427 }
428
429 void TaskWidgetConfig::StepCheckMinVersionInfo()
430 {
431     if (!isMinVersionCompatible(
432             m_installContext.widgetConfig.webAppType.appType,
433             m_installContext.widgetConfig.minVersion))
434     {
435         if (!GlobalSettings::TestModeEnabled() && !m_installContext.m_quiet) {
436             LogDebug("Platform version to low - launching");
437             std::string label = WIDGET_NOT_COMPATIBLE + QUESTION;
438             createInstallPopup(PopupType::WIDGET_MIN_VERSION, label);
439         } else {
440             LogError(
441                 "Platform version lower than required -> cancelling installation");
442             ThrowMsg(Exceptions::NotAllowed,
443                      "Platform version does not meet requirements");
444         }
445     }
446
447     m_installContext.job->UpdateProgress(
448         InstallerContext::INSTALL_WIDGET_CONFIG2,
449         "Check MinVersion Finished");
450 }
451
452 void TaskWidgetConfig::StepVerifyFeatures()
453 {
454     using namespace WrtDB;
455     ConfigParserData &data = m_installContext.widgetConfig.configInfo;
456     ConfigParserData::FeaturesList list = data.featuresList;
457     ConfigParserData::FeaturesList newList;
458
459     //in case of tests, this variable is unused
460     std::string featureInfo;
461     FOREACH(it, list)
462     {
463         // check feature vender for permission
464         // WAC, TIZEN WebApp cannot use other feature
465
466         if (!isFeatureAllowed(m_installContext.widgetConfig.webAppType.appType,
467                               it->name))
468         {
469             LogInfo("This application type not allowed to use this feature");
470             ThrowMsg(
471                 Exceptions::WidgetConfigFileInvalid,
472                 "This app type [" <<
473                 m_installContext.widgetConfig.webAppType.getApptypeToString()
474                                   <<
475                 "] cannot be allowed to use [" <<
476                 DPL::ToUTF8String(it->name) + "] feature");
477         }
478         if (!WrtDB::FeatureDAOReadOnly::isFeatureInstalled(
479                 DPL::ToUTF8String(it->name)))
480         {
481             LogWarning("Feature not found. Checking if required :[" <<
482                        DPL::ToUTF8String(it->name) << "]");
483
484             if (it->required) {
485                 /**
486                  * WL-3210 The WRT MUST inform the user if a widget cannot be
487                  * installed because one or more required features are not
488                  * supported.
489                  */
490                 std::ostringstream os;
491                 os <<
492                 "Widget cannot be installed, required feature is missing:["
493                    << DPL::ToUTF8String(it->name) << "]";
494                 if (!GlobalSettings::TestModeEnabled() && !isTizenWebApp()) {
495                     std::string label = os.str();
496                     createInstallPopup(PopupType::WIDGET_WRONG_FEATURE_INFO,
497                                        label);
498                 }
499                 ThrowMsg(Exceptions::WidgetConfigFileInvalid, os.str());
500             }
501         } else {
502             newList.insert(*it);
503             featureInfo += DPL::ToUTF8String(it->name);
504             featureInfo += DPL::ToUTF8String(BR);
505         }
506     }
507     if (!data.accessInfoSet.empty()) {
508         featureInfo += WINDGET_INSTALL_NETWORK_ACCESS;
509         featureInfo += DPL::ToUTF8String(BR);
510     }
511     data.featuresList = newList;
512     if (!featureInfo.empty()) {
513         m_popupData.addWidgetInfo(DPL::FromUTF8String(featureInfo));
514     }
515
516     m_installContext.job->UpdateProgress(
517         InstallerContext::INSTALL_WIDGET_CONFIG2,
518         "Widget Config step2 Finished");
519 }
520
521 bool TaskWidgetConfig::isFeatureAllowed(WrtDB::AppType appType,
522                                         DPL::String featureName)
523 {
524     using namespace WrtDB;
525     LogInfo("AppType = [" <<
526             WidgetType(appType).getApptypeToString() << "]");
527     LogInfo("FetureName = [" << featureName << "]");
528
529     AppType featureType = APP_TYPE_UNKNOWN;
530     std::string featureStr = DPL::ToUTF8String(featureName);
531     const char* feature = featureStr.c_str();
532
533     // check prefix of  feature name
534     if (strstr(feature, PluginsPrefix::TIZENPluginsPrefix) == feature) {
535         // Tizen WebApp feature
536         featureType = APP_TYPE_TIZENWEBAPP;
537     } else if (strstr(feature, PluginsPrefix::WACPluginsPrefix) == feature) {
538         // WAC 2.0 feature
539         featureType = APP_TYPE_WAC20;
540     } else if (strstr(feature, PluginsPrefix::W3CPluginsPrefix) == feature) {
541         // W3C standard feature
542         // Both WAC and TIZEN WebApp are possible to use W3C plugins
543         return true;
544     } else {
545         // unknown feature
546         // unknown feature will be checked next step
547         return true;
548     }
549
550     if (appType == featureType) {
551         return true;
552     }
553     return false;
554 }
555
556 bool TaskWidgetConfig::parseVersionString(const std::string &version,
557                                           long &majorVersion,
558                                           long &minorVersion,
559                                           long &microVersion) const
560 {
561     std::istringstream inputString(version);
562     inputString >> majorVersion;
563     if (inputString.bad() || inputString.fail()) {
564         LogWarning("Invalid minVersion format.");
565         return false;
566     }
567     inputString.get(); // skip period
568     inputString >> minorVersion;
569     if (inputString.bad() || inputString.fail()) {
570         LogWarning("Invalid minVersion format");
571         return false;
572     } else {
573         inputString.get(); // skip period
574         if (inputString.bad() || inputString.fail()) {
575             inputString >> microVersion;
576         }
577     }
578     return true;
579 }
580
581 bool TaskWidgetConfig::isMinVersionCompatible(
582     WrtDB::AppType appType,
583     const DPL::OptionalString &
584     widgetVersion) const
585 {
586     if (widgetVersion.IsNull() || (*widgetVersion).empty()) {
587         LogWarning("minVersion attribute is empty. WRT assumes platform "
588                    "supports this widget.");
589         return false;
590     }
591
592     //Parse widget version
593     long majorWidget = 0, minorWidget = 0, microWidget = 0;
594     if (!parseVersionString(DPL::ToUTF8String(*widgetVersion), majorWidget,
595                             minorWidget, microWidget))
596     {
597         LogWarning("Invalid format of widget version string.");
598         return false;
599     }
600
601     //Parse supported version
602     long majorSupported = 0, minorSupported = 0, microSupported = 0;
603     std::string version;
604     if (appType == WrtDB::AppType::APP_TYPE_TIZENWEBAPP) {
605         version = WrtDB::GlobalConfig::GetTizenVersion();
606     } else if (appType == WrtDB::AppType::APP_TYPE_WAC20) {
607         version = WrtDB::GlobalConfig::GetWACVersion();
608     } else {
609         LogWarning("Invaild AppType");
610         return false;
611     }
612
613     if (!parseVersionString(version,
614                             majorSupported, minorSupported, microSupported))
615     {
616         LogWarning("Invalid format of platform version string.");
617         return true;
618     }
619
620     if (majorWidget > majorSupported ||
621         (majorWidget == majorSupported && minorWidget > minorSupported) ||
622         (majorWidget == majorSupported && minorWidget == minorSupported
623          && microWidget > microSupported))
624     {
625         LogInfo("Platform doesn't support this widget.");
626         return false;
627     }
628     return true;
629 }
630
631 bool TaskWidgetConfig::isTizenWebApp() const
632 {
633     bool ret = FALSE;
634     if (m_installContext.widgetConfig.webAppType.appType
635         == WrtDB::AppType::APP_TYPE_TIZENWEBAPP)
636     {
637         ret = TRUE;
638     }
639
640     return ret;
641 }
642
643 bool TaskWidgetConfig::parseConfigurationFileBrowser(
644     WrtDB::ConfigParserData& configInfo,
645     const std::string&
646     _currentPath,
647     int* pErrCode)
648 {
649     ParserRunner parser;
650     Try
651     {
652         parser.Parse(_currentPath, ElementParserPtr(new
653                                                     RootParser<
654                                                         WidgetParser>(
655                                                         configInfo,
656                                                         DPL::FromUTF32String(
657                                                             L"widget"))));
658     }
659     Catch(ElementParser::Exception::Base)
660     {
661         LogError("Invalid widget configuration file!");
662         *pErrCode = WRT_WM_ERR_INVALID_ARCHIVE;
663         return false;
664     }
665     return true;
666 }
667
668 bool TaskWidgetConfig::parseConfigurationFileWidget(
669     WrtDB::ConfigParserData& configInfo,
670     const std::string&
671     _currentPath,
672     int* pErrCode)
673 {
674     ParserRunner parser;
675
676     //TODO: rewrite this madness
677     std::string cfgAbsPath;
678     DIR* dir = NULL;
679     struct dirent* ptr = NULL;
680
681     dir = opendir(_currentPath.c_str());
682     if (dir == NULL) {
683         *pErrCode = WRT_ERR_UNKNOWN;
684         return false;
685     }
686     bool has_config_xml = false;
687     errno = 0;
688     while ((ptr = readdir(dir)) != NULL) { //Find configuration file, based on
689                                            // its name
690         if (ptr->d_type == DT_REG) {
691             if (!strcmp(ptr->d_name, WRT_WIDGET_CONFIG_FILE_NAME)) {
692                 std::string dName(ptr->d_name);
693                 WrtUtilJoinPaths(cfgAbsPath, _currentPath, dName);
694
695                 //Parse widget configuration file
696                 LogDebug("Found config: " << cfgAbsPath);
697
698                 Try
699                 {
700                     parser.Parse(cfgAbsPath, ElementParserPtr(new
701                                                               RootParser<
702                                                                   WidgetParser>(
703                                                                   configInfo,
704                                                                   DPL
705                                                                       ::
706                                                                       FromUTF32String(
707                                                                       L"widget"))));
708                 }
709                 Catch(ElementParser::Exception::Base)
710                 {
711                     LogError("Invalid widget configuration file!");
712                     //                    _rethrown_exception.Dump();
713                     *pErrCode = WRT_WM_ERR_INVALID_ARCHIVE;
714                     if (-1 == TEMP_FAILURE_RETRY(closedir(dir))) {
715                         LogError(
716                             "Failed to close dir: " << _currentPath <<
717                             " with error: "
718                                                     << DPL::GetErrnoString());
719                     }
720                     return false;
721                 }
722
723                 has_config_xml = true;
724                 break;
725             }
726         }
727     }
728     if (-1 == TEMP_FAILURE_RETRY(closedir(dir))) {
729         LogError("Failed to close dir: " << _currentPath << " with error: "
730                                          << DPL::GetErrnoString());
731     }
732
733     //We must have config.xml so leaveing if we doesn't
734     if (!has_config_xml) {
735         LogError("Invalid archive");
736         *pErrCode = WRT_WM_ERR_INVALID_ARCHIVE;
737         return false;
738     }
739     return true;
740 }
741
742 bool TaskWidgetConfig::locateAndParseConfigurationFile(
743     const std::string& _currentPath,
744     WrtDB::WidgetRegisterInfo& pWidgetConfigInfo,
745     const std::string& baseFolder,
746     int* pErrCode)
747 {
748     using namespace WrtDB;
749
750     if (!pErrCode) {
751         return false;
752     }
753
754     ConfigParserData& configInfo = pWidgetConfigInfo.configInfo;
755
756     // check if this installation from browser, or not.
757     size_t pos = _currentPath.rfind("/");
758     std::ostringstream infoPath;
759     infoPath << _currentPath.substr(pos + 1);
760
761     if (infoPath.str() != WRT_WIDGET_CONFIG_FILE_NAME) {
762         if (_currentPath.empty() || baseFolder.empty()) {
763             *pErrCode = WRT_ERR_INVALID_ARG;
764             return false;
765         }
766         // in case of general installation using wgt archive
767         if (!parseConfigurationFileWidget(configInfo, _currentPath,
768                                           pErrCode))
769         {
770             return false;
771         }
772     } else {
773         // in case of browser installation
774         if (!parseConfigurationFileBrowser(configInfo, _currentPath,
775                                            pErrCode))
776         {
777             return false;
778         }
779     }
780
781     if (!fillWidgetConfig(pWidgetConfigInfo, configInfo)) {
782         *pErrCode = WRT_WM_ERR_INVALID_ARCHIVE;
783         return false;
784     }
785     return true;
786 }
787
788 bool TaskWidgetConfig::fillWidgetConfig(
789     WrtDB::WidgetRegisterInfo& pWidgetConfigInfo,
790     WrtDB::ConfigParserData& configInfo)
791 {
792     if (!!configInfo.widget_id) {
793         if (!pWidgetConfigInfo.guid) {
794             pWidgetConfigInfo.guid = configInfo.widget_id;
795         } else {
796             if (pWidgetConfigInfo.guid != configInfo.widget_id) {
797                 LogError("Invalid archive");
798                 return false;
799             }
800         }
801     }
802     if (!!configInfo.tizenAppId) {
803         if (DPL::ToUTF8String(pWidgetConfigInfo.tzAppid).compare(
804                 DPL::ToUTF8String(*configInfo.tizenAppId)) < 0)
805         {
806             LogError("Invalid archive - Tizen App ID not same error");
807             return false;
808         }
809     }
810     if (!!configInfo.tizenPkgId) {
811         if (pWidgetConfigInfo.tzPkgid != *configInfo.tizenPkgId) {
812             LogError("Invalid archive - Tizen Pkg ID not same error");
813             return false;
814         }
815     }
816     if (!!configInfo.version) {
817         if (!pWidgetConfigInfo.version) {
818             pWidgetConfigInfo.version = configInfo.version;
819         } else {
820             if (pWidgetConfigInfo.version != configInfo.version) {
821                 LogError("Invalid archive");
822                 return false;
823             }
824         }
825     }
826     if (!!configInfo.minVersionRequired) {
827         pWidgetConfigInfo.minVersion = configInfo.minVersionRequired;
828     } else if (!!configInfo.tizenMinVersionRequired) {
829         pWidgetConfigInfo.minVersion = configInfo.tizenMinVersionRequired;
830     }
831     return true;
832 }
833
834 void TaskWidgetConfig::processFile(
835     const std::string& path,
836     WrtDB::WidgetRegisterInfo &
837     widgetConfiguration)
838 {
839     int pErrCode;
840
841     if (!locateAndParseConfigurationFile(path, widgetConfiguration,
842                                          DEFAULT_LANGUAGE, &pErrCode))
843     {
844         LogWarning("Widget archive: Failed while parsing config file");
845         ThrowMsg(Exception::ConfigParseFailed, path);
846     }
847 }
848 } //namespace WidgetInstall
849 } //namespace Jobs