diff options
-rw-r--r-- | CMakeLists.txt | 6 | ||||
-rw-r--r-- | lib/CMakeLists.txt | 49 | ||||
-rw-r--r-- | lib/LICENSE | 204 | ||||
-rw-r--r-- | lib/include/shortcut.h | 268 | ||||
-rw-r--r-- | lib/include/shortcut_PG.h | 59 | ||||
-rw-r--r-- | lib/shortcut.pc.in | 10 | ||||
-rw-r--r-- | lib/src/main.c | 776 | ||||
-rw-r--r-- | libshortcut.manifest | 22 | ||||
-rw-r--r-- | packaging/libshortcut.spec | 66 | ||||
-rw-r--r-- | pkgmgr_shortcut/CMakeLists.txt | 31 | ||||
-rw-r--r-- | pkgmgr_shortcut/include/dlist.h | 44 | ||||
-rw-r--r-- | pkgmgr_shortcut/src/dlist.c | 181 | ||||
-rw-r--r-- | pkgmgr_shortcut/src/service_register.c | 776 | ||||
-rw-r--r-- | sample.xml | 62 | ||||
-rw-r--r-- | test/Makefile | 4 | ||||
-rw-r--r-- | test/application.c | 57 | ||||
-rw-r--r-- | test/homescreen.c | 40 | ||||
-rw-r--r-- | test/shortcut.c | 41 | ||||
-rwxr-xr-x | test_db_builder.sh | 80 |
19 files changed, 2776 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..ea60a32 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,6 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) + +set(CMAKE_SKIP_BUILD_RPATH true) + +ADD_SUBDIRECTORY("pkgmgr_shortcut") +ADD_SUBDIRECTORY("lib") 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/lib/LICENSE b/lib/LICENSE new file mode 100644 index 0000000..9c13a9b --- /dev/null +++ b/lib/LICENSE @@ -0,0 +1,204 @@ +Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
+
diff --git a/lib/include/shortcut.h b/lib/include/shortcut.h new file mode 100644 index 0000000..f05f5ae --- /dev/null +++ b/lib/include/shortcut.h @@ -0,0 +1,268 @@ +/* + * 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. + * +*/ + +#ifndef __SHORTCUT_H__ +#define __SHORTCUT_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup APPLICATION_FRAMEWORK + * @{ + */ + +/** + * @defgroup SHORTCUT Add to home (shortcut) + * @author Sung-jae Park <nicesj.park@samsung.com> + * @version 0.1 + * @brief To enhance the Add to home feature. Two types of API set are supported. + * One for the homescreen developers. + * The others for the application developers who should implement the Add to home feature. + */ + +/** + * @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] 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. + * @param[in] icon Absolute path of an icon file for this shortcut. + * @param[in] pid Process ID of who request add_to_home. + * @param[in] data Callback data. + * @return int Developer should returns the result of handling shortcut creation request. + * Returns 0, if succeed to handles the add_to_home request, or returns proper errno. + * @see shortcut_set_request_cb + * @pre None + * @post None + * @remarks None + */ +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. + * @param[in] ret Result value, it could be 0 if succeed to add a shortcut, or errno. + * @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 add_to_home_shortcut() + * @pre None + * @post None + * @remarks None + */ +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. + * 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_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_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_UNKNOWN = 0x1FFF0000, +}; + +#define ADD_TO_HOME_IS_LIVEBOX(type) (!!((type) & 0x10000000)) + +/** + * @fn int shortcut_set_request_cb(request_cb_t request_cb, void *data) + * + * @brief Homescreen should use this function to service the shortcut creating request. + * + * @par Sync (or) Async: + * This is an asynchronous API. + * + * @par Important Notes: + * - Should be used from the homescreen. + * - Should check the return value of this function + * + * @param[in] request_cb Callback function pointer which will be invoked when add_to_home is requested. + * @param[in] data Callback data to deliver to the callback function. + * + * @return Return Type (int) + * - 0 - callback function is successfully registered + * - < 0 - Failed to register the callback function for request. + * + * @see request_cb_t + * + * @pre - You have to prepare a callback function + * + * @post - If a request is sent from the application, the registered callback will be invoked. + * + * @remarks - None + * + * @par Prospective Clients: + * Homescreen + * + * @par Example + * @code + * #include <shortcut.h> + * + * 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", appid); + * printf("Name: %s\n", name); + * printf("Type: %d\n", type); + * printf("Content: %s\n", content_info); + * printf("Icon: %s\n", icon); + * printf("Requested from: %d\n", pid); + * printf("CBDATA: %p\n", data); + * return 0; // returns success. + * } + * + * static int app_create(void *data) + * { + * shortcut_set_request_cb(request_cb, NULL); + * return 0; + * } + * + * int main(int argc, char *argv[]) + * { + * appcore.... + * } + * + * @endcode + */ +extern int shortcut_set_request_cb(request_cb_t request_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. + * + * @par Sync (or) Async: + * This is an asynchronous API. + * + * @par Important Notes: + * - Application should check the return value of this function. + * - 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] 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. + * @param[in] icon Absolute path of an icon file + * @param[in] result_cb Callback function pointer which will be invoked after add_to_home request. + * @param[in] data Callback data to deliver to the callback function. + * + * @return Return Type (int) + * - 0 - Succeed to send the request + * - <0 - Failed to send the request + * + * @see result_cb_t + * + * @pre - You have to prepare the callback function + * + * @post - You have to check the return status from callback function which is passed by argument. + * + * @remarks - If a homescreen does not support this feature, you will get proper error code. + * + * @par Prospective Clients: + * Inhouse Apps. + * + * @par Example + * @code + * + * #include <stdio.h> + * #include <shortcut.h> + * + * static int result_cb(int ret, int pid, void *data) + * { + * if (ret < 0) + * printf("Failed to add a shortcut: %s\n", perror(ret)); + * + * printf("Processed by the %d\n", pid); + * return 0; + * } + * + * static int app_create(void *data) + * { + * add_to_home_shortcut("org.tizen.gallery", "With friends", + * SHORTCUT_DATA, "gallery:0000-0000", + * "/opt/media/Pictures/Friends.jpg", result_cb, NULL); + * return 0; + * } + * + * int main(int argc, char *argv[]) + * { + * appcore.... + * } + * + * @endcode + */ +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 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 +} +#endif + +#endif +/* @} + * End of a file + */ diff --git a/lib/include/shortcut_PG.h b/lib/include/shortcut_PG.h new file mode 100644 index 0000000..c3bd6c2 --- /dev/null +++ b/lib/include/shortcut_PG.h @@ -0,0 +1,59 @@ +/* + * 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. + * +*/ + +/** + * @ingroup SLP_PG + * @defgroup SHORTCUT_PG Add to home (shortcut) + * @{ + + <h1 class="pg">Introduction</h1> + 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 + + <h2 class="pg">Properties</h2> +- Types of shortcut +- Header File : shortcut.h + +<h1 class="pg">Programming Guide</h1> + +<h2 class="pg">Types of shortcut</h1> +Shortcut defines 3 kinds of types. + +<h3 class="pg">1. SHORTCUT_PACKAGE</h1> +We can use this for adding a package shortcut with additional information. <br/> +@code +@endcode + +<h3 class="pg">2. SHORTCUT_DATA</h1> +@code +@endcode + +<h3 class="pg">3. SHORTCUT_FILE</h1> +@code +@endcode + +<h2 class="pg">Error code</h1> +<h3 class="pg">1. -EINVAL</h1> +<h3 class="pg">1. -EFAULT</h1> +@code +@endcode +*/ + +/** +@} +*/ diff --git a/lib/shortcut.pc.in b/lib/shortcut.pc.in new file mode 100644 index 0000000..8daf96d --- /dev/null +++ b/lib/shortcut.pc.in @@ -0,0 +1,10 @@ +prefix=@PREFIX@ +exec_prefix=@EXEC_PREFIX@ +libdir=@LIBDIR@ +includedir=@INCLUDEDIR@ + +Name: shortcut +Description: shortcut server platform library +Version: @VERSION@ +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..89871f0 --- /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 <stdlib.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <libgen.h> + +#include <dlog.h> +#include <glib.h> +#include <db-util.h> +#include <vconf.h> +#include <vconf-keys.h> + +#include <packet.h> +#include <com-core.h> +#include <com-core_packet.h> + +#include "shortcut.h" + +#if !defined(FLOG) +#define DbgPrint(format, arg...) LOGD("[[32m%s/%s[0m:%d] " format, basename(__FILE__), __func__, __LINE__, ##arg) +#define ErrPrint(format, arg...) LOGE("[[32m%s/%s[0m:%d] " format, basename(__FILE__), __func__, __LINE__, ##arg) +#else +extern FILE *__file_log_fp; +#define DbgPrint(format, arg...) do { fprintf(__file_log_fp, "[LOG] [[32m%s/%s[0m:%d] " format, basename(__FILE__), __func__, __LINE__, ##arg); fflush(__file_log_fp); } while (0) + +#define ErrPrint(format, arg...) do { fprintf(__file_log_fp, "[ERR] [[32m%s/%s[0m:%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, NULL); + 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, NULL); + 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, NULL); + 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, NULL); + 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, NULL); + 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, NULL); + 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, NULL); + 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 new file mode 100644 index 0000000..f1055e7 --- /dev/null +++ b/libshortcut.manifest @@ -0,0 +1,22 @@ +<manifest> + <!-- Shortcut service --> + <define> + <domain name="shortcut-service" policy="restricted" /> + <provide> + <label name="shortcut-service::db" /> + </provide> + </define> + <request> + <domain name="_" /> + </request> + + <assign> + <!-- Executable file --> + <filesystem path="/usr/lib/libshortcut.so.0.0.1" label="_" /> + <filesystem path="/usr/etc/package-manager/parserlib/libshortcut-list.so" label="_" /> + + <!-- Database file --> + <filesystem path="/opt/dbspace/.shortcut_service.db" label="shortcut-service::db" /> + <filesystem path="/opt/dbspace/.shortcut_service.db-journal" label="shortcut-service::db" /> + </assign> +</manifest> diff --git a/packaging/libshortcut.spec b/packaging/libshortcut.spec new file mode 100644 index 0000000..73eaf59 --- /dev/null +++ b/packaging/libshortcut.spec @@ -0,0 +1,66 @@ +Name: libshortcut +Summary: Shortcut add feature supporting library +Version: 0.3.17 +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, 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. + +%package devel +Summary: AddToHome feature supporting library development files +Group: Development/Libraries +Requires: %{name} = %{version}-%{release} + +%description devel +[Shortcut] AddToHome feature supporting library for menu/home screen developers +(dev). + +%prep +%setup -q + +%build +cmake . -DCMAKE_INSTALL_PREFIX=%{_prefix} +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 + +%postun + +%files -n libshortcut +%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/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 <stdio.h> +#include <stdlib.h> +#include <assert.h> + +#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..6e8b618 --- /dev/null +++ b/pkgmgr_shortcut/src/service_register.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 <stdio.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <libgen.h> +#include <string.h> + +#include <sqlite3.h> +#include <db-util.h> +#include <libxml/parser.h> +#include <libxml/tree.h> +#include <dlog.h> + +#include "dlist.h" + +#if !defined(FLOG) +#define DbgPrint(format, arg...) LOGD("[[32m%s/%s[0m:%d] " format, basename(__FILE__), __func__, __LINE__, ##arg) +#define ErrPrint(format, arg...) LOGE("[[32m%s/%s[0m:%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, NULL) != 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, NULL) != 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, NULL) != 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, NULL) != 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, NULL) != 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, NULL) != 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, NULL) != 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, NULL) != 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, NULL) != 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, NULL) != 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, NULL) != 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, NULL) != 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, NULL) != 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_UPGRADE(xmlDocPtr docPtr, const char *appid) +{ + xmlNodePtr root; + + 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; + } + + 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 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 @@ +<?xml version="1.0" encoding="utf-8" ?> +<manifest xmlns="http://tizen.org/ns/packages" package="org.tizen.myapp" version="0.3.5" install-location="auto"> +<shortcut-list test="a"> + <shortcut appid="org.tizen.myapp" extra_key="key" extra_data="SERVICE INFORMATION 1"> + <icon>/opt/usr/apps/org.tizen.myapp/res/icon/myapp_shortcut01.png</icon> + <label>Default Name</label> + <label xml:lang="en-us">Name en</label> + <label xml:lang="nl-nl">Name nl</label> + <label xml:lang="de-de">Name de</label> + <label xml:lang="zh-hk">Name hk</label> + <label xml:lang="zh-cn">Name cn</label> + <label xml:lang="ru-ru">Name ru</label> + <label xml:lang="zh-tw">Name tw</label> + <label xml:lang="ja-jp">Name jp</label> + <label xml:lang="es-es">Name es</label> + <label xml:lang="el-gr">Name gr</label> + <label xml:lang="it-it">Name it</label> + <label xml:lang="tr-tr">Name tr</label> + <label xml:lang="pt-pt">Name pt</label> + <label xml:lang="fr-fr">Name fr</label> + <label xml:lang="kor-kr">Name kr</label> + </shortcut> + <shortcut appid="org.tizen.myapp-gadget" extra_key="key" extra_data="SERVICE INFORMATION 2"> + <icon>/opt/usr/apps/org.tizen.myapp/res/icon/gadget_shortcut01.png</icon> + <label>Default Name 02</label> + <label xml:lang="en-us">Name en</label> + <label xml:lang="nl-nl">Name nl</label> + <label xml:lang="de-de">Name de</label> + <label xml:lang="zh-hk">Name hk</label> + <label xml:lang="zh-cn">Name cn</label> + <label xml:lang="ru-ru">Name ru</label> + <label xml:lang="zh-tw">Name tw</label> + <label xml:lang="ja-jp">Name jp</label> + <label xml:lang="es-es">Name es</label> + <label xml:lang="el-gr">Name gr</label> + <label xml:lang="it-it">Name it</label> + <label xml:lang="tr-tr">Name tr</label> + <label xml:lang="pt-pt">Name pt</label> + <label xml:lang="fr-fr">Name fr</label> + <label xml:lang="kor-kr">Name kr</label> + </shortcut> + <shortcut appid="org.tizen.myapp" extra_key="key" extra_data="SERVICE INFORMATION 3"> + <icon>/opt/usr/apps/org.tizen.myapp/res/icon/mayapp_shortcut02.png</icon> + <label>Default Name 03</label> + <label xml:lang="en-us">Name en</label> + <label xml:lang="nl-nl">Name nl</label> + <label xml:lang="de-de">Name de</label> + <label xml:lang="zh-hk">Name hk</label> + <label xml:lang="zh-cn">Name cn</label> + <label xml:lang="ru-ru">Name ru</label> + <label xml:lang="zh-tw">Name tw</label> + <label xml:lang="ja-jp">Name jp</label> + <label xml:lang="es-es">Name es</label> + <label xml:lang="el-gr">Name gr</label> + <label xml:lang="it-it">Name it</label> + <label xml:lang="tr-tr">Name tr</label> + <label xml:lang="pt-pt">Name pt</label> + <label xml:lang="fr-fr">Name fr</label> + <label xml:lang="kor-kr">Name kr</label> + </shortcut> +</shortcut-list> +</manifest> diff --git a/test/Makefile b/test/Makefile new file mode 100644 index 0000000..abe5c1b --- /dev/null +++ b/test/Makefile @@ -0,0 +1,4 @@ +all: + @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 new file mode 100644 index 0000000..563273e --- /dev/null +++ b/test/application.c @@ -0,0 +1,57 @@ +/* + * 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 <Elementary.h> +#include <shortcut.h> + +static int result_cb(int ret, int pid, void *data) +{ + printf("Client: Return %d (%d)\n", ret, pid); + //elm_exit(); + return 0; +} + +static Eina_Bool shortcut_add_cb(void *data) +{ + int ret; + + 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; +} + +int elm_main(int argc, char *argv[]) +{ + Ecore_Timer *timer; + + timer = ecore_timer_add(3.0f, shortcut_add_cb, NULL); + if (!timer) { + printf("Failed to add a timer\n"); + } + + elm_run(); + elm_shutdown(); + + return 0; +} + +ELM_MAIN() +/* End of a file */ diff --git a/test/homescreen.c b/test/homescreen.c new file mode 100644 index 0000000..68a221b --- /dev/null +++ b/test/homescreen.c @@ -0,0 +1,40 @@ +/* + * 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 <Elementary.h> +#include <shortcut.h> + +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, period: %lf\n", + name, type, exec, icon, pid, data, period); + return 0; +} + +int elm_main(int argc, char *argv[]) +{ + shortcut_set_request_cb(shortcut_request_cb, NULL); + + elm_run(); + elm_shutdown(); + + return 0; +} + +ELM_MAIN() +/* End of a file */ + diff --git a/test/shortcut.c b/test/shortcut.c new file mode 100644 index 0000000..d6c7012 --- /dev/null +++ b/test/shortcut.c @@ -0,0 +1,41 @@ +/* + * 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 <Elementary.h> +#include <shortcut.h> + +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; +} + +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); + + elm_run(); + elm_shutdown(); + + 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" |