From 11a58e2aed32893adf9d71c16914bcdbbe7836b4 Mon Sep 17 00:00:00 2001 From: Jinkun Jang Date: Sat, 16 Mar 2013 01:12:42 +0900 Subject: [PATCH] merge with master --- CMakeLists.txt | 50 +- debian/changelog | 6 - debian/compat | 1 - debian/control | 29 - debian/dirs | 2 - debian/libslp-shortcut-0.install.in | 1 - debian/libslp-shortcut-dev.install.in | 3 - debian/rules | 114 --- lib/CMakeLists.txt | 49 ++ LICENSE => lib/LICENSE | 0 {include => lib/include}/shortcut.h | 91 ++- .../SLP_shortcut_PG.h => lib/include/shortcut_PG.h | 11 +- shortcut.pc.in => lib/shortcut.pc.in | 1 - lib/src/main.c | 776 ++++++++++++++++++++ libshortcut.manifest | 17 + packaging/libshortcut.spec | 32 +- pkgmgr_shortcut/CMakeLists.txt | 31 + pkgmgr_shortcut/include/dlist.h | 44 ++ pkgmgr_shortcut/src/dlist.c | 181 +++++ pkgmgr_shortcut/src/service_register.c | 756 ++++++++++++++++++++ sample.xml | 62 ++ src/main.c | 791 --------------------- src/secom_socket.c | 245 ------- test/Makefile | 5 +- test/application.c | 14 +- test/homescreen.c | 16 +- include/secom_socket.h => test/shortcut.c | 47 +- test_db_builder.sh | 80 +++ 28 files changed, 2136 insertions(+), 1319 deletions(-) delete mode 100644 debian/changelog delete mode 100644 debian/compat delete mode 100644 debian/control delete mode 100644 debian/dirs delete mode 100644 debian/libslp-shortcut-0.install.in delete mode 100644 debian/libslp-shortcut-dev.install.in delete mode 100755 debian/rules create mode 100644 lib/CMakeLists.txt rename LICENSE => lib/LICENSE (100%) rename {include => lib/include}/shortcut.h (61%) rename include/SLP_shortcut_PG.h => lib/include/shortcut_PG.h (81%) rename shortcut.pc.in => lib/shortcut.pc.in (91%) create mode 100644 lib/src/main.c create mode 100644 pkgmgr_shortcut/CMakeLists.txt create mode 100644 pkgmgr_shortcut/include/dlist.h create mode 100644 pkgmgr_shortcut/src/dlist.c create mode 100644 pkgmgr_shortcut/src/service_register.c create mode 100644 sample.xml delete mode 100644 src/main.c delete mode 100644 src/secom_socket.c rename include/secom_socket.h => test/shortcut.c (50%) create mode 100755 test_db_builder.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index c2e1079..ea60a32 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,52 +1,6 @@ CMAKE_MINIMUM_REQUIRED(VERSION 2.6) -PROJECT(shortcut C) - -SET(PREFIX ${CMAKE_INSTALL_PREFIX}) -SET(EXEC_PREFIX "\${prefix}") -SET(LIBDIR "\${exec_prefix}/lib") -SET(INCLUDEDIR "\${prefix}/include/${PROJECT_NAME}") -SET(VERSION_MAJOR 0) -SET(VERSION "${VERSION_MAJOR}.0.1") set(CMAKE_SKIP_BUILD_RPATH true) -SET(SRCS src/main.c src/secom_socket.c) - -INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include) - -INCLUDE(FindPkgConfig) -pkg_check_modules(glib_pkg REQUIRED gobject-2.0) -pkg_check_modules(pkgs REQUIRED - glib-2.0 - dlog -) - -FOREACH(flag ${pkgs_CFLAGS}) - SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") -ENDFOREACH(flag) - -SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden") - -SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}") - -#ADD_DEFINITIONS("-Werror") -#ADD_DEFINITIONS("-Wall") -#ADD_DEFINITIONS("-Wextra") -#ADD_DEFINITIONS("-ansi") -#ADD_DEFINITIONS("-pedantic") - -ADD_DEFINITIONS("-DPREFIX=\"${PREFIX}\"") -ADD_DEFINITIONS("-DLOG_TAG=\"${PROJECT_NAME}\"") - -ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS}) -SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES SOVERSION ${VERSION_MAJOR}) -SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES VERSION ${VERSION}) -TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_LDFLAGS}) - -CONFIGURE_FILE(${PROJECT_NAME}.pc.in ${PROJECT_NAME}.pc @ONLY) -SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${PROJECT_NAME}.pc") - -INSTALL(TARGETS ${PROJECT_NAME} DESTINATION lib) -INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.pc DESTINATION lib/pkgconfig) -INSTALL(FILES ${CMAKE_SOURCE_DIR}/include/shortcut.h DESTINATION include/${PROJECT_NAME}) -INSTALL(FILES ${CMAKE_SOURCE_DIR}/include/SLP_shortcut_PG.h DESTINATION include/${PROJECT_NAME}) +ADD_SUBDIRECTORY("pkgmgr_shortcut") +ADD_SUBDIRECTORY("lib") diff --git a/debian/changelog b/debian/changelog deleted file mode 100644 index 0bfc7b0..0000000 --- a/debian/changelog +++ /dev/null @@ -1,6 +0,0 @@ -libslp-shortcut (0.0.5) unstable; urgency=low - - * Git:165.213.180.234:/slp/pkgs/s/shortcut - * Tag: libslp-shortcut_0.0.5 - - -- Sung-jae Park Mon, 02 Jan 2012 13:15:52 +0900 diff --git a/debian/compat b/debian/compat deleted file mode 100644 index 7ed6ff8..0000000 --- a/debian/compat +++ /dev/null @@ -1 +0,0 @@ -5 diff --git a/debian/control b/debian/control deleted file mode 100644 index f8a7fda..0000000 --- a/debian/control +++ /dev/null @@ -1,29 +0,0 @@ -Source: libslp-shortcut -Section: libs -Priority: optional -Maintainer: Sung-jae Park , Young-joo Park -Build-Depends: debhelper (>= 5), libglib2.0-dev, dlog-dev -Standards-Version: 3.7.2 - -Package: libslp-shortcut-0 -Section: libs -Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, libglib2.0-0, libdlog-0 -Description: Shortcut service supporting library (shared object) - -Package: libslp-shortcut-dev -Section: libs -Architecture: any -Depends: libslp-shortcut-0 (= ${Source-Version}) -Description: Shortcut (Add to home) service supporting library (development) -XB-Generate-Docs: yes - -Package: libslp-shortcut-dbg -Section: debug -Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, libslp-shortcut-0 (= ${Source-Version}) -Description: Shortcut service supporting library (unstripped) - - - - diff --git a/debian/dirs b/debian/dirs deleted file mode 100644 index ca882bb..0000000 --- a/debian/dirs +++ /dev/null @@ -1,2 +0,0 @@ -usr/bin -usr/sbin diff --git a/debian/libslp-shortcut-0.install.in b/debian/libslp-shortcut-0.install.in deleted file mode 100644 index a7c24c5..0000000 --- a/debian/libslp-shortcut-0.install.in +++ /dev/null @@ -1 +0,0 @@ -@PREFIX@/lib/*.so.* diff --git a/debian/libslp-shortcut-dev.install.in b/debian/libslp-shortcut-dev.install.in deleted file mode 100644 index 4430783..0000000 --- a/debian/libslp-shortcut-dev.install.in +++ /dev/null @@ -1,3 +0,0 @@ -@PREFIX@/include/shortcut/shortcut.h -@PREFIX@/include/shortcut/SLP_shortcut_PG.h -@PREFIX@/lib/pkgconfig/*.pc diff --git a/debian/rules b/debian/rules deleted file mode 100755 index 6618431..0000000 --- a/debian/rules +++ /dev/null @@ -1,114 +0,0 @@ -#!/usr/bin/make -f -# -*- makefile -*- -# Sample debian/rules that uses debhelper. -# This file was originally written by Joey Hess and Craig Small. -# As a special exception, when this file is copied by dh-make into a -# dh-make output file, you may use that output file without restriction. -# This special exception was added by Craig Small in version 0.37 of dh-make. - -# Uncomment this to turn on verbose mode. -#export DH_VERBOSE=1 - -CFLAGS ?= -Wall -g -LDFLAGS ?= -PREFIX ?= /usr -DATADIR ?= /opt - -BUILDDIR ?= $(CURDIR)/cmake-tmp - -ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) - CFLAGS += -O0 -else - CFLAGS += -O2 -endif - -LDFLAGS += -Wl,--rpath=$(PREFIX)/lib -Wl,--as-needed - -configure: configure-stamp -configure-stamp: - dh_testdir - # Add here commands to configure the package. - mkdir -p $(BUILDDIR) && cd $(BUILDDIR) && CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" cmake .. -DCMAKE_INSTALL_PREFIX=$(PREFIX) - - touch configure-stamp - -build: build-stamp - -build-stamp: configure-stamp - dh_testdir - - # Add here commands to compile the package. - cd $(BUILDDIR) && $(MAKE) - #docbook-to-man debian/wavplayer.sgml > wavplayer.1 - - for f in `find $(CURDIR)/debian/ -name "*.in"`; do \ - cat $$f > $${f%.in}; \ - sed -i -e "s#@PREFIX@#$(PREFIX)#g" $${f%.in}; \ - sed -i -e "s#@DATADIR@#$(DATADIR)#g" $${f%.in}; \ - done - - - touch $@ - -clean: - dh_testdir - dh_testroot - rm -f build-stamp configure-stamp - - # Add here commands to clean up after the build process. - -rm -rf $(BUILDDIR) - #rm -rf CMakeCache.txt CMakeFiles cmake_install.cmake Makefile install_manifest.txt - - for f in `find $(CURDIR)/debian/ -name "*.in"`; do \ - rm -f $${f%.in}; \ - done - - dh_clean - -install: build - dh_testdir - dh_testroot - dh_clean -k - dh_installdirs - - # Add here commands to install the package into debian/wavplayer. - cd $(BUILDDIR) && $(MAKE) DESTDIR=$(CURDIR)/debian/tmp install - - -# Build architecture-independent files here. -binary-indep: build install -# We have nothing to do by default. - -# Build architecture-dependent files here. -binary-arch: build install - dh_testdir - dh_testroot -# dh_installchangelogs -# dh_installdocs -# dh_installexamples - dh_install --sourcedir=debian/tmp -# dh_installmenu -# dh_installdebconf -# dh_installlogrotate -# dh_installemacsen -# dh_installpam -# dh_installmime -# dh_python -# dh_installinit -# dh_installcron -# dh_installinfo - dh_installman - dh_link - dh_strip --dbg-package=libslp-shortcut-dbg - dh_compress - dh_fixperms -# dh_perl - dh_makeshlibs - dh_installdeb - dh_shlibdeps - dh_gencontrol - dh_md5sums - dh_builddeb - -binary: binary-indep binary-arch -.PHONY: build clean binary-indep binary-arch binary install configure diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt new file mode 100644 index 0000000..0e27e2d --- /dev/null +++ b/lib/CMakeLists.txt @@ -0,0 +1,49 @@ +PROJECT(shortcut C) + +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/lib/include) + +SET(PREFIX ${CMAKE_INSTALL_PREFIX}) +SET(EXEC_PREFIX "\${prefix}") +SET(LIBDIR "\${exec_prefix}/lib") +SET(INCLUDEDIR "\${prefix}/include/${PROJECT_NAME}") +SET(VERSION_MAJOR 0) +SET(VERSION "${VERSION_MAJOR}.0.1") + +INCLUDE(FindPkgConfig) +pkg_check_modules(svc_pkgs REQUIRED + dlog + sqlite3 + libxml-2.0 + glib-2.0 + db-util + com-core + vconf +) + +FOREACH(flag ${svc_pkgs_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} -fvisibility=hidden -g -Wall -Werror") +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}") + +ADD_DEFINITIONS("-DPREFIX=\"${PREFIX}\"") +ADD_DEFINITIONS("-DLOG_TAG=\"SHORTCUT\"") + +ADD_LIBRARY(${PROJECT_NAME} SHARED + src/main.c +) + +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${svc_pkgs_LDFLAGS}) + +CONFIGURE_FILE(${PROJECT_NAME}.pc.in ${PROJECT_NAME}.pc @ONLY) +SET_DIRECTORY_PROPERTIES(PROPERTIES ADDITIONAL_MAKE_CLEAN_FILES "${PROJECT_NAME}.pc") + +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION lib) +INSTALL(FILES ${CMAKE_SOURCE_DIR}/lib/include/shortcut.h DESTINATION include/${PROJECT_NAME}) +INSTALL(FILES ${CMAKE_SOURCE_DIR}/lib/include/shortcut_PG.h DESTINATION include/${PROJECT_NAME}) +INSTALL(FILES ${CMAKE_BINARY_DIR}/lib/${PROJECT_NAME}.pc DESTINATION lib/pkgconfig) +INSTALL(FILES ${CMAKE_SOURCE_DIR}/lib/LICENSE DESTINATION /usr/share/license RENAME "lib${PROJECT_NAME}") + +SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES SOVERSION ${VERSION_MAJOR}) +SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES VERSION ${VERSION}) diff --git a/LICENSE b/lib/LICENSE similarity index 100% rename from LICENSE rename to lib/LICENSE diff --git a/include/shortcut.h b/lib/include/shortcut.h similarity index 61% rename from include/shortcut.h rename to lib/include/shortcut.h index b488faf..5edd598 100644 --- a/include/shortcut.h +++ b/lib/include/shortcut.h @@ -1,18 +1,19 @@ /* - * Copyright 2012 Samsung Electronics Co., Ltd + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. * - * Licensed under the Flora License, Version 1.0 (the "License"); + * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.tizenopensource.org/license + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - */ + * +*/ #ifndef __SHORTCUT_H__ #define __SHORTCUT_H__ @@ -39,7 +40,7 @@ extern "C" { * @brief This function prototype is used to define a callback function for the add_to_home reqeust. * The homescreen should define a callback as this type and implementing the service code * for adding a new application shortcut. - * @param[in] pkgname Shortcut is added for this package. + * @param[in] appid Shortcut is added for this package. * @param[in] name Name for created shortcut icon. * @param[in] type 3 kinds of types are defined. * @param[in] content_info Specific information for creating a new shortcut. @@ -53,7 +54,7 @@ extern "C" { * @post None * @remarks None */ -typedef int (*request_cb_t)(const char *pkgname, const char *name, int type, const char *content_info, const char *icon, int pid, void *data); +typedef int (*request_cb_t)(const char *appid, const char *name, int type, const char *content_info, const char *icon, int pid, double period, void *data); /** * @brief This function prototype is used to define for receiving the result of add_to_home. @@ -61,7 +62,7 @@ typedef int (*request_cb_t)(const char *pkgname, const char *name, int type, con * @param[in] pid Process ID of who handles this add_to_home request. * @param[in] data Callback data. * @return int Returns 0, if there is no error or returns errno. - * @see shortcut_add_to_home() + * @see add_to_home_shortcut() * @pre None * @post None * @remarks None @@ -72,16 +73,36 @@ typedef int (*result_cb_t)(int ret, int pid, void *data); * @brief Basically, three types of shortcut is defined. * Every homescreen developer should support these types of shortcut. * Or returns proper errno to figure out why the application failed to add a shortcut. - * SHORTCUT_PACKAGE is used for adding a package itself as a shortcut - * SHORTCUT_DATA is used for adding a shortcut for "content" data. - * SHORTCUT_FILE is used for adding a shortcut for "file". + * LAUNCH_BY_PACKAGE is used for adding a package itself as a shortcut + * LAUNCH_BY_URI is used for adding a shortcut for "uri" data. */ -enum { - SHORTCUT_PACKAGE = 0x0, /**< Launch the package using given pakcage name. */ - SHORTCUT_DATA = 0x01, /**< Launch the related package with given data(content_info). */ - SHORTCUT_FILE = 0x02, /** < Launch the related package with given filename(content_info). */ +enum shortcut_type { + /*!< Deprecated type */ + SHORTCUT_PACKAGE = 0x00000000, /**< Launch the package using given pakcage name. */ + SHORTCUT_DATA = 0x00000001, /**< Launch the related package with given data(content_info). */ + SHORTCUT_FILE = 0x00000002, /**< Launch the related package with given filename(content_info). */ + + /*!< Use these */ + LAUNCH_BY_PACKAGE = 0x00000000, /*!< Launch the package using given pakcage name. */ + LAUNCH_BY_URI = 0x00000001, /*!< Launch the related package with given data(URI). */ + + LIVEBOX_TYPE_DEFAULT = 0x10000000, + LIVEBOX_TYPE_EASY_DEFAULT = 0x30000000, + LIVEBOX_TYPE_1x1 = 0x10010000, + LIVEBOX_TYPE_2x1 = 0x10020000, + LIVEBOX_TYPE_2x2 = 0x10040000, + LIVEBOX_TYPE_4x1 = 0x10080000, + LIVEBOX_TYPE_4x2 = 0x10100000, + LIVEBOX_TYPE_4x3 = 0x10200000, + LIVEBOX_TYPE_4x4 = 0x10400000, + LIVEBOX_TYPE_EASY_1x1 = 0x30010000, + LIVEBOX_TYPE_EASY_3x1 = 0x30020000, + LIVEBOX_TYPE_EASY_3x3 = 0x30040000, + LIVEBOX_TYPE_UNKNOWN = 0x1FFF0000, }; +#define ADD_TO_HOME_IS_LIVEBOX(type) (!!((type) & 0x10000000)) + /** * @fn int shortcut_set_request_cb(request_cb_t request_cb, void *data) * @@ -116,9 +137,9 @@ enum { * @code * #include * - * static int request_cb(const char *pkgname, const char *name, int type, const char *content_info, const char *icon, int pid, void *data) + * static int request_cb(const char *appid, const char *name, int type, const char *content_info, const char *icon, int pid, void *data) * { - * printf("Package name: %s\n", pkgname); + * printf("Package name: %s\n", appid); * printf("Name: %s\n", name); * printf("Type: %d\n", type); * printf("Content: %s\n", content_info); @@ -144,7 +165,7 @@ enum { extern int shortcut_set_request_cb(request_cb_t request_cb, void *data); /** - * @fn int shortcut_add_to_home(const char *pkgname, const char *name, int type, const char *content_info, const char *icon, result_cb_t result_cb, void *data) + * @fn int add_to_home_shortcut(const char *appid, const char *name, int type, const char *content_info, const char *icon, result_cb_t result_cb, void *data) * * @brief The application, which supporting the add_to_home feature, should invoke this. * @@ -156,7 +177,7 @@ extern int shortcut_set_request_cb(request_cb_t request_cb, void *data); * - Application should check the return status from the callback function * - Application should set the callback function to get the result of this request. * - * @param[in] pkgname Package name of owner of this shortcut. + * @param[in] appid Package name of owner of this shortcut. * @param[in] name Name for created shortcut icon. * @param[in] type 3 kinds of types are defined. * @param[in] content_info Specific information for delivering to the creating shortcut. @@ -196,7 +217,7 @@ extern int shortcut_set_request_cb(request_cb_t request_cb, void *data); * * static int app_create(void *data) * { - * shortcut_add_to_home("com.samsung.gallery", "With friends", + * add_to_home_shortcut("org.tizen.gallery", "With friends", * SHORTCUT_DATA, "gallery:0000-0000", * "/opt/media/Pictures/Friends.jpg", result_cb, NULL); * return 0; @@ -209,9 +230,37 @@ extern int shortcut_set_request_cb(request_cb_t request_cb, void *data); * * @endcode */ -extern int shortcut_add_to_home(const char *pkgname, const char *name, int type, const char *content_info, const char *icon, result_cb_t result_cb, void *data); +extern int shortcut_get_list(const char *appid, int (*cb)(const char *appid, const char *icon, const char *name, const char *extra_key, const char *extra_data, void *data), void *data); + +extern int add_to_home_shortcut(const char *appid, const char *name, int type, const char *content_info, const char *icon, result_cb_t result_cb, void *data); + +extern int add_to_home_livebox(const char *appid, const char *name, int type, const char *content, const char *icon, double period, result_cb_t result_cb, void *data); + + +/*! + * \brief Number of preview images for homescreen + */ +extern int homescreen_get_image_count(const char *appid); +/*! + * \return string allocated in the heap - Path of image + */ +extern char *homescreen_get_image(const char *appid, int idx); + +/*! + * \brief Description of the homescreen (based on i18n) + */ +extern int homescreen_get_description(const char *appid, void (*cb)(const char *appid, const char *icon, const char *name, const char *desc, void *data), void *data); + +/*! + * \note + * These two functions are deprecated now. + * + * Please replace the "shortcut_add_to_home" with "add_to_home_shortcut" + * Please replace the "shortcut_add_to_home_with_period" with "add_to_home_livebox" + */ +extern int shortcut_add_to_home(const char *appid, const char *name, int type, const char *content, const char *icon, result_cb_t result_cb, void *data) __attribute__ ((deprecated)); -extern int add_to_home_shortcut(const char *pkgname, const char *name, int type, const char *content_info, const char *icon, result_cb_t result_cb, void *data); +extern int shortcut_add_to_home_with_period(const char *appid, const char *name, int type, const char *content, const char *icon, double period, result_cb_t result_cb, void *data) __attribute__ ((deprecated)); #ifdef __cplusplus } diff --git a/include/SLP_shortcut_PG.h b/lib/include/shortcut_PG.h similarity index 81% rename from include/SLP_shortcut_PG.h rename to lib/include/shortcut_PG.h index eec5363..c3bd6c2 100644 --- a/include/SLP_shortcut_PG.h +++ b/lib/include/shortcut_PG.h @@ -1,18 +1,19 @@ /* - * Copyright 2012 Samsung Electronics Co., Ltd + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. * - * Licensed under the Flora License, Version 1.0 (the "License"); + * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.tizenopensource.org/license + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - */ + * +*/ /** * @ingroup SLP_PG @@ -20,7 +21,7 @@ * @{

Introduction

- Shortcut is a communication interfaces for homescreen and applications. To enable the add_to_home feature. Shortcut(libslp-shortcut) uses socket for IPC. + Shortcut is a communication interfaces for homescreen and applications. To enable the add_to_home feature. Shortcut(libshortcut) uses socket for IPC. @image html SLP_Shortcut_PG_image01.png diff --git a/shortcut.pc.in b/lib/shortcut.pc.in similarity index 91% rename from shortcut.pc.in rename to lib/shortcut.pc.in index 9798259..8daf96d 100644 --- a/shortcut.pc.in +++ b/lib/shortcut.pc.in @@ -6,6 +6,5 @@ includedir=@INCLUDEDIR@ Name: shortcut Description: shortcut server platform library Version: @VERSION@ -Requires: glib-2.0 Libs: -L${libdir} -lshortcut Cflags: -I${includedir} diff --git a/lib/src/main.c b/lib/src/main.c new file mode 100644 index 0000000..d485a53 --- /dev/null +++ b/lib/src/main.c @@ -0,0 +1,776 @@ +/* + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "shortcut.h" + +#if !defined(FLOG) +#define DbgPrint(format, arg...) LOGD("[%s/%s:%d] " format, basename(__FILE__), __func__, __LINE__, ##arg) +#define ErrPrint(format, arg...) LOGE("[%s/%s:%d] " format, basename(__FILE__), __func__, __LINE__, ##arg) +#else +extern FILE *__file_log_fp; +#define DbgPrint(format, arg...) do { fprintf(__file_log_fp, "[LOG] [%s/%s:%d] " format, basename(__FILE__), __func__, __LINE__, ##arg); fflush(__file_log_fp); } while (0) + +#define ErrPrint(format, arg...) do { fprintf(__file_log_fp, "[ERR] [%s/%s:%d] " format, basename(__FILE__), __func__, __LINE__, ##arg); fflush(__file_log_fp); } while (0) +#endif + +#define EAPI __attribute__((visibility("default"))) + +int errno; + + + +static struct info { + const char *dbfile; + sqlite3 *handle; + int server_fd; + int client_fd; + const char *socket_file; + struct { + int (*request_cb)(const char *appid, const char *name, int type, const char *content, const char *icon, pid_t pid, double period, void *data); + void *data; + } server_cb; + int initialized; + int db_opened; +} s_info = { + .server_fd = -1, + .client_fd = -1, + .socket_file = "/tmp/.shortcut", + .dbfile = "/opt/dbspace/.shortcut_service.db", + .handle = NULL, + .initialized = 0, + .db_opened = 0, +}; + + + +static struct packet *add_shortcut_handler(pid_t pid, int handle, const struct packet *packet) +{ + const char *appid; + const char *name; + int type; + const char *content; + const char *icon; + int ret; + + if (!packet) + return NULL; + + if (packet_get(packet, "ssiss", &appid, &name, &type, &content, &icon) != 5) { + ErrPrint("Invalid packet\n"); + return NULL; + } + + DbgPrint("appid[%s], name[%s], type[0x%x], content[%s], icon[%s]\n", appid, name, type, content, icon); + + if (s_info.server_cb.request_cb) + ret = s_info.server_cb.request_cb(appid, name, type, content, icon, pid, -1.0f, s_info.server_cb.data); + else + ret = 0; + + return packet_create_reply(packet, "i", ret); +} + + + +static struct packet *add_livebox_handler(pid_t pid, int handle, const struct packet *packet) +{ + const char *appid; + const char *name; + int type; + const char *content; + const char *icon; + double period; + int ret; + + if (!packet) + return NULL; + + if (packet_get(packet, "ssissd", &appid, &name, &type, &content, &icon, &period) != 6) { + ErrPrint("Invalid packet\n"); + return NULL; + } + + DbgPrint("appid[%s], name[%s], type[0x%x], content[%s], icon[%s], period[%lf]\n", appid, name, type, content, icon, period); + + if (s_info.server_cb.request_cb) + ret = s_info.server_cb.request_cb(appid, name, type, content, icon, pid, period, s_info.server_cb.data); + else + ret = 0; + + return packet_create_reply(packet, "i", ret); +} + + + +EAPI int shortcut_set_request_cb(request_cb_t request_cb, void *data) +{ + s_info.server_cb.request_cb = request_cb; + s_info.server_cb.data = data; + + if (s_info.server_fd < 0) { + static struct method service_table[] = { + { + .cmd = "add_shortcut", + .handler = add_shortcut_handler, + }, + { + .cmd = "add_livebox", + .handler = add_livebox_handler, + }, + { + .cmd = NULL, + .handler = NULL, + }, + }; + + unlink(s_info.socket_file); /* Delete previous socket file for creating a new server socket */ + s_info.server_fd = com_core_packet_server_init(s_info.socket_file, service_table); + } + + DbgPrint("Server FD: %d\n", s_info.server_fd); + + return s_info.server_fd > 0 ? 0 : s_info.server_fd; +} + + + +struct result_cb_item { + result_cb_t result_cb; + void *data; +}; + + + +static int shortcut_send_cb(pid_t pid, int handle, const struct packet *packet, void *data) +{ + struct result_cb_item *item = data; + int ret; + + if (!packet) { + ErrPrint("Packet is not valid\n"); + ret = -EFAULT; + } else if (packet_get(packet, "i", &ret) != 1) { + ErrPrint("Packet is not valid\n"); + ret = -EINVAL; + } + + if (item->result_cb) + ret = item->result_cb(ret, pid, item->data); + else + ret = 0; + free(item); + return ret; +} + + + +static int livebox_send_cb(pid_t pid, int handle, const struct packet *packet, void *data) +{ + struct result_cb_item *item = data; + int ret; + + if (!packet) { + ErrPrint("Packet is not valid\n"); + ret = -EFAULT; + } else if (packet_get(packet, "i", &ret) != 1) { + ErrPrint("Packet is not valid\n"); + ret = -EINVAL; + } + + if (item->result_cb) + ret = item->result_cb(ret, pid, item->data); + else + ret = 0; + free(item); + return ret; +} + + + +static int disconnected_cb(int handle, void *data) +{ + if (s_info.client_fd != handle) { + /*!< This is not my favor */ + return 0; + } + + s_info.client_fd = -EINVAL; + return 0; +} + + + +EAPI int add_to_home_shortcut(const char *appid, const char *name, int type, const char *content, const char *icon, result_cb_t result_cb, void *data) +{ + struct packet *packet; + struct result_cb_item *item; + int ret; + + if (!s_info.initialized) { + s_info.initialized = 1; + com_core_add_event_callback(CONNECTOR_DISCONNECTED, disconnected_cb, NULL); + } + + if (s_info.client_fd < 0) { + static struct method service_table[] = { + { + .cmd = NULL, + .handler = NULL, + }, + }; + + s_info.client_fd = com_core_packet_client_init(s_info.socket_file, 0, service_table); + if (s_info.client_fd < 0) { + ErrPrint("Failed to make connection\n"); + return s_info.client_fd; + } + } + + item = malloc(sizeof(*item)); + if (!item) { + ErrPrint("Heap: %s\n", strerror(errno)); + return -ENOMEM; + } + + item->result_cb = result_cb; + item->data = data; + + if (!appid) + appid = ""; + + if (!name) + name = ""; + + if (!content) + content = ""; + + if (!icon) + icon = ""; + + packet = packet_create("add_shortcut", "ssiss", appid, name, type, content, icon); + if (!packet) { + ErrPrint("Failed to build a packet\n"); + free(item); + return -EFAULT; + } + + ret = com_core_packet_async_send(s_info.client_fd, packet, 0.0f, shortcut_send_cb, item); + if (ret < 0) { + packet_destroy(packet); + free(item); + com_core_packet_client_fini(s_info.client_fd); + s_info.client_fd = -1; + } + + return ret; +} + + + +EAPI int add_to_home_livebox(const char *appid, const char *name, int type, const char *content, const char *icon, double period, result_cb_t result_cb, void *data) +{ + struct packet *packet; + struct result_cb_item *item; + int ret; + + if (!s_info.initialized) { + s_info.initialized = 1; + com_core_add_event_callback(CONNECTOR_DISCONNECTED, disconnected_cb, NULL); + } + + if (s_info.client_fd < 0) { + static struct method service_table[] = { + { + .cmd = NULL, + .handler = NULL, + }, + }; + + s_info.client_fd = com_core_packet_client_init(s_info.socket_file, 0, service_table); + if (s_info.client_fd < 0) + return s_info.client_fd; + } + + item = malloc(sizeof(*item)); + if (!item) { + ErrPrint("Heap: %s\n", strerror(errno)); + return -ENOMEM; + } + + item->result_cb = result_cb; + item->data = data; + + packet = packet_create("add_livebox", "ssissd", appid, name, type, content, icon, period); + if (!packet) { + ErrPrint("Failed to build a packet\n"); + free(item); + return -EFAULT; + } + + ret = com_core_packet_async_send(s_info.client_fd, packet, 0.0f, livebox_send_cb, item); + if (ret < 0) { + packet_destroy(packet); + free(item); + com_core_packet_client_fini(s_info.client_fd); + s_info.client_fd = -1; + } + + return ret; +} + + +EAPI int shortcut_add_to_home_with_period(const char *appid, const char *name, int type, const char *content, const char *icon, double period, result_cb_t result_cb, void *data) +{ + return add_to_home_livebox(appid, name, type, content, icon, period, result_cb, data); +} + +EAPI int shortcut_add_to_home(const char *appid, const char *name, int type, const char *content, const char *icon, result_cb_t result_cb, void *data) +{ + return add_to_home_shortcut(appid, name, type, content, icon, result_cb, data); +} + +static inline int open_db(void) +{ + int ret; + + ret = db_util_open(s_info.dbfile, &s_info.handle, DB_UTIL_REGISTER_HOOK_METHOD); + if (ret != SQLITE_OK) { + DbgPrint("Failed to open a %s\n", s_info.dbfile); + return -EIO; + } + + return 0; +} + + + +/*! + * \note this function will returns allocated(heap) string + */ +static inline char *get_i18n_name(const char *lang, int id) +{ + sqlite3_stmt *stmt; + static const char *query = "SELECT name FROM shortcut_name WHERE id = ? AND lang = ? COLLATE NOCASE"; + const unsigned char *name; + char *ret; + int status; + + status = sqlite3_prepare_v2(s_info.handle, query, -1, &stmt, NULL); + if (status != SQLITE_OK) { + ErrPrint("Failed to prepare stmt: %s\n", sqlite3_errmsg(s_info.handle)); + return NULL; + } + + status = sqlite3_bind_int(stmt, 1, id); + if (status != SQLITE_OK) { + ErrPrint("Failed to bind id: %s\n", sqlite3_errmsg(s_info.handle)); + ret = NULL; + goto out; + } + + status = sqlite3_bind_text(stmt, 2, lang, -1, SQLITE_TRANSIENT); + if (status != SQLITE_OK) { + ErrPrint("Failed to bind lang: %s\n", sqlite3_errmsg(s_info.handle)); + ret = NULL; + goto out; + } + + DbgPrint("id: %d, lang: %s\n", id, lang); + if (SQLITE_ROW != sqlite3_step(stmt)) { + ErrPrint("Failed to do step: %s\n", sqlite3_errmsg(s_info.handle)); + ret = NULL; + goto out; + } + + name = sqlite3_column_text(stmt, 0); + ret = name ? strdup((const char *)name) : NULL; + +out: + sqlite3_reset(stmt); + sqlite3_clear_bindings(stmt); + sqlite3_finalize(stmt); + return ret; +} + + + +static inline int homescreen_get_i18n(const char *appid, const char *lang, char **name, char **desc) +{ + sqlite3_stmt *stmt; + static const char *query = "SELECT name, desc FROM desc WHERE appid = ? AND lang = ?"; + const unsigned char *_name; + const unsigned char *_desc; + int status; + + status = sqlite3_prepare_v2(s_info.handle, query, -1, &stmt, NULL); + if (status != SQLITE_OK) { + ErrPrint("Failed to prepare stmt: %s\n", sqlite3_errmsg(s_info.handle)); + return -EIO; + } + + status = sqlite3_bind_text(stmt, 1, appid, -1, SQLITE_TRANSIENT); + if (status != SQLITE_OK) { + ErrPrint("Failed to bind appid: %s\n", sqlite3_errmsg(s_info.handle)); + status = -EIO; + goto out; + } + + status = sqlite3_bind_text(stmt, 2, lang, -1, SQLITE_TRANSIENT); + if (status != SQLITE_OK) { + ErrPrint("Failed to bind lang: %s\n", sqlite3_errmsg(s_info.handle)); + status = -EIO; + goto out; + } + + if (SQLITE_ROW != sqlite3_step(stmt)) { + ErrPrint("Failed to do step: %s\n", sqlite3_errmsg(s_info.handle)); + status = -EIO; + goto out; + } + + if (name) { + _name = sqlite3_column_text(stmt, 0); + *name = _name ? strdup((const char *)_name) : NULL; + } + + if (desc) { + _desc = sqlite3_column_text(stmt, 1); + *desc = _desc ? strdup((const char *)_desc) : NULL; + } + +out: + sqlite3_reset(stmt); + sqlite3_clear_bindings(stmt); + sqlite3_finalize(stmt); + return status; +} + + + +/*! + * cb: SYNC callback + */ +EAPI int homescreen_get_description(const char *appid, void (*cb)(const char *appid, const char *icon, const char *name, const char *desc, void *data), void *data) +{ + sqlite3_stmt *stmt; + static const char *query = "SELECT icon, name, desc FROM homescreen WHERE appid = ?"; + char *i18n_name; + char *i18n_desc; + const unsigned char *desc; + const unsigned char *name; + const unsigned char *icon; + int ret; + + ret = sqlite3_prepare_v2(s_info.handle, query, -1, &stmt, NULL); + if (ret != SQLITE_OK) { + ErrPrint("Prepare failed: %s\n", sqlite3_errmsg(s_info.handle)); + ret = -EIO; + goto out; + } + + ret = sqlite3_bind_text(stmt, 1, appid, -1, SQLITE_TRANSIENT); + if (ret != SQLITE_OK) { + ErrPrint("Prepare failed: %s\n", sqlite3_errmsg(s_info.handle)); + ret = -EIO; + goto out; + } + + if (SQLITE_ROW != sqlite3_step(stmt)) { + ErrPrint("Step failed: %s\n", sqlite3_errmsg(s_info.handle)); + ret = -EIO; + goto out; + } + + icon = sqlite3_column_text(stmt, 0); + name = sqlite3_column_text(stmt, 1); + desc = sqlite3_column_text(stmt, 2); + + /*! + * \todo + * Get the i18n name and desc + */ + if (homescreen_get_i18n(appid, "en-us", &i18n_name, &i18n_desc) < 0) { + i18n_name = NULL; + i18n_desc = NULL; + } + + cb(appid, (const char *)icon, i18n_name ? i18n_name : (const char *)name, i18n_desc ? i18n_desc : (const char *)desc, data); + + free(i18n_name); + free(i18n_desc); + +out: + sqlite3_reset(stmt); + sqlite3_clear_bindings(stmt); + sqlite3_finalize(stmt); + return ret; +} + + + +EAPI char *homescreen_get_image(const char *appid, int idx) +{ + static const char *query = "SELECT path FROM image WHERE appid = ? AND id = ?"; + sqlite3_stmt *stmt; + int ret; + const unsigned char *path; + char *ret_path = NULL; + + ret = sqlite3_prepare_v2(s_info.handle, query, -1, &stmt, NULL); + if (ret != SQLITE_OK) { + ErrPrint("Prepare failed: %s\n", sqlite3_errmsg(s_info.handle)); + goto out; + } + + ret = sqlite3_bind_text(stmt, 1, appid, -1, SQLITE_TRANSIENT); + if (ret != SQLITE_OK) { + ErrPrint("bind failed: %s\n", sqlite3_errmsg(s_info.handle)); + goto out; + } + + ret = sqlite3_bind_int(stmt, 2, idx); + if (ret != SQLITE_OK) { + ErrPrint("bind failed: %s\n", sqlite3_errmsg(s_info.handle)); + goto out; + } + + if (SQLITE_ROW != sqlite3_step(stmt)) { + ErrPrint("Step failed: %s\n", sqlite3_errmsg(s_info.handle)); + goto out; + } + + path = sqlite3_column_text(stmt, 0); + if (!path) { + ErrPrint("Get result: %s\n", sqlite3_errmsg(s_info.handle)); + goto out; + } + + ret_path = strdup((const char *)path); + if (!ret_path) + ErrPrint("Heap: %s\n", strerror(errno)); + +out: + sqlite3_reset(stmt); + sqlite3_clear_bindings(stmt); + sqlite3_finalize(stmt); + return ret_path; +} + + + +EAPI int homescreen_get_image_count(const char *appid) +{ + static const char *query = "SELECT COUNT(id) FROM image WHERE appid = ?"; + sqlite3_stmt *stmt; + int ret; + + ret = sqlite3_prepare_v2(s_info.handle, query, -1, &stmt, NULL); + if (ret != SQLITE_OK) { + ErrPrint("bind failed: %s\n", sqlite3_errmsg(s_info.handle)); + ret = -EIO; + goto out; + } + + ret = sqlite3_bind_text(stmt, 1, appid, -1, SQLITE_TRANSIENT); + if (ret != SQLITE_OK) { + ErrPrint("bind failed: %s\n", sqlite3_errmsg(s_info.handle)); + ret = -EIO; + goto out; + } + + if (SQLITE_ROW != sqlite3_step(stmt)) { + ErrPrint("step failed: %s\n", sqlite3_errmsg(s_info.handle)); + ret = -EIO; + goto out; + } + + ret = sqlite3_column_int(stmt, 0); + +out: + sqlite3_reset(stmt); + sqlite3_clear_bindings(stmt); + sqlite3_finalize(stmt); + return ret; +} + + + +static inline char *cur_locale(void) +{ + char *language; + language = vconf_get_str(VCONFKEY_LANGSET); + if (language) { + char *ptr; + + ptr = language; + while (*ptr) { + if (*ptr == '.') { + *ptr = '\0'; + break; + } + + if (*ptr == '_') + *ptr = '-'; + + ptr++; + } + } else { + language = strdup("en-us"); + if (!language) + ErrPrint("Heap: %s\n", strerror(errno)); + } + + return language; +} + + + +/*! + * \note READ ONLY DB + */ +EAPI int shortcut_get_list(const char *appid, int (*cb)(const char *appid, const char *icon, const char *name, const char *extra_key, const char *extra_data, void *data), void *data) +{ + sqlite3_stmt *stmt; + const char *query; + const unsigned char *name; + char *i18n_name; + const unsigned char *extra_data; + const unsigned char *extra_key; + const unsigned char *icon; + int id; + int ret; + int cnt; + char *language; + + if (!s_info.db_opened) + s_info.db_opened = (open_db() == 0); + + if (!s_info.db_opened) { + ErrPrint("Failed to open a DB\n"); + return -EIO; + } + + language = cur_locale(); + if (!language) { + ErrPrint("Locale is not valid\n"); + return -EINVAL; + } + + if (appid) { + query = "SELECT id, appid, name, extra_key, extra_data, icon FROM shortcut_service WHERE appid = ?"; + ret = sqlite3_prepare_v2(s_info.handle, query, -1, &stmt, NULL); + if (ret != SQLITE_OK) { + ErrPrint("prepare: %s\n", sqlite3_errmsg(s_info.handle)); + free(language); + return -EIO; + } + + ret = sqlite3_bind_text(stmt, 1, appid, -1, SQLITE_TRANSIENT); + if (ret != SQLITE_OK) { + ErrPrint("bind text: %s\n", sqlite3_errmsg(s_info.handle)); + sqlite3_finalize(stmt); + free(language); + return -EIO; + } + } else { + query = "SELECT id, appid, name, extra_key, extra_data, icon FROM shortcut_service"; + ret = sqlite3_prepare_v2(s_info.handle, query, -1, &stmt, NULL); + if (ret != SQLITE_OK) { + ErrPrint("prepare: %s\n", sqlite3_errmsg(s_info.handle)); + free(language); + return -EIO; + } + } + + cnt = 0; + while (SQLITE_ROW == sqlite3_step(stmt)) { + id = sqlite3_column_int(stmt, 0); + + appid = (const char *)sqlite3_column_text(stmt, 1); + if (!appid) { + LOGE("Failed to get package name\n"); + continue; + } + + name = sqlite3_column_text(stmt, 2); + if (!name) { + LOGE("Failed to get name\n"); + continue; + } + + extra_key = sqlite3_column_text(stmt, 3); + if (!extra_key) { + LOGE("Failed to get service\n"); + continue; + } + + extra_data = sqlite3_column_text(stmt, 4); + if (!extra_data) { + LOGE("Failed to get service\n"); + continue; + } + + icon = sqlite3_column_text(stmt, 5); + if (!icon) { + LOGE("Failed to get icon\n"); + continue; + } + + /*! + * \todo + * Implement the "GET LOCALE" code + */ + i18n_name = get_i18n_name(language, id); + + cnt++; + if (cb(appid, (char *)icon, (i18n_name != NULL ? i18n_name : (char *)name), (char *)extra_key, (char *)extra_data, data) < 0) { + free(i18n_name); + break; + } + + free(i18n_name); + } + + sqlite3_reset(stmt); + sqlite3_clear_bindings(stmt); + sqlite3_finalize(stmt); + free(language); + return cnt; +} + + + +/* End of a file */ diff --git a/libshortcut.manifest b/libshortcut.manifest index a76fdba..f1055e7 100644 --- a/libshortcut.manifest +++ b/libshortcut.manifest @@ -1,5 +1,22 @@ + + + + + + + + + + + + + + + + diff --git a/packaging/libshortcut.spec b/packaging/libshortcut.spec index c04cf87..b53a521 100644 --- a/packaging/libshortcut.spec +++ b/packaging/libshortcut.spec @@ -1,17 +1,22 @@ -Name: libshortcut -Summary: Shortcut add feature supporting library -Version: 0.0.5 -Release: 0 -Group: main/devel -License: Apache License -Source0: %{name}-%{version}.tar.gz +Name: libshortcut +Summary: Shortcut add feature supporting library +Version: 0.3.20 +Release: 0 +Group: main/devel +License: Apache License +Source0: %{name}-%{version}.tar.gz Requires(post): /sbin/ldconfig Requires(postun): /sbin/ldconfig -BuildRequires: cmake, gettext-tools +BuildRequires: cmake, gettext-tools, coreutils BuildRequires: pkgconfig(glib-2.0) BuildRequires: pkgconfig(dlog) +BuildRequires: pkgconfig(db-util) +BuildRequires: pkgconfig(sqlite3) +BuildRequires: pkgconfig(com-core) +BuildRequires: pkgconfig(libxml-2.0) +BuildRequires: pkgconfig(vconf) %description [Shortcut] AddToHome feature supporting library for menu/home screen developers. @@ -35,6 +40,9 @@ make %{?jobs:-j%jobs} %install rm -rf %{buildroot} %make_install +mkdir -p %{buildroot}/opt/dbspace +touch %{buildroot}/opt/dbspace/.shortcut_service.db +touch %{buildroot}/opt/dbspace/.shortcut_service.db-journal %post @@ -44,9 +52,15 @@ rm -rf %{buildroot} %manifest libshortcut.manifest %defattr(-,root,root,-) %{_libdir}/*.so* +%{_prefix}/etc/package-manager/parserlib/* +%{_datarootdir}/license/* +%attr(640,root,app) /opt/dbspace/.shortcut_service.db +%attr(640,root,app) /opt/dbspace/.shortcut_service.db-journal %files devel %defattr(-,root,root,-) -%{_includedir}/shortcut/SLP_shortcut_PG.h +%{_includedir}/shortcut/shortcut_PG.h %{_includedir}/shortcut/shortcut.h %{_libdir}/pkgconfig/shortcut.pc + +# End of a file diff --git a/pkgmgr_shortcut/CMakeLists.txt b/pkgmgr_shortcut/CMakeLists.txt new file mode 100644 index 0000000..0a4abc7 --- /dev/null +++ b/pkgmgr_shortcut/CMakeLists.txt @@ -0,0 +1,31 @@ +PROJECT(shortcut-list C) + +INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/pkgmgr_shortcut/include) + +INCLUDE(FindPkgConfig) +pkg_check_modules(bin_pkgs REQUIRED + dlog + sqlite3 + libxml-2.0 + db-util +) + +FOREACH(flag ${bin_pkgs_CFLAGS}) + SET(EXTRA_CFLAGS "${EXTRA_CFLAGS} ${flag}") +ENDFOREACH(flag) + +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS} -g -Wall -Werror") + +ADD_DEFINITIONS("-DPREFIX=\"${PREFIX}\"") +ADD_DEFINITIONS("-DLOG_TAG=\"PKGMGR_SHORTCUT\"") + +ADD_LIBRARY(${PROJECT_NAME} SHARED + src/service_register.c + src/dlist.c +) + +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${bin_pkgs_LDFLAGS}) + +INSTALL(TARGETS ${PROJECT_NAME} DESTINATION "etc/package-manager/parserlib") + +# End of a file diff --git a/pkgmgr_shortcut/include/dlist.h b/pkgmgr_shortcut/include/dlist.h new file mode 100644 index 0000000..f840f92 --- /dev/null +++ b/pkgmgr_shortcut/include/dlist.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ + +#define dlist_remove_data(list, data) do { \ + struct dlist *l; \ + l = dlist_find_data(list, data); \ + list = dlist_remove(list, l); \ +} while (0) + +#define dlist_foreach(list, l, data) \ + for ((l) = (list); (l) && ((data) = dlist_data(l)); (l) = dlist_next(l)) + +#define dlist_foreach_safe(list, l, n, data) \ + for ((l) = (list), (n) = dlist_next(l); \ + (l) && ((data) = dlist_data(l)); \ + (l) = (n), (n) = dlist_next(l)) + +struct dlist; + +extern struct dlist *dlist_append(struct dlist *list, void *data); +extern struct dlist *dlist_prepend(struct dlist *list, void *data); +extern struct dlist *dlist_remove(struct dlist *list, struct dlist *l); +extern struct dlist *dlist_find_data(struct dlist *list, void *data); +extern void *dlist_data(struct dlist *l); +extern struct dlist *dlist_next(struct dlist *l); +extern struct dlist *dlist_prev(struct dlist *l); +extern int dlist_count(struct dlist *l); +extern struct dlist *dlist_nth(struct dlist *l, int nth); + +/* End of a file */ diff --git a/pkgmgr_shortcut/src/dlist.c b/pkgmgr_shortcut/src/dlist.c new file mode 100644 index 0000000..a212608 --- /dev/null +++ b/pkgmgr_shortcut/src/dlist.c @@ -0,0 +1,181 @@ +/* + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ + +#include +#include +#include + +#include "dlist.h" + +/*! + * \brief + * This dlist is called Modified Doubly Linked List. + * + * Noramlly, The dobule linked list contains address of previous and next element. + * This dlist also contains them, but the tail element only contains prev address. + * + * The head element's prev pointer indicates the last element. + * But the last element's next pointer indicates NIL. + * + * So we can find the last element while crawling this DList + * But we have to remember the address of the head element. + */ + +struct dlist { + struct dlist *next; + struct dlist *prev; + void *data; +}; + +struct dlist *dlist_append(struct dlist *list, void *data) +{ + struct dlist *item; + + item = malloc(sizeof(*item)); + if (!item) + return NULL; + + item->next = NULL; + item->data = data; + + if (!list) { + item->prev = item; + + list = item; + } else { + item->prev = list->prev; + item->prev->next = item; + list->prev = item; + } + + assert(!list->prev->next && "item NEXT"); + + return list; +} + +struct dlist *dlist_prepend(struct dlist *list, void *data) +{ + struct dlist *item; + + item = malloc(sizeof(*item)); + if (!item) + return NULL; + + item->data = data; + + if (!list) { + item->prev = item; + item->next = NULL; + } else { + if (list->prev->next) + list->prev->next = item; + + item->prev = list->prev; + item->next = list; + + list->prev = item; + + } + + return item; +} + +struct dlist *dlist_remove(struct dlist *list, struct dlist *l) +{ + if (!list || !l) + return NULL; + + if (l == list) + list = l->next; + else + l->prev->next = l->next; + + if (l->next) + l->next->prev = l->prev; + /*! + * \note + * If the removed entry 'l' has no next element, it is the last element. + * In this case, check the existence of the list first, + * and if the list is not empty, update the 'prev' of the list (which is a head element of the list) + * + * If we didn't care about this, the head element(list) can indicates the invalid element. + */ + else if (list) + list->prev = l->prev; + + free(l); + return list; +} + +struct dlist *dlist_find_data(struct dlist *list, void *data) +{ + struct dlist *l; + void *_data; + + dlist_foreach(list, l, _data) { + if (data == _data) + return l; + } + + return NULL; +} + +void *dlist_data(struct dlist *l) +{ + return l ? l->data : NULL; +} + +struct dlist *dlist_next(struct dlist *l) +{ + return l ? l->next : NULL; +} + +struct dlist *dlist_prev(struct dlist *l) +{ + return l ? l->prev : NULL; +} + +int dlist_count(struct dlist *l) +{ + register int i; + struct dlist *n; + void *data; + + i = 0; + dlist_foreach(l, n, data) { + i++; + } + + return i; +} + +struct dlist *dlist_nth(struct dlist *l, int nth) +{ + register int i; + struct dlist *n; + + i = 0; + for (n = l; n; n = n->next) { + if (i == nth) + return n; + i++; + } + + return NULL; +} + +/* End of a file */ diff --git a/pkgmgr_shortcut/src/service_register.c b/pkgmgr_shortcut/src/service_register.c new file mode 100644 index 0000000..50b5ae2 --- /dev/null +++ b/pkgmgr_shortcut/src/service_register.c @@ -0,0 +1,756 @@ +/* + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * +*/ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "dlist.h" + +#if !defined(FLOG) +#define DbgPrint(format, arg...) LOGD("[%s/%s:%d] " format, basename(__FILE__), __func__, __LINE__, ##arg) +#define ErrPrint(format, arg...) LOGE("[%s/%s:%d] " format, basename(__FILE__), __func__, __LINE__, ##arg) +#endif +/* End of a file */ + +/*! + * DB Table schema + * + * +----+-------+------+---------+-----------+------------+ + * | id | appid | Icon | Name | extra_key | extra_data | + * +----+-------+------+---------+-----------+------------+ + * | id | - | - | - | - | - | + * +----+-------+------+---------+-----------+------------+ + * + * +----+------+------+ + * | fk | lang | name | + * +----+------+------+ + * | id | - | - | + * +----+------+------+ + */ + +#if !defined(LIBXML_TREE_ENABLED) + #error "LIBXML is not supporting the tree" +#endif + +int errno; + +static struct { + const char *dbfile; + sqlite3 *handle; +} s_info = { + .dbfile = "/opt/dbspace/.shortcut_service.db", + .handle = NULL, +}; + +static inline int begin_transaction(void) +{ + sqlite3_stmt *stmt; + int ret; + + ret = sqlite3_prepare_v2(s_info.handle, "BEGIN TRANSACTION", -1, &stmt, NULL); + if (ret != SQLITE_OK) { + DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle)); + return EXIT_FAILURE; + } + + if (sqlite3_step(stmt) != SQLITE_DONE) { + DbgPrint("Failed to do update (%s)\n", + sqlite3_errmsg(s_info.handle)); + sqlite3_finalize(stmt); + return EXIT_FAILURE; + } + + sqlite3_finalize(stmt); + return EXIT_SUCCESS; +} + +static inline int rollback_transaction(void) +{ + int ret; + sqlite3_stmt *stmt; + + ret = sqlite3_prepare_v2(s_info.handle, "ROLLBACK TRANSACTION", -1, &stmt, NULL); + if (ret != SQLITE_OK) { + DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle)); + return EXIT_FAILURE; + } + + if (sqlite3_step(stmt) != SQLITE_DONE) { + DbgPrint("Failed to do update (%s)\n", + sqlite3_errmsg(s_info.handle)); + sqlite3_finalize(stmt); + return EXIT_FAILURE; + } + + sqlite3_finalize(stmt); + return EXIT_SUCCESS; +} + +static inline int commit_transaction(void) +{ + sqlite3_stmt *stmt; + int ret; + + ret = sqlite3_prepare_v2(s_info.handle, "COMMIT TRANSACTION", -1, &stmt, NULL); + if (ret != SQLITE_OK) { + DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle)); + return EXIT_FAILURE; + } + + if (sqlite3_step(stmt) != SQLITE_DONE) { + DbgPrint("Failed to do update (%s)\n", + sqlite3_errmsg(s_info.handle)); + sqlite3_finalize(stmt); + return EXIT_FAILURE; + } + + sqlite3_finalize(stmt); + return EXIT_SUCCESS; +} +static inline void db_create_table(void) +{ + char *err; + static const char *ddl = + "CREATE TABLE shortcut_service (" + "id INTEGER PRIMARY KEY AUTOINCREMENT, " + "appid TEXT, " + "icon TEXT, " + "name TEXT, " + "extra_key TEXT, " + "extra_data TEXT)"; + + if (sqlite3_exec(s_info.handle, ddl, NULL, NULL, &err) != SQLITE_OK) { + ErrPrint("Failed to execute the DDL (%s)\n", err); + return; + } + + if (sqlite3_changes(s_info.handle) == 0) + ErrPrint("No changes to DB\n"); + + ddl = "CREATE TABLE shortcut_name (id INTEGER, lang TEXT, name TEXT)"; + if (sqlite3_exec(s_info.handle, ddl, NULL, NULL, &err) != SQLITE_OK) { + ErrPrint("Failed to execute the DDL (%s)\n", err); + return; + } + + if (sqlite3_changes(s_info.handle) == 0) + ErrPrint("No changes to DB\n"); +} + +static inline int db_remove_record(const char *appid, const char *key, const char *data) +{ + static const char *dml = "DELETE FROM shortcut_service WHERE appid = ? AND extra_key = ? AND extra_data = ?"; + sqlite3_stmt *stmt; + int ret; + + if (!appid || !key || !data) { + ErrPrint("Invalid argument\n"); + return -EINVAL; + } + + ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL); + if (ret != SQLITE_OK) { + ErrPrint("Failed to prepare the initial DML(%s)\n", sqlite3_errmsg(s_info.handle)); + return -EIO; + } + + ret = -EIO; + if (sqlite3_bind_text(stmt, 1, appid, -1, SQLITE_TRANSIENT) != SQLITE_OK) { + ErrPrint("Failed to bind a appid(%s)\n", sqlite3_errmsg(s_info.handle)); + goto out; + } + + if (sqlite3_bind_text(stmt, 2, key, -1, SQLITE_TRANSIENT) != SQLITE_OK) { + ErrPrint("Failed to bind a key(%s)\n", sqlite3_errmsg(s_info.handle)); + goto out; + } + + if (sqlite3_bind_text(stmt, 3, data, -1, SQLITE_TRANSIENT) != SQLITE_OK) { + ErrPrint("Failed to bind a data(%s)\n", sqlite3_errmsg(s_info.handle)); + goto out; + } + + ret = 0; + if (sqlite3_step(stmt) != SQLITE_DONE) { + ret = -EIO; + ErrPrint("Failed to execute the DML for %s - %s(%s)\n", appid, key, data); + } + + if (sqlite3_changes(s_info.handle) == 0) + DbgPrint("No changes\n"); + +out: + sqlite3_reset(stmt); + sqlite3_clear_bindings(stmt); + sqlite3_finalize(stmt); + return ret; +} + +static inline int db_remove_name(int id) +{ + static const char *dml = "DELETE FROM shortcut_name WHERE id = ?"; + sqlite3_stmt *stmt; + int ret; + + if (id < 0) { + ErrPrint("Inavlid id\n"); + return -EINVAL; + } + + ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL); + if (ret != SQLITE_OK) { + ErrPrint("Failed to prepare the initial DML(%s)\n", sqlite3_errmsg(s_info.handle)); + return -EIO; + } + + if (sqlite3_bind_int(stmt, 1, id) != SQLITE_OK) { + ErrPrint("Failed to bind id(%d)\n", id); + ret = -EIO; + goto out; + } + + ret = 0; + if (sqlite3_step(stmt) != SQLITE_DONE) { + ret = -EIO; + ErrPrint("Failed to execute the DML for %d\n", id); + goto out; + } + + if (sqlite3_changes(s_info.handle) == 0) + DbgPrint("No changes\n"); + +out: + sqlite3_reset(stmt); + sqlite3_clear_bindings(stmt); + sqlite3_finalize(stmt); + return ret; +} + +static inline int db_insert_record(const char *appid, const char *icon, const char *name, const char *key, const char *data) +{ + static const char *dml = "INSERT INTO shortcut_service (appid, icon, name, extra_key, extra_data) VALUES (?, ?, ?, ?, ?)"; + sqlite3_stmt *stmt; + int ret; + + if (!appid) { + ErrPrint("Failed to get appid\n"); + return -EINVAL; + } + + if (!name) { + ErrPrint("Failed to get name\n"); + return -EINVAL; + } + + if (!key) { + ErrPrint("Failed to get key\n"); + return -EINVAL; + } + + if (!data) { + ErrPrint("Faield to get key\n"); + return -EINVAL; + } + + icon = icon ? icon : ""; + + ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL); + if (ret != SQLITE_OK) { + ErrPrint("Failed to prepare the initial DML(%s)\n", sqlite3_errmsg(s_info.handle)); + return -EIO; + } + + ret = -EIO; + if (sqlite3_bind_text(stmt, 1, appid, -1, SQLITE_TRANSIENT) != SQLITE_OK) { + ErrPrint("Failed to bind a appid(%s)\n", sqlite3_errmsg(s_info.handle)); + goto out; + } + + if (sqlite3_bind_text(stmt, 2, icon, -1, SQLITE_TRANSIENT) != SQLITE_OK) { + ErrPrint("Failed to bind a icon(%s)\n", sqlite3_errmsg(s_info.handle)); + goto out; + } + + if (sqlite3_bind_text(stmt, 3, name, -1, SQLITE_TRANSIENT) != SQLITE_OK) { + ErrPrint("Failed to bind a name(%s)\n", sqlite3_errmsg(s_info.handle)); + goto out; + } + + if (sqlite3_bind_text(stmt, 4, key, -1, SQLITE_TRANSIENT) != SQLITE_OK) { + ErrPrint("Failed to bind a service(%s)\n", sqlite3_errmsg(s_info.handle)); + goto out; + } + + if (sqlite3_bind_text(stmt, 5, data, -1, SQLITE_TRANSIENT) != SQLITE_OK) { + ErrPrint("Failed to bind a service(%s)\n", sqlite3_errmsg(s_info.handle)); + goto out; + } + + ret = 0; + if (sqlite3_step(stmt) != SQLITE_DONE) { + ErrPrint("Failed to execute the DML for %s - %s\n", appid, name); + ret = -EIO; + } + +out: + sqlite3_reset(stmt); + sqlite3_clear_bindings(stmt); + sqlite3_finalize(stmt); + return ret; +} + +static inline int db_insert_name(int id, const char *lang, const char *name) +{ + static const char *dml = "INSERT INTO shortcut_name (id, lang, name) VALUES (?, ?, ?)"; + sqlite3_stmt *stmt; + int ret; + + if (id < 0 || !lang || !name) { + ErrPrint("Invalid parameters\n"); + return -EINVAL; + } + + ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL); + if (ret != SQLITE_OK) { + ErrPrint("Failed to prepare the initial DML(%s)\n", sqlite3_errmsg(s_info.handle)); + return -EIO; + } + + if (sqlite3_bind_int(stmt, 1, id) != SQLITE_OK) { + ErrPrint("Failed to bind a id(%s)\n", sqlite3_errmsg(s_info.handle)); + ret = -EIO; + goto out; + } + + if (sqlite3_bind_text(stmt, 2, lang, -1, SQLITE_TRANSIENT) != SQLITE_OK) { + ErrPrint("Failed to bind a id(%s)\n", sqlite3_errmsg(s_info.handle)); + ret = -EIO; + goto out; + } + + if (sqlite3_bind_text(stmt, 3, name, -1, SQLITE_TRANSIENT) != SQLITE_OK) { + ErrPrint("Failed to bind a id(%s)\n", sqlite3_errmsg(s_info.handle)); + ret = -EIO; + goto out; + } + + ret = 0; + if (sqlite3_step(stmt) != SQLITE_DONE) { + ErrPrint("Failed to execute the DML for %d %s %s\n", id, lang, name); + ret = -EIO; + } + +out: + sqlite3_reset(stmt); + sqlite3_clear_bindings(stmt); + sqlite3_finalize(stmt); + return ret; +} + +static inline int db_get_id(const char *appid, const char *key, const char *data) +{ + static const char *dml = "SELECT id FROM shortcut_service WHERE appid = ? AND extra_key = ? AND extra_data = ?"; + sqlite3_stmt *stmt; + int ret; + + if (!appid || !key || !data) { + ErrPrint("Invalid argument\n"); + return -EINVAL; + } + + ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL); + if (ret != SQLITE_OK) { + ErrPrint("Failed to prepare the initial DML(%s)\n", sqlite3_errmsg(s_info.handle)); + return -EIO; + } + + ret = -EIO; + if (sqlite3_bind_text(stmt, 1, appid, -1, SQLITE_TRANSIENT) != SQLITE_OK) { + ErrPrint("Failed to bind a appid(%s) - %s\n", appid, sqlite3_errmsg(s_info.handle)); + goto out; + } + + if (sqlite3_bind_text(stmt, 2, key, -1, SQLITE_TRANSIENT) != SQLITE_OK) { + ErrPrint("Failed to bind a key(%s) - %s\n", key, sqlite3_errmsg(s_info.handle)); + goto out; + } + + if (sqlite3_bind_text(stmt, 3, data, -1, SQLITE_TRANSIENT) != SQLITE_OK) { + ErrPrint("Failed to bind a data(%s) - %s\n", data, sqlite3_errmsg(s_info.handle)); + goto out; + } + + if (sqlite3_step(stmt) != SQLITE_ROW) { + ErrPrint("Failed to execute the DML for %s - %s, %s\n", appid, key, data); + ret = -EIO; + goto out; + } + + ret = sqlite3_column_int(stmt, 0); + +out: + sqlite3_reset(stmt); + sqlite3_clear_bindings(stmt); + sqlite3_finalize(stmt); + return ret; +} + +static inline int db_init(void) +{ + int ret; + struct stat stat; + + ret = db_util_open(s_info.dbfile, &s_info.handle, DB_UTIL_REGISTER_HOOK_METHOD); + if (ret != SQLITE_OK) { + ErrPrint("Failed to open a DB\n"); + return -EIO; + } + + if (lstat(s_info.dbfile, &stat) < 0) { + ErrPrint("%s\n", strerror(errno)); + db_util_close(s_info.handle); + s_info.handle = NULL; + return -EIO; + } + + if (!S_ISREG(stat.st_mode)) { + ErrPrint("Invalid file\n"); + db_util_close(s_info.handle); + s_info.handle = NULL; + return -EINVAL; + } + + if (!stat.st_size) + db_create_table(); + + return 0; +} + +static inline int db_fini(void) +{ + if (!s_info.handle) + return 0; + + db_util_close(s_info.handle); + s_info.handle = NULL; + + return 0; +} + +int PKGMGR_PARSER_PLUGIN_UNINSTALL(xmlDocPtr docPtr, const char *_appid) +{ + xmlNodePtr node = NULL; + xmlChar *key; + xmlChar *data; + xmlChar *appid; + xmlNodePtr root; + int id; + + root = xmlDocGetRootElement(docPtr); + if (!root) { + ErrPrint("Invalid node ptr\n"); + return -EINVAL; + } + + if (!s_info.handle) { + if (db_init() < 0) + return -EIO; + } + + for (root = root->children; root; root = root->next) { + if (!xmlStrcasecmp(root->name, (const xmlChar *)"shortcut-list")) + break; + } + + if (!root) { + ErrPrint("Root has no shortcut-list\n"); + return -EINVAL; + } + + DbgPrint("AppID: %s\n", _appid); + root = root->children; + for (node = root; node; node = node->next) { + if (node->type == XML_ELEMENT_NODE) + DbgPrint("Element %s\n", node->name); + + if (xmlStrcasecmp(node->name, (const xmlChar *)"shortcut")) + continue; + + if (!xmlHasProp(node, (xmlChar *)"extra_data") + || !xmlHasProp(node, (xmlChar *)"extra_key") + || !xmlHasProp(node, (xmlChar *)"appid")) + { + DbgPrint("Invalid element %s\n", node->name); + continue; + } + + appid = xmlGetProp(node, (xmlChar *)"appid"); + key = xmlGetProp(node, (xmlChar *)"extra_key"); + data = xmlGetProp(node, (xmlChar *)"extra_data"); + + DbgPrint("appid: %s\n", appid); + DbgPrint("key: %s\n", key); + DbgPrint("data: %s\n", data); + + id = db_get_id((char *)appid, (char *)key, (char *)data); + if (id < 0) { + ErrPrint("No records found\n"); + xmlFree(appid); + xmlFree(key); + xmlFree(data); + continue; + } + + begin_transaction(); + if (db_remove_record((char *)appid, (char *)key, (char *)data) < 0) { + ErrPrint("Failed to remove a record\n"); + rollback_transaction(); + xmlFree(appid); + xmlFree(key); + xmlFree(data); + continue; + } + + if (db_remove_name(id) < 0) { + ErrPrint("Failed to remove name records\n"); + rollback_transaction(); + xmlFree(appid); + xmlFree(key); + xmlFree(data); + continue; + } + commit_transaction(); + xmlFree(appid); + xmlFree(key); + xmlFree(data); + + /*! + * \note + * if (node->children) + * DbgPrint("Skip this node's children\n"); + */ + } + + return 0; +} + +int PKGMGR_PARSER_PLUGIN_INSTALL(xmlDocPtr docPtr, const char *appid) +{ + xmlNodePtr node = NULL; + xmlNodePtr child = NULL; + xmlChar *key; + xmlChar *data; + xmlChar *name; + xmlChar *icon; + xmlChar *shortcut_appid; + xmlNodePtr root; + struct i18n_name { + xmlChar *name; + xmlChar *lang; + } *i18n; + struct dlist *i18n_list = NULL; + struct dlist *l; + struct dlist *n; + int id; + + root = xmlDocGetRootElement(docPtr); + if (!root) { + ErrPrint("Invalid node ptr\n"); + return -EINVAL; + } + + if (!s_info.handle) { + if (db_init() < 0) + return -EIO; + } + + for (root = root->children; root; root = root->next) { + if (!xmlStrcasecmp(root->name, (const xmlChar *)"shortcut-list")) + break; + } + + if (!root) { + ErrPrint("Root has no children\n"); + return -EINVAL; + } + + DbgPrint("AppID: %s\n", appid); + + root = root->children; /* Jump to children node */ + for (node = root; node; node = node->next) { + if (node->type == XML_ELEMENT_NODE) + DbgPrint("Element %s\n", node->name); + + if (xmlStrcasecmp(node->name, (const xmlChar *)"shortcut")) + continue; + + if (!xmlHasProp(node, (xmlChar *)"extra_key") || !xmlHasProp(node, (xmlChar *)"extra_data")) { + DbgPrint("Invalid element %s\n", node->name); + continue; + } + + key = xmlGetProp(node, (xmlChar *)"extra_key"); + data = xmlGetProp(node, (xmlChar *)"extra_data"); + shortcut_appid = xmlGetProp(node, (xmlChar *)"appid"); + + icon = NULL; + name = NULL; + for (child = node->children; child; child = child->next) { + if (!xmlStrcasecmp(child->name, (const xmlChar *)"icon")) { + if (icon) { + DbgPrint("Icon is duplicated\n"); + continue; + } + + icon = xmlNodeGetContent(child); + continue; + } + + if (!xmlStrcasecmp(child->name, (const xmlChar *)"label")) { + xmlChar *lang; + lang = xmlNodeGetLang(child); + if (!lang) { + if (name) { + DbgPrint("Default name is duplicated\n"); + } else { + name = xmlNodeGetContent(child); + DbgPrint("Default name is %s\n", name); + } + + continue; + } + + i18n = malloc(sizeof(*i18n)); + if (!i18n) { + ErrPrint("Heap: %s\n", strerror(errno)); + break; + } + + i18n->lang = lang; + i18n->name = xmlNodeGetContent(child); + i18n_list = dlist_append(i18n_list, i18n); + continue; + } + } + + DbgPrint("appid: %s\n", appid); + DbgPrint("shortcut appid: %s\n", shortcut_appid); + DbgPrint("key: %s\n", key); + DbgPrint("data: %s\n", data); + DbgPrint("icon: %s\n", icon); + DbgPrint("Default name: %s\n", name); + + if (!shortcut_appid) { + shortcut_appid = xmlStrdup((xmlChar *)appid); + DbgPrint("Use the default appid\n"); + } + + begin_transaction(); + if (db_insert_record((char *)shortcut_appid, (char *)icon, (char *)name, (char *)key, (char *)data) < 0) { + ErrPrint("Failed to insert a new record\n"); + rollback_transaction(); + + dlist_foreach_safe(i18n_list, l, n, i18n) { + i18n_list = dlist_remove(i18n_list, l); + xmlFree(i18n->lang); + xmlFree(i18n->name); + free(i18n); + } + } else { + id = db_get_id((char *)shortcut_appid, (char *)key, (char *)data); + if (id < 0) { + ErrPrint("Failed to insert a new record\n"); + rollback_transaction(); + + dlist_foreach_safe(i18n_list, l, n, i18n) { + i18n_list = dlist_remove(i18n_list, l); + xmlFree(i18n->lang); + xmlFree(i18n->name); + free(i18n); + } + } else { + dlist_foreach_safe(i18n_list, l, n, i18n) { + i18n_list = dlist_remove(i18n_list, l); + if (db_insert_name(id, (char *)i18n->lang, (char *)i18n->name) < 0) + ErrPrint("Failed to add i18n name: %s(%s)\n", i18n->name, i18n->lang); + xmlFree(i18n->lang); + xmlFree(i18n->name); + free(i18n); + } + commit_transaction(); + } + } + + xmlFree(key); + xmlFree(data); + xmlFree(icon); + xmlFree(name); + xmlFree(shortcut_appid); + } + + return 0; +} + +int PKGMGR_PARSER_PLUGIN_UPGRADE(xmlDocPtr docPtr, const char *appid) +{ + /* So... ugly */ + PKGMGR_PARSER_PLUGIN_UNINSTALL(docPtr, appid); + PKGMGR_PARSER_PLUGIN_INSTALL(docPtr, appid); + return 0; +} + +/* +int main(int argc, char *argv[]) +{ + xmlDoc *doc; + xmlNode *root; + + if (argc != 2) { + ErrPRint("Invalid argument: %s XML_FILENAME\n", argv[0]); + return -EINVAL; + } + + doc = xmlReadFile(argv[1], NULL, 0); + if (!doc) { + ErrPrint("Failed to parse %s\n", argv[1]); + return -EIO; + } + + root = xmlDocGetRootElement(doc); + + db_init(); + install_shortcut("", root); + db_fini(); + + xmlFreeDoc(doc); + xmlCleanupParser(); + return 0; +} +*/ + +/* End of a file */ diff --git a/sample.xml b/sample.xml new file mode 100644 index 0000000..0e471a0 --- /dev/null +++ b/sample.xml @@ -0,0 +1,62 @@ + + + + + /opt/usr/apps/org.tizen.myapp/res/icon/myapp_shortcut01.png + + + + + + + + + + + + + + + + + + + /opt/usr/apps/org.tizen.myapp/res/icon/gadget_shortcut01.png + + + + + + + + + + + + + + + + + + + /opt/usr/apps/org.tizen.myapp/res/icon/mayapp_shortcut02.png + + + + + + + + + + + + + + + + + + + diff --git a/src/main.c b/src/main.c deleted file mode 100644 index ef4d76e..0000000 --- a/src/main.c +++ /dev/null @@ -1,791 +0,0 @@ -/* - * Copyright 2012 Samsung Electronics Co., Ltd - * - * Licensed under the Flora License, Version 1.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.tizenopensource.org/license - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - - - -#define EAPI __attribute__((visibility("default"))) - - - -extern int errno; - - - -struct server_cb { - request_cb_t request_cb; - void *data; -}; - - - -struct client_cb { - result_cb_t result_cb; - void *data; -}; - - - -static struct info { - pthread_mutex_t server_mutex; - int server_fd; - const char *socket_file; - struct server_cb server_cb; - unsigned int seq; -} s_info = { - .server_mutex = PTHREAD_MUTEX_INITIALIZER, - .server_fd = -1, - .socket_file = "/tmp/.shortcut", - .seq = 0, -}; - - - -struct packet { - struct { - unsigned int seq; - enum { - PACKET_ERR = 0x0, - PACKET_REQ, - PACKET_ACK, - PACKET_MAX = 0xFF, /* MAX */ - } type; - - int payload_size; - - union { - struct { - int shortcut_type; - struct { - int pkgname; - int name; - int exec; - int icon; - } field_size; - } req; - - struct { - int ret; - } ack; - } data; - } head; - - char payload[]; -}; - - - -struct connection_state { - void *data; - struct packet packet; - enum { - BEGIN, - HEADER, - PAYLOAD, - END, - ERROR, - } state; - int length; - int from_pid; - char *payload; -}; - - - -static inline -gboolean check_reply_service(int conn_fd, struct connection_state *state) -{ - struct client_cb *client_cb = state->data; - - if (client_cb->result_cb) { - /* If the callback return FAILURE, - * remove itself from the callback list */ - client_cb->result_cb(state->packet.head.data.ack.ret, - state->from_pid, client_cb->data); - } - - state->state = BEGIN; - state->length = 0; - state->from_pid = 0; - - /* NOTE: If we want close the connection, returns FALSE */ - return FALSE; -} - - - -static inline -gboolean do_reply_service(int conn_fd, struct connection_state *state) -{ - int ret; - struct packet send_packet; - - ret = -ENOSYS; - if (s_info.server_cb.request_cb) { - char *pkgname; - char *name; - char *exec; - char *icon; - - if (state->packet.head.data.req.field_size.pkgname) - pkgname = state->payload; - else - pkgname = NULL; - - if (state->packet.head.data.req.field_size.name) - name = state->payload + state->packet.head.data.req.field_size.pkgname; - else - name = NULL; - - if (state->packet.head.data.req.field_size.exec) { - exec = state->payload + state->packet.head.data.req.field_size.pkgname; - exec += state->packet.head.data.req.field_size.name; - } else { - exec = NULL; - } - - if (state->packet.head.data.req.field_size.icon) { - icon = state->payload + state->packet.head.data.req.field_size.pkgname; - icon += state->packet.head.data.req.field_size.name; - icon += state->packet.head.data.req.field_size.exec; - } else { - icon = NULL; - } - - LOGD("Pkgname: [%s] Type: [%x], Name: [%s], Exec: [%s], Icon: [%s]\n", - pkgname, - state->packet.head.data.req.shortcut_type, - name, - exec, - icon); - - ret = s_info.server_cb.request_cb( - pkgname, - name, - state->packet.head.data.req.shortcut_type, - exec, - icon, - state->from_pid, - s_info.server_cb.data); - } - - send_packet.head.type = PACKET_ACK; - send_packet.head.payload_size = 0; - send_packet.head.seq = state->packet.head.seq; - send_packet.head.data.ack.ret = ret; - - if (secom_send(conn_fd, (const char*)&send_packet, sizeof(send_packet)) != sizeof(send_packet)) { - LOGE("Faield to send ack packet\n"); - return FALSE; - } - - state->state = BEGIN; - state->length = 0; - state->from_pid = 0; - return TRUE; -} - - - -static inline -gboolean filling_payload(int conn_fd, struct connection_state *state) -{ - if (state->length < state->packet.head.payload_size) { - int ret; - int check_pid; - - ret = secom_recv(conn_fd, - state->payload + state->length, - state->packet.head.payload_size - state->length, - &check_pid); - if (ret < 0) - return FALSE; - - if (state->from_pid != check_pid) { - LOGD("PID is not matched (%d, expected %d)\n", - check_pid, state->from_pid); - return FALSE; - } - - state->length += ret; - } - - if (state->length == state->packet.head.payload_size) { - state->length = 0; - state->state = END; - } - - return TRUE; -} - - - -static inline -gboolean deal_error_packet(int conn_fd, struct connection_state *state) -{ - if (state->length < state->packet.head.payload_size) { - int ret; - char *buf; - int check_pid; - - buf = alloca(state->packet.head.payload_size - state->length); - - ret = secom_recv(conn_fd, - buf, - state->packet.head.payload_size - state->length, - &check_pid); - if (ret < 0) - return FALSE; - - if (check_pid != state->from_pid) - LOGD("PID is not matched (%d, expected %d)\n", - check_pid, state->from_pid); - - state->length += ret; - } - - if (state->length < state->packet.head.payload_size) - return TRUE; - - /* Now, drop this connection */ - return FALSE; -} - - - -static inline -gboolean filling_header(int conn_fd, struct connection_state *state) -{ - if (state->length < sizeof(state->packet)) { - int ret; - int check_pid; - - ret = secom_recv(conn_fd, - ((char*)&state->packet) + state->length, - sizeof(state->packet) - state->length, - &check_pid); - if (ret < 0) - return FALSE; - - if (state->from_pid == 0) - state->from_pid = check_pid; - - if (state->from_pid != check_pid) { - LOGD("PID is not matched (%d, expected %d)\n", - check_pid, state->from_pid); - return FALSE; - } - - state->length += ret; - } - - if (state->length < sizeof(state->packet)) - return TRUE; - - if (state->packet.head.type == PACKET_ACK) { - state->length = 0; - - if (state->packet.head.payload_size) - state->state = ERROR; - else - state->state = END; - } else if (state->packet.head.type == PACKET_REQ) { - /* Let's take the next part. */ - state->state = PAYLOAD; - state->length = 0; - - state->payload = calloc(1, state->packet.head.payload_size); - if (!state->payload) { - LOGE("Heap: %s\n", strerror(errno)); - return FALSE; - } - } else { - LOGE("Invalid packet type\n"); - return FALSE; - } - - return TRUE; -} - - - -static -gboolean client_connection_cb(GIOChannel *src, GIOCondition cond, gpointer data) -{ - int conn_fd = -1; - gboolean ret; - int read_size; - struct connection_state *state = data; - struct client_cb *client_cb = state->data; - - if (!(cond & G_IO_IN)) { - LOGE("Condition value is unexpected value\n"); - ret = FALSE; - goto out; - } - - conn_fd = g_io_channel_unix_get_fd(src); - - if (ioctl(conn_fd, FIONREAD, &read_size) < 0) { - LOGE("Failed to get q size\n"); - ret = FALSE; - goto out; - } - - if (read_size == 0) { - if (client_cb->result_cb) { - /* If the callback return FAILURE, - * remove itself from the callback list */ - client_cb->result_cb(-ECONNABORTED, - state->from_pid, client_cb->data); - } - ret = FALSE; - goto out; - } - - switch (state->state) { - case BEGIN: - state->state = HEADER; - case HEADER: - ret = filling_header(conn_fd, state); - break; - case ERROR: - ret = deal_error_packet(conn_fd, state); - break; - default: - ret = FALSE; - break; - } - - if (state->state == END) - ret = check_reply_service(conn_fd, state); - -out: - if (ret == FALSE) { - if (conn_fd >= 0) - close(conn_fd); - free(state->data); - free(state); - } - - return ret; -} - - - -static -gboolean connection_cb(GIOChannel *src, GIOCondition cond, gpointer data) -{ - int conn_fd = -1; - struct connection_state *state = data; - gboolean ret; - int read_size; - - if (!(cond & G_IO_IN)) { - ret = FALSE; - goto out; - } - - conn_fd = g_io_channel_unix_get_fd(src); - - if (ioctl(conn_fd, FIONREAD, &read_size) < 0) { - LOGE("Failed to get q size\n"); - ret = FALSE; - goto out; - } - - if (read_size == 0) { - LOGE("Disconnected\n"); - ret = FALSE; - goto out; - } - - switch (state->state) { - case BEGIN: - state->state = HEADER; - case HEADER: - ret = filling_header(conn_fd, state); - break; - case PAYLOAD: - ret = filling_payload(conn_fd, state); - break; - default: - LOGE("[%s:%d] Invalid state(%x)\n", - __func__, __LINE__, state->state); - ret = FALSE; - break; - } - - if (state->state == END) { - ret = do_reply_service(conn_fd, state); - if (state->payload) { - free(state->payload); - state->payload = NULL; - } - - memset(&state->packet, 0, sizeof(state->packet)); - } - -out: - if (ret == FALSE) { - if (conn_fd >= 0) - secom_put_connection_handle(conn_fd); - - if (state->payload) - free(state->payload); - - free(state); - } - - return ret; -} - - - -static -gboolean accept_cb(GIOChannel *src, GIOCondition cond, gpointer data) -{ - int server_fd; - int connection_fd; - GIOChannel *gio; - guint id; - struct connection_state *state; - - server_fd = g_io_channel_unix_get_fd(src); - if (server_fd != s_info.server_fd) { - LOGE("Unknown FD is gotten.\n"); - /* NOTE: - * In this case, don't try to do anything. - * This is not recoverble error */ - return FALSE; - } - - if (!(cond & G_IO_IN)) { - close(s_info.server_fd); - if (pthread_mutex_lock(&s_info.server_mutex) != 0) - LOGE("[%s:%d] Failed to get lock (%s)\n", - __func__, __LINE__, strerror(errno)); - s_info.server_fd = -1; - if (pthread_mutex_unlock(&s_info.server_mutex) != 0) - LOGE("[%s:%d] Failed to do unlock mutex (%s)\n", - __func__, __LINE__, strerror(errno)); - return FALSE; - } - - connection_fd = secom_get_connection_handle(server_fd); - if (connection_fd < 0) { - /* Error log will be printed from - * get_connection_handle function */ - return FALSE; - } - - if (fcntl(connection_fd, F_SETFD, FD_CLOEXEC) < 0) - LOGE("Error: %s\n", strerror(errno)); - - if (fcntl(connection_fd, F_SETFL, O_NONBLOCK) < 0) - LOGE("Error: %s\n", strerror(errno)); - - gio = g_io_channel_unix_new(connection_fd); - if (!gio) { - LOGE("Failed to create a new connection channel\n"); - secom_put_connection_handle(connection_fd); - return FALSE; - } - - state = calloc(1, sizeof(*state)); - if (!state) { - LOGE("Heap: %s\n", strerror(errno)); - secom_put_connection_handle(connection_fd); - return FALSE; - } - - state->state = BEGIN; - id = g_io_add_watch(gio, - G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, - (GIOFunc)connection_cb, state); - if (id == 0) { - GError *err = NULL; - LOGE("Failed to create g_io watch\n"); - free(state); - g_io_channel_unref(gio); - g_io_channel_shutdown(gio, TRUE, &err); - secom_put_connection_handle(connection_fd); - return FALSE; - } - - g_io_channel_unref(gio); - return TRUE; -} - - - -static inline int init_client(struct client_cb *client_cb, - const char *packet, int packet_size) -{ - GIOChannel *gio; - guint id; - int client_fd; - struct connection_state *state; - - client_fd = secom_create_client(s_info.socket_file); - if (client_fd < 0) { - LOGE("Failed to make the client FD\n"); - return -EFAULT; - } - - if (fcntl(client_fd, F_SETFD, FD_CLOEXEC) < 0) - LOGE("Error: %s\n", strerror(errno)); - - if (fcntl(client_fd, F_SETFL, O_NONBLOCK) < 0) - LOGE("Error: %s\n", strerror(errno)); - - gio = g_io_channel_unix_new(client_fd); - if (!gio) { - close(client_fd); - return -EFAULT; - } - - state = calloc(1, sizeof(*state)); - if (!state) { - LOGE("Error: %s\n", strerror(errno)); - close(client_fd); - return -ENOMEM; - } - - state->data = client_cb; - - id = g_io_add_watch(gio, - G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, - (GIOFunc)client_connection_cb, state); - if (id == 0) { - GError *err = NULL; - LOGE("Failed to create g_io watch\n"); - free(state); - g_io_channel_unref(gio); - g_io_channel_shutdown(gio, TRUE, &err); - close(client_fd); - return -EFAULT; - } - - g_io_channel_unref(gio); - - if (secom_send(client_fd, packet, packet_size) != packet_size) { - GError *err = NULL; - LOGE("Failed to send all packet " - "(g_io_channel is not cleared now\n"); - free(state); - g_io_channel_shutdown(gio, TRUE, &err); - close(client_fd); - return -EFAULT; - } - - return client_fd; -} - - - -static inline -int init_server(void) -{ - GIOChannel *gio; - guint id; - - if (s_info.server_fd != -1) { - LOGE("Already initialized\n"); - return 0; - } - - if (pthread_mutex_lock(&s_info.server_mutex) != 0) { - LOGE("[%s:%d] Failed to get lock (%s)\n", - __func__, __LINE__, strerror(errno)); - return -EFAULT; - } - - unlink(s_info.socket_file); - s_info.server_fd = secom_create_server(s_info.socket_file); - - if (s_info.server_fd < 0) { - LOGE("Failed to open a socket (%s)\n", strerror(errno)); - if (pthread_mutex_unlock(&s_info.server_mutex) != 0) - LOGE("[%s:%d] Failed to do unlock mutex (%s)\n", - __func__, __LINE__, strerror(errno)); - return -EFAULT; - } - - if (fcntl(s_info.server_fd, F_SETFD, FD_CLOEXEC) < 0) - LOGE("Error: %s\n", strerror(errno)); - - if (fcntl(s_info.server_fd, F_SETFL, O_NONBLOCK) < 0) - LOGE("Error: %s\n", strerror(errno)); - - gio = g_io_channel_unix_new(s_info.server_fd); - if (!gio) { - close(s_info.server_fd); - s_info.server_fd = -1; - if (pthread_mutex_unlock(&s_info.server_mutex) != 0) - LOGE("[%s:%d] Failed to do unlock mutex (%s)\n", - __func__, __LINE__, strerror(errno)); - return -EFAULT; - } - - id = g_io_add_watch(gio, - G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL, - (GIOFunc)accept_cb, NULL); - if (id == 0) { - GError *err = NULL; - LOGE("Failed to create g_io watch\n"); - g_io_channel_unref(gio); - g_io_channel_shutdown(gio, TRUE, &err); - close(s_info.server_fd); - s_info.server_fd = -1; - if (pthread_mutex_unlock(&s_info.server_mutex) != 0) - LOGE("[%s:%d] Failed to do unlock mutex (%s)\n", - __func__, __LINE__, strerror(errno)); - - return -EFAULT; - } - - g_io_channel_unref(gio); - - if (pthread_mutex_unlock(&s_info.server_mutex) != 0) { - GError *err = NULL; - g_io_channel_shutdown(gio, TRUE, &err); - LOGE("[%s:%d] Failed to do unlock mutex (%s)\n", - __func__, __LINE__, strerror(errno)); - /* NOTE: - * We couldn't make a lock for this statements. - * We already meet the unrecoverble error - */ - close(s_info.server_fd); - s_info.server_fd = -1; - return -EFAULT; - } - - return 0; -} - - - -EAPI int shortcut_set_request_cb(request_cb_t request_cb, void *data) -{ - int ret; - s_info.server_cb.request_cb = request_cb; - s_info.server_cb.data = data; - - ret = init_server(); - if (ret != 0) { - LOGE("Failed to initialize the server\n"); - } - - return ret; -} - - - -EAPI int add_to_home_shortcut(const char *pkgname, const char *name, int type, const char *content_info, const char *icon, result_cb_t result_cb, void *data) -{ - struct packet *packet; - int pkgname_len; - int name_len; - int exec_len; - int icon_len; - int packet_size; - char *payload; - struct client_cb *client_cb; - int client_fd; - - pkgname_len = pkgname ? strlen(pkgname) + 1 : 0; - name_len = name ? strlen(name) + 1 : 0; - exec_len = content_info ? strlen(content_info) + 1 : 0; - icon_len = icon ? strlen(icon) + 1 : 0; - - packet_size = sizeof(*packet) + name_len + exec_len + icon_len + pkgname_len + 1; - - packet = alloca(packet_size); - if (!packet) { - LOGE("Heap: %s\n", strerror(errno)); - return -ENOMEM; - } - - packet->head.seq = s_info.seq++; - packet->head.type = PACKET_REQ; - packet->head.data.req.shortcut_type = type; - packet->head.data.req.field_size.pkgname = pkgname_len; - packet->head.data.req.field_size.name = name_len; - packet->head.data.req.field_size.exec = exec_len; - packet->head.data.req.field_size.icon = icon_len; - packet->head.payload_size = pkgname_len + name_len + exec_len + icon_len + 1; - - payload = packet->payload; - - if (pkgname_len) { - strncpy(payload, pkgname, pkgname_len); - payload += pkgname_len; - } - - if (name_len) { - strncpy(payload, name, name_len); - payload += name_len; - } - - if (exec_len) { - strncpy(payload, content_info, exec_len); - payload += exec_len; - } - - if (icon_len) - strncpy(payload, icon, icon_len); - - client_cb = malloc(sizeof(*client_cb)); - if (!client_cb) { - LOGE("Heap: %s\n", strerror(errno)); - return -ENOMEM; - } - - client_cb->result_cb = result_cb; - client_cb->data = data; - - if (init_client(client_cb, (const char*)packet, packet_size) < 0) { - LOGE("Failed to init client FD\n"); - free(client_cb); - return -EFAULT; - } - - return 0; -} - -EAPI int shortcut_add_to_home(const char *pkgname, const char *name, int type, const char *content_info, const char *icon, result_cb_t result_cb, void *data) -{ - return add_to_home_shortcut(pkgname, name, type, content_info, icon, result_cb, data); -} - - - -/* End of a file */ diff --git a/src/secom_socket.c b/src/secom_socket.c deleted file mode 100644 index 60bac2b..0000000 --- a/src/secom_socket.c +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Copyright 2012 Samsung Electronics Co., Ltd - * - * Licensed under the Flora License, Version 1.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.tizenopensource.org/license - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define _GNU_SOURCE -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - - - -extern int errno; - - - -inline static -int create_socket(const char *peer, struct sockaddr_un *addr) -{ - int len; - int handle; - - len = sizeof(struct sockaddr_un); - bzero(addr, len); - - if (strlen(peer) >= sizeof(addr->sun_path)) { - LOGE("peer %s is too long to remember it\\n", peer); - return -1; - } - - // We can believe this has no prob, because - // we already check the size of add.rsun_path - strcpy(addr->sun_path, peer); - addr->sun_family = AF_UNIX; - - handle = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); - if (handle < 0) { - LOGE("Failed to create a socket %s\n", strerror(errno)); - return -1; - } - - return handle; -} - - - -int secom_create_client(const char *peer) -{ - struct sockaddr_un addr; - int handle; - int state; - int on = 1; - - handle = create_socket(peer, &addr); - if (handle < 0) - return handle; - - state = connect(handle, (struct sockaddr*)&addr, sizeof(addr)); - if (state < 0) { - LOGE("Failed to connect to server [%s] %s\n", peer, strerror(errno)); - if (close(handle) < 0) - LOGE("Failed to close a handle\n"); - - return -1; - } - - if (setsockopt(handle, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) - LOGE("Failed to change sock opt : %s\n", strerror(errno)); - - return handle; -} - - - -int secom_create_server(const char *peer) -{ - int handle; - int state; - struct sockaddr_un addr; - - handle = create_socket(peer, &addr); - if (handle < 0) return handle; - - state = bind(handle, &addr, sizeof(addr)); - if (state < 0) { - LOGE("Failed to bind a socket %s\n", strerror(errno)); - if (close(handle) < 0) { - LOGE("Failed to close a handle\n"); - } - return -1; - } - - state = listen(handle, 5); - if (state < 0) { - LOGE("Failed to listen a socket %s\n", strerror(errno)); - if (close(handle) < 0) { - LOGE("Failed to close a handle\n"); - } - return -1; - } - - if (chmod(peer, 0666) < 0) { - LOGE("Failed to change the permission of a socket (%s)\n", strerror(errno)); - } - - return handle; -} - - - -int secom_get_connection_handle(int server_handle) -{ - struct sockaddr_un addr; - int handle; - int on = 1; - socklen_t size = sizeof(addr); - - handle = accept(server_handle, (struct sockaddr*)&addr, &size); - if (handle < 0) { - LOGE("Failed to accept a new client %s\n", strerror(errno)); - return -1; - } - - if (setsockopt(handle, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)) < 0) { - LOGE("Failed to change sock opt : %s\n", strerror(errno)); - } - - return handle; -} - - - -int secom_put_connection_handle(int conn_handle) -{ - if (close(conn_handle) < 0) { - LOGE("Failed to close a handle\n"); - return -1; - } - return 0; -} - - - -int secom_send(int handle, const char *buffer, int size) -{ - struct msghdr msg; - struct iovec iov; - int ret; - - memset(&msg, 0, sizeof(msg)); - iov.iov_base = (char*)buffer; - iov.iov_len = size; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - - ret = sendmsg(handle, &msg, 0); - if (ret < 0) { - LOGE("Failed to send message [%s]\n", strerror(errno)); - return -1; - } - LOGD("Send done: %d\n", ret); - - return iov.iov_len; -} - - - -int secom_recv(int handle, char *buffer, int size, int *sender_pid) -{ - struct msghdr msg; - struct cmsghdr *cmsg; - struct iovec iov; - int _pid; - int ret; - char control[1024]; - - if (!sender_pid) sender_pid = &_pid; - *sender_pid = -1; - - memset(&msg, 0, sizeof(msg)); - iov.iov_base = buffer; - iov.iov_len = size; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - msg.msg_control = control; - msg.msg_controllen = sizeof(control); - - ret = recvmsg(handle, &msg, 0); - if (ret < 0) { - LOGE("Failed to recvmsg [%s] (%d)\n", strerror(errno), ret); - return -1; - } - - cmsg = CMSG_FIRSTHDR(&msg); - while (cmsg) { - if (cmsg->cmsg_level == SOL_SOCKET - && cmsg->cmsg_type == SCM_CREDENTIALS) - { - struct ucred *cred; - cred = (struct ucred*)CMSG_DATA(cmsg); - *sender_pid = cred->pid; - } - - cmsg = CMSG_NXTHDR(&msg, cmsg); - } - - return iov.iov_len; -} - - - -int secom_destroy(int handle) -{ - if (close(handle) < 0) { - LOGE("Failed to close a handle\n"); - return -1; - } - return 0; -} - - - -#undef _GNU_SOURCE -// End of a file diff --git a/test/Makefile b/test/Makefile index 45201b2..abe5c1b 100644 --- a/test/Makefile +++ b/test/Makefile @@ -1,3 +1,4 @@ all: - @gcc homescreen.c -o homescreen `pkg-config ecore elementary shortcut --cflags --libs` - @gcc application.c -o application `pkg-config ecore elementary shortcut --cflags --libs` + @gcc homescreen.c -Wall -o homescreen `pkg-config ecore elementary shortcut --cflags --libs` + @gcc application.c -Wall -o application `pkg-config ecore elementary shortcut --cflags --libs` + @gcc shortcut.c -Wall -o shortcut `pkg-config ecore elementary shortcut --cflags --libs` diff --git a/test/application.c b/test/application.c index fd1f3b7..563273e 100644 --- a/test/application.c +++ b/test/application.c @@ -1,18 +1,19 @@ /* - * Copyright 2012 Samsung Electronics Co., Ltd + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. * - * Licensed under the Flora License, Version 1.0 (the "License"); + * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.tizenopensource.org/license + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - */ + * +*/ #include #include @@ -28,9 +29,12 @@ static Eina_Bool shortcut_add_cb(void *data) { int ret; - ret = shortcut_add_to_home("MyName", 0, "/usr/bin/true", "/opt/share/image/what.png", result_cb, NULL); + ret = add_to_home_shortcut("pkgname", "MyName", 0, "/usr/bin/true", "/opt/share/image/what.png", result_cb, NULL); printf("Client: shortcut_add_to_home returns: %d\n", ret); + ret = add_to_home_livebox("pkgname", "MyName", 0, "/usr/bin/true", "/opt/share/image/what.png", 1.0f, result_cb, NULL); + printf("Client: shortcut_add_to_home_with_period returns: %d\n", ret); + return ECORE_CALLBACK_RENEW; } diff --git a/test/homescreen.c b/test/homescreen.c index 5a05357..68a221b 100644 --- a/test/homescreen.c +++ b/test/homescreen.c @@ -1,32 +1,32 @@ /* - * Copyright 2012 Samsung Electronics Co., Ltd + * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. * - * Licensed under the Flora License, Version 1.0 (the "License"); + * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.tizenopensource.org/license + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - */ + * +*/ #include #include -int shortcut_request_cb(const char *name, int type, const char *exec, const char *icon, int pid, void *data) +int shortcut_request_cb(const char *pkgname, const char *name, int type, const char *exec, const char *icon, int pid, double period, void *data) { - printf("SERVER: name: %s, type: %d, exec: %s, icon: %s, pid: %d, data: %p\n", - name, type, exec, icon, pid, data); + printf("SERVER: name: %s, type: %d, exec: %s, icon: %s, pid: %d, data: %p, period: %lf\n", + name, type, exec, icon, pid, data, period); return 0; } int elm_main(int argc, char *argv[]) { - int ret; shortcut_set_request_cb(shortcut_request_cb, NULL); elm_run(); diff --git a/include/secom_socket.h b/test/shortcut.c similarity index 50% rename from include/secom_socket.h rename to test/shortcut.c index 3e6b7d6..d6c7012 100644 --- a/include/secom_socket.h +++ b/test/shortcut.c @@ -13,38 +13,29 @@ * See the License for the specific language governing permissions and * limitations under the License. * - */ +*/ +#include +#include -/* - * Create client connection - */ -extern int secom_create_client(const char *peer); - -/* - * Create server connection - */ -extern int secom_create_server(const char *peer); - -/* - * Get the raw handle to use it for non-blocking mode. - */ -extern int secom_get_connection_handle(int server_handle); -extern int secom_put_connection_handle(int conn_handle); +static int shortcut_list_cb(const char *appid, const char *icon, const char *name, const char *extra_key, const char *extra_data, void *data) +{ + printf("appid[%s] icon[%s], name[%s] extra_key[%s], extra_ata[%s]\n", appid, icon, name, extra_key, extra_data); + return 0; +} -/* - * Send data to the connected peer. - */ -extern int secom_send(int conn, const char *buffer, int size); +int elm_main(int argc, char *argv[]) +{ + int ret; + ret = shortcut_get_list(NULL, shortcut_list_cb, NULL); + if (ret < 0) + printf("Error: %d\n", ret); -/* - * Recv data from the connected peer. and its PID value - */ -extern int secom_recv(int conn, char *buffer, int size, int *sender_pid); + elm_run(); + elm_shutdown(); -/* - * Destroy a connection - */ -extern int secom_destroy(int conn); + return 0; +} +ELM_MAIN() /* End of a file */ diff --git a/test_db_builder.sh b/test_db_builder.sh new file mode 100755 index 0000000..bf9ede4 --- /dev/null +++ b/test_db_builder.sh @@ -0,0 +1,80 @@ +#!/bin/sh +#/* +# * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved. +# * +# * Licensed under the Apache License, Version 2.0 (the "License"); +# * you may not use this file except in compliance with the License. +# * You may obtain a copy of the License at +# * +# * http://www.apache.org/licenses/LICENSE-2.0 +# * +# * Unless required by applicable law or agreed to in writing, software +# * distributed under the License is distributed on an "AS IS" BASIS, +# * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# * See the License for the specific language governing permissions and +# * limitations under the License. +# * +#*/ + +DBFILE="/opt/dbspace/.shortcut_service.db" + +APPID=( +"org.tizen.facebook" +"org.tizen.facebook" +"org.tizen.facebook" +"org.tizen.facebook" +"org.tizen.facebook" +) + +ICON=( +"" +"" +"" +"" +"" +) + +NAME=( +"Friend's wall" +"Groups" +"Update status" +"Like by me" +"My wall" +) + +KEY=( +"livebox_shortcut_type" +"livebox_shortcut_type" +"livebox_shortcut_type" +"livebox_shortcut_type" +"livebox_shortcut_type" +) + +VALUE=( +"shortcut_friends" +"shortcut_groups" +"shortcut_post" +"shortcut_like" +"shortcut_me" +) + +CNT=0 +ERR=0 +MAX=5 + +sqlite3 $DBFILE "CREATE TABLE shortcut_service (id INTEGER PRIMARY KEY AUTOINCREMENT, appid TEXT, icon TEXT, name TEXT, extra_key TEXT, extra_data TEXT)" +sqlite3 $DBFILE "CREATE TABLE shortcut_name (id INTEGER, lang TEXT, name TEXT)" +while [ $CNT -lt $MAX ] +do + echo "Insert a new record ('${APPID[$CNT]}', '${ICON[$CNT]}', '${NAME[$CNT]}', \"${KEY[$CNT]}\", \"${VALUE[$CNT]}\")" + sqlite3 $DBFILE "INSERT INTO shortcut_service (appid, icon, name, extra_key, extra_data) VALUES ('${APPID[$CNT]}', '${ICON[$CNT]}', \"${NAME[$CNT]}\", \"${KEY[$CNT]}\", \"${VALUE[$CNT]}\")" 2>/dev/null + if [ $? -ne 0 ]; then + let ERR=$ERR+1 + fi + ID=`sqlite3 $DBFILE "SELECT id FROM shortcut_service WHERE appid = \"${APPID[$CNT]}\" AND extra_key = \"${KEY[$CNT]}\" AND extra_data = \"${VALUE[$CNT]}\""` + echo "Insert a name: \"${NAME[$CNT]}\"" + sqlite3 $DBFILE "INSERT INTO shortcut_name (id, lang, name) VALUES ('$ID', 'en-us', \"${NAME[CNT]}\")" + let CNT=$CNT+1 +done + +echo "Error/Total: $ERR/$CNT" -- 2.7.4