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