tizen 2.4 release
[framework/web/wrt-installer.git] / src / pkg-manager / backendlib.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  *
18  *
19  * @file       backendlib.cpp
20  * @author     Soyoung Kim (sy037.kim@samsung.com)
21  * @version    0.1
22  * @brief      This is implementation file for providing widget information
23  *             to package manager
24  */
25 #include "package-manager-plugin.h"
26 #include <package-manager.h>
27 #include <regex.h>
28 #include <dpl/wrt-dao-ro/global_config.h>
29 #include <vcore/VCore.h>
30 #include <dpl/wrt-dao-ro/WrtDatabase.h>
31 #include <dpl/wrt-dao-ro/widget_dao_read_only.h>
32 #include <dpl/wrt-dao-ro/feature_dao_read_only.h>
33 #include <dpl/wrt-dao-ro/widget_config.h>
34 #include <string>
35 #include <dpl/db/sql_connection.h>
36 #include <dpl/foreach.h>
37 #include <dpl/utils/folder_size.h>
38 #include <dpl/wrt-dao-ro/wrt_db_types.h>
39 #include <dpl/copy.h>
40 #include <dpl/abstract_waitable_input_adapter.h>
41 #include <dpl/abstract_waitable_output_adapter.h>
42 #include <dpl/zip_input.h>
43 #include <dpl/binary_queue.h>
44 #include <dpl/file_input.h>
45 #include <dpl/wrt-dao-ro/config_parser_data.h>
46 #include <dpl/localization/LanguageTagsProvider.h>
47 #include <dpl/optional_typedefs.h>
48 #include "root_parser.h"
49 #include "widget_parser.h"
50 #include "parser_runner.h"
51 #include <dpl/log/log.h>
52 #include <dpl/log/secure_log.h>
53
54 using namespace WrtDB;
55
56 #undef TRUE
57 #undef FALSE
58 #define TRUE 0
59 #define FALSE -1
60 #define GET_DIRECTORY_SIZE_KB(x)    (x) / 1024
61
62 #ifdef __cplusplus
63 extern "C"
64 {
65 #endif
66
67 static void pkg_native_plugin_on_unload();
68 static int pkg_plugin_app_is_installed(const char *pkg_name);
69 static int pkg_plugin_get_installed_apps_list(const char *category,
70                                               const char *option,
71                                               package_manager_pkg_info_t **list,
72                                               int *count);
73 static int pkg_plugin_get_app_detail_info(
74     const char *pkg_name,
75     package_manager_pkg_detail_info_t *
76     pkg_detail_info);
77 static int pkg_plugin_get_app_detail_info_from_package(
78     const char *pkg_path,
79     package_manager_pkg_detail_info_t
80     *pkg_detail_info);
81
82 pkgmgr_info *pkgmgr_client_check_pkginfo_from_file(const char *pkg_path);
83
84 static void pkg_native_plugin_on_unload()
85 {
86     _D("pkg_native_plugin_unload() is called");
87 }
88
89 // regexec() function does not work properly in specific locale (ex, Estonian)
90 // So, change locale temporally before call regcomp and regexec
91 class ScopeLocale {
92 public:
93     ScopeLocale() {
94         currentLocale = setlocale(LC_ALL , NULL);
95         if (NULL == setlocale(LC_ALL, "C")) {
96             _W("Failed to change locale to \"C\"");
97         }
98     }
99
100     ~ScopeLocale() {
101         if (NULL == setlocale(LC_ALL, currentLocale.c_str())) {
102             _W("Failed to set previous locale");
103         }
104     }
105
106 private:
107     std::string currentLocale;
108 };
109
110 static int pkg_plugin_app_is_installed(const char *pkg_name)
111 {
112     const char* REG_PKGID_PATTERN = "^[a-zA-Z0-9]{10}$";
113     _D("pkg_plugin_app_is_installed() is called");
114
115     WrtDB::WrtDatabase::attachToThreadRO();
116
117     {
118         ScopeLocale locale;
119         regex_t reg;
120         if (regcomp(&reg, REG_PKGID_PATTERN, REG_NOSUB | REG_EXTENDED) != 0) {
121             _D("Regcomp failed");
122         }
123
124         if (!(regexec(&reg, pkg_name,
125                         static_cast<size_t>(0), NULL, 0) == 0))
126         {
127             _E("Invalid argument : %s", pkg_name);
128             return FALSE;
129         }
130     }
131
132     Try {
133         WrtDB::TizenPkgId pkgid(DPL::FromUTF8String(pkg_name));
134         WrtDB::TizenAppId appid = WidgetDAOReadOnly::getTizenAppId(pkgid);
135         _D("appid : %ls", appid.c_str());
136     } Catch(WidgetDAOReadOnly::Exception::WidgetNotExist) {
137         WrtDB::WrtDatabase::detachFromThread();
138         return FALSE;
139     }
140     WrtDB::WrtDatabase::detachFromThread();
141     return TRUE;
142 }
143
144 static int pkg_plugin_get_installed_apps_list(const char * /*category*/,
145                                               const char * /*option*/,
146                                               package_manager_pkg_info_t **list,
147                                               int *count)
148 {
149     _D("pkg_plugin_get_installed_apps_list() is called");
150
151     package_manager_pkg_info_t *pkg_list = NULL;
152     package_manager_pkg_info_t *pkg_last = NULL;
153
154     WrtDB::WrtDatabase::attachToThreadRO();
155     TizenAppIdList tizenAppIdList = WidgetDAOReadOnly::getTizenAppIdList();
156     *count = 0;
157
158     FOREACH(iterator, tizenAppIdList) {
159         package_manager_pkg_info_t *pkg_info =
160             static_cast<package_manager_pkg_info_t*>
161             (malloc(sizeof(package_manager_pkg_info_t)));
162
163         if (pkg_info == NULL) {
164             continue;
165         }
166
167         if (NULL == pkg_list) {
168             pkg_list = pkg_info;
169             pkg_last = pkg_info;
170         } else {
171             pkg_last->next = pkg_info;
172         }
173
174         TizenAppId tzAppid = *iterator;
175         WidgetDAOReadOnly widget(tzAppid);
176         strncpy(pkg_info->pkg_type, "wgt", PKG_TYPE_STRING_LEN_MAX);
177         snprintf(pkg_info->pkg_name, PKG_NAME_STRING_LEN_MAX, "%s",
178                  DPL::ToUTF8String(tzAppid).c_str());
179
180         DPL::OptionalString version = widget.getVersion();
181         if (!!version) {
182             strncpy(pkg_info->version,
183                     DPL::ToUTF8String(*version).c_str(),
184                     PKG_VERSION_STRING_LEN_MAX - 1);
185         }
186
187         (*count)++;
188         pkg_last = pkg_info;
189     }
190     *list = pkg_list;
191     WrtDB::WrtDatabase::detachFromThread();
192
193     return TRUE;
194 }
195
196 static int pkg_plugin_get_app_detail_info(
197     const char *pkg_name,
198     package_manager_pkg_detail_info_t *
199     pkg_detail_info)
200 {
201     _D("pkg_plugin_get_app_detail_info() is called");
202
203     WrtDB::WrtDatabase::attachToThreadRO();
204
205     WrtDB::TizenAppId appid;
206     Try {
207         WrtDB::TizenPkgId pkgid(DPL::FromUTF8String(pkg_name));
208         appid = WidgetDAOReadOnly::getTizenAppId(pkgid);
209         _D("appid : %ls", appid.c_str());
210     } Catch(WidgetDAOReadOnly::Exception::WidgetNotExist) {
211         WrtDB::WrtDatabase::detachFromThread();
212         return FALSE;
213     }
214
215     WidgetDAOReadOnly widget(appid);
216
217     DPL::OptionalString version = widget.getVersion();
218     DPL::OptionalString id = widget.getGUID();
219     DPL::OptionalString locale = widget.getDefaultlocale();
220
221     if (!!version) {
222         strncpy(pkg_detail_info->version,
223                 DPL::ToUTF8String(*version).c_str(),
224                 PKG_VERSION_STRING_LEN_MAX - 1);
225     }
226     snprintf(pkg_detail_info->pkgid, PKG_NAME_STRING_LEN_MAX, "%s",
227              pkg_name);
228     snprintf(pkg_detail_info->optional_id, PKG_NAME_STRING_LEN_MAX, "%s",
229              DPL::ToUTF8String(appid).c_str());
230     WidgetLocalizedInfo localizedInfo;
231
232     if (!locale) {
233         _D("locale is NULL");
234         DPL::String languageTag(L"");
235         localizedInfo = widget.getLocalizedInfo(languageTag);
236     } else {
237         localizedInfo = widget.getLocalizedInfo(*locale);
238     }
239     DPL::OptionalString desc(localizedInfo.description);
240
241     if (!!desc) {
242         strncpy(pkg_detail_info->pkg_description,
243                 DPL::ToUTF8String(*desc).c_str(),
244                 PKG_VALUE_STRING_LEN_MAX - 1);
245     }
246     strncpy(pkg_detail_info->pkg_type, "wgt", PKG_TYPE_STRING_LEN_MAX);
247     strncpy(pkg_detail_info->pkg_name, pkg_name, PKG_NAME_STRING_LEN_MAX - 1);
248
249     std::string min_version = DPL::ToUTF8String((*widget.getMinimumWacVersion()));
250
251     strncpy(pkg_detail_info->min_platform_version, min_version.c_str(),
252             PKG_VERSION_STRING_LEN_MAX - 1);
253
254     /* set installed time */
255     pkg_detail_info->installed_time = widget.getInstallTime();
256
257     /* set Widget size */
258     DPL::String pkgName = DPL::FromUTF8String(pkg_name);
259     std::string installPath = WidgetConfig::GetWidgetBasePath(pkgName);
260     std::string persistentPath =
261         WidgetConfig::GetWidgetPersistentStoragePath(pkgName);
262     std::string tempPath =
263         WidgetConfig::GetWidgetTemporaryStoragePath(pkgName);
264     installPath += "/";
265     tempPath += "/";
266     persistentPath += "/";
267
268     size_t installedSize = Utils::getFolderSize(installPath);
269     size_t persistentSize = Utils::getFolderSize(persistentPath);
270     size_t appSize = installedSize - persistentSize;
271     size_t dataSize = persistentSize + Utils::getFolderSize(tempPath);
272
273     pkg_detail_info->installed_size = GET_DIRECTORY_SIZE_KB(installedSize);
274     pkg_detail_info->app_size = GET_DIRECTORY_SIZE_KB(appSize);
275     pkg_detail_info->data_size = GET_DIRECTORY_SIZE_KB(dataSize);
276
277     WrtDB::WrtDatabase::detachFromThread();
278     return TRUE;
279 }
280
281 int getConfigParserData(const std::string &widgetPath, ConfigParserData& configInfo)
282 {
283     const char* CONFIG_XML = "config.xml";
284     const char* WITH_OSP_XML = "res/wgt/config.xml";
285
286     Try {
287         ParserRunner parser;
288
289         std::unique_ptr<DPL::ZipInput> zipFile(
290                 new DPL::ZipInput(widgetPath));
291
292         std::unique_ptr<DPL::ZipInput::File> configFile;
293
294         // Open config.xml file
295         Try {
296             configFile.reset(zipFile->OpenFile(CONFIG_XML));
297         }
298         Catch(DPL::ZipInput::Exception::OpenFileFailed)
299         {
300             configFile.reset(zipFile->OpenFile(WITH_OSP_XML));
301         }
302
303         // Extract config
304         DPL::BinaryQueue buffer;
305         DPL::AbstractWaitableInputAdapter inputAdapter(configFile.get());
306         DPL::AbstractWaitableOutputAdapter outputAdapter(&buffer);
307         DPL::Copy(&inputAdapter, &outputAdapter);
308         parser.Parse(&buffer,
309                 ElementParserPtr(
310                     new RootParser<WidgetParser>(configInfo,
311                         DPL::
312                         FromUTF32String(
313                             L"widget"))));
314     }
315     Catch(DPL::ZipInput::Exception::OpenFailed)
316     {
317         _E("Failed to open widget package");
318         return FALSE;
319     }
320     Catch(DPL::ZipInput::Exception::OpenFileFailed)
321     {
322         _E("Failed to open config.xml file");
323         return FALSE;
324     }
325     Catch(DPL::CopyFailed)
326     {
327         _E("Failed to extract config.xml file");
328         return FALSE;
329     }
330     Catch(DPL::FileInput::Exception::OpenFailed)
331     {
332         _E("Failed to open config.xml file");
333         return FALSE;
334     }
335     Catch(ElementParser::Exception::ParseError)
336     {
337         _E("Failed to parse config.xml file");
338         return FALSE;
339     }
340     Catch(DPL::ZipInput::Exception::SeekFileFailed)
341     {
342         _E("Failed to seek widget archive - corrupted package?");
343         return FALSE;
344     }
345
346     return TRUE;
347 }
348
349 char* getIconInfo(const std::string &widgetPath,
350         const std::string &icon_name, int &icon_size)
351 {
352     Try {
353         std::unique_ptr<DPL::ZipInput> zipFile(
354                 new DPL::ZipInput(widgetPath));
355
356         std::unique_ptr<DPL::ZipInput::File> iconFile;
357
358         Try {
359             iconFile.reset(zipFile->OpenFile(icon_name));
360         }
361         Catch(DPL::ZipInput::Exception::OpenFileFailed)
362         {
363             _D("This web app is hybrid web app");
364             std::string hybrid_icon = "res/wgt/" + icon_name;
365             iconFile.reset(zipFile->OpenFile(hybrid_icon));
366         }
367
368         DPL::BinaryQueue buffer;
369         DPL::AbstractWaitableInputAdapter inputAdapter(iconFile.get());
370         DPL::AbstractWaitableOutputAdapter outputAdapter(&buffer);
371         DPL::Copy(&inputAdapter, &outputAdapter);
372         icon_size = buffer.Size();
373         char *getBuffer = (char*) calloc(1, (sizeof(char) * icon_size) + 1);
374         buffer.Flatten(getBuffer, buffer.Size());
375         return getBuffer;
376     }
377     Catch(DPL::ZipInput::Exception::OpenFailed)
378     {
379         _D("Failed to open widget package");
380         return NULL;
381     }
382     Catch(DPL::ZipInput::Exception::OpenFileFailed)
383     {
384         _D("Not found icon file %s", icon_name.c_str());
385         return NULL;
386     }
387 }
388
389 char* getIconForLocale(const std::string& bp, const std::string& tag,
390                                      const std::string& icon, int & size)
391 {
392     std::string iconPath;
393     if (!tag.empty()) {
394         iconPath += std::string("locales/") + tag;
395     }
396     if (!iconPath.empty()) {
397         iconPath += "/";
398     }
399
400     iconPath += icon;
401     return getIconInfo(bp, iconPath, size);
402 }
403
404 char* getIcon(const std::string & basepath, const WrtDB::ConfigParserData & config, int & size)
405 {
406     const std::list<std::string> defaultIcons{ "icon.svg", "icon.ico", "icon.png", "icon.gif", "icon.jpg" };
407     LanguageTags tagsList =
408         LanguageTagsProviderSingleton::Instance().getLanguageTags();
409
410     char * result = NULL;
411
412     //for each locale tag - searching for icon presence and returning raw data
413     //first found is best as locale tags are ordered
414     FOREACH(tag, tagsList)
415     {
416         FOREACH(icon, config.iconsList)
417         {
418             std::string src = DPL::ToUTF8String(icon->src);
419             result = getIconForLocale(basepath, DPL::ToUTF8String(*tag), src, size);
420             if(result) {
421                 return result;
422             }
423         }
424         FOREACH(i, defaultIcons)
425         {
426             result = getIconForLocale(basepath, DPL::ToUTF8String(*tag), *i, size);
427             if(result) {
428                 return result;
429             }
430         }
431     }
432     return NULL;
433 }
434
435 int getWidgetDetailInfoFromPackage(const char* pkgPath,
436         package_manager_pkg_detail_info_t* pkg_detail_info)
437 {
438     const std::string widget_path(pkgPath);
439     ConfigParserData configInfo;
440
441     if (FALSE == getConfigParserData(widget_path, configInfo)) {
442         return FALSE;
443     }
444
445     strncpy(pkg_detail_info->pkg_type, "wgt", PKG_TYPE_STRING_LEN_MAX);
446     if (!!configInfo.tizenPkgId) {
447         strncpy(pkg_detail_info->pkgid,
448                 DPL::ToUTF8String(*configInfo.tizenPkgId).c_str(), PKG_TYPE_STRING_LEN_MAX - 1);
449     }
450     if (!!configInfo.tizenAppId) {
451         strncpy(pkg_detail_info->pkg_name,
452                 DPL::ToUTF8String(*configInfo.tizenAppId).c_str(),
453                 PKG_NAME_STRING_LEN_MAX - 1);
454     }
455     if (!!configInfo.version) {
456         strncpy(pkg_detail_info->version,
457                 DPL::ToUTF8String(*configInfo.version).c_str(),
458                 PKG_VERSION_STRING_LEN_MAX - 1);
459     }
460
461     DPL::OptionalString name;
462     DPL::OptionalString desc;
463
464     LanguageTags tags = LanguageTagsProviderSingleton::Instance().getLanguageTags();
465
466     auto toLowerCase = [](const DPL::String & r)
467     {
468         DPL::String result;
469         std::transform(r.begin(), r.end(), std::inserter(result, result.begin()), ::tolower);
470         return result;
471     };
472
473     if (!!configInfo.defaultlocale)
474     {
475         Locale & dl = *configInfo.defaultlocale;
476         configInfo.defaultlocale = toLowerCase(dl);
477     }
478
479     bool isNameFound = false;
480     bool isDescFound = false;
481     FOREACH(tag, tags)
482     {
483         *tag = toLowerCase(*tag);
484         FOREACH(localizedData, configInfo.localizedDataSet)
485         {
486             Locale i = localizedData->first;
487             i = toLowerCase(i);
488
489             if (!!configInfo.defaultlocale && *configInfo.defaultlocale == i)
490             {
491                 if (!isNameFound)
492                     name = localizedData->second.name;
493                 if (!isDescFound)
494                     desc = localizedData->second.description;
495             }
496
497             if (*tag == i)
498             {
499                 if (!isNameFound) {
500                     name = localizedData->second.name;
501                     if (name)
502                         isNameFound = true;
503                 }
504
505                 if (!isDescFound) {
506                     desc = localizedData->second.description;
507                     if (desc)
508                         isDescFound = true;
509                 }
510             }
511         }
512         if (isNameFound && isDescFound) break;
513     }
514
515     if (!!name) {
516         strncpy(pkg_detail_info->label, DPL::ToUTF8String(*name).c_str(),
517                 PKG_LABEL_STRING_LEN_MAX - 1);
518     }
519
520     if (!!desc) {
521         strncpy(pkg_detail_info->pkg_description,
522                 DPL::ToUTF8String(*desc).c_str(),
523                 PKG_VALUE_STRING_LEN_MAX - 1);
524     }
525
526     if (!!configInfo.tizenMinVersionRequired) {
527         strncpy(pkg_detail_info->min_platform_version,
528                 DPL::ToUTF8String(*configInfo.tizenMinVersionRequired).c_str(),
529                 PKG_VERSION_STRING_LEN_MAX - 1);
530     }
531
532     if (!!configInfo.authorName) {
533         strncpy(pkg_detail_info->author,
534                 DPL::ToUTF8String(*configInfo.authorName).c_str(),
535                 PKG_VALUE_STRING_LEN_MAX - 1);
536     }
537
538
539     pkg_detail_info->privilege_list = NULL;
540     FOREACH(it, configInfo.featuresList) {
541         std::string featureInfo =  DPL::ToUTF8String(it->name);
542         _D("privilege : %s", featureInfo.c_str());
543         int length = featureInfo.size();
544         char *privilege = (char*) calloc(1, (sizeof(char) * (length + 1)));
545         if (privilege == NULL) {
546             continue;
547         }
548         snprintf(privilege, length + 1, "%s", featureInfo.c_str());
549         pkg_detail_info->privilege_list =
550             g_list_append(pkg_detail_info->privilege_list, privilege);
551     }
552
553     char* icon_buf = getIcon(widget_path, configInfo, pkg_detail_info->icon_size);
554
555     if (icon_buf) {
556         _D("icon size : %d", pkg_detail_info->icon_size);
557         pkg_detail_info->icon_buf = icon_buf;
558     } else {
559         _D("No icon");
560         pkg_detail_info->icon_size = 0;
561         pkg_detail_info->icon_buf = NULL;
562     }
563
564     return TRUE;
565 }
566
567 static int pkg_plugin_get_app_detail_info_from_package(
568     const char * pkg_path,
569     package_manager_pkg_detail_info_t * pkg_detail_info)
570 {
571     _D("pkg_plugin_get_app_detail_info_from_package() is called");
572     return getWidgetDetailInfoFromPackage(pkg_path, pkg_detail_info);
573 }
574
575 pkgmgr_info *pkgmgr_client_check_pkginfo_from_file(const char *pkg_path)
576 {
577     _D("pkgmgr_client_check_pkginfo_from_file() is called");
578     package_manager_pkg_detail_info_t *pkg_detail_info;
579     pkg_detail_info = (package_manager_pkg_detail_info_t*)malloc(
580             sizeof(package_manager_pkg_detail_info_t));
581     if (pkg_detail_info == NULL) {
582         _E("Failed to get memory alloc");
583         return NULL;
584     }
585     int ret = getWidgetDetailInfoFromPackage(pkg_path, pkg_detail_info);
586     if (FALSE == ret) {
587         _E("Failed to get package detail info ");
588         free(pkg_detail_info);
589         return NULL;
590     }
591     return reinterpret_cast<pkgmgr_info*>(pkg_detail_info);
592 }
593
594 __attribute__ ((visibility("default")))
595 int pkg_plugin_on_load(pkg_plugin_set *set)
596 {
597     if (NULL == set) {
598         return FALSE;
599     }
600     memset(set, 0x00, sizeof(pkg_plugin_set));
601
602     set->plugin_on_unload = pkg_native_plugin_on_unload;
603     set->pkg_is_installed = pkg_plugin_app_is_installed;
604     set->get_installed_pkg_list = pkg_plugin_get_installed_apps_list;
605     set->get_pkg_detail_info = pkg_plugin_get_app_detail_info;
606     set->get_pkg_detail_info_from_package =
607         pkg_plugin_get_app_detail_info_from_package;
608
609     return TRUE;
610 }
611
612 #ifdef __cplusplus
613 }
614 #endif