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