summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xCMakeLists.txt207
-rw-r--r--LICENSE206
-rw-r--r--data-provider-master.desktop9
-rw-r--r--data-provider-master.rule5
-rw-r--r--data/CMakeLists.txt7
-rw-r--r--data/abi.ini17
-rwxr-xr-xdata/data-provider-master98
-rw-r--r--data/data-provider-master.service39
-rw-r--r--data/dump_livebox.sh7
-rw-r--r--data/mobile.data-provider-master.service29
-rw-r--r--data/wayland.mobile.conf.ini37
-rw-r--r--data/wayland.mobile.resolution.ini13
-rw-r--r--data/wayland.wearable.conf.ini37
-rw-r--r--data/wayland.wearable.resolution.ini14
-rw-r--r--data/x11.mobile.conf.ini37
-rw-r--r--data/x11.mobile.resolution.ini13
-rw-r--r--data/x11.wearable.conf.ini37
-rw-r--r--data/x11.wearable.resolution.ini14
-rw-r--r--include/abi.h24
-rw-r--r--include/badge_service.h20
-rw-r--r--include/buffer_handler.h332
-rw-r--r--include/client_life.h105
-rw-r--r--include/client_rpc.h27
-rw-r--r--include/conf.h201
-rw-r--r--include/critical_log.h23
-rw-r--r--include/dead_monitor.h20
-rw-r--r--include/debug.h70
-rw-r--r--include/event.h53
-rw-r--r--include/fault_manager.h25
-rw-r--r--include/file_service.h20
-rw-r--r--include/group.h65
-rw-r--r--include/instance.h264
-rw-r--r--include/io.h25
-rw-r--r--include/lite-errno.h69
-rw-r--r--include/liveinfo.h35
-rw-r--r--include/main.h16
-rw-r--r--include/notification_service.h20
-rw-r--r--include/package.h131
-rw-r--r--include/parser.h45
-rw-r--r--include/pkgmgr.h40
-rw-r--r--include/rpc_to_slave.h29
-rw-r--r--include/script_handler.h39
-rw-r--r--include/server.h20
-rw-r--r--include/service_common.h63
-rw-r--r--include/setting.h21
-rw-r--r--include/shortcut_service.h20
-rw-r--r--include/slave_life.h215
-rw-r--r--include/slave_rpc.h32
-rw-r--r--include/util.h89
-rw-r--r--include/utility_service.h21
-rw-r--r--include/xmonitor.h34
-rw-r--r--packaging/data-provider-master.changes8
-rw-r--r--packaging/data-provider-master.manifest70
-rwxr-xr-xpackaging/data-provider-master.spec205
-rw-r--r--pkgmgr_livebox/CMakeLists.txt31
-rw-r--r--pkgmgr_livebox/include/dlist.h43
-rw-r--r--pkgmgr_livebox/livebox.xml78
-rw-r--r--pkgmgr_livebox/src/dlist.c189
-rw-r--r--pkgmgr_livebox/src/service_register.c3194
-rw-r--r--res/CMakeLists.txt1
-rw-r--r--res/edje/CMakeLists.txt9
-rw-r--r--res/edje/master.edc112
-rw-r--r--src/abi.c154
-rw-r--r--src/badge_service.c593
-rw-r--r--src/buffer_handler.c1765
-rw-r--r--src/buffer_handler_wayland.c921
-rw-r--r--src/client_life.c870
-rw-r--r--src/client_rpc.c283
-rw-r--r--src/conf.c953
-rw-r--r--src/critical_log.c179
-rw-r--r--src/dead_monitor.c98
-rw-r--r--src/event.c676
-rw-r--r--src/fault_manager.c369
-rw-r--r--src/file_service.c719
-rw-r--r--src/group.c889
-rw-r--r--src/instance.c3294
-rw-r--r--src/io.c895
-rw-r--r--src/liveinfo.c223
-rw-r--r--src/main.c461
-rw-r--r--src/notification_service.c709
-rw-r--r--src/package.c1609
-rw-r--r--src/parser.c891
-rw-r--r--src/pkgmgr.c626
-rw-r--r--src/script_handler.c1511
-rw-r--r--src/server.c8541
-rw-r--r--src/service_common.c1193
-rw-r--r--src/setting.c240
-rw-r--r--src/shortcut_service.c256
-rw-r--r--src/slave_life.c1717
-rw-r--r--src/slave_rpc.c702
-rw-r--r--src/util.c732
-rw-r--r--src/util_wayland.c26
-rw-r--r--src/util_x11.c27
-rw-r--r--src/utility_service.c452
-rw-r--r--src/xmonitor.c490
-rw-r--r--src/xmonitor_wayland.c251
-rw-r--r--util_liveinfo/CMakeLists.txt38
-rw-r--r--util_liveinfo/include/liveinfo.h16
-rw-r--r--util_liveinfo/include/node.h41
-rw-r--r--util_liveinfo/src/liveinfo.c2010
-rw-r--r--util_liveinfo/src/node.c389
101 files changed, 42788 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100755
index 0000000..f11d495
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,207 @@
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+PROJECT(data-provider-master C)
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(pkg REQUIRED
+ ail
+ dlog
+ aul
+ vconf
+ sqlite3
+ db-util
+ glib-2.0
+ gio-2.0
+ bundle
+ ecore
+ eina
+ com-core
+ pkgmgr
+ notification
+ notification-service
+ badge
+ badge-service
+ libsmack
+ shortcut
+ libsystemd-daemon
+)
+
+IF (LIVEBOX)
+pkg_check_modules(pkg_livebox REQUIRED
+ livebox-service
+)
+ENDIF (LIVEBOX)
+
+IF (X11_SUPPORT)
+pkg_check_modules(pkg_extra REQUIRED
+ ecore-x
+ x11
+ libdri2
+ libdrm
+ libtbm
+ xfixes
+ dri2proto
+ xext
+ xdamage
+)
+ENDIF (X11_SUPPORT)
+
+IF (WAYLAND_SUPPORT)
+pkg_check_modules(pkg_extra REQUIRED
+ ecore-wayland
+)
+ENDIF (WAYLAND_SUPPORT)
+
+SET(PACKAGE "${PROJECT_NAME}")
+SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -Winline -Werror -fno-builtin-malloc -fno-omit-frame-pointer -g")
+
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/include)
+
+#ADD_DEFINITIONS("-DPREFIX=\"${CMAKE_INSTALL_PREFIX}\"")
+ADD_DEFINITIONS("-DPATH_MAX=256")
+ADD_DEFINITIONS("-DPACKAGE=\"${PACKAGE}\"")
+ADD_DEFINITIONS("-DLOCALEDIR=\"${LOCALEDIR}\"")
+
+ADD_DEFINITIONS("-DINFO_SOCKET=\"/opt/usr/share/live_magazine/.live.socket\"")
+ADD_DEFINITIONS("-DCLIENT_SOCKET=\"/opt/usr/share/live_magazine/.client.socket\"")
+ADD_DEFINITIONS("-DSLAVE_SOCKET=\"/opt/usr/share/live_magazine/.slave.socket\"")
+ADD_DEFINITIONS("-DSERVICE_SOCKET=\"/opt/usr/share/live_magazine/.service.socket\"")
+
+ADD_DEFINITIONS("-DCLIENT_PORT=\"8208\"")
+
+ADD_DEFINITIONS("-DBADGE_SOCKET=\"/tmp/.badge.service\"")
+ADD_DEFINITIONS("-DSHORTCUT_SOCKET=\"/tmp/.shortcut.service\"")
+ADD_DEFINITIONS("-DNOTIFICATION_SOCKET=\"/tmp/.notification.service\"")
+ADD_DEFINITIONS("-DUTILITY_SOCKET=\"/tmp/.utility.service\"")
+
+ADD_DEFINITIONS("-DUTILITY_SMACK_LABEL=\"data-provider-master::utility\"")
+ADD_DEFINITIONS("-DSHORTCUT_SMACK_LABEL=\"data-provider-master::shortcut\"")
+ADD_DEFINITIONS("-DNOTIFICATION_SMACK_LABEL=\"data-provider-master::notification\"")
+ADD_DEFINITIONS("-DBADGE_SMACK_LABEL=\"data-provider-master::badge\"")
+ADD_DEFINITIONS("-DDATA_SHARE_LABEL=\"data-provider-master::share\"")
+
+ADD_DEFINITIONS("-DDEFAULT_MASTER_CONF=\"/usr/share/data-provider-master/conf.ini\"")
+
+ADD_DEFINITIONS("-DNDEBUG")
+
+ADD_DEFINITIONS("-D_USE_ECORE_TIME_GET")
+
+IF (MOBILE)
+ ADD_DEFINITIONS("-DMOBILE")
+ELSEIF (WEARABLE)
+ ADD_DEFINITIONS("-DWEARABLE")
+ENDIF (MOBILE)
+
+SET(BUILD_SOURCE
+ src/main.c
+ src/util.c
+ src/setting.c
+ src/critical_log.c
+ src/shortcut_service.c
+ src/badge_service.c
+ src/notification_service.c
+ src/service_common.c
+ src/conf.c
+)
+
+IF (LIVEBOX)
+ ADD_DEFINITIONS("-DHAVE_LIVEBOX")
+ SET(BUILD_SOURCE
+ ${BUILD_SOURCE}
+ src/utility_service.c
+ src/dead_monitor.c
+ src/package.c
+ src/instance.c
+ src/server.c
+ src/abi.c
+ src/fault_manager.c
+ src/parser.c
+ src/io.c
+ src/slave_life.c
+ src/slave_rpc.c
+ src/client_life.c
+ src/client_rpc.c
+ src/group.c
+ src/script_handler.c
+ src/liveinfo.c
+ src/pkgmgr.c
+ src/event.c
+ src/file_service.c
+ )
+
+ IF (WAYLAND_SUPPORT)
+ ADD_DEFINITIONS("-DHAVE_WAYLAND")
+ SET(BUILD_SOURCE
+ ${BUILD_SOURCE}
+ src/xmonitor_wayland.c
+ src/buffer_handler_wayland.c
+ src/util_wayland.c
+ )
+ ENDIF (WAYLAND_SUPPORT)
+
+ IF (X11_SUPPORT)
+ ADD_DEFINITIONS("-DHAVE_X11")
+ SET(BUILD_SOURCE
+ ${BUILD_SOURCE}
+ src/xmonitor.c
+ src/buffer_handler.c
+ src/util_x11.c
+ )
+ ENDIF (X11_SUPPORT)
+ENDIF (LIVEBOX)
+
+IF (WAYLAND_SUPPORT)
+ ADD_DEFINITIONS("-DHAVE_WAYLAND")
+ SET(BUILD_SOURCE
+ ${BUILD_SOURCE}
+ src/util_wayland.c
+ )
+ENDIF (WAYLAND_SUPPORT)
+
+IF (X11_SUPPORT)
+ ADD_DEFINITIONS("-DHAVE_X11")
+ SET(BUILD_SOURCE
+ ${BUILD_SOURCE}
+ src/util_x11.c
+ )
+ENDIF (X11_SUPPORT)
+
+#ADD_DEFINITIONS("-D_APPLY_SCRIPT_ASYNC_UPDATE")
+#ADD_DEFINITIONS("-DFLOG")
+ADD_DEFINITIONS(${pkg_CFLAGS})
+ADD_DEFINITIONS(${pkg_LDFLAGS})
+ADD_DEFINITIONS(${pkg_extra_CFLAGS})
+ADD_DEFINITIONS(${pkg_extra_LDFLAGS})
+ADD_DEFINITIONS(${pkg_livebox_CFLAGS})
+ADD_DEFINITIONS(${pkg_livebox_LDFLAGS})
+
+ADD_EXECUTABLE(${PROJECT_NAME} ${BUILD_SOURCE})
+
+TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkg_LDFLAGS} ${pkg_extra_LDFLAGS} ${pkg_livebox_LDFLAGS} "-ldl -lrt")
+
+IF (LIVEBOX)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/data/abi.ini DESTINATION /usr/share/data-provider-master PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/data/${PRODUCT}.conf.ini DESTINATION /usr/share/data-provider-master RENAME "conf.ini" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/data/${PRODUCT}.resolution.ini DESTINATION /usr/share/data-provider-master RENAME "resolution.ini" PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ)
+ENDIF (LIVEBOX)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/LICENSE DESTINATION /usr/share/license RENAME "${PROJECT_NAME}")
+IF (MOBILE)
+INSTALL(TARGETS ${PROJECT_NAME} DESTINATION /usr/bin PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE SETUID)
+INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}.rule DESTINATION /opt/etc/smack/accesses.d)
+ELSE (MOBILE)
+INSTALL(TARGETS ${PROJECT_NAME} DESTINATION /usr/bin PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
+ENDIF (MOBILE)
+
+# INCLUDE FOR BUILD & INSTALL .PO FILES
+ADD_SUBDIRECTORY(res)
+ADD_SUBDIRECTORY(data)
+IF (LIVEBOX)
+ADD_SUBDIRECTORY(pkgmgr_livebox)
+
+IF (X11_SUPPORT)
+ IF ("${ENGINEER_BINARY}" STREQUAL "true")
+ ADD_SUBDIRECTORY(util_liveinfo)
+ ENDIF ("${ENGINEER_BINARY}" STREQUAL "true")
+ENDIF (X11_SUPPORT)
+ENDIF (LIVEBOX)
+
+# End of a file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..571fe79
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,206 @@
+Flora License
+
+Version 1.1, April, 2013
+
+http://floralicense.org/license/
+
+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.
+
+"Tizen Certified Platform" shall mean a software platform that complies
+with the standards set forth in the Tizen Compliance Specification
+and passes the Tizen Compliance Tests as defined from time to time
+by the Tizen Technical Steering Group and certified by the Tizen
+Association or its designated agent.
+
+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
+solely as incorporated into a Tizen Certified Platform, 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 solely
+as incorporated into a Tizen Certified Platform 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 pursuant to the copyright license
+above, in any medium, with or without modifications, and in Source or
+Object form, provided that You meet the following conditions:
+
+ 1. You must give any other recipients of the Work or Derivative Works
+ a copy of this License; and
+ 2. You must cause any modified files to carry prominent notices stating
+ that You changed the files; and
+ 3. 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
+ 4. 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
+ and your own copyright statement or terms and conditions do not conflict
+ the conditions stated in the License including section 3.
+
+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 Flora License to your work
+
+To apply the Flora 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 Flora License, Version 1.1 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://floralicense.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.
+
diff --git a/data-provider-master.desktop b/data-provider-master.desktop
new file mode 100644
index 0000000..77d74ae
--- /dev/null
+++ b/data-provider-master.desktop
@@ -0,0 +1,9 @@
+Name=Live Data Provider - Master
+Type=Application
+Exec=/usr/bin/data-provider-master
+Icon=data-provider-master.png
+NoDisplay=True
+Network=True
+Comment=Homescreen-Live Box content data provider (master)
+X-TIZEN-TaskManage=False
+X-TIZEN-Multiple=False
diff --git a/data-provider-master.rule b/data-provider-master.rule
new file mode 100644
index 0000000..c8dc2de
--- /dev/null
+++ b/data-provider-master.rule
@@ -0,0 +1,5 @@
+data-provider-master notification::db rw
+data-provider-master ail::db rw
+data-provider-master svi-data x
+data-provider-master data-provider-master::db rw
+data-provider-master system::vconf_system rwxat
diff --git a/data/CMakeLists.txt b/data/CMakeLists.txt
new file mode 100644
index 0000000..af462e3
--- /dev/null
+++ b/data/CMakeLists.txt
@@ -0,0 +1,7 @@
+#INSTALL(FILES ${CMAKE_SOURCE_DIR}/data/data-provider-master DESTINATION /etc/rc.d/init.d/ PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
+IF (MOBILE)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/data/mobile.data-provider-master.service DESTINATION /usr/lib/systemd/user/ RENAME data-provider-master.service PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ)
+ELSE (MOBILE)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/data/data-provider-master.service DESTINATION /usr/lib/systemd/system/ PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ)
+INSTALL(FILES ${CMAKE_SOURCE_DIR}/data/dump_livebox.sh DESTINATION /opt/etc/dump.d/module.d/ PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
+ENDIF (MOBILE)
diff --git a/data/abi.ini b/data/abi.ini
new file mode 100644
index 0000000..ad8eec3
--- /dev/null
+++ b/data/abi.ini
@@ -0,0 +1,17 @@
+[c]
+package=org.tizen.data-provider-slave
+
+[cpp]
+package=org.tizen.data-provider-slave
+
+[html]
+package=dbox.web-provider
+
+[osp]
+package=gi2qxenosh.osp-appwidget-service
+
+[app]
+package=/APPID/
+
+[dali]
+package=provider.multi-livebox
diff --git a/data/data-provider-master b/data/data-provider-master
new file mode 100755
index 0000000..6dd2a92
--- /dev/null
+++ b/data/data-provider-master
@@ -0,0 +1,98 @@
+#!/bin/sh
+#
+# Copyright 2013 Samsung Electronics Co., Ltd
+#
+# Licensed under the Flora License, Version 1.1 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://floralicense.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.
+#
+
+launch_provider()
+{
+ RETRY_COUNT=0
+ while [ ! -f "/tmp/.stop.provider" ]; do
+ # PROVIDER_HEAP_MONITOR_START=false
+ # PROVIDER_DISABLE_CALL_OPTION=false
+ # PROVIDER_METHOD="shm", "pixmap", "file" (default = "file")
+ BUFMGR_LOCK_TYPE="once" BUFMGR_MAP_CACHE="true" /usr/bin/data-provider-master
+ vconftool set -t bool memory/data-provider-master/started 0 -f
+ let RETRY_COUNT=$RETRY_COUNT+1
+ if [ $RETRY_COUNT -gt 5 ]; then
+ echo "EXCEED THE MAXIMUM RETRY COUNT: $RETRY_COUNT (max 5)"
+ break;
+ fi
+ done
+ rm /tmp/.stop.provider
+}
+
+start ()
+{
+ OLDPID=`ps ax | grep /usr/bin/data-provider-master | grep -v grep | awk '{print $1}'`
+ if [ x"$OLDPID" != x"" ]; then
+ echo $OLDPID is already running.
+ exit 0
+ fi
+
+ rm /tmp/.stop.provider
+ launch_provider &
+}
+
+stop ()
+{
+ TMP=`which ps`
+ if [ $? -ne 0 ]; then
+ echo "'ps' is not exists"
+ exit 0
+ fi
+
+ TMP=`which grep`
+ if [ $? -ne 0 ]; then
+ echo "'grep' is not exists"
+ exit 0
+ fi
+
+ TMP=`which awk`
+ if [ $? -ne 0 ]; then
+ echo "'awk' is not exists"
+ exit 0
+ fi
+
+ if [ ! -f "/usr/bin/data-provider-master" ]; then
+ echo "Data provider master is not installed correctly";
+ exit 0;
+ fi
+
+ touch /tmp/.stop.provider
+ BIN_INODE=`stat -Lc "%i" /usr/bin/data-provider-master`
+
+ PID=`ps ax | grep 'data-provider-master' | awk '{print $1}'`
+ for I in $PID;
+ do
+ if [ ! -f "/proc/$I/exe" ]; then
+ continue;
+ fi
+
+ INODE=`stat -Lc "%i" /proc/$I/exe 2>/dev/null`
+ if [ x"$BIN_INODE" == x"$INODE" ]; then
+ echo "Send TERM to $I"
+ kill $I # Try to terminate a master which is launched already
+ break
+ fi
+ done
+}
+
+case "$1" in
+ start|"") start;;
+ stop) stop;;
+ restart) stop; start;;
+esac
+
+# End of a file
diff --git a/data/data-provider-master.service b/data/data-provider-master.service
new file mode 100644
index 0000000..e359660
--- /dev/null
+++ b/data/data-provider-master.service
@@ -0,0 +1,39 @@
+#
+# Copyright 2013 Samsung Electronics Co., Ltd
+#
+# Licensed under the Flora License, Version 1.1 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://floralicense.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.
+#
+
+[Unit]
+Description=Data Provider daemon
+DefaultDependencies=no
+After=check-mount.service
+
+[Service]
+Environment=MULTISENSE_SND_PLAYER=tizen_snd_player
+Environment=ELM_MODULES=ctxpopup_copypasteUI>entry/api:datetime_input_popup>datetime/api:object_dump>win/api:access_output_tts>access/api
+Environment=EINA_LOG_LEVEL=1
+Environment=ECORE_INPUT_TIMEOUT_FIX=0
+Environment=EINA_LOG_LEVELS=ecore_x:4,evas_main:1
+Environment=BUFMGR_LOCK_TYPE="once"
+Environment=BUFMGR_MAP_CACHE="true"
+Environment=ELM_PROFILE=mobile
+EnvironmentFile=-/run/tizen-mobile-env
+Type=simple
+ExecStart=/usr/bin/data-provider-master
+RestartSec=1
+Restart=always
+MemoryLimit=50M
+
+[Install]
+WantedBy=multi-user.target
diff --git a/data/dump_livebox.sh b/data/dump_livebox.sh
new file mode 100644
index 0000000..2fb6c32
--- /dev/null
+++ b/data/dump_livebox.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+LIVEBOX_DEBUG=$1/livebox
+mkdir -p ${LIVEBOX_DEBUG}
+/bin/cp -r /opt/usr/share/live_magazine ${LIVEBOX_DEBUG}
+/bin/cp -r /tmp/.dbox.service ${LIVEBOX_DEBUG}/log
+ls -la /tmp/ | /bin/grep srw > ${LIVEBOX_DEBUG}/log/tmp.hidden_files
diff --git a/data/mobile.data-provider-master.service b/data/mobile.data-provider-master.service
new file mode 100644
index 0000000..ee61361
--- /dev/null
+++ b/data/mobile.data-provider-master.service
@@ -0,0 +1,29 @@
+#
+# 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.
+#
+
+[Unit]
+Description=Data Provider daemon
+After=xorg.target
+
+[Service]
+Type=notify
+Environment=BUFMGR_LOCK_TYPE="once"
+Environment=BUFMGR_MAP_CACHE="true"
+ExecStart=/usr/bin/data-provider-master
+RestartSec=1
+
+[Install]
+WantedBy=tizen-middleware.target
diff --git a/data/wayland.mobile.conf.ini b/data/wayland.mobile.conf.ini
new file mode 100644
index 0000000..c9b95c7
--- /dev/null
+++ b/data/wayland.mobile.conf.ini
@@ -0,0 +1,37 @@
+base_width=720
+base_height=1280
+minimum_period=1.0
+#script=edje
+#default_abi=c
+#default_group=disclosure
+default_period=-1.0
+default_packet_time=0.0001
+#default_content=default
+minimum_space=104857600
+#replace_tag=/APPID/
+slave_ttl=30.0
+slave_activate_time=30.0
+slave_relaunch_time=3.0
+slave_relaunch_count=3
+max_log_line=1000
+max_log_file=3
+sqilte_flush_max=1048576
+#db_path=/opt/dbspace/.livebox.db
+#share_path=/opt/usr/share/live_magazine/
+log_path=/tmp/.dbox.service
+#always_path=/opt/usr/share/live_magazine/always
+#reader_path=/opt/usr/share/live_magazine/reader
+#script_port_path=/usr/share/data-provider-master/plugin-script/
+ping_interval=240.0
+slave_max_load=30
+use_sw_backend=false
+provider_method=shm
+debug_mode=false
+overwrite_content=false
+com_core_thread=true
+use_xmonitor=false
+#input=/dev/input/event2
+pd_request_timeout=5.0
+premultiplied=1
+#emergency_disk=source=tmpfs;type=tmpfs;option=size=6M
+#services=[livebox],[shortcut],[notification],[utility],[badge],[file]
diff --git a/data/wayland.mobile.resolution.ini b/data/wayland.mobile.resolution.ini
new file mode 100644
index 0000000..e2b5a17
--- /dev/null
+++ b/data/wayland.mobile.resolution.ini
@@ -0,0 +1,13 @@
+1x1=175x175
+2x1=354x175
+2x2=354x354
+4x1=712x175
+4x2=712x354
+4x3=712x533
+4x4=712x712
+4x5=712x891
+4x6=712x1070
+21x21=224x215
+23x21=680x215
+23x23=680x653
+0x0=720x1280
diff --git a/data/wayland.wearable.conf.ini b/data/wayland.wearable.conf.ini
new file mode 100644
index 0000000..2866b74
--- /dev/null
+++ b/data/wayland.wearable.conf.ini
@@ -0,0 +1,37 @@
+base_width=320
+base_height=320
+minimum_period=1.0
+#script=edje
+#default_abi=c
+#default_group=disclosure
+default_period=-1.0
+default_packet_time=0.0001
+#default_content=default
+minimum_space=104857600
+#replace_tag=/APPID/
+slave_ttl=0.0
+slave_activate_time=30.0
+slave_relaunch_time=3.0
+slave_relaunch_count=3
+max_log_line=1000
+max_log_file=3
+sqilte_flush_max=1048576
+#db_path=/opt/dbspace/.livebox.db
+#share_path=/opt/usr/share/live_magazine/
+log_path=/tmp/.dbox.service
+#always_path=/opt/usr/share/live_magazine/always
+#reader_path=/opt/usr/share/live_magazine/reader
+#script_port_path=/usr/share/data-provider-master/plugin-script/
+ping_interval=240.0
+slave_max_load=30
+use_sw_backend=false
+provider_method=shm
+debug_mode=false
+overwrite_content=false
+com_core_thread=true
+use_xmonitor=false
+#input=/dev/input/event2
+pd_request_timeout=5.0
+premultiplied=0
+#emergency_disk=source=tmpfs;type=tmpfs;option=size=6M
+services=[livebox],[shortcut],[badge]
diff --git a/data/wayland.wearable.resolution.ini b/data/wayland.wearable.resolution.ini
new file mode 100644
index 0000000..b9e7561
--- /dev/null
+++ b/data/wayland.wearable.resolution.ini
@@ -0,0 +1,14 @@
+1x1=320x320
+2x1=0x0
+2x2=320x320
+4x1=0x0
+4x2=0x0
+4x3=0x0
+4x4=0x0
+4x5=0x0
+4x6=0x0
+21x21=0x0
+23x21=0x0
+23x23=0x0
+0x0=320x320
+base=320x320
diff --git a/data/x11.mobile.conf.ini b/data/x11.mobile.conf.ini
new file mode 100644
index 0000000..d0bdfb5
--- /dev/null
+++ b/data/x11.mobile.conf.ini
@@ -0,0 +1,37 @@
+base_width=720
+base_height=1280
+minimum_period=1.0
+#script=edje
+#default_abi=c
+#default_group=disclosure
+default_period=-1.0
+default_packet_time=0.0001
+#default_content=default
+minimum_space=104857600
+#replace_tag=/APPID/
+slave_ttl=30.0
+slave_activate_time=30.0
+slave_relaunch_time=3.0
+slave_relaunch_count=3
+max_log_line=1000
+max_log_file=3
+sqilte_flush_max=1048576
+#db_path=/opt/dbspace/.livebox.db
+#share_path=/opt/usr/share/live_magazine/
+log_path=/tmp/.dbox.service
+#always_path=/opt/usr/share/live_magazine/always
+#reader_path=/opt/usr/share/live_magazine/reader
+#script_port_path=/usr/share/data-provider-master/plugin-script/
+ping_interval=240.0
+slave_max_load=30
+use_sw_backend=false
+provider_method=pixmap
+debug_mode=false
+overwrite_content=false
+com_core_thread=true
+use_xmonitor=false
+#input=/dev/input/event2
+pd_request_timeout=5.0
+premultiplied=0
+#emergency_disk=source=tmpfs;type=tmpfs;option=size=6M
+#services=[livebox],[shortcut],[notification],[utility],[badge],[file]
diff --git a/data/x11.mobile.resolution.ini b/data/x11.mobile.resolution.ini
new file mode 100644
index 0000000..e2b5a17
--- /dev/null
+++ b/data/x11.mobile.resolution.ini
@@ -0,0 +1,13 @@
+1x1=175x175
+2x1=354x175
+2x2=354x354
+4x1=712x175
+4x2=712x354
+4x3=712x533
+4x4=712x712
+4x5=712x891
+4x6=712x1070
+21x21=224x215
+23x21=680x215
+23x23=680x653
+0x0=720x1280
diff --git a/data/x11.wearable.conf.ini b/data/x11.wearable.conf.ini
new file mode 100644
index 0000000..260dadb
--- /dev/null
+++ b/data/x11.wearable.conf.ini
@@ -0,0 +1,37 @@
+base_width=320
+base_height=320
+minimum_period=1.0
+#script=edje
+#default_abi=c
+#default_group=disclosure
+default_period=-1.0
+default_packet_time=0.0001
+#default_content=default
+minimum_space=104857600
+#replace_tag=/APPID/
+slave_ttl=0.0
+slave_activate_time=30.0
+slave_relaunch_time=3.0
+slave_relaunch_count=3
+max_log_line=1000
+max_log_file=3
+sqilte_flush_max=1048576
+#db_path=/opt/dbspace/.livebox.db
+#share_path=/opt/usr/share/live_magazine/
+log_path=/tmp/.dbox.service
+#always_path=/opt/usr/share/live_magazine/always
+#reader_path=/opt/usr/share/live_magazine/reader
+#script_port_path=/usr/share/data-provider-master/plugin-script/
+ping_interval=240.0
+slave_max_load=30
+use_sw_backend=false
+provider_method=pixmap
+debug_mode=false
+overwrite_content=false
+com_core_thread=true
+use_xmonitor=false
+#input=/dev/input/event2
+pd_request_timeout=5.0
+premultiplied=0
+#emergency_disk=source=tmpfs;type=tmpfs;option=size=6M
+services=[livebox],[shortcut],[badge]
diff --git a/data/x11.wearable.resolution.ini b/data/x11.wearable.resolution.ini
new file mode 100644
index 0000000..b9e7561
--- /dev/null
+++ b/data/x11.wearable.resolution.ini
@@ -0,0 +1,14 @@
+1x1=320x320
+2x1=0x0
+2x2=320x320
+4x1=0x0
+4x2=0x0
+4x3=0x0
+4x4=0x0
+4x5=0x0
+4x6=0x0
+21x21=0x0
+23x21=0x0
+23x23=0x0
+0x0=320x320
+base=320x320
diff --git a/include/abi.h b/include/abi.h
new file mode 100644
index 0000000..2b4ebd8
--- /dev/null
+++ b/include/abi.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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.
+ */
+
+extern int abi_add_entry(const char *abi, const char *pkgname);
+extern int abi_update_entry(const char *abi, const char *pkgname);
+extern int abi_del_entry(const char *abi);
+extern const char *abi_find_slave(const char *abi);
+extern void abi_del_all(void);
+extern const char *abi_find_by_pkgname(const char *pkgname);
+
+/* End of a file */
diff --git a/include/badge_service.h b/include/badge_service.h
new file mode 100644
index 0000000..ed49c9f
--- /dev/null
+++ b/include/badge_service.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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.
+ */
+
+extern int badge_service_init(void);
+extern int badge_service_fini(void);
+
+/* End of a file */
diff --git a/include/buffer_handler.h b/include/buffer_handler.h
new file mode 100644
index 0000000..e3aa982
--- /dev/null
+++ b/include/buffer_handler.h
@@ -0,0 +1,332 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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.
+ */
+
+struct buffer_info;
+struct inst_info;
+struct buffer;
+
+enum buffer_type { /*!< Must have to be sync with libprovider, liblivebox-viewer, liblivebox-edje */
+ BUFFER_TYPE_FILE,
+ BUFFER_TYPE_SHM,
+ BUFFER_TYPE_PIXMAP,
+ BUFFER_TYPE_ERROR
+};
+
+/*!
+ * \brief
+ * \param[in] type
+ * \param[in] w
+ * \param[in] h
+ * \param[in] pixel_size
+ * \return buffer_info
+ */
+extern struct buffer_info *buffer_handler_create(struct inst_info *inst, enum buffer_type type, int w, int h, int pixel_size);
+
+/*!
+ * \brief
+ * \param[in] info
+ * \return int
+ */
+extern int buffer_handler_destroy(struct buffer_info *info);
+
+/*!
+ * \brief
+ * \param[in] info
+ * \return int
+ */
+extern int buffer_handler_load(struct buffer_info *info);
+
+/*!
+ * \brief
+ * \param[in] info
+ * \return int
+ */
+extern int buffer_handler_unload(struct buffer_info *info);
+
+/*!
+ * \brief
+ * \param[in] info
+ * \return int
+ */
+extern int buffer_handler_is_loaded(const struct buffer_info *info);
+
+/*!
+ * \brief Reallocate buffer
+ * \param[in] info
+ * \param[in] w
+ * \param[in] h
+ * \return int
+ */
+extern int buffer_handler_resize(struct buffer_info *info, int w, int h);
+
+/*!
+ * \brief Only update the size information
+ * \param[in] info
+ * \param[in] w
+ * \param[in] h
+ * \return void
+ */
+extern void buffer_handler_update_size(struct buffer_info *info, int w, int h);
+
+/*!
+ * \brief
+ * \param[in] info
+ * \return const char *
+ */
+extern const char *buffer_handler_id(const struct buffer_info *info);
+
+/*!
+ * \param[in] info
+ * \return buffer_type
+ */
+extern enum buffer_type buffer_handler_type(const struct buffer_info *info);
+
+/*!
+ * \brief This API is not supported for Pixmap.
+ * \param[in] info
+ * \return void*
+ */
+extern void *buffer_handler_fb(struct buffer_info *info);
+
+/*!
+ * \brief
+ * \param[in] info
+ * \param[out] w
+ * \param[out] h
+ * \return int
+ */
+extern int buffer_handler_get_size(struct buffer_info *info, int *w, int *h);
+
+/*!
+ * \brief This API only can be used for file type buffer
+ * \param[in] info
+ * \return void
+ */
+extern void buffer_handler_flush(struct buffer_info *info);
+
+/*!
+ * \brief
+ * \param[in] info
+ * \return 0 if fails. Return value should be casted to Pixmap type
+ */
+extern int buffer_handler_pixmap(const struct buffer_info *info);
+
+/*!
+ * \brief
+ * \param[in] info
+ * \return buffer
+ */
+extern void *buffer_handler_pixmap_acquire_buffer(struct buffer_info *info);
+
+/*!
+ * \brief
+ * \param[in] info
+ * \return int
+ */
+extern int buffer_handler_pixmap_release_buffer(void *canvas);
+
+/*!
+ * \brief
+ * \return int
+ */
+extern int buffer_handler_init(void);
+
+/*!
+ * \brief
+ * \details
+ * \remarks
+ * \return int
+ * \retval
+ * \pre
+ * \post
+ * \sa
+ */
+extern int buffer_handler_fini(void);
+
+/*!
+ * \brief
+ * \details
+ * \remarks
+ * \param[in] info
+ * \return void *
+ * \retval NULL
+ * \retval address
+ * \pre
+ * \post
+ * \sa
+ */
+extern void *buffer_handler_pixmap_ref(struct buffer_info *info);
+
+/*!
+ * \brief
+ * \details
+ * \remarks
+ * \param[in] buffer_ptr
+ * \return int
+ * \retval
+ * \pre
+ * \post
+ * \sa
+ */
+extern int buffer_handler_pixmap_unref(void *buffer_ptr);
+
+/*!
+ * \brief
+ * \details
+ * \remarks
+ * \param[in] pixmap
+ * \return void *
+ * \retval
+ * \pre
+ * \post
+ * \sa
+ */
+extern void *buffer_handler_pixmap_find(int pixmap);
+
+/*!
+ * \brief
+ * \details
+ * \remarks
+ * \param[in] info
+ * \return void *
+ * \retval
+ * \pre
+ * \post
+ * \sa
+ */
+extern void *buffer_handler_pixmap_buffer(struct buffer_info *info);
+
+/*!
+ * \brief
+ * \details
+ * \remarks
+ * \param[in] info
+ * \return struct inst_info *
+ * \retval
+ * \pre
+ * \post
+ * \sa
+ */
+extern struct inst_info *buffer_handler_instance(struct buffer_info *info);
+
+/*!
+ * \brief
+ * \details
+ * \remarks
+ * \param[in] type
+ * \param[in] resource
+ * \return struct buffer *
+ * \retval NULL
+ * \retval address
+ * \pre
+ * \post
+ * \sa
+ */
+extern struct buffer *buffer_handler_raw_open(enum buffer_type type, void *resource);
+
+/*!
+ * \brief
+ * \details
+ * \remarks
+ * \param[in] buffer
+ * \return int
+ * \retval
+ * \pre
+ * \post
+ * \sa
+ */
+extern int buffer_handler_raw_close(struct buffer *buffer);
+
+/*!
+ * \brief
+ * \details
+ * \remarks
+ * \param[in] buffer
+ * \return void *
+ * \retval NULL
+ * \pre
+ * \post
+ * \sa
+ */
+extern void *buffer_handler_raw_data(struct buffer *buffer);
+
+/*!
+ * \brief
+ * \details
+ * \remarks
+ * \param[in] buffer
+ * \return int
+ * \retval
+ * \pre
+ * \post
+ * \sa
+ */
+extern int buffer_handler_raw_size(struct buffer *buffer);
+
+/*!
+ * \brief
+ * \details
+ * \remarks
+ * \param[in] buffer
+ * \return int
+ * \retval
+ * \pre
+ * \post
+ * \sa
+ */
+extern int buffer_handler_lock(struct buffer_info *buffer);
+
+/*!
+ * \brief
+ * \details
+ * \remarks
+ * \param[in] buffer
+ * \return int
+ * \retval
+ * \pre
+ * \post
+ * \sa
+ */
+extern int buffer_handler_unlock(struct buffer_info *buffer);
+
+/*!
+ * \brief
+ * \details
+ * \remarks
+ * \param[in] buffer
+ * \param[in] data
+ * \return int
+ * \retval
+ * \pre
+ * \post
+ * \sa
+ */
+extern int buffer_handler_set_data(struct buffer_info *buffer, void *data);
+
+/*!
+ * \brief
+ * \details
+ * \remarks
+ * \param[in] buffer
+ * \return void *
+ * \retval NULL
+ * \retval address
+ * \pre
+ * \post
+ * \sa
+ */
+extern void *buffer_handler_data(struct buffer_info *buffer);
+/* End of a file */
diff --git a/include/client_life.h b/include/client_life.h
new file mode 100644
index 0000000..fa88612
--- /dev/null
+++ b/include/client_life.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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.
+ */
+
+enum client_event {
+ CLIENT_EVENT_ACTIVATE,
+ CLIENT_EVENT_DEACTIVATE
+};
+
+enum client_global_event {
+ CLIENT_GLOBAL_EVENT_CREATE,
+ CLIENT_GLOBAL_EVENT_DESTROY
+};
+
+struct inst_info;
+struct packet;
+
+/*!
+ * \note
+ * Create & Destroy
+ */
+extern struct client_node *client_create(pid_t pid, int handle);
+#define client_destroy(client) client_unref(client)
+
+/*!
+ * \note
+ * Reference count
+ */
+extern struct client_node *client_ref(struct client_node *client);
+extern struct client_node *client_unref(struct client_node *client);
+extern const int const client_refcnt(const struct client_node *client);
+
+/*!
+ * \note
+ * Information of client PID
+ */
+extern const pid_t const client_pid(const struct client_node *client);
+extern struct client_node *client_find_by_pid(pid_t pid);
+extern struct client_node *client_find_by_rpc_handle(int handle);
+
+/*!
+ * \note
+ * Statistics for state of client
+ */
+extern const int const client_count_paused(void);
+extern int client_is_all_paused(void);
+extern int client_count(void);
+
+/*!
+ * \note
+ * For dead signal handler
+ */
+extern struct client_node *client_deactivated_by_fault(struct client_node *client);
+extern void client_reset_fault(struct client_node *client);
+extern const int const client_is_faulted(const struct client_node *client);
+
+/*!
+ * \note
+ * For other components which wants to know the state of a client
+ */
+extern int client_event_callback_add(struct client_node *client, enum client_event event, int (*cb)(struct client_node *, void *), void *data);
+extern int client_event_callback_del(struct client_node *client, enum client_event event, int (*cb)(struct client_node *, void *), void *data);
+
+extern int client_global_event_handler_del(enum client_global_event event_type, int (*cb)(struct client_node *, void *), void *data);
+extern int client_global_event_handler_add(enum client_global_event event_type, int (*cb)(struct client_node *client, void *data), void *data);
+
+/*!
+ * \note
+ * Private data set & get
+ */
+extern int client_set_data(struct client_node *client, const char *tag, void *data);
+extern void *client_data(struct client_node *client, const char *tag);
+extern void *client_del_data(struct client_node *client, const char *tag);
+
+/*!
+ * Handling the client statues
+ * Paused or Resumed
+ */
+extern void client_paused(struct client_node *client);
+extern void client_resumed(struct client_node *client);
+
+extern int client_subscribe(struct client_node *client, const char *cluster, const char *category);
+extern int client_unsubscribe(struct client_node *client, const char *cluster, const char *category);
+extern int client_is_subscribed(struct client_node *client, const char *cluster, const char *category);
+
+extern int client_init(void);
+extern void client_fini(void);
+
+extern int client_browse_list(const char *cluster, const char *category, int (*cb)(struct client_node *client, void *data), void *data);
+extern int client_nr_of_subscriber(const char *cluster, const char *category);
+
+extern int client_broadcast(struct inst_info *inst, struct packet *packet);
+/* End of a file */
diff --git a/include/client_rpc.h b/include/client_rpc.h
new file mode 100644
index 0000000..20a8a38
--- /dev/null
+++ b/include/client_rpc.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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.
+ */
+
+/*!
+ */
+extern int client_rpc_async_request(struct client_node *client, struct packet *packet);
+extern int client_rpc_handle(struct client_node *client);
+
+/*!
+ */
+extern int client_rpc_init(struct client_node *client, int handle);
+extern int client_rpc_fini(struct client_node *client);
+
+/* End of a file */
diff --git a/include/conf.h b/include/conf.h
new file mode 100644
index 0000000..aab11d1
--- /dev/null
+++ b/include/conf.h
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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.
+ */
+
+struct conf {
+ int width;
+ int height;
+
+ int base_width;
+ int base_height;
+ double minimum_period;
+
+ struct {
+ char *script;
+ char *abi;
+ char *pd_group;
+ double period;
+ int pixels;
+ } default_conf;
+
+ struct {
+ char *name;
+ char *secured;
+ char *abi;
+ } launch_key;
+
+ double default_packet_time;
+
+ char *empty_content;
+ char *empty_title;
+
+ char *default_content;
+ char *default_title;
+
+ unsigned long minimum_space;
+
+ char *replace_tag;
+
+ double slave_ttl;
+ double slave_activate_time;
+ double slave_relaunch_time;
+ int slave_relaunch_count;
+
+ int max_log_line;
+ int max_log_file;
+
+ unsigned long sqlite_flush_max;
+
+ struct {
+ char *conf;
+ char *image;
+ char *script;
+ char *root;
+ char *script_port;
+ char *slave_log;
+ char *reader;
+ char *always;
+ char *db;
+ char *input;
+ } path;
+
+ int max_size_type;
+
+ int slave_max_load;
+
+ double ping_time;
+
+ char *vconf_sys_cluster;
+ int max_pended_ctx_events;
+
+ int use_sw_backend;
+ char *provider_method;
+ int debug_mode;
+ int overwrite_content;
+ int com_core_thread;
+ int use_xmonitor;
+ int premultiplied;
+
+ double scale_width_factor;
+ double scale_height_factor;
+
+ double pd_request_timeout;
+
+ char *emergency_disk;
+ char *services;
+};
+
+extern struct conf g_conf;
+
+extern int conf_loader(void);
+extern void conf_update_size(void);
+extern void conf_reset(void);
+extern void conf_init(void);
+
+#define BASE_W g_conf.base_width
+#define BASE_H g_conf.base_height
+
+#define CR 13
+#define LF 10
+
+#define EMERGENCY_DISK g_conf.emergency_disk
+#define SCALE_WIDTH_FACTOR g_conf.scale_width_factor
+#define SCALE_HEIGHT_FACTOR g_conf.scale_height_factor
+
+#define USE_SW_BACKEND g_conf.use_sw_backend
+#define PROVIDER_METHOD g_conf.provider_method
+#define DEBUG_MODE g_conf.debug_mode
+#define OVERWRITE_CONTENT g_conf.overwrite_content
+#define COM_CORE_THREAD g_conf.com_core_thread
+
+#define MINIMUM_PERIOD g_conf.minimum_period
+
+#define DEFAULT_SCRIPT g_conf.default_conf.script
+#define DEFAULT_ABI g_conf.default_conf.abi
+#define DEFAULT_GROUP g_conf.default_conf.pd_group
+#define DEFAULT_PERIOD g_conf.default_conf.period
+#define DEFAULT_PIXELS g_conf.default_conf.pixels
+#define PRIORITY_NO_CHANGE -1.0f
+
+#define BUNDLE_SLAVE_NAME g_conf.launch_key.name
+#define BUNDLE_SLAVE_SECURED g_conf.launch_key.secured
+#define BUNDLE_SLAVE_ABI g_conf.launch_key.abi
+#define PACKET_TIME g_conf.default_packet_time
+#define CONTENT_NO_CHANGE g_conf.empty_content
+#define TITLE_NO_CHANGE g_conf.empty_title
+#define DEFAULT_TITLE g_conf.default_title
+#define DEFAULT_CONTENT g_conf.default_content
+#define MINIMUM_SPACE g_conf.minimum_space
+
+#define IMAGE_PATH g_conf.path.image
+#define SCRIPT_PATH g_conf.path.script
+#define SCRIPT_PORT_PATH g_conf.path.script_port
+#define CONF_PATH g_conf.path.conf
+#define ROOT_PATH g_conf.path.root
+#define SLAVE_LOG_PATH g_conf.path.slave_log
+#define READER_PATH g_conf.path.reader
+#define ALWAYS_PATH g_conf.path.always
+#define INPUT_PATH g_conf.path.input
+
+#define REPLACE_TAG_APPID g_conf.replace_tag
+#define SLAVE_TTL g_conf.slave_ttl
+#define SLAVE_ACTIVATE_TIME g_conf.slave_activate_time
+#define SLAVE_RELAUNCH_TIME g_conf.slave_relaunch_time
+#define SLAVE_RELAUNCH_COUNT g_conf.slave_relaunch_count
+
+#define MAX_LOG_LINE g_conf.max_log_line
+#define MAX_LOG_FILE g_conf.max_log_file
+
+#define SQLITE_FLUSH_MAX g_conf.sqlite_flush_max
+#define DBFILE g_conf.path.db
+
+#define PD_REQUEST_TIMEOUT g_conf.pd_request_timeout
+
+#define SLAVE_MAX_LOAD g_conf.slave_max_load
+#define DEFAULT_PING_TIME g_conf.ping_time
+#define PREMULTIPLIED_COLOR g_conf.premultiplied
+#define SERVICES g_conf.services
+
+#define SERVICE_LIVEBOX "[livebox]"
+#define SERVICE_NOTIFICATION "[notification]"
+#define SERVICE_BADGE "[badge]"
+#define SERVICE_SHORTCUT "[shortcut]"
+#define SERVICE_UTILITY "[utility]"
+#define SERVICE_FILE "[file]"
+
+#define PAUSED_FILE "/tmp/.live.paused"
+
+#define MAX_ABI 256
+#define MAX_PKGNAME 512
+#define DELAY_TIME 0.0000001f
+#define DEFAULT_CLUSTER "user,created"
+#define MINIMUM_REACTIVATION_TIME 10
+
+#if !defined(VCONFKEY_MASTER_STARTED)
+#define VCONFKEY_MASTER_STARTED "memory/data-provider-master/started"
+#endif
+
+#if !defined(VCONFKEY_MASTER_RESTART_COUNT)
+#define VCONFKEY_MASTER_RESTART_COUNT "memory/private/data-provider-master/restart_count"
+#endif
+
+#define USE_XMONITOR g_conf.use_xmonitor
+
+#define HAPI __attribute__((visibility("hidden")))
+/*!
+ * EAPI is defined from eina.h
+ */
+
+/* End of a file */
diff --git a/include/critical_log.h b/include/critical_log.h
new file mode 100644
index 0000000..f060ce1
--- /dev/null
+++ b/include/critical_log.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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.
+ */
+
+extern int critical_log(const char *func, int line, const char *fmt, ...);
+extern int critical_log_init(const char *tag);
+extern void critical_log_fini(void);
+
+#define CRITICAL_LOG(args...) critical_log(__func__, __LINE__, args)
+
+/* End of a file */
diff --git a/include/dead_monitor.h b/include/dead_monitor.h
new file mode 100644
index 0000000..96efa3b
--- /dev/null
+++ b/include/dead_monitor.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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.
+ */
+
+extern int dead_init(void);
+extern int dead_fini(void);
+
+/* End of a file */
diff --git a/include/debug.h b/include/debug.h
new file mode 100644
index 0000000..cc4911f
--- /dev/null
+++ b/include/debug.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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.
+ */
+
+#if !defined(FLOG)
+#define DbgPrint(format, arg...) SECURE_LOGD(format, ##arg)
+#define ErrPrint(format, arg...) SECURE_LOGE(format, ##arg)
+#define WarnPrint(format, arg...) SECURE_LOGW(format, ##arg)
+#else
+extern FILE *__file_log_fp;
+#define DbgPrint(format, arg...) do { fprintf(__file_log_fp, "[LOG] [%s/%s:%d] " format, util_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, util_basename(__FILE__), __func__, __LINE__, ##arg); fflush(__file_log_fp); } while (0)
+#define WarnPrint(format, arg...) do { fprintf(__file_log_fp, "[WRN] [%s/%s:%d] " format, util_basename(__FILE__), __func__, __LINE__, ##arg); fflush(__file_log_fp); } while (0)
+#endif
+
+// DbgPrint("FREE\n");
+#define DbgFree(a) do { \
+ free(a); \
+} while (0)
+
+#define DbgXFree(a) do { \
+ DbgPrint("XFree\n"); \
+ XFree(a); \
+} while (0)
+
+
+#if defined(LOG_TAG)
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "DATA_PROVIDER_MASTER"
+
+#if defined(_ENABLE_PERF)
+#define PERF_INIT() \
+ struct timeval __stv; \
+ struct timeval __etv; \
+ struct timeval __rtv
+
+#define PERF_BEGIN() do { \
+ if (gettimeofday(&__stv, NULL) < 0) { \
+ ErrPrint("gettimeofday: %s\n", strerror(errno)); \
+ } \
+} while (0)
+
+#define PERF_MARK(tag) do { \
+ if (gettimeofday(&__etv, NULL) < 0) { \
+ ErrPrint("gettimeofday: %s\n", strerror(errno)); \
+ } \
+ timersub(&__etv, &__stv, &__rtv); \
+ DbgPrint("[%s] %u.%06u\n", tag, __rtv.tv_sec, __rtv.tv_usec); \
+} while (0)
+#else
+#define PERF_INIT()
+#define PERF_BEGIN()
+#define PERF_MARK(tag)
+#endif
+
+/* End of a file */
diff --git a/include/event.h b/include/event.h
new file mode 100644
index 0000000..800b071
--- /dev/null
+++ b/include/event.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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.
+ */
+
+struct event_data {
+ int x;
+ int y;
+ unsigned int keycode;
+ int device;
+ int slot;
+ struct {
+ int major;
+ int minor;
+ } touch;
+ struct {
+ int major;
+ int minor;
+ } width;
+ int distance; /* Hovering */
+#if defined(_USE_ECORE_TIME_GET)
+ double tv;
+#else
+ struct timeval tv;
+#endif
+};
+
+enum event_state {
+ EVENT_STATE_DEACTIVATED,
+ EVENT_STATE_ACTIVATE,
+ EVENT_STATE_ACTIVATED,
+ EVENT_STATE_DEACTIVATE,
+ EVENT_STATE_ERROR
+};
+
+extern int event_init(void);
+extern int event_fini(void);
+extern int event_activate(int x, int y, int (*event_cb)(enum event_state state, struct event_data *event, void *data), void *data);
+extern int event_deactivate(int (*event_cb)(enum event_state state, struct event_data *event, void *data), void *data);
+extern int event_is_activated(void);
+
+/* End of a file */
diff --git a/include/fault_manager.h b/include/fault_manager.h
new file mode 100644
index 0000000..cfc1bec
--- /dev/null
+++ b/include/fault_manager.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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.
+ */
+
+extern int fault_check_pkgs(struct slave_node *node);
+extern int fault_func_call(struct slave_node *node, const char *pkgname, const char *filename, const char *func);
+extern int fault_func_ret(struct slave_node *node, const char *pkgname, const char *filename, const char *func);
+extern int const fault_is_occured(void);
+extern void fault_unicast_info(struct client_node *client, const char *pkgname, const char *filename, const char *func);
+extern void fault_broadcast_info(const char *pkgname, const char *filename, const char *func);
+extern int fault_info_set(struct slave_node *slave, const char *pkgname, const char *id, const char *func);
+
+/* End of a file */
diff --git a/include/file_service.h b/include/file_service.h
new file mode 100644
index 0000000..208f739
--- /dev/null
+++ b/include/file_service.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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.
+ */
+
+extern int file_service_init(void);
+extern int file_service_fini(void);
+
+/* End of a file */
diff --git a/include/group.h b/include/group.h
new file mode 100644
index 0000000..04dfddd
--- /dev/null
+++ b/include/group.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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.
+ */
+
+struct cluster;
+struct category;
+struct pkg_info;
+struct context_info;
+struct context_item;
+struct context_option;
+
+extern struct cluster *group_create_cluster(const char *name);
+extern struct cluster *group_find_cluster(const char *name);
+extern int group_destroy_cluster(struct cluster *cluster);
+
+extern struct category *group_create_category(struct cluster *cluster, const char *name);
+extern struct category *group_find_category(struct cluster *cluster, const char *name);
+extern int group_destroy_category(struct category *category);
+
+extern const char * const group_category_name(struct category *category);
+extern const char * const group_cluster_name(struct cluster *cluster);
+extern const char *group_cluster_name_by_category(struct category *category);
+
+extern int group_add_package(struct category *category, const char *pkgname);
+extern int group_del_package(struct category *category, const char *pkgname);
+
+extern int group_add_livebox(const char *group, const char *pkgname);
+extern int group_del_livebox(const char *pkgname);
+
+extern int group_init(void);
+extern int group_fini(void);
+
+extern struct context_info *group_create_context_info(struct category *category, const char *pkgname);
+extern struct context_item *group_add_context_item(struct context_info *info, const char *ctx_item);
+extern int group_add_option(struct context_item *item, const char *key, const char *value);
+extern int group_destroy_context_info(struct context_info *info);
+
+extern Eina_List * const group_context_info_list(struct category *category);
+extern Eina_List * const group_context_item_list(struct context_info *info);
+extern Eina_List * const group_context_option_list(struct context_item *item);
+extern Eina_List * const group_cluster_list(void);
+extern Eina_List * const group_category_list(struct cluster *cluster);
+extern struct context_info * const group_context_info_from_item(struct context_item *item);
+extern struct category * const group_category_from_context_info(struct context_info *info);
+extern const char * const group_option_item_key(struct context_option *option);
+extern const char * const group_option_item_value(struct context_option *option);
+extern const char * const group_context_item(struct context_item *item);
+extern const char * const group_pkgname_from_context_info(struct context_info *info);
+
+extern void *group_context_item_del_data(struct context_item *item, const char *tag);
+extern void *group_context_item_data(struct context_item *item, const char *tag);
+extern int group_context_item_add_data(struct context_item *item, const char *tag, void *data);
+/* End of a file */
diff --git a/include/instance.h b/include/instance.h
new file mode 100644
index 0000000..a61c32c
--- /dev/null
+++ b/include/instance.h
@@ -0,0 +1,264 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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.
+ */
+
+/*!
+ * \note
+ * An instance has three states.
+ * ACTIVATED, DEACTIVATED, DESTROYED
+ *
+ * When the master is launched and someone requires to create this instance,
+ * The master just allocate a heap for new instance.
+ * We defined this as "DEACTIVATED" state.
+ *
+ * After master successfully allocate heap for an instance,
+ * It will send a load request to a specified slave
+ * (The slave will be specified when a package informaion is
+ * prepared via configuration file of each livebox packages.)
+ * We defined this as "REQUEST_TO_ACTIVATE" state.
+ *
+ * After the slave create a new instance, it will sends back
+ * "created" event to the master.
+ * Then the master will change the state of the instance to
+ * "ACTIVATED".
+ *
+ * Sometimes, slaves can meet some unexpected problems then
+ * it will tries to clear all problems and tries to keep them in safe env.
+ * To do this, master or slave can be terminated.
+ * In this case, the master has to find the fault module(crashed livebox)
+ * and prevent it from loading at the slave.
+ * And it will send requests for re-creating all other normal liveboxes.
+ * We defined this as "REQUEST_TO_REACTIVATE".
+ *
+ * After slave is launched again(recovered from fault situation), it will
+ * receives "re-create" event from the master, then it will create all
+ * instances of requested liveboxes.
+ *
+ * When the master receives "created" event from the slaves,
+ * It will change the instance's state to "ACTIVATED"
+ * But now, the master will not send "created" event to the clients.
+ *
+ * Because the clients don't want to know the re-created liveboxes.
+ * They just want to know about fault liveboxes to display deactivated
+ * message.
+ *
+ * Sometimes the master can send requests to the slave to unload instances.
+ * We defined this as "REQUEST_TO_DEACTIVATE".
+ *
+ * After the slave successfully destroy instances,
+ * The master will change the instance's state to "DEACTIVATED"
+ * It is same state with the first time when it is created in the master.
+ *
+ * Sometimes, the instances can be deleted permanently from the master and slave.
+ * We called this "destorying an instance".
+ * So we defined its states as "DESTROYED".
+ * It can make confusing us, the "DESTROYED" means like the instance is already deleted from the
+ * heap,.
+ * Yes, it is right. But the instance cannot be deleted directly.
+ * Because some callbacks still reference it to complete its job.
+ * So the instance needs to keep this DESTROYED state for a while
+ * until all callbacks are done for their remained jobs.
+ *
+ * To unload the instance from the slave,
+ * The master should send a request to the slave,
+ * And the master should keep the instance until it receives "deleted" event from the slave.
+ * We defined this state as "REQUEST_TO_DESTROY".
+ *
+ * After master receives "deleted" event from the slave,
+ * It will change the state of an master to "DESTROYED"
+ *
+ * There is one more event to change the state of an instance to "DESTROYED".
+ * In case of system created livebox, it could be destroyed itself.
+ * So the slave will send "deleted" event to the master directly.
+ * Even if the master doesn't requests to delete it.
+ *
+ * In this case, the master will change the state of an instance to
+ * "DESTROYED" state. but it will wait to delete it from the heap until
+ * reference count of an instance reaches to ZERO.
+ */
+
+enum instance_event {
+ INSTANCE_EVENT_DESTROY,
+ INSTNACE_EVENT_UNKNOWN
+};
+
+enum instance_destroy_type {
+ INSTANCE_DESTROY_DEFAULT = 0x00,
+ INSTANCE_DESTROY_UPGRADE = 0x01,
+ INSTANCE_DESTROY_UNINSTALL = 0x02,
+ INSTANCE_DESTROY_TERMINATE = 0x03,
+ INSTANCE_DESTROY_FAULT = 0x04,
+ INSTANCE_DESTROY_TEMPORARY = 0x05,
+ INSTANCE_DESTROY_UNKNOWN = 0x06
+};
+
+enum instance_state {
+ INST_INIT = 0x0, /*!< Only keeps in the master */
+
+ /*!
+ */
+ INST_ACTIVATED, /*!< This instance is loaded to the slave */
+ INST_REQUEST_TO_ACTIVATE, /*!< Sent a request to a slave to load this */
+ INST_REQUEST_TO_REACTIVATE, /*!< Sent a request to a slave to load this without "created" event for clients(viewer) */
+
+ /*!
+ */
+ INST_DESTROYED, /*!< Instance is unloaded and also it requires to be deleted from the master */
+ INST_REQUEST_TO_DESTROY /*!< Sent a request to a slave, when the master receives deleted event, the master will delete this */
+};
+
+enum livebox_visible_state { /*!< Must be sync'd with livebox-viewer */
+ LB_SHOW = 0x00, /*!< Livebox is showed. Default state */
+ LB_HIDE = 0x01, /*!< Livebox is hide, with no update event, but keep update timer */
+
+ LB_HIDE_WITH_PAUSE = 0x02, /*!< Livebix is hide, it needs to be paused (with freezed update timer) */
+
+ LB_VISIBLE_ERROR = 0xFFFFFFFF /* To enlarge the size of this enumeration type */
+};
+
+#define IS_PD 1
+#define IS_LB 0
+
+struct inst_info;
+struct pkg_info;
+struct script_handle;
+struct client_node;
+
+extern struct inst_info *instance_create(struct client_node *client, double timestamp, const char *pkgname, const char *content, const char *cluster, const char *category, double period, int width, int height);
+extern int instance_destroy(struct inst_info *inst, enum instance_destroy_type type);
+extern int instance_reload(struct inst_info *inst, enum instance_destroy_type type);
+
+extern struct inst_info * instance_ref(struct inst_info *inst);
+extern struct inst_info * instance_unref(struct inst_info *inst);
+
+extern int instance_state_reset(struct inst_info *inst);
+extern int instance_destroyed(struct inst_info *inst, int reason);
+
+extern int instance_reactivate(struct inst_info *inst);
+extern int instance_activate(struct inst_info *inst);
+
+extern int instance_recover_state(struct inst_info *inst);
+extern int instance_need_slave(struct inst_info *inst);
+
+extern void instance_set_lb_info(struct inst_info *inst, double priority, const char *content, const char *title);
+extern void instance_set_lb_size(struct inst_info *inst, int w, int h);
+extern void instance_set_pd_size(struct inst_info *inst, int w, int h);
+extern void instance_set_alt_info(struct inst_info *inst, const char *icon, const char *name);
+
+extern int instance_set_pinup(struct inst_info *inst, int pinup);
+extern int instance_resize(struct inst_info *inst, int w, int h);
+extern int instance_hold_scroll(struct inst_info *inst, int seize);
+extern int instance_set_period(struct inst_info *inst, double period);
+extern int instance_clicked(struct inst_info *inst, const char *event, double timestamp, double x, double y);
+extern int instance_text_signal_emit(struct inst_info *inst, const char *emission, const char *source, double sx, double sy, double ex, double ey);
+extern int instance_signal_emit(struct inst_info *inst, const char *emission, const char *source, double sx, double sy, double ex, double ey, double x, double y, int down);
+extern int instance_change_group(struct inst_info *inst, const char *cluster, const char *category);
+extern int instance_set_visible_state(struct inst_info *inst, enum livebox_visible_state state);
+extern enum livebox_visible_state instance_visible_state(struct inst_info *inst);
+extern int instance_set_update_mode(struct inst_info *inst, int active_update);
+extern int instance_active_update(struct inst_info *inst);
+
+/*!
+ * \note
+ * getter
+ */
+extern const double const instance_timestamp(const struct inst_info *inst);
+extern struct pkg_info * const instance_package(const struct inst_info *inst);
+extern struct script_info * const instance_lb_script(const struct inst_info *inst);
+extern struct script_info * const instance_pd_script(const struct inst_info *inst);
+extern struct buffer_info * const instance_pd_buffer(const struct inst_info *inst);
+extern struct buffer_info * const instance_lb_buffer(const struct inst_info *inst);
+extern const char * const instance_id(const struct inst_info *inst);
+extern const char * const instance_content(const struct inst_info *inst);
+extern const char * const instance_category(const struct inst_info *inst);
+extern const char * const instance_cluster(const struct inst_info *inst);
+extern const char * const instance_title(const struct inst_info *inst);
+extern const char * const instance_auto_launch(const struct inst_info *inst);
+extern const int const instance_priority(const struct inst_info *inst);
+extern const struct client_node * const instance_client(const struct inst_info *inst);
+extern const double const instance_period(const struct inst_info *inst);
+extern const int const instance_timeout(const struct inst_info *inst);
+extern const int const instance_lb_width(const struct inst_info *inst);
+extern const int const instance_lb_height(const struct inst_info *inst);
+extern const int const instance_pd_width(const struct inst_info *inst);
+extern const int const instance_pd_height(const struct inst_info *inst);
+extern const enum instance_state const instance_state(const struct inst_info *inst);
+
+/*!
+ * event
+ */
+extern int instance_unicast_created_event(struct inst_info *inst, struct client_node *client);
+extern int instance_unicast_deleted_event(struct inst_info *inst, struct client_node *client, int reason);
+
+extern int instance_create_lb_buffer(struct inst_info *inst, int pixels);
+extern int instance_create_pd_buffer(struct inst_info *inst, int pixels);
+
+extern void instance_slave_set_pd_pos(struct inst_info *inst, double x, double y);
+extern void instance_slave_get_pd_pos(struct inst_info *inst, double *x, double *y);
+
+extern int instance_slave_open_pd(struct inst_info *inst, struct client_node *client);
+extern int instance_slave_close_pd(struct inst_info *inst, struct client_node *client, int reason);
+
+extern int instance_freeze_updator(struct inst_info *inst);
+extern int instance_thaw_updator(struct inst_info *inst);
+
+extern int instance_send_access_event(struct inst_info *inst, int status);
+
+extern int instance_lb_update_begin(struct inst_info *inst, double priority, const char *content, const char *title);
+extern int instance_lb_update_end(struct inst_info *inst);
+
+extern int instance_pd_update_begin(struct inst_info *inst);
+extern int instance_pd_update_end(struct inst_info *inst);
+
+extern void instance_pd_updated(const char *pkgname, const char *id, const char *descfile);
+extern void instance_lb_updated_by_instance(struct inst_info *inst, const char *safe_file);
+extern void instance_pd_updated_by_instance(struct inst_info *inst, const char *descfile);
+
+/*!
+ * \note
+ * if the status is LB_STATUS_ERROR_FAULT (slave is faulted)
+ * even though the PD is not created, this will forcely send the PD_DESTROYED event to the client.
+ */
+extern int instance_client_pd_destroyed(struct inst_info *inst, int status);
+extern int instance_client_pd_created(struct inst_info *inst, int status);
+
+extern int instance_send_access_status(struct inst_info *inst, int status);
+extern int instance_send_key_status(struct inst_info *inst, int status);
+extern int instance_forward_packet(struct inst_info *inst, struct packet *packet);
+
+extern struct client_node *instance_pd_owner(struct inst_info *inst);
+
+/*!
+ * Multiple viewer
+ */
+extern int instance_add_client(struct inst_info *inst, struct client_node *client);
+extern int instance_del_client(struct inst_info *inst, struct client_node *client);
+extern int instance_has_client(struct inst_info *inst, struct client_node *client);
+extern void *instance_client_list(struct inst_info *inst);
+
+extern int instance_init(void);
+extern int instance_fini(void);
+
+extern int instance_event_callback_add(struct inst_info *inst, enum instance_event type, int (*event_cb)(struct inst_info *inst, void *data), void *data);
+extern int instance_event_callback_del(struct inst_info *inst, enum instance_event type, int (*event_cb)(struct inst_info *inst, void *data), void *data);
+
+/*!
+ */
+extern int instance_set_data(struct inst_info *inst, const char *tag, void *data);
+extern void *instance_del_data(struct inst_info *inst, const char *tag);
+extern void *instance_get_data(struct inst_info *inst, const char *tag);
+
+extern void instance_reload_period(struct inst_info *inst, double period);
+/* End of a file */
diff --git a/include/io.h b/include/io.h
new file mode 100644
index 0000000..c3d83b4
--- /dev/null
+++ b/include/io.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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.
+ */
+
+extern int io_init(void);
+extern int io_fini(void);
+extern int io_load_package_db(struct pkg_info *info);
+extern char *io_livebox_pkgname(const char *pkgname);
+extern int io_update_livebox_package(const char *pkgname, int (*cb)(const char *pkgid, const char *lbid, int prime, void *data), void *data);
+extern int io_crawling_liveboxes(int (*cb)(const char *pkgid, const char *lbid, int prime, void *data), void *data);
+extern int io_is_exists(const char *lbid);
+
+/* End of a file */
diff --git a/include/lite-errno.h b/include/lite-errno.h
new file mode 100644
index 0000000..a46b9f5
--- /dev/null
+++ b/include/lite-errno.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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.
+ */
+
+#ifndef __LIVEBOX_ERRNO_H
+#define __LIVEBOX_ERRNO_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*!
+ * \addtogroup CAPI_LIVEBOX_SERVICE_MODULE
+ * \{
+ */
+
+/*!
+ * \brief
+ * Definitions for the result status of livebox operation.
+ */
+enum livebox_status {
+ LB_STATUS_SUCCESS = 0x00000000, /*!< Operation is successfully completed */
+ LB_STATUS_ERROR = 0x80000000, /*!< This will be OR'd with other specific error value */
+ LB_STATUS_ERROR_INVALID = LB_STATUS_ERROR | 0x0001, /*!< Invalid request */
+ LB_STATUS_ERROR_FAULT = LB_STATUS_ERROR | 0x0002, /*!< Fault - Unable to recover from the error */
+ LB_STATUS_ERROR_MEMORY = LB_STATUS_ERROR | 0x0004, /*!< Memory is not enough to do this operation */
+ LB_STATUS_ERROR_EXIST = LB_STATUS_ERROR | 0x0008, /*!< Already exists */
+ LB_STATUS_ERROR_BUSY = LB_STATUS_ERROR | 0x0010, /*!< Busy so the operation is not started(accepted), try again */
+ LB_STATUS_ERROR_PERMISSION = LB_STATUS_ERROR | 0x0020, /*!< Permission error */
+ LB_STATUS_ERROR_ALREADY = LB_STATUS_ERROR | 0x0040, /*!< Operation is already started */
+ LB_STATUS_ERROR_CANCEL = LB_STATUS_ERROR | 0x0080, /*!< Operation is canceled */
+ LB_STATUS_ERROR_IO = LB_STATUS_ERROR | 0x0100, /*!< I/O Error */
+ LB_STATUS_ERROR_NOT_EXIST = LB_STATUS_ERROR | 0x0200, /*!< Not exists */
+ LB_STATUS_ERROR_TIMEOUT = LB_STATUS_ERROR | 0x0400, /*!< Timeout */
+ LB_STATUS_ERROR_NOT_IMPLEMENTED = LB_STATUS_ERROR | 0x0800, /*!< Operation is not implemented */
+ LB_STATUS_ERROR_NO_SPACE = LB_STATUS_ERROR | 0x1000, /*!< No space to operate */
+ LB_STATUS_ERROR_DISABLED = LB_STATUS_ERROR | 0x2000 /*!< Disabled */
+};
+
+/*!
+ * \brief Check whether given code value indicates error or not.
+ * \param[in] s
+ * \return 1 or 0
+ */
+#define LB_STATUS_IS_ERROR(s) (!!((s) & LB_STATUS_ERROR))
+
+/*!
+ * \}
+ */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+/* End of a file */
+
diff --git a/include/liveinfo.h b/include/liveinfo.h
new file mode 100644
index 0000000..f951e26
--- /dev/null
+++ b/include/liveinfo.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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.
+ */
+
+struct liveinfo;
+
+extern int liveinfo_init(void);
+extern void liveinfo_fini(void);
+extern struct liveinfo *liveinfo_create(pid_t pid, int handle);
+extern void liveinfo_destroy(struct liveinfo *info);
+
+extern struct liveinfo *liveinfo_find_by_pid(pid_t pid);
+extern struct liveinfo *liveinfo_find_by_handle(int handle);
+
+extern const char *liveinfo_filename(struct liveinfo *info);
+extern pid_t liveinfo_pid(struct liveinfo *info);
+extern FILE *liveinfo_fifo(struct liveinfo *info);
+extern int liveinfo_open_fifo(struct liveinfo *info);
+extern void liveinfo_close_fifo(struct liveinfo *info);
+extern void liveinfo_set_data(struct liveinfo *info, void *data);
+extern void *liveinfo_data(struct liveinfo *info);
+
+/* End of a file */
diff --git a/include/main.h b/include/main.h
new file mode 100644
index 0000000..67a71d8
--- /dev/null
+++ b/include/main.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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.
+ */
+
diff --git a/include/notification_service.h b/include/notification_service.h
new file mode 100644
index 0000000..e02dfa3
--- /dev/null
+++ b/include/notification_service.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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.
+ */
+
+extern int notification_service_init(void);
+extern int notification_service_fini(void);
+
+/* End of a file */
diff --git a/include/package.h b/include/package.h
new file mode 100644
index 0000000..dd5d3f6
--- /dev/null
+++ b/include/package.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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.
+ */
+
+enum lb_type {
+ LB_TYPE_NONE = 0x0,
+ LB_TYPE_SCRIPT,
+ LB_TYPE_FILE,
+ LB_TYPE_TEXT,
+ LB_TYPE_BUFFER
+};
+
+enum pd_type {
+ PD_TYPE_NONE = 0x0,
+ PD_TYPE_SCRIPT,
+ PD_TYPE_TEXT,
+ PD_TYPE_BUFFER
+};
+
+enum alter_type {
+ ALTER_CREATE,
+ ALTER_DESTROY
+};
+
+struct pkg_info;
+struct inst_info;
+struct context_info;
+struct slave_node;
+
+/*!
+ * \brief
+ * Construction & Destruction
+ */
+extern struct pkg_info *package_create(const char *pkgid, const char *lbid);
+extern int package_destroy(struct pkg_info *info);
+extern char *package_lb_pkgname(const char *pkgname);
+extern int package_is_lb_pkgname(const char *pkgname);
+extern struct pkg_info *package_find(const char *pkgname);
+extern const char *package_find_by_secured_slave(struct slave_node *slave);
+extern struct inst_info *package_find_instance_by_id(const char *pkgname, const char *id);
+extern struct inst_info *package_find_instance_by_timestamp(const char *pkgname, double timestamp);
+extern int package_dump_fault_info(struct pkg_info *info);
+extern int package_set_fault_info(struct pkg_info *info, double timestamp, const char *filename, const char *function);
+extern int package_get_fault_info(struct pkg_info *info, double *timestmap, const char **filename, const char **function);
+
+/*!
+ * \brief
+ * Readonly functions
+ */
+extern const int const package_is_fault(const struct pkg_info *info);
+extern struct slave_node * const package_slave(const struct pkg_info *info);
+extern const int const package_timeout(const struct pkg_info *info);
+extern const double const package_period(const struct pkg_info *info);
+extern const int const package_secured(const struct pkg_info *info);
+extern const char * const package_script(const struct pkg_info *info);
+extern const char * const package_abi(const struct pkg_info *info);
+extern const char * const package_lb_path(const struct pkg_info *info);
+extern const char * const package_lb_group(const struct pkg_info *info);
+extern const char * const package_pd_path(const struct pkg_info *info);
+extern const char * const package_pd_group(const struct pkg_info *info);
+extern const int const package_pinup(const struct pkg_info *info);
+extern const char * const package_auto_launch(const struct pkg_info *info);
+extern const unsigned int const package_size_list(const struct pkg_info *info);
+extern const int const package_pd_width(const struct pkg_info *info);
+extern const int const package_pd_height(const struct pkg_info *info);
+extern const char * const package_name(const struct pkg_info *info);
+extern const char * const package_libexec(struct pkg_info *info);
+extern int package_network(struct pkg_info *info);
+extern Eina_List *package_ctx_info(struct pkg_info *pkginfo);
+
+extern int package_set_libexec(struct pkg_info *info, const char *libexec);
+extern void package_set_pinup(struct pkg_info *info, int pinup);
+extern void package_set_auto_launch(struct pkg_info *info, const char *auto_launch);
+extern void package_set_size_list(struct pkg_info *info, unsigned int size_list);
+extern void package_set_lb_type(struct pkg_info *info, enum lb_type type);
+extern void package_set_pd_type(struct pkg_info *info, enum pd_type type);
+extern int package_set_lb_group(struct pkg_info *info, const char *group);
+extern int package_set_lb_path(struct pkg_info *info, const char *path);
+extern int package_set_pd_group(struct pkg_info *info, const char *group);
+extern int package_set_pd_path(struct pkg_info *info, const char *path);
+extern int package_set_script(struct pkg_info *info, const char *script);
+extern void package_set_secured(struct pkg_info *info, int secured);
+extern void package_set_period(struct pkg_info *info, double period);
+extern void package_set_timeout(struct pkg_info *info, int timeout);
+extern void package_set_network(struct pkg_info *info, int network);
+extern void package_set_pd_height(struct pkg_info *info, int height);
+extern void package_set_pd_width(struct pkg_info *info, int width);
+extern int package_set_abi(struct pkg_info *info, const char *abi);
+extern void package_add_ctx_info(struct pkg_info *pkginfo, struct context_info *info);
+extern void package_del_ctx_info(struct pkg_info *pkginfo, struct context_info *info);
+
+/*!
+ * \brief
+ * Reference counter
+ */
+extern struct pkg_info * const package_ref(struct pkg_info *info);
+extern struct pkg_info * const package_unref(struct pkg_info *info);
+extern const int const package_refcnt(const struct pkg_info *info);
+
+extern const enum pd_type const package_pd_type(const struct pkg_info *info);
+extern const enum lb_type const package_lb_type(const struct pkg_info *info);
+
+extern int package_add_instance(struct pkg_info *info, struct inst_info *inst);
+extern int package_del_instance(struct pkg_info *info, struct inst_info *inst);
+extern Eina_List *package_instance_list(struct pkg_info *info);
+
+extern int package_clear_fault(struct pkg_info *info);
+extern int package_alter_instances_to_client(struct client_node *client, enum alter_type alter);
+
+extern const Eina_List *package_list(void);
+extern int const package_fault_count(struct pkg_info *info);
+
+extern int package_init(void);
+extern int package_fini(void);
+
+extern int package_is_enabled(const char *appid);
+extern int package_faulted(struct pkg_info *info, int broadcast);
+
+/* End of a file */
diff --git a/include/parser.h b/include/parser.h
new file mode 100644
index 0000000..16e297a
--- /dev/null
+++ b/include/parser.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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.
+ */
+
+struct parser;
+
+extern struct parser *parser_load(const char *filename);
+extern int parser_unload(struct parser *handle);
+extern double parser_period(struct parser *handle);
+extern int parser_network(struct parser *handle);
+extern int parser_timeout(struct parser *handle);
+extern const char *parser_auto_launch(struct parser *handle);
+extern unsigned int parser_size(struct parser *handle);
+extern void parser_get_pdsize(struct parser *handle, unsigned int *width, unsigned int *height);
+extern const char *parser_group_str(struct parser *handle);
+extern int parser_secured(struct parser *handle);
+extern int parser_pinup(struct parser *handler);
+
+extern const char *parser_lb_path(struct parser *handle);
+extern const char *parser_lb_group(struct parser *handle);
+extern const char *parser_pd_path(struct parser *handle);
+extern const char *parser_pd_group(struct parser *handle);
+
+extern const char *parser_abi(struct parser *handle);
+
+extern int parser_text_pd(struct parser *handle);
+extern int parser_text_lb(struct parser *handle);
+extern int parser_buffer_lb(struct parser *handle);
+extern int parser_buffer_pd(struct parser *handle);
+
+extern const char *parser_script(struct parser *handle);
+
+/* End of a file */
diff --git a/include/pkgmgr.h b/include/pkgmgr.h
new file mode 100644
index 0000000..e4fe4c2
--- /dev/null
+++ b/include/pkgmgr.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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.
+ */
+
+enum pkgmgr_event_type {
+ PKGMGR_EVENT_DOWNLOAD,
+ PKGMGR_EVENT_INSTALL,
+ PKGMGR_EVENT_UPDATE,
+ PKGMGR_EVENT_UNINSTALL,
+ PKGMGR_EVENT_RECOVER
+};
+
+enum pkgmgr_status {
+ PKGMGR_STATUS_START,
+ PKGMGR_STATUS_PROCESSING,
+ PKGMGR_STATUS_COMMAND,
+ PKGMGR_STATUS_END,
+ PKGMGR_STATUS_ERROR
+};
+
+extern int pkgmgr_init(void);
+extern int pkgmgr_fini(void);
+
+extern int pkgmgr_add_event_callback(enum pkgmgr_event_type type, int (*cb)(const char *pkgname, enum pkgmgr_status status, double value, void *data), void *data);
+
+extern void *pkgmgr_del_event_callback(enum pkgmgr_event_type type, int (*cb)(const char *pkgname, enum pkgmgr_status status, double value, void *data), void *data);
+
+/* End of a file */
diff --git a/include/rpc_to_slave.h b/include/rpc_to_slave.h
new file mode 100644
index 0000000..d80c021
--- /dev/null
+++ b/include/rpc_to_slave.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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.
+ */
+
+extern int rpc_send_new(struct inst_info *inst, void (*ret_cb)(const char *funcname, GVariant *result, void *data), void *data, int skip_need_to_create);
+extern int rpc_send_renew(struct inst_info *inst, void (*ret_cb)(const char *funcname, GVariant *result, void *data), void *data);
+
+extern void rpc_send_update_request(const char *pkgname, const char *cluster, const char *category);
+/*!
+ * \brief
+ * \param[in] period if it is negative value, the data provider will use the default period
+ */
+extern struct inst_info *rpc_send_create_request(struct client_node *client, const char *pkgname, const char *content, const char *cluster, const char *category, double timestamp, double period);
+extern void rpc_send_resume_request(void);
+extern void rpc_send_pause_request(void);
+
+/* End of a file */
diff --git a/include/script_handler.h b/include/script_handler.h
new file mode 100644
index 0000000..5e84f2b
--- /dev/null
+++ b/include/script_handler.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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.
+ */
+
+struct script_info;
+struct fb_info;
+
+extern struct script_info *script_handler_create(struct inst_info *inst, const char *file, const char *group, int w, int h);
+extern int script_handler_destroy(struct script_info *info);
+extern int script_handler_parse_desc(struct inst_info *inst, const char *descfile, int is_pd);
+extern int script_handler_unload(struct script_info *info, int is_pd);
+extern int script_handler_load(struct script_info *info, int is_pd);
+extern int script_handler_is_loaded(struct script_info *info);
+extern int script_handler_feed_event(struct script_info *info, int event, double timestamp);
+
+extern int script_init(void);
+extern int script_fini(void);
+
+extern int script_signal_emit(void *buffer_handle, const char *part, const char *signal, double sx, double sy, double ex, double ey);
+
+extern int script_handler_update_pointer(struct script_info *inst, int x, int y, int down);
+extern int script_handler_update_keycode(struct script_info *info, unsigned int keycode);
+extern int script_handler_resize(struct script_info *info, int w, int h);
+extern const char *script_handler_buffer_id(struct script_info *info);
+extern struct buffer_info *script_handler_buffer_info(struct script_info *info);
+
+/* End of a file */
diff --git a/include/server.h b/include/server.h
new file mode 100644
index 0000000..457ab15
--- /dev/null
+++ b/include/server.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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.
+ */
+
+extern int server_init(void);
+extern int server_fini(void);
+
+/* End of a file */
diff --git a/include/service_common.h b/include/service_common.h
new file mode 100644
index 0000000..f0dbf96
--- /dev/null
+++ b/include/service_common.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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.
+ */
+enum tcb_type {
+ TCB_CLIENT_TYPE_APP = 0x00,
+ TCB_CLIENT_TYPE_SERVICE = 0x01,
+ TCB_CLIENT_TYPE_UNKNOWN = 0xff
+};
+
+enum tcb_event_type {
+ TCB_EVENT_CREATE = 0x01,
+ TCB_EVENT_DESTROY = 0x02
+};
+
+struct tcb;
+struct service_context;
+struct service_event_item;
+
+extern int tcb_fd(struct tcb *tcb);
+
+/*!
+ * \remarks This function will return valid pid only after it gets the packet from a client.
+ * or it will returns -1.
+ * \param[in] Thread Control Block
+ * \return pid Process Id
+ * \retval -1 TCB is not valid or the client is remote host. so we cannot get the PID of it.
+ * \retval >0 Process Id (PID)
+ */
+extern int tcb_pid(struct tcb *tcb);
+
+extern struct service_context *tcb_svc_ctx(struct tcb *tcb);
+extern int tcb_client_type(struct tcb *tcb);
+extern int tcb_client_type_set(struct tcb *tcb, enum tcb_type type);
+extern int tcb_is_valid(struct service_context *svc_ctx, struct tcb *tcb);
+
+extern struct service_context *service_common_create(const char *addr, int (*service_thread_main)(struct tcb *tcb, struct packet *packet, void *data), void *data);
+extern int service_common_destroy(struct service_context *svc_ctx);
+
+extern int service_common_multicast_packet(struct tcb *tcb, struct packet *packet, int type);
+extern int service_common_unicast_packet(struct tcb *tcb, struct packet *packet);
+
+extern struct service_event_item *service_common_add_timer(struct service_context *svc_ctx, double timer, int (*timer_cb)(struct service_context *svc_cx, void *data), void *data);
+extern int service_common_update_timer(struct service_event_item *item, double timer);
+extern int service_common_del_timer(struct service_context *svc_ctx, struct service_event_item *item);
+
+extern int service_common_fd(struct service_context *ctx);
+
+extern int service_register_tcb_callback(struct service_context *svc_ctx, struct tcb *tcb, enum tcb_event_type event, void (*cb)(struct service_context *svc_ctx, struct tcb *tcb, void *data), void *data);
+extern int service_unregister_tcb_callback(struct service_context *svc_ctx, struct tcb *tcb, enum tcb_event_type event, void (*cb)(struct service_context *svc_ctx, struct tcb *tcb, void *data), void *data);
+
+/* End of a file */
diff --git a/include/setting.h b/include/setting.h
new file mode 100644
index 0000000..6d0700f
--- /dev/null
+++ b/include/setting.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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.
+ */
+
+extern int setting_is_lcd_off(void);
+extern int setting_init(void);
+extern int setting_fini(void);
+
+/* End of a file */
diff --git a/include/shortcut_service.h b/include/shortcut_service.h
new file mode 100644
index 0000000..2810039
--- /dev/null
+++ b/include/shortcut_service.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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.
+ */
+
+extern int shortcut_service_init(void);
+extern int shortcut_service_fini(void);
+
+/* End of a file */
diff --git a/include/slave_life.h b/include/slave_life.h
new file mode 100644
index 0000000..7f477f3
--- /dev/null
+++ b/include/slave_life.h
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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.
+ */
+
+/*!
+ * Managing the reference counter of a slave
+ */
+
+struct slave_node;
+
+enum slave_event {
+ SLAVE_EVENT_ACTIVATE,
+ SLAVE_EVENT_DEACTIVATE, /* deactivate callback, can return REACTIVATE, DEFAULT */
+ SLAVE_EVENT_DELETE,
+ SLAVE_EVENT_FAULT, /* Critical fault */
+
+ SLAVE_EVENT_PAUSE,
+ SLAVE_EVENT_RESUME,
+
+ SLAVE_NEED_TO_REACTIVATE
+};
+
+enum slave_state {
+ /*!
+ * Launch the slave but not yet receives "hello" packet
+ */
+ SLAVE_REQUEST_TO_LAUNCH,
+
+ /*!
+ * \note
+ * Terminate the slave but not yet receives dead signal
+ */
+ SLAVE_REQUEST_TO_TERMINATE,
+
+ /*!
+ * \note
+ * No slave process exists, just slave object created
+ */
+ SLAVE_TERMINATED,
+
+ /*!
+ * \note
+ * State change request is sent,
+ */
+ SLAVE_REQUEST_TO_PAUSE,
+ SLAVE_REQUEST_TO_RESUME,
+
+ /*!
+ * \note
+ * Request an action for disconnecting to master from the provider side.
+ * This flag should be treated as an activated state.
+ */
+ SLAVE_REQUEST_TO_DISCONNECT,
+
+ /*!
+ * \note
+ * SLAVE_ACTIVATED = { SLAVE_PAUSED, SLAVE_RESUMED }
+ */
+ SLAVE_PAUSED,
+ SLAVE_RESUMED,
+
+ SLAVE_ERROR = 0xFF /* Explicitly define the size of this enum type */
+};
+
+enum PROVIDER_CTRL {
+ PROVIDER_CTRL_DEFAULT = 0x00, /*!< Set default control operation */
+ PROVIDER_CTRL_MANUAL_TERMINATION = 0x01, /*!< Terminate process manually */
+ PROVIDER_CTRL_MANUAL_REACTIVATION = 0x02, /*!< Reactivate process manually */
+};
+
+extern struct slave_node *slave_ref(struct slave_node *slave);
+extern struct slave_node *slave_unref(struct slave_node *slave);
+extern const int const slave_refcnt(struct slave_node *slave);
+
+/*!
+ * \brief
+ * Create a new slave object or destroy it
+ *
+ * \param[in] name
+ * \param[in] is_secured
+ * \param[in] abi
+ * \param[in] pkgname
+ * \param[in] period
+ * \return slave_node
+ */
+extern struct slave_node *slave_create(const char *name, int is_secured, const char *abi, const char *pkgname, int network);
+
+/*!
+ * \brief
+ * \param[in] slave
+ * \return void
+ */
+extern void slave_destroy(struct slave_node *slave);
+
+/*!
+ * \brief
+ * Launch or terminate a slave
+ * \param[in] slave
+ * \return int
+ */
+extern int slave_activate(struct slave_node *slave);
+
+/*!
+ * \brief After this function call, the slave object can be deleted
+ * \param[in] slave
+ */
+extern struct slave_node *slave_deactivate(struct slave_node *slave, int direct) __attribute__((warn_unused_result));
+
+/*!
+ * To check the slave's activation state
+ */
+extern const int const slave_is_activated(struct slave_node *slave);
+extern int slave_activated(struct slave_node *slave);
+
+extern int slave_give_more_ttl(struct slave_node *slave);
+extern int slave_freeze_ttl(struct slave_node *slave);
+extern int slave_thaw_ttl(struct slave_node *slave);
+extern int slave_expired_ttl(struct slave_node *slave);
+
+/*!
+ * \NOTE
+ * To mangage the unexpected termination of a slave
+ * After this function call, the slave object can be deleted
+ */
+extern struct slave_node *slave_deactivated_by_fault(struct slave_node *slave) __attribute__((warn_unused_result));
+
+/*!
+ * \NOTE
+ * After this function, the slave object can be deleted
+ */
+extern struct slave_node *slave_deactivated(struct slave_node *slave) __attribute__((warn_unused_result));
+
+extern int slave_event_callback_add(struct slave_node *slave, enum slave_event event, int (*cb)(struct slave_node *, void *), void *data);
+extern int slave_event_callback_del(struct slave_node *slave, enum slave_event event, int (*cb)(struct slave_node *, void *), void *data);
+
+extern int slave_set_data(struct slave_node *slave, const char *tag, void *data);
+extern void *slave_del_data(struct slave_node *slave, const char *tag);
+extern void *slave_data(struct slave_node *slave, const char *tag);
+
+extern struct slave_node *slave_find_by_pid(pid_t pid);
+extern struct slave_node *slave_find_by_name(const char *name);
+extern struct slave_node *slave_find_by_pkgname(const char *pkgname);
+extern struct slave_node *slave_find_by_rpc_handle(int handle);
+
+extern void slave_dead_handler(struct slave_node *slave);
+extern const int const slave_is_secured(const struct slave_node *slave);
+extern const char * const slave_name(const struct slave_node *slave);
+extern const pid_t const slave_pid(const struct slave_node *slave);
+extern const char * const slave_abi(const struct slave_node *slave);
+extern int slave_set_pid(struct slave_node *slave, pid_t pid);
+
+/*!
+ * \note
+ * Used for making decision of destroying a slave or not
+ * Used for balancing load of the slave.
+ */
+extern void slave_load_package(struct slave_node *slave);
+extern void slave_unload_package(struct slave_node *slave);
+extern int const slave_loaded_package(struct slave_node *slave);
+extern struct slave_node *slave_find_available(const char *abi, int secured, int network);
+
+extern double const slave_ttl(const struct slave_node *slave);
+
+/*!
+ * \note
+ * Used for making decision of activating a slave or not
+ */
+extern void slave_load_instance(struct slave_node *slave);
+
+/*!
+ * \NOTE
+ * After this function call, the slave object can be deleted.
+ */
+extern struct slave_node *slave_unload_instance(struct slave_node *slave) __attribute__((warn_unused_result));
+
+extern int const slave_loaded_instance(struct slave_node *slave);
+
+extern int slave_resume(struct slave_node *slave);
+extern int slave_pause(struct slave_node *slave);
+
+extern const char *slave_pkgname(const struct slave_node *slave);
+extern enum slave_state slave_state(const struct slave_node *slave);
+extern const char *slave_state_string(const struct slave_node *slave);
+
+extern const void *slave_list(void);
+extern int const slave_fault_count(const struct slave_node *slave);
+
+extern int slave_need_to_reactivate_instances(struct slave_node *slave);
+extern void slave_set_reactivate_instances(struct slave_node *slave, int reactivate);
+
+extern void slave_set_reactivation(struct slave_node *slave, int flag);
+extern int slave_need_to_reactivate(struct slave_node *slave);
+
+extern int slave_network(const struct slave_node *slave);
+extern void slave_set_network(struct slave_node *slave, int network);
+
+extern int slave_deactivate_all(int reactivate, int reactivate_instances, int no_timer);
+extern int slave_activate_all(void);
+
+extern void slave_set_control_option(struct slave_node *slave, int ctrl);
+extern int slave_control_option(struct slave_node *slave);
+
+/* End of a file */
diff --git a/include/slave_rpc.h b/include/slave_rpc.h
new file mode 100644
index 0000000..f5dc7fa
--- /dev/null
+++ b/include/slave_rpc.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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.
+ */
+
+extern int slave_rpc_async_request(struct slave_node *slave, const char *pkgname, struct packet *packet, void (*ret_cb)(struct slave_node *slave, const struct packet *packet, void *data), void *data, int urgent);
+extern int slave_rpc_request_only(struct slave_node *slave, const char *pkgname, struct packet *packet, int urgent);
+
+extern int slave_rpc_update_handle(struct slave_node *slave, int handle);
+extern int slave_rpc_ping(struct slave_node *slave);
+extern void slave_rpc_request_update(const char *pkgname, const char *id, const char *cluster, const char *category, const char *content, int force);
+extern int slave_rpc_handle(struct slave_node *slave);
+extern int slave_rpc_ping_freeze(struct slave_node *slave);
+extern int slave_rpc_ping_thaw(struct slave_node *slave);
+
+extern int slave_rpc_disconnect(struct slave_node *slave);
+
+extern int slave_rpc_init(struct slave_node *slave);
+extern int slave_rpc_fini(struct slave_node *slave);
+
+/* End of a file */
diff --git a/include/util.h b/include/util.h
new file mode 100644
index 0000000..4f32a76
--- /dev/null
+++ b/include/util.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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.
+ */
+
+extern unsigned long util_string_hash(const char *str);
+extern double util_timestamp(void);
+extern int util_check_ext(const char *filename, const char *check_ptr);
+extern int util_validate_livebox_package(const char *pkgname);
+extern int util_unlink(const char *filename);
+extern int util_unlink_files(const char *folder);
+extern char *util_slavename(void);
+extern const char *util_basename(const char *name);
+extern unsigned long long util_free_space(const char *path);
+extern char *util_replace_string(const char *src, const char *pattern, const char *replace);
+extern const char *util_uri_to_path(const char *uri);
+extern void *util_timer_add(double interval, Eina_Bool (*cb)(void *data), void *data);
+extern void util_timer_interval_set(void *timer, double interval);
+extern double util_time_delay_for_compensation(double period);
+extern void util_setup_log_disk(void);
+extern void util_remove_emergency_disk(void);
+extern void util_prepare_emergency_disk(void);
+extern int util_emergency_disk_is_mounted(void);
+extern int util_service_is_enabled(const char *tag);
+
+extern int util_screen_size_get(int *width, int *height);
+extern int util_screen_init(void);
+extern int util_screen_fini(void);
+
+#define SCHEMA_FILE "file://"
+#define SCHEMA_PIXMAP "pixmap://"
+#define SCHEMA_SHM "shm://"
+
+#define CRITICAL_SECTION_BEGIN(handle) \
+do { \
+ int ret; \
+ ret = pthread_mutex_lock(handle); \
+ if (ret != 0) \
+ ErrPrint("Failed to lock: %s\n", strerror(ret)); \
+} while (0)
+
+#define CRITICAL_SECTION_END(handle) \
+do { \
+ int ret; \
+ ret = pthread_mutex_unlock(handle); \
+ if (ret != 0) \
+ ErrPrint("Failed to unlock: %s\n", strerror(ret)); \
+} while (0)
+
+#define CANCEL_SECTION_BEGIN() do { \
+ int ret; \
+ ret = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL); \
+ if (ret != 0) \
+ ErrPrint("Unable to set cancelate state: %s\n", strerror(ret)); \
+} while (0)
+
+#define CANCEL_SECTION_END() do { \
+ int ret; \
+ ret = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL); \
+ if (ret != 0) \
+ ErrPrint("Unable to set cancelate state: %s\n", strerror(ret)); \
+} while (0)
+
+#define CLOSE_PIPE(p) do { \
+ int status; \
+ status = close(p[PIPE_READ]); \
+ if (status < 0) \
+ ErrPrint("close: %s\n", strerror(errno)); \
+ status = close(p[PIPE_WRITE]); \
+ if (status < 0) \
+ ErrPrint("close: %s\n", strerror(errno)); \
+} while (0)
+
+#define PIPE_READ 0
+#define PIPE_WRITE 1
+#define PIPE_MAX 2
+
+/* End of a file */
diff --git a/include/utility_service.h b/include/utility_service.h
new file mode 100644
index 0000000..db80cd0
--- /dev/null
+++ b/include/utility_service.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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.
+ */
+
+extern int utility_service_init(void);
+extern int utility_service_fini(void);
+
+/* End of a file */
+
diff --git a/include/xmonitor.h b/include/xmonitor.h
new file mode 100644
index 0000000..3e01722
--- /dev/null
+++ b/include/xmonitor.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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.
+ */
+
+enum xmonitor_event {
+ XMONITOR_PAUSED,
+ XMONITOR_RESUMED,
+
+ XMONITOR_ERROR = 0xFFFFFFFF /* To specify the size of this enum */
+};
+
+extern int xmonitor_init(void);
+extern void xmonitor_fini(void);
+extern int xmonitor_update_state(int pid);
+extern int xmonitor_add_event_callback(enum xmonitor_event event, int (*cb)(void *user_data), void *user_data);
+extern int xmonitor_del_event_callback(enum xmonitor_event event, int (*cb)(void *user_data), void *user_data);
+extern int xmonitor_is_paused(void);
+extern void xmonitor_handle_state_changes(void);
+extern int xmonitor_resume(struct client_node *client);
+extern int xmonitor_pause(struct client_node *client);
+
+/* End of a file */
diff --git a/packaging/data-provider-master.changes b/packaging/data-provider-master.changes
new file mode 100644
index 0000000..5e22b27
--- /dev/null
+++ b/packaging/data-provider-master.changes
@@ -0,0 +1,8 @@
+* Wed Sep 11 2013 Rusty Lynch <rusty.lynch@intel.com> accepted/tizen/20130620.160431@d15ede1
+- Add support for systemd socket activation for notification service
+
+* Thu Jun 20 2013 Victor Hakoun <victor.hakoun@eurogiciel.fr> accepted/tizen/20130620.115235@e8bd452
+- Replace manifest with default floor
+
+* Fri Jun 07 2013 Victor Hakoun <victor.hakoun@eurogiciel.fr> accepted/tizen/20130530.164904@68752b5
+- Fix build x86_64
diff --git a/packaging/data-provider-master.manifest b/packaging/data-provider-master.manifest
new file mode 100644
index 0000000..5efa5e7
--- /dev/null
+++ b/packaging/data-provider-master.manifest
@@ -0,0 +1,70 @@
+<manifest>
+ <!-- Provider master label -->
+ <define>
+ <domain name="data-provider-master" policy="restricted" />
+ <provide>
+ <label name="data-provider-master::log" />
+ <label name="data-provider-master::db" />
+ <label name="data-provider-master::data" />
+ <label name="data-provider-master::share" />
+ <label name="data-provider-master::shortcut" />
+ <label name="data-provider-master::shortcut.shortcut" />
+ <label name="data-provider-master::shortcut.livebox" />
+ <label name="data-provider-master::badge" />
+ <label name="data-provider-master::badge.client" />
+ <label name="data-provider-master::notification" />
+ <label name="data-provider-master::notification.client" />
+ <label name="data-provider-master::utility" />
+ </provide>
+ <request>
+ <smack request="sys-assert::core" type="rwxat" />
+ <smack request="security-server::api-privilege-by-pid" type="w" />
+ <!--
+ <smack request="notification::db" type="rw" />
+ <smack request="badge::db" type="rw" />
+ -->
+ </request>
+ <permit>
+ <smack permit="dbus" type="rx" />
+ </permit>
+ </define>
+ <request>
+ <domain name="_" />
+ </request>
+
+ <assign>
+ <!-- Executable file -->
+ <filesystem path="/usr/bin/data-provider-master" label="data-provider-master" exec_label="data-provider-master" />
+ <filesystem path="/opt/usr/devel/usr/bin/liveinfo" label="data-provider-master" exec_label="data-provider-master" />
+ <filesystem path="/opt/usr/devel/usr/bin" label="_" />
+
+ <!-- Configuration data -->
+ <filesystem path="/usr/share/data-provider-master" label="data-provider-master::data" />
+ <filesystem path="/usr/share/data-provider-master/abi.ini" label="data-provider-master::data" />
+
+ <!-- livebox-service is able to access the resolution.ini file -->
+ <filesystem path="/usr/share/data-provider-master/resolution.ini" label="_" />
+
+ <!-- Slave provider and the master provider are able to access the conf.ini file -->
+ <filesystem path="/usr/share/data-provider-master/conf.ini" label="data-provider-master::data" />
+
+ <!-- Shared data folder -->
+ <filesystem path="/opt/usr/share/live_magazine" label="data-provider-master::share" type="transmutable" />
+ <filesystem path="/opt/usr/share/live_magazine/log" label="data-provider-master::share" type="transmutable" />
+ <filesystem path="/opt/usr/share/live_magazine/reader" label="data-provider-master::share" type="transmutable" />
+ <filesystem path="/opt/usr/share/live_magazine/always" label="data-provider-master::share" type="transmutable" />
+
+ <!-- Database -->
+ <filesystem path="/opt/dbspace/.livebox.db" label="data-provider-master::db" />
+ <filesystem path="/opt/dbspace/.livebox.db-journal" label="data-provider-master::db" />
+
+ <filesystem path="/usr/lib/systemd/system/data-provider-master.service" label="_" />
+ <filesystem path="/usr/lib/systemd/system/multi-user.target.wants/data-provider-master.service" label="_" />
+
+ <!-- Package manager plugin -->
+ <filesystem path="/usr/etc/package-manager/parserlib/liblivebox.so" label="_" />
+
+ <!-- Logdump script -->
+ <filesystem path="/opt/etc/dump.d/module.d/dump_livebox.sh" label="_" exec_label="_" />
+ </assign>
+</manifest>
diff --git a/packaging/data-provider-master.spec b/packaging/data-provider-master.spec
new file mode 100755
index 0000000..ad79dc6
--- /dev/null
+++ b/packaging/data-provider-master.spec
@@ -0,0 +1,205 @@
+%bcond_with wayland
+
+Name: data-provider-master
+Summary: Master service provider for liveboxes
+Version: 0.43.2
+Release: 1
+Group: HomeTF/Livebox
+License: Flora
+Source0: %{name}-%{version}.tar.gz
+Source1001: %{name}.manifest
+BuildRequires: cmake, gettext-tools, smack, coreutils
+BuildRequires: pkgconfig(ail)
+BuildRequires: pkgconfig(dlog)
+BuildRequires: pkgconfig(aul)
+BuildRequires: pkgconfig(vconf)
+BuildRequires: pkgconfig(sqlite3)
+BuildRequires: pkgconfig(db-util)
+BuildRequires: pkgconfig(glib-2.0)
+BuildRequires: pkgconfig(gio-2.0)
+BuildRequires: pkgconfig(libsmack)
+BuildRequires: pkgconfig(bundle)
+
+%if %{with wayland}
+BuildRequires: pkgconfig(ecore-wayland)
+%else
+BuildRequires: pkgconfig(ecore-x)
+BuildRequires: pkgconfig(x11)
+BuildRequires: pkgconfig(libdri2)
+BuildRequires: pkgconfig(libdrm)
+BuildRequires: pkgconfig(libtbm)
+BuildRequires: pkgconfig(xfixes)
+BuildRequires: pkgconfig(dri2proto)
+BuildRequires: pkgconfig(xext)
+BuildRequires: pkgconfig(xdamage)
+%endif
+
+BuildRequires: pkgconfig(ecore)
+BuildRequires: pkgconfig(eina)
+BuildRequires: pkgconfig(com-core)
+BuildRequires: pkgconfig(libxml-2.0)
+BuildRequires: pkgconfig(pkgmgr)
+
+%if "%{sec_product_feature_livebox}" != "0"
+BuildRequires: pkgconfig(livebox-service)
+%endif
+
+BuildRequires: pkgconfig(notification)
+BuildRequires: pkgconfig(notification-service)
+BuildRequires: pkgconfig(badge)
+BuildRequires: pkgconfig(badge-service)
+BuildRequires: pkgconfig(shortcut)
+BuildRequires: pkgconfig(security-server)
+BuildRequires: pkgconfig(libsystemd-daemon)
+Requires(post): sys-assert
+Requires(post): dbus
+
+%description
+Manage the 2nd stage livebox service provider and communicate with the viewer application.
+Keep trace on the life-cycle of the livebox and status of the service providers, viewer applications.
+
+%prep
+%setup -q
+cp %{SOURCE1001} .
+
+%build
+%if 0%{?sec_build_binary_debug_enable}
+export CFLAGS="$CFLAGS -DTIZEN_DEBUG_ENABLE"
+export CXXFLAGS="$CXXFLAGS -DTIZEN_DEBUG_ENABLE"
+export FFLAGS="$FFLAGS -DTIZEN_DEBUG_ENABLE"
+%endif
+
+export ENGINEER=false
+%if 0%{?tizen_build_binary_release_type_eng}
+export CFLAGS="${CFLAGS} -DTIZEN_ENGINEER_MODE"
+export CXXFLAGS="${CXXFLAGS} -DTIZEN_ENGINEER_MODE"
+export FFLAGS="${FFLAGS} -DTIZEN_ENGINEER_MODE"
+export ENGINEER=true
+%endif
+
+%if %{with wayland}
+export WAYLAND_SUPPORT=On
+export X11_SUPPORT=Off
+export LIVEBOX_SHM=wayland
+%else
+export WAYLAND_SUPPORT=Off
+export X11_SUPPORT=On
+export LIVEBOX_SHM=x11
+%endif
+
+%if "%{_repository}" == "wearable"
+export LIVEBOX_SHM="${LIVEBOX_SHM}.wearable"
+export MOBILE=Off
+export WEARABLE=On
+%else
+export LIVEBOX_SHM="${LIVEBOX_SHM}.mobile"
+export MOBILE=On
+export WEARABLE=Off
+%endif
+
+%if "%{sec_product_feature_livebox}" == "0"
+export LIVEBOX=Off
+%else
+export LIVEBOX=On
+%endif
+
+%cmake . -DPRODUCT=${LIVEBOX_SHM} -DENGINEER_BINARY=${ENGINEER} -DWAYLAND_SUPPORT=${WAYLAND_SUPPORT} -DX11_SUPPORT=${X11_SUPPORT} -DMOBILE=${MOBILE} -DWEARABLE=${WEARABLE} -DLIVEBOX=${LIVEBOX}
+
+CFLAGS="${CFLAGS} -Wall -Winline -Werror" LDFLAGS="${LDFLAGS}" make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+%make_install
+mkdir -p %{buildroot}/%{_datarootdir}/license
+%if "%{_repository}" == "wearable"
+mkdir -p %{buildroot}%{_libdir}/systemd/system/multi-user.target.wants
+ln -sf ../data-provider-master.service %{buildroot}%{_libdir}/systemd/system/multi-user.target.wants/data-provider-master.service
+%else
+mkdir -p %{buildroot}/%{_libdir}/systemd/user/tizen-middleware.target.wants
+ln -sf %{_libdir}/systemd/user/data-provider-master.service %{buildroot}/%{_libdir}/systemd/user/tizen-middleware.target.wants/data-provider-master.service
+%endif
+
+%if "%{sec_product_feature_livebox}" == "0"
+# Nothing provides
+%else
+mkdir -p %{buildroot}/opt/usr/share/live_magazine
+mkdir -p %{buildroot}/opt/usr/share/live_magazine/log
+mkdir -p %{buildroot}/opt/usr/share/live_magazine/reader
+mkdir -p %{buildroot}/opt/usr/share/live_magazine/always
+mkdir -p %{buildroot}/opt/usr/devel/usr/bin
+mkdir -p %{buildroot}/opt/dbspace
+touch %{buildroot}/opt/dbspace/.livebox.db
+touch %{buildroot}/opt/dbspace/.livebox.db-journal
+if [ ! -s %{buildroot}/opt/dbspace/.livebox.db ]; then
+echo "LiveBox DB file is not exists, initiate it"
+sqlite3 %{buildroot}/opt/dbspace/.livebox.db <<EOF
+CREATE TABLE version ( version INTEGER );
+CREATE TABLE box_size ( pkgid TEXT NOT NULL, size_type INTEGER, preview TEXT, touch_effect INTEGER, need_frame INTEGER, mouse_event INTEGER, FOREIGN KEY(pkgid) REFERENCES pkgmap(pkgid) ON DELETE CASCADE);
+CREATE TABLE client (pkgid TEXT PRIMARY KEY NOT NULL, icon TEXT, name TEXT, auto_launch TEXT, pd_size TEXT, content TEXT, nodisplay INTEGER, setup TEXT, FOREIGN KEY(pkgid) REFERENCES pkgmap(pkgid) ON DELETE CASCADE);
+CREATE TABLE groupinfo ( id INTEGER PRIMARY KEY AUTOINCREMENT, cluster TEXT NOT NULL, category TEXT NOT NULL, pkgid TEXT NOT NULL, FOREIGN KEY(pkgid) REFERENCES pkgmap(pkgid) ON DELETE CASCADE);
+CREATE TABLE groupmap (option_id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER, pkgid TEXT NOT NULL, ctx_item TEXT NOT NULL, FOREIGN KEY(id) REFERENCES groupinfo(id), FOREIGN KEY(pkgid) REFERENCES pkgmap(pkgid) ON DELETE CASCADE);
+CREATE TABLE i18n ( pkgid TEXT NOT NULL, lang TEXT COLLATE NOCASE, name TEXT, icon TEXT, FOREIGN KEY(pkgid) REFERENCES pkgmap(pkgid) ON DELETE CASCADE);
+CREATE TABLE option ( pkgid TEXT NOT NULL, option_id INTEGER, key TEXT NOT NULL, value TEXT NOT NULL, FOREIGN KEY(option_id) REFERENCES groupmap(option_id), FOREIGN KEY(pkgid) REFERENCES pkgmap(pkgid) ON DELETE CASCADE);
+CREATE TABLE pkgmap ( pkgid TEXT PRIMARY KEY NOT NULL, appid TEXT, uiapp TEXT, prime INTEGER, category TEXT DEFAULT 'http://tizen.org/category/default' );
+CREATE TABLE provider ( pkgid TEXT PRIMARY KEY NOT NULL, network INTEGER, abi TEXT, secured INTEGER, box_type INTEGER, box_src TEXT, box_group TEXT, pd_type INTEGER, pd_src TEXT, pd_group TEXT, libexec TEXT, timeout INTEGER, period TEXT, script TEXT, pinup INTEGER, FOREIGN KEY(pkgid) REFERENCES pkgmap(pkgid) ON DELETE CASCADE);
+EOF
+fi
+%endif
+
+%pre
+# Executing the stop script for stopping the service of installed provider (old version)
+if [ -x %{_sysconfdir}/rc.d/init.d/data-provider-master ]; then
+ %{_sysconfdir}/rc.d/init.d/data-provider-master stop
+fi
+
+%post
+%if "%{sec_product_feature_livebox}" == "0"
+#Nothing provides
+%else
+chown 5000:5000 /opt/usr/share/live_magazine
+chmod 750 /opt/usr/share/live_magazine
+chown 5000:5000 /opt/usr/share/live_magazine/log
+chmod 750 /opt/usr/share/live_magazine/log
+chown 5000:5000 /opt/usr/share/live_magazine/reader
+chmod 750 /opt/usr/share/live_magazine/reader
+chown 5000:5000 /opt/usr/share/live_magazine/always
+chmod 750 /opt/usr/share/live_magazine/always
+chown 0:5000 /opt/dbspace/.livebox.db
+chmod 640 /opt/dbspace/.livebox.db
+chown 0:5000 /opt/dbspace/.livebox.db-journal
+chmod 640 /opt/dbspace/.livebox.db-journal
+%endif
+vconftool set -t bool "memory/data-provider-master/started" 0 -i -u 5000 -f -s system::vconf_system
+vconftool set -t int "memory/private/data-provider-master/restart_count" 0 -i -u 5000 -f -s data-provider-master
+vconftool set -t string "db/data-provider-master/serveraddr" "/opt/usr/share/live_magazine/.client.socket" -i -u 5000 -f -s system::vconf_system
+echo "Successfully installed. Please start a daemon again manually"
+echo "%{_sysconfdir}/init.d/data-provider-master start"
+
+%files -n data-provider-master
+%manifest %{name}.manifest
+%defattr(-,root,root,-)
+%{_bindir}/data-provider-master
+%if "%{_repository}" == "wearable"
+%{_libdir}/systemd/system/multi-user.target.wants/data-provider-master.service
+%{_libdir}/systemd/system/data-provider-master.service
+/opt/etc/dump.d/module.d/dump_livebox.sh
+%else
+%{_libdir}/systemd/user/data-provider-master.service
+%{_libdir}/systemd/user/tizen-middleware.target.wants/data-provider-master.service
+/opt/etc/smack/accesses.d
+%endif
+%{_datarootdir}/license/*
+%if "%{sec_product_feature_livebox}" == "0"
+# Nothing provides
+%else
+%if 0%{?tizen_build_binary_release_type_eng}
+/opt/usr/devel/usr/bin/*
+%endif
+%{_prefix}/etc/package-manager/parserlib/*
+%{_datarootdir}/data-provider-master/*
+/opt/usr/share/live_magazine/*
+/opt/dbspace/.livebox.db
+/opt/dbspace/.livebox.db-journal
+%endif
+
+# End of a file
diff --git a/pkgmgr_livebox/CMakeLists.txt b/pkgmgr_livebox/CMakeLists.txt
new file mode 100644
index 0000000..c20b5c1
--- /dev/null
+++ b/pkgmgr_livebox/CMakeLists.txt
@@ -0,0 +1,31 @@
+PROJECT(livebox C)
+
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/pkgmgr_livebox/include)
+
+INCLUDE(FindPkgConfig)
+pkg_check_modules(bin_pkgs REQUIRED
+ dlog
+ sqlite3
+ libxml-2.0
+ db-util
+ livebox-service
+)
+
+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_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_livebox/include/dlist.h b/pkgmgr_livebox/include/dlist.h
new file mode 100644
index 0000000..cd1a421
--- /dev/null
+++ b/pkgmgr_livebox/include/dlist.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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 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_livebox/livebox.xml b/pkgmgr_livebox/livebox.xml
new file mode 100644
index 0000000..e14cdea
--- /dev/null
+++ b/pkgmgr_livebox/livebox.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<manifest xmlns="http://tizen.org/ns/packages" package="org.tizen.nicesj" version="1.0" install-location="auto">
+
+<livebox appid="org.tizen.nicesj.livebox" primary="true" secured="false" network="false" abi="c" timeout="20" period="10.0" libexec="/usr/apps/org.tizen.myapp/libexec/liblive-org.tizen.nicesj.so" pinup="false" script="edje" nodisplay="false">
+ <label>My livebox</label>
+ <icon>/usr/share/icons/small/org.tizen.live-nicesj.png</icon>
+ <label xml:lang="en_US">Sample</label>
+ <label xml:lang="ko_KR">Hangul</label>
+ <content>Content information</content>
+
+ <launch>org.tizen.nicesj</launch>
+
+ <setup>org.tizen.nicesj</setup>
+
+ <box type="image" mouse_event="false">
+ <size touch_effect="true" preview="ABSPATH">1x1</size>
+ <size touch_effect="true" preview="ABSPATH">2x1</size>
+ <size touch_effect="true" need_frame="true">2x2</size>
+ <size>4x1</size>
+ <size need_frame="true">4x2</size>
+ <size touch_effect="false" need_frame="true">4x3</size>
+ <size touch_effect="false">4x4</size>
+
+ <!-- Easy home -->
+ <size>21x21</size>
+ <size preview="ABSPATH">23x21</size>
+ <size>23x23</size>
+
+ <!-- Only supported for special livebox - inhouse / commercialization target only -->
+ <size>0x0</size>
+ <script src="/opt/usr/apps/org.tizen.myapp/res/script/my.edj" group="my_group" />
+ </box>
+
+ <pd type="script">
+ <size>720x100</size>
+ <script src="/opt/usr/apps/org.tizen.myapp/res/script/mypd.edj" group="group_string" />
+ </pd>
+
+ <group>
+ <cluster name="cluster1">
+ <category name="category1" context="APP_USED_FREQUENTLY">
+ <option key="time_span" value="value" />
+ <option key="result_size" value="value" />
+ </category>
+ <category name="category2" context="APP_USED_FREQUENTLY_THISTIME">
+ <option key="time_span" value="value" />
+ <option key="result_size" value="value" />
+ <option key="time_interval" value="value" />
+ </category>
+ </cluster>
+ <cluster name="cluster2">
+ <category name="category1" context="CONTACT_COMMUNICATED_FREQUENTLY">
+ <option key="data_provider" value="org.tizen.contact" />
+ <option key="time_span" value="value" />
+ <option key="result_size" value="size" />
+ </category>
+ <category name="category2" context="CONTACT_COMMUNICATED_FREQUENTLY_THISTIME">
+ <option key="data_provider" value="org.tizen.contact" />
+ <option key="time_span" value="value" />
+ <option key="result_size" value="value" />
+ <option key="time_interval" value="value" />
+ </category>
+ <category name="category3" context="CONTACT_COMMUNICATED_ATLEASTONCE">
+ <option key="data_provider" value="value" />
+ <option key="time_span" value="value" />
+ <option key="result_size" value="value" />
+ </category>
+ </cluster>
+ <cluster name="noctx_cluster">
+ <category name="noctx_category" />
+ </cluster>
+ <!--
+ KEYWORD_SEARCHED_FREQUENTLY(DATA_PROVIDER, TIME_SPAN, RESULT_SIZE)
+ MUSIC_PLAYED_FREQUENTLY(DATA_PROVIDER, TIME_SPAN, RESULT_SIZE)
+ -->
+ </group>
+</livebox>
+</manifest>
diff --git a/pkgmgr_livebox/src/dlist.c b/pkgmgr_livebox/src/dlist.c
new file mode 100644
index 0000000..3ae571b
--- /dev/null
+++ b/pkgmgr_livebox/src/dlist.c
@@ -0,0 +1,189 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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 <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_livebox/src/service_register.c b/pkgmgr_livebox/src/service_register.c
new file mode 100644
index 0000000..17e7726
--- /dev/null
+++ b/pkgmgr_livebox/src/service_register.c
@@ -0,0 +1,3194 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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 <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 <livebox-service.h>
+
+#include "dlist.h"
+
+#if !defined(FLOG)
+#define DbgPrint(format, arg...) SECURE_LOGD("[%s/%s:%d] " format, basename(__FILE__), __func__, __LINE__, ##arg)
+#define ErrPrint(format, arg...) SECURE_LOGE("[%s/%s:%d] " format, basename(__FILE__), __func__, __LINE__, ##arg)
+#define ErrPrintWithConsole(format, arg...) do { fprintf(stderr, "[%s/%s:%d] " format, basename(__FILE__), __func__, __LINE__, ##arg); SECURE_LOGE("[%s/%s:%d] " format, basename(__FILE__), __func__, __LINE__, ##arg); } while (0)
+#endif
+
+#define CUR_VER 3
+#define DEFAULT_CATEGORY "http://tizen.org/category/default"
+
+/*!
+ * \note
+ * DB Table schema
+ *
+ * version
+ * +---------+
+ * | version |
+ * +---------+
+ * | - |
+ * +---------+
+ * CREATE TABLE version ( version INTEGER )
+ *
+ *
+ * pkgmap
+ * +-------+-------+-------+-------+-------------------+
+ * | appid | pkgid | uiapp | prime | categ(from ver 2) |
+ * +-------+-------+-------+-------+-------------------+
+ * | - | - | - | - | - |
+ * +-------+-------+-------+-------+-------------------+
+ * CREATE TABLE pkgmap ( pkgid TEXT PRIMARY KEY NOT NULL, appid TEXT, uiapp TEXT, prime INTEGER, category TEXT )
+ *
+ *
+ * provider
+ * +-------+---------+-----+---------+----------+---------+-----------+---------+--------+----------+---------+---------+--------+--------+-------+
+ * | pkgid | network | abi | secured | box_type | box_src | box_group | pd_type | pd_src | pd_group | libexec | timeout | period | script | pinup |
+ * +-------+---------+-----+---------+----------+---------+-----------+---------+--------+----------+---------+---------+--------+--------+-------+
+ * | - | - | - | - | - | - | - | - | - | - | - | - | - | - | - |
+ * +-------+---------+-----+---------+----------+---------+-----------+---------+--------+----------+---------+---------+--------+--------+-------+
+ * CREATE TABLE provider ( pkgid TEXT PRIMARY KEY NOT NULL, network INTEGER, abi TEXT, secured INTEGER, box_type INTEGER, box_src TEXT, box_group TEXT, pd_type TEXT, pd_src TEXT, pd_group TEXT, libexec TEXT, timeout INTEGER, period TEXT, script TEXT, pinup INTEGER, FOREIGN KEY(pkgid) REFERENCES pkgmap(pkgid))
+ *
+ * = box_type = { text | buffer | script | image }
+ * = pd_type = { text | buffer | script }
+ * = network = { 1 | 0 }
+ * = secured = { 1 | 0 }
+ *
+ *
+ * client
+ * +-------+------+---------+-------------+---------+---------+-----------+-------+
+ * | pkgid | Icon | Name | auto_launch | pd_size | content | nodisplay | setup |
+ * +-------+------+---------+-------------+---------+---------+-----------+-------+
+ * | - | - | - | - | - | - | - | - |
+ * +-------+------+---------+-------------+---------+---------+-----------+-------+
+ * CREATE TABLE client ( pkgid TEXT PRIMARY KEY NOT NULL, icon TEXT, name TEXT, auto_launch TEXT, pd_size TEXT, content TEXT, nodisplay INTEGER, setup TEXT, FOREIGN KEY(pkgid) REFERENCES pkgmap(pkgid) )
+ *
+ * = auto_launch = UI-APPID
+ * = pd_size = WIDTHxHEIGHT
+ *
+ *
+ * i18n
+ * +-------+------+------+------+
+ * | fk | lang | name | icon |
+ * +-------+------+------+------+
+ * | pkgid | - | - | - |
+ * +-------+------+------+------+
+ * CREATE TABLE i18n ( pkgid TEXT NOT NULL, lang TEXT COLLATE NOCASE, name TEXT, icon TEXT, FOREIGN KEY(pkgid) REFERENCES pkgmap(pkgid) )
+ *
+ *
+ * box_size
+ * +-------+-----------+---------+--------------+------------+-------------------------+
+ * | pkgid | size_type | preview | touch_effect | need_frame | mouse_event(from ver 3) |
+ * +-------+-----------+---------+--------------+------------+-------------------------+
+ * | - | - | - | - | - | - |
+ * +-------+-----------+---------+--------------+------------+-------------------------+
+ * CREATE TABLE box_size ( pkgid TEXT NOT NULL, size_type INTEGER, preview TEXT, INTEGER, touch_effect INTEGER, need_frame INTEGER, mouse_event INTEGER, FOREIGN KEY(pkgid) REFERENCES pkgmap(pkgid) )
+ *
+ * = box_size_list = { WIDTHxHEIGHT; WIDTHxHEIGHT; ... }
+ *
+ * groupinfo
+ * +----+---------+----------+-------+
+ * | id | cluster | category | pkgid |
+ * +----+---------+----------+-------+
+ * | - | - | - | - |
+ * +----+---------+----------+-------|
+ * CREATE TABLE groupinfo ( id INTEGER PRIMARY KEY AUTOINCREMENT, cluster TEXT NOT NULL, category TEXT NOT NULL, appid TEXT NOT NULL, FOREIGN KEY(pkgid) REFERENCES pkgmap(pkgid) ))
+ *
+ * groupmap
+ * +-------+----+----------+-----------+
+ * | pkgid | id | ctx_item | option_id |
+ * +-------+----+----------+-----------+
+ * CREATE TABLE groupmap ( option_id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER, pkgid TEXT NOT NULL, ctx_item TEXT NOT NULL, FOREIGN KEY(id) REFERENCES groupinfo(id), FOREIGN KEY(pkgid) REFERENCES pkgmap(pkgid) )
+ *
+ *
+ * option
+ * +-------+-----------+-----+-------+
+ * | pkgid | option_id | key | value |
+ * +-------+-----------+-----+-------+
+ * CREATE TABLE option ( pkgid TEXT NOT NULL, option_id INTEGER, key TEXT NOT NULL, value TEXT NOT NULL, FOREIGN KEY(option_id) REFERENCES groupmap(option_id), FOREIGN KEY(pkgid) REFERENCES pkgmap(pkgid) )
+ */
+
+#if !defined(LIBXML_TREE_ENABLED)
+ #error "LIBXML is not supporting the tree"
+#endif
+
+#if defined(LOG_TAG)
+#undef LOG_TAG
+#endif
+
+#define LOG_TAG "PKGMGR_LIVEBOX"
+
+int errno;
+
+struct i18n {
+ xmlChar *lang;
+ xmlChar *name;
+ xmlChar *icon;
+};
+
+enum lb_type {
+ LB_TYPE_NONE = 0x0,
+ LB_TYPE_SCRIPT,
+ LB_TYPE_FILE,
+ LB_TYPE_TEXT,
+ LB_TYPE_BUFFER,
+};
+
+enum pd_type {
+ PD_TYPE_NONE = 0x0,
+ PD_TYPE_SCRIPT,
+ PD_TYPE_TEXT,
+ PD_TYPE_BUFFER,
+};
+
+struct livebox {
+ xmlChar *pkgid;
+ int secured;
+ int network;
+ xmlChar *auto_launch;
+ xmlChar *abi;
+ xmlChar *name; /* Default name */
+ xmlChar *icon; /* Default icon */
+ xmlChar *libexec; /* Path of the SO file */
+ xmlChar *timeout; /* INTEGER, timeout */
+ xmlChar *period; /* DOUBLE, update period */
+ xmlChar *script; /* Script engine */
+ xmlChar *content; /* Content information */
+ xmlChar *setup;
+ xmlChar *uiapp; /* UI App Id */
+ xmlChar *category; /* Category of this box */
+
+ int pinup; /* Is this support the pinup feature? */
+ int primary; /* Is this primary livebox? */
+ int nodisplay;
+
+ int default_mouse_event; /* Mouse event processing option for livebox */
+ int default_touch_effect;
+ int default_need_frame;
+
+ enum lb_type lb_type;
+ xmlChar *lb_src;
+ xmlChar *lb_group;
+ int size_list; /* 1x1, 2x1, 2x2, 4x1, 4x2, 4x3, 4x4 */
+
+ xmlChar *preview[NR_OF_SIZE_LIST];
+ int touch_effect[NR_OF_SIZE_LIST]; /* Touch effect of a livebox */
+ int need_frame[NR_OF_SIZE_LIST]; /* Box needs frame which should be cared by viewer */
+ int mouse_event[NR_OF_SIZE_LIST];
+
+ enum pd_type pd_type;
+ xmlChar *pd_src;
+ xmlChar *pd_group;
+ xmlChar *pd_size; /* Default PD size */
+
+ struct dlist *i18n_list;
+ struct dlist *group_list;
+};
+
+struct group {
+ xmlChar *cluster;
+ xmlChar *category;
+ xmlChar *ctx_item;
+ struct dlist *option_list;
+};
+
+struct option {
+ xmlChar *key;
+ xmlChar *value;
+};
+
+static struct {
+ const char *dbfile;
+ sqlite3 *handle;
+} s_info = {
+ .dbfile = "/opt/dbspace/.livebox.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 void db_create_version(void)
+{
+ static const char *ddl = "CREATE TABLE version (version INTEGER)";
+ char *err;
+
+ 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 int set_version(int version)
+{
+ static const char *dml = "INSERT INTO version (version) VALUES (?)";
+ sqlite3_stmt *stmt;
+ int ret;
+
+ 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, version) != SQLITE_OK) {
+ ErrPrint("Failed to bind a id(%s)\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_step(stmt);
+ if (ret != SQLITE_DONE) {
+ ErrPrint("Failed to execute the DML for version: %d\n", ret);
+ ret = -EIO;
+ } else {
+ ret = 0;
+ }
+
+out:
+ sqlite3_reset(stmt);
+ sqlite3_clear_bindings(stmt);
+ sqlite3_finalize(stmt);
+ return ret;
+}
+
+static int update_version(int version)
+{
+ static const char *dml = "UPDATE version SET version = ?";
+ sqlite3_stmt *stmt;
+ int ret;
+
+ 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, version) != SQLITE_OK) {
+ ErrPrint("Failed to bind a version: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_step(stmt);
+ if (ret != SQLITE_DONE) {
+ ErrPrint("Failed to execute DML: %d\n", ret);
+ ret = -EIO;
+ } else {
+ ret = 0;
+ }
+
+out:
+ sqlite3_reset(stmt);
+ sqlite3_clear_bindings(stmt);
+ sqlite3_finalize(stmt);
+ return ret;
+}
+
+static int get_version(void)
+{
+ static const char *dml = "SELECT version FROM version";
+ sqlite3_stmt *stmt;
+ int ret;
+
+ ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
+ if (ret != SQLITE_OK) {
+ return -ENOSYS;
+ }
+
+ if (sqlite3_step(stmt) != SQLITE_ROW) {
+ ret = -ENOENT;
+ } else {
+ ret = sqlite3_column_int(stmt, 0);
+ }
+
+ sqlite3_reset(stmt);
+ sqlite3_clear_bindings(stmt);
+ sqlite3_finalize(stmt);
+ return ret;
+}
+
+/*!
+ * \note
+ * From version 1 to 2
+ */
+static void upgrade_pkgmap_for_category(void)
+{
+ char *err;
+ static const char *ddl;
+
+ ddl = "ALTER TABLE pkgmap ADD COLUMN category TEXT DEFAULT \"" DEFAULT_CATEGORY "\"";
+ 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");
+ }
+
+ return;
+}
+
+/*!
+ * \note
+ * From version 2 to 3
+ * mouse_event is deleted from client table
+ * mouse_event is added to box_size table
+ *
+ * Every size has their own configuration for mouse_event flag.
+ */
+static void upgrade_to_version_3(void)
+{
+ char *err;
+ static const char *ddl;
+ static const char *dml;
+ sqlite3_stmt *select_stmt;
+ int ret;
+
+ /*
+ * Step 1
+ * Create a new column for mouse_event to box_size table.
+ */
+ ddl = "ALTER TABLE box_size ADD COLUMN mouse_event INTEGER DEFAULT 0";
+ 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");
+ }
+
+ /*
+ * Step 2
+ * Copy mouse_event values from the client to the box_size table.
+ */
+ dml = "SELECT pkgid, mouse_event FROM client";
+ ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &select_stmt, NULL);
+ if (ret == SQLITE_OK) {
+ sqlite3_stmt *update_stmt;
+
+ dml = "UPDATE box_size SET mouse_event = ? WHERE pkgid = ?";
+ ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &update_stmt, NULL);
+ if (ret == SQLITE_OK) {
+ int mouse_event;
+ const char *pkgid;
+
+ while (sqlite3_step(select_stmt) == SQLITE_ROW) {
+ pkgid = (const char *)sqlite3_column_text(select_stmt, 0);
+ if (!pkgid) {
+ ErrPrint("Package Id is not valid\n");
+ continue;
+ }
+
+ mouse_event = sqlite3_column_int(select_stmt, 1);
+
+ ret = sqlite3_bind_int(update_stmt, 1, mouse_event);
+ if (ret != SQLITE_OK) {
+ ErrPrint("Failed to bind mouse_event [%s], [%d]\n", pkgid, mouse_event);
+ sqlite3_reset(update_stmt);
+ sqlite3_clear_bindings(update_stmt);
+ continue;
+ }
+
+ ret = sqlite3_bind_text(update_stmt, 2, pkgid, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ ErrPrint("Failed to bind pkgid [%s], [%d]\n", pkgid, mouse_event);
+ sqlite3_reset(update_stmt);
+ sqlite3_clear_bindings(update_stmt);
+ continue;
+ }
+
+ ret = sqlite3_step(update_stmt);
+ if (ret != SQLITE_DONE) {
+ ErrPrint("Failed to execute DML: %d\n", ret);
+ sqlite3_reset(update_stmt);
+ sqlite3_clear_bindings(update_stmt);
+ continue;
+ }
+
+ sqlite3_reset(update_stmt);
+ sqlite3_clear_bindings(update_stmt);
+ }
+
+ sqlite3_finalize(update_stmt);
+ } else {
+ ErrPrint("Failed to execute DML\n");
+ }
+
+ sqlite3_reset(select_stmt);
+ sqlite3_clear_bindings(select_stmt);
+ sqlite3_finalize(select_stmt);
+ } else {
+ ErrPrint("Failed to prepare the initial DML(%s)\n", sqlite3_errmsg(s_info.handle));
+ }
+
+ /*
+ * Step 3
+ * Drop a column from the client table
+ */
+ ddl = "ALTER TABLE client DROP COLUMN mouse_event";
+ 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");
+ }
+
+ return;
+}
+
+static void do_upgrade_db_schema(void)
+{
+ int version;
+
+ version = get_version();
+
+ switch (version) {
+ case -ENOSYS:
+ db_create_version();
+ /* Need to create version table */
+ case -ENOENT:
+ if (set_version(CUR_VER) < 0) {
+ ErrPrint("Failed to set version\n");
+ }
+ /* Need to set version */
+ case 1:
+ upgrade_pkgmap_for_category();
+ case 2:
+ upgrade_to_version_3();
+ default:
+ /* Need to update version */
+ DbgPrint("Old version: %d\n", version);
+ if (update_version(CUR_VER) < 0) {
+ ErrPrint("Failed to update version\n");
+ }
+ case CUR_VER:
+ break;
+ }
+}
+
+static inline int db_create_pkgmap(void)
+{
+ char *err;
+ static const char *ddl;
+
+ ddl = "CREATE TABLE pkgmap ( pkgid TEXT PRIMARY KEY NOT NULL, appid TEXT, uiapp TEXT, prime INTEGER, category TEXT )";
+ if (sqlite3_exec(s_info.handle, ddl, NULL, NULL, &err) != SQLITE_OK) {
+ ErrPrint("Failed to execute the DDL (%s)\n", err);
+ return -EIO;
+ }
+
+ if (sqlite3_changes(s_info.handle) == 0) {
+ ErrPrint("No changes to DB\n");
+ }
+
+ return 0;
+}
+
+static inline int db_insert_pkgmap(const char *appid, const char *pkgid, const char *uiappid, int primary, const char *category)
+{
+ int ret;
+ static const char *dml;
+ sqlite3_stmt *stmt;
+
+ dml = "INSERT INTO pkgmap ( appid, pkgid, uiapp, prime, category ) VALUES (? ,?, ?, ?, ?)";
+ ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
+ if (ret != SQLITE_OK) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ return -EIO;
+ }
+
+ ret = sqlite3_bind_text(stmt, 1, appid, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_text(stmt, 2, pkgid, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_text(stmt, 3, uiappid, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_int(stmt, 4, primary);
+ if (ret != SQLITE_OK) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_text(stmt, 5, category, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = 0;
+ if (sqlite3_step(stmt) != SQLITE_DONE) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ }
+
+out:
+ sqlite3_reset(stmt);
+ sqlite3_clear_bindings(stmt);
+ sqlite3_finalize(stmt);
+ return ret;
+}
+
+static inline int db_remove_pkgmap(const char *pkgid)
+{
+ int ret;
+ static const char *dml;
+ sqlite3_stmt *stmt;
+
+ dml = "DELETE FROM pkgmap WHERE pkgid = ?";
+ ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
+ if (ret != SQLITE_OK) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ return -EIO;
+ }
+
+ ret = sqlite3_bind_text(stmt, 1, pkgid, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = 0;
+ if (sqlite3_step(stmt) != SQLITE_DONE) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ }
+
+out:
+ sqlite3_reset(stmt);
+ sqlite3_clear_bindings(stmt);
+ sqlite3_finalize(stmt);
+ return ret;
+}
+
+static inline int db_create_provider(void)
+{
+ char *err;
+ static const char *ddl;
+
+ ddl = "CREATE TABLE provider (" \
+ "pkgid TEXT PRIMARY KEY NOT NULL, network INTEGER, " \
+ "abi TEXT, secured INTEGER, box_type INTEGER, " \
+ "box_src TEXT, box_group TEXT, pd_type INTEGER, " \
+ "pd_src TEXT, pd_group TEXT, libexec TEXT, timeout INTEGER, period TEXT, script TEXT, pinup INTEGER, "\
+ "FOREIGN KEY(pkgid) REFERENCES pkgmap(pkgid) ON DELETE CASCADE)";
+
+ if (sqlite3_exec(s_info.handle, ddl, NULL, NULL, &err) != SQLITE_OK) {
+ ErrPrint("Failed to execute the DDL (%s)\n", err);
+ return -EIO;
+ }
+
+ if (sqlite3_changes(s_info.handle) == 0) {
+ ErrPrint("No changes to DB\n");
+ }
+
+ return 0;
+}
+
+static inline int db_remove_provider(const char *pkgid)
+{
+ static const char *dml;
+ int ret;
+ sqlite3_stmt *stmt;
+
+ dml = "DELETE FROM provider WHERE pkgid = ?";
+ ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
+ if (ret != SQLITE_OK) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ return -EIO;
+ }
+
+ ret = sqlite3_bind_text(stmt, 1, pkgid, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = 0;
+ if (sqlite3_step(stmt) != SQLITE_DONE) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ }
+
+out:
+ sqlite3_reset(stmt);
+ sqlite3_clear_bindings(stmt);
+ sqlite3_finalize(stmt);
+ return ret;
+}
+static int db_insert_provider(struct livebox *livebox)
+{
+ static const char *dml;
+ int ret;
+ sqlite3_stmt *stmt;
+ char *abi = (char *)livebox->abi;
+ char *box_src = (char *)livebox->lb_src;
+ char *box_group = (char *)livebox->lb_group;
+ char *pd_src = (char *)livebox->pd_src;
+ char *pd_group = (char *)livebox->pd_group;
+ char *libexec = (char *)livebox->libexec;
+ char *timeout = (char *)livebox->timeout;
+ char *period = (char *)livebox->period;
+ char *script = (char *)livebox->script;
+
+ if (!abi) {
+ abi = "c";
+ }
+
+ if (!timeout) {
+ timeout = "10";
+ }
+
+ if (!period) {
+ period = "0.0";
+ }
+
+ if (!script) {
+ script = "edje";
+ }
+
+ dml = "INSERT INTO provider ( pkgid, network, abi, secured, box_type, box_src, box_group, pd_type, pd_src, pd_group, libexec, timeout, period, script, pinup ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
+ ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ return -EIO;
+ }
+
+ ret = sqlite3_bind_text(stmt, 1, (char *)livebox->pkgid, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_int(stmt, 2, livebox->network);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_text(stmt, 3, abi, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+ ret = sqlite3_bind_int(stmt, 4, livebox->secured);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_int(stmt, 5, livebox->lb_type);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_text(stmt, 6, box_src, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_text(stmt, 7, box_group, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_int(stmt, 8, livebox->pd_type);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_text(stmt, 9, pd_src, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_text(stmt, 10, pd_group, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_text(stmt, 11, libexec, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_int(stmt, 12, atoi(timeout));
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_text(stmt, 13, period, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_text(stmt, 14, script, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_int(stmt, 15, livebox->pinup);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = 0;
+ if (sqlite3_step(stmt) != SQLITE_DONE) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ }
+
+out:
+ sqlite3_reset(stmt);
+ sqlite3_clear_bindings(stmt);
+ sqlite3_finalize(stmt);
+ return ret;
+}
+
+static inline int db_create_client(void)
+{
+ char *err;
+ static const char *ddl;
+
+ ddl = "CREATE TABLE client (" \
+ "pkgid TEXT PRIMARY KEY NOT NULL, icon TEXT, name TEXT, " \
+ "auto_launch TEXT, pd_size TEXT, content TEXT, nodisplay INTEGER, setup TEXT, FOREIGN KEY(pkgid) REFERENCES pkgmap(pkgid) ON DELETE CASCADE)";
+ if (sqlite3_exec(s_info.handle, ddl, NULL, NULL, &err) != SQLITE_OK) {
+ ErrPrint("Failed to execute the DDL (%s)\n", err);
+ return -EIO;
+ }
+
+ if (sqlite3_changes(s_info.handle) == 0) {
+ ErrPrint("No changes to DB\n");
+ }
+
+ return 0;
+}
+
+static inline int db_insert_client(struct livebox *livebox)
+{
+ static const char *dml;
+ int ret;
+ sqlite3_stmt *stmt;
+
+ dml = "INSERT INTO client ( pkgid, icon, name, auto_launch, pd_size, content, nodisplay, setup ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)";
+ ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ return -EIO;
+ }
+
+ ret = sqlite3_bind_text(stmt, 1, (char *)livebox->pkgid, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_text(stmt, 2, (char *)livebox->icon, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_text(stmt, 3, (char *)livebox->name, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_text(stmt, 4, (char *)livebox->auto_launch, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_text(stmt, 5, (char *)livebox->pd_size, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_text(stmt, 6, (char *)livebox->content, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_int(stmt, 7, livebox->nodisplay);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_text(stmt, 8, (char *)livebox->setup, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = 0;
+ if (sqlite3_step(stmt) != SQLITE_DONE) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ }
+
+out:
+ sqlite3_reset(stmt);
+ sqlite3_clear_bindings(stmt);
+ sqlite3_finalize(stmt);
+ return ret;
+}
+
+static inline int db_remove_client(const char *pkgid)
+{
+ static const char *dml;
+ int ret;
+ sqlite3_stmt *stmt;
+
+ dml = "DELETE FROM client WHERE pkgid = ?";
+ ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
+ if (ret != SQLITE_OK) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ return -EIO;
+ }
+
+ ret = sqlite3_bind_text(stmt, 1, pkgid, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = 0;
+ if (sqlite3_step(stmt) != SQLITE_DONE) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ }
+
+out:
+ sqlite3_reset(stmt);
+ sqlite3_clear_bindings(stmt);
+ sqlite3_finalize(stmt);
+ return ret;
+}
+
+static inline int db_create_i18n(void)
+{
+ char *err;
+ static const char *ddl;
+
+ ddl = "CREATE TABLE i18n ( pkgid TEXT NOT NULL, lang TEXT COLLATE NOCASE, name TEXT, " \
+ "icon TEXT, FOREIGN KEY(pkgid) REFERENCES pkgmap(pkgid) ON DELETE CASCADE)";
+ if (sqlite3_exec(s_info.handle, ddl, NULL, NULL, &err) != SQLITE_OK) {
+ ErrPrint("Failed to execute the DDL (%s)\n", err);
+ return -EIO;
+ }
+
+ if (sqlite3_changes(s_info.handle) == 0) {
+ ErrPrint("No changes to DB\n");
+ }
+
+ return 0;
+}
+
+static inline int db_insert_i18n(const char *pkgid, const char *lang, const char *name, const char *icon)
+{
+ static const char *dml;
+ int ret;
+ sqlite3_stmt *stmt;
+
+ DbgPrint("%s - lang[%s] name[%s] icon[%s]\n", pkgid, lang, name, icon);
+ dml = "INSERT INTO i18n ( pkgid, lang, name, icon ) VALUES (?, ?, ?, ?)";
+ ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ return -EIO;
+ }
+
+ ret = sqlite3_bind_text(stmt, 1, pkgid, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_text(stmt, 2, lang, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_text(stmt, 3, name, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_text(stmt, 4, icon, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = 0;
+ if (sqlite3_step(stmt) != SQLITE_DONE) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ }
+
+out:
+ sqlite3_reset(stmt);
+ sqlite3_clear_bindings(stmt);
+ sqlite3_finalize(stmt);
+ return ret;
+}
+
+static inline int db_remove_i18n(const char *pkgid)
+{
+ static const char *dml;
+ int ret;
+ sqlite3_stmt *stmt;
+
+ dml = "DELETE FROM i18n WHERE pkgid = ?";
+ ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
+ if (ret != SQLITE_OK) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ return -EIO;
+ }
+
+ ret = sqlite3_bind_text(stmt, 1, pkgid, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = 0;
+ if (sqlite3_step(stmt) != SQLITE_DONE) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ }
+
+ 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_create_group(void)
+{
+ char *err;
+ static const char *ddl;
+
+ ddl = "CREATE TABLE groupinfo ( id INTEGER PRIMARY KEY AUTOINCREMENT, cluster TEXT NOT NULL, category TEXT NOT NULL, pkgid TEXT NOT NULL, FOREIGN KEY(pkgid) REFERENCES pkgmap(pkgid) ON DELETE CASCADE)";
+ if (sqlite3_exec(s_info.handle, ddl, NULL, NULL, &err) != SQLITE_OK) {
+ ErrPrint("Failed to execute the DDL (%s)\n", err);
+ return -EIO;
+ }
+
+ if (sqlite3_changes(s_info.handle) == 0) {
+ ErrPrint("No changes to DB\n");
+ }
+
+ return 0;
+}
+
+static inline int db_insert_group(const char *pkgid, const char *cluster, const char *category)
+{
+ static const char *dml;
+ int ret;
+ sqlite3_stmt *stmt;
+
+ dml = "INSERT INTO groupinfo ( cluster, category, pkgid ) VALUES (?, ?, ?)";
+ ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ return -EIO;
+ }
+
+ ret = sqlite3_bind_text(stmt, 1, cluster, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_text(stmt, 2, category, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_text(stmt, 3, pkgid, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = 0;
+ if (sqlite3_step(stmt) != SQLITE_DONE) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ }
+
+out:
+ sqlite3_reset(stmt);
+ sqlite3_clear_bindings(stmt);
+ sqlite3_finalize(stmt);
+ return ret;
+}
+
+static int db_get_group_id(const char *cluster, const char *category)
+{
+ static const char *dml = "SELECT id FROM groupinfo WHERE cluster = ? AND category = ?";
+ sqlite3_stmt *stmt;
+ int ret;
+
+ if (!cluster || !category) {
+ 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, cluster, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
+ ErrPrint("Failed to bind a cluster(%s) - %s\n", cluster, sqlite3_errmsg(s_info.handle));
+ goto out;
+ }
+
+ if (sqlite3_bind_text(stmt, 2, category, -1, SQLITE_TRANSIENT) != SQLITE_OK) {
+ ErrPrint("Failed to bind a category(%s) - %s\n", category, sqlite3_errmsg(s_info.handle));
+ goto out;
+ }
+
+ if (sqlite3_step(stmt) != SQLITE_ROW) {
+ ErrPrint("Failed to execute the DML for %s - %s\n", cluster, category);
+ 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_remove_group(const char *pkgid)
+{
+ static const char *dml;
+ int ret;
+ sqlite3_stmt *stmt;
+
+ dml = "DELETE FROM groupinfo WHERE pkgid = ?";
+ ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
+ if (ret != SQLITE_OK) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ return -EIO;
+ }
+
+ ret = sqlite3_bind_text(stmt, 1, pkgid, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = 0;
+ if (sqlite3_step(stmt) != SQLITE_DONE) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ }
+
+ 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_create_groupmap(void)
+{
+ char *err;
+ static const char *ddl;
+
+ ddl = "CREATE TABLE groupmap (option_id INTEGER PRIMARY KEY AUTOINCREMENT, id INTEGER, pkgid TEXT NOT NULL, ctx_item TEXT NOT NULL, FOREIGN KEY(id) REFERENCES groupinfo(id), FOREIGN KEY(pkgid) REFERENCES pkgmap(pkgid) ON DELETE CASCADE)";
+ if (sqlite3_exec(s_info.handle, ddl, NULL, NULL, &err) != SQLITE_OK) {
+ ErrPrint("Failed to execute the DDL (%s)\n", err);
+ return -EIO;
+ }
+
+ if (sqlite3_changes(s_info.handle) == 0) {
+ ErrPrint("No changes to DB\n");
+ }
+
+ return 0;
+}
+
+static inline int db_get_option_id(int id, const char *pkgid, const char *ctx_item)
+{
+ static const char *dml;
+ int ret;
+ sqlite3_stmt *stmt;
+
+ dml = "SELECT option_id FROM groupmap WHERE id = ? AND pkgid = ? AND ctx_item = ?";
+ ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
+ if (ret != SQLITE_OK) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ return -EIO;
+ }
+
+ ret = sqlite3_bind_int(stmt, 1, id);
+ if (ret != SQLITE_OK) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_text(stmt, 2, pkgid, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_text(stmt, 3, ctx_item, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = 0;
+ if (sqlite3_step(stmt) != SQLITE_ROW) {
+ DbgPrint("Error: %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 int db_insert_groupmap(int id, const char *pkgid, const char *ctx_item)
+{
+ static const char *dml;
+ int ret;
+ sqlite3_stmt *stmt;
+
+ DbgPrint("%d (%s) add to groupmap\n", id, pkgid);
+
+ dml = "INSERT INTO groupmap ( id, pkgid, ctx_item ) VALUES (?, ?, ?)";
+ ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ return -EIO;
+ }
+
+ ret = sqlite3_bind_int(stmt, 1, id);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_text(stmt, 2, pkgid, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_text(stmt, 3, ctx_item, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = 0;
+ if (sqlite3_step(stmt) != SQLITE_DONE) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ }
+
+out:
+ sqlite3_reset(stmt);
+ sqlite3_clear_bindings(stmt);
+ sqlite3_finalize(stmt);
+ return ret;
+}
+
+static inline int db_remove_groupmap(const char *pkgid)
+{
+ static const char *dml;
+ int ret;
+ sqlite3_stmt *stmt;
+
+ dml = "DELETE FROM groupmap WHERE pkgid = ?";
+ ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
+ if (ret != SQLITE_OK) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ return -EIO;
+ }
+
+ ret = sqlite3_bind_text(stmt, 1, pkgid, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = 0;
+ if (sqlite3_step(stmt) != SQLITE_DONE) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ }
+
+ 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_create_option(void)
+{
+ char *err;
+ static const char *ddl;
+
+ ddl = "CREATE TABLE option ( pkgid TEXT NOT NULL, option_id INTEGER, key TEXT NOT NULL, value TEXT NOT NULL, " \
+ "FOREIGN KEY(option_id) REFERENCES groupmap(option_id), " \
+ "FOREIGN KEY(pkgid) REFERENCES pkgmap(pkgid) ON DELETE CASCADE)";
+ if (sqlite3_exec(s_info.handle, ddl, NULL, NULL, &err) != SQLITE_OK) {
+ ErrPrint("Failed to execute the DDL (%s)\n", err);
+ return -EIO;
+ }
+
+ if (sqlite3_changes(s_info.handle) == 0) {
+ ErrPrint("No changes to DB\n");
+ }
+
+ return 0;
+}
+
+static inline int db_insert_option(const char *pkgid, int option_id, const char *key, const char *value)
+{
+ static const char *dml;
+ int ret;
+ sqlite3_stmt *stmt;
+
+ dml = "INSERT INTO option (pkgid, option_id, key, value) VALUES (?, ?, ?, ?)";
+ ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ return -EIO;
+ }
+
+ ret = sqlite3_bind_text(stmt, 1, pkgid, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_int(stmt, 2, option_id);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_text(stmt, 3, key, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_text(stmt, 4, value, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = 0;
+ if (sqlite3_step(stmt) != SQLITE_DONE) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ }
+out:
+ sqlite3_reset(stmt);
+ sqlite3_clear_bindings(stmt);
+ sqlite3_finalize(stmt);
+ return ret;
+}
+
+static inline int db_remove_option(const char *pkgid)
+{
+ static const char *dml;
+ int ret;
+ sqlite3_stmt *stmt;
+
+ dml = "DELETE FROM option WHERE pkgid = ?";
+ ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
+ if (ret != SQLITE_OK) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ return -EIO;
+ }
+
+ ret = sqlite3_bind_text(stmt, 1, pkgid, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = 0;
+ if (sqlite3_step(stmt) != SQLITE_DONE) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ }
+
+ 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_create_box_size(void)
+{
+ char *err;
+ static const char *ddl;
+
+ ddl = "CREATE TABLE box_size ( pkgid TEXT NOT NULL, size_type INTEGER, preview TEXT, touch_effect INTEGER, need_frame INTEGER, mouse_event INTEGER " \
+ "FOREIGN KEY(pkgid) REFERENCES pkgmap(pkgid) ON DELETE CASCADE)";
+ if (sqlite3_exec(s_info.handle, ddl, NULL, NULL, &err) != SQLITE_OK) {
+ ErrPrint("Failed to execute the DDL (%s)\n", err);
+ return -EIO;
+ }
+
+ if (sqlite3_changes(s_info.handle) == 0) {
+ ErrPrint("No changes to DB\n");
+ }
+
+ return 0;
+}
+
+static int db_insert_box_size(const char *pkgid, int size_type, const char *preview, int touch_effect, int need_frame, int mouse_event)
+{
+ static const char *dml;
+ int ret;
+ sqlite3_stmt *stmt;
+
+ DbgPrint("box size: %s - %d (%s) is added\n", pkgid, size_type, preview);
+ dml = "INSERT INTO box_size ( pkgid, size_type, preview, touch_effect, need_frame, mouse_event ) VALUES (?, ?, ?, ?, ?, ?)";
+ ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ return -EIO;
+ }
+
+ ret = sqlite3_bind_text(stmt, 1, pkgid, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_int(stmt, 2, size_type);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_text(stmt, 3, preview, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_int(stmt, 4, touch_effect);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_int(stmt, 5, need_frame);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = sqlite3_bind_int(stmt, 6, mouse_event);
+ if (ret != SQLITE_OK) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = 0;
+ if (sqlite3_step(stmt) != SQLITE_DONE) {
+ ErrPrintWithConsole("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ }
+
+out:
+ sqlite3_reset(stmt);
+ sqlite3_clear_bindings(stmt);
+ sqlite3_finalize(stmt);
+ return ret;
+}
+
+static inline int db_remove_box_size(const char *pkgid)
+{
+ static const char *dml;
+ int ret;
+ sqlite3_stmt *stmt;
+
+ dml = "DELETE FROM box_size WHERE pkgid = ?";
+ ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
+ if (ret != SQLITE_OK) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ return -EIO;
+ }
+
+ ret = sqlite3_bind_text(stmt, 1, pkgid, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ goto out;
+ }
+
+ ret = 0;
+ if (sqlite3_step(stmt) != SQLITE_DONE) {
+ DbgPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = -EIO;
+ }
+
+ 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 void db_create_table(void)
+{
+ int ret;
+ begin_transaction();
+
+ ret = db_create_pkgmap();
+ if (ret < 0) {
+ rollback_transaction();
+ return;
+ }
+
+ ret = db_create_provider();
+ if (ret < 0) {
+ rollback_transaction();
+ return;
+ }
+
+ ret = db_create_client();
+ if (ret < 0) {
+ rollback_transaction();
+ return;
+ }
+
+ ret = db_create_i18n();
+ if (ret < 0) {
+ rollback_transaction();
+ return;
+ }
+
+ ret = db_create_box_size();
+ if (ret < 0) {
+ rollback_transaction();
+ return;
+ }
+
+ ret = db_create_group();
+ if (ret < 0) {
+ rollback_transaction();
+ return;
+ }
+
+ ret = db_create_option();
+ if (ret < 0) {
+ rollback_transaction();
+ return;
+ }
+
+ ret = db_create_groupmap();
+ if (ret < 0) {
+ rollback_transaction();
+ return;
+ }
+
+ commit_transaction();
+}
+
+static 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;
+}
+
+static inline int validate_pkgid(const char *appid, const char *pkgid)
+{
+ /* Just return 1 Always */
+ return 1 || !strncmp(appid, pkgid, strlen(appid));
+}
+
+static int livebox_destroy(struct livebox *livebox)
+{
+ struct dlist *l;
+ struct dlist *n;
+ struct i18n *i18n;
+ struct group *group;
+ struct option *option;
+ struct dlist *il;
+ struct dlist *in;
+
+ xmlFree(livebox->auto_launch);
+ xmlFree(livebox->pkgid);
+ xmlFree(livebox->abi);
+ xmlFree(livebox->name);
+ xmlFree(livebox->icon);
+ xmlFree(livebox->lb_src);
+ xmlFree(livebox->lb_group);
+ xmlFree(livebox->pd_src);
+ xmlFree(livebox->pd_group);
+ xmlFree(livebox->pd_size);
+ xmlFree(livebox->libexec);
+ xmlFree(livebox->script);
+ xmlFree(livebox->period);
+ xmlFree(livebox->content);
+ xmlFree(livebox->setup);
+ xmlFree(livebox->category);
+ xmlFree(livebox->preview[0]); /* 1x1 */
+ xmlFree(livebox->preview[1]); /* 2x1 */
+ xmlFree(livebox->preview[2]); /* 2x2 */
+ xmlFree(livebox->preview[3]); /* 4x1 */
+ xmlFree(livebox->preview[4]); /* 4x2 */
+ xmlFree(livebox->preview[5]); /* 4x3 */
+ xmlFree(livebox->preview[6]); /* 4x4 */
+ xmlFree(livebox->preview[7]); /* 4x5 */
+ xmlFree(livebox->preview[8]); /* 4x6 */
+ xmlFree(livebox->preview[9]); /* easy 1x1 */
+ xmlFree(livebox->preview[10]); /* easy 3x1 */
+ xmlFree(livebox->preview[11]); /* easy 3x3 */
+ xmlFree(livebox->preview[12]); /* full */
+
+ dlist_foreach_safe(livebox->i18n_list, l, n, i18n) {
+ livebox->i18n_list = dlist_remove(livebox->i18n_list, l);
+ xmlFree(i18n->name);
+ xmlFree(i18n->icon);
+ xmlFree(i18n->lang);
+ free(i18n);
+ }
+
+ dlist_foreach_safe(livebox->group_list, l, n, group) {
+ livebox->group_list = dlist_remove(livebox->group_list, l);
+ DbgPrint("Release %s/%s\n", group->cluster, group->category);
+
+ if (group->ctx_item) {
+ dlist_foreach_safe(group->option_list, il, in, option) {
+ group->option_list = dlist_remove(group->option_list, il);
+ DbgPrint("Release option %s(%s)\n", option->key, option->value);
+ xmlFree(option->key);
+ xmlFree(option->value);
+ free(option);
+ }
+ xmlFree(group->ctx_item);
+ }
+
+ xmlFree(group->cluster);
+ xmlFree(group->category);
+ free(group);
+ }
+
+ free(livebox);
+ return 0;
+}
+
+static inline void update_i18n_name(struct livebox *livebox, xmlNodePtr node)
+{
+ struct i18n *i18n;
+ struct dlist *l;
+ xmlChar *lang;
+ xmlChar *name;
+
+ name = xmlNodeGetContent(node);
+ if (!name) {
+ ErrPrint("Invalid tag\n");
+ return;
+ }
+
+ lang = xmlNodeGetLang(node);
+ if (!lang) {
+ if (livebox->name) {
+ DbgPrint("Override default name: %s\n", livebox->name);
+ xmlFree(livebox->name);
+ }
+
+ livebox->name = name;
+ return;
+ }
+
+ dlist_foreach(livebox->i18n_list, l, i18n) {
+ if (!xmlStrcasecmp(i18n->lang, lang)) {
+ if (i18n->name) {
+ DbgPrint("Override name: %s\n", i18n->name);
+ xmlFree(i18n->name);
+ }
+
+ i18n->name = name;
+ return;
+ }
+ }
+
+ i18n = calloc(1, sizeof(*i18n));
+ if (!i18n) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ xmlFree(name);
+ xmlFree(lang);
+ return;
+ }
+
+ i18n->name = name;
+ i18n->lang = lang;
+ DbgPrint("Label[%s] - [%s] added\n", i18n->lang, i18n->name);
+ livebox->i18n_list = dlist_append(livebox->i18n_list, i18n);
+}
+
+static inline void update_i18n_icon(struct livebox *livebox, xmlNodePtr node)
+{
+ struct i18n *i18n;
+ struct dlist *l;
+ xmlChar *lang;
+ xmlChar *icon;
+
+ icon = xmlNodeGetContent(node);
+ if (!icon) {
+ ErrPrint("Invalid tag\n");
+ return;
+ }
+
+ lang = xmlNodeGetLang(node);
+ if (!lang) {
+ if (livebox->icon) {
+ DbgPrint("Override default icon: %s\n", livebox->icon);
+ xmlFree(livebox->icon);
+ }
+
+ livebox->icon = icon;
+ return;
+ }
+
+ dlist_foreach(livebox->i18n_list, l, i18n) {
+ if (!xmlStrcasecmp(i18n->lang, lang)) {
+ if (i18n->icon) {
+ DbgPrint("Override icon %s for %s\n", i18n->icon, i18n->name);
+ xmlFree(i18n->icon);
+ }
+
+ i18n->icon = icon;
+ return;
+ }
+ }
+
+ i18n = calloc(1, sizeof(*i18n));
+ if (!i18n) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ xmlFree(icon);
+ xmlFree(lang);
+ return;
+ }
+
+ i18n->icon = icon;
+ i18n->lang = lang;
+ DbgPrint("Icon[%s] - [%s] added\n", i18n->lang, i18n->icon);
+ livebox->i18n_list = dlist_append(livebox->i18n_list, i18n);
+}
+
+static inline void update_launch(struct livebox *livebox, xmlNodePtr node)
+{
+ xmlChar *launch;
+
+ launch = xmlNodeGetContent(node);
+ if (!launch) {
+ DbgPrint("Has no launch\n");
+ return;
+ }
+
+ if (livebox->auto_launch) {
+ xmlFree(livebox->auto_launch);
+ }
+
+ livebox->auto_launch = xmlStrdup(launch);
+ if (!livebox->auto_launch) {
+ ErrPrint("Failed to duplicate string: %s\n", (char *)launch);
+ return;
+ }
+}
+
+static inline void update_category(struct livebox *livebox, xmlNodePtr node)
+{
+ xmlChar *category;
+ category = xmlNodeGetContent(node);
+ if (!category) {
+ DbgPrint("Has no valid category\n");
+ return;
+ }
+
+ if (livebox->category) {
+ xmlFree(livebox->category);
+ }
+
+ livebox->category = xmlStrdup(category);
+ if (!livebox->category) {
+ ErrPrint("Failed to duplicate string: %s\n", (char *)category);
+ return;
+ }
+}
+
+static inline void update_ui_appid(struct livebox *livebox, xmlNodePtr node)
+{
+ xmlChar *uiapp;
+ uiapp = xmlNodeGetContent(node);
+ if (!uiapp) {
+ DbgPrint("Has no valid ui-appid\n");
+ return;
+ }
+
+ if (livebox->uiapp) {
+ xmlFree(livebox->uiapp);
+ }
+
+ livebox->uiapp = xmlStrdup(uiapp);
+ if (!livebox->uiapp) {
+ ErrPrint("Failed to duplicate string: %s\n", (char *)uiapp);
+ return;
+ }
+}
+
+static inline void update_setup(struct livebox *livebox, xmlNodePtr node)
+{
+ xmlChar *setup;
+ setup = xmlNodeGetContent(node);
+ if (!setup) {
+ DbgPrint("Has no setup\n");
+ return;
+ }
+
+ if (livebox->setup) {
+ xmlFree(livebox->setup);
+ }
+
+ livebox->setup = xmlStrdup(setup);
+ if (!livebox->setup) {
+ ErrPrint("Failed to duplicate string: %s\n", (char *)setup);
+ return;
+ }
+}
+
+static inline void update_content(struct livebox *livebox, xmlNodePtr node)
+{
+ xmlChar *content;
+ content = xmlNodeGetContent(node);
+ if (!content) {
+ DbgPrint("Has no content\n");
+ return;
+ }
+
+ if (livebox->content) {
+ xmlFree(livebox->content);
+ }
+
+ livebox->content = xmlStrdup(content);
+ if (!livebox->content) {
+ ErrPrint("Failed to duplicate string: %s\n", (char *)content);
+ return;
+ }
+}
+
+static void update_size_info(struct livebox *livebox, int idx, xmlNodePtr node)
+{
+ if (xmlHasProp(node, (const xmlChar *)"preview")) {
+ livebox->preview[idx] = xmlGetProp(node, (const xmlChar *)"preview");
+ }
+
+ if (xmlHasProp(node, (const xmlChar *)"need_frame")) {
+ xmlChar *need_frame;
+
+ need_frame = xmlGetProp(node, (const xmlChar *)"need_frame");
+ if (need_frame) {
+ livebox->need_frame[idx] = !xmlStrcasecmp(need_frame, (const xmlChar *)"true");
+ xmlFree(need_frame);
+ } else {
+ livebox->need_frame[idx] = livebox->default_need_frame;
+ }
+ } else {
+ livebox->need_frame[idx] = livebox->default_need_frame;
+ }
+
+ if (xmlHasProp(node, (const xmlChar *)"touch_effect")) {
+ xmlChar *touch_effect;
+
+ touch_effect = xmlGetProp(node, (const xmlChar *)"touch_effect");
+ if (touch_effect) {
+ livebox->touch_effect[idx] = !xmlStrcasecmp(touch_effect, (const xmlChar *)"true");
+ xmlFree(touch_effect);
+ } else {
+ livebox->touch_effect[idx] = livebox->default_touch_effect;
+ }
+ } else {
+ livebox->touch_effect[idx] = livebox->default_touch_effect;
+ }
+
+ if (xmlHasProp(node, (const xmlChar *)"mouse_event")) {
+ xmlChar *mouse_event;
+
+ mouse_event = xmlGetProp(node, (const xmlChar *)"mouse_event");
+ if (mouse_event) {
+ livebox->mouse_event[idx] = !xmlStrcasecmp(mouse_event, (const xmlChar *)"true");
+ xmlFree(mouse_event);
+ } else {
+ livebox->mouse_event[idx] = livebox->default_mouse_event;
+ }
+ } else {
+ livebox->mouse_event[idx] = livebox->default_mouse_event;
+ }
+}
+
+static inline void update_box(struct livebox *livebox, xmlNodePtr node)
+{
+ if (!xmlHasProp(node, (const xmlChar *)"type")) {
+ livebox->lb_type = LB_TYPE_FILE;
+ } else {
+ xmlChar *type;
+
+ type = xmlGetProp(node, (const xmlChar *)"type");
+ if (!type) {
+ ErrPrint("Type is NIL\n");
+ livebox->lb_type = LB_TYPE_FILE;
+ } else {
+ if (!xmlStrcasecmp(type, (const xmlChar *)"text")) {
+ livebox->lb_type = LB_TYPE_TEXT;
+ } else if (!xmlStrcasecmp(type, (const xmlChar *)"buffer")) {
+ livebox->lb_type = LB_TYPE_BUFFER;
+ } else if (!xmlStrcasecmp(type, (const xmlChar *)"script")) {
+ livebox->lb_type = LB_TYPE_SCRIPT;
+ } else { /* Default */
+ livebox->lb_type = LB_TYPE_FILE;
+ }
+
+ xmlFree(type);
+ }
+ }
+
+ if (!xmlHasProp(node, (const xmlChar *)"mouse_event")) {
+ livebox->default_mouse_event = 0;
+ } else {
+ xmlChar *mouse_event;
+
+ mouse_event = xmlGetProp(node, (const xmlChar *)"mouse_event");
+ if (!mouse_event) {
+ ErrPrint("mouse_event is NIL\n");
+ livebox->default_mouse_event = 0;
+ } else {
+ livebox->default_mouse_event = !xmlStrcasecmp(mouse_event, (const xmlChar *)"true");
+ xmlFree(mouse_event);
+ }
+ }
+
+ if (!xmlHasProp(node, (const xmlChar *)"touch_effect")) {
+ livebox->default_touch_effect = 1;
+ } else {
+ xmlChar *touch_effect;
+
+ touch_effect = xmlGetProp(node, (const xmlChar *)"touch_effect");
+ if (!touch_effect) {
+ ErrPrint("default touch_effect is NIL\n");
+ livebox->default_touch_effect = 1;
+ } else {
+ livebox->default_touch_effect = !xmlStrcasecmp(touch_effect, (const xmlChar *)"true");
+ xmlFree(touch_effect);
+ }
+ }
+
+ if (!xmlHasProp(node, (const xmlChar *)"need_frame")) {
+ livebox->default_need_frame = 0;
+ } else {
+ xmlChar *need_frame;
+
+ need_frame = xmlGetProp(node, (const xmlChar *)"need_frame");
+ if (!need_frame) {
+ ErrPrint("default need_frame is NIL\n");
+ livebox->default_need_frame = 0;
+ } else {
+ livebox->default_need_frame = !xmlStrcasecmp(need_frame, (const xmlChar *)"true");
+ xmlFree(need_frame);
+ }
+ }
+
+ for (node = node->children; node; node = node->next) {
+ if (!xmlStrcasecmp(node->name, (const xmlChar *)"size")) {
+ xmlChar *size;
+ int is_easy = 0;
+
+ size = xmlNodeGetContent(node);
+ if (!size) {
+ ErrPrint("Invalid size tag\n");
+ continue;
+ }
+
+ if (xmlHasProp(node, (const xmlChar *)"mode")) {
+ xmlChar *mode;
+ mode = xmlGetProp(node, (const xmlChar *)"mode");
+ if (mode) {
+ DbgPrint("Easy mode: %s\n", mode);
+ is_easy = !xmlStrcasecmp(mode, (const xmlChar *)"easy");
+ xmlFree(mode);
+ }
+ }
+
+ if (!xmlStrcasecmp(size, (const xmlChar *)"1x1")) {
+ if (is_easy) {
+ livebox->size_list |= LB_SIZE_TYPE_EASY_1x1;
+ update_size_info(livebox, 9, node);
+ } else {
+ livebox->size_list |= LB_SIZE_TYPE_1x1;
+ update_size_info(livebox, 0, node);
+ }
+ } else if (!xmlStrcasecmp(size, (const xmlChar *)"3x1")) {
+ if (is_easy) {
+ livebox->size_list |= LB_SIZE_TYPE_EASY_3x1;
+ update_size_info(livebox, 10, node);
+ } else {
+ ErrPrint("Invalid size tag (%s)\n", size);
+ }
+ } else if (!xmlStrcasecmp(size, (const xmlChar *)"3x3")) {
+ if (is_easy) {
+ livebox->size_list |= LB_SIZE_TYPE_EASY_3x3;
+ update_size_info(livebox, 11, node);
+ } else {
+ ErrPrint("Invalid size tag (%s)\n", size);
+ }
+ } else if (!xmlStrcasecmp(size, (const xmlChar *)"2x1")) {
+ livebox->size_list |= LB_SIZE_TYPE_2x1;
+ update_size_info(livebox, 1, node);
+ } else if (!xmlStrcasecmp(size, (const xmlChar *)"2x2")) {
+ livebox->size_list |= LB_SIZE_TYPE_2x2;
+ update_size_info(livebox, 2, node);
+ } else if (!xmlStrcasecmp(size, (const xmlChar *)"4x1")) {
+ livebox->size_list |= LB_SIZE_TYPE_4x1;
+ update_size_info(livebox, 3, node);
+ } else if (!xmlStrcasecmp(size, (const xmlChar *)"4x2")) {
+ livebox->size_list |= LB_SIZE_TYPE_4x2;
+ update_size_info(livebox, 4, node);
+ } else if (!xmlStrcasecmp(size, (const xmlChar *)"4x3")) {
+ livebox->size_list |= LB_SIZE_TYPE_4x3;
+ update_size_info(livebox, 5, node);
+ } else if (!xmlStrcasecmp(size, (const xmlChar *)"4x4")) {
+ livebox->size_list |= LB_SIZE_TYPE_4x4;
+ update_size_info(livebox, 6, node);
+ } else if (!xmlStrcasecmp(size, (const xmlChar *)"4x5")) {
+ livebox->size_list |= LB_SIZE_TYPE_4x5;
+ update_size_info(livebox, 7, node);
+ } else if (!xmlStrcasecmp(size, (const xmlChar *)"4x6")) {
+ livebox->size_list |= LB_SIZE_TYPE_4x6;
+ update_size_info(livebox, 8, node);
+ } else if (!xmlStrcasecmp(size, (const xmlChar *)"21x21")) {
+ livebox->size_list |= LB_SIZE_TYPE_EASY_1x1;
+ update_size_info(livebox, 9, node);
+ } else if (!xmlStrcasecmp(size, (const xmlChar *)"23x21")) {
+ livebox->size_list |= LB_SIZE_TYPE_EASY_3x1;
+ update_size_info(livebox, 10, node);
+ } else if (!xmlStrcasecmp(size, (const xmlChar *)"23x23")) {
+ livebox->size_list |= LB_SIZE_TYPE_EASY_3x3;
+ update_size_info(livebox, 11, node);
+ } else if (!xmlStrcasecmp(size, (const xmlChar *)"0x0")) {
+ livebox->size_list |= LB_SIZE_TYPE_0x0;
+ update_size_info(livebox, 12, node);
+ } else {
+ ErrPrint("Invalid size tag (%s)\n", size);
+ }
+
+ xmlFree(size);
+ } else if (!xmlStrcasecmp(node->name, (const xmlChar *)"script")) {
+ xmlChar *src;
+
+ if (!xmlHasProp(node, (const xmlChar *)"src")) {
+ ErrPrint("Invalid script tag. has no src\n");
+ continue;
+ }
+
+ src = xmlGetProp(node, (const xmlChar *)"src");
+ if (!src) {
+ ErrPrint("Invalid script tag. src is NIL\n");
+ continue;
+ }
+
+ if (livebox->lb_src) {
+ DbgPrint("Override lb src: %s\n", livebox->lb_src);
+ xmlFree(livebox->lb_src);
+ }
+
+ livebox->lb_src = src;
+
+ if (xmlHasProp(node, (const xmlChar *)"group")) {
+ xmlChar *group;
+ group = xmlGetProp(node, (const xmlChar *)"group");
+ if (!group) {
+ ErrPrint("Group is NIL\n");
+ } else {
+ if (livebox->lb_group) {
+ DbgPrint("Override lb group: %s\n", livebox->lb_group);
+ xmlFree(livebox->lb_group);
+ }
+
+ livebox->lb_group = group;
+ }
+ }
+ }
+ }
+}
+
+static inline void update_group(struct livebox *livebox, xmlNodePtr node)
+{
+ xmlNodePtr cluster;
+ xmlNodePtr category;
+ xmlNodePtr option_item;
+ xmlChar *cluster_name;
+ xmlChar *category_name;
+ xmlChar *ctx_item;
+
+ xmlChar *key;
+ xmlChar *value;
+
+ struct group *group;
+ struct option *option;
+
+ cluster = node;
+ for (cluster = cluster->children; cluster; cluster = cluster->next) {
+ if (xmlStrcasecmp(cluster->name, (const xmlChar *)"cluster")) {
+ DbgPrint("Skip: %s\n", cluster->name);
+ continue;
+ }
+
+ if (!xmlHasProp(cluster, (const xmlChar *)"name")) {
+ ErrPrint("Invalid cluster, has no name\n");
+ continue;
+ }
+
+ cluster_name = xmlGetProp(cluster, (const xmlChar *)"name");
+ if (!cluster_name) {
+ ErrPrint("Invalid cluster name. NIL\n");
+ continue;
+ }
+
+ for (category = cluster->children; category; category = category->next) {
+ if (xmlStrcasecmp(category->name, (const xmlChar *)"category")) {
+ DbgPrint("Skip: %s\n", category->name);
+ continue;
+ }
+
+ if (!xmlHasProp(category, (const xmlChar *)"name")) {
+ ErrPrint("Invalid category, has no name\n");
+ continue;
+ }
+
+ category_name = xmlGetProp(category, (const xmlChar *)"name");
+ if (!category_name) {
+ ErrPrint("Invalid category name. NIL\n");
+ continue;
+ }
+
+ group = calloc(1, sizeof(*group));
+ if (!group) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ xmlFree(category_name);
+ continue;
+ }
+
+ group->cluster = xmlStrdup(cluster_name);
+ if (!group->cluster) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ xmlFree(category_name);
+ free(group);
+ continue;
+ }
+
+ group->category = category_name;
+ livebox->group_list = dlist_append(livebox->group_list, group);
+
+ if (!xmlHasProp(category, (const xmlChar *)"context")) {
+ DbgPrint("%s, %s has no ctx info\n", group->cluster, group->category);
+ continue;
+ }
+
+ ctx_item = xmlGetProp(category, (const xmlChar *)"context");
+ if (!ctx_item) {
+ ErrPrint("Failed to get context ID (%s, %s)\n", group->cluster, group->category);
+ continue;
+ }
+
+ group->ctx_item = ctx_item;
+ DbgPrint("Build group item: %s - %s - %s\n", group->cluster, group->category, group->ctx_item);
+
+ for (option_item = category->children; option_item; option_item = option_item->next) {
+ if (xmlStrcasecmp(option_item->name, (const xmlChar *)"option")) {
+ DbgPrint("Skip: %s\n", option_item->name);
+ continue;
+ }
+
+ if (!xmlHasProp(option_item, (const xmlChar *)"key")) {
+ ErrPrint("Invalid option, has no key\n");
+ continue;
+ }
+
+ if (!xmlHasProp(option_item, (const xmlChar *)"value")) {
+ ErrPrint("Invalid option, has no value\n");
+ continue;
+ }
+
+ key = xmlGetProp(option_item, (const xmlChar *)"key");
+ if (!key) {
+ ErrPrint("Invalid key. NIL\n");
+ continue;
+ }
+
+ value = xmlGetProp(option_item, (const xmlChar *)"value");
+ if (!value) {
+ ErrPrint("Invalid valid. NIL\n");
+ xmlFree(key);
+ continue;
+ }
+
+ option = calloc(1, sizeof(*option));
+ if (!option) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ xmlFree(key);
+ xmlFree(value);
+ continue;
+ }
+
+ option->key = key;
+ option->value = value;
+
+ group->option_list = dlist_append(group->option_list, option);
+ }
+ }
+
+ xmlFree(cluster_name);
+ }
+}
+
+static inline void update_pd(struct livebox *livebox, xmlNodePtr node)
+{
+ if (!xmlHasProp(node, (const xmlChar *)"type")) {
+ livebox->pd_type = PD_TYPE_SCRIPT;
+ } else {
+ xmlChar *type;
+
+ type = xmlGetProp(node, (const xmlChar *)"type");
+ if (!type) {
+ ErrPrint("type is NIL\n");
+ return;
+ }
+
+ if (!xmlStrcasecmp(type, (const xmlChar *)"text")) {
+ livebox->pd_type = PD_TYPE_TEXT;
+ } else if (!xmlStrcasecmp(type, (const xmlChar *)"buffer")) {
+ livebox->pd_type = PD_TYPE_BUFFER;
+ } else {
+ livebox->pd_type = PD_TYPE_SCRIPT;
+ }
+
+ xmlFree(type);
+ }
+
+ for (node = node->children; node; node = node->next) {
+ if (!xmlStrcasecmp(node->name, (const xmlChar *)"size")) {
+ xmlChar *size;
+
+ size = xmlNodeGetContent(node);
+ if (!size) {
+ ErrPrint("Invalid size tag\n");
+ continue;
+ }
+
+ if (livebox->pd_size) {
+ DbgPrint("Override pd size: %s\n", livebox->pd_size);
+ xmlFree(livebox->pd_size);
+ }
+ livebox->pd_size = size;
+ } else if (!xmlStrcasecmp(node->name, (const xmlChar *)"script")) {
+ xmlChar *src;
+
+ if (!xmlHasProp(node, (const xmlChar *)"src")) {
+ ErrPrint("Invalid script tag, has no src\n");
+ continue;
+ }
+
+ src = xmlGetProp(node, (const xmlChar *)"src");
+ if (!src) {
+ ErrPrint("src is NIL\n");
+ continue;
+ }
+
+ if (livebox->pd_src) {
+ DbgPrint("Overide PD src: %s\n", livebox->pd_src);
+ xmlFree(livebox->pd_src);
+ }
+
+ livebox->pd_src = src;
+
+ if (xmlHasProp(node, (const xmlChar *)"group")) {
+ xmlChar *group;
+ group = xmlGetProp(node, (const xmlChar *)"group");
+ if (!group) {
+ ErrPrint("Group is NIL\n");
+ } else {
+ if (livebox->pd_group) {
+ DbgPrint("Override PD group : %s\n", livebox->pd_group);
+ xmlFree(livebox->pd_group);
+ }
+
+ livebox->pd_group = group;
+ }
+ }
+ }
+ }
+}
+
+static int db_insert_livebox(struct livebox *livebox, const char *appid)
+{
+ struct dlist *l;
+ struct dlist *il;
+ struct i18n *i18n;
+ struct group *group;
+ int ret;
+ int id;
+ struct option *option;
+
+ begin_transaction();
+ ret = db_insert_pkgmap(appid, (char *)livebox->pkgid, (char *)livebox->uiapp, livebox->primary, (char *)livebox->category);
+ if (ret < 0) {
+ goto errout;
+ }
+
+ ret = db_insert_provider(livebox);
+ if (ret < 0) {
+ goto errout;
+ }
+
+ ret = db_insert_client(livebox);
+ if (ret < 0) {
+ goto errout;
+ }
+
+ dlist_foreach(livebox->i18n_list, l, i18n) {
+ ret = db_insert_i18n((char *)livebox->pkgid, (char *)i18n->lang, (char *)i18n->name, (char *)i18n->icon);
+ if (ret < 0) {
+ goto errout;
+ }
+ }
+
+ if (livebox->size_list & LB_SIZE_TYPE_1x1) {
+ ret = db_insert_box_size((char *)livebox->pkgid, LB_SIZE_TYPE_1x1, (char *)livebox->preview[0], livebox->touch_effect[0], livebox->need_frame[0], livebox->mouse_event[0]);
+ if (ret < 0) {
+ goto errout;
+ }
+ }
+
+ if (livebox->size_list & LB_SIZE_TYPE_2x1) {
+ ret = db_insert_box_size((char *)livebox->pkgid, LB_SIZE_TYPE_2x1, (char *)livebox->preview[1], livebox->touch_effect[1], livebox->need_frame[1], livebox->mouse_event[1]);
+ if (ret < 0) {
+ goto errout;
+ }
+ }
+
+ if (livebox->size_list & LB_SIZE_TYPE_2x2) {
+ ret = db_insert_box_size((char *)livebox->pkgid, LB_SIZE_TYPE_2x2, (char *)livebox->preview[2], livebox->touch_effect[2], livebox->need_frame[2], livebox->mouse_event[2]);
+ if (ret < 0) {
+ goto errout;
+ }
+ }
+
+ if (livebox->size_list & LB_SIZE_TYPE_4x1) {
+ ret = db_insert_box_size((char *)livebox->pkgid, LB_SIZE_TYPE_4x1, (char *)livebox->preview[3], livebox->touch_effect[3], livebox->need_frame[3], livebox->mouse_event[3]);
+ if (ret < 0) {
+ goto errout;
+ }
+ }
+
+ if (livebox->size_list & LB_SIZE_TYPE_4x2) {
+ ret = db_insert_box_size((char *)livebox->pkgid, LB_SIZE_TYPE_4x2, (char *)livebox->preview[4], livebox->touch_effect[4], livebox->need_frame[4], livebox->mouse_event[4]);
+ if (ret < 0) {
+ goto errout;
+ }
+ }
+
+ if (livebox->size_list & LB_SIZE_TYPE_4x3) {
+ ret = db_insert_box_size((char *)livebox->pkgid, LB_SIZE_TYPE_4x3, (char *)livebox->preview[5], livebox->touch_effect[5], livebox->need_frame[5], livebox->mouse_event[5]);
+ if (ret < 0) {
+ goto errout;
+ }
+ }
+
+ if (livebox->size_list & LB_SIZE_TYPE_4x4) {
+ ret = db_insert_box_size((char *)livebox->pkgid, LB_SIZE_TYPE_4x4, (char *)livebox->preview[6], livebox->touch_effect[6], livebox->need_frame[6], livebox->mouse_event[6]);
+ if (ret < 0) {
+ goto errout;
+ }
+ }
+
+ if (livebox->size_list & LB_SIZE_TYPE_4x5) {
+ ret = db_insert_box_size((char *)livebox->pkgid, LB_SIZE_TYPE_4x5, (char *)livebox->preview[7], livebox->touch_effect[7], livebox->need_frame[7], livebox->mouse_event[7]);
+ if (ret < 0) {
+ goto errout;
+ }
+ }
+
+ if (livebox->size_list & LB_SIZE_TYPE_4x6) {
+ ret = db_insert_box_size((char *)livebox->pkgid, LB_SIZE_TYPE_4x6, (char *)livebox->preview[8], livebox->touch_effect[8], livebox->need_frame[8], livebox->mouse_event[8]);
+ if (ret < 0) {
+ goto errout;
+ }
+ }
+
+ if (livebox->size_list & LB_SIZE_TYPE_EASY_1x1) {
+ ret = db_insert_box_size((char *)livebox->pkgid, LB_SIZE_TYPE_EASY_1x1, (char *)livebox->preview[9], livebox->touch_effect[9], livebox->need_frame[9], livebox->mouse_event[9]);
+ if (ret < 0) {
+ goto errout;
+ }
+ }
+
+ if (livebox->size_list & LB_SIZE_TYPE_EASY_3x1) {
+ ret = db_insert_box_size((char *)livebox->pkgid, LB_SIZE_TYPE_EASY_3x1, (char *)livebox->preview[10], livebox->touch_effect[10], livebox->need_frame[10], livebox->mouse_event[10]);
+ if (ret < 0) {
+ goto errout;
+ }
+ }
+
+ if (livebox->size_list & LB_SIZE_TYPE_EASY_3x3) {
+ ret = db_insert_box_size((char *)livebox->pkgid, LB_SIZE_TYPE_EASY_3x3, (char *)livebox->preview[11], livebox->touch_effect[11], livebox->need_frame[11], livebox->mouse_event[11]);
+ if (ret < 0) {
+ goto errout;
+ }
+ }
+
+ if (livebox->size_list & LB_SIZE_TYPE_0x0) {
+ ret = db_insert_box_size((char *)livebox->pkgid, LB_SIZE_TYPE_0x0, (char *)livebox->preview[12], livebox->touch_effect[12], livebox->need_frame[12], livebox->mouse_event[12]);
+ if (ret < 0) {
+ goto errout;
+ }
+ }
+
+ dlist_foreach(livebox->group_list, l, group) {
+ /* group ID "id" */
+ id = db_get_group_id((char *)group->cluster, (char *)group->category);
+ if (id < 0) {
+ int ret;
+
+ ret = db_insert_group((char *)livebox->pkgid, (char *)group->cluster, (char *)group->category);
+ if (ret < 0) {
+ ErrPrint("[%s]-[%s] is not exists\n", group->cluster, group->category);
+ continue;
+ }
+
+ DbgPrint("New group name is built - %s/%s\n", group->cluster, group->category);
+ id = db_get_group_id((char *)group->cluster, (char *)group->category);
+ if (id < 0) {
+ ErrPrint("Failed to get group id for %s/%s\n", group->cluster, group->category);
+ continue;
+ }
+ }
+
+ if (!group->ctx_item) {
+ DbgPrint("%s, %s - has no ctx info\n", group->cluster, group->category);
+ continue;
+ }
+
+ ret = db_insert_groupmap(id, (char *)livebox->pkgid, (char *)group->ctx_item);
+ if (ret < 0) {
+ goto errout;
+ }
+
+ /* REUSE "id" from here , option ID */
+ id = db_get_option_id(id, (char *)livebox->pkgid, (char *)group->ctx_item);
+ if (id < 0) {
+ goto errout;
+ }
+
+ dlist_foreach(group->option_list, il, option) {
+ ret = db_insert_option((char *)livebox->pkgid, id, (char *)option->key, (char *)option->value);
+ if (ret < 0) {
+ goto errout;
+ }
+ }
+ }
+
+ commit_transaction();
+ livebox_destroy(livebox);
+ return 0;
+
+errout:
+ ErrPrint("ROLLBACK\n");
+ rollback_transaction();
+ livebox_destroy(livebox);
+ return ret;
+}
+
+static int do_install(xmlNodePtr node, const char *appid)
+{
+ struct livebox *livebox;
+ xmlChar *pkgid;
+ xmlChar *tmp;
+
+ if (!xmlHasProp(node, (const xmlChar *)"appid")) {
+ ErrPrint("Missing appid\n");
+ return -EINVAL;
+ }
+
+ pkgid = xmlGetProp(node, (const xmlChar *)"appid");
+ if (!pkgid || !validate_pkgid(appid, (char *)pkgid)) {
+ ErrPrint("Invalid appid\n");
+ xmlFree(pkgid);
+ return -EINVAL;
+ }
+
+ DbgPrint("appid: %s\n", (char *)pkgid);
+
+ livebox = calloc(1, sizeof(*livebox));
+ if (!livebox) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ xmlFree(pkgid);
+ return -ENOMEM;
+ }
+
+ livebox->pkgid = pkgid;
+
+ if (xmlHasProp(node, (const xmlChar *)"primary")) {
+ tmp = xmlGetProp(node, (const xmlChar *)"primary");
+ livebox->primary = !xmlStrcasecmp(tmp, (const xmlChar *)"true");
+ xmlFree(tmp);
+ }
+
+ if (xmlHasProp(node, (const xmlChar *)"script")) {
+ livebox->script = xmlGetProp(node, (const xmlChar *)"script");
+ if (!livebox->script) {
+ ErrPrint("script is NIL\n");
+ }
+ }
+
+ if (xmlHasProp(node, (const xmlChar *)"nodisplay")) {
+ tmp = xmlGetProp(node, (const xmlChar *)"nodisplay");
+ livebox->nodisplay = tmp && !xmlStrcasecmp(tmp, (const xmlChar *)"true");
+ xmlFree(tmp);
+ }
+
+ if (xmlHasProp(node, (const xmlChar *)"pinup")) {
+ tmp = xmlGetProp(node, (const xmlChar *)"pinup");
+ livebox->pinup = tmp && !xmlStrcasecmp(tmp, (const xmlChar *)"true");
+ xmlFree(tmp);
+ }
+
+ if (xmlHasProp(node, (const xmlChar *)"period")) {
+ livebox->period = xmlGetProp(node, (const xmlChar *)"period");
+ if (!livebox->period) {
+ ErrPrint("Period is NIL\n");
+ }
+ }
+
+ if (xmlHasProp(node, (const xmlChar *)"timeout")) {
+ livebox->timeout = xmlGetProp(node, (const xmlChar *)"timeout");
+ if (!livebox->timeout) {
+ ErrPrint("Timeout is NIL\n");
+ }
+ }
+
+ if (xmlHasProp(node, (const xmlChar *)"secured")) {
+ tmp = xmlGetProp(node, (const xmlChar *)"secured");
+ livebox->secured = tmp && !xmlStrcasecmp(tmp, (const xmlChar *)"true");
+ xmlFree(tmp);
+ }
+
+ if (xmlHasProp(node, (const xmlChar *)"network")) {
+ tmp = xmlGetProp(node, (const xmlChar *)"network");
+ livebox->network = tmp && !xmlStrcasecmp(tmp, (const xmlChar *)"true");
+ xmlFree(tmp);
+ }
+
+ if (xmlHasProp(node, (const xmlChar *)"abi")) {
+ livebox->abi = xmlGetProp(node, (const xmlChar *)"abi");
+ if (!livebox->abi) {
+ ErrPrint("ABI is NIL\n");
+ livebox_destroy(livebox);
+ return -EFAULT;
+ }
+ } else {
+ livebox->abi = xmlStrdup((const xmlChar *)"c");
+ if (!livebox->abi) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ livebox_destroy(livebox);
+ return -ENOMEM;
+ }
+ }
+
+ if (xmlHasProp(node, (const xmlChar *)"libexec")) {
+ livebox->libexec = xmlGetProp(node, (const xmlChar *)"libexec");
+ if (!livebox->libexec) {
+ ErrPrint("libexec is NIL\n");
+ livebox_destroy(livebox);
+ return -EFAULT;
+ }
+ } else if (!xmlStrcasecmp(livebox->abi, (const xmlChar *)"c") || !xmlStrcasecmp(livebox->abi, (const xmlChar *)"cpp")) {
+ char *filename;
+ int len;
+
+ len = strlen((char *)livebox->pkgid) + strlen("/libexec/liblive-.so") + 1;
+
+ filename = malloc(len);
+ if (!filename) {
+ livebox_destroy(livebox);
+ return -ENOMEM;
+ }
+
+ snprintf(filename, len, "/libexec/liblive-%s.so", livebox->pkgid);
+ livebox->libexec = xmlStrdup((xmlChar *)filename);
+ DbgPrint("Use the default libexec: %s\n", filename);
+ free(filename);
+
+ if (!livebox->libexec) {
+ livebox_destroy(livebox);
+ return -ENOMEM;
+ }
+ }
+
+ for (node = node->children; node; node = node->next) {
+ if (!xmlStrcmp(node->name, (const xmlChar *)"text")) {
+ continue;
+ }
+
+ DbgPrint("Nodename: %s\n", node->name);
+ if (!xmlStrcasecmp(node->name, (const xmlChar *)"label")) {
+ update_i18n_name(livebox, node);
+ continue;
+ }
+
+ if (!xmlStrcasecmp(node->name, (const xmlChar *)"icon")) {
+ update_i18n_icon(livebox, node);
+ continue;
+ }
+
+ if (!xmlStrcasecmp(node->name, (const xmlChar *)"box")) {
+ update_box(livebox, node);
+ continue;
+ }
+
+ if (!xmlStrcasecmp(node->name, (const xmlChar *)"pd")) {
+ update_pd(livebox, node);
+ continue;
+ }
+
+ if (!xmlStrcasecmp(node->name, (const xmlChar *)"group")) {
+ update_group(livebox, node);
+ continue;
+ }
+
+ if (!xmlStrcasecmp(node->name, (const xmlChar *)"content")) {
+ update_content(livebox, node);
+ continue;
+ }
+
+ if (!xmlStrcasecmp(node->name, (const xmlChar *)"setup")) {
+ update_setup(livebox, node);
+ continue;
+ }
+
+ if (!xmlStrcasecmp(node->name, (const xmlChar *)"launch")) {
+ update_launch(livebox, node);
+ continue;
+ }
+
+ if (!xmlStrcasecmp(node->name, (const xmlChar *)"ui-appid")) {
+ update_ui_appid(livebox, node);
+ continue;
+ }
+
+ if (!xmlStrcasecmp(node->name, (const xmlChar *)"category")) {
+ update_category(livebox, node);
+ continue;
+ }
+ }
+
+ return db_insert_livebox(livebox, appid);
+}
+
+static inline int do_uninstall(xmlNodePtr node, const char *appid)
+{
+ xmlChar *pkgid;
+ int ret;
+
+ if (!xmlHasProp(node, (const xmlChar *)"appid")) {
+ ErrPrint("Missing appid\n");
+ return -EINVAL;
+ }
+
+ pkgid = xmlGetProp(node, (const xmlChar *)"appid");
+ if (!validate_pkgid(appid, (char *)pkgid)) {
+ ErrPrint("Invalid package\n");
+ xmlFree(pkgid);
+ return -EINVAL;
+ }
+
+ begin_transaction();
+ ret = db_remove_box_size((char *)pkgid);
+ if (ret < 0) {
+ goto errout;
+ }
+
+ ret = db_remove_i18n((char *)pkgid);
+ if (ret < 0) {
+ goto errout;
+ }
+
+ ret = db_remove_client((char *)pkgid);
+ if (ret < 0) {
+ goto errout;
+ }
+
+ ret = db_remove_provider((char *)pkgid);
+ if (ret < 0) {
+ goto errout;
+ }
+
+ ret = db_remove_option((char *)pkgid);
+ DbgPrint("Remove option: %d\n", ret);
+
+ ret = db_remove_groupmap((char *)pkgid);
+ DbgPrint("Remove groupmap: %d\n", ret);
+
+ ret = db_remove_group((char *)pkgid);
+ if (ret < 0) {
+ goto errout;
+ }
+
+ ret = db_remove_pkgmap((char *)pkgid);
+ if (ret < 0) {
+ goto errout;
+ }
+
+ commit_transaction();
+ xmlFree(pkgid);
+
+ return 0;
+
+errout:
+ rollback_transaction();
+ xmlFree(pkgid);
+ return ret;
+}
+
+static int pkglist_get_via_callback(const char *appid, void (*cb)(const char *appid, const char *pkgid, int prime, void *data), void *data)
+{
+ const char *dml = "SELECT pkgid, prime FROM pkgmap WHERE appid = ?";
+ int ret;
+ sqlite3_stmt *stmt;
+ const char *pkgid;
+ int prime;
+ int cnt = 0;
+
+ if (!cb || !appid || !strlen(appid)) {
+ return -EINVAL;
+ }
+
+ if (!s_info.handle) {
+ if (db_init() < 0) {
+ ErrPrint("Failed to init DB\n");
+ return -EIO;
+ }
+ }
+
+ ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
+ if (ret != SQLITE_OK) {
+ ErrPrint("Failed to prepare the intial 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 cluster - %s\n", sqlite3_errmsg(s_info.handle));
+ goto out;
+ }
+
+ while (sqlite3_step(stmt) == SQLITE_ROW) {
+ pkgid = (const char *)sqlite3_column_text(stmt, 0);
+ if (!pkgid || !strlen(pkgid)) {
+ continue;
+ }
+
+ prime = sqlite3_column_int(stmt, 1);
+ cb(appid, pkgid, prime, data);
+ cnt++;
+ }
+
+out:
+ sqlite3_reset(stmt);
+ sqlite3_clear_bindings(stmt);
+ sqlite3_finalize(stmt);
+ return cnt;
+}
+
+static void clear_all_pkg(const char *appid, const char *pkgid, int prime, void *data)
+{
+ int ret;
+
+ ErrPrintWithConsole("Remove old package info: appid(%s), pkgid(%s)\n", appid, pkgid);
+
+ ret = db_remove_box_size((char *)pkgid);
+ if (ret < 0) {
+ ErrPrint("Remove box size: %d\n", ret);
+ }
+
+ ret = db_remove_i18n((char *)pkgid);
+ if (ret < 0) {
+ ErrPrint("Remove i18n: %d\n", ret);
+ }
+
+ ret = db_remove_client((char *)pkgid);
+ if (ret < 0) {
+ ErrPrint("Remove client: %d\n", ret);
+ }
+
+ ret = db_remove_provider((char *)pkgid);
+ if (ret < 0) {
+ ErrPrint("Remove provider: %d\n", ret);
+ }
+
+ ret = db_remove_option((char *)pkgid);
+ if (ret < 0) {
+ ErrPrint("Remove option: %d\n", ret);
+ }
+
+ ret = db_remove_groupmap((char *)pkgid);
+ if (ret < 0) {
+ ErrPrint("Remove groupmap: %d\n", ret);
+ }
+
+ ret = db_remove_group((char *)pkgid);
+ if (ret < 0) {
+ ErrPrint("Remove group: %d\n", ret);
+ }
+
+ ret = db_remove_pkgmap((char *)pkgid);
+ if (ret < 0) {
+ ErrPrint("Remove pkgmap: %d\n", ret);
+ }
+}
+
+int PKGMGR_PARSER_PLUGIN_PRE_INSTALL(const char *appid)
+{
+ int cnt;
+
+ ErrPrintWithConsole("%s\n", appid);
+
+ if (!s_info.handle) {
+ if (db_init() < 0) {
+ ErrPrintWithConsole("Failed to init DB\n");
+ return -EIO;
+ }
+ }
+
+ do_upgrade_db_schema();
+
+ begin_transaction();
+ cnt = pkglist_get_via_callback(appid, clear_all_pkg, NULL);
+ commit_transaction();
+
+ if (cnt > 0) {
+ DbgPrint("Package[%s] is not deleted: %d\n", appid, cnt);
+ }
+ return 0;
+}
+
+int PKGMGR_PARSER_PLUGIN_POST_INSTALL(const char *appid)
+{
+ ErrPrintWithConsole("[%s]\n", appid);
+ db_fini();
+ return 0;
+}
+
+int PKGMGR_PARSER_PLUGIN_INSTALL(xmlDocPtr docPtr, const char *appid)
+{
+ xmlNodePtr node;
+ int ret;
+
+ ErrPrintWithConsole("[%s]\n", appid);
+
+ if (!s_info.handle) {
+ ErrPrintWithConsole("Failed to init DB\n");
+ return -EIO;
+ }
+
+ node = xmlDocGetRootElement(docPtr);
+ if (!node) {
+ ErrPrintWithConsole("Invalid document\n");
+ return -EINVAL;
+ }
+
+ for (node = node->children; node; node = node->next) {
+ DbgPrint("node->name: %s\n", node->name);
+ if (!xmlStrcasecmp(node->name, (const xmlChar *)"livebox")) {
+ ret = do_install(node, appid);
+ if (ret < 0) {
+ DbgPrint("Returns: %d\n", ret);
+ }
+ }
+ }
+
+ return 0;
+}
+
+int PKGMGR_PARSER_PLUGIN_PRE_UPGRADE(const char *appid)
+{
+ int cnt;
+
+ ErrPrintWithConsole("[%s]\n", appid);
+
+ if (!s_info.handle) {
+ if (db_init() < 0) {
+ ErrPrint("Failed to init DB\n");
+ return -EIO;
+ }
+ }
+
+ do_upgrade_db_schema();
+
+ begin_transaction();
+ cnt = pkglist_get_via_callback(appid, clear_all_pkg, NULL);
+ commit_transaction();
+
+ if (cnt > 0) {
+ DbgPrint("Package %s is deleted: %d\n", appid, cnt);
+ }
+ return 0;
+}
+
+int PKGMGR_PARSER_PLUGIN_POST_UPGRADE(const char *appid)
+{
+ ErrPrintWithConsole("[%s]\n", appid);
+ db_fini();
+ return 0;
+}
+
+int PKGMGR_PARSER_PLUGIN_UPGRADE(xmlDocPtr docPtr, const char *appid)
+{
+ xmlNodePtr node;
+ int ret;
+
+ ErrPrintWithConsole("[%s]\n", appid);
+
+ if (!s_info.handle) {
+ ErrPrint("Failed to init DB\n");
+ return -EIO;
+ }
+
+ node = xmlDocGetRootElement(docPtr);
+ if (!node) {
+ ErrPrint("Invalid document\n");
+ return -EINVAL;
+ }
+
+ for (node = node->children; node; node = node->next) {
+ if (!xmlStrcasecmp(node->name, (const xmlChar *)"livebox")) {
+ ret = do_install(node, appid);
+ if (ret < 0) {
+ DbgPrint("Returns: %d\n", ret);
+ }
+ }
+ }
+
+ return 0;
+}
+
+int PKGMGR_PARSER_PLUGIN_PRE_UNINSTALL(const char *appid)
+{
+ ErrPrintWithConsole("[%s]\n", appid);
+
+ if (!s_info.handle) {
+ if (db_init() < 0) {
+ ErrPrint("Failed to init DB\n");
+ return -EIO;
+ }
+ }
+
+ do_upgrade_db_schema();
+ return 0;
+}
+
+int PKGMGR_PARSER_PLUGIN_POST_UNINSTALL(const char *appid)
+{
+ int cnt;
+
+ ErrPrintWithConsole("[%s]\n", appid);
+
+ if (!s_info.handle) {
+ return -EIO;
+ }
+
+ begin_transaction();
+ cnt = pkglist_get_via_callback(appid, clear_all_pkg, NULL);
+ commit_transaction();
+
+ if (cnt > 0) {
+ DbgPrint("Package %s is deleted: %d\n", appid, cnt);
+ }
+ db_fini();
+ return 0;
+}
+
+int PKGMGR_PARSER_PLUGIN_UNINSTALL(xmlDocPtr docPtr, const char *appid)
+{
+ ErrPrintWithConsole("[%s]\n", appid);
+ if (!s_info.handle) {
+ return -EIO;
+ }
+ /* Doesn't need to do anything from here, we already dealt it with this */
+ return 0;
+}
+
+/* End of a file */
diff --git a/res/CMakeLists.txt b/res/CMakeLists.txt
new file mode 100644
index 0000000..2ab7c7b
--- /dev/null
+++ b/res/CMakeLists.txt
@@ -0,0 +1 @@
+ADD_SUBDIRECTORY(edje)
diff --git a/res/edje/CMakeLists.txt b/res/edje/CMakeLists.txt
new file mode 100644
index 0000000..ec7f868
--- /dev/null
+++ b/res/edje/CMakeLists.txt
@@ -0,0 +1,9 @@
+#ADD_CUSTOM_TARGET(master.edj
+# COMMAND edje_cc -id ${CMAKE_CURRENT_SOURCE_DIR}/image ${EDJE_CFLAGS}
+# ${CMAKE_CURRENT_SOURCE_DIR}/master.edc master.edj
+# DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/master.edc
+#)
+#ADD_DEPENDENCIES(${PROJECT_NAME} master.edj)
+#INSTALL(FILES master.edj DESTINATION "/opt/apps/org.tizen.${PROJECT_NAME}/res/edje")
+
+# End of a file
diff --git a/res/edje/master.edc b/res/edje/master.edc
new file mode 100644
index 0000000..38fcf7e
--- /dev/null
+++ b/res/edje/master.edc
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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.
+ */
+
+collections {
+ group {
+ name: "error";
+ parts {
+ part {
+ name: "image";
+ type: SWALLOW;
+ description {
+ state: "default" 0.0;
+ rel1 { relative: 0.0 0.0; }
+ rel2 { relative: 1.0 1.0; }
+ }
+ }
+
+ part {
+ name: "bg";
+ type: RECT;
+ description {
+ state: "default" 0.0;
+ rel1 { relative: 0.0 0.0; }
+ rel2 { relative: 1.0 1.0; }
+ color: 50 50 50 50;
+ }
+ }
+
+ part {
+ name: "pkgname";
+ type: TEXT;
+ description {
+ state: "default" 0.0;
+ rel1 { relative: 0.25 0.2; to, "bg"; }
+ rel2 { relative: 0.75 0.35; to, "bg"; }
+ text {
+ font: "SLP:style=medium";
+ size: 20;
+ fit: 1 1;
+ text: "pkgname";
+ align: 0.5 0.5;
+ }
+ }
+ }
+ part {
+ name: "function";
+ type: TEXT;
+ description {
+ state: "default" 0.0;
+ rel1 { relative: 0.25 0.35; to, "bg"; }
+ rel2 { relative: 0.75 0.5; to, "bg"; }
+ text {
+ font: "SLP:style=medium";
+ size: 20;
+ fit: 1 1;
+ text: "function";
+ align: 0.5 0.5;
+ }
+ }
+ }
+ part {
+ name: "slave_pid";
+ type: TEXT;
+ description {
+ state: "default" 0.0;
+ rel1 { relative: 0.25 0.5; to, "bg"; }
+ rel2 { relative: 0.75 0.65; to, "bg"; }
+ text {
+ font: "SLP:style=medium";
+ size: 20;
+ fit: 1 1;
+ text: "slave_pid";
+ align: 0.5 0.5;
+ }
+ }
+ }
+ part {
+ name: "filename";
+ type: TEXT;
+ description {
+ state: "default" 0.0;
+ rel1 { relative: 0.0 0.65; to, "bg"; }
+ rel2 { relative: 1.0 0.8; to, "bg"; }
+ text {
+ font: "SLP:style=medium";
+ size: 20;
+ fit: 1 1;
+ text: "filename";
+ align: 0.5 0.5;
+ }
+ }
+ }
+ } // parts
+ }
+} // collections
+
+
+
+// End of a file
diff --git a/src/abi.c b/src/abi.c
new file mode 100644
index 0000000..edbfa21
--- /dev/null
+++ b/src/abi.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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 <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <Eina.h>
+#include <dlog.h>
+#include <livebox-errno.h>
+
+#include "util.h"
+#include "debug.h"
+#include "conf.h"
+
+int errno;
+
+struct item {
+ char *abi;
+ char *pkgname; /*!< Slave package name */
+};
+
+static struct {
+ Eina_List *list;
+} s_abi = {
+ .list = NULL,
+};
+
+HAPI int abi_add_entry(const char *abi, const char *pkgname)
+{
+ struct item *item;
+
+ item = malloc(sizeof(*item));
+ if (!item) {
+ ErrPrint("Failed to add a new entry for abi[%s - %s]\n", abi, pkgname);
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ item->abi = strdup(abi);
+ if (!item->abi) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(item);
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ item->pkgname = strdup(pkgname);
+ if (!item->pkgname) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(item->abi);
+ DbgFree(item);
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ s_abi.list = eina_list_append(s_abi.list, item);
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI int abi_update_entry(const char *abi, const char *pkgname)
+{
+ Eina_List *l;
+ Eina_List *n;
+ struct item *item;
+ char *_pkgname;
+
+ _pkgname = strdup(pkgname);
+ if (!_pkgname) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ EINA_LIST_FOREACH_SAFE(s_abi.list, l, n, item) {
+ if (!strcasecmp(item->abi, abi)) {
+ DbgFree(item->pkgname);
+ item->pkgname = _pkgname;
+ return 0;
+ }
+ }
+
+ DbgFree(_pkgname);
+ return LB_STATUS_ERROR_NOT_EXIST;
+}
+
+HAPI int abi_del_entry(const char *abi)
+{
+ Eina_List *l;
+ Eina_List *n;
+ struct item *item;
+
+ EINA_LIST_FOREACH_SAFE(s_abi.list, l, n, item) {
+ if (!strcasecmp(item->abi, abi)) {
+ s_abi.list = eina_list_remove(s_abi.list, item);
+ DbgFree(item->abi);
+ DbgFree(item->pkgname);
+ DbgFree(item);
+ return LB_STATUS_SUCCESS;
+ }
+ }
+
+ return LB_STATUS_ERROR_NOT_EXIST;
+}
+
+HAPI void abi_del_all(void)
+{
+ struct item *item;
+
+ EINA_LIST_FREE(s_abi.list, item) {
+ DbgFree(item->abi);
+ DbgFree(item->pkgname);
+ DbgFree(item);
+ }
+}
+
+HAPI const char *abi_find_slave(const char *abi)
+{
+ Eina_List *l;
+ struct item *item;
+
+ EINA_LIST_FOREACH(s_abi.list, l, item) {
+ if (!strcasecmp(item->abi, abi)) {
+ return item->pkgname;
+ }
+ }
+
+ return NULL;
+}
+
+HAPI const char *abi_find_by_pkgname(const char *pkgname)
+{
+ Eina_List *l;
+ struct item *item;
+
+ EINA_LIST_FOREACH(s_abi.list, l, item) {
+ if (!strcmp(item->pkgname, pkgname)) {
+ return item->abi;
+ }
+ }
+
+ return NULL;
+}
+
+/* End of a file */
diff --git a/src/badge_service.c b/src/badge_service.c
new file mode 100644
index 0000000..2b1dc0b
--- /dev/null
+++ b/src/badge_service.c
@@ -0,0 +1,593 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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 <stdio.h>
+
+#include <Eina.h>
+
+#include <dlog.h>
+#if defined(HAVE_LIVEBOX)
+#include <livebox-errno.h>
+#else
+#include "lite-errno.h"
+#endif
+#include <packet.h>
+
+#include <sys/smack.h>
+
+#include <badge.h>
+#include <badge_db.h>
+#include <badge_setting_service.h>
+#include <security-server.h>
+
+#include "service_common.h"
+#include "debug.h"
+#include "util.h"
+#include "conf.h"
+
+static struct info {
+ Eina_List *context_list;
+ struct service_context *svc_ctx;
+} s_info = {
+ .context_list = NULL, /*!< \WARN: This is only used for SERVICE THREAD */
+ .svc_ctx = NULL, /*!< \WARN: This is only used for MAIN THREAD */
+};
+
+#define ENABLE_BS_ACCESS_CONTROL 1
+
+struct context {
+ struct tcb *tcb;
+ double seq;
+};
+
+struct badge_service {
+ const char *cmd;
+ void (*handler)(struct tcb *tcb, struct packet *packet, void *data);
+ const char *rule;
+ const char *access;
+};
+
+/*!
+ * FUNCTIONS to check smack permission
+ */
+static int _is_valid_permission(int fd, struct badge_service *service)
+{
+ int ret;
+
+ if (service->rule != NULL && service->access != NULL) {
+ ret = security_server_check_privilege_by_sockfd(fd, service->rule, service->access);
+ if (ret == SECURITY_SERVER_API_ERROR_ACCESS_DENIED) {
+ ErrPrint("SMACK:Access denied\n");
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+static int _is_manager_permission(int fd)
+{
+ int ret;
+
+ ret = security_server_check_privilege_by_sockfd(fd,
+ "data-provider-master::badge.manager", "w");
+ if (ret == SECURITY_SERVER_API_ERROR_ACCESS_DENIED) {
+ ErrPrint("SMACK:not a manager\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+/*!
+ * FUNCTIONS to handle badge
+ */
+static inline char *get_string(char *string)
+{
+ if (string == NULL) {
+ return NULL;
+ }
+ if (string[0] == '\0') {
+ return NULL;
+ }
+
+ return string;
+}
+
+/*!
+ * SERVICE HANDLER
+ */
+static void _handler_insert_badge(struct tcb *tcb, struct packet *packet, void *data)
+{
+ int ret = 0, ret_p = 0;
+ struct packet *packet_reply = NULL;
+ struct packet *packet_service = NULL;
+ char *pkgname = NULL;
+ char *writable_pkg = NULL;
+ char *caller = NULL;
+
+ if (packet_get(packet, "sss", &pkgname, &writable_pkg, &caller) == 3) {
+ pkgname = get_string(pkgname);
+ writable_pkg = get_string(writable_pkg);
+ caller = get_string(caller);
+
+ if (pkgname != NULL && writable_pkg != NULL && caller != NULL) {
+ ret = badge_db_insert(pkgname, writable_pkg, caller);
+ } else {
+ ret = BADGE_ERROR_INVALID_DATA;
+ }
+
+ packet_reply = packet_create_reply(packet, "i", ret);
+ if (packet_reply) {
+ if ((ret_p = service_common_unicast_packet(tcb, packet_reply)) < 0) {
+ ErrPrint("Failed to send a reply packet:%d", ret_p);
+ }
+ packet_destroy(packet_reply);
+ } else {
+ ErrPrint("Failed to create a reply packet");
+ }
+
+ if (ret == BADGE_ERROR_NONE) {
+ packet_service = packet_create("insert_badge", "is", ret, pkgname);
+ if (packet_service != NULL) {
+ if ((ret_p = service_common_multicast_packet(tcb, packet_service, TCB_CLIENT_TYPE_SERVICE)) < 0) {
+ ErrPrint("Failed to send a muticast packet:%d", ret_p);
+ }
+ packet_destroy(packet_service);
+ } else {
+ ErrPrint("Failed to create a multicast packet");
+ }
+ } else {
+ ErrPrint("Failed to insert a badge:%d", ret);
+ }
+ } else {
+ ErrPrint("Failed to get data from the packet");
+ }
+}
+
+static void _handler_delete_badge(struct tcb *tcb, struct packet *packet, void *data)
+{
+ int ret = 0, ret_p = 0;
+ struct packet *packet_reply = NULL;
+ struct packet *packet_service = NULL;
+ char *pkgname = NULL;
+ char *caller = NULL;
+
+ if (packet_get(packet, "ss", &pkgname, &caller) == 2) {
+ pkgname = get_string(pkgname);
+ caller = get_string(caller);
+
+ if (pkgname != NULL && caller != NULL) {
+ if (_is_manager_permission(tcb_fd(tcb)) == 1) {
+ ret = badge_db_delete(pkgname, pkgname);
+ } else {
+ ret = badge_db_delete(pkgname, caller);
+ }
+ } else {
+ ret = BADGE_ERROR_INVALID_DATA;
+ }
+
+ packet_reply = packet_create_reply(packet, "i", ret);
+ if (packet_reply) {
+ if ((ret_p = service_common_unicast_packet(tcb, packet_reply)) < 0) {
+ ErrPrint("Failed to send a reply packet:%d", ret_p);
+ }
+ packet_destroy(packet_reply);
+ } else {
+ ErrPrint("Failed to create a reply packet");
+ }
+
+ if (ret == BADGE_ERROR_NONE) {
+ packet_service = packet_create("delete_badge", "is", ret, pkgname);
+ if (packet_service != NULL) {
+ if ((ret_p = service_common_multicast_packet(tcb, packet_service, TCB_CLIENT_TYPE_SERVICE)) < 0) {
+ ErrPrint("Failed to send a muticast packet:%d", ret_p);
+ }
+ packet_destroy(packet_service);
+ } else {
+ ErrPrint("Failed to create a multicast packet");
+ }
+ } else {
+ ErrPrint("Failed to delete a badge:%d", ret);
+ }
+ } else {
+ ErrPrint("Failed to get data from the packet");
+ }
+}
+
+static void _handler_set_badge_count(struct tcb *tcb, struct packet *packet, void *data)
+{
+ int ret = 0, ret_p = 0;
+ struct packet *packet_reply = NULL;
+ struct packet *packet_service = NULL;
+ char *pkgname = NULL;
+ char *caller = NULL;
+ int count = 0;
+
+ if (packet_get(packet, "ssi", &pkgname, &caller, &count) == 3) {
+ pkgname = get_string(pkgname);
+ caller = get_string(caller);
+
+ if (pkgname != NULL && caller != NULL) {
+ ret = badge_db_set_count(pkgname, caller, count);
+ } else {
+ ret = BADGE_ERROR_INVALID_DATA;
+ }
+
+ packet_reply = packet_create_reply(packet, "i", ret);
+ if (packet_reply) {
+ if ((ret_p = service_common_unicast_packet(tcb, packet_reply)) < 0) {
+ ErrPrint("Failed to send a reply packet:%d", ret_p);
+ }
+ packet_destroy(packet_reply);
+ } else {
+ ErrPrint("Failed to create a reply packet");
+ }
+
+ if (ret == BADGE_ERROR_NONE) {
+ packet_service = packet_create("set_badge_count", "isi", ret, pkgname, count);
+ if (packet_service != NULL) {
+ if ((ret_p = service_common_multicast_packet(tcb, packet_service, TCB_CLIENT_TYPE_SERVICE)) < 0) {
+ ErrPrint("Failed to send a muticast packet:%d", ret_p);
+ }
+ packet_destroy(packet_service);
+ } else {
+ ErrPrint("Failed to create a multicast packet");
+ }
+ } else {
+ ErrPrint("Failed to set count of badge:%d", ret);
+ }
+ } else {
+ ErrPrint("Failed to get data from the packet");
+ }
+}
+
+static void _handler_set_display_option(struct tcb *tcb, struct packet *packet, void *data)
+{
+ int ret = 0, ret_p = 0;
+ struct packet *packet_reply = NULL;
+ struct packet *packet_service = NULL;
+ char *pkgname = NULL;
+ char *caller = NULL;
+ int is_display = 0;
+
+ if (packet_get(packet, "ssi", &pkgname, &caller, &is_display) == 3) {
+ pkgname = get_string(pkgname);
+ caller = get_string(caller);
+
+ if (pkgname != NULL && caller != NULL) {
+ ret = badge_db_set_display_option(pkgname, caller, is_display);
+ } else {
+ ret = BADGE_ERROR_INVALID_DATA;
+ }
+
+ packet_reply = packet_create_reply(packet, "i", ret);
+ if (packet_reply) {
+ if ((ret_p = service_common_unicast_packet(tcb, packet_reply)) < 0) {
+ ErrPrint("Failed to send a reply packet:%d", ret_p);
+ }
+ packet_destroy(packet_reply);
+ } else {
+ ErrPrint("Failed to create a reply packet");
+ }
+
+ if (ret == BADGE_ERROR_NONE) {
+ packet_service = packet_create("set_disp_option", "isi", ret, pkgname, is_display);
+ if (packet_service != NULL) {
+ if ((ret_p = service_common_multicast_packet(tcb, packet_service, TCB_CLIENT_TYPE_SERVICE)) < 0) {
+ ErrPrint("Failed to send a muticast packet:%d", ret_p);
+ }
+ packet_destroy(packet_service);
+ } else {
+ ErrPrint("Failed to create a multicast packet");
+ }
+ } else {
+ ErrPrint("Failed to set display option of badge:%d", ret);
+ }
+ } else {
+ ErrPrint("Failed to get data from the packet");
+ }
+}
+
+static void _handler_set_setting_property(struct tcb *tcb, struct packet *packet, void *data)
+{
+ int ret = 0, ret_p = 0;
+ int is_display = 0;
+ struct packet *packet_reply = NULL;
+ struct packet *packet_service = NULL;
+ char *pkgname = NULL;
+ char *property = NULL;
+ char *value = NULL;
+
+ if (packet_get(packet, "sss", &pkgname, &property, &value) == 3) {
+ pkgname = get_string(pkgname);
+ property = get_string(property);
+ value = get_string(value);
+
+ if (pkgname != NULL && property != NULL && value != NULL) {
+ ret = badge_setting_db_set(pkgname, property, value);
+ } else {
+ ret = BADGE_ERROR_INVALID_DATA;
+ }
+
+ packet_reply = packet_create_reply(packet, "ii", ret, ret);
+ if (packet_reply) {
+ if ((ret_p = service_common_unicast_packet(tcb, packet_reply)) < 0) {
+ ErrPrint("failed to send reply packet:%d\n", ret_p);
+ }
+ packet_destroy(packet_reply);
+ } else {
+ ErrPrint("failed to create a reply packet\n");
+ }
+
+ if (ret == BADGE_ERROR_NONE) {
+ if (strcmp(property, "OPT_BADGE") == 0) {
+ if (strcmp(value, "ON") == 0) {
+ is_display = 1;
+ } else {
+ is_display = 0;
+ }
+
+ packet_service = packet_create("set_disp_option", "isi", ret, pkgname, is_display);
+ if (packet_service != NULL) {
+ if ((ret_p = service_common_multicast_packet(tcb, packet_service, TCB_CLIENT_TYPE_SERVICE)) < 0) {
+ ErrPrint("Failed to send a muticast packet:%d", ret_p);
+ }
+ packet_destroy(packet_service);
+ } else {
+ ErrPrint("Failed to create a multicast packet");
+ }
+ }
+ } else {
+ ErrPrint("failed to set noti property:%d\n", ret);
+ }
+ } else {
+ ErrPrint("Failed to get data from the packet");
+ }
+}
+
+static void _handler_get_setting_property(struct tcb *tcb, struct packet *packet, void *data)
+{
+ int ret = 0, ret_p = 0;
+ struct packet *packet_reply = NULL;
+ char *pkgname = NULL;
+ char *property = NULL;
+ char *value = NULL;
+
+ if (packet_get(packet, "sss", &pkgname, &property) == 2) {
+ pkgname = get_string(pkgname);
+ property = get_string(property);
+
+ if (pkgname != NULL && property != NULL) {
+ ret = badge_setting_db_get(pkgname, property, &value);
+ } else {
+ ret = BADGE_ERROR_INVALID_DATA;
+ }
+
+ packet_reply = packet_create_reply(packet, "is", ret, value);
+ if (packet_reply) {
+ if ((ret_p = service_common_unicast_packet(tcb, packet_reply)) < 0) {
+ ErrPrint("failed to send reply packet:%d\n", ret_p);
+ }
+ packet_destroy(packet_reply);
+ } else {
+ ErrPrint("failed to create a reply packet\n");
+ }
+
+ if (value != NULL) {
+ DbgFree(value);
+ }
+ }
+}
+
+static void _handler_service_register(struct tcb *tcb, struct packet *packet, void *data)
+{
+ int ret = 0;
+ struct packet *packet_reply;
+
+ ret = tcb_client_type_set(tcb, TCB_CLIENT_TYPE_SERVICE);
+ if (ret < 0) {
+ ErrPrint("Failed to set the type of client:%d", ret);
+ }
+
+ packet_reply = packet_create_reply(packet, "i", ret);
+ if (packet_reply) {
+ if ((ret = service_common_unicast_packet(tcb, packet_reply)) < 0) {
+ ErrPrint("Failed to send a reply packet:%d", ret);
+ }
+ packet_destroy(packet_reply);
+ } else {
+ ErrPrint("Failed to create a reply packet");
+ }
+}
+
+static void _handler_access_control_error(struct tcb *tcb, struct packet *packet)
+{
+ int ret_p = 0;
+ struct packet *packet_reply = NULL;
+
+ packet_reply = packet_create_reply(packet, "i", BADGE_ERROR_PERMISSION_DENIED);
+ if (packet_reply) {
+ if ((ret_p = service_common_unicast_packet(tcb, packet_reply)) < 0) {
+ ErrPrint("Failed to send a reply packet:%d", ret_p);
+ }
+ packet_destroy(packet_reply);
+ } else {
+ ErrPrint("Failed to create a reply packet");
+ }
+}
+
+/*!
+ * SERVICE THREAD
+ */
+static int service_thread_main(struct tcb *tcb, struct packet *packet, void *data)
+{
+ int i = 0;
+ const char *command;
+ static struct badge_service service_req_table[] = {
+ {
+ .cmd = "insert_badge",
+ .handler = _handler_insert_badge,
+ .rule = "data-provider-master::badge.client",
+ .access = "w",
+ },
+ {
+ .cmd = "delete_badge",
+ .handler = _handler_delete_badge,
+ .rule = "data-provider-master::badge.client",
+ .access = "w",
+ },
+ {
+ .cmd = "set_badge_count",
+ .handler = _handler_set_badge_count,
+ .rule = "data-provider-master::badge.client",
+ .access = "w",
+ },
+ {
+ .cmd = "set_disp_option",
+ .handler = _handler_set_display_option,
+ .rule = "data-provider-master::badge.client",
+ .access = "w",
+ },
+ {
+ .cmd = "set_noti_property",
+ .handler = _handler_set_setting_property,
+ .rule = "data-provider-master::badge.client",
+ .access = "w",
+ },
+ {
+ .cmd = "get_noti_property",
+ .handler = _handler_get_setting_property,
+ .rule = "data-provider-master::badge.client",
+ .access = "r",
+ },
+ {
+ .cmd = "service_register",
+ .handler = _handler_service_register,
+ .rule = NULL,
+ .access = NULL,
+ },
+ {
+ .cmd = NULL,
+ .handler = NULL,
+ .rule = NULL,
+ .access = NULL,
+ },
+ };
+
+ if (!packet) {
+ DbgPrint("TCB: %p is terminated (NIL packet)\n", tcb);
+ return 0;
+ }
+
+ command = packet_command(packet);
+ if (!command) {
+ ErrPrint("Invalid command\n");
+ return -EINVAL;
+ }
+ DbgPrint("Command: [%s], Packet type[%d]\n", command, packet_type(packet));
+
+ switch (packet_type(packet)) {
+ case PACKET_REQ:
+ /* Need to send reply packet */
+ for (i = 0; service_req_table[i].cmd; i++) {
+ if (strcmp(service_req_table[i].cmd, command)) {
+ continue;
+ }
+
+#if ENABLE_BS_ACCESS_CONTROL
+ if (_is_valid_permission(tcb_fd(tcb), &(service_req_table[i])) == 1) {
+ service_req_table[i].handler(tcb, packet, data);
+ } else {
+ _handler_access_control_error(tcb, packet);
+ }
+#else
+ _is_valid_permission(tcb_fd(tcb), &(service_req_table[i]));
+ service_req_table[i].handler(tcb, packet, data);
+#endif
+ break;
+ }
+
+ break;
+ case PACKET_REQ_NOACK:
+ break;
+ case PACKET_ACK:
+ break;
+ default:
+ ErrPrint("Packet type is not valid[%s]\n", command);
+ return -EINVAL;
+ }
+
+ /*!
+ * return value has no meanning,
+ * it will be printed by dlogutil.
+ */
+ return 0;
+}
+
+
+/*!
+ * MAIN THREAD
+ * Do not try to do anyother operation in these functions
+ */
+HAPI int badge_service_init(void)
+{
+ if (s_info.svc_ctx) {
+ ErrPrint("Already initialized\n");
+ return LB_STATUS_ERROR_ALREADY;
+ }
+
+ s_info.svc_ctx = service_common_create(BADGE_SOCKET, service_thread_main, NULL);
+ if (!s_info.svc_ctx) {
+ ErrPrint("Unable to activate service thread\n");
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ if (smack_fsetlabel(service_common_fd(s_info.svc_ctx), BADGE_SMACK_LABEL, SMACK_LABEL_IPOUT) != 0) {
+ if (errno != EOPNOTSUPP) {
+ ErrPrint("Unable to set SMACK label(%d)\n", errno);
+ service_common_destroy(s_info.svc_ctx);
+ s_info.svc_ctx = NULL;
+ return LB_STATUS_ERROR_FAULT;
+ }
+ }
+
+ if (smack_fsetlabel(service_common_fd(s_info.svc_ctx), BADGE_SMACK_LABEL, SMACK_LABEL_IPIN) != 0) {
+ if (errno != EOPNOTSUPP) {
+ ErrPrint("Unable to set SMACK label(%d)\n", errno);
+ service_common_destroy(s_info.svc_ctx);
+ s_info.svc_ctx = NULL;
+ return LB_STATUS_ERROR_FAULT;
+ }
+ }
+
+ DbgPrint("Successfully initiated\n");
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI int badge_service_fini(void)
+{
+ if (!s_info.svc_ctx) {
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ service_common_destroy(s_info.svc_ctx);
+ s_info.svc_ctx = NULL;
+ DbgPrint("Successfully finalized\n");
+ return LB_STATUS_SUCCESS;
+}
+
+/* End of a file */
diff --git a/src/buffer_handler.c b/src/buffer_handler.c
new file mode 100644
index 0000000..c27eecf
--- /dev/null
+++ b/src/buffer_handler.c
@@ -0,0 +1,1765 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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 <stdio.h>
+#include <unistd.h> /* access */
+#include <sys/mman.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/shm.h>
+#include <sys/ipc.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <Ecore.h>
+#include <Ecore_X.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Xproto.h>
+#include <X11/extensions/Xdamage.h>
+#include <X11/extensions/Xfixes.h>
+#include <X11/extensions/XShm.h>
+
+#include <dri2.h>
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+#include <tbm_bufmgr.h>
+
+#include <dlog.h>
+#include <packet.h>
+#include <livebox-errno.h>
+
+#include "debug.h"
+#include "conf.h"
+#include "util.h"
+#include "instance.h"
+#include "package.h"
+#include "client_life.h"
+#include "client_rpc.h"
+#include "buffer_handler.h"
+#include "script_handler.h" // Reverse dependency. must has to be broken
+
+struct buffer {
+ enum {
+ CREATED = 0x00beef00,
+ DESTROYED = 0x00dead00
+ } state;
+ enum buffer_type type;
+ int refcnt;
+ void *info;
+ char data[];
+};
+
+/*!
+ * \brief Allocate this in the buffer->data.
+ */
+struct gem_data {
+ DRI2Buffer *dri2_buffer;
+ unsigned int attachments[1];
+ tbm_bo pixmap_bo;
+ int count;
+ int buf_count;
+ int w;
+ int h;
+ int depth;
+ Pixmap pixmap;
+ void *data; /* Gem layer */
+ int refcnt;
+
+ void *compensate_data; /* Check the pitch value, copy this to data */
+};
+
+struct buffer_info
+{
+ void *buffer;
+ char *id;
+ char *lock;
+ int lock_fd;
+
+ enum buffer_type type;
+
+ int w;
+ int h;
+ int pixel_size;
+ int is_loaded;
+
+ struct inst_info *inst;
+ void *data;
+};
+
+static struct {
+ tbm_bufmgr slp_bufmgr;
+ int evt_base;
+ int err_base;
+ int fd;
+ Eina_List *pixmap_list;
+} s_info = {
+ .slp_bufmgr = NULL,
+ .evt_base = 0,
+ .err_base = 0,
+ .fd = -1,
+ .pixmap_list = NULL,
+};
+
+static int destroy_lock_file(struct buffer_info *info)
+{
+ if (!info->inst) {
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (!info->lock) {
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (close(info->lock_fd) < 0) {
+ ErrPrint("close: %s\n", strerror(errno));
+ }
+ info->lock_fd = -1;
+
+ if (unlink(info->lock) < 0) {
+ ErrPrint("unlink: %s\n", strerror(errno));
+ }
+
+ DbgFree(info->lock);
+ info->lock = NULL;
+ return LB_STATUS_SUCCESS;
+}
+
+static int create_lock_file(struct buffer_info *info)
+{
+ const char *id;
+ int len;
+ char *file;
+ char target[3] = "pd";
+
+ if (!info->inst) {
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ id = instance_id(info->inst);
+ if (!id) {
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ len = strlen(id);
+ file = malloc(len + 20);
+ if (!file) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ if (script_handler_buffer_info(instance_pd_script(info->inst)) != info && instance_pd_buffer(info->inst) != info) {
+ target[0] = 'l';
+ target[1] = 'b';
+ /* target[2] = '\0'; // We already have this ;) */
+ }
+
+ snprintf(file, len + 20, "%s.%s.lck", util_uri_to_path(id), target);
+ info->lock_fd = open(file, O_WRONLY|O_CREAT, 0644);
+ if (info->lock_fd < 0) {
+ ErrPrint("open: %s\n", strerror(errno));
+ DbgFree(file);
+ return LB_STATUS_ERROR_IO;
+ }
+
+ info->lock = file;
+ return LB_STATUS_SUCCESS;
+}
+
+static int do_buffer_lock(struct buffer_info *buffer)
+{
+ struct flock flock;
+ int ret;
+
+ if (buffer->lock_fd < 0) {
+ return LB_STATUS_SUCCESS;
+ }
+
+ flock.l_type = F_WRLCK;
+ flock.l_whence = SEEK_SET;
+ flock.l_start = 0;
+ flock.l_len = 0;
+ flock.l_pid = getpid();
+
+ do {
+ ret = fcntl(buffer->lock_fd, F_SETLKW, &flock);
+ if (ret < 0) {
+ ret = errno;
+ ErrPrint("fcntl: %s\n", strerror(errno));
+ }
+ } while (ret == EINTR);
+
+ return LB_STATUS_SUCCESS;
+}
+
+static int do_buffer_unlock(struct buffer_info *buffer)
+{
+ struct flock flock;
+ int ret;
+
+ if (buffer->lock_fd < 0) {
+ return LB_STATUS_SUCCESS;
+ }
+
+ flock.l_type = F_UNLCK;
+ flock.l_whence = SEEK_SET;
+ flock.l_start = 0;
+ flock.l_len = 0;
+ flock.l_pid = getpid();
+
+ do {
+ ret = fcntl(buffer->lock_fd, F_SETLKW, &flock);
+ if (ret < 0) {
+ ret = errno;
+ ErrPrint("fcntl: %s\n", strerror(errno));
+ }
+ } while (ret == EINTR);
+
+ return LB_STATUS_SUCCESS;
+}
+
+static inline struct buffer *create_pixmap(struct buffer_info *info)
+{
+ struct gem_data *gem;
+ struct buffer *buffer;
+ Display *disp;
+ Window parent;
+ XGCValues gcv;
+ GC gc;
+
+ disp = ecore_x_display_get();
+ if (!disp) {
+ return NULL;
+ }
+
+ parent = DefaultRootWindow(disp);
+
+ buffer = calloc(1, sizeof(*buffer) + sizeof(*gem));
+ if (!buffer) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ gem = (struct gem_data *)buffer->data;
+
+ buffer->type = BUFFER_TYPE_PIXMAP;
+ buffer->refcnt = 1;
+ buffer->state = CREATED;
+
+ gem->attachments[0] = DRI2BufferFrontLeft;
+ gem->count = 1;
+ gem->w = info->w; /*!< This can be changed by DRI2GetBuffers */
+ gem->h = info->h; /*!< This can be changed by DRI2GetBuffers */
+ gem->depth = info->pixel_size;
+ /*!
+ * \NOTE
+ * Use the 24 Bits
+ * 32 Bits is not supported for video playing.
+ * But for the transparent background, use the 32 bits, and give up video.
+ */
+ gem->pixmap = XCreatePixmap(disp, parent, info->w, info->h, (info->pixel_size << 3));
+ if (gem->pixmap == (Pixmap)0) {
+ ErrPrint("Failed to create a pixmap\n");
+ DbgFree(buffer);
+ return NULL;
+ }
+
+ /*!
+ * \note
+ * Clear pixmap
+ */
+ memset(&gcv, 0, sizeof(gcv));
+ gc = XCreateGC(disp, gem->pixmap, GCForeground, &gcv);
+ if (gc) {
+ XFillRectangle(disp, gem->pixmap, gc, 0, 0, info->w, info->h);
+ XSync(disp, False);
+ XFreeGC(disp, gc);
+ } else {
+ XSync(disp, False);
+ ErrPrint("Unable to clear the pixmap\n");
+ }
+
+ return buffer;
+}
+
+static inline int create_gem(struct buffer *buffer)
+{
+ struct gem_data *gem;
+ Display *disp;
+
+ disp = ecore_x_display_get();
+ if (!disp) {
+ ErrPrint("Failed to get display\n");
+ return LB_STATUS_ERROR_IO;
+ }
+
+ gem = (struct gem_data *)buffer->data;
+
+ if (s_info.fd < 0) {
+ gem->data = calloc(1, gem->w * gem->h * gem->depth);
+ if (!gem->data) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ ErrPrint("DRI2(gem) is not supported - Fallback to the S/W Backend\n");
+ return LB_STATUS_SUCCESS;
+ }
+
+ DRI2CreateDrawable(disp, gem->pixmap);
+
+ gem->dri2_buffer = DRI2GetBuffers(disp, gem->pixmap,
+ &gem->w, &gem->h, gem->attachments, gem->count, &gem->buf_count);
+ if (!gem->dri2_buffer || !gem->dri2_buffer->name) {
+ ErrPrint("Failed to get a gem buffer\n");
+ DRI2DestroyDrawable(disp, gem->pixmap);
+ return LB_STATUS_ERROR_FAULT;
+ }
+ /*!
+ * \How can I destroy this?
+ */
+ gem->pixmap_bo = tbm_bo_import(s_info.slp_bufmgr, gem->dri2_buffer->name);
+ if (!gem->pixmap_bo) {
+ ErrPrint("Failed to import BO\n");
+ DRI2DestroyDrawable(disp, gem->pixmap);
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ if (gem->dri2_buffer->pitch != gem->w * gem->depth) {
+ gem->compensate_data = calloc(1, gem->w * gem->h * gem->depth);
+ if (!gem->compensate_data) {
+ ErrPrint("Failed to allocate heap\n");
+ }
+ }
+
+ DbgPrint("dri2_buffer: %p, name: %p, %dx%d, pitch: %d, buf_count: %d, depth: %d, compensate: %p\n",
+ gem->dri2_buffer, gem->dri2_buffer->name, gem->w, gem->h,
+ gem->dri2_buffer->pitch, gem->buf_count, gem->depth, gem->compensate_data);
+
+ return LB_STATUS_SUCCESS;
+}
+
+static inline void *acquire_gem(struct buffer *buffer)
+{
+ struct gem_data *gem;
+
+ if (!buffer) {
+ return NULL;
+ }
+
+ gem = (struct gem_data *)buffer->data;
+ if (s_info.fd < 0) {
+ ErrPrint("GEM is not supported - Use the fake gem buffer\n");
+ } else {
+ if (!gem->pixmap_bo) {
+ ErrPrint("GEM is not created\n");
+ return NULL;
+ }
+
+ if (!gem->data) {
+ tbm_bo_handle handle;
+
+ if (gem->refcnt) {
+ ErrPrint("Already acquired. but the buffer is not valid\n");
+ return NULL;
+ }
+
+ handle = tbm_bo_map(gem->pixmap_bo, TBM_DEVICE_CPU, TBM_OPTION_READ | TBM_OPTION_WRITE);
+ gem->data = handle.ptr;
+ }
+ }
+
+ gem->refcnt++;
+
+ /*!
+ * \note
+ * If there is a compensate canvas buffer,
+ * use it
+ */
+ return gem->compensate_data ? gem->compensate_data : gem->data;
+}
+
+static inline void release_gem(struct buffer *buffer)
+{
+ struct gem_data *gem;
+
+ gem = (struct gem_data *)buffer->data;
+ if (s_info.fd >= 0 && !gem->pixmap_bo) {
+ ErrPrint("GEM is not created\n");
+ return;
+ }
+
+ if (!gem->data) {
+ if (gem->refcnt > 0) {
+ ErrPrint("Reference count is not valid %d\n", gem->refcnt);
+ gem->refcnt = 0;
+ }
+ return;
+ }
+
+ gem->refcnt--;
+ if (gem->refcnt == 0) {
+ if (s_info.fd < 0) {
+ DbgPrint("S/W Gem buffer has no reference\n");
+ } else {
+ /*!
+ * \note
+ * Update the gem buffer using compensate data buffer if it is exists
+ */
+ if (gem->compensate_data) {
+ register int x;
+ register int y;
+ int *gem_pixel;
+ int *pixel;
+ int gap;
+
+ pixel = gem->compensate_data;
+ gem_pixel = gem->data;
+ gap = gem->dri2_buffer->pitch - (gem->w * gem->depth);
+
+ for (y = 0; y < gem->h; y++) {
+ for (x = 0; x < gem->w; x++) {
+ *gem_pixel++ = *pixel++;
+ }
+
+ gem_pixel = (int *)(((char *)gem_pixel) + gap);
+ }
+ }
+
+ if (gem->pixmap_bo) {
+ tbm_bo_unmap(gem->pixmap_bo);
+ }
+
+ gem->data = NULL;
+ }
+ } else if (gem->refcnt < 0) {
+ ErrPrint("Invalid refcnt: %d (reset)\n", gem->refcnt);
+ gem->refcnt = 0;
+ }
+}
+
+static inline int destroy_pixmap(struct buffer *buffer)
+{
+ struct gem_data *gem;
+
+ gem = (struct gem_data *)buffer->data;
+
+ if (gem->pixmap) {
+ Display *disp;
+
+ disp = ecore_x_display_get();
+ if (!disp) {
+ return LB_STATUS_ERROR_IO;
+ }
+
+ DbgPrint("pixmap %lu\n", gem->pixmap);
+ XFreePixmap(disp, gem->pixmap);
+ }
+
+ buffer->state = DESTROYED;
+ DbgFree(buffer);
+ return LB_STATUS_SUCCESS;
+}
+
+static inline int destroy_gem(struct buffer *buffer)
+{
+ struct gem_data *gem;
+
+ if (!buffer) {
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ /*!
+ * Forcely release the acquire_buffer.
+ */
+ gem = (struct gem_data *)buffer->data;
+ if (!gem) {
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ if (s_info.fd >= 0) {
+ if (gem->compensate_data) {
+ DbgPrint("Release compensate buffer %p\n", gem->compensate_data);
+ DbgFree(gem->compensate_data);
+ gem->compensate_data = NULL;
+ }
+
+ if (gem->pixmap_bo) {
+ DbgPrint("unref pixmap bo\n");
+ tbm_bo_unref(gem->pixmap_bo);
+ gem->pixmap_bo = NULL;
+
+ DRI2DestroyDrawable(ecore_x_display_get(), gem->pixmap);
+ }
+ } else if (gem->data) {
+ DbgPrint("Release fake gem buffer\n");
+ DbgFree(gem->data);
+ gem->data = NULL;
+ }
+
+ return LB_STATUS_SUCCESS;
+}
+
+static inline int load_file_buffer(struct buffer_info *info)
+{
+ struct buffer *buffer;
+ double timestamp;
+ int size;
+ char *new_id;
+ int len;
+
+ len = strlen(IMAGE_PATH) + 40;
+ new_id = malloc(len);
+ if (!new_id) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ timestamp = util_timestamp();
+ snprintf(new_id, len, SCHEMA_FILE "%s%lf", IMAGE_PATH, timestamp);
+
+ size = sizeof(*buffer) + info->w * info->h * info->pixel_size;
+ if (!size) {
+ ErrPrint("Canvas buffer size is ZERO\n");
+ DbgFree(new_id);
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ buffer = calloc(1, size);
+ if (!buffer) {
+ ErrPrint("Failed to allocate buffer\n");
+ DbgFree(new_id);
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ buffer->type = BUFFER_TYPE_FILE;
+ buffer->refcnt = 0;
+ buffer->state = CREATED;
+ buffer->info = info;
+
+ DbgFree(info->id);
+ info->id = new_id;
+ info->buffer = buffer;
+ info->is_loaded = 1;
+
+ DbgPrint("FILE type %d created\n", size);
+ return LB_STATUS_SUCCESS;
+}
+
+static inline int load_shm_buffer(struct buffer_info *info)
+{
+ int id;
+ int size;
+ struct buffer *buffer; /* Just for getting a size */
+ char *new_id;
+ int len;
+
+ size = info->w * info->h * info->pixel_size;
+ if (!size) {
+ ErrPrint("Invalid buffer size\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ id = shmget(IPC_PRIVATE, size + sizeof(*buffer), IPC_CREAT | 0666);
+ if (id < 0) {
+ ErrPrint("shmget: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ buffer = shmat(id, NULL, 0);
+ if (buffer == (void *)-1) {
+ ErrPrint("%s shmat: %s\n", info->id, strerror(errno));
+
+ if (shmctl(id, IPC_RMID, 0) < 0) {
+ ErrPrint("%s shmctl: %s\n", info->id, strerror(errno));
+ }
+
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ buffer->type = BUFFER_TYPE_SHM;
+ buffer->refcnt = id;
+ buffer->state = CREATED; /*!< Needless */
+ buffer->info = (void *)size; /*!< Use this field to indicates the size of SHM */
+
+ len = strlen(SCHEMA_SHM) + 30; /* strlen("shm://") + 30 */
+
+ new_id = malloc(len);
+ if (!new_id) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ if (shmdt(buffer) < 0) {
+ ErrPrint("shmdt: %s\n", strerror(errno));
+ }
+
+ if (shmctl(id, IPC_RMID, 0) < 0) {
+ ErrPrint("shmctl: %s\n", strerror(errno));
+ }
+
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ snprintf(new_id, len, SCHEMA_SHM "%d", id);
+
+ DbgFree(info->id);
+ info->id = new_id;
+ info->buffer = buffer;
+ info->is_loaded = 1;
+ return LB_STATUS_SUCCESS;
+}
+
+static inline int load_pixmap_buffer(struct buffer_info *info)
+{
+ struct buffer *buffer;
+ struct gem_data *gem;
+ char *new_id;
+ int len;
+
+ /*!
+ * \NOTE
+ * Before call the buffer_handler_pixmap_ref function,
+ * You should make sure that the is_loaded value is toggled (1)
+ * Or the buffer_handler_pixmap_ref function will return NULL
+ */
+ info->is_loaded = 1;
+
+ if (info->buffer) {
+ DbgPrint("Buffer is already exists, but override it with new one\n");
+ }
+
+ buffer = buffer_handler_pixmap_ref(info);
+ if (!buffer) {
+ DbgPrint("Failed to make a reference of a pixmap\n");
+ info->is_loaded = 0;
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ len = strlen(SCHEMA_PIXMAP) + 30; /* strlen("pixmap://") + 30 */
+ new_id = malloc(len);
+ if (!new_id) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ info->is_loaded = 0;
+ buffer_handler_pixmap_unref(buffer);
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ DbgFree(info->id);
+ info->id = new_id;
+
+ gem = (struct gem_data *)buffer->data;
+
+ snprintf(info->id, len, SCHEMA_PIXMAP "%d:%d", (int)gem->pixmap, info->pixel_size);
+ DbgPrint("Loaded pixmap(info->id): %s\n", info->id);
+ return LB_STATUS_SUCCESS;
+}
+
+EAPI int buffer_handler_load(struct buffer_info *info)
+{
+ int ret;
+
+ if (!info) {
+ ErrPrint("buffer handler is nil\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (info->is_loaded) {
+ DbgPrint("Buffer is already loaded\n");
+ return LB_STATUS_SUCCESS;
+ }
+
+ switch (info->type) {
+ case BUFFER_TYPE_FILE:
+ ret = load_file_buffer(info);
+ (void)create_lock_file(info);
+ break;
+ case BUFFER_TYPE_SHM:
+ ret = load_shm_buffer(info);
+ (void)create_lock_file(info);
+ break;
+ case BUFFER_TYPE_PIXMAP:
+ ret = load_pixmap_buffer(info);
+ break;
+ default:
+ ErrPrint("Invalid buffer\n");
+ ret = LB_STATUS_ERROR_INVALID;
+ break;
+ }
+
+ return ret;
+}
+
+static inline int unload_file_buffer(struct buffer_info *info)
+{
+ const char *path;
+ char *new_id;
+
+ new_id = strdup(SCHEMA_FILE "/tmp/.live.undefined");
+ if (!new_id) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ DbgFree(info->buffer);
+ info->buffer = NULL;
+
+ path = util_uri_to_path(info->id);
+ if (path && unlink(path) < 0) {
+ ErrPrint("unlink: %s\n", strerror(errno));
+ }
+
+ DbgFree(info->id);
+ info->id = new_id;
+ return LB_STATUS_SUCCESS;
+}
+
+static inline int unload_shm_buffer(struct buffer_info *info)
+{
+ int id;
+ char *new_id;
+
+ new_id = strdup(SCHEMA_SHM "-1");
+ if (!new_id) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ if (sscanf(info->id, SCHEMA_SHM "%d", &id) != 1) {
+ ErrPrint("%s Invalid ID\n", info->id);
+ DbgFree(new_id);
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (id < 0) {
+ ErrPrint("(%s) Invalid id: %d\n", info->id, id);
+ DbgFree(new_id);
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (shmdt(info->buffer) < 0) {
+ ErrPrint("Detach shm: %s\n", strerror(errno));
+ }
+
+ if (shmctl(id, IPC_RMID, 0) < 0) {
+ ErrPrint("Remove shm: %s\n", strerror(errno));
+ }
+
+ info->buffer = NULL;
+
+ DbgFree(info->id);
+ info->id = new_id;
+ return LB_STATUS_SUCCESS;
+}
+
+static inline int unload_pixmap_buffer(struct buffer_info *info)
+{
+ int id;
+ char *new_id;
+ int pixels;
+
+ new_id = strdup(SCHEMA_PIXMAP "0:0");
+ if (!new_id) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ if (sscanf(info->id, SCHEMA_PIXMAP "%d:%d", &id, &pixels) != 2) {
+ ErrPrint("Invalid ID (%s)\n", info->id);
+ DbgFree(new_id);
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (id == 0) {
+ ErrPrint("(%s) Invalid id: %d\n", info->id, id);
+ DbgFree(new_id);
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ /*!
+ * Decrease the reference counter.
+ */
+ buffer_handler_pixmap_unref(info->buffer);
+
+ /*!
+ * \note
+ * Just clear the info->buffer.
+ * It will be reallocated again.
+ */
+ info->buffer = NULL;
+
+ DbgFree(info->id);
+ info->id = new_id;
+ return LB_STATUS_SUCCESS;
+}
+
+EAPI int buffer_handler_unload(struct buffer_info *info)
+{
+ int ret;
+
+ if (!info) {
+ ErrPrint("buffer handler is NIL\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (!info->is_loaded) {
+ ErrPrint("Buffer is not loaded\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ switch (info->type) {
+ case BUFFER_TYPE_FILE:
+ (void)destroy_lock_file(info);
+ ret = unload_file_buffer(info);
+ break;
+ case BUFFER_TYPE_SHM:
+ (void)destroy_lock_file(info);
+ ret = unload_shm_buffer(info);
+ break;
+ case BUFFER_TYPE_PIXMAP:
+ ret = unload_pixmap_buffer(info);
+ break;
+ default:
+ ErrPrint("Invalid buffer\n");
+ ret = LB_STATUS_ERROR_INVALID;
+ break;
+ }
+
+ if (ret == 0) {
+ info->is_loaded = 0;
+ }
+
+ return ret;
+}
+
+EAPI const char *buffer_handler_id(const struct buffer_info *info)
+{
+ return info ? info->id : "";
+}
+
+EAPI enum buffer_type buffer_handler_type(const struct buffer_info *info)
+{
+ return info ? info->type : BUFFER_TYPE_ERROR;
+}
+
+EAPI void *buffer_handler_fb(struct buffer_info *info)
+{
+ struct buffer *buffer;
+
+ if (!info) {
+ return NULL;
+ }
+
+ buffer = info->buffer;
+
+ if (info->type == BUFFER_TYPE_PIXMAP) {
+ void *canvas;
+ int ret;
+
+ /*!
+ * \note
+ * For getting the buffer address of gem.
+ */
+ canvas = buffer_handler_pixmap_acquire_buffer(info);
+ ret = buffer_handler_pixmap_release_buffer(canvas);
+ if (ret < 0) {
+ ErrPrint("Failed to release buffer: %d\n", ret);
+ }
+ return canvas;
+ }
+
+ return buffer->data;
+}
+
+EAPI int buffer_handler_pixmap(const struct buffer_info *info)
+{
+ struct buffer *buf;
+ struct gem_data *gem;
+
+ if (!info) {
+ ErrPrint("Inavlid buffer handler\n");
+ return 0;
+ }
+
+ if (info->type != BUFFER_TYPE_PIXMAP) {
+ ErrPrint("Invalid buffer type\n");
+ return 0;
+ }
+
+ buf = (struct buffer *)info->buffer;
+ if (!buf) {
+ ErrPrint("Invalid buffer data\n");
+ return 0;
+ }
+
+ gem = (struct gem_data *)buf->data;
+ return gem->pixmap;
+}
+
+EAPI void *buffer_handler_pixmap_acquire_buffer(struct buffer_info *info)
+{
+ struct buffer *buffer;
+
+ if (!info || !info->is_loaded) {
+ ErrPrint("Buffer is not loaded\n");
+ return NULL;
+ }
+
+ buffer = buffer_handler_pixmap_ref(info);
+ if (!buffer) {
+ return NULL;
+ }
+
+ return acquire_gem(buffer);
+}
+
+EAPI void *buffer_handler_pixmap_buffer(struct buffer_info *info)
+{
+ struct buffer *buffer;
+ struct gem_data *gem;
+
+ if (!info) {
+ return NULL;
+ }
+
+ if (!info->is_loaded) {
+ ErrPrint("Buffer is not loaded\n");
+ return NULL;
+ }
+
+ buffer = info->buffer;
+ if (!buffer) {
+ return NULL;
+ }
+
+ gem = (struct gem_data *)buffer->data;
+ return gem->compensate_data ? gem->compensate_data : gem->data;
+}
+
+/*!
+ * \return "buffer" object (Not the buffer_info)
+ */
+EAPI void *buffer_handler_pixmap_ref(struct buffer_info *info)
+{
+ struct buffer *buffer;
+
+ if (!info->is_loaded) {
+ ErrPrint("Buffer is not loaded\n");
+ return NULL;
+ }
+
+ if (info->type != BUFFER_TYPE_PIXMAP) {
+ ErrPrint("Buffer type is not matched\n");
+ return NULL;
+ }
+
+ buffer = info->buffer;
+ if (!buffer) {
+ int need_gem = 1;
+
+ buffer = create_pixmap(info);
+ if (!buffer) {
+ ErrPrint("Failed to create a pixmap\n");
+ return NULL;
+ }
+
+ info->buffer = buffer;
+
+ if (info->inst) {
+ struct pkg_info *pkg;
+
+ if (instance_lb_buffer(info->inst) == info) {
+ pkg = instance_package(info->inst);
+ if (package_lb_type(pkg) == LB_TYPE_BUFFER) {
+ need_gem = 0;
+ }
+ } else if (instance_pd_buffer(info->inst) == info) {
+ pkg = instance_package(info->inst);
+ if (package_pd_type(pkg) == PD_TYPE_BUFFER) {
+ need_gem = 0;
+ }
+ }
+ }
+
+ if (need_gem) {
+ create_gem(buffer);
+ }
+
+ } else if (buffer->state != CREATED || buffer->type != BUFFER_TYPE_PIXMAP) {
+ ErrPrint("Invalid buffer\n");
+ return NULL;
+ } else if (buffer->refcnt > 0) {
+ buffer->refcnt++;
+ return buffer;
+ }
+
+ s_info.pixmap_list = eina_list_append(s_info.pixmap_list, buffer);
+ return buffer;
+}
+
+/*!
+ * \return "buffer"
+ */
+EAPI void *buffer_handler_pixmap_find(int pixmap)
+{
+ struct buffer *buffer;
+ struct gem_data *gem;
+ Eina_List *l;
+ Eina_List *n;
+
+ if (pixmap == 0) {
+ return NULL;
+ }
+
+ EINA_LIST_FOREACH_SAFE(s_info.pixmap_list, l, n, buffer) {
+ if (!buffer || buffer->state != CREATED || buffer->type != BUFFER_TYPE_PIXMAP) {
+ s_info.pixmap_list = eina_list_remove(s_info.pixmap_list, buffer);
+ DbgPrint("Invalid buffer (List Removed: %p)\n", buffer);
+ continue;
+ }
+
+ gem = (struct gem_data *)buffer->data;
+ if (gem->pixmap == pixmap) {
+ return buffer;
+ }
+ }
+
+ return NULL;
+}
+
+EAPI int buffer_handler_pixmap_release_buffer(void *canvas)
+{
+ struct buffer *buffer;
+ struct gem_data *gem;
+ Eina_List *l;
+ Eina_List *n;
+ void *_ptr;
+
+ if (!canvas) {
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ EINA_LIST_FOREACH_SAFE(s_info.pixmap_list, l, n, buffer) {
+ if (!buffer || buffer->state != CREATED || buffer->type != BUFFER_TYPE_PIXMAP) {
+ s_info.pixmap_list = eina_list_remove(s_info.pixmap_list, buffer);
+ continue;
+ }
+
+ gem = (struct gem_data *)buffer->data;
+ _ptr = gem->compensate_data ? gem->compensate_data : gem->data;
+
+ if (!_ptr) {
+ continue;
+ }
+
+ if (_ptr == canvas) {
+ release_gem(buffer);
+ buffer_handler_pixmap_unref(buffer);
+ return LB_STATUS_SUCCESS;
+ }
+ }
+
+ return LB_STATUS_ERROR_NOT_EXIST;
+}
+
+/*!
+ * \note
+ *
+ * \return Return NULL if the buffer is in still uses.
+ * Return buffer_ptr if it needs to destroy
+ */
+EAPI int buffer_handler_pixmap_unref(void *buffer_ptr)
+{
+ struct buffer *buffer = buffer_ptr;
+ struct buffer_info *info;
+
+ buffer->refcnt--;
+ if (buffer->refcnt > 0) {
+ return LB_STATUS_SUCCESS; /* Return NULL means, gem buffer still in use */
+ }
+
+ s_info.pixmap_list = eina_list_remove(s_info.pixmap_list, buffer);
+
+ info = buffer->info;
+
+ if (destroy_gem(buffer) < 0) {
+ ErrPrint("Failed to destroy gem buffer\n");
+ }
+
+ if (destroy_pixmap(buffer) < 0) {
+ ErrPrint("Failed to destroy pixmap\n");
+ }
+
+ if (info && info->buffer == buffer) {
+ info->buffer = NULL;
+ }
+
+ return LB_STATUS_SUCCESS;
+}
+
+EAPI int buffer_handler_is_loaded(const struct buffer_info *info)
+{
+ return info ? info->is_loaded : 0;
+}
+
+EAPI void buffer_handler_update_size(struct buffer_info *info, int w, int h)
+{
+ if (!info) {
+ return;
+ }
+
+ info->w = w;
+ info->h = h;
+}
+
+EAPI int buffer_handler_resize(struct buffer_info *info, int w, int h)
+{
+ int ret;
+
+ if (!info) {
+ ErrPrint("Invalid handler\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (info->w == w && info->h == h) {
+ DbgPrint("No changes\n");
+ return LB_STATUS_SUCCESS;
+ }
+
+ buffer_handler_update_size(info, w, h);
+
+ if (!info->is_loaded) {
+ DbgPrint("Buffer size is updated[%dx%d]\n", w, h);
+ return LB_STATUS_SUCCESS;
+ }
+
+ ret = buffer_handler_unload(info);
+ if (ret < 0) {
+ ErrPrint("Unload: %d\n", ret);
+ }
+
+ ret = buffer_handler_load(info);
+ if (ret < 0) {
+ ErrPrint("Load: %d\n", ret);
+ }
+
+ return LB_STATUS_SUCCESS;
+}
+
+EAPI int buffer_handler_get_size(struct buffer_info *info, int *w, int *h)
+{
+ if (!info) {
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (w) {
+ *w = info->w;
+ }
+ if (h) {
+ *h = info->h;
+ }
+
+ return LB_STATUS_SUCCESS;
+}
+
+EAPI struct inst_info *buffer_handler_instance(struct buffer_info *info)
+{
+ return info->inst;
+}
+
+/*!
+ * \note
+ * Only for used S/W Backend
+ */
+static inline int sync_for_pixmap(struct buffer *buffer)
+{
+ XShmSegmentInfo si;
+ XImage *xim;
+ GC gc;
+ Display *disp;
+ struct gem_data *gem;
+ Screen *screen;
+ Visual *visual;
+
+ if (buffer->state != CREATED) {
+ ErrPrint("Invalid state of a FB\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (buffer->type != BUFFER_TYPE_PIXMAP) {
+ ErrPrint("Invalid buffer\n");
+ return LB_STATUS_SUCCESS;
+ }
+
+ disp = ecore_x_display_get();
+ if (!disp) {
+ ErrPrint("Failed to get a display\n");
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ gem = (struct gem_data *)buffer->data;
+ if (gem->w == 0 || gem->h == 0) {
+ DbgPrint("Nothing can be sync\n");
+ return LB_STATUS_SUCCESS;
+ }
+
+ si.shmid = shmget(IPC_PRIVATE, gem->w * gem->h * gem->depth, IPC_CREAT | 0666);
+ if (si.shmid < 0) {
+ ErrPrint("shmget: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ si.readOnly = False;
+ si.shmaddr = shmat(si.shmid, NULL, 0);
+ if (si.shmaddr == (void *)-1) {
+ if (shmctl(si.shmid, IPC_RMID, 0) < 0) {
+ ErrPrint("shmctl: %s\n", strerror(errno));
+ }
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ screen = DefaultScreenOfDisplay(disp);
+ visual = DefaultVisualOfScreen(screen);
+ /*!
+ * \NOTE
+ * XCreatePixmap can only uses 24 bits depth only.
+ */
+ xim = XShmCreateImage(disp, visual, (gem->depth << 3), ZPixmap, NULL, &si, gem->w, gem->h);
+ if (xim == NULL) {
+ if (shmdt(si.shmaddr) < 0) {
+ ErrPrint("shmdt: %s\n", strerror(errno));
+ }
+
+ if (shmctl(si.shmid, IPC_RMID, 0) < 0) {
+ ErrPrint("shmctl: %s\n", strerror(errno));
+ }
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ xim->data = si.shmaddr;
+ XShmAttach(disp, &si);
+ XSync(disp, False);
+
+ gc = XCreateGC(disp, gem->pixmap, 0, NULL);
+ if (!gc) {
+ XShmDetach(disp, &si);
+ XDestroyImage(xim);
+
+ if (shmdt(si.shmaddr) < 0) {
+ ErrPrint("shmdt: %s\n", strerror(errno));
+ }
+
+ if (shmctl(si.shmid, IPC_RMID, 0) < 0) {
+ ErrPrint("shmctl: %s\n", strerror(errno));
+ }
+
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ memcpy(xim->data, gem->data, gem->w * gem->h * gem->depth);
+
+ /*!
+ * \note Do not send the event.
+ * Instead of X event, master will send the updated event to the viewer
+ */
+ XShmPutImage(disp, gem->pixmap, gc, xim, 0, 0, 0, 0, gem->w, gem->h, False);
+ XSync(disp, False);
+
+ XFreeGC(disp, gc);
+ XShmDetach(disp, &si);
+ XDestroyImage(xim);
+
+ if (shmdt(si.shmaddr) < 0) {
+ ErrPrint("shmdt: %s\n", strerror(errno));
+ }
+
+ if (shmctl(si.shmid, IPC_RMID, 0) < 0) {
+ ErrPrint("shmctl: %s\n", strerror(errno));
+ }
+
+ return LB_STATUS_SUCCESS;
+}
+
+EAPI void buffer_handler_flush(struct buffer_info *info)
+{
+ int fd;
+ int size;
+ struct buffer *buffer;
+
+ if (!info || !info->buffer) {
+ return;
+ }
+
+ buffer = info->buffer;
+
+ if (buffer->type == BUFFER_TYPE_PIXMAP) {
+ if (s_info.fd > 0) {
+ //return;
+ //PERF_INIT();
+ //PERF_BEGIN();
+ XRectangle rect;
+ XserverRegion region;
+
+ rect.x = 0;
+ rect.y = 0;
+ rect.width = info->w;
+ rect.height = info->h;
+
+ region = XFixesCreateRegion(ecore_x_display_get(), &rect, 1);
+ XDamageAdd(ecore_x_display_get(), buffer_handler_pixmap(info), region);
+ XFixesDestroyRegion(ecore_x_display_get(), region);
+ XFlush(ecore_x_display_get());
+ //PERF_MARK("XFlush");
+ } else {
+ if (sync_for_pixmap(buffer) < 0) {
+ ErrPrint("Failed to sync via S/W Backend\n");
+ }
+ }
+ } else if (buffer->type == BUFFER_TYPE_FILE) {
+ fd = open(util_uri_to_path(info->id), O_WRONLY | O_CREAT, 0644);
+ if (fd < 0) {
+ ErrPrint("%s open falied: %s\n", util_uri_to_path(info->id), strerror(errno));
+ return;
+ }
+
+ size = info->w * info->h * info->pixel_size;
+ do_buffer_lock(info);
+ if (write(fd, info->buffer, size) != size) {
+ ErrPrint("Write is not completed: %s\n", strerror(errno));
+ }
+ do_buffer_unlock(info);
+
+ if (close(fd) < 0) {
+ ErrPrint("close: %s\n", strerror(errno));
+ }
+ } else {
+ DbgPrint("Flush nothing\n");
+ }
+}
+
+HAPI int buffer_handler_init(void)
+{
+ int dri2Major, dri2Minor;
+ char *driverName, *deviceName;
+ drm_magic_t magic;
+
+ if (!DRI2QueryExtension(ecore_x_display_get(), &s_info.evt_base, &s_info.err_base)) {
+ ErrPrint("DRI2 is not supported\n");
+ return LB_STATUS_SUCCESS;
+ }
+
+ if (!DRI2QueryVersion(ecore_x_display_get(), &dri2Major, &dri2Minor)) {
+ ErrPrint("DRI2 is not supported\n");
+ s_info.evt_base = 0;
+ s_info.err_base = 0;
+ return LB_STATUS_SUCCESS;
+ }
+
+ if (!DRI2Connect(ecore_x_display_get(), DefaultRootWindow(ecore_x_display_get()), &driverName, &deviceName)) {
+ ErrPrint("DRI2 is not supported\n");
+ s_info.evt_base = 0;
+ s_info.err_base = 0;
+ return LB_STATUS_SUCCESS;
+ }
+
+ if (USE_SW_BACKEND) {
+ DbgPrint("Fallback to the S/W Backend\n");
+ s_info.evt_base = 0;
+ s_info.err_base = 0;
+ DbgFree(deviceName);
+ DbgFree(driverName);
+ return LB_STATUS_SUCCESS;
+ }
+
+ s_info.fd = open(deviceName, O_RDWR);
+ DbgFree(deviceName);
+ DbgFree(driverName);
+ if (s_info.fd < 0) {
+ ErrPrint("Failed to open a drm device: (%s)\n", strerror(errno));
+ s_info.evt_base = 0;
+ s_info.err_base = 0;
+ return LB_STATUS_SUCCESS;
+ }
+
+ drmGetMagic(s_info.fd, &magic);
+ DbgPrint("DRM Magic: 0x%X\n", magic);
+ if (!DRI2Authenticate(ecore_x_display_get(), DefaultRootWindow(ecore_x_display_get()), (unsigned int)magic)) {
+ ErrPrint("Failed to do authenticate for DRI2\n");
+ if (close(s_info.fd) < 0) {
+ ErrPrint("close: %s\n", strerror(errno));
+ }
+ s_info.fd = -1;
+ s_info.evt_base = 0;
+ s_info.err_base = 0;
+ return LB_STATUS_SUCCESS;
+ }
+
+ s_info.slp_bufmgr = tbm_bufmgr_init(s_info.fd);
+ if (!s_info.slp_bufmgr) {
+ ErrPrint("Failed to init bufmgr\n");
+ if (close(s_info.fd) < 0) {
+ ErrPrint("close: %s\n", strerror(errno));
+ }
+ s_info.fd = -1;
+ s_info.evt_base = 0;
+ s_info.err_base = 0;
+ return LB_STATUS_SUCCESS;
+ }
+
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI int buffer_handler_fini(void)
+{
+ if (s_info.fd >= 0) {
+ if (close(s_info.fd) < 0) {
+ ErrPrint("close: %s\n", strerror(errno));
+ }
+ s_info.fd = -1;
+ }
+
+ if (s_info.slp_bufmgr) {
+ tbm_bufmgr_deinit(s_info.slp_bufmgr);
+ s_info.slp_bufmgr = NULL;
+ }
+
+ return LB_STATUS_SUCCESS;
+}
+
+static inline struct buffer *raw_open_file(const char *filename)
+{
+ struct buffer *buffer;
+ int fd;
+ off_t off;
+ int ret;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ ErrPrint("open: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ off = lseek(fd, 0L, SEEK_END);
+ if (off == (off_t)-1) {
+ ErrPrint("lseek: %s\n", strerror(errno));
+
+ if (close(fd) < 0) {
+ ErrPrint("close: %s\n", strerror(errno));
+ }
+
+ return NULL;
+ }
+
+ if (lseek(fd, 0L, SEEK_SET) == (off_t)-1) {
+ ErrPrint("lseek: %s\n", strerror(errno));
+
+ if (close(fd) < 0) {
+ ErrPrint("close: %s\n", strerror(errno));
+ }
+
+ return NULL;
+ }
+
+ buffer = calloc(1, sizeof(*buffer) + off);
+ if (!buffer) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+
+ if (close(fd) < 0) {
+ ErrPrint("close: %s\n", strerror(errno));
+ }
+
+ return NULL;
+ }
+
+ buffer->state = CREATED;
+ buffer->type = BUFFER_TYPE_FILE;
+ buffer->refcnt = 0;
+ buffer->info = (void *)off;
+
+ ret = read(fd, buffer->data, off);
+ if (ret < 0) {
+ ErrPrint("read: %s\n", strerror(errno));
+ DbgFree(buffer);
+
+ if (close(fd) < 0) {
+ ErrPrint("close: %s\n", strerror(errno));
+ }
+
+ return NULL;
+ }
+
+ if (close(fd) < 0) {
+ ErrPrint("close: %s\n", strerror(errno));
+ }
+
+ return buffer;
+}
+
+static inline int raw_close_file(struct buffer *buffer)
+{
+ DbgFree(buffer);
+ return 0;
+}
+
+static inline struct buffer *raw_open_shm(int shm)
+{
+ struct buffer *buffer;
+
+ buffer = (struct buffer *)shmat(shm, NULL, SHM_RDONLY);
+ if (buffer == (struct buffer *)-1) {
+ ErrPrint("shmat: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ return buffer;
+}
+
+static inline int raw_close_shm(struct buffer *buffer)
+{
+ int ret;
+
+ ret = shmdt(buffer);
+ if (ret < 0) {
+ ErrPrint("shmdt: %s\n", strerror(errno));
+ }
+
+ return ret;
+}
+
+static inline struct buffer *raw_open_pixmap(unsigned int pixmap)
+{
+ struct buffer *buffer;
+
+ buffer = calloc(1, sizeof(*buffer) + DEFAULT_PIXELS);
+ if (!buffer) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ buffer->state = CREATED;
+ buffer->type = BUFFER_TYPE_PIXMAP;
+
+ return buffer;
+}
+
+static inline int raw_close_pixmap(struct buffer *buffer)
+{
+ DbgFree(buffer);
+ return 0;
+}
+
+EAPI void *buffer_handler_raw_data(struct buffer *buffer)
+{
+ if (!buffer || buffer->state != CREATED) {
+ return NULL;
+ }
+
+ return buffer->data;
+}
+
+EAPI int buffer_handler_raw_size(struct buffer *buffer)
+{
+ if (!buffer || buffer->state != CREATED) {
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ return (int)buffer->info;
+}
+
+EAPI struct buffer *buffer_handler_raw_open(enum buffer_type buffer_type, void *resource)
+{
+ struct buffer *handle;
+
+ switch (buffer_type) {
+ case BUFFER_TYPE_SHM:
+ handle = raw_open_shm((int)resource);
+ break;
+ case BUFFER_TYPE_FILE:
+ handle = raw_open_file(resource);
+ break;
+ case BUFFER_TYPE_PIXMAP:
+ handle = raw_open_pixmap((unsigned int)resource);
+ break;
+ default:
+ handle = NULL;
+ break;
+ }
+
+ return handle;
+}
+
+EAPI int buffer_handler_raw_close(struct buffer *buffer)
+{
+ int ret;
+
+ switch (buffer->type) {
+ case BUFFER_TYPE_SHM:
+ ret = raw_close_shm(buffer);
+ break;
+ case BUFFER_TYPE_FILE:
+ ret = raw_close_file(buffer);
+ break;
+ case BUFFER_TYPE_PIXMAP:
+ ret = raw_close_pixmap(buffer);
+ break;
+ default:
+ ret = LB_STATUS_ERROR_INVALID;
+ break;
+ }
+
+ return ret;
+}
+
+EAPI int buffer_handler_lock(struct buffer_info *buffer)
+{
+ if (buffer->type == BUFFER_TYPE_PIXMAP) {
+ return LB_STATUS_SUCCESS;
+ }
+
+ if (buffer->type == BUFFER_TYPE_FILE) {
+ return LB_STATUS_SUCCESS;
+ }
+
+ return do_buffer_lock(buffer);
+}
+
+EAPI int buffer_handler_unlock(struct buffer_info *buffer)
+{
+ if (buffer->type == BUFFER_TYPE_PIXMAP) {
+ return LB_STATUS_SUCCESS;
+ }
+
+ if (buffer->type == BUFFER_TYPE_FILE) {
+ return LB_STATUS_SUCCESS;
+ }
+
+ return do_buffer_unlock(buffer);
+}
+
+/*!
+ * \note
+ * Only can be used by master.
+ * Plugin cannot access the user data
+ */
+
+HAPI int buffer_handler_set_data(struct buffer_info *buffer, void *data)
+{
+ if (!buffer) {
+ ErrPrint("Invalid handle\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ buffer->data = data;
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI void *buffer_handler_data(struct buffer_info *buffer)
+{
+ if (!buffer) {
+ ErrPrint("Invalid handle\n");
+ return NULL;
+ }
+
+ return buffer->data;
+}
+
+HAPI int buffer_handler_destroy(struct buffer_info *info)
+{
+ Eina_List *l;
+ struct buffer *buffer;
+
+ if (!info) {
+ DbgPrint("Buffer is not created yet. info is NIL\n");
+ return LB_STATUS_SUCCESS;
+ }
+
+ EINA_LIST_FOREACH(s_info.pixmap_list, l, buffer) {
+ if (buffer->info == info) {
+ buffer->info = NULL;
+ }
+ }
+
+ buffer_handler_unload(info);
+ DbgFree(info->id);
+ DbgFree(info);
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI struct buffer_info *buffer_handler_create(struct inst_info *inst, enum buffer_type type, int w, int h, int pixel_size)
+{
+ struct buffer_info *info;
+
+ info = malloc(sizeof(*info));
+ if (!info) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ switch (type) {
+ case BUFFER_TYPE_SHM:
+ if (pixel_size != DEFAULT_PIXELS) {
+ DbgPrint("SHM only supportes %d bytes pixels (requested: %d)\n", DEFAULT_PIXELS, pixel_size);
+ pixel_size = DEFAULT_PIXELS;
+ }
+
+ info->id = strdup(SCHEMA_SHM "-1");
+ if (!info->id) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(info);
+ return NULL;
+ }
+ break;
+ case BUFFER_TYPE_FILE:
+ if (pixel_size != DEFAULT_PIXELS) {
+ DbgPrint("FILE only supportes %d bytes pixels (requested: %d)\n", DEFAULT_PIXELS, pixel_size);
+ pixel_size = DEFAULT_PIXELS;
+ }
+
+ info->id = strdup(SCHEMA_FILE "/tmp/.live.undefined");
+ if (!info->id) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(info);
+ return NULL;
+ }
+ break;
+ case BUFFER_TYPE_PIXMAP:
+ info->id = strdup(SCHEMA_PIXMAP "0:0");
+ if (!info->id) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(info);
+ return NULL;
+ }
+ break;
+ default:
+ ErrPrint("Invalid type\n");
+ DbgFree(info);
+ return NULL;
+ }
+
+ info->lock = NULL;
+ info->lock_fd = -1;
+ info->w = w;
+ info->h = h;
+ info->pixel_size = pixel_size;
+ info->type = type;
+ info->is_loaded = 0;
+ info->inst = inst;
+ info->buffer = NULL;
+ info->data = NULL;
+
+ return info;
+}
+
+/* End of a file */
diff --git a/src/buffer_handler_wayland.c b/src/buffer_handler_wayland.c
new file mode 100644
index 0000000..947e1b4
--- /dev/null
+++ b/src/buffer_handler_wayland.c
@@ -0,0 +1,921 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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 <stdio.h>
+#include <unistd.h> /* access */
+#include <sys/mman.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/shm.h>
+#include <sys/ipc.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <Ecore.h>
+
+#include <dlog.h>
+#include <packet.h>
+#include <livebox-errno.h>
+
+#include "debug.h"
+#include "conf.h"
+#include "util.h"
+#include "instance.h"
+#include "package.h"
+#include "client_life.h"
+#include "client_rpc.h"
+#include "buffer_handler.h"
+#include "script_handler.h" // Reverse dependency. must has to be broken
+
+struct buffer {
+ enum {
+ CREATED = 0x00beef00,
+ DESTROYED = 0x00dead00
+ } state;
+ enum buffer_type type;
+ int refcnt;
+ void *info;
+ char data[];
+};
+
+struct buffer_info
+{
+ void *buffer;
+ char *id;
+ char *lock;
+ int lock_fd;
+
+ enum buffer_type type;
+
+ int w;
+ int h;
+ int pixel_size;
+ int is_loaded;
+
+ struct inst_info *inst;
+ void *data;
+};
+
+static int destroy_lock_file(struct buffer_info *info)
+{
+ if (!info->inst) {
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (!info->lock) {
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (close(info->lock_fd) < 0) {
+ ErrPrint("close: %s\n", strerror(errno));
+ }
+ info->lock_fd = -1;
+
+ if (unlink(info->lock) < 0) {
+ ErrPrint("unlink: %s\n", strerror(errno));
+ }
+
+ DbgFree(info->lock);
+ info->lock = NULL;
+ return LB_STATUS_SUCCESS;
+}
+
+static int create_lock_file(struct buffer_info *info)
+{
+ const char *id;
+ int len;
+ char *file;
+ char target[3] = "pd";
+
+ if (!info->inst) {
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ id = instance_id(info->inst);
+ if (!id) {
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ len = strlen(id);
+ file = malloc(len + 20);
+ if (!file) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ if (script_handler_buffer_info(instance_pd_script(info->inst)) != info && instance_pd_buffer(info->inst) != info) {
+ target[0] = 'l';
+ target[1] = 'b';
+ /* target[2] = '\0'; // We already have this ;) */
+ }
+
+ snprintf(file, len + 20, "%s.%s.lck", util_uri_to_path(id), target);
+ info->lock_fd = open(file, O_WRONLY|O_CREAT, 0644);
+ if (info->lock_fd < 0) {
+ ErrPrint("open: %s\n", strerror(errno));
+ DbgFree(file);
+ return LB_STATUS_ERROR_IO;
+ }
+
+ info->lock = file;
+ return LB_STATUS_SUCCESS;
+}
+
+static int do_buffer_lock(struct buffer_info *buffer)
+{
+ struct flock flock;
+ int ret;
+
+ if (buffer->lock_fd < 0) {
+ return LB_STATUS_SUCCESS;
+ }
+
+ flock.l_type = F_WRLCK;
+ flock.l_whence = SEEK_SET;
+ flock.l_start = 0;
+ flock.l_len = 0;
+ flock.l_pid = getpid();
+
+ do {
+ ret = fcntl(buffer->lock_fd, F_SETLKW, &flock);
+ if (ret < 0) {
+ ret = errno;
+ ErrPrint("fcntl: %s\n", strerror(errno));
+ }
+ } while (ret == EINTR);
+
+ return LB_STATUS_SUCCESS;
+}
+
+static int do_buffer_unlock(struct buffer_info *buffer)
+{
+ struct flock flock;
+ int ret;
+
+ if (buffer->lock_fd < 0) {
+ return LB_STATUS_SUCCESS;
+ }
+
+ flock.l_type = F_UNLCK;
+ flock.l_whence = SEEK_SET;
+ flock.l_start = 0;
+ flock.l_len = 0;
+ flock.l_pid = getpid();
+
+ do {
+ ret = fcntl(buffer->lock_fd, F_SETLKW, &flock);
+ if (ret < 0) {
+ ret = errno;
+ ErrPrint("fcntl: %s\n", strerror(errno));
+ }
+ } while (ret == EINTR);
+
+ return LB_STATUS_SUCCESS;
+}
+
+static inline int load_file_buffer(struct buffer_info *info)
+{
+ struct buffer *buffer;
+ double timestamp;
+ int size;
+ char *new_id;
+ int len;
+
+ len = strlen(IMAGE_PATH) + 40;
+ new_id = malloc(len);
+ if (!new_id) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ timestamp = util_timestamp();
+ snprintf(new_id, len, SCHEMA_FILE "%s%lf", IMAGE_PATH, timestamp);
+
+ size = sizeof(*buffer) + info->w * info->h * info->pixel_size;
+ if (!size) {
+ ErrPrint("Canvas buffer size is ZERO\n");
+ DbgFree(new_id);
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ buffer = calloc(1, size);
+ if (!buffer) {
+ ErrPrint("Failed to allocate buffer\n");
+ DbgFree(new_id);
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ buffer->type = BUFFER_TYPE_FILE;
+ buffer->refcnt = 0;
+ buffer->state = CREATED;
+ buffer->info = info;
+
+ DbgFree(info->id);
+ info->id = new_id;
+ info->buffer = buffer;
+ info->is_loaded = 1;
+
+ DbgPrint("FILE type %d created\n", size);
+ return LB_STATUS_SUCCESS;
+}
+
+static inline int load_shm_buffer(struct buffer_info *info)
+{
+ int id;
+ int size;
+ struct buffer *buffer; /* Just for getting a size */
+ char *new_id;
+ int len;
+
+ size = info->w * info->h * info->pixel_size;
+ if (!size) {
+ ErrPrint("Invalid buffer size\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ id = shmget(IPC_PRIVATE, size + sizeof(*buffer), IPC_CREAT | 0666);
+ if (id < 0) {
+ ErrPrint("shmget: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ buffer = shmat(id, NULL, 0);
+ if (buffer == (void *)-1) {
+ ErrPrint("%s shmat: %s\n", info->id, strerror(errno));
+
+ if (shmctl(id, IPC_RMID, 0) < 0) {
+ ErrPrint("%s shmctl: %s\n", info->id, strerror(errno));
+ }
+
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ buffer->type = BUFFER_TYPE_SHM;
+ buffer->refcnt = id;
+ buffer->state = CREATED; /*!< Needless */
+ buffer->info = (void *)size; /*!< Use this field to indicates the size of SHM */
+
+ len = strlen(SCHEMA_SHM) + 30; /* strlen("shm://") + 30 */
+
+ new_id = malloc(len);
+ if (!new_id) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ if (shmdt(buffer) < 0) {
+ ErrPrint("shmdt: %s\n", strerror(errno));
+ }
+
+ if (shmctl(id, IPC_RMID, 0) < 0) {
+ ErrPrint("shmctl: %s\n", strerror(errno));
+ }
+
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ snprintf(new_id, len, SCHEMA_SHM "%d", id);
+
+ DbgFree(info->id);
+ info->id = new_id;
+ info->buffer = buffer;
+ info->is_loaded = 1;
+ return LB_STATUS_SUCCESS;
+}
+
+EAPI int buffer_handler_load(struct buffer_info *info)
+{
+ int ret;
+
+ if (!info) {
+ ErrPrint("buffer handler is nil\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (info->is_loaded) {
+ DbgPrint("Buffer is already loaded\n");
+ return LB_STATUS_SUCCESS;
+ }
+
+ switch (info->type) {
+ case BUFFER_TYPE_FILE:
+ ret = load_file_buffer(info);
+ (void)create_lock_file(info);
+ break;
+ case BUFFER_TYPE_SHM:
+ ret = load_shm_buffer(info);
+ (void)create_lock_file(info);
+ break;
+ case BUFFER_TYPE_PIXMAP:
+ default:
+ ErrPrint("Invalid buffer\n");
+ ret = LB_STATUS_ERROR_INVALID;
+ break;
+ }
+
+ return ret;
+}
+
+static inline int unload_file_buffer(struct buffer_info *info)
+{
+ const char *path;
+ char *new_id;
+
+ new_id = strdup(SCHEMA_FILE "/tmp/.live.undefined");
+ if (!new_id) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ DbgFree(info->buffer);
+ info->buffer = NULL;
+
+ path = util_uri_to_path(info->id);
+ if (path && unlink(path) < 0) {
+ ErrPrint("unlink: %s\n", strerror(errno));
+ }
+
+ DbgFree(info->id);
+ info->id = new_id;
+ return LB_STATUS_SUCCESS;
+}
+
+static inline int unload_shm_buffer(struct buffer_info *info)
+{
+ int id;
+ char *new_id;
+
+ new_id = strdup(SCHEMA_SHM "-1");
+ if (!new_id) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ if (sscanf(info->id, SCHEMA_SHM "%d", &id) != 1) {
+ ErrPrint("%s Invalid ID\n", info->id);
+ DbgFree(new_id);
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (id < 0) {
+ ErrPrint("(%s) Invalid id: %d\n", info->id, id);
+ DbgFree(new_id);
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (shmdt(info->buffer) < 0) {
+ ErrPrint("Detach shm: %s\n", strerror(errno));
+ }
+
+ if (shmctl(id, IPC_RMID, 0) < 0) {
+ ErrPrint("Remove shm: %s\n", strerror(errno));
+ }
+
+ info->buffer = NULL;
+
+ DbgFree(info->id);
+ info->id = new_id;
+ return LB_STATUS_SUCCESS;
+}
+
+EAPI int buffer_handler_unload(struct buffer_info *info)
+{
+ int ret;
+
+ if (!info) {
+ ErrPrint("buffer handler is NIL\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (!info->is_loaded) {
+ ErrPrint("Buffer is not loaded\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ switch (info->type) {
+ case BUFFER_TYPE_FILE:
+ (void)destroy_lock_file(info);
+ ret = unload_file_buffer(info);
+ break;
+ case BUFFER_TYPE_SHM:
+ (void)destroy_lock_file(info);
+ ret = unload_shm_buffer(info);
+ break;
+ case BUFFER_TYPE_PIXMAP:
+ default:
+ ErrPrint("Invalid buffer\n");
+ ret = LB_STATUS_ERROR_INVALID;
+ break;
+ }
+
+ if (ret == 0) {
+ info->is_loaded = 0;
+ }
+
+ return ret;
+}
+
+EAPI const char *buffer_handler_id(const struct buffer_info *info)
+{
+ return info ? info->id : "";
+}
+
+EAPI enum buffer_type buffer_handler_type(const struct buffer_info *info)
+{
+ return info ? info->type : BUFFER_TYPE_ERROR;
+}
+
+EAPI void *buffer_handler_fb(struct buffer_info *info)
+{
+ struct buffer *buffer;
+
+ if (!info) {
+ return NULL;
+ }
+
+ buffer = info->buffer;
+
+ if (info->type == BUFFER_TYPE_PIXMAP) {
+ return NULL;
+ }
+
+ return buffer->data;
+}
+
+EAPI int buffer_handler_pixmap(const struct buffer_info *info)
+{
+ return 0;
+}
+
+EAPI void *buffer_handler_pixmap_acquire_buffer(struct buffer_info *info)
+{
+ return NULL;
+}
+
+EAPI void *buffer_handler_pixmap_buffer(struct buffer_info *info)
+{
+ return NULL;
+}
+
+/*!
+ * \return "buffer" object (Not the buffer_info)
+ */
+EAPI void *buffer_handler_pixmap_ref(struct buffer_info *info)
+{
+ return NULL;
+}
+
+/*!
+ * \return "buffer"
+ */
+EAPI void *buffer_handler_pixmap_find(int pixmap)
+{
+ return NULL;
+}
+
+EAPI int buffer_handler_pixmap_release_buffer(void *canvas)
+{
+ return LB_STATUS_ERROR_NOT_EXIST;
+}
+
+/*!
+ * \note
+ *
+ * \return Return NULL if the buffer is in still uses.
+ * Return buffer_ptr if it needs to destroy
+ */
+EAPI int buffer_handler_pixmap_unref(void *buffer_ptr)
+{
+ return LB_STATUS_SUCCESS;
+}
+
+EAPI int buffer_handler_is_loaded(const struct buffer_info *info)
+{
+ return info ? info->is_loaded : 0;
+}
+
+EAPI void buffer_handler_update_size(struct buffer_info *info, int w, int h)
+{
+ if (!info) {
+ return;
+ }
+
+ info->w = w;
+ info->h = h;
+}
+
+EAPI int buffer_handler_resize(struct buffer_info *info, int w, int h)
+{
+ int ret;
+
+ if (!info) {
+ ErrPrint("Invalid handler\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (info->w == w && info->h == h) {
+ DbgPrint("No changes\n");
+ return LB_STATUS_SUCCESS;
+ }
+
+ buffer_handler_update_size(info, w, h);
+
+ if (!info->is_loaded) {
+ DbgPrint("Buffer size is updated[%dx%d]\n", w, h);
+ return LB_STATUS_SUCCESS;
+ }
+
+ ret = buffer_handler_unload(info);
+ if (ret < 0) {
+ ErrPrint("Unload: %d\n", ret);
+ }
+
+ ret = buffer_handler_load(info);
+ if (ret < 0) {
+ ErrPrint("Load: %d\n", ret);
+ }
+
+ return LB_STATUS_SUCCESS;
+}
+
+EAPI int buffer_handler_get_size(struct buffer_info *info, int *w, int *h)
+{
+ if (!info) {
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (w) {
+ *w = info->w;
+ }
+ if (h) {
+ *h = info->h;
+ }
+
+ return LB_STATUS_SUCCESS;
+}
+
+EAPI struct inst_info *buffer_handler_instance(struct buffer_info *info)
+{
+ return info->inst;
+}
+
+EAPI void buffer_handler_flush(struct buffer_info *info)
+{
+ int fd;
+ int size;
+ struct buffer *buffer;
+
+ if (!info || !info->buffer) {
+ return;
+ }
+
+ buffer = info->buffer;
+
+ if (buffer->type == BUFFER_TYPE_PIXMAP) {
+ /*!
+ * \note
+ * Not supported for wayland or this should be ported correctly
+ */
+ } else if (buffer->type == BUFFER_TYPE_FILE) {
+ fd = open(util_uri_to_path(info->id), O_WRONLY | O_CREAT, 0644);
+ if (fd < 0) {
+ ErrPrint("%s open falied: %s\n", util_uri_to_path(info->id), strerror(errno));
+ return;
+ }
+
+ size = info->w * info->h * info->pixel_size;
+ do_buffer_lock(info);
+ if (write(fd, info->buffer, size) != size) {
+ ErrPrint("Write is not completed: %s\n", strerror(errno));
+ }
+ do_buffer_unlock(info);
+
+ if (close(fd) < 0) {
+ ErrPrint("close: %s\n", strerror(errno));
+ }
+ } else {
+ DbgPrint("Flush nothing\n");
+ }
+}
+
+HAPI int buffer_handler_init(void)
+{
+ /*!
+ * \TODO
+ * Implement this for wayland
+ */
+ if (USE_SW_BACKEND) {
+ DbgPrint("Fallback to the S/W Backend\n");
+ return LB_STATUS_SUCCESS;
+ }
+
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI int buffer_handler_fini(void)
+{
+ /*!
+ * \TODO
+ * Implement this for wayland
+ */
+ return LB_STATUS_SUCCESS;
+}
+
+static inline struct buffer *raw_open_file(const char *filename)
+{
+ struct buffer *buffer;
+ int fd;
+ off_t off;
+ int ret;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ ErrPrint("open: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ off = lseek(fd, 0L, SEEK_END);
+ if (off == (off_t)-1) {
+ ErrPrint("lseek: %s\n", strerror(errno));
+
+ if (close(fd) < 0) {
+ ErrPrint("close: %s\n", strerror(errno));
+ }
+
+ return NULL;
+ }
+
+ if (lseek(fd, 0L, SEEK_SET) == (off_t)-1) {
+ ErrPrint("lseek: %s\n", strerror(errno));
+
+ if (close(fd) < 0) {
+ ErrPrint("close: %s\n", strerror(errno));
+ }
+
+ return NULL;
+ }
+
+ buffer = calloc(1, sizeof(*buffer) + off);
+ if (!buffer) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+
+ if (close(fd) < 0) {
+ ErrPrint("close: %s\n", strerror(errno));
+ }
+
+ return NULL;
+ }
+
+ buffer->state = CREATED;
+ buffer->type = BUFFER_TYPE_FILE;
+ buffer->refcnt = 0;
+ buffer->info = (void *)off;
+
+ ret = read(fd, buffer->data, off);
+ if (ret < 0) {
+ ErrPrint("read: %s\n", strerror(errno));
+ DbgFree(buffer);
+
+ if (close(fd) < 0) {
+ ErrPrint("close: %s\n", strerror(errno));
+ }
+
+ return NULL;
+ }
+
+ if (close(fd) < 0) {
+ ErrPrint("close: %s\n", strerror(errno));
+ }
+
+ return buffer;
+}
+
+static inline int raw_close_file(struct buffer *buffer)
+{
+ DbgFree(buffer);
+ return 0;
+}
+
+static inline struct buffer *raw_open_shm(int shm)
+{
+ struct buffer *buffer;
+
+ buffer = (struct buffer *)shmat(shm, NULL, SHM_RDONLY);
+ if (buffer == (struct buffer *)-1) {
+ ErrPrint("shmat: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ return buffer;
+}
+
+static inline int raw_close_shm(struct buffer *buffer)
+{
+ int ret;
+
+ ret = shmdt(buffer);
+ if (ret < 0) {
+ ErrPrint("shmdt: %s\n", strerror(errno));
+ }
+
+ return ret;
+}
+
+EAPI void *buffer_handler_raw_data(struct buffer *buffer)
+{
+ if (!buffer || buffer->state != CREATED) {
+ return NULL;
+ }
+
+ return buffer->data;
+}
+
+EAPI int buffer_handler_raw_size(struct buffer *buffer)
+{
+ if (!buffer || buffer->state != CREATED) {
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ return (int)buffer->info;
+}
+
+EAPI struct buffer *buffer_handler_raw_open(enum buffer_type buffer_type, void *resource)
+{
+ struct buffer *handle;
+
+ switch (buffer_type) {
+ case BUFFER_TYPE_SHM:
+ handle = raw_open_shm((int)resource);
+ break;
+ case BUFFER_TYPE_FILE:
+ handle = raw_open_file(resource);
+ break;
+ case BUFFER_TYPE_PIXMAP:
+ default:
+ handle = NULL;
+ break;
+ }
+
+ return handle;
+}
+
+EAPI int buffer_handler_raw_close(struct buffer *buffer)
+{
+ int ret;
+
+ switch (buffer->type) {
+ case BUFFER_TYPE_SHM:
+ ret = raw_close_shm(buffer);
+ break;
+ case BUFFER_TYPE_FILE:
+ ret = raw_close_file(buffer);
+ break;
+ case BUFFER_TYPE_PIXMAP:
+ default:
+ ret = LB_STATUS_ERROR_INVALID;
+ break;
+ }
+
+ return ret;
+}
+
+EAPI int buffer_handler_lock(struct buffer_info *buffer)
+{
+ if (buffer->type == BUFFER_TYPE_PIXMAP) {
+ return LB_STATUS_SUCCESS;
+ }
+
+ if (buffer->type == BUFFER_TYPE_FILE) {
+ return LB_STATUS_SUCCESS;
+ }
+
+ return do_buffer_lock(buffer);
+}
+
+EAPI int buffer_handler_unlock(struct buffer_info *buffer)
+{
+ if (buffer->type == BUFFER_TYPE_PIXMAP) {
+ return LB_STATUS_SUCCESS;
+ }
+
+ if (buffer->type == BUFFER_TYPE_FILE) {
+ return LB_STATUS_SUCCESS;
+ }
+
+ return do_buffer_unlock(buffer);
+}
+
+/*!
+ * \note
+ * Only can be used by master.
+ * Plugin cannot access the user data
+ */
+
+HAPI int buffer_handler_set_data(struct buffer_info *buffer, void *data)
+{
+ if (!buffer) {
+ ErrPrint("Invalid handle\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ buffer->data = data;
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI void *buffer_handler_data(struct buffer_info *buffer)
+{
+ if (!buffer) {
+ ErrPrint("Invalid handle\n");
+ return NULL;
+ }
+
+ return buffer->data;
+}
+
+HAPI int buffer_handler_destroy(struct buffer_info *info)
+{
+ Eina_List *l;
+ struct buffer *buffer;
+
+ if (!info) {
+ DbgPrint("Buffer is not created yet. info is NIL\n");
+ return LB_STATUS_SUCCESS;
+ }
+
+ buffer_handler_unload(info);
+ DbgFree(info->id);
+ DbgFree(info);
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI struct buffer_info *buffer_handler_create(struct inst_info *inst, enum buffer_type type, int w, int h, int pixel_size)
+{
+ struct buffer_info *info;
+
+ info = malloc(sizeof(*info));
+ if (!info) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ switch (type) {
+ case BUFFER_TYPE_SHM:
+ if (pixel_size != DEFAULT_PIXELS) {
+ DbgPrint("SHM only supportes %d bytes pixels (requested: %d)\n", DEFAULT_PIXELS, pixel_size);
+ pixel_size = DEFAULT_PIXELS;
+ }
+
+ info->id = strdup(SCHEMA_SHM "-1");
+ if (!info->id) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(info);
+ return NULL;
+ }
+ break;
+ case BUFFER_TYPE_FILE:
+ if (pixel_size != DEFAULT_PIXELS) {
+ DbgPrint("FILE only supportes %d bytes pixels (requested: %d)\n", DEFAULT_PIXELS, pixel_size);
+ pixel_size = DEFAULT_PIXELS;
+ }
+
+ info->id = strdup(SCHEMA_FILE "/tmp/.live.undefined");
+ if (!info->id) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(info);
+ return NULL;
+ }
+ break;
+ case BUFFER_TYPE_PIXMAP:
+ default:
+ ErrPrint("Invalid type\n");
+ DbgFree(info);
+ return NULL;
+ }
+
+ info->lock = NULL;
+ info->lock_fd = -1;
+ info->w = w;
+ info->h = h;
+ info->pixel_size = pixel_size;
+ info->type = type;
+ info->is_loaded = 0;
+ info->inst = inst;
+ info->buffer = NULL;
+ info->data = NULL;
+
+ return info;
+}
+
+/* End of a file */
diff --git a/src/client_life.c b/src/client_life.c
new file mode 100644
index 0000000..d01dc2a
--- /dev/null
+++ b/src/client_life.c
@@ -0,0 +1,870 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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 <stdio.h>
+#include <errno.h>
+
+#include <Eina.h>
+#include <Ecore.h>
+
+#include <dlog.h>
+#include <packet.h>
+#include <livebox-errno.h>
+
+#include "client_life.h"
+#include "instance.h"
+#include "client_rpc.h"
+#include "debug.h"
+#include "util.h"
+#include "slave_life.h"
+#include "xmonitor.h"
+#include "conf.h"
+
+int errno;
+
+static struct {
+ Eina_List *client_list;
+ int nr_of_paused_clients;
+
+ enum global_event_process {
+ GLOBAL_EVENT_PROCESS_IDLE = 0x00,
+ GLOBAL_EVENT_PROCESS_CREATE = 0x01,
+ GLOBAL_EVENT_PROCESS_DESTROY = 0x02
+ } in_event_process;
+
+ Eina_List *create_event_list;
+ Eina_List *destroy_event_list;
+
+} s_info = {
+ .client_list = NULL,
+ .nr_of_paused_clients = 0,
+ .in_event_process = GLOBAL_EVENT_PROCESS_IDLE,
+ .create_event_list = NULL,
+ .destroy_event_list = NULL,
+};
+
+struct subscribe_item {
+ char *cluster;
+ char *category;
+};
+
+struct global_event_item {
+ void *cbdata;
+ int (*cb)(struct client_node *client, void *data);
+ int deleted;
+};
+
+struct event_item {
+ void *data;
+ int (*cb)(struct client_node *, void *);
+ int deleted;
+};
+
+struct data_item {
+ char *tag;
+ void *data;
+};
+
+struct client_node {
+ pid_t pid;
+ int refcnt;
+
+ int paused;
+
+ enum client_event_process {
+ CLIENT_EVENT_PROCESS_IDLE = 0x00,
+ CLIENT_EVENT_PROCESS_DEACTIVATE = 0x01,
+ CLIENT_EVENT_PROCESS_ACTIVATE = 0x02
+ } in_event_process;
+ Eina_List *event_deactivate_list;
+ Eina_List *event_activate_list;
+
+ Eina_List *data_list;
+ Eina_List *subscribe_list;
+
+ int faulted;
+};
+
+static inline void invoke_global_destroyed_cb(struct client_node *client)
+{
+ Eina_List *l;
+ Eina_List *n;
+ struct global_event_item *item;
+
+ s_info.in_event_process |= GLOBAL_EVENT_PROCESS_DESTROY;
+ EINA_LIST_FOREACH_SAFE(s_info.destroy_event_list, l, n, item) {
+ /*!
+ * The first,
+ * item->deleted will be checked, so if it is deleted, remove item from the list
+ * The second, if the first routine takes false path,
+ * item->cb will be called, if it returns negative value, remove item from the list
+ * The third, if the second routine takes false path,
+ * Check the item->deleted again, so if it is turnned on, remove item from the list
+ */
+ if (item->deleted || item->cb(client, item->cbdata) < 0 || item->deleted) {
+ s_info.destroy_event_list = eina_list_remove(s_info.destroy_event_list, item);
+ DbgFree(item);
+ }
+ }
+ s_info.in_event_process &= ~GLOBAL_EVENT_PROCESS_DESTROY;
+}
+
+static inline void invoke_global_created_cb(struct client_node *client)
+{
+ Eina_List *l;
+ Eina_List *n;
+ struct global_event_item *item;
+
+ s_info.in_event_process |= GLOBAL_EVENT_PROCESS_CREATE;
+ EINA_LIST_FOREACH_SAFE(s_info.create_event_list, l, n, item) {
+ /*!
+ * The first,
+ * item->deleted will be checked, so if it is deleted, remove item from the list
+ * The second, if the first routine takes false path,
+ * item->cb will be called, if it returns negative value, remove item from the list
+ * The third, if the second routine takes false path,
+ * Check the item->deleted again, so if it is turnned on, remove item from the list
+ */
+
+ if (item->deleted || item->cb(client, item->cbdata) < 0 || item->deleted) {
+ s_info.create_event_list = eina_list_remove(s_info.create_event_list, item);
+ DbgFree(item);
+ }
+ }
+ s_info.in_event_process &= ~GLOBAL_EVENT_PROCESS_CREATE;
+}
+
+static inline void invoke_deactivated_cb(struct client_node *client)
+{
+ struct event_item *item;
+ Eina_List *l;
+ Eina_List *n;
+
+ client->in_event_process |= CLIENT_EVENT_PROCESS_DEACTIVATE;
+ EINA_LIST_FOREACH_SAFE(client->event_deactivate_list, l, n, item) {
+ /*!
+ * The first,
+ * item->deleted will be checked, so if it is deleted, remove item from the list
+ * The second, if the first routine takes false path,
+ * item->cb will be called, if it returns negative value, remove item from the list
+ * The third, if the second routine takes false path,
+ * Check the item->deleted again, so if it is turnned on, remove item from the list
+ */
+
+ if (item->deleted || item->cb(client, item->data) < 0 || item->deleted) {
+ client->event_deactivate_list = eina_list_remove(client->event_deactivate_list, item);
+ DbgFree(item);
+ }
+ }
+ client->in_event_process &= ~CLIENT_EVENT_PROCESS_DEACTIVATE;
+}
+
+static inline void invoke_activated_cb(struct client_node *client)
+{
+ struct event_item *item;
+ Eina_List *l;
+ Eina_List *n;
+
+ client->in_event_process |= CLIENT_EVENT_PROCESS_ACTIVATE;
+ EINA_LIST_FOREACH_SAFE(client->event_activate_list, l, n, item) {
+ /*!
+ * The first,
+ * item->deleted will be checked, so if it is deleted, remove item from the list
+ * The second, if the first routine takes false path,
+ * item->cb will be called, if it returns negative value, remove item from the list
+ * The third, if the second routine takes false path,
+ * Check the item->deleted again, so if it is turnned on, remove item from the list
+ */
+
+ if (item->deleted || item->cb(client, item->data) < 0 || item->deleted) {
+ client->event_activate_list = eina_list_remove(client->event_activate_list, item);
+ DbgFree(item);
+ }
+ }
+ client->in_event_process &= ~CLIENT_EVENT_PROCESS_ACTIVATE;
+}
+
+static inline void destroy_client_data(struct client_node *client)
+{
+ struct event_item *event;
+ struct data_item *data;
+ struct subscribe_item *item;
+ Ecore_Timer *timer;
+
+ timer = client_del_data(client, "create,timer");
+ if (timer) {
+ ecore_timer_del(timer);
+ }
+
+ DbgPrint("Destroy client: %p\n", client);
+
+ invoke_global_destroyed_cb(client);
+ client_rpc_fini(client); /*!< Finalize the RPC after invoke destroy callbacks */
+
+ EINA_LIST_FREE(client->data_list, data) {
+ DbgPrint("Tag is not cleared (%s)\n", data->tag);
+ DbgFree(data->tag);
+ DbgFree(data);
+ }
+
+ EINA_LIST_FREE(client->event_deactivate_list, event) {
+ DbgFree(event);
+ }
+
+ EINA_LIST_FREE(client->subscribe_list, item) {
+ DbgFree(item->cluster);
+ DbgFree(item->category);
+ DbgFree(item);
+ }
+
+ if (client->paused) {
+ s_info.nr_of_paused_clients--;
+ }
+
+ s_info.client_list = eina_list_remove(s_info.client_list, client);
+ DbgFree(client);
+
+ /*!
+ * \note
+ * If there is any changes of clients,
+ * We should check the pause/resume states again.
+ */
+ xmonitor_handle_state_changes();
+}
+
+static inline struct client_node *create_client_data(pid_t pid)
+{
+ struct client_node *client;
+
+ client = calloc(1, sizeof(*client));
+ if (!client) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ client->pid = pid;
+ client->refcnt = 1;
+
+ s_info.client_list = eina_list_append(s_info.client_list, client);
+
+ /*!
+ * \note
+ * Right after create a client ADT,
+ * We assume that the client is paused.
+ */
+ client_paused(client);
+ xmonitor_handle_state_changes();
+ return client;
+}
+
+static Eina_Bool created_cb(void *data)
+{
+ (void)client_del_data(data, "create,timer");
+
+ invoke_global_created_cb(data);
+ invoke_activated_cb(data);
+ /*!
+ * \note
+ * Client PAUSE/RESUME event must has to be sent after created event.
+ */
+ xmonitor_update_state(client_pid(data));
+
+ (void)client_unref(data);
+ return ECORE_CALLBACK_CANCEL;
+}
+
+/*!
+ * \note
+ * Noramlly, client ADT is created when it send the "acquire" packet.
+ * It means we have the handle for communicating with the client already,
+ * So we just create its ADT in this function.
+ * And invoke the global created event & activated event callbacks
+ */
+HAPI struct client_node *client_create(pid_t pid, int handle)
+{
+ struct client_node *client;
+ int ret;
+
+ client = client_find_by_rpc_handle(handle);
+ if (client) {
+ ErrPrint("Client %d(%d) is already exists\n", pid, handle);
+ return client;
+ }
+
+ client = create_client_data(pid);
+ if (!client) {
+ ErrPrint("Failed to create a new client (%d)\n", pid);
+ return NULL;
+ }
+
+ ret = client_rpc_init(client, handle);
+ if (ret < 0) {
+ client = client_unref(client);
+ ErrPrint("Failed to initialize the RPC for %d, Destroy client data %p(has to be 0x0)\n", pid, client);
+ } else {
+ Ecore_Timer *create_timer;
+ /*!
+ * \note
+ * To save the time to send reply packet to the client.
+ */
+ create_timer = ecore_timer_add(DELAY_TIME, created_cb, client_ref(client));
+ if (create_timer == NULL) {
+ ErrPrint("Failed to add a timer for client created event\n");
+ client = client_unref(client); /* Decrease refcnt for argument */
+ client = client_unref(client); /* Destroy client object */
+ return NULL;
+ }
+
+ ret = client_set_data(client, "create,timer", create_timer);
+ DbgPrint("Set data: %d\n", ret);
+ }
+
+ return client;
+}
+
+HAPI struct client_node *client_ref(struct client_node *client)
+{
+ if (!client) {
+ return NULL;
+ }
+
+ client->refcnt++;
+ return client;
+}
+
+HAPI struct client_node *client_unref(struct client_node *client)
+{
+ if (!client) {
+ return NULL;
+ }
+
+ if (client->refcnt == 0) {
+ ErrPrint("Client refcnt is not managed correctly\n");
+ return NULL;
+ }
+
+ client->refcnt--;
+ if (client->refcnt == 0) {
+ destroy_client_data(client);
+ client = NULL;
+ }
+
+ return client;
+}
+
+HAPI const int const client_refcnt(const struct client_node *client)
+{
+ return client->refcnt;
+}
+
+HAPI const pid_t const client_pid(const struct client_node *client)
+{
+ return client ? client->pid : (pid_t)-1;
+}
+
+HAPI struct client_node *client_find_by_pid(pid_t pid)
+{
+ Eina_List *l;
+ struct client_node *client;
+
+ EINA_LIST_FOREACH(s_info.client_list, l, client) {
+ if (client->pid == pid) {
+ return client;
+ }
+ }
+
+ return NULL;
+}
+
+HAPI struct client_node *client_find_by_rpc_handle(int handle)
+{
+ Eina_List *l;
+ struct client_node *client;
+
+ if (handle <= 0) {
+ ErrPrint("Invalid handle %d\n", handle);
+ return NULL;
+ }
+
+ EINA_LIST_FOREACH(s_info.client_list, l, client) {
+ if (client_rpc_handle(client) == handle) {
+ return client;
+ }
+ }
+
+ return NULL;
+}
+
+HAPI const int const client_count_paused(void)
+{
+ return s_info.nr_of_paused_clients;
+}
+
+HAPI int client_is_all_paused(void)
+{
+ DbgPrint("%d, %d\n", eina_list_count(s_info.client_list), s_info.nr_of_paused_clients);
+ return eina_list_count(s_info.client_list) == s_info.nr_of_paused_clients;
+}
+
+HAPI int client_count(void)
+{
+ return eina_list_count(s_info.client_list);
+}
+
+HAPI struct client_node *client_deactivated_by_fault(struct client_node *client)
+{
+ if (!client || client->faulted) {
+ return client;
+ }
+
+ ErrPrint("Client[%p] is faulted(%d), pid(%d)\n", client, client->refcnt, client->pid);
+ client->faulted = 1;
+ client->pid = (pid_t)-1;
+
+ invoke_deactivated_cb(client);
+ client = client_destroy(client);
+ /*!
+ * \todo
+ * Who invokes this function has to care the reference counter of a client
+ * do I need to invoke the deactivated callback from here?
+ * client->pid = (pid_t)-1;
+ * slave_unref(client)
+ */
+ return client;
+}
+
+HAPI const int const client_is_faulted(const struct client_node *client)
+{
+ /*!
+ * \note
+ * If the "client" is NIL, I assume that it is fault so returns TRUE(1)
+ */
+ return client ? client->faulted : 1;
+}
+
+HAPI void client_reset_fault(struct client_node *client)
+{
+ if (client) {
+ client->faulted = 0;
+ }
+}
+
+HAPI int client_event_callback_add(struct client_node *client, enum client_event event, int (*cb)(struct client_node *, void *), void *data)
+{
+ struct event_item *item;
+
+ if (!cb) {
+ ErrPrint("Invalid callback (cb == NULL)\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ item = malloc(sizeof(*item));
+ if (!item) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ item->cb = cb;
+ item->data = data;
+ item->deleted = 0;
+
+ /*!
+ * \note
+ * Use the eina_list_prepend API.
+ * To keep the sequence of a callback invocation.
+ *
+ * Here is an example sequence.
+ *
+ * client_event_callback_add(CALLBACK_01);
+ * client_event_callback_add(CALLBACK_02);
+ * client_event_callback_add(CALLBACK_03);
+ *
+ * Then the invoke_event_callback function will call the CALLBACKS as below sequence
+ *
+ * invoke_CALLBACK_03
+ * invoke_CALLBACK_02
+ * invoke_CALLBACK_01
+ */
+
+ switch (event) {
+ case CLIENT_EVENT_DEACTIVATE:
+ client->event_deactivate_list = eina_list_prepend(client->event_deactivate_list, item);
+ break;
+ case CLIENT_EVENT_ACTIVATE:
+ client->event_activate_list = eina_list_prepend(client->event_activate_list, item);
+ break;
+ default:
+ DbgFree(item);
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI int client_event_callback_del(struct client_node *client, enum client_event event, int (*cb)(struct client_node *, void *), void *data)
+{
+ struct event_item *item;
+ Eina_List *l;
+ Eina_List *n;
+
+ if (!cb) {
+ ErrPrint("Invalid callback (cb == NULL)\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ switch (event) {
+ case CLIENT_EVENT_DEACTIVATE:
+ EINA_LIST_FOREACH_SAFE(client->event_deactivate_list, l, n, item) {
+ if (item->cb == cb && item->data == data) {
+ if (client->in_event_process & CLIENT_EVENT_PROCESS_DEACTIVATE) {
+ item->deleted = 1;
+ } else {
+ client->event_deactivate_list = eina_list_remove(client->event_deactivate_list, item);
+ DbgFree(item);
+ }
+ return LB_STATUS_SUCCESS;
+ }
+ }
+ break;
+
+ case CLIENT_EVENT_ACTIVATE:
+ EINA_LIST_FOREACH_SAFE(client->event_activate_list, l, n, item) {
+ if (item->cb == cb && item->data == data) {
+ if (client->in_event_process & CLIENT_EVENT_PROCESS_ACTIVATE) {
+ item->deleted = 1;
+ } else {
+ client->event_activate_list = eina_list_remove(client->event_activate_list, item);
+ DbgFree(item);
+ }
+ return LB_STATUS_SUCCESS;
+ }
+ }
+ break;
+
+ default:
+ ErrPrint("Invalid event\n");
+ break;
+ }
+
+ return LB_STATUS_ERROR_NOT_EXIST;
+}
+
+HAPI int client_set_data(struct client_node *client, const char *tag, void *data)
+{
+ struct data_item *item;
+
+ item = calloc(1, sizeof(*item));
+ if (!item) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ item->tag = strdup(tag);
+ if (!item->tag) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(item);
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ item->data = data;
+
+ client->data_list = eina_list_append(client->data_list, item);
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI void *client_data(struct client_node *client, const char *tag)
+{
+ Eina_List *l;
+ struct data_item *item;
+
+ EINA_LIST_FOREACH(client->data_list, l, item) {
+ if (!strcmp(item->tag, tag)) {
+ return item->data;
+ }
+ }
+
+ return NULL;
+}
+
+HAPI void *client_del_data(struct client_node *client, const char *tag)
+{
+ Eina_List *l;
+ Eina_List *n;
+ struct data_item *item;
+
+ EINA_LIST_FOREACH_SAFE(client->data_list, l, n, item) {
+ if (!strcmp(item->tag, tag)) {
+ void *data;
+ client->data_list = eina_list_remove(client->data_list, item);
+ data = item->data;
+ DbgFree(item->tag);
+ DbgFree(item);
+ return data;
+ }
+ }
+
+ return NULL;
+}
+
+HAPI void client_paused(struct client_node *client)
+{
+ if (client->paused) {
+ return;
+ }
+
+ client->paused = 1;
+ s_info.nr_of_paused_clients++;
+}
+
+HAPI void client_resumed(struct client_node *client)
+{
+ if (client->paused == 0) {
+ return;
+ }
+
+ client->paused = 0;
+ s_info.nr_of_paused_clients--;
+}
+
+HAPI int client_init(void)
+{
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI void client_fini(void)
+{
+ struct global_event_item *handler;
+ struct client_node *client;
+ Eina_List *l;
+ Eina_List *n;
+
+ EINA_LIST_FOREACH_SAFE(s_info.client_list, l, n, client) {
+ (void)client_destroy(client);
+ }
+
+ EINA_LIST_FREE(s_info.create_event_list, handler) {
+ DbgFree(handler);
+ }
+
+ EINA_LIST_FREE(s_info.destroy_event_list, handler) {
+ DbgFree(handler);
+ }
+}
+
+HAPI int client_global_event_handler_add(enum client_global_event event_type, int (*cb)(struct client_node *client, void *data), void *data)
+{
+ struct global_event_item *handler;
+
+ handler = malloc(sizeof(*handler));
+ if (!handler) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ handler->cbdata = data;
+ handler->cb = cb;
+ handler->deleted = 0;
+
+ switch (event_type) {
+ case CLIENT_GLOBAL_EVENT_CREATE:
+ s_info.create_event_list = eina_list_prepend(s_info.create_event_list, handler);
+ break;
+ case CLIENT_GLOBAL_EVENT_DESTROY:
+ s_info.destroy_event_list = eina_list_prepend(s_info.destroy_event_list, handler);
+ break;
+ default:
+ DbgFree(handler);
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI int client_global_event_handler_del(enum client_global_event event_type, int (*cb)(struct client_node *, void *), void *data)
+{
+ Eina_List *l;
+ Eina_List *n;
+ struct global_event_item *item;
+
+ switch (event_type) {
+ case CLIENT_GLOBAL_EVENT_CREATE:
+ EINA_LIST_FOREACH_SAFE(s_info.create_event_list, l, n, item) {
+ if (item->cb == cb && item->cbdata == data) {
+ if (s_info.in_event_process & GLOBAL_EVENT_PROCESS_CREATE) {
+ item->deleted = 1;
+ } else {
+ s_info.create_event_list = eina_list_remove(s_info.create_event_list, item);
+ DbgFree(item);
+ }
+ return LB_STATUS_SUCCESS;
+ }
+ }
+ break;
+ case CLIENT_GLOBAL_EVENT_DESTROY:
+ EINA_LIST_FOREACH_SAFE(s_info.destroy_event_list, l, n, item) {
+ if (item->cb == cb && item->cbdata == data) {
+ if (s_info.in_event_process & GLOBAL_EVENT_PROCESS_DESTROY) {
+ item->deleted = 1;
+ } else {
+ s_info.destroy_event_list = eina_list_remove(s_info.destroy_event_list, item);
+ DbgFree(item);
+ }
+ return LB_STATUS_SUCCESS;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return LB_STATUS_ERROR_NOT_EXIST;
+}
+
+HAPI int client_subscribe(struct client_node *client, const char *cluster, const char *category)
+{
+ struct subscribe_item *item;
+
+ item = malloc(sizeof(*item));
+ if (!item) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ item->cluster = strdup(cluster);
+ if (!item->cluster) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(item);
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ item->category = strdup(category);
+ if (!item->category) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(item->cluster);
+ DbgFree(item);
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ client->subscribe_list = eina_list_append(client->subscribe_list, item);
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI int client_unsubscribe(struct client_node *client, const char *cluster, const char *category)
+{
+ struct subscribe_item *item;
+ Eina_List *l;
+ Eina_List *n;
+
+ EINA_LIST_FOREACH_SAFE(client->subscribe_list, l, n, item) {
+ if (!strcasecmp(cluster, item->cluster) && !strcasecmp(category, item->category)) {
+ client->subscribe_list = eina_list_remove(client->subscribe_list, item);
+ DbgFree(item->cluster);
+ DbgFree(item->category);
+ DbgFree(item);
+ return LB_STATUS_SUCCESS;
+ }
+ }
+
+ return LB_STATUS_ERROR_NOT_EXIST;
+}
+
+HAPI int client_is_subscribed(struct client_node *client, const char *cluster, const char *category)
+{
+ struct subscribe_item *item;
+ Eina_List *l;
+
+ EINA_LIST_FOREACH(client->subscribe_list, l, item) {
+ if (!strcmp(item->cluster, "*")) {
+ return 1;
+ }
+
+ if (strcasecmp(item->cluster, cluster)) {
+ continue;
+ }
+
+ if (!strcmp(item->category, "*")) {
+ return 1;
+ }
+
+ if (!strcasecmp(item->category, category)) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+HAPI int client_browse_list(const char *cluster, const char *category, int (*cb)(struct client_node *client, void *data), void *data)
+{
+ Eina_List *l;
+ struct client_node *client;
+ int cnt;
+
+ if (!cb || !cluster || !category) {
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ cnt = 0;
+ EINA_LIST_FOREACH(s_info.client_list, l, client) {
+ if (!client_is_subscribed(client, cluster, category)) {
+ continue;
+ }
+
+ if (cb(client, data) < 0) {
+ return LB_STATUS_ERROR_CANCEL;
+ }
+
+ cnt++;
+ }
+
+ return cnt;
+}
+
+HAPI int client_nr_of_subscriber(const char *cluster, const char *category)
+{
+ Eina_List *l;
+ struct client_node *client;
+ int cnt;
+
+ cnt = 0;
+ EINA_LIST_FOREACH(s_info.client_list, l, client) {
+ cnt += !!client_is_subscribed(client, cluster, category);
+ }
+
+ return cnt;
+}
+
+HAPI int client_broadcast(struct inst_info *inst, struct packet *packet)
+{
+ Eina_List *l;
+ Eina_List *list;
+ struct client_node *client;
+
+ list = inst ? instance_client_list(inst) : s_info.client_list;
+ EINA_LIST_FOREACH(list, l, client) {
+ if (client_pid(client) == -1) {
+ ErrPrint("Client[%p] has PID[%d]\n", client, client_pid(client));
+ continue;
+ }
+
+ (void)client_rpc_async_request(client, packet_ref(packet));
+ }
+
+ packet_unref(packet);
+ return LB_STATUS_SUCCESS;
+}
+
+/* End of a file */
diff --git a/src/client_rpc.c b/src/client_rpc.c
new file mode 100644
index 0000000..a9b00f4
--- /dev/null
+++ b/src/client_rpc.c
@@ -0,0 +1,283 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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 <stdio.h>
+#include <errno.h>
+
+#include <Eina.h>
+#include <Ecore.h>
+
+#include <dlog.h>
+#include <com-core_packet.h>
+#include <packet.h>
+#include <livebox-errno.h>
+
+#include "client_life.h"
+#include "instance.h"
+#include "client_rpc.h"
+#include "debug.h"
+#include "conf.h"
+#include "util.h"
+
+#define RPC_TAG "rpc"
+
+/*!
+ * \note
+ * Static component information structure.
+ */
+static struct info {
+ Eina_List *command_list; /*!< Packet Q: Before sending the request, all request commands will stay here */
+ Ecore_Timer *command_consumer; /*!< This timer will consuming the command Q. sending them to the specified client */
+} s_info = {
+ .command_list = NULL,
+ .command_consumer = NULL,
+};
+
+struct client_rpc {
+ int handle; /*!< Handler for communication with client */
+};
+
+struct command {
+ struct packet *packet;
+ struct client_node *client; /*!< Target client. who should receive this command */
+};
+
+/*!
+ * \brief
+ * Creating or Destroying command object
+ */
+static inline struct command *create_command(struct client_node *client, struct packet *packet)
+{
+ struct command *command;
+
+ command = calloc(1, sizeof(*command));
+ if (!command) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ command->packet = packet_ref(packet);
+ command->client = client_ref(client);
+
+ return command;
+}
+
+static inline void destroy_command(struct command *command)
+{
+ client_unref(command->client);
+ packet_unref(command->packet);
+ DbgFree(command);
+}
+
+static inline int count_command(void)
+{
+ return eina_list_count(s_info.command_list);
+}
+
+static inline struct command *pop_command(void)
+{
+ struct command *command;
+
+ command = eina_list_nth(s_info.command_list, 0);
+ if (!command) {
+ return NULL;
+ }
+
+ s_info.command_list = eina_list_remove(s_info.command_list, command);
+ return command;
+}
+
+static Eina_Bool command_consumer_cb(void *data)
+{
+ struct command *command;
+ struct client_rpc *rpc;
+ int ret;
+
+ command = pop_command();
+ if (!command) {
+ s_info.command_consumer = NULL;
+ return ECORE_CALLBACK_CANCEL;
+ }
+
+ if (!command->client) {
+ DbgPrint("Has no client\n");
+ goto out;
+ }
+
+ if (client_is_faulted(command->client)) {
+ ErrPrint("Client[%p] is faulted, discard command\n", command->client);
+ goto out;
+ }
+
+ rpc = client_data(command->client, RPC_TAG);
+ if (!rpc) {
+ ErrPrint("Client is not activated\n");
+ goto out;
+ }
+
+ if (rpc->handle < 0) {
+ DbgPrint("RPC is not initialized\n");
+ goto out;
+ }
+
+ ret = com_core_packet_send_only(rpc->handle, command->packet);
+ if (ret < 0) {
+ ErrPrint("Failed to send packet %d\n", ret);
+ }
+
+out:
+ destroy_command(command);
+ return ECORE_CALLBACK_RENEW;
+}
+
+static inline void push_command(struct command *command)
+{
+ s_info.command_list = eina_list_append(s_info.command_list, command);
+
+ if (s_info.command_consumer) {
+ return;
+ }
+
+ s_info.command_consumer = ecore_timer_add(PACKET_TIME, command_consumer_cb, NULL);
+ if (!s_info.command_consumer) {
+ ErrPrint("Failed to add command consumer\n");
+ s_info.command_list = eina_list_remove(s_info.command_list, command);
+ destroy_command(command);
+ }
+}
+
+HAPI int client_rpc_async_request(struct client_node *client, struct packet *packet)
+{
+ struct command *command;
+ struct client_rpc *rpc;
+
+ if (!client || !packet) {
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (client_is_faulted(client)) {
+ ErrPrint("Client[%p] is faulted\n", client);
+ packet_unref(packet);
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ rpc = client_data(client, RPC_TAG);
+ if (!rpc) {
+ ErrPrint("Client[%p] is not ready for communication (%s)\n", client, packet_command(packet));
+ }
+
+ command = create_command(client, packet);
+ if (!command) {
+ packet_unref(packet);
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ push_command(command);
+ packet_unref(packet);
+ return LB_STATUS_SUCCESS;
+}
+
+static int deactivated_cb(struct client_node *client, void *data)
+{
+ struct client_rpc *rpc;
+ struct command *command;
+ Eina_List *l;
+ Eina_List *n;
+
+ rpc = client_data(client, RPC_TAG);
+ if (!rpc) {
+ ErrPrint("client is not valid\n");
+ return LB_STATUS_SUCCESS;
+ }
+
+ DbgPrint("Reset handle for %d\n", client_pid(client));
+ rpc->handle = -1;
+
+ DbgPrint("Begin: Destroying command\n");
+ EINA_LIST_FOREACH_SAFE(s_info.command_list, l, n, command) {
+ if (command->client == client) {
+ s_info.command_list = eina_list_remove(s_info.command_list, command);
+ destroy_command(command);
+ }
+ }
+ DbgPrint("End: Destroying command\n");
+
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI int client_rpc_init(struct client_node *client, int handle)
+{
+ struct client_rpc *rpc;
+ int ret;
+
+ rpc = calloc(1, sizeof(*rpc));
+ if (!rpc) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ ret = client_set_data(client, RPC_TAG, rpc);
+ if (ret < 0) {
+ ErrPrint("Failed to set \"rpc\" for client\n");
+ DbgFree(rpc);
+ return ret;
+ }
+
+ DbgPrint("CLIENT: New handle assigned for %d, %d (old: %d)\n", client_pid(client), handle, rpc->handle);
+ rpc->handle = handle;
+
+ ret = client_event_callback_add(client, CLIENT_EVENT_DEACTIVATE, deactivated_cb, NULL);
+ if (ret < 0) {
+ struct client_rpc *weird;
+
+ weird = client_del_data(client, RPC_TAG);
+ if (weird != rpc) {
+ ErrPrint("What happens? (%p <> %p)\n", weird, rpc);
+ }
+ DbgFree(rpc);
+ }
+
+ return ret;
+}
+
+HAPI int client_rpc_fini(struct client_node *client)
+{
+ struct client_rpc *rpc;
+
+ rpc = client_del_data(client, RPC_TAG);
+ if (!rpc) {
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ client_event_callback_del(client, CLIENT_EVENT_DEACTIVATE, deactivated_cb, NULL);
+ DbgFree(rpc);
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI int client_rpc_handle(struct client_node *client)
+{
+ struct client_rpc *rpc;
+
+ rpc = client_data(client, RPC_TAG);
+ if (!rpc) {
+ DbgPrint("Client has no RPC\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ return rpc->handle;
+}
+
+/* End of a file */
diff --git a/src/conf.c b/src/conf.c
new file mode 100644
index 0000000..53941ca
--- /dev/null
+++ b/src/conf.c
@@ -0,0 +1,953 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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 <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <dlog.h>
+#if defined(HAVE_LIVEBOX)
+#include <livebox-errno.h>
+#else
+#include "lite-errno.h"
+#endif
+#include <Eina.h>
+
+#include "conf.h"
+#include "util.h"
+#include "debug.h"
+
+static const char *CONF_DEFAULT_SERVICES = "[livebox],[shortcut],[notification],[badge],[utility],[file]";
+static const char *CONF_DEFAULT_EMERGENCY_DISK = "source=tmpfs;type=tmpfs;option=size=6M";
+static const char *CONF_DEFAULT_PATH_CONF = "/opt/usr/live/%s/etc/%s.conf";
+static const char *CONF_DEFAULT_PATH_IMAGE = "/opt/usr/share/live_magazine/";
+static const char *CONF_DEFAULT_PATH_LOG = "/opt/usr/share/live_magazine/log";
+static const char *CONF_DEFAULT_PATH_READER = "/opt/usr/share/live_magazine/reader";
+static const char *CONF_DEFAULT_PATH_ALWAYS = "/opt/usr/share/live_magazine/always";
+static const char *CONF_DEFAULT_PATH_SCRIPT = "/opt/usr/live/%s/res/script/%s.edj";
+static const char *CONF_DEFAULT_PATH_ROOT = "/opt/usr/live/";
+static const char *CONF_DEFAULT_PATH_SCRIPT_PORT = "/usr/share/data-provider-master/plugin-script/";
+static const char *CONF_DEFAULT_PATH_DB = "/opt/dbspace/.livebox.db";
+static const char *CONF_DEFAULT_PATH_INPUT = "/dev/input/event2";
+static const char *CONF_DEFAULT_SCRIPT_TYPE = "edje";
+static const char *CONF_DEFAULT_ABI = "c";
+static const char *CONF_DEFAULT_PD_GROUP = "disclosure";
+static const char *CONF_DEFAULT_LAUNCH_BUNDLE_NAME = "name";
+static const char *CONF_DEFAULT_LAUNCH_BUNDLE_SECURED = "secured";
+static const char *CONF_DEFAULT_LAUNCH_BUNDLE_ABI = "abi";
+static const char *CONF_DEFAULT_CONTENT = "default";
+static const char *CONF_DEFAULT_TITLE = "";
+static const char *CONF_DEFAULT_EMPTY_CONTENT = "";
+static const char *CONF_DEFAULT_EMPTY_TITLE = "";
+static const char *CONF_DEFAULT_REPLACE_TAG = "/APPID/";
+static const char *CONF_DEFAULT_PROVIDER_METHOD = "pixmap";
+static const int CONF_DEFAULT_WIDTH = 0;
+static const int CONF_DEFAULT_HEIGHT = 0;
+static const int CONF_DEFAULT_BASE_WIDTH = 720;
+static const int CONF_DEFAULT_BASE_HEIGHT = 1280;
+static const double CONF_DEFAULT_MINIMUM_PERIOD = 1.0f;
+static const double CONF_DEFAULT_PERIOD = -1.0f;
+static const double CONF_DEFAULT_PACKET_TIME = 0.0001f;
+static const unsigned long CONF_DEFAULT_MINIMUM_SPACE = 5242880;
+static const double CONF_DEFAULT_SLAVE_TTL = 30.0f;
+static const double CONF_DEFAULT_SLAVE_ACTIVATE_TIME = 30.0f;
+static const double CONF_DEFAULT_SLAVE_RELAUNCH_TIME = 3.0f;
+static const int CONF_DEFAULT_SLAVE_RELAUNCH_COUNT = 3;
+static const int CONF_DEFAULT_MAX_LOG_LINE = 1000;
+static const int CONF_DEFAULT_MAX_LOG_FILE = 3;
+static const int CONF_DEFAULT_SQLITE_FLUSH_MAX = 1048576;
+static const double CONF_DEFAULT_PING_TIME = 240.0f;
+static const int CONF_DEFAULT_SLAVE_MAX_LOAD = 30;
+static const int CONF_DEFAULT_USE_SW_BACKEND = 0;
+static const int CONF_DEFAULT_DEBUG_MODE = 0;
+static const int CONF_DEFAULT_OVERWRITE_CONTENT = 0;
+static const int CONF_DEFAULT_COM_CORE_THREAD = 1;
+static const int CONF_DEFAULT_USE_XMONITOR = 0;
+static const int CONF_DEFAULT_PREMULTIPLIED = 1;
+static const double CONF_DEFAULT_SCALE_WIDTH_FACTOR = 1.0f;
+static const double CONF_DEFAULT_SCALE_HEIGHT_FACTOR = 1.0f;
+static const double CONF_DEFAULT_PD_REQUEST_TIMEOUT = 5.0f;
+static const int CONF_DEFAULT_PIXELS = sizeof(int);
+
+int errno;
+
+HAPI struct conf g_conf;
+
+HAPI void conf_update_size(void)
+{
+ util_screen_size_get(&g_conf.width, &g_conf.height);
+
+ g_conf.scale_width_factor = (double)g_conf.width / (double)BASE_W;
+ g_conf.scale_height_factor = (double)g_conf.height / (double)BASE_H;
+}
+
+static void use_xmonitor(char *buffer)
+{
+ g_conf.use_xmonitor = !strcasecmp(buffer, "true");
+}
+
+static void emergency_disk_handler(char *buffer)
+{
+ g_conf.emergency_disk = strdup(buffer);
+ if (!g_conf.emergency_disk) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ }
+}
+
+static void services_handler(char *buffer)
+{
+ g_conf.services = strdup(buffer);
+ if (!g_conf.services) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ }
+}
+
+static void use_sw_backend_handler(char *buffer)
+{
+ g_conf.use_sw_backend = !strcasecmp(buffer, "true");
+}
+
+static void provider_method_handler(char *buffer)
+{
+ g_conf.provider_method = strdup(buffer);
+ if (!g_conf.provider_method) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ }
+}
+
+static void debug_mode_handler(char *buffer)
+{
+ g_conf.debug_mode = !strcasecmp(buffer, "true");
+}
+
+static void overwrite_content_handler(char *buffer)
+{
+ g_conf.overwrite_content = !strcasecmp(buffer, "true");
+}
+
+static void com_core_thread_handler(char *buffer)
+{
+ g_conf.com_core_thread = !strcasecmp(buffer, "true");
+}
+
+static void base_width_handler(char *buffer)
+{
+ if (sscanf(buffer, "%d", &g_conf.base_width) != 1) {
+ ErrPrint("Failed to parse the base_width\n");
+ }
+}
+
+static void base_height_handler(char *buffer)
+{
+ if (sscanf(buffer, "%d", &g_conf.base_height) != 1) {
+ ErrPrint("Failed to parse the base_height\n");
+ }
+}
+
+static void minimum_period_handler(char *buffer)
+{
+ if (sscanf(buffer, "%lf", &g_conf.minimum_period) != 1) {
+ ErrPrint("Failed to parse the minimum_period\n");
+ }
+ DbgPrint("Minimum period: %lf\n", g_conf.minimum_period);
+}
+
+static void pixels_handler(char *buffer)
+{
+ if (sscanf(buffer, "%d", &g_conf.default_conf.pixels) != 1) {
+ ErrPrint("Failed to parse the minimum_period\n");
+ }
+ DbgPrint("Default pixels: %lf\n", g_conf.default_conf.pixels);
+}
+
+static void script_handler(char *buffer)
+{
+ g_conf.default_conf.script = strdup(buffer);
+ if (!g_conf.default_conf.script) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ }
+}
+
+static void default_abi_handler(char *buffer)
+{
+ g_conf.default_conf.abi = strdup(buffer);
+ if (!g_conf.default_conf.abi) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ }
+}
+
+static void default_group_handler(char *buffer)
+{
+ g_conf.default_conf.pd_group = strdup(buffer);
+ if (!g_conf.default_conf.pd_group) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ }
+}
+
+static void default_period_handler(char *buffer)
+{
+ if (sscanf(buffer, "%lf", &g_conf.default_conf.period) != 1) {
+ ErrPrint("Failed to parse the default_period\n");
+ }
+ DbgPrint("Default Period: %lf\n", g_conf.default_conf.period);
+}
+
+static void default_packet_time_handler(char *buffer)
+{
+ if (sscanf(buffer, "%lf", &g_conf.default_packet_time) != 1) {
+ ErrPrint("Failed to parse the default_packet_time\n");
+ }
+ DbgPrint("Default packet time: %lf\n", g_conf.default_packet_time);
+}
+
+static void default_content_handler(char *buffer)
+{
+ g_conf.default_content = strdup(buffer);
+ if (!g_conf.default_content) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ }
+}
+
+static void default_title_handler(char *buffer)
+{
+ g_conf.default_title = strdup(buffer);
+ if (!g_conf.default_title) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ }
+}
+
+static void minimum_space_handler(char *buffer)
+{
+ if (sscanf(buffer, "%lu", &g_conf.minimum_space) != 1) {
+ ErrPrint("Failed to parse the minimum_space\n");
+ }
+}
+
+static void replace_tag_handler(char *buffer)
+{
+ g_conf.replace_tag = strdup(buffer);
+ if (!g_conf.replace_tag) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ }
+}
+
+static void slave_ttl_handler(char *buffer)
+{
+ if (sscanf(buffer, "%lf", &g_conf.slave_ttl) != 1) {
+ ErrPrint("Failed to parse the slave_ttl\n");
+ }
+ DbgPrint("Slave TTL: %lf\n", g_conf.slave_ttl);
+}
+
+static void slave_activate_time_handler(char *buffer)
+{
+ if (sscanf(buffer, "%lf", &g_conf.slave_activate_time) != 1) {
+ ErrPrint("Failed to parse the slave_activate_time\n");
+ }
+ DbgPrint("Slave activate time: %lf\n", g_conf.slave_activate_time);
+}
+
+static void slave_relaunch_time_handler(char *buffer)
+{
+ if (sscanf(buffer, "%lf", &g_conf.slave_relaunch_time) != 1) {
+ ErrPrint("Failed to parse the slave_activate_time\n");
+ }
+ DbgPrint("Slave relaunch time: %lf\n", g_conf.slave_relaunch_time);
+}
+
+static void slave_relaunch_count_handler(char *buffer)
+{
+ if (sscanf(buffer, "%d", &g_conf.slave_relaunch_count) != 1) {
+ ErrPrint("Failed to parse the max_log_line\n");
+ }
+}
+
+static void max_log_line_handler(char *buffer)
+{
+ if (sscanf(buffer, "%d", &g_conf.max_log_line) != 1) {
+ ErrPrint("Failed to parse the max_log_line\n");
+ }
+}
+
+static void max_log_file_handler(char *buffer)
+{
+ if (sscanf(buffer, "%d", &g_conf.max_log_file) != 1) {
+ ErrPrint("Failed to parse the max_log_file\n");
+ }
+}
+
+static void sqlite_flush_max_handler(char *buffer)
+{
+ if (sscanf(buffer, "%lu", &g_conf.sqlite_flush_max) != 1) {
+ ErrPrint("Failed to parse the sqlite_flush_max\n");
+ }
+}
+
+static void db_path_handler(char *buffer)
+{
+ g_conf.path.db = strdup(buffer);
+ if (!g_conf.path.db) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ }
+}
+
+static void reader_path_handler(char *buffer)
+{
+ g_conf.path.reader = strdup(buffer);
+ if (!g_conf.path.reader) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ }
+}
+
+static void always_path_handler(char *buffer)
+{
+ g_conf.path.always = strdup(buffer);
+ if (!g_conf.path.always) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ }
+}
+
+static void log_path_handler(char *buffer)
+{
+ g_conf.path.slave_log = strdup(buffer);
+ if (!g_conf.path.slave_log) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ }
+}
+
+static void script_port_path_handler(char *buffer)
+{
+ g_conf.path.script_port = strdup(buffer);
+ if (!g_conf.path.script_port) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ }
+}
+
+static void share_path_handler(char *buffer)
+{
+ g_conf.path.image = strdup(buffer);
+ if (!g_conf.path.image) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ }
+}
+
+static void input_path_handler(char *buffer)
+{
+ g_conf.path.input = strdup(buffer);
+ if (!g_conf.path.input) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ }
+}
+
+static void ping_time_handler(char *buffer)
+{
+ if (sscanf(buffer, "%lf", &g_conf.ping_time) != 1) {
+ ErrPrint("Failed to parse the ping_time\n");
+ }
+ DbgPrint("Default ping time: %lf\n", g_conf.ping_time);
+}
+
+static void slave_max_loader(char *buffer)
+{
+ if (sscanf(buffer, "%d", &g_conf.slave_max_load) != 1) {
+ ErrPrint("Failed to parse the slave_max_load\n");
+ }
+}
+
+static void premultiplied_handler(char *buffer)
+{
+ if (sscanf(buffer, "%d", &g_conf.premultiplied) != 1) {
+ ErrPrint("Failed to parse the premultiplied color\n");
+ }
+
+ DbgPrint("Premultiplied: %d\n", g_conf.premultiplied);
+}
+
+static void pd_request_timeout_handler(char *buffer)
+{
+ if (sscanf(buffer, "%lf", &g_conf.pd_request_timeout) != 1) {
+ ErrPrint("Failed to parse the request_timeout\n");
+ }
+ DbgPrint("Default PD request timeout: %lf\n", g_conf.pd_request_timeout);
+}
+
+HAPI void conf_init(void)
+{
+ g_conf.width = CONF_DEFAULT_WIDTH;
+ g_conf.height = CONF_DEFAULT_HEIGHT;
+ g_conf.base_width = CONF_DEFAULT_BASE_WIDTH;
+ g_conf.base_height = CONF_DEFAULT_BASE_HEIGHT;
+ g_conf.minimum_period = CONF_DEFAULT_MINIMUM_PERIOD;
+ g_conf.default_conf.period = CONF_DEFAULT_PERIOD;
+ g_conf.default_conf.pixels = CONF_DEFAULT_PIXELS;
+ g_conf.minimum_space = CONF_DEFAULT_MINIMUM_SPACE;
+ g_conf.default_packet_time = CONF_DEFAULT_PACKET_TIME;
+ g_conf.slave_ttl = CONF_DEFAULT_SLAVE_TTL;
+ g_conf.slave_activate_time = CONF_DEFAULT_SLAVE_ACTIVATE_TIME;
+ g_conf.slave_relaunch_time = CONF_DEFAULT_SLAVE_RELAUNCH_TIME;
+ g_conf.slave_relaunch_count = CONF_DEFAULT_SLAVE_RELAUNCH_COUNT;
+ g_conf.max_log_line = CONF_DEFAULT_MAX_LOG_LINE;
+ g_conf.max_log_file = CONF_DEFAULT_MAX_LOG_FILE;
+ g_conf.sqlite_flush_max = CONF_DEFAULT_SQLITE_FLUSH_MAX;
+ g_conf.ping_time = CONF_DEFAULT_PING_TIME;
+ g_conf.slave_max_load = CONF_DEFAULT_SLAVE_MAX_LOAD;
+ g_conf.use_sw_backend = CONF_DEFAULT_USE_SW_BACKEND;
+ g_conf.debug_mode = CONF_DEFAULT_DEBUG_MODE;
+ g_conf.overwrite_content = CONF_DEFAULT_OVERWRITE_CONTENT;
+ g_conf.com_core_thread = CONF_DEFAULT_COM_CORE_THREAD;
+ g_conf.use_xmonitor = CONF_DEFAULT_USE_XMONITOR;
+ g_conf.scale_width_factor = CONF_DEFAULT_SCALE_WIDTH_FACTOR;
+ g_conf.scale_height_factor = CONF_DEFAULT_SCALE_HEIGHT_FACTOR;
+ g_conf.pd_request_timeout = CONF_DEFAULT_PD_REQUEST_TIMEOUT;
+ g_conf.premultiplied = CONF_DEFAULT_PREMULTIPLIED;
+ g_conf.default_conf.script = (char *)CONF_DEFAULT_SCRIPT_TYPE;
+ g_conf.default_conf.abi = (char *)CONF_DEFAULT_ABI;
+ g_conf.default_conf.pd_group = (char *)CONF_DEFAULT_PD_GROUP;
+ g_conf.launch_key.name = (char *)CONF_DEFAULT_LAUNCH_BUNDLE_NAME;
+ g_conf.launch_key.secured = (char *)CONF_DEFAULT_LAUNCH_BUNDLE_SECURED;
+ g_conf.launch_key.abi = (char *)CONF_DEFAULT_LAUNCH_BUNDLE_ABI;
+ g_conf.empty_content = (char *)CONF_DEFAULT_EMPTY_CONTENT;
+ g_conf.empty_title = (char *)CONF_DEFAULT_EMPTY_TITLE;
+ g_conf.default_content = (char *)CONF_DEFAULT_CONTENT;
+ g_conf.default_title = (char *)CONF_DEFAULT_TITLE;
+ g_conf.replace_tag = (char *)CONF_DEFAULT_REPLACE_TAG;
+ g_conf.path.conf = (char *)CONF_DEFAULT_PATH_CONF;
+ g_conf.path.image = (char *)CONF_DEFAULT_PATH_IMAGE;
+ g_conf.path.slave_log = (char *)CONF_DEFAULT_PATH_LOG;
+ g_conf.path.reader = (char *)CONF_DEFAULT_PATH_READER;
+ g_conf.path.always = (char *)CONF_DEFAULT_PATH_ALWAYS;
+ g_conf.path.script = (char *)CONF_DEFAULT_PATH_SCRIPT;
+ g_conf.path.root = (char *)CONF_DEFAULT_PATH_ROOT;
+ g_conf.path.script_port = (char *)CONF_DEFAULT_PATH_SCRIPT_PORT;
+ g_conf.path.db = (char *)CONF_DEFAULT_PATH_DB;
+ g_conf.path.input = (char *)CONF_DEFAULT_PATH_INPUT;
+ g_conf.provider_method = (char *)CONF_DEFAULT_PROVIDER_METHOD;
+ g_conf.emergency_disk = (char *)CONF_DEFAULT_EMERGENCY_DISK;
+ g_conf.services = (char *)CONF_DEFAULT_SERVICES;
+}
+
+HAPI int conf_loader(void)
+{
+ FILE *fp;
+ int c;
+ enum state {
+ START,
+ SPACE,
+ TOKEN,
+ VALUE,
+ ERROR,
+ COMMENT,
+ END
+ } state;
+ int ch_idx;
+ int token_idx;
+ int buffer_idx;
+ int quote;
+ int linelen;
+ char buffer[256];
+ static const struct token_parser {
+ const char *name;
+ void (*handler)(char *buffer);
+ } token_handler[] = {
+ {
+ .name = "base_width",
+ .handler = base_width_handler,
+ },
+ {
+ .name = "base_height",
+ .handler = base_height_handler,
+ },
+ {
+ .name = "minimum_period",
+ .handler = minimum_period_handler,
+ },
+ {
+ .name = "script",
+ .handler = script_handler,
+ },
+ {
+ .name = "pixels",
+ .handler = pixels_handler,
+ },
+ {
+ .name = "default_abi",
+ .handler = default_abi_handler,
+ },
+ {
+ .name = "default_group",
+ .handler = default_group_handler,
+ },
+ {
+ .name = "default_period",
+ .handler = default_period_handler,
+ },
+ {
+ .name = "default_packet_time",
+ .handler = default_packet_time_handler,
+ },
+ {
+ .name = "default_content",
+ .handler = default_content_handler,
+ },
+ {
+ .name = "default_title",
+ .handler = default_title_handler,
+ },
+ {
+ .name = "minimum_space",
+ .handler = minimum_space_handler,
+ },
+ {
+ .name = "replace_tag",
+ .handler = replace_tag_handler,
+ },
+ {
+ .name = "slave_ttl",
+ .handler = slave_ttl_handler,
+ },
+ {
+ .name = "slave_activate_time",
+ .handler = slave_activate_time_handler,
+ },
+ {
+ .name = "slave_relaunch_time",
+ .handler = slave_relaunch_time_handler,
+ },
+ {
+ .name = "slave_relaunch_count",
+ .handler = slave_relaunch_count_handler,
+ },
+ {
+ .name = "max_log_line",
+ .handler = max_log_line_handler,
+ },
+ {
+ .name = "max_log_file",
+ .handler = max_log_file_handler,
+ },
+ {
+ .name = "sqilte_flush_max",
+ .handler = sqlite_flush_max_handler,
+ },
+ {
+ .name = "db_path",
+ .handler = db_path_handler,
+ },
+ {
+ .name = "log_path",
+ .handler = log_path_handler,
+ },
+ {
+ .name = "reader_path",
+ .handler = reader_path_handler,
+ },
+ {
+ .name = "always_path",
+ .handler = always_path_handler,
+ },
+ {
+ .name = "share_path",
+ .handler = share_path_handler,
+ },
+ {
+ .name = "script_port_path",
+ .handler = script_port_path_handler,
+ },
+ {
+ .name = "ping_interval",
+ .handler = ping_time_handler,
+ },
+ {
+ .name = "slave_max_load",
+ .handler = slave_max_loader,
+ },
+ {
+ .name = "use_sw_backend",
+ .handler = use_sw_backend_handler,
+ },
+ {
+ .name = "emergency_disk",
+ .handler = emergency_disk_handler,
+ },
+ {
+ .name = "services",
+ .handler = services_handler,
+ },
+ {
+ .name = "use_xmonitor",
+ .handler = use_xmonitor,
+ },
+ {
+ .name = "provider_method",
+ .handler = provider_method_handler,
+ },
+ {
+ .name = "debug_mode",
+ .handler = debug_mode_handler,
+ },
+ {
+ .name = "overwrite_content",
+ .handler = overwrite_content_handler,
+ },
+ {
+ .name = "com_core_thread",
+ .handler = com_core_thread_handler,
+ },
+ {
+ .name = "input",
+ .handler = input_path_handler,
+ },
+ {
+ .name = "pd_request_timeout",
+ .handler = pd_request_timeout_handler,
+ },
+ {
+ .name = "premultiplied",
+ .handler = premultiplied_handler,
+ },
+ {
+ .name = NULL,
+ .handler = NULL,
+ },
+ };
+
+ fp = fopen(DEFAULT_MASTER_CONF, "rt");
+ if (!fp) {
+ ErrPrint("Error: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_IO;
+ }
+
+ state = START;
+ ch_idx = 0;
+ token_idx = -1;
+ buffer_idx = 0;
+ quote = 0;
+ linelen = 0;
+ do {
+ c = getc(fp);
+ if ((c == EOF) && (state == VALUE)) {
+ DbgPrint("[%s:%d] VALUE state EOF\n", __func__, __LINE__);
+ state = END;
+ }
+
+ switch (state) {
+ case COMMENT:
+ if (c == CR || c == LF || c == EOF) {
+ buffer[buffer_idx] = '\0';
+
+ state = START;
+ token_idx = -1;
+ ch_idx = 0;
+ buffer_idx = 0;
+ linelen = -1; /* Will be ZERO by follwing increment code */
+ quote = 0;
+ } else {
+ buffer[buffer_idx++] = c;
+ if (buffer_idx == (sizeof(buffer) - 1)) {
+ buffer[buffer_idx] = '\0';
+ buffer_idx = 0;
+ }
+ }
+ break;
+ case START:
+ if (linelen == 0 && c == '#') {
+ state = COMMENT;
+ } else if (isspace(c)) {
+ /* Ignore empty space */
+ } else {
+ state = TOKEN;
+ ungetc(c, fp);
+ }
+ break;
+ case SPACE:
+ if (c == '=') {
+ state = VALUE;
+ } else if (!isspace(c)) {
+ state = ERROR;
+ }
+ break;
+ case VALUE:
+ if (c == '"') {
+ if (quote == 1) {
+ buffer[buffer_idx] = '\0';
+ state = END;
+ } else if (buffer_idx != 0) {
+ buffer[buffer_idx++] = c;
+ if (buffer_idx >= sizeof(buffer)) {
+ state = ERROR;
+ }
+ } else {
+ quote = 1;
+ }
+ } else if (isspace(c)) {
+ if (buffer_idx == 0) {
+ /* Ignore */
+ } else if (quote == 1) {
+ buffer[buffer_idx++] = c;
+ if (buffer_idx >= sizeof(buffer)) {
+ state = ERROR;
+ }
+ } else {
+ buffer[buffer_idx] = '\0';
+ ungetc(c, fp);
+ state = END;
+ }
+ } else {
+ buffer[buffer_idx++] = c;
+ if (buffer_idx >= sizeof(buffer)) {
+ state = ERROR;
+ }
+ }
+ break;
+ case TOKEN:
+ if (c == '=') {
+ if (token_idx < 0) {
+ state = ERROR;
+ } else {
+ state = VALUE;
+ }
+ } else if (isspace(c)) {
+ if (token_idx < 0) {
+ break;
+ }
+
+ if (token_handler[token_idx].name[ch_idx] != '\0') {
+ state = ERROR;
+ } else {
+ state = SPACE;
+ }
+ } else {
+ if (token_idx < 0) {
+ /* Now start to find a token! */
+ token_idx = 0;
+ }
+
+ if (token_handler[token_idx].name[ch_idx] == c) {
+ ch_idx++;
+ } else {
+ ungetc(c, fp);
+ while (ch_idx-- > 0)
+ ungetc(token_handler[token_idx].name[ch_idx], fp);
+
+ token_idx++;
+
+ if (token_handler[token_idx].name == NULL) {
+ state = ERROR;
+ } else {
+ ch_idx = 0;
+ }
+ }
+ }
+ break;
+ case ERROR:
+ if (c == CR || c == LF || c == EOF) {
+ state = START;
+ token_idx = -1;
+ buffer_idx = 0;
+ ch_idx = 0;
+ linelen = -1;
+ quote = 0;
+ }
+ break;
+ case END:
+ if (c == LF || c == CR || c == EOF) {
+ state = START;
+
+ if (token_idx >= 0 && token_handler[token_idx].handler) {
+ buffer[buffer_idx] = '\0';
+ token_handler[token_idx].handler(buffer);
+ }
+
+ token_idx = -1;
+ ch_idx = 0;
+ buffer_idx = 0;
+ linelen = -1;
+ quote = 0;
+ /* Finish */
+ } else if (isspace(c)) {
+ /* ignore */
+ } else {
+ state = ERROR;
+ }
+ break;
+ default:
+ /* ?? */
+ break;
+ }
+
+ linelen++;
+ } while (c != EOF);
+
+ if (fclose(fp) != 0) {
+ ErrPrint("fclose: %s\n", strerror(errno));
+ }
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI void conf_reset(void)
+{
+ g_conf.width = CONF_DEFAULT_WIDTH;
+ g_conf.height = CONF_DEFAULT_HEIGHT;
+ g_conf.base_width = CONF_DEFAULT_BASE_WIDTH;
+ g_conf.base_height = CONF_DEFAULT_BASE_HEIGHT;
+ g_conf.minimum_period = CONF_DEFAULT_MINIMUM_PERIOD;
+ g_conf.default_conf.period = CONF_DEFAULT_PERIOD;
+ g_conf.minimum_space = CONF_DEFAULT_MINIMUM_SPACE;
+ g_conf.default_packet_time = CONF_DEFAULT_PACKET_TIME;
+ g_conf.slave_ttl = CONF_DEFAULT_SLAVE_TTL;
+ g_conf.slave_activate_time = CONF_DEFAULT_SLAVE_ACTIVATE_TIME;
+ g_conf.slave_relaunch_time = CONF_DEFAULT_SLAVE_RELAUNCH_TIME;
+ g_conf.slave_relaunch_count = CONF_DEFAULT_SLAVE_RELAUNCH_COUNT;
+ g_conf.max_log_line = CONF_DEFAULT_MAX_LOG_LINE;
+ g_conf.max_log_file = CONF_DEFAULT_MAX_LOG_FILE;
+ g_conf.sqlite_flush_max = CONF_DEFAULT_SQLITE_FLUSH_MAX;
+ g_conf.ping_time = CONF_DEFAULT_PING_TIME;
+ g_conf.slave_max_load = CONF_DEFAULT_SLAVE_MAX_LOAD;
+ g_conf.use_sw_backend = CONF_DEFAULT_USE_SW_BACKEND;
+ g_conf.debug_mode = CONF_DEFAULT_DEBUG_MODE;
+ g_conf.overwrite_content = CONF_DEFAULT_OVERWRITE_CONTENT;
+ g_conf.com_core_thread = CONF_DEFAULT_COM_CORE_THREAD;
+ g_conf.use_xmonitor = CONF_DEFAULT_USE_XMONITOR;
+ g_conf.scale_width_factor = CONF_DEFAULT_SCALE_WIDTH_FACTOR;
+ g_conf.scale_height_factor = CONF_DEFAULT_SCALE_HEIGHT_FACTOR;
+ g_conf.pd_request_timeout = CONF_DEFAULT_PD_REQUEST_TIMEOUT;
+ g_conf.premultiplied = CONF_DEFAULT_PREMULTIPLIED;
+ g_conf.default_conf.pixels = CONF_DEFAULT_PIXELS;
+
+ if (g_conf.default_conf.script != CONF_DEFAULT_SCRIPT_TYPE) {
+ DbgFree(g_conf.default_conf.script);
+ g_conf.default_conf.script = (char *)CONF_DEFAULT_SCRIPT_TYPE;
+ }
+
+ if (g_conf.default_conf.abi != CONF_DEFAULT_ABI) {
+ DbgFree(g_conf.default_conf.abi);
+ g_conf.default_conf.abi = (char *)CONF_DEFAULT_ABI;
+ }
+
+ if (g_conf.default_conf.pd_group != CONF_DEFAULT_PD_GROUP) {
+ DbgFree(g_conf.default_conf.pd_group);
+ g_conf.default_conf.pd_group = (char *)CONF_DEFAULT_PD_GROUP;
+ }
+
+ if (g_conf.launch_key.name != CONF_DEFAULT_LAUNCH_BUNDLE_NAME) {
+ DbgFree(g_conf.launch_key.name);
+ g_conf.launch_key.name = (char *)CONF_DEFAULT_LAUNCH_BUNDLE_NAME;
+ }
+
+ if (g_conf.launch_key.secured != CONF_DEFAULT_LAUNCH_BUNDLE_SECURED) {
+ DbgFree(g_conf.launch_key.secured);
+ g_conf.launch_key.secured = (char *)CONF_DEFAULT_LAUNCH_BUNDLE_SECURED;
+ }
+
+ if (g_conf.launch_key.abi != CONF_DEFAULT_LAUNCH_BUNDLE_ABI) {
+ DbgFree(g_conf.launch_key.abi);
+ g_conf.launch_key.abi = (char *)CONF_DEFAULT_LAUNCH_BUNDLE_ABI;
+ }
+
+ if (g_conf.empty_content != CONF_DEFAULT_EMPTY_CONTENT) {
+ DbgFree(g_conf.empty_content);
+ g_conf.empty_content = (char *)CONF_DEFAULT_EMPTY_CONTENT;
+ }
+
+ if (g_conf.empty_title != CONF_DEFAULT_EMPTY_TITLE) {
+ DbgFree(g_conf.empty_title);
+ g_conf.empty_title = (char *)CONF_DEFAULT_EMPTY_TITLE;
+ }
+
+ if (g_conf.default_content != CONF_DEFAULT_CONTENT) {
+ DbgFree(g_conf.default_content);
+ g_conf.default_content = (char *)CONF_DEFAULT_CONTENT;
+ }
+
+ if (g_conf.default_title != CONF_DEFAULT_TITLE) {
+ DbgFree(g_conf.default_title);
+ g_conf.default_title = (char *)CONF_DEFAULT_TITLE;
+ }
+
+ if (g_conf.replace_tag != CONF_DEFAULT_REPLACE_TAG) {
+ DbgFree(g_conf.replace_tag);
+ g_conf.replace_tag = (char *)CONF_DEFAULT_REPLACE_TAG;
+ }
+
+ if (g_conf.path.conf != CONF_DEFAULT_PATH_CONF) {
+ DbgFree(g_conf.path.conf);
+ g_conf.path.conf = (char *)CONF_DEFAULT_PATH_CONF;
+ }
+
+ if (g_conf.path.image != CONF_DEFAULT_PATH_IMAGE) {
+ DbgFree(g_conf.path.image);
+ g_conf.path.image = (char *)CONF_DEFAULT_PATH_IMAGE;
+ }
+
+ if (g_conf.path.slave_log != CONF_DEFAULT_PATH_LOG) {
+ DbgFree(g_conf.path.slave_log);
+ g_conf.path.slave_log = (char *)CONF_DEFAULT_PATH_LOG;
+ }
+
+ if (g_conf.path.reader != CONF_DEFAULT_PATH_READER) {
+ DbgFree(g_conf.path.reader);
+ g_conf.path.reader = (char *)CONF_DEFAULT_PATH_READER;
+ }
+
+ if (g_conf.path.always != CONF_DEFAULT_PATH_ALWAYS) {
+ DbgFree(g_conf.path.always);
+ g_conf.path.always = (char *)CONF_DEFAULT_PATH_ALWAYS;
+ }
+
+ if (g_conf.path.script != CONF_DEFAULT_PATH_SCRIPT) {
+ DbgFree(g_conf.path.script);
+ g_conf.path.script = (char *)CONF_DEFAULT_PATH_SCRIPT;
+ }
+
+ if (g_conf.path.root != CONF_DEFAULT_PATH_ROOT) {
+ DbgFree(g_conf.path.root);
+ g_conf.path.root = (char *)CONF_DEFAULT_PATH_ROOT;
+ }
+
+ if (g_conf.path.script_port != CONF_DEFAULT_PATH_SCRIPT_PORT) {
+ DbgFree(g_conf.path.script_port);
+ g_conf.path.script_port = (char *)CONF_DEFAULT_PATH_SCRIPT_PORT;
+ }
+
+ if (g_conf.path.db != CONF_DEFAULT_PATH_DB) {
+ DbgFree(g_conf.path.db);
+ g_conf.path.db = (char *)CONF_DEFAULT_PATH_DB;
+ }
+
+ if (g_conf.path.input != CONF_DEFAULT_PATH_INPUT) {
+ DbgFree(g_conf.path.input);
+ g_conf.path.input = (char *)CONF_DEFAULT_PATH_INPUT;
+ }
+
+ if (g_conf.provider_method != CONF_DEFAULT_PROVIDER_METHOD) {
+ DbgFree(g_conf.provider_method);
+ g_conf.provider_method = (char *)CONF_DEFAULT_PROVIDER_METHOD;
+ }
+
+ if (g_conf.emergency_disk != CONF_DEFAULT_EMERGENCY_DISK) {
+ DbgFree(g_conf.emergency_disk);
+ g_conf.emergency_disk = (char *)CONF_DEFAULT_EMERGENCY_DISK;
+ }
+
+ if (g_conf.services != CONF_DEFAULT_SERVICES) {
+ DbgFree(g_conf.services);
+ g_conf.services = (char *)CONF_DEFAULT_SERVICES;
+ }
+}
+
+/* End of a file */
diff --git a/src/critical_log.c b/src/critical_log.c
new file mode 100644
index 0000000..6bf10d6
--- /dev/null
+++ b/src/critical_log.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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 <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <string.h>
+#include <libgen.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <pthread.h>
+
+#include <dlog.h>
+#include <Eina.h>
+#if defined(HAVE_LIVEBOX)
+#include <livebox-errno.h>
+#else
+#include "lite-errno.h"
+#endif
+
+#include "conf.h"
+#include "debug.h"
+#include "util.h"
+#include "critical_log.h"
+
+static struct {
+ FILE *fp;
+ int file_id;
+ int nr_of_lines;
+ char *filename;
+ pthread_mutex_t cri_lock;
+} s_info = {
+ .fp = NULL,
+ .file_id = 0,
+ .nr_of_lines = 0,
+ .filename = NULL,
+ .cri_lock = PTHREAD_MUTEX_INITIALIZER,
+};
+
+
+
+static inline void rotate_log(void)
+{
+ char *filename;
+ int namelen;
+
+ if (s_info.nr_of_lines < MAX_LOG_LINE) {
+ return;
+ }
+
+ s_info.file_id = (s_info.file_id + 1) % MAX_LOG_FILE;
+
+ namelen = strlen(s_info.filename) + strlen(SLAVE_LOG_PATH) + 30;
+ filename = malloc(namelen);
+ if (filename) {
+ snprintf(filename, namelen, "%s/%d_%s.%d", SLAVE_LOG_PATH, s_info.file_id, s_info.filename, getpid());
+
+ if (s_info.fp) {
+ if (fclose(s_info.fp) != 0) {
+ ErrPrint("fclose: %s\n", strerror(errno));
+ }
+ }
+
+ s_info.fp = fopen(filename, "w+");
+ if (!s_info.fp) {
+ ErrPrint("Failed to open a file: %s\n", filename);
+ }
+
+ DbgFree(filename);
+ }
+
+ s_info.nr_of_lines = 0;
+}
+
+
+
+HAPI int critical_log(const char *func, int line, const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+
+ if (!s_info.fp) {
+ return LB_STATUS_ERROR_IO;
+ }
+
+ CRITICAL_SECTION_BEGIN(&s_info.cri_lock);
+
+ fprintf(s_info.fp, "%lf [%s:%d] ", util_timestamp(), util_basename((char *)func), line);
+
+ va_start(ap, fmt);
+ ret = vfprintf(s_info.fp, fmt, ap);
+ va_end(ap);
+
+ fflush(s_info.fp);
+
+ s_info.nr_of_lines++;
+ rotate_log();
+
+ CRITICAL_SECTION_END(&s_info.cri_lock);
+ return ret;
+}
+
+
+
+HAPI int critical_log_init(const char *name)
+{
+ int namelen;
+ char *filename;
+
+ if (s_info.fp) {
+ return LB_STATUS_SUCCESS;
+ }
+
+ s_info.filename = strdup(name);
+ if (!s_info.filename) {
+ ErrPrint("Failed to create a log file\n");
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ namelen = strlen(name) + strlen(SLAVE_LOG_PATH) + 30;
+
+ filename = malloc(namelen);
+ if (!filename) {
+ ErrPrint("Failed to create a log file\n");
+ DbgFree(s_info.filename);
+ s_info.filename = NULL;
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ snprintf(filename, namelen, "%s/%d_%s.%d", SLAVE_LOG_PATH, s_info.file_id, name, getpid());
+
+ s_info.fp = fopen(filename, "w+");
+ if (!s_info.fp) {
+ ErrPrint("Failed to open log: %s\n", strerror(errno));
+ DbgFree(s_info.filename);
+ s_info.filename = NULL;
+ DbgFree(filename);
+ return LB_STATUS_ERROR_IO;
+ }
+
+ DbgFree(filename);
+ return LB_STATUS_SUCCESS;
+}
+
+
+
+HAPI void critical_log_fini(void)
+{
+ if (s_info.filename) {
+ DbgFree(s_info.filename);
+ s_info.filename = NULL;
+ }
+
+ if (s_info.fp) {
+ if (fclose(s_info.fp) != 0) {
+ ErrPrint("fclose: %s\n", strerror(errno));
+ }
+ s_info.fp = NULL;
+ }
+}
+
+
+
+/* End of a file */
diff --git a/src/dead_monitor.c b/src/dead_monitor.c
new file mode 100644
index 0000000..313327f
--- /dev/null
+++ b/src/dead_monitor.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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 <stdio.h>
+#include <unistd.h>
+
+#include <gio/gio.h>
+#include <packet.h>
+#include <com-core.h>
+#include <dlog.h>
+
+#include <Eina.h>
+
+#include "slave_life.h"
+#include "client_life.h"
+#include "instance.h"
+#include "fault_manager.h"
+#include "util.h"
+#include "debug.h"
+#include "liveinfo.h"
+#include "conf.h"
+
+static int evt_cb(int handle, void *data)
+{
+ struct slave_node *slave;
+ struct client_node *client;
+ struct liveinfo *liveinfo;
+
+ slave = slave_find_by_rpc_handle(handle);
+ if (slave) {
+ if (slave_pid(slave) != (pid_t)-1) {
+ switch (slave_state(slave)) {
+ case SLAVE_REQUEST_TO_DISCONNECT:
+ DbgPrint("Disconnected from %d\n", slave_pid(slave));
+ case SLAVE_REQUEST_TO_TERMINATE:
+ slave = slave_deactivated(slave);
+ break;
+ default:
+ slave = slave_deactivated_by_fault(slave);
+ break;
+ }
+ }
+
+ if (!slave) {
+ DbgPrint("Slave is deleted\n");
+ }
+
+ return 0;
+ }
+
+ client = client_find_by_rpc_handle(handle);
+ if (client) {
+ if (client_pid(client) != (pid_t)-1) {
+ client = client_deactivated_by_fault(client);
+ }
+
+ if (!client) {
+ DbgPrint("Client is deleted\n");
+ }
+
+ return 0;
+ }
+
+ liveinfo = liveinfo_find_by_handle(handle);
+ if (liveinfo) {
+ liveinfo_destroy(liveinfo);
+ return 0;
+ }
+
+ return 0;
+}
+
+HAPI int dead_init(void)
+{
+ com_core_add_event_callback(CONNECTOR_DISCONNECTED, evt_cb, NULL);
+ return 0;
+}
+
+HAPI int dead_fini(void)
+{
+ com_core_del_event_callback(CONNECTOR_DISCONNECTED, evt_cb, NULL);
+ return 0;
+}
+
+/* End of a file */
diff --git a/src/event.c b/src/event.c
new file mode 100644
index 0000000..0604c11
--- /dev/null
+++ b/src/event.c
@@ -0,0 +1,676 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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 <stdio.h>
+#include <errno.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <linux/input.h>
+
+#include <Eina.h>
+#include <Ecore.h>
+#include <dlog.h>
+#include <livebox-errno.h>
+
+#include "util.h"
+#include "debug.h"
+#include "conf.h"
+#include "event.h"
+
+#define EVENT_CH 'e'
+
+#if !defined(ABS_MT_TOOL_X)
+#define ABS_MT_TOOL_X 0x3c /* Center X tool position */
+#endif
+
+#if !defined(ABS_MT_TOOL_Y)
+#define ABS_MT_TOOL_Y 0x3d /* Center Y tool position */
+#endif
+
+int errno;
+
+static struct info {
+ pthread_t tid;
+ Eina_List *event_list;
+ int handle;
+ pthread_mutex_t event_list_lock;
+ int evt_pipe[PIPE_MAX];
+ int tcb_pipe[PIPE_MAX];
+ Ecore_Fd_Handler *event_handler;
+
+ struct event_data event_data;
+
+ Eina_List *event_listener_list;
+ Eina_List *reactivate_list;
+} s_info = {
+ .event_list = NULL,
+ .handle = -1,
+ .event_handler = NULL,
+
+ .event_data = {
+ .x = -1,
+ .y = -1,
+ .device = -1,
+ .slot = -1,
+ .keycode = 0,
+ },
+
+ .event_listener_list = NULL,
+ .reactivate_list = NULL,
+};
+
+struct event_listener {
+ int (*event_cb)(enum event_state state, struct event_data *event, void *data);
+ void *cbdata;
+
+ enum event_state state;
+
+#if defined(_USE_ECORE_TIME_GET)
+ double tv;
+#else
+ struct timeval tv; /* Recording Activate / Deactivate time */
+#endif
+ int x; /* RelX */
+ int y; /* RelY */
+};
+
+static int activate_thread(void);
+
+HAPI int event_init(void)
+{
+ int ret;
+ ret = pthread_mutex_init(&s_info.event_list_lock, NULL);
+ if (ret != 0) {
+ ErrPrint("Mutex: %s\n", strerror(ret));
+ return LB_STATUS_ERROR_FAULT;
+ }
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI int event_fini(void)
+{
+ int ret;
+ ret = pthread_mutex_destroy(&s_info.event_list_lock);
+ if (ret != 0) {
+ ErrPrint("Mutex destroy failed: %s\n", strerror(ret));
+ }
+ return LB_STATUS_SUCCESS;
+}
+
+static inline int processing_input_event(struct input_event *event)
+{
+ struct event_data *item;
+
+ switch (event->type) {
+ case EV_SYN:
+ switch (event->code) {
+ break;
+ case SYN_CONFIG:
+ break;
+ case SYN_MT_REPORT:
+ case SYN_REPORT:
+ if (s_info.event_data.x < 0 || s_info.event_data.y < 0) {
+ /* Waiting full event packet */
+ break;
+ }
+
+ item = malloc(sizeof(*item));
+ if (item) {
+ char event_ch = EVENT_CH;
+
+#if defined(_USE_ECORE_TIME_GET)
+ s_info.event_data.tv = ecore_time_get();
+#else
+ if (gettimeofday(&s_info.event_data.tv, NULL) < 0) {
+ ErrPrint("gettimeofday: %s\n", strerror(errno));
+ }
+#endif
+
+ memcpy(item, &s_info.event_data, sizeof(*item));
+
+ CRITICAL_SECTION_BEGIN(&s_info.event_list_lock);
+ s_info.event_list = eina_list_append(s_info.event_list, item);
+ CRITICAL_SECTION_END(&s_info.event_list_lock);
+
+ if (write(s_info.evt_pipe[PIPE_WRITE], &event_ch, sizeof(event_ch)) != sizeof(event_ch)) {
+ ErrPrint("Unable to send an event: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_IO;
+ }
+
+ /* Take a breathe */
+ pthread_yield();
+ } else {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ }
+
+ if (s_info.event_data.device < 0) {
+ s_info.event_data.x = -1;
+ s_info.event_data.y = -1;
+ s_info.event_data.slot = -1;
+ }
+ break;
+ /*
+ case SYN_DROPPED:
+ DbgPrint("EV_SYN, SYN_DROPPED\n");
+ break;
+ */
+ default:
+ DbgPrint("EV_SYN, 0x%x\n", event->code);
+ break;
+ }
+ break;
+ case EV_KEY:
+ DbgPrint("EV_KEY: 0x%X\n", event->value);
+ s_info.event_data.keycode = event->value;
+ break;
+ case EV_REL:
+ break;
+ case EV_ABS:
+ switch (event->code) {
+ case ABS_DISTANCE:
+ s_info.event_data.distance = event->value;
+ break;
+ case ABS_MT_TOOL_X:
+ case ABS_MT_TOOL_Y:
+ break;
+ case ABS_MT_POSITION_X:
+ s_info.event_data.x = event->value;
+ break;
+ case ABS_MT_POSITION_Y:
+ s_info.event_data.y = event->value;
+ break;
+ case ABS_MT_SLOT:
+ s_info.event_data.slot = event->value;
+ break;
+ case ABS_MT_TRACKING_ID:
+ s_info.event_data.device = event->value;
+ break;
+ case ABS_MT_TOUCH_MAJOR:
+ s_info.event_data.touch.major = event->value;
+ break;
+ case ABS_MT_TOUCH_MINOR:
+ s_info.event_data.touch.minor = event->value;
+ break;
+ case ABS_MT_WIDTH_MAJOR:
+ s_info.event_data.width.major = event->value;
+ break;
+ case ABS_MT_WIDTH_MINOR:
+ s_info.event_data.width.minor = event->value;
+ break;
+ default:
+ DbgPrint("EV_ABS, 0x%x\n", event->code);
+ break;
+ }
+ break;
+ case EV_MSC:
+ break;
+ case EV_SW:
+ break;
+ case EV_LED:
+ break;
+ case EV_SND:
+ break;
+ case EV_REP:
+ break;
+ case EV_FF:
+ break;
+ case EV_PWR:
+ break;
+ case EV_FF_STATUS:
+ break;
+ default:
+ DbgPrint("0x%X, 0x%X\n", event->type, event->code);
+ break;
+ }
+
+ return LB_STATUS_SUCCESS;
+}
+
+static void *event_thread_main(void *data)
+{
+ fd_set set;
+ long ret = 0;
+ struct input_event input_event;
+ char *ptr = (char *)&input_event;
+ int offset = 0;
+ int readsize = 0;
+ int fd;
+
+ DbgPrint("Initiated\n");
+
+ while (1) {
+ FD_ZERO(&set);
+ FD_SET(s_info.handle, &set);
+ FD_SET(s_info.tcb_pipe[PIPE_READ], &set);
+
+ fd = s_info.handle > s_info.tcb_pipe[PIPE_READ] ? s_info.handle : s_info.tcb_pipe[PIPE_READ];
+ ret = select(fd + 1, &set, NULL, NULL, NULL);
+ if (ret < 0) {
+ ret = -errno;
+ if (errno == EINTR) {
+ DbgPrint("Select receives INTR\n");
+ continue;
+ }
+ ErrPrint("Error: %s\n", strerror(errno));
+ break;
+ } else if (ret == 0) {
+ ErrPrint("Timeout expired\n");
+ ret = LB_STATUS_ERROR_TIMEOUT;
+ break;
+ }
+
+ if (FD_ISSET(s_info.handle, &set)) {
+ readsize = read(s_info.handle, ptr + offset, sizeof(input_event) - offset);
+ if (readsize < 0) {
+ ErrPrint("Unable to read device: %s / fd: %d / offset: %d / size: %d - %d\n", strerror(errno), s_info.handle, offset, sizeof(input_event), readsize);
+ ret = LB_STATUS_ERROR_FAULT;
+ break;
+ }
+
+ offset += readsize;
+ if (offset == sizeof(input_event)) {
+ offset = 0;
+ if (processing_input_event(&input_event) < 0) {
+ ret = LB_STATUS_ERROR_FAULT;
+ break;
+ }
+ }
+ }
+
+ if (FD_ISSET(s_info.tcb_pipe[PIPE_READ], &set)) {
+ char event_ch;
+
+ if (read(s_info.tcb_pipe[PIPE_READ], &event_ch, sizeof(event_ch)) != sizeof(event_ch)) {
+ ErrPrint("Unable to read TCB_PIPE: %s\n", strerror(errno));
+ }
+
+ ret = LB_STATUS_ERROR_CANCEL;
+ break;
+ }
+ }
+
+ return (void *)ret;
+}
+
+static inline void clear_all_listener_list(void)
+{
+ struct event_listener *listener;
+ enum event_state next_state;
+ Eina_List *l;
+ Eina_List *n;
+
+ s_info.event_handler = NULL;
+ CLOSE_PIPE(s_info.evt_pipe);
+
+ while (s_info.event_listener_list) {
+ EINA_LIST_FOREACH_SAFE(s_info.event_listener_list, l, n, listener) {
+ switch (listener->state) {
+ case EVENT_STATE_ACTIVATE:
+ next_state = EVENT_STATE_ACTIVATED;
+ break;
+ case EVENT_STATE_ACTIVATED:
+ next_state = EVENT_STATE_DEACTIVATE;
+ break;
+ case EVENT_STATE_DEACTIVATE:
+ next_state = EVENT_STATE_DEACTIVATED;
+ break;
+ case EVENT_STATE_DEACTIVATED:
+ default:
+ s_info.event_listener_list = eina_list_remove(s_info.event_listener_list, listener);
+ DbgFree(listener);
+ continue;
+ }
+
+ if (listener->event_cb(listener->state, &s_info.event_data, listener->cbdata) < 0) {
+ if (eina_list_data_find(s_info.event_listener_list, listener)) {
+ s_info.event_listener_list = eina_list_remove(s_info.event_listener_list, listener);
+ DbgFree(listener);
+ continue;
+ }
+ }
+
+ listener->state = next_state;
+ }
+ }
+}
+
+static Eina_Bool event_read_cb(void *data, Ecore_Fd_Handler *handler)
+{
+ int fd;
+ struct event_data *item;
+ char event_ch;
+ struct event_listener *listener;
+ Eina_List *l;
+ Eina_List *n;
+ enum event_state next_state;
+ enum event_state cur_state;
+ struct event_data modified_item;
+
+ fd = ecore_main_fd_handler_fd_get(handler);
+ if (fd < 0) {
+ ErrPrint("Invalid fd\n");
+ return ECORE_CALLBACK_CANCEL;
+ }
+
+ if (read(fd, &event_ch, sizeof(event_ch)) != sizeof(event_ch)) {
+ ErrPrint("Unable to read event ch: %s\n", strerror(errno));
+ return ECORE_CALLBACK_CANCEL;
+ }
+
+ CRITICAL_SECTION_BEGIN(&s_info.event_list_lock);
+ item = eina_list_nth(s_info.event_list, 0);
+ if (item) {
+ s_info.event_list = eina_list_remove(s_info.event_list, item);
+ }
+ CRITICAL_SECTION_END(&s_info.event_list_lock);
+
+ if (item) {
+ EINA_LIST_FOREACH_SAFE(s_info.event_listener_list, l, n, listener) {
+ switch (listener->state) {
+ case EVENT_STATE_ACTIVATE:
+#if defined(_USE_ECORE_TIME_GET)
+ if (listener->tv > item->tv) {
+ continue;
+ }
+#else
+ if (timercmp(&listener->tv, &item->tv, >)) {
+ /* Ignore previous events before activating this listener */
+ continue;
+ }
+#endif
+
+ next_state = EVENT_STATE_ACTIVATED;
+ cur_state = listener->state;
+ break;
+ case EVENT_STATE_DEACTIVATE:
+#if defined(_USE_ECORE_TIME_GET)
+ if (listener->tv > item->tv) {
+ /* Consuming all events occurred while activating this listener */
+ cur_state = EVENT_STATE_ACTIVATED;
+ next_state = EVENT_STATE_ACTIVATED;
+ break;
+ }
+#else
+ if (timercmp(&listener->tv, &item->tv, >)) {
+ /* Consuming all events occurred while activating this listener */
+ cur_state = EVENT_STATE_ACTIVATED;
+ next_state = EVENT_STATE_ACTIVATED;
+ break;
+ }
+#endif
+
+ cur_state = listener->state;
+ next_state = EVENT_STATE_DEACTIVATED;
+ break;
+ case EVENT_STATE_ACTIVATED:
+ cur_state = listener->state;
+ next_state = listener->state;
+ break;
+ case EVENT_STATE_DEACTIVATED:
+ default:
+ /* Remove this from the list */
+ /* Check the item again. the listener can be deleted from the callback */
+ if (eina_list_data_find(s_info.event_listener_list, listener)) {
+ s_info.event_listener_list = eina_list_remove(s_info.event_listener_list, listener);
+ DbgFree(listener);
+ }
+
+ continue;
+ }
+
+ memcpy(&modified_item, item, sizeof(modified_item));
+ modified_item.x -= listener->x;
+ modified_item.y -= listener->y;
+
+ if (listener->event_cb(cur_state, &modified_item, listener->cbdata) < 0) {
+ if (eina_list_data_find(s_info.event_listener_list, listener)) {
+ s_info.event_listener_list = eina_list_remove(s_info.event_listener_list, listener);
+ DbgFree(listener);
+ continue;
+ }
+ }
+
+ listener->state = next_state;
+ }
+
+ DbgFree(item);
+ }
+
+ if (s_info.handle < 0 && !s_info.event_list) {
+ /* This callback must has to clear all listeners in this case */
+ clear_all_listener_list();
+
+ EINA_LIST_FREE(s_info.reactivate_list, listener) {
+ s_info.event_listener_list = eina_list_append(s_info.event_listener_list, listener);
+ }
+
+ if (s_info.event_listener_list) {
+ if (activate_thread() < 0) {
+ EINA_LIST_FREE(s_info.event_listener_list, listener) {
+ (void)listener->event_cb(EVENT_STATE_ERROR, NULL, listener->cbdata);
+ }
+ }
+ }
+
+ return ECORE_CALLBACK_CANCEL;
+ }
+
+ return ECORE_CALLBACK_RENEW;
+}
+
+static int activate_thread(void)
+{
+ int status;
+
+ s_info.handle = open(INPUT_PATH, O_RDONLY);
+ if (s_info.handle < 0) {
+ ErrPrint("Unable to access the device: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_IO;
+ }
+
+ if (fcntl(s_info.handle, F_SETFD, FD_CLOEXEC) < 0) {
+ ErrPrint("Error: %s\n", strerror(errno));
+ }
+
+ if (fcntl(s_info.handle, F_SETFL, O_NONBLOCK) < 0) {
+ ErrPrint("Error: %s\n", strerror(errno));
+ }
+
+ status = pipe2(s_info.evt_pipe, O_CLOEXEC);
+ if (status < 0) {
+ ErrPrint("Unable to prepare evt pipe: %s\n", strerror(errno));
+ if (close(s_info.handle) < 0) {
+ ErrPrint("Failed to close handle: %s\n", strerror(errno));
+ }
+ s_info.handle = -1;
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ status = pipe2(s_info.tcb_pipe, O_CLOEXEC);
+ if (status < 0) {
+ ErrPrint("Unable to prepare tcb pipe: %s\n", strerror(errno));
+ if (close(s_info.handle) < 0) {
+ ErrPrint("Failed to close handle: %s\n", strerror(errno));
+ }
+ s_info.handle = -1;
+ CLOSE_PIPE(s_info.evt_pipe);
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ s_info.event_handler = ecore_main_fd_handler_add(s_info.evt_pipe[PIPE_READ], ECORE_FD_READ, event_read_cb, NULL, NULL, NULL);
+ if (!s_info.event_handler) {
+ if (close(s_info.handle) < 0) {
+ ErrPrint("Failed to close handle: %s\n", strerror(errno));
+ }
+ s_info.handle = -1;
+
+ CLOSE_PIPE(s_info.tcb_pipe);
+ CLOSE_PIPE(s_info.evt_pipe);
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ status = pthread_create(&s_info.tid, NULL, event_thread_main, NULL);
+ if (status != 0) {
+ ErrPrint("Failed to initiate the thread: %s\n", strerror(status));
+ ecore_main_fd_handler_del(s_info.event_handler);
+ s_info.event_handler = NULL;
+
+ if (close(s_info.handle) < 0) {
+ ErrPrint("close: %s\n", strerror(errno));
+ }
+ s_info.handle = -1;
+
+ CLOSE_PIPE(s_info.tcb_pipe);
+ CLOSE_PIPE(s_info.evt_pipe);
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ DbgPrint("Event handler activated\n");
+ return LB_STATUS_SUCCESS;
+}
+
+/*!
+ * x, y is the starting point.
+ */
+HAPI int event_activate(int x, int y, int (*event_cb)(enum event_state state, struct event_data *event, void *data), void *data)
+{
+ struct event_listener *listener;
+ int ret = LB_STATUS_SUCCESS;
+
+ listener = malloc(sizeof(*listener));
+ if (!listener) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+#if defined(_USE_ECORE_TIME_GET)
+ listener->tv = ecore_time_get();
+#else
+ if (gettimeofday(&listener->tv, NULL) < 0) {
+ ErrPrint("gettimeofday: %s\n", strerror(errno));
+ DbgFree(listener);
+ return LB_STATUS_ERROR_FAULT;
+ }
+#endif
+
+ listener->event_cb = event_cb;
+ listener->cbdata = data;
+ listener->state = EVENT_STATE_ACTIVATE;
+ listener->x = x;
+ listener->y = y;
+
+ if (s_info.handle < 0) {
+ /*!
+ * \note
+ * We don't need to lock to access event_list here.
+ * If the _sinfo.handle is greater than 0, the event_list will not be touched.
+ * But if the s_info.handle is less than 0, it means, there is not thread,
+ * so we can access the event_list without lock.
+ */
+ if (s_info.event_list) {
+ DbgPrint("Event thread is deactivating now. activating will be delayed\n");
+ s_info.reactivate_list = eina_list_append(s_info.reactivate_list, listener);
+ } else {
+ s_info.event_listener_list = eina_list_append(s_info.event_listener_list, listener);
+
+ if ((ret = activate_thread()) < 0) {
+ s_info.event_listener_list = eina_list_remove(s_info.event_listener_list, listener);
+ DbgFree(listener);
+ }
+ }
+ } else {
+ s_info.event_listener_list = eina_list_append(s_info.event_listener_list, listener);
+ }
+
+ return ret;
+}
+
+HAPI int event_deactivate(int (*event_cb)(enum event_state state, struct event_data *event, void *data), void *data)
+{
+ int status;
+ void *ret;
+ char event_ch = EVENT_CH;
+ struct event_listener *listener = NULL;
+ Eina_List *l;
+ int keep_thread = 0;
+
+ EINA_LIST_FOREACH(s_info.event_listener_list, l, listener) {
+ if (listener->event_cb == event_cb && listener->cbdata == data) {
+ listener->state = EVENT_STATE_DEACTIVATE;
+ }
+
+ keep_thread += (listener->state == EVENT_STATE_ACTIVATE || listener->state == EVENT_STATE_ACTIVATED);
+ }
+
+ if (!listener) {
+ ErrPrint("Listener is not registered\n");
+ return LB_STATUS_ERROR_NOT_EXIST;
+ }
+
+ if (s_info.handle < 0) {
+ ErrPrint("Event handler is not actiavated\n");
+ DbgFree(listener);
+ return LB_STATUS_SUCCESS;
+ }
+
+ if (keep_thread) {
+ return LB_STATUS_SUCCESS;
+ }
+
+ /* Terminating thread */
+ if (write(s_info.tcb_pipe[PIPE_WRITE], &event_ch, sizeof(event_ch)) != sizeof(event_ch)) {
+ ErrPrint("Unable to write tcb_pipe: %s\n", strerror(errno));
+ }
+
+ status = pthread_join(s_info.tid, &ret);
+ if (status != 0) {
+ ErrPrint("Failed to join a thread: %s\n", strerror(errno));
+ } else {
+ DbgPrint("Thread returns: %p\n", ret);
+ }
+
+ if (close(s_info.handle) < 0) {
+ ErrPrint("Unable to release the fd: %s\n", strerror(errno));
+ }
+
+ s_info.handle = -1;
+ DbgPrint("Event handler deactivated\n");
+
+ CLOSE_PIPE(s_info.tcb_pipe);
+
+ if (!eina_list_count(s_info.event_list)) {
+ ecore_main_fd_handler_del(s_info.event_handler);
+ clear_all_listener_list();
+ }
+
+ s_info.event_data.x = -1;
+ s_info.event_data.y = -1;
+ s_info.event_data.slot = -1;
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI int event_is_activated(void)
+{
+ return s_info.handle >= 0;
+}
+
+/* End of a file */
diff --git a/src/fault_manager.c b/src/fault_manager.c
new file mode 100644
index 0000000..1ec4398
--- /dev/null
+++ b/src/fault_manager.c
@@ -0,0 +1,369 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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 <stdio.h>
+#include <string.h>
+#include <stdlib.h> /* free */
+
+#include <gio/gio.h>
+
+#include <Eina.h>
+#include <packet.h>
+#include <dlog.h>
+#include <livebox-errno.h>
+#include <livebox-service.h>
+
+#include "util.h"
+#include "debug.h"
+#include "slave_life.h"
+#include "slave_rpc.h"
+#include "client_life.h"
+#include "instance.h"
+#include "client_rpc.h"
+#include "package.h"
+#include "conf.h"
+#include "critical_log.h"
+
+static struct info {
+ Eina_List *call_list;
+ int fault_mark_count;
+} s_info = {
+ .call_list = NULL,
+ .fault_mark_count = 0,
+};
+
+struct fault_info {
+ struct slave_node *slave;
+ double timestamp;
+ char *pkgname;
+ char *filename;
+ char *func;
+};
+
+HAPI int const fault_is_occured(void)
+{
+ return s_info.fault_mark_count;
+}
+
+static void clear_log_file(struct slave_node *slave)
+{
+ char filename[BUFSIZ];
+ int ret;
+
+ ret = snprintf(filename, sizeof(filename) - 1, "%s/slave.%d", SLAVE_LOG_PATH, slave_pid(slave));
+ if (ret == sizeof(filename) - 1) {
+ filename[sizeof(filename) - 1] = '\0';
+ ErrPrint("filename buffer is overflowed\n");
+ }
+
+ if (unlink(filename) < 0) {
+ ErrPrint("unlink: %s\n", strerror(errno));
+ }
+}
+
+static char *check_log_file(struct slave_node *slave)
+{
+ char libexec[BUFSIZ];
+ char *ptr;
+ FILE *fp;
+ char filename[BUFSIZ];
+
+ snprintf(filename, sizeof(filename), "%s/slave.%d", SLAVE_LOG_PATH, slave_pid(slave));
+ fp = fopen(filename, "rt");
+ if (!fp) {
+ ErrPrint("No log file found [%s]\n", strerror(errno));
+ return NULL;
+ }
+
+ ptr = fgets(libexec, sizeof(libexec), fp);
+ if (fclose(fp) != 0) {
+ ErrPrint("fclose: %s\n", strerror(errno));
+ }
+
+ if (ptr != libexec) {
+ ErrPrint("Invalid log\n");
+ return NULL;
+ }
+
+ if (unlink(filename) < 0) {
+ ErrPrint("Failed to unlink %s\n", filename);
+ }
+
+ ptr = livebox_service_pkgname_by_libexec(libexec);
+ if (!ptr) {
+ ErrPrint("Failed to find the faulted package\n");
+ }
+
+ DbgPrint("Faulted package: %s\n", ptr);
+ return ptr;
+}
+
+HAPI void fault_unicast_info(struct client_node *client, const char *pkgname, const char *filename, const char *func)
+{
+ struct packet *packet;
+
+ if (!client || !pkgname || !filename || !func) {
+ return;
+ }
+
+ packet = packet_create_noack("fault_package", "sss", pkgname, filename, func);
+ if (!packet) {
+ return;
+ }
+
+ client_rpc_async_request(client, packet);
+}
+
+HAPI void fault_broadcast_info(const char *pkgname, const char *filename, const char *func)
+{
+ struct packet *packet;
+
+ packet = packet_create_noack("fault_package", "sss", pkgname, filename, func);
+ if (!packet) {
+ ErrPrint("Failed to create a param\n");
+ return;
+ }
+
+ client_broadcast(NULL, packet);
+}
+
+static inline void dump_fault_info(const char *name, pid_t pid, const char *pkgname, const char *filename, const char *funcname)
+{
+ CRITICAL_LOG("Slavename: %s[%d]\n" \
+ "Package: %s\n" \
+ "Filename: %s\n" \
+ "Funcname: %s\n", name, pid, pkgname, filename, funcname);
+}
+
+HAPI int fault_info_set(struct slave_node *slave, const char *pkgname, const char *id, const char *func)
+{
+ struct pkg_info *pkg;
+ int ret;
+
+ pkg = package_find(pkgname);
+ if (!pkg) {
+ return LB_STATUS_ERROR_NOT_EXIST;
+ }
+
+ ret = package_set_fault_info(pkg, util_timestamp(), id, func);
+ if (ret < 0) {
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ dump_fault_info(slave_name(slave), slave_pid(slave), pkgname, id, func);
+ ErrPrint("Set fault %s(%d)\n", !ret ? "Success" : "Failed", ret);
+ fault_broadcast_info(pkgname, id, func);
+
+ /*!
+ * \note
+ * Update statistics
+ */
+ s_info.fault_mark_count++;
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI int fault_check_pkgs(struct slave_node *slave)
+{
+ struct fault_info *info;
+ struct pkg_info *pkg;
+ const char *pkgname;
+ Eina_List *l;
+ Eina_List *n;
+ int checked;
+
+ /*!
+ * \note
+ * First step.
+ * Check the log file
+ */
+ pkgname = (const char *)check_log_file(slave);
+ if (pkgname) {
+ pkg = package_find(pkgname);
+ if (pkg) {
+ (void)package_set_fault_info(pkg, util_timestamp(), NULL, NULL);
+ dump_fault_info(slave_name(slave), slave_pid(slave), pkgname, "", "");
+ fault_broadcast_info(pkgname, "", "");
+ DbgFree((char *)pkgname);
+
+ s_info.fault_mark_count = 0;
+ clear_log_file(slave);
+ EINA_LIST_REVERSE_FOREACH_SAFE(s_info.call_list, l, n, info) {
+ if (info->slave != slave) {
+ continue;
+ }
+
+ s_info.call_list = eina_list_remove_list(s_info.call_list, l);
+
+ DbgFree(info->pkgname);
+ DbgFree(info->filename);
+ DbgFree(info->func);
+ DbgFree(info);
+ }
+ return 0;
+ }
+ DbgFree((char *)pkgname);
+ }
+
+ /*!
+ * \note
+ * Second step.
+ * Is it secured slave?
+ */
+ pkgname = package_find_by_secured_slave(slave);
+ if (pkgname) {
+ pkg = package_find(pkgname);
+ if (pkg) {
+ (void)package_set_fault_info(pkg, util_timestamp(), NULL, NULL);
+ dump_fault_info(slave_name(slave), slave_pid(slave), pkgname, "", "");
+ fault_broadcast_info(pkgname, "", "");
+
+ s_info.fault_mark_count = 0;
+ clear_log_file(slave);
+ EINA_LIST_REVERSE_FOREACH_SAFE(s_info.call_list, l, n, info) {
+ if (info->slave != slave) {
+ continue;
+ }
+
+ s_info.call_list = eina_list_remove_list(s_info.call_list, l);
+
+ DbgFree(info->pkgname);
+ DbgFree(info->filename);
+ DbgFree(info->func);
+ DbgFree(info);
+ }
+ return 0;
+ }
+ }
+
+ /*!
+ * \note
+ * At last, check the pair of function call and return mark
+ */
+ checked = 0;
+ EINA_LIST_REVERSE_FOREACH_SAFE(s_info.call_list, l, n, info) {
+ if (info->slave == slave) {
+ const char *filename;
+ const char *func;
+
+ pkg = package_find(info->pkgname);
+ if (!pkg) {
+ ErrPrint("Failed to find a package %s\n", info->pkgname);
+ continue;
+ }
+
+ filename = info->filename ? info->filename : "";
+ func = info->func ? info->func : "";
+
+ if (!checked) {
+ (void)package_set_fault_info(pkg, info->timestamp, info->filename, info->func);
+ fault_broadcast_info(info->pkgname, info->filename, info->func);
+ } else {
+ DbgPrint("Treated as a false log\n");
+ dump_fault_info(
+ slave_name(info->slave), slave_pid(info->slave), info->pkgname, filename, func);
+ }
+
+ s_info.call_list = eina_list_remove_list(s_info.call_list, l);
+
+ DbgFree(info->pkgname);
+ DbgFree(info->filename);
+ DbgFree(info->func);
+ DbgFree(info);
+ checked = 1;
+ }
+ }
+
+ s_info.fault_mark_count = 0;
+ clear_log_file(slave);
+ return 0;
+}
+
+HAPI int fault_func_call(struct slave_node *slave, const char *pkgname, const char *filename, const char *func)
+{
+ struct fault_info *info;
+
+ info = malloc(sizeof(*info));
+ if (!info) {
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ info->slave = slave;
+
+ info->pkgname = strdup(pkgname);
+ if (!info->pkgname) {
+ DbgFree(info);
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ info->filename = strdup(filename);
+ if (!info->filename) {
+ DbgFree(info->pkgname);
+ DbgFree(info);
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ info->func = strdup(func);
+ if (!info->func) {
+ DbgFree(info->filename);
+ DbgFree(info->pkgname);
+ DbgFree(info);
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ info->timestamp = util_timestamp();
+
+ s_info.call_list = eina_list_append(s_info.call_list, info);
+
+ s_info.fault_mark_count++;
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI int fault_func_ret(struct slave_node *slave, const char *pkgname, const char *filename, const char *func)
+{
+ struct fault_info *info;
+ Eina_List *l;
+
+ EINA_LIST_FOREACH(s_info.call_list, l, info) {
+ if (info->slave != slave) {
+ continue;
+ }
+
+ if (strcmp(info->pkgname, pkgname)) {
+ continue;
+ }
+
+ if (strcmp(info->filename, filename)) {
+ continue;
+ }
+
+ if (strcmp(info->func, func)) {
+ continue;
+ }
+
+ s_info.call_list = eina_list_remove_list(s_info.call_list, l);
+ DbgFree(info->filename);
+ DbgFree(info->pkgname);
+ DbgFree(info->func);
+ DbgFree(info);
+
+ s_info.fault_mark_count--;
+ return 0;
+ }
+
+ return LB_STATUS_ERROR_NOT_EXIST;
+}
+
+/* End of a file */
diff --git a/src/file_service.c b/src/file_service.c
new file mode 100644
index 0000000..f473ade
--- /dev/null
+++ b/src/file_service.c
@@ -0,0 +1,719 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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 <stdio.h>
+#include <pthread.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <Eina.h>
+
+#include <dlog.h>
+
+#include <livebox-errno.h>
+#include <packet.h>
+#include <com-core.h>
+
+#include "file_service.h"
+#include "service_common.h"
+#include "debug.h"
+#include "util.h"
+#include "conf.h"
+#include "buffer_handler.h"
+
+#define FILE_SERVICE_ADDR "remote://:8209"
+
+#define PUSH_EXIT 'e'
+#define PUSH_ITEM 'i'
+
+#define PKT_CHUNKSZ 4096
+
+static struct info {
+ struct service_context *svc_ctx;
+
+ pthread_t push_thid;
+
+ Eina_List *request_list;
+ pthread_mutex_t request_list_lock;
+
+ int request_pipe[PIPE_MAX];
+} s_info = {
+ .svc_ctx = NULL,
+ .request_list = NULL,
+ .request_list_lock = PTHREAD_MUTEX_INITIALIZER,
+ .request_pipe = { 0, },
+};
+
+struct request_item {
+ enum {
+ REQUEST_TYPE_FILE = 0x00,
+ REQUEST_TYPE_SHM = 0x01,
+ REQUEST_TYPE_PIXMAP = 0x02,
+ REQUEST_TYPE_MAX = 0x02,
+ } type;
+ union {
+ char *filename;
+ int shm;
+ unsigned int pixmap;
+ } data;
+ struct tcb *tcb;
+};
+
+typedef int (*send_data_func_t)(int fd, const struct request_item *item);
+
+/*!
+ * File transfer header.
+ * This must should be shared with client.
+ */
+struct burst_head {
+ off_t size;
+ int flen;
+ char fname[];
+};
+
+struct burst_data {
+ int size;
+ char data[];
+};
+
+static inline struct request_item *create_request_item(struct tcb *tcb, int type, void *data)
+{
+ struct request_item *item;
+
+ item = malloc(sizeof(*item));
+ if (!item) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ switch (type) {
+ case REQUEST_TYPE_FILE:
+ item->data.filename = strdup(data);
+ if (!item->data.filename) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(item);
+ return NULL;
+ }
+ break;
+ case REQUEST_TYPE_PIXMAP:
+ item->data.pixmap = (unsigned int)data;
+ break;
+ case REQUEST_TYPE_SHM:
+ item->data.shm = (int)data;
+ break;
+ default:
+ ErrPrint("Invalid type of request\n");
+ DbgFree(item);
+ return NULL;
+ }
+
+ item->type = type;
+ item->tcb = tcb;
+ return item;
+}
+
+static inline int destroy_request_item(struct request_item *item)
+{
+ switch (item->type) {
+ case REQUEST_TYPE_FILE:
+ DbgFree(item->data.filename);
+ break;
+ case REQUEST_TYPE_SHM:
+ case REQUEST_TYPE_PIXMAP:
+ break;
+ default:
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ DbgFree(item);
+ return LB_STATUS_SUCCESS;
+}
+
+static int request_file_handler(struct tcb *tcb, struct packet *packet, struct request_item **item)
+{
+ const char *filename;
+
+ if (packet_get(packet, "s", &filename) != 1) {
+ ErrPrint("Invalid packet\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ *item = create_request_item(tcb, REQUEST_TYPE_FILE, (void *)filename);
+ return *item ? LB_STATUS_SUCCESS : LB_STATUS_ERROR_MEMORY;
+}
+
+static int request_pixmap_handler(struct tcb *tcb, struct packet *packet, struct request_item **item)
+{
+ unsigned int pixmap;
+
+ if (packet_get(packet, "i", &pixmap) != 1) {
+ ErrPrint("Invalid packet\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (pixmap == 0) {
+ ErrPrint("pixmap is not valid\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ /*!
+ * \TODO
+ * Attach to pixmap and copy its data to the client
+ */
+ *item = create_request_item(tcb, REQUEST_TYPE_PIXMAP, (void *)pixmap);
+ return *item ? LB_STATUS_SUCCESS : LB_STATUS_ERROR_MEMORY;
+}
+
+static int request_shm_handler(struct tcb *tcb, struct packet *packet, struct request_item **item)
+{
+ int shm;
+
+ if (packet_get(packet, "i", &shm) != 1) {
+ ErrPrint("Invalid packet\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (shm < 0) {
+ ErrPrint("shm is not valid: %d\n", shm);
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ /*!
+ * \TODO
+ * Attach to SHM and copy its buffer to the client
+ */
+ *item = create_request_item(tcb, REQUEST_TYPE_SHM, (void *)shm);
+ return *item ? LB_STATUS_SUCCESS : LB_STATUS_ERROR_MEMORY;
+}
+
+/* SERVER THREAD */
+static int service_thread_main(struct tcb *tcb, struct packet *packet, void *data)
+{
+ const char *cmd;
+ char ch = PUSH_ITEM;
+ int ret;
+ int i;
+ struct request_item *item;
+ struct packet *reply;
+ struct {
+ const char *cmd;
+ int (*request_handler)(struct tcb *tcb, struct packet *packet, struct request_item **item);
+ } cmd_table[] = {
+ {
+ .cmd = "request,file",
+ .request_handler = request_file_handler,
+ },
+ {
+ .cmd = "request,pixmap",
+ .request_handler = request_pixmap_handler,
+ },
+ {
+ .cmd = "request,shm",
+ .request_handler = request_shm_handler,
+ },
+ {
+ .cmd = NULL,
+ .request_handler = NULL,
+ },
+ };
+
+ if (!packet) {
+ DbgPrint("TCB %p is disconnected\n", tcb);
+ return LB_STATUS_SUCCESS;
+ }
+
+ cmd = packet_command(packet);
+ if (!cmd) {
+ ErrPrint("Invalid packet. cmd is not valid\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ switch (packet_type(packet)) {
+ case PACKET_REQ:
+ for (i = 0; cmd_table[i].cmd; i++) {
+ /*!
+ * Protocol sequence
+ * FILE REQUEST COMMAND (Client -> Server)
+ * REPLY FOR REQUEST (Client <- Server)
+ * PUSH FILE (Client <- Server)
+ *
+ * Client & Server must has to keep this communication sequence.
+ */
+ if (strcmp(cmd, cmd_table[i].cmd)) {
+ continue;
+ }
+
+ item = NULL;
+ ret = cmd_table[i].request_handler(tcb, packet, &item);
+
+ reply = packet_create_reply(packet, "i", ret);
+ if (!reply) {
+ ErrPrint("Failed to create a reply packet\n");
+ break;
+ }
+
+ if (service_common_unicast_packet(tcb, reply) < 0) {
+ ErrPrint("Unable to send reply packet\n");
+ }
+
+ packet_destroy(reply);
+
+ /*!
+ * \note
+ * After send the reply packet, file push thread can sending a file
+ */
+ if (ret != LB_STATUS_SUCCESS || !item) {
+ break;
+ }
+
+ CRITICAL_SECTION_BEGIN(&s_info.request_list_lock);
+ s_info.request_list = eina_list_append(s_info.request_list, item);
+ CRITICAL_SECTION_END(&s_info.request_list_lock);
+
+ ret = write(s_info.request_pipe[PIPE_WRITE], &ch, sizeof(ch));
+ if (ret < 0) {
+ ErrPrint("write: %s\n", strerror(errno));
+
+ CRITICAL_SECTION_BEGIN(&s_info.request_list_lock);
+ s_info.request_list = eina_list_remove(s_info.request_list, item);
+ CRITICAL_SECTION_END(&s_info.request_list_lock);
+
+ destroy_request_item(item);
+ /*!
+ * \note for the client
+ * In this case, the client can waiting files forever.
+ * So the client must has to wait only a few seconds.
+ * If the client could not get the any data in that time,
+ * it should cancel the waiting.
+ */
+ }
+ }
+
+ break;
+ case PACKET_REQ_NOACK:
+ case PACKET_ACK:
+ /* File service has no this case, it is passive service type */
+ ErrPrint("Invalid packet.\n");
+ break;
+ default:
+ break;
+ }
+
+ return LB_STATUS_SUCCESS;
+}
+
+static int send_file(int handle, const struct request_item *item)
+{
+ struct burst_head *head;
+ struct burst_data *body;
+ int pktsz;
+ int flen;
+ off_t fsize;
+ int fd;
+ int ret = 0;
+
+ /* TODO: push a file to the client */
+ fd = open(item->data.filename, O_RDONLY);
+ if (fd < 0) {
+ ErrPrint("open: %s\n", strerror(errno));
+ return -EIO;
+ }
+
+ flen = strlen(item->data.filename);
+ if (flen == 0) {
+ ret = -EINVAL;
+ goto errout;
+ }
+
+ pktsz = sizeof(*head) + flen + 1;
+
+ head = malloc(pktsz);
+ if (!head) {
+ ErrPrint("heap: %s\n", strerror(errno));
+ ret = -ENOMEM;
+ goto errout;
+ }
+
+ fsize = lseek(fd, 0L, SEEK_END);
+ if (fsize == (off_t)-1) {
+ ErrPrint("heap: %s\n", strerror(errno));
+ DbgFree(head);
+ ret = -EIO;
+ goto errout;
+ }
+
+ head->flen = flen;
+ head->size = fsize;
+ strcpy(head->fname, item->data.filename);
+
+ /* Anytime we can fail to send packet */
+ ret = com_core_send(handle, (void *)head, pktsz, 2.0f);
+ DbgFree(head);
+ if (ret < 0) {
+ ret = -EFAULT;
+ goto errout;
+ }
+
+ if (lseek(fd, 0L, SEEK_SET) == (off_t)-1) {
+ ErrPrint("seek: %s\n", strerror(errno));
+
+ body = malloc(sizeof(*body));
+ if (!body) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return -ENOMEM;
+ }
+
+ body->size = -1;
+ ret = com_core_send(handle, (void *)body, sizeof(*body), 2.0f);
+ DbgFree(body);
+
+ if (ret < 0) {
+ ret = -EFAULT;
+ } else {
+ ret = -EIO;
+ }
+
+ goto errout;
+ }
+
+ body = malloc(PKT_CHUNKSZ + sizeof(*body));
+ if (!body) {
+ ErrPrint("heap: %s\n", strerror(errno));
+ goto errout;
+ }
+
+ /* Burst pushing. */
+ while (fsize > 0) {
+ if (fsize > PKT_CHUNKSZ) {
+ body->size = PKT_CHUNKSZ;
+ } else {
+ body->size = fsize;
+ }
+
+ ret = read(fd, body->data, body->size);
+ if (ret < 0) {
+ ErrPrint("read: %s\n", strerror(errno));
+ ret = -EIO;
+ break;
+ }
+
+ body->size = ret;
+ fsize -= ret;
+ pktsz = sizeof(*body) + body->size;
+
+ /* Send BODY */
+ ret = com_core_send(handle, (void *)body, pktsz, 2.0f);
+ if (ret != pktsz) {
+ ret = -EFAULT;
+ break;
+ }
+ }
+
+ /* Send EOF */
+ body->size = -1;
+ ret = com_core_send(handle, (void *)body, sizeof(*body), 2.0f);
+ if (ret < 0) {
+ ret = -EFAULT;
+ }
+
+ DbgFree(body);
+
+errout:
+ if (close(fd) < 0) {
+ ErrPrint("close: %s\n", strerror(errno));
+ }
+
+ return ret;
+}
+
+static int send_buffer(int handle, const struct request_item *item)
+{
+ struct buffer *buffer;
+ struct burst_head *head;
+ struct burst_data *body;
+ char *data;
+ int pktsz;
+ int ret;
+ int size;
+ int offset;
+ int type;
+
+ if (item->type == REQUEST_TYPE_SHM) {
+ type = BUFFER_TYPE_SHM;
+ } else {
+ type = BUFFER_TYPE_PIXMAP;
+ }
+
+ buffer = buffer_handler_raw_open(type, (void *)item->data.shm);
+ if (!buffer) {
+ return -EINVAL;
+ }
+
+ pktsz = sizeof(*head);
+
+ head = malloc(pktsz);
+ if (!head) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ (void)buffer_handler_raw_close(buffer);
+ return -ENOMEM;
+ }
+
+ size = head->size = buffer_handler_raw_size(buffer);
+ head->flen = 0;
+
+ /* Anytime we can fail to send packet */
+ ret = com_core_send(handle, (void *)head, pktsz, 2.0f);
+ DbgFree(head);
+ if (ret < 0) {
+ ret = -EFAULT;
+ goto errout;
+ }
+
+ body = malloc(sizeof(*body) + PKT_CHUNKSZ);
+ if (!body) {
+ ret = -ENOMEM;
+ goto errout;
+ }
+
+ data = (char *)buffer_handler_raw_data(buffer);
+ offset = 0;
+ while (offset < size) {
+ body->size = size - offset;
+
+ if (body->size > PKT_CHUNKSZ) {
+ body->size = PKT_CHUNKSZ;
+ }
+
+ memcpy(body->data, data, body->size);
+ pktsz = sizeof(*body) + body->size;
+
+ ret = com_core_send(handle, (void *)body, pktsz, 2.0f);
+ if (ret < 0) {
+ ret = -EFAULT;
+ break;
+ }
+
+ offset += body->size;
+ }
+
+ DbgFree(body);
+
+errout:
+ (void)buffer_handler_raw_close(buffer);
+ return ret;
+}
+
+static void *push_main(void *data)
+{
+ fd_set set;
+ int ret;
+ char ch;
+ struct request_item *item;
+ int conn_fd;
+ send_data_func_t send_data[] = {
+ send_file,
+ send_buffer,
+ send_buffer,
+ };
+
+ while (1) {
+ FD_ZERO(&set);
+ FD_SET(s_info.request_pipe[PIPE_READ], &set);
+
+ ret = select(s_info.request_pipe[PIPE_READ] + 1, &set, NULL, NULL, NULL);
+ if (ret < 0) {
+ ret = -errno;
+ if (errno == EINTR) {
+ ErrPrint("INTERRUPTED\n");
+ ret = 0;
+ continue;
+ }
+ ErrPrint("Error: %s\n", strerror(errno));
+ break;
+ } else if (ret == 0) {
+ ErrPrint("Timeout\n");
+ ret = -ETIMEDOUT;
+ break;
+ }
+
+ if (!FD_ISSET(s_info.request_pipe[PIPE_READ], &set)) {
+ DbgPrint("Unknown data\n");
+ ret = -EINVAL;
+ break;
+ }
+
+ ret = read(s_info.request_pipe[PIPE_READ], &ch, sizeof(ch));
+ if (ret != sizeof(ch)) {
+ ErrPrint("read: %s\n", strerror(errno));
+ ret = -EFAULT;
+ break;
+ }
+
+ if (ch == PUSH_EXIT) {
+ DbgPrint("Thread is terminating\n");
+ ret = -ECANCELED;
+ break;
+ }
+
+ CRITICAL_SECTION_BEGIN(&s_info.request_list_lock);
+ item = eina_list_nth(s_info.request_list, 0);
+ s_info.request_list = eina_list_remove(s_info.request_list, item);
+ CRITICAL_SECTION_END(&s_info.request_list_lock);
+
+ if (!item) {
+ ErrPrint("Request item is not valid\n");
+ continue;
+ }
+
+ /* Validate the TCB? */
+ conn_fd = tcb_is_valid(s_info.svc_ctx, item->tcb);
+ if (conn_fd < 0) {
+ ErrPrint("TCB is not valid\n");
+ destroy_request_item(item);
+ continue;
+ }
+
+ /*
+ * \note
+ * From now, we cannot believe the conn_fd.
+ * It can be closed any time.
+ * Even though we using it.
+ */
+ if (item->type < REQUEST_TYPE_MAX && item->type >= 0) {
+ (void)send_data[item->type](conn_fd, item);
+ } else {
+ ErrPrint("Invalid type\n");
+ }
+
+ destroy_request_item(item);
+ }
+
+ return (void *)ret;
+}
+
+/* MAIN THREAD */
+int file_service_init(void)
+{
+ int status;
+
+ if (s_info.svc_ctx) {
+ ErrPrint("Already initialized\n");
+ return LB_STATUS_ERROR_ALREADY;
+ }
+
+ if (pipe2(s_info.request_pipe, O_CLOEXEC) < 0) {
+ ErrPrint("pipe: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ status = pthread_mutex_init(&s_info.request_list_lock, NULL);
+ if (status != 0) {
+ ErrPrint("Failed to create lock: %s\n", strerror(status));
+ CLOSE_PIPE(s_info.request_pipe);
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ s_info.svc_ctx = service_common_create(FILE_SERVICE_ADDR, service_thread_main, NULL);
+ if (!s_info.svc_ctx) {
+ ErrPrint("Unable to activate service thread\n");
+
+ status = pthread_mutex_destroy(&s_info.request_list_lock);
+ if (status != 0) {
+ ErrPrint("Destroy lock: %s\n", strerror(status));
+ }
+
+ CLOSE_PIPE(s_info.request_pipe);
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ status = pthread_create(&s_info.push_thid, NULL, push_main, NULL);
+ if (status != 0) {
+ ErrPrint("Failed to create a push service: %s\n", strerror(status));
+
+ service_common_destroy(s_info.svc_ctx);
+ s_info.svc_ctx = NULL;
+
+ status = pthread_mutex_destroy(&s_info.request_list_lock);
+ if (status != 0) {
+ ErrPrint("Destroy lock: %s\n", strerror(status));
+ }
+
+ CLOSE_PIPE(s_info.request_pipe);
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ /*!
+ * \note
+ * Remote service doesn't need to set the additional SMAK label.
+ */
+
+ DbgPrint("Successfully initiated\n");
+ return LB_STATUS_SUCCESS;
+}
+
+/* MAIN THREAD */
+int file_service_fini(void)
+{
+ struct request_item *item;
+ int status;
+ char ch;
+ void *retval;
+
+ if (!s_info.svc_ctx) {
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ ch = PUSH_EXIT;
+ status = write(s_info.request_pipe[PIPE_WRITE], &ch, sizeof(ch));
+ if (status != sizeof(ch)) {
+ ErrPrint("write: %s\n", strerror(errno));
+ /* Forcely terminate the thread */
+ status = pthread_cancel(s_info.push_thid);
+ if (status != 0) {
+ ErrPrint("cancel: %s\n", strerror(status));
+ }
+ }
+
+ status = pthread_join(s_info.push_thid, &retval);
+ if (status != 0) {
+ ErrPrint("join: %s\n", strerror(status));
+ }
+
+ CRITICAL_SECTION_BEGIN(&s_info.request_list_lock);
+ EINA_LIST_FREE(s_info.request_list, item) {
+ destroy_request_item(item);
+ }
+ CRITICAL_SECTION_END(&s_info.request_list_lock);
+
+ service_common_destroy(s_info.svc_ctx);
+ s_info.svc_ctx = NULL;
+
+ status = pthread_mutex_destroy(&s_info.request_list_lock);
+ if (status != 0) {
+ ErrPrint("destroy mutex: %s\n", strerror(status));
+ }
+
+ CLOSE_PIPE(s_info.request_pipe);
+
+ DbgPrint("Successfully Finalized\n");
+ return LB_STATUS_SUCCESS;
+}
+
+/* End of a file */
diff --git a/src/group.c b/src/group.c
new file mode 100644
index 0000000..ff03488
--- /dev/null
+++ b/src/group.c
@@ -0,0 +1,889 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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 <stdio.h>
+#include <ctype.h>
+#include <stdlib.h> /* malloc */
+#include <errno.h>
+#include <string.h> /* strdup */
+
+#include <dlog.h>
+#include <Eina.h>
+#include <livebox-errno.h>
+
+#include "util.h"
+#include "debug.h"
+#include "group.h"
+#include "conf.h"
+
+int errno;
+
+static struct info {
+ Eina_List *cluster_list;
+} s_info = {
+ .cluster_list = NULL,
+};
+
+struct cluster {
+ char *name;
+ Eina_List *category_list;
+};
+
+struct category {
+ char *name;
+ struct cluster *cluster;
+ Eina_List *info_list; /* list of instances of the struct inst_info */
+};
+
+struct context_info {
+ char *pkgname;
+ struct category *category;
+ Eina_List *context_list; /* context item list */
+};
+
+struct context_item_data {
+ char *tag;
+ void *data;
+};
+
+struct context_item {
+ char *ctx_item;
+ struct context_info *info;
+ Eina_List *option_list;
+ Eina_List *data_list;
+};
+
+struct context_option {
+ struct context_item *item;
+ char *key;
+ char *value;
+};
+
+HAPI struct context_info *group_create_context_info(struct category *category, const char *pkgname)
+{
+ struct context_info *info;
+
+ info = calloc(1, sizeof(*info));
+ if (!info) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ info->pkgname = strdup(pkgname);
+ if (!info->pkgname) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(info);
+ return NULL;
+ }
+
+ info->category = category;
+ category->info_list = eina_list_append(category->info_list, info);
+ return info;
+}
+
+static inline void del_options(struct context_item *item)
+{
+ struct context_option *option;
+
+ EINA_LIST_FREE(item->option_list, option) {
+ DbgFree(option->key);
+ DbgFree(option->value);
+ DbgFree(option);
+ }
+}
+
+static inline void del_context_item(struct context_info *info)
+{
+ struct context_item *item;
+
+ EINA_LIST_FREE(info->context_list, item) {
+ del_options(item);
+ DbgFree(item->ctx_item);
+ DbgFree(item);
+ }
+}
+
+HAPI struct context_item *group_add_context_item(struct context_info *info, const char *ctx_item)
+{
+ struct context_item *item;
+
+ item = calloc(1, sizeof(*item));
+ if (!item) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ item->ctx_item = strdup(ctx_item);
+ if (!item->ctx_item) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(item);
+ return NULL;
+ }
+
+ item->info = info;
+ info->context_list = eina_list_append(info->context_list, item);
+ return item;
+}
+
+HAPI int group_add_option(struct context_item *item, const char *key, const char *value)
+{
+ struct context_option *option;
+
+ option = calloc(1, sizeof(*option));
+ if (!option) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ option->key = strdup(key);
+ if (!option->key) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(option);
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ option->value = strdup(value);
+ if (!option->value) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(option->key);
+ DbgFree(option);
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ option->item = item;
+ item->option_list = eina_list_append(item->option_list, option);
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI int group_destroy_context_info(struct context_info *info)
+{
+ struct category *category;
+
+ category = info->category;
+ if (!category) {
+ ErrPrint("No category found\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ category->info_list = eina_list_remove(category->info_list, info);
+
+ del_context_item(info);
+ DbgFree(info->pkgname);
+ DbgFree(info);
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI struct cluster *group_create_cluster(const char *name)
+{
+ struct cluster *cluster;
+
+ cluster = malloc(sizeof(*cluster));
+ if (!cluster) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ cluster->name = strdup(name);
+ if (!cluster->name) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(cluster);
+ return NULL;
+ }
+
+ cluster->category_list = NULL;
+
+ s_info.cluster_list = eina_list_append(s_info.cluster_list, cluster);
+ return cluster;
+}
+
+HAPI struct cluster *group_find_cluster(const char *name)
+{
+ Eina_List *l;
+ struct cluster *cluster;
+
+ EINA_LIST_FOREACH(s_info.cluster_list, l, cluster) {
+ if (!strcasecmp(cluster->name, name)) {
+ return cluster;
+ }
+ }
+
+ return NULL;
+}
+
+HAPI struct category *group_create_category(struct cluster *cluster, const char *name)
+{
+ struct category *category;
+
+ category = malloc(sizeof(*category));
+ if (!category) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ category->name = strdup(name);
+ if (!category->name) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(category);
+ return NULL;
+ }
+
+ category->cluster = cluster;
+ category->info_list = NULL;
+
+ cluster->category_list = eina_list_append(cluster->category_list, category);
+ return category;
+}
+
+static inline void destroy_cluster(struct cluster *cluster)
+{
+ struct category *category;
+ Eina_List *l;
+ Eina_List *n;
+
+ EINA_LIST_FOREACH_SAFE(cluster->category_list, l, n, category) {
+ group_destroy_category(category);
+ }
+
+ DbgFree(cluster->name);
+ DbgFree(cluster);
+}
+
+HAPI int group_destroy_cluster(struct cluster *cluster)
+{
+ Eina_List *l;
+ Eina_List *n;
+ struct cluster *item;
+
+ EINA_LIST_FOREACH_SAFE(s_info.cluster_list, l, n, item) {
+ if (item == cluster) {
+ s_info.cluster_list = eina_list_remove_list(s_info.cluster_list, l);
+ destroy_cluster(cluster);
+ return LB_STATUS_SUCCESS;
+ }
+ }
+
+ return LB_STATUS_ERROR_NOT_EXIST;
+}
+
+static inline void destroy_category(struct category *category)
+{
+ Eina_List *l;
+ Eina_List *n;
+ struct context_info *info;
+
+ EINA_LIST_FOREACH_SAFE(category->info_list, l, n, info) {
+ group_destroy_context_info(info);
+ }
+
+ DbgFree(category->name);
+ DbgFree(category);
+}
+
+HAPI int group_destroy_category(struct category *category)
+{
+ struct cluster *cluster;
+
+ cluster = category->cluster;
+ if (cluster) {
+ cluster->category_list = eina_list_remove(cluster->category_list, category);
+ }
+
+ destroy_category(category);
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI struct category *group_find_category(struct cluster *cluster, const char *name)
+{
+ struct category *category;
+ Eina_List *l;
+
+ EINA_LIST_FOREACH(cluster->category_list, l, category) {
+ if (!strcasecmp(category->name, name)) {
+ return category;
+ }
+ }
+
+ return NULL;
+}
+
+HAPI Eina_List * const group_context_info_list(struct category *category)
+{
+ return category->info_list;
+}
+
+HAPI Eina_List *const group_context_item_list(struct context_info *info)
+{
+ return info->context_list;
+}
+
+HAPI Eina_List *const group_context_option_list(struct context_item *item)
+{
+ return item->option_list;
+}
+
+HAPI Eina_List *const group_cluster_list(void)
+{
+ return s_info.cluster_list;
+}
+
+HAPI Eina_List * const group_category_list(struct cluster *cluster)
+{
+ return cluster->category_list;
+}
+
+HAPI struct context_info * const group_context_info_from_item(struct context_item *item)
+{
+ return item->info;
+}
+
+HAPI struct category * const group_category_from_context_info(struct context_info *info)
+{
+ return info->category;
+}
+
+HAPI const char * const group_pkgname_from_context_info(struct context_info *info)
+{
+ return info->pkgname;
+}
+
+HAPI const char * const group_option_item_key(struct context_option *option)
+{
+ return option->key;
+}
+
+HAPI const char * const group_option_item_value(struct context_option *option)
+{
+ return option->value;
+}
+
+HAPI const char * const group_context_item(struct context_item *item)
+{
+ return item->ctx_item;
+}
+
+HAPI int group_context_item_add_data(struct context_item *item, const char *tag, void *data)
+{
+ struct context_item_data *tmp;
+
+ tmp = malloc(sizeof(*tmp));
+ if (!tmp) {
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ tmp->tag = strdup(tag);
+ if (!tmp->tag) {
+ DbgFree(tmp);
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ tmp->data = data;
+ item->data_list = eina_list_append(item->data_list, tmp);
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI void *group_context_item_data(struct context_item *item, const char *tag)
+{
+ struct context_item_data *tmp;
+ Eina_List *l;
+
+ EINA_LIST_FOREACH(item->data_list, l, tmp) {
+ if (!strcmp(tmp->tag, tag)) {
+ return tmp->data;
+ }
+ }
+
+ return NULL;
+}
+
+HAPI void *group_context_item_del_data(struct context_item *item, const char *tag)
+{
+ struct context_item_data *tmp;
+ Eina_List *l;
+ Eina_List *n;
+
+ EINA_LIST_FOREACH_SAFE(item->data_list, l, n, tmp) {
+ if (!strcmp(tmp->tag, tag)) {
+ void *data;
+
+ item->data_list = eina_list_remove(item->data_list, tmp);
+
+ data = tmp->data;
+
+ DbgFree(tmp->tag);
+ DbgFree(tmp);
+
+ return data;
+ }
+ }
+
+ return NULL;
+}
+
+HAPI const char * const group_category_name(struct category *category)
+{
+ return category ? category->name : NULL;
+}
+
+HAPI const char * const group_cluster_name(struct cluster *cluster)
+{
+ return cluster ? cluster->name : NULL;
+}
+
+HAPI const char *group_cluster_name_by_category(struct category *category)
+{
+ return !category ? NULL : (category->cluster ? category->cluster->name : NULL);
+}
+
+static inline char *get_token(char *ptr, int *len)
+{
+ char *name;
+ int _len;
+
+ if (*len == 0) {
+ ErrPrint("Start brace but len = 0\n");
+ return NULL;
+ }
+
+ _len = *len;
+
+ while (_len > 0 && isspace(ptr[_len])) {
+ _len--;
+ }
+
+ if (_len == 0) {
+ ErrPrint("Token has no string\n");
+ return NULL;
+ }
+
+ name = malloc(_len + 1);
+ if (!name) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ strncpy(name, ptr - *len, _len);
+ name[_len] = '\0';
+
+ *len = _len;
+ return name;
+}
+
+HAPI int group_add_livebox(const char *group, const char *pkgname)
+{
+ struct cluster *cluster;
+ struct category *category;
+ struct context_info *info = NULL;
+ struct context_item *item = NULL;
+ char *key;
+ char *name;
+ char *ptr;
+ int len;
+ int is_open = 0;
+ enum {
+ CLUSTER,
+ CATEGORY,
+ CONTEXT_ITEM,
+ CONTEXT_OPTION_KEY,
+ CONTEXT_OPTION_VALUE,
+ CONTEXT_ERROR = 0xFFFFFFFF
+ } state;
+
+ state = CLUSTER;
+
+ ptr = (char *)group;
+ len = 0;
+ key = NULL;
+
+ /* Skip the first space characters */
+ while (*ptr && isspace(*ptr)) ptr++;
+
+ cluster = NULL;
+ while (*ptr) {
+ if (*ptr == '{') {
+ name = get_token(ptr, &len);
+ if (!name) {
+ ErrPrint("Failed to get token\n");
+ return LB_STATUS_ERROR_FAULT;
+ }
+ /* cluster{category{context{key=value,key=value},context{key=value}}} */
+ /* cluster{category} */
+
+ switch (state) {
+ case CLUSTER:
+ cluster = group_find_cluster(name);
+ if (!cluster) {
+ cluster = group_create_cluster(name);
+ }
+
+ if (!cluster) {
+ ErrPrint("Failed to get cluster\n");
+ DbgFree(name);
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ state = CATEGORY;
+ break;
+
+ case CATEGORY:
+ category = group_find_category(cluster, name);
+ if (!category) {
+ category = group_create_category(cluster, name);
+ }
+
+ if (!category) {
+ ErrPrint("Failed to get category\n");
+ DbgFree(name);
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ info = group_create_context_info(category, pkgname);
+ if (!info) {
+ ErrPrint("Failed to create ctx info\n");
+ DbgFree(name);
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ state = CONTEXT_ITEM;
+ break;
+
+ case CONTEXT_ITEM:
+ item = group_add_context_item(info, name);
+ if (!item) {
+ ErrPrint("Failed to create a context item\n");
+ DbgFree(name);
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ state = CONTEXT_OPTION_KEY;
+ break;
+
+ case CONTEXT_OPTION_KEY:
+ case CONTEXT_OPTION_VALUE:
+ default:
+ ErrPrint("Invalid state\n");
+ DbgFree(name);
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ DbgFree(name);
+ is_open++;
+ len = 0;
+ ptr++;
+ while (*ptr && isspace(*ptr)) ptr++;
+ continue;
+ } else if (*ptr == ',') {
+ name = get_token(ptr, &len);
+ if (!name) {
+ ErrPrint("Failed to get token (len:%d)\n", len);
+ len = 0;
+ ptr++;
+ while (*ptr && isspace(*ptr)) ptr++;
+ continue;
+ }
+
+ switch (state) {
+ case CLUSTER:
+ if (is_open != 0) {
+ ErrPrint("Invalid state\n");
+ DbgFree(name);
+ return LB_STATUS_ERROR_FAULT;
+ }
+ cluster = group_find_cluster(name);
+ if (!cluster) {
+ cluster = group_create_cluster(name);
+ }
+
+ if (!cluster) {
+ ErrPrint("Failed to get cluster\n");
+ DbgFree(name);
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ state = CATEGORY;
+ break;
+
+ case CATEGORY:
+ if (is_open != 1) {
+ ErrPrint("Invalid state\n");
+ DbgFree(name);
+ return LB_STATUS_ERROR_FAULT;
+ }
+ category = group_find_category(cluster, name);
+ if (!category) {
+ category = group_create_category(cluster, name);
+ }
+
+ if (!category) {
+ ErrPrint("Failed to get category\n");
+ DbgFree(name);
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ info = group_create_context_info(category, pkgname);
+ if (!info) {
+ ErrPrint("Failed to create ctx info\n");
+ DbgFree(name);
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ state = CONTEXT_ITEM;
+ break;
+ case CONTEXT_ITEM:
+ if (is_open == 1) {
+ category = group_find_category(cluster, name);
+ if (!category) {
+ category = group_create_category(cluster, name);
+ }
+
+ if (!category) {
+ ErrPrint("Failed to get category\n");
+ DbgFree(name);
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ info = group_create_context_info(category, pkgname);
+ if (!info) {
+ ErrPrint("Failed to create ctx info\n");
+ DbgFree(name);
+ return LB_STATUS_ERROR_FAULT;
+ }
+ } else if (is_open == 2) {
+ item = group_add_context_item(info, name);
+ if (!item) {
+ ErrPrint("Failed to create a context item\n");
+ DbgFree(name);
+ return LB_STATUS_ERROR_FAULT;
+ }
+ state = CONTEXT_OPTION_KEY;
+ } else {
+ ErrPrint("Invalid state\n");
+ DbgFree(name);
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ break;
+ case CONTEXT_OPTION_VALUE:
+ if (is_open != 3) {
+ ErrPrint("Invalid state\n");
+ DbgFree(name);
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ if (group_add_option(item, key, name) < 0) {
+ ErrPrint("Failed to add a new option: %s - %s\n", key, name);
+ }
+
+ DbgFree(key);
+ key = NULL;
+
+ state = CONTEXT_OPTION_KEY;
+ break;
+ case CONTEXT_OPTION_KEY:
+ default:
+ ErrPrint("Invalid state (%s)\n", name);
+ DbgFree(name);
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ DbgFree(name);
+ len = 0;
+ ptr++;
+ while (*ptr && isspace(*ptr)) ptr++;
+ continue;
+ } else if (*ptr == '=') {
+ if (is_open != 3 || state != CONTEXT_OPTION_KEY) {
+ ErrPrint("Invalid state\n");
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ key = get_token(ptr, &len);
+ if (!key) {
+ ErrPrint("Failed to get token\n");
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ state = CONTEXT_OPTION_VALUE;
+ len = 0;
+ ptr++;
+ while (*ptr && isspace(*ptr)) ptr++;
+ continue;
+ } else if (*ptr == '}') {
+ if (is_open <= 0) {
+ ErrPrint("Invalid state\n");
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ name = get_token(ptr, &len);
+ if (!name) {
+ ErrPrint("Failed to get token, len:%d\n", len);
+ is_open--;
+ len = 0;
+ ptr++;
+ while (*ptr && isspace(*ptr)) ptr++;
+ continue;
+ }
+
+ switch (state) {
+ case CATEGORY:
+ category = group_find_category(cluster, name);
+ if (!category) {
+ category = group_create_category(cluster, name);
+ }
+
+ if (!category) {
+ ErrPrint("Failed to get category\n");
+ DbgFree(name);
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ info = group_create_context_info(category, pkgname);
+ if (!info) {
+ ErrPrint("Failed to create ctx info\n");
+ DbgFree(name);
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ state = CLUSTER;
+ break;
+ case CONTEXT_ITEM:
+ if (is_open == 1) {
+ category = group_find_category(cluster, name);
+ if (!category) {
+ category = group_create_category(cluster, name);
+ }
+
+ if (!category) {
+ ErrPrint("Failed to get category\n");
+ DbgFree(name);
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ info = group_create_context_info(category, pkgname);
+ if (!info) {
+ ErrPrint("Failed to create ctx info\n");
+ DbgFree(name);
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ state = CLUSTER;
+ } else if (is_open == 2) {
+ state = CATEGORY;
+ } else {
+ ErrPrint("Invalid state\n");
+ DbgFree(name);
+ return LB_STATUS_ERROR_FAULT;
+ }
+ break;
+ case CONTEXT_OPTION_VALUE:
+ if (is_open != 2) {
+ ErrPrint("Invalid state (%s)\n", name);
+ DbgFree(name);
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ if (group_add_option(item, key, name) < 0) {
+ ErrPrint("Failed to add a new option: %s - %s\n", key, name);
+ }
+
+ DbgFree(key);
+ key = NULL;
+
+ state = CONTEXT_ITEM;
+ break;
+ case CONTEXT_OPTION_KEY:
+ case CLUSTER:
+ default:
+ ErrPrint("Invalid state (%s)\n", name);
+ break;
+ }
+
+ DbgFree(name);
+ is_open--;
+ len = 0;
+ ptr++;
+ while (*ptr && isspace(*ptr)) ptr++;
+ continue;
+ }
+
+ len++;
+ ptr++;
+ }
+
+ /* If some cases, the key is not released, try release it, doesn't need to check NULL */
+ DbgFree(key);
+
+ if (state != CLUSTER) {
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI int group_del_livebox(const char *pkgname)
+{
+ Eina_List *l;
+ Eina_List *n;
+ Eina_List *s_l;
+ Eina_List *s_n;
+ Eina_List *i_l;
+ Eina_List *i_n;
+ struct cluster *cluster;
+ struct category *category;
+ struct context_info *info;
+
+ EINA_LIST_FOREACH_SAFE(s_info.cluster_list, l, n, cluster) {
+ EINA_LIST_FOREACH_SAFE(cluster->category_list, s_l, s_n, category) {
+ EINA_LIST_FOREACH_SAFE(category->info_list, i_l, i_n, info) {
+ if (!strcmp(pkgname, info->pkgname)) {
+ group_destroy_context_info(info);
+ }
+ }
+
+ if (!category->info_list) {
+ group_destroy_category(category);
+ }
+ }
+
+ if (!cluster->category_list) {
+ group_destroy_cluster(cluster);
+ }
+ }
+
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI int group_init(void)
+{
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI int group_fini(void)
+{
+ struct cluster *cluster;
+ struct category *category;
+
+ EINA_LIST_FREE(s_info.cluster_list, cluster) {
+
+ EINA_LIST_FREE(cluster->category_list, category) {
+ destroy_category(category);
+ }
+
+ destroy_cluster(cluster);
+ }
+ return LB_STATUS_SUCCESS;
+}
+
+/* End of a file */
diff --git a/src/instance.c b/src/instance.c
new file mode 100644
index 0000000..32e6b91
--- /dev/null
+++ b/src/instance.c
@@ -0,0 +1,3294 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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 <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <dlog.h>
+#include <Eina.h>
+#include <gio/gio.h>
+#include <Ecore.h>
+
+#include <packet.h>
+#include <com-core_packet.h>
+#include <livebox-service.h>
+#include <livebox-errno.h>
+
+#include "conf.h"
+#include "util.h"
+#include "debug.h"
+#include "slave_life.h"
+#include "slave_rpc.h"
+#include "client_life.h"
+#include "instance.h"
+#include "client_rpc.h"
+#include "package.h"
+#include "script_handler.h"
+#include "buffer_handler.h"
+#include "setting.h"
+
+int errno;
+
+static struct info {
+ enum buffer_type env_buf_type;
+} s_info = {
+ .env_buf_type = BUFFER_TYPE_FILE,
+};
+
+struct set_pinup_cbdata {
+ struct inst_info *inst;
+ int pinup;
+};
+
+struct resize_cbdata {
+ struct inst_info *inst;
+ int w;
+ int h;
+};
+
+struct update_mode_cbdata {
+ struct inst_info *inst;
+ int active_update;
+};
+
+struct change_group_cbdata {
+ struct inst_info *inst;
+ char *cluster;
+ char *category;
+};
+
+struct period_cbdata {
+ struct inst_info *inst;
+ double period;
+};
+
+struct event_item {
+ int (*event_cb)(struct inst_info *inst, void *data);
+ void *data;
+ int deleted;
+};
+
+struct tag_item {
+ char *tag;
+ void *data;
+};
+
+struct inst_info {
+ struct pkg_info *info;
+
+ enum instance_state state; /*!< Represents current state */
+ enum instance_state requested_state; /*!< Only ACTIVATED | DESTROYED is acceptable */
+ enum instance_destroy_type destroy_type;
+ int changing_state;
+
+ char *id;
+ double timestamp;
+
+ char *content;
+ char *cluster;
+ char *category;
+ char *title;
+ int is_pinned_up;
+ double sleep_at;
+ int scroll_locked; /*!< Scroller which is in viewer is locked. */
+ int active_update; /*!< Viewer will reload the buffer by itself, so the provider doesn't need to send the updated event */
+
+ char *icon;
+ char *name;
+
+ enum livebox_visible_state visible;
+
+ struct {
+ int width;
+ int height;
+ double priority;
+
+ union {
+ struct script_info *script;
+ struct buffer_info *buffer;
+ } canvas;
+
+ double period;
+ } lb;
+
+ struct {
+ int width;
+ int height;
+ double x;
+ double y;
+
+ union {
+ struct script_info *script;
+ struct buffer_info *buffer;
+ } canvas;
+
+ struct client_node *owner;
+ int is_opened_for_reactivate;
+ int need_to_send_close_event;
+ char *pended_update_desc;
+ int pended_update_cnt;
+ } pd;
+
+ struct client_node *client; /*!< Owner - creator */
+ Eina_List *client_list; /*!< Viewer list */
+ int refcnt;
+
+ Ecore_Timer *update_timer; /*!< Only used for secured livebox */
+
+ enum event_process {
+ INST_EVENT_PROCESS_IDLE = 0x00,
+ INST_EVENT_PROCESS_DELETE = 0x01
+ } in_event_process;
+ Eina_List *delete_event_list;
+
+ Eina_List *data_list;
+};
+
+#define CLIENT_SEND_EVENT(instance, packet) ((instance)->client ? client_rpc_async_request((instance)->client, (packet)) : client_broadcast((instance), (packet)))
+
+static Eina_Bool update_timer_cb(void *data);
+
+static inline void timer_thaw(struct inst_info *inst)
+{
+ double pending;
+ double period;
+ double delay;
+ double sleep_time;
+
+ ecore_timer_thaw(inst->update_timer);
+ period = ecore_timer_interval_get(inst->update_timer);
+ pending = ecore_timer_pending_get(inst->update_timer);
+ delay = util_time_delay_for_compensation(period) - pending;
+ ecore_timer_delay(inst->update_timer, delay);
+
+ if (inst->sleep_at == 0.0f) {
+ return;
+ }
+
+ sleep_time = util_timestamp() - inst->sleep_at;
+ if (sleep_time > pending) {
+ (void)update_timer_cb(inst);
+ }
+
+ inst->sleep_at = 0.0f;
+}
+
+static inline void timer_freeze(struct inst_info *inst)
+{
+ ecore_timer_freeze(inst->update_timer);
+
+ if (ecore_timer_interval_get(inst->update_timer) <= 1.0f) {
+ return;
+ }
+
+#if defined(_USE_ECORE_TIME_GET)
+ inst->sleep_at = ecore_time_get();
+#else
+ struct timeval tv;
+ if (gettimeofday(&tv, NULL) < 0) {
+ ErrPrint("gettimeofday: %s\n", strerror(errno));
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ }
+ inst->sleep_at = (double)tv.tv_sec + (double)tv.tv_usec / 1000000.0f;
+#endif
+}
+
+
+static int viewer_deactivated_cb(struct client_node *client, void *data)
+{
+ struct inst_info *inst = data;
+
+ DbgPrint("%d is deleted from the list of viewer of %s(%s)\n", client_pid(client), package_name(instance_package(inst)), instance_id(inst));
+ if (!eina_list_data_find(inst->client_list, client)) {
+ ErrPrint("Not found\n");
+ return LB_STATUS_ERROR_NOT_EXIST;
+ }
+
+ inst->client_list = eina_list_remove(inst->client_list, client);
+ if (!inst->client_list && !inst->client) {
+ DbgPrint("Has no clients\n");
+ instance_destroy(inst, INSTANCE_DESTROY_DEFAULT);
+ }
+
+ instance_unref(inst);
+ return -1; /*!< Remove this callback from the cb list */
+}
+
+static int pause_livebox(struct inst_info *inst)
+{
+ struct packet *packet;
+
+ packet = packet_create_noack("lb_pause", "ss", package_name(inst->info), inst->id);
+ if (!packet) {
+ ErrPrint("Failed to create a new packet\n");
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ return slave_rpc_request_only(package_slave(inst->info), package_name(inst->info), packet, 0);
+}
+
+/*! \TODO Wake up the freeze'd timer */
+static int resume_livebox(struct inst_info *inst)
+{
+ struct packet *packet;
+
+ packet = packet_create_noack("lb_resume", "ss", package_name(inst->info), inst->id);
+ if (!packet) {
+ ErrPrint("Failed to create a new packet\n");
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ return slave_rpc_request_only(package_slave(inst->info), package_name(inst->info), packet, 0);
+}
+
+static inline int instance_recover_visible_state(struct inst_info *inst)
+{
+ int ret;
+
+ switch (inst->visible) {
+ case LB_SHOW:
+ case LB_HIDE:
+ instance_thaw_updator(inst);
+
+ ret = 0;
+ break;
+ case LB_HIDE_WITH_PAUSE:
+ ret = pause_livebox(inst);
+
+ instance_freeze_updator(inst);
+ break;
+ default:
+ ret = LB_STATUS_ERROR_INVALID;
+ break;
+ }
+
+ DbgPrint("Visible state is recovered to %d\n", ret);
+ return ret;
+}
+
+static inline void instance_send_update_mode_event(struct inst_info *inst, int active_mode, int status)
+{
+ struct packet *packet;
+ const char *pkgname;
+
+ if (!inst->info) {
+ ErrPrint("Instance info is not ready to use\n");
+ return;
+ }
+
+ pkgname = package_name(inst->info);
+
+ packet = packet_create_noack("update_mode", "ssii", pkgname, inst->id, status, active_mode);
+ if (packet) {
+ CLIENT_SEND_EVENT(inst, packet);
+ } else {
+ ErrPrint("Failed to send update mode event\n");
+ }
+}
+
+static inline void instance_send_resized_event(struct inst_info *inst, int is_pd, int w, int h, int status)
+{
+ struct packet *packet;
+ enum lb_type lb_type;
+ const char *pkgname;
+ const char *id;
+
+ if (!inst->info) {
+ ErrPrint("Instance info is not ready to use\n");
+ return;
+ }
+
+ pkgname = package_name(inst->info);
+
+ lb_type = package_lb_type(inst->info);
+ if (lb_type == LB_TYPE_SCRIPT) {
+ id = script_handler_buffer_id(inst->lb.canvas.script);
+ } else if (lb_type == LB_TYPE_BUFFER) {
+ id = buffer_handler_id(inst->lb.canvas.buffer);
+ } else {
+ id = "";
+ }
+
+ packet = packet_create_noack("size_changed", "sssiiii", pkgname, inst->id, id, is_pd, w, h, status);
+ if (packet) {
+ CLIENT_SEND_EVENT(inst, packet);
+ } else {
+ ErrPrint("Failed to send size changed event\n");
+ }
+}
+
+static void update_mode_cb(struct slave_node *slave, const struct packet *packet, void *data)
+{
+ struct update_mode_cbdata *cbdata = data;
+ int ret;
+
+ if (!packet) {
+ ErrPrint("Invalid packet\n");
+ ret = LB_STATUS_ERROR_FAULT;
+ goto out;
+ }
+
+ if (packet_get(packet, "i", &ret) != 1) {
+ ErrPrint("Invalid parameters\n");
+ ret = LB_STATUS_ERROR_INVALID;
+ goto out;
+ }
+
+ if (ret == (int)LB_STATUS_SUCCESS) {
+ cbdata->inst->active_update = cbdata->active_update;
+ }
+
+out:
+ instance_send_update_mode_event(cbdata->inst, cbdata->active_update, ret);
+ instance_unref(cbdata->inst);
+ DbgFree(cbdata);
+}
+
+HAPI int instance_unicast_created_event(struct inst_info *inst, struct client_node *client)
+{
+ struct packet *packet;
+ enum lb_type lb_type;
+ enum pd_type pd_type;
+ const char *lb_file;
+ const char *pd_file;
+
+ if (!client) {
+ client = inst->client;
+ if (!client) {
+ return LB_STATUS_SUCCESS;
+ }
+ }
+
+ lb_type = package_lb_type(inst->info);
+ pd_type = package_pd_type(inst->info);
+
+ if (lb_type == LB_TYPE_SCRIPT) {
+ lb_file = script_handler_buffer_id(inst->lb.canvas.script);
+ } else if (lb_type == LB_TYPE_BUFFER) {
+ lb_file = buffer_handler_id(inst->lb.canvas.buffer);
+ } else {
+ lb_file = "";
+ }
+
+ if (pd_type == PD_TYPE_SCRIPT) {
+ pd_file = script_handler_buffer_id(inst->pd.canvas.script);
+ } else if (pd_type == PD_TYPE_BUFFER) {
+ pd_file = buffer_handler_id(inst->pd.canvas.buffer);
+ } else {
+ pd_file = "";
+ }
+
+ packet = packet_create_noack("created", "dsssiiiisssssdiiiiidsi",
+ inst->timestamp,
+ package_name(inst->info), inst->id, inst->content,
+ inst->lb.width, inst->lb.height,
+ inst->pd.width, inst->pd.height,
+ inst->cluster, inst->category,
+ lb_file, pd_file,
+ package_auto_launch(inst->info),
+ inst->lb.priority,
+ package_size_list(inst->info),
+ !!inst->client,
+ package_pinup(inst->info),
+ lb_type, pd_type,
+ inst->lb.period, inst->title,
+ inst->is_pinned_up);
+ if (!packet) {
+ ErrPrint("Failed to build a packet for %s\n", package_name(inst->info));
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ return client_rpc_async_request(client, packet);
+}
+
+static int update_client_list(struct client_node *client, void *data)
+{
+ struct inst_info *inst = data;
+
+ if (!instance_has_client(inst, client)) {
+ instance_add_client(inst, client);
+ }
+
+ return LB_STATUS_SUCCESS;
+}
+
+static int instance_broadcast_created_event(struct inst_info *inst)
+{
+ struct packet *packet;
+ enum lb_type lb_type;
+ enum pd_type pd_type;
+ const char *lb_file;
+ const char *pd_file;
+
+ lb_type = package_lb_type(inst->info);
+ pd_type = package_pd_type(inst->info);
+
+ if (lb_type == LB_TYPE_SCRIPT) {
+ lb_file = script_handler_buffer_id(inst->lb.canvas.script);
+ } else if (lb_type == LB_TYPE_BUFFER) {
+ lb_file = buffer_handler_id(inst->lb.canvas.buffer);
+ } else {
+ lb_file = "";
+ }
+
+ if (pd_type == PD_TYPE_SCRIPT) {
+ pd_file = script_handler_buffer_id(inst->pd.canvas.script);
+ } else if (pd_type == PD_TYPE_BUFFER) {
+ pd_file = buffer_handler_id(inst->pd.canvas.buffer);
+ } else {
+ pd_file = "";
+ }
+
+ if (!inst->client) {
+ client_browse_list(inst->cluster, inst->category, update_client_list, inst);
+ }
+
+ packet = packet_create_noack("created", "dsssiiiisssssdiiiiidsi",
+ inst->timestamp,
+ package_name(inst->info), inst->id, inst->content,
+ inst->lb.width, inst->lb.height,
+ inst->pd.width, inst->pd.height,
+ inst->cluster, inst->category,
+ lb_file, pd_file,
+ package_auto_launch(inst->info),
+ inst->lb.priority,
+ package_size_list(inst->info),
+ !!inst->client,
+ package_pinup(inst->info),
+ lb_type, pd_type,
+ inst->lb.period, inst->title,
+ inst->is_pinned_up);
+ if (!packet) {
+ ErrPrint("Failed to build a packet for %s\n", package_name(inst->info));
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ return CLIENT_SEND_EVENT(inst, packet);
+}
+
+HAPI int instance_unicast_deleted_event(struct inst_info *inst, struct client_node *client, int reason)
+{
+ struct packet *packet;
+
+ if (!client) {
+ client = inst->client;
+ if (!client) {
+ return LB_STATUS_ERROR_INVALID;
+ }
+ }
+
+ packet = packet_create_noack("deleted", "ssdi", package_name(inst->info), inst->id, inst->timestamp, reason);
+ if (!packet) {
+ ErrPrint("Failed to build a packet for %s\n", package_name(inst->info));
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ return client_rpc_async_request(client, packet);
+}
+
+static int instance_broadcast_deleted_event(struct inst_info *inst, int reason)
+{
+ struct packet *packet;
+ struct client_node *client;
+ Eina_List *l;
+ Eina_List *n;
+ int ret;
+
+ packet = packet_create_noack("deleted", "ssdi", package_name(inst->info), inst->id, inst->timestamp, reason);
+ if (!packet) {
+ ErrPrint("Failed to build a packet for %s\n", package_name(inst->info));
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ ret = CLIENT_SEND_EVENT(inst, packet);
+
+ EINA_LIST_FOREACH_SAFE(inst->client_list, l, n, client) {
+ instance_del_client(inst, client);
+ }
+
+ return ret;
+}
+
+static int client_deactivated_cb(struct client_node *client, void *data)
+{
+ struct inst_info *inst = data;
+ instance_destroy(inst, INSTANCE_DESTROY_DEFAULT);
+ return LB_STATUS_SUCCESS;
+}
+
+static int send_pd_destroyed_to_client(struct inst_info *inst, int status)
+{
+ struct packet *packet;
+
+ if (!inst->pd.need_to_send_close_event && status != LB_STATUS_ERROR_FAULT) {
+ ErrPrint("PD is not created\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ packet = packet_create_noack("pd_destroyed", "ssi", package_name(inst->info), inst->id, status);
+ if (!packet) {
+ ErrPrint("Failed to create a packet\n");
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ inst->pd.need_to_send_close_event = 0;
+
+ return CLIENT_SEND_EVENT(inst, packet);
+}
+
+static inline void invoke_delete_callbacks(struct inst_info *inst)
+{
+ Eina_List *l;
+ Eina_List *n;
+ struct event_item *item;
+
+ inst->in_event_process |= INST_EVENT_PROCESS_DELETE;
+ EINA_LIST_FOREACH_SAFE(inst->delete_event_list, l, n, item) {
+ if (item->deleted || item->event_cb(inst, item->data) < 0 || item->deleted) {
+ inst->delete_event_list = eina_list_remove(inst->delete_event_list, item);
+ DbgFree(item);
+ }
+ }
+ inst->in_event_process &= ~INST_EVENT_PROCESS_DELETE;
+}
+
+HAPI int instance_event_callback_add(struct inst_info *inst, enum instance_event type, int (*event_cb)(struct inst_info *inst, void *data), void *data)
+{
+ struct event_item *item;
+
+ if (!event_cb) {
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ switch (type) {
+ case INSTANCE_EVENT_DESTROY:
+ item = malloc(sizeof(*item));
+ if (!item) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ item->event_cb = event_cb;
+ item->data = data;
+ item->deleted = 0;
+
+ inst->delete_event_list = eina_list_append(inst->delete_event_list, item);
+ break;
+ default:
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI int instance_event_callback_del(struct inst_info *inst, enum instance_event type, int (*event_cb)(struct inst_info *inst, void *data), void *data)
+{
+ Eina_List *l;
+ Eina_List *n;
+ struct event_item *item;
+
+ switch (type) {
+ case INSTANCE_EVENT_DESTROY:
+ EINA_LIST_FOREACH_SAFE(inst->delete_event_list, l, n, item) {
+ if (item->event_cb == event_cb && item->data == data) {
+ if (inst->in_event_process & INST_EVENT_PROCESS_DELETE) {
+ item->deleted = 1;
+ } else {
+ inst->delete_event_list = eina_list_remove(inst->delete_event_list, item);
+ DbgFree(item);
+ }
+ return LB_STATUS_SUCCESS;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return LB_STATUS_ERROR_NOT_EXIST;
+}
+
+static inline void destroy_instance(struct inst_info *inst)
+{
+ struct pkg_info *pkg;
+ enum lb_type lb_type;
+ enum pd_type pd_type;
+ struct slave_node *slave;
+ struct event_item *item;
+ struct tag_item *tag_item;
+
+ (void)send_pd_destroyed_to_client(inst, LB_STATUS_SUCCESS);
+
+ invoke_delete_callbacks(inst);
+
+ pkg = inst->info;
+
+ lb_type = package_lb_type(pkg);
+ pd_type = package_pd_type(pkg);
+ slave = package_slave(inst->info);
+
+ DbgPrint("Instance is destroyed (%p), slave(%p)\n", inst, slave);
+
+ if (lb_type == LB_TYPE_SCRIPT) {
+ (void)script_handler_unload(inst->lb.canvas.script, 0);
+ if (script_handler_destroy(inst->lb.canvas.script) == (int)LB_STATUS_SUCCESS) {
+ inst->lb.canvas.script = NULL;
+ }
+ } else if (lb_type == LB_TYPE_BUFFER) {
+ (void)buffer_handler_unload(inst->lb.canvas.buffer);
+ if (buffer_handler_destroy(inst->lb.canvas.buffer) == (int)LB_STATUS_SUCCESS) {
+ inst->lb.canvas.buffer = NULL;
+ }
+ }
+
+ if (pd_type == PD_TYPE_SCRIPT) {
+ (void)script_handler_unload(inst->pd.canvas.script, 1);
+ if (script_handler_destroy(inst->pd.canvas.script) == (int)LB_STATUS_SUCCESS) {
+ inst->pd.canvas.script = NULL;
+ }
+ } else if (pd_type == PD_TYPE_BUFFER) {
+ (void)buffer_handler_unload(inst->pd.canvas.buffer);
+ if (buffer_handler_destroy(inst->pd.canvas.buffer) == (int)LB_STATUS_SUCCESS) {
+ inst->pd.canvas.buffer = NULL;
+ }
+ }
+
+ if (inst->client) {
+ client_event_callback_del(inst->client, CLIENT_EVENT_DEACTIVATE, client_deactivated_cb, inst);
+ client_unref(inst->client);
+ }
+
+ if (inst->update_timer) {
+ ecore_timer_del(inst->update_timer);
+ }
+
+ EINA_LIST_FREE(inst->data_list, tag_item) {
+ DbgPrint("Tagged item[%s] %p\n", tag_item->tag, tag_item->data);
+ DbgFree(tag_item->tag);
+ DbgFree(tag_item);
+ }
+
+ EINA_LIST_FREE(inst->delete_event_list, item) {
+ DbgFree(item);
+ }
+ DbgFree(inst->icon);
+ DbgFree(inst->name);
+ DbgFree(inst->category);
+ DbgFree(inst->cluster);
+ DbgFree(inst->content);
+ DbgFree(inst->title);
+ util_unlink(util_uri_to_path(inst->id));
+ DbgFree(inst->id);
+ package_del_instance(inst->info, inst);
+ DbgFree(inst);
+
+ slave = slave_unload_instance(slave);
+}
+
+static Eina_Bool update_timer_cb(void *data)
+{
+ struct inst_info *inst = (struct inst_info *)data;
+
+ slave_rpc_request_update(package_name(inst->info), inst->id, inst->cluster, inst->category, NULL, 0);
+ return ECORE_CALLBACK_RENEW;
+}
+
+static inline int fork_package(struct inst_info *inst, const char *pkgname)
+{
+ struct pkg_info *info;
+ int len;
+
+ info = package_find(pkgname);
+ if (!info) {
+ ErrPrint("%s is not found\n", pkgname);
+ return LB_STATUS_ERROR_NOT_EXIST;
+ }
+
+ len = strlen(SCHEMA_FILE "%s%s_%d_%lf.png") + strlen(IMAGE_PATH) + strlen(package_name(info)) + 50;
+ inst->id = malloc(len);
+ if (!inst->id) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ snprintf(inst->id, len, SCHEMA_FILE "%s%s_%d_%lf.png", IMAGE_PATH, package_name(info), client_pid(inst->client), inst->timestamp);
+
+ instance_set_pd_size(inst, package_pd_width(info), package_pd_height(info));
+
+ inst->lb.period = package_period(info);
+
+ inst->info = info;
+
+ if (package_secured(info)) {
+ if (inst->lb.period > 0.0f) {
+ inst->update_timer = util_timer_add(inst->lb.period, update_timer_cb, inst);
+ if (!inst->update_timer) {
+ ErrPrint("Failed to add an update timer for instance %s\n", inst->id);
+ } else {
+ timer_freeze(inst); /* Freeze the update timer as default */
+ }
+ } else {
+ inst->update_timer = NULL;
+ }
+ }
+
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI struct inst_info *instance_create(struct client_node *client, double timestamp, const char *pkgname, const char *content, const char *cluster, const char *category, double period, int width, int height)
+{
+ struct inst_info *inst;
+
+ inst = calloc(1, sizeof(*inst));
+ if (!inst) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ inst->timestamp = timestamp;
+ inst->lb.width = width;
+ inst->lb.height = height;
+
+ inst->content = strdup(content);
+ if (!inst->content) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(inst);
+ return NULL;
+ }
+
+ inst->cluster = strdup(cluster);
+ if (!inst->cluster) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(inst->content);
+ DbgFree(inst);
+ return NULL;
+ }
+
+ inst->category = strdup(category);
+ if (!inst->category) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(inst->cluster);
+ DbgFree(inst->content);
+ DbgFree(inst);
+ return NULL;
+ }
+
+ inst->title = strdup(DEFAULT_TITLE); /*!< Use the DEFAULT Title "" */
+ if (!inst->title) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(inst->category);
+ DbgFree(inst->cluster);
+ DbgFree(inst->content);
+ DbgFree(inst);
+ return NULL;
+ }
+
+ if (client) {
+ inst->client = client_ref(client);
+ if (client_event_callback_add(inst->client, CLIENT_EVENT_DEACTIVATE, client_deactivated_cb, inst) < 0) {
+ ErrPrint("Failed to add client event callback: %s\n", inst->id);
+ }
+ }
+
+ if (fork_package(inst, pkgname) < 0) {
+ (void)client_unref(inst->client);
+ DbgFree(inst->title);
+ DbgFree(inst->category);
+ DbgFree(inst->cluster);
+ DbgFree(inst->content);
+ DbgFree(inst);
+ return NULL;
+ }
+
+ inst->state = INST_INIT;
+ inst->requested_state = INST_INIT;
+ instance_ref(inst);
+
+ if (package_add_instance(inst->info, inst) < 0) {
+ instance_destroy(inst, INSTANCE_DESTROY_FAULT);
+ return NULL;
+ }
+
+ slave_load_instance(package_slave(inst->info));
+
+ if (instance_activate(inst) < 0) {
+ instance_state_reset(inst);
+ instance_destroy(inst, INSTANCE_DESTROY_FAULT);
+ inst = NULL;
+ }
+
+ return inst;
+}
+
+HAPI struct inst_info *instance_ref(struct inst_info *inst)
+{
+ if (!inst) {
+ return NULL;
+ }
+
+ inst->refcnt++;
+ return inst;
+}
+
+HAPI struct inst_info *instance_unref(struct inst_info *inst)
+{
+ if (!inst) {
+ return NULL;
+ }
+
+ if (inst->refcnt == 0) {
+ ErrPrint("Instance refcnt is not valid\n");
+ return NULL;
+ }
+
+ inst->refcnt--;
+ if (inst->refcnt == 0) {
+ destroy_instance(inst);
+ inst = NULL;
+ }
+
+ return inst;
+}
+
+static void deactivate_cb(struct slave_node *slave, const struct packet *packet, void *data)
+{
+ struct inst_info *inst = data;
+ int ret;
+
+ /*!
+ * \note
+ * In this callback, we cannot trust the "client" information.
+ * It could be cleared before reach to here.
+ */
+
+ if (!packet) {
+ /*!
+ * \note
+ * The instance_reload will care this.
+ * And it will be called from the slave activate callback.
+ */
+ goto out;
+ }
+
+ if (packet_get(packet, "i", &ret) != 1) {
+ ErrPrint("Invalid argument\n");
+ goto out;
+ }
+
+ DbgPrint("[%s] %d (0x%X)\n", inst->id, ret, inst->state);
+
+ if (inst->state == INST_DESTROYED) {
+ /*!
+ * \note
+ * Already destroyed.
+ * Do nothing at here anymore.
+ */
+ goto out;
+ }
+
+ switch (ret) {
+ case 0:
+ /*!
+ * \note
+ * Successfully unloaded
+ */
+ switch (inst->requested_state) {
+ case INST_ACTIVATED:
+ instance_state_reset(inst);
+ instance_reactivate(inst);
+ break;
+ case INST_DESTROYED:
+ instance_broadcast_deleted_event(inst, ret);
+ instance_state_reset(inst);
+ instance_destroy(inst, INSTANCE_DESTROY_DEFAULT);
+ default:
+ /*!< Unable to reach here */
+ break;
+ }
+
+ break;
+ case LB_STATUS_ERROR_INVALID:
+ /*!
+ * \note
+ * Slave has no instance of this package.
+ */
+ case LB_STATUS_ERROR_NOT_EXIST:
+ /*!
+ * \note
+ * This instance's previous state is only can be the INST_ACTIVATED.
+ * So we should care the slave_unload_instance from here.
+ * And we should send notification to clients, about this is deleted.
+ */
+ /*!
+ * \note
+ * Slave has no instance of this.
+ * In this case, ignore the requested_state
+ * Because, this instance is already met a problem.
+ */
+ default:
+ /*!
+ * \note
+ * Failed to unload this instance.
+ * This is not possible, slave will always return LB_STATUS_ERROR_NOT_EXIST, LB_STATUS_ERROR_INVALID, or 0.
+ * but care this exceptional case.
+ */
+ instance_broadcast_deleted_event(inst, ret);
+ instance_state_reset(inst);
+ instance_destroy(inst, INSTANCE_DESTROY_DEFAULT);
+ break;
+ }
+
+out:
+ inst->changing_state = 0;
+ instance_unref(inst);
+}
+
+static void reactivate_cb(struct slave_node *slave, const struct packet *packet, void *data)
+{
+ struct inst_info *inst = data;
+ enum lb_type lb_type;
+ enum pd_type pd_type;
+ int ret;
+ const char *content;
+ const char *title;
+ int is_pinned_up;
+
+ if (!packet) {
+ /*!
+ * \note
+ * instance_reload function will care this.
+ * and it will be called from the slave_activate callback
+ */
+ goto out;
+ }
+
+ if (packet_get(packet, "issi", &ret, &content, &title, &is_pinned_up) != 4) {
+ ErrPrint("Invalid parameter\n");
+ goto out;
+ }
+
+ if (strlen(content)) {
+ char *tmp;
+
+ tmp = strdup(content);
+ if (!tmp) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ goto out;
+ }
+
+ DbgFree(inst->content);
+ inst->content = tmp;
+ }
+
+ if (strlen(title)) {
+ char *tmp;
+
+ tmp = strdup(title);
+ if (!tmp) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ goto out;
+ }
+
+ DbgFree(inst->title);
+ inst->title = tmp;
+ }
+
+ if (inst->state == INST_DESTROYED) {
+ /*!
+ * \note
+ * Already destroyed.
+ * Do nothing at here anymore.
+ */
+ goto out;
+ }
+
+ switch (ret) {
+ case 0: /*!< normally created */
+ inst->state = INST_ACTIVATED;
+ switch (inst->requested_state) {
+ case INST_DESTROYED:
+ instance_destroy(inst, INSTANCE_DESTROY_DEFAULT);
+ break;
+ case INST_ACTIVATED:
+ inst->is_pinned_up = is_pinned_up;
+ lb_type = package_lb_type(inst->info);
+ pd_type = package_pd_type(inst->info);
+
+ /*!
+ * \note
+ * Optimization point.
+ * In case of the BUFFER type,
+ * the slave will request the buffer to render its contents.
+ * so the buffer will be automatcially recreated when it gots the
+ * buffer request packet.
+ * so load a buffer from here is not neccessary.
+ * I should to revise it and concrete the concept.
+ * Just leave it only for now.
+ */
+
+ if (lb_type == LB_TYPE_SCRIPT && inst->lb.canvas.script) {
+ script_handler_load(inst->lb.canvas.script, 0);
+ } else if (lb_type == LB_TYPE_BUFFER && inst->lb.canvas.buffer) {
+ buffer_handler_load(inst->lb.canvas.buffer);
+ }
+
+ if (pd_type == PD_TYPE_SCRIPT && inst->pd.canvas.script && inst->pd.is_opened_for_reactivate) {
+ double x, y;
+ /*!
+ * \note
+ * We should to send a request to open a PD to slave.
+ * if we didn't send it, the slave will not recognize the state of a PD.
+ * We have to keep the view of PD seamless even if the livebox is reactivated.
+ * To do that, send open request from here.
+ */
+ ret = instance_slave_open_pd(inst, NULL);
+ instance_slave_get_pd_pos(inst, &x, &y);
+
+ /*!
+ * \note
+ * In this case, master already loads the PD script.
+ * So just send the pd,show event to the slave again.
+ */
+ ret = instance_signal_emit(inst, "pd,show", instance_id(inst), 0.0, 0.0, 0.0, 0.0, x, y, 0);
+ } else if (pd_type == PD_TYPE_BUFFER && inst->pd.canvas.buffer && inst->pd.is_opened_for_reactivate) {
+ double x, y;
+
+ buffer_handler_load(inst->pd.canvas.buffer);
+ instance_slave_get_pd_pos(inst, &x, &y);
+
+ /*!
+ * \note
+ * We should to send a request to open a PD to slave.
+ * if we didn't send it, the slave will not recognize the state of a PD.
+ * We have to keep the view of PD seamless even if the livebox is reactivated.
+ * To do that, send open request from here.
+ */
+ ret = instance_slave_open_pd(inst, NULL);
+
+ /*!
+ * \note
+ * In this case, just send the pd,show event for keeping the compatibility
+ */
+ ret = instance_signal_emit(inst, "pd,show", instance_id(inst), 0.0, 0.0, 0.0, 0.0, x, y, 0);
+ }
+
+ /*!
+ * \note
+ * After create an instance again,
+ * Send resize request to the livebox.
+ * instance_resize(inst, inst->lb.width, inst->lb.height);
+ *
+ * renew request will resize the livebox while creating it again
+ */
+
+ /*!
+ * \note
+ * This function will check the visiblity of a livebox and
+ * make decision whether it thaw the update timer or not.
+ */
+ instance_recover_visible_state(inst);
+ default:
+ break;
+ }
+ break;
+ default:
+ instance_broadcast_deleted_event(inst, ret);
+ instance_state_reset(inst);
+ instance_destroy(inst, INSTANCE_DESTROY_DEFAULT);
+ break;
+ }
+
+out:
+ inst->changing_state = 0;
+ instance_unref(inst);
+}
+
+static void activate_cb(struct slave_node *slave, const struct packet *packet, void *data)
+{
+ struct inst_info *inst = data;
+ int ret;
+ int w;
+ int h;
+ double priority;
+ char *content;
+ char *title;
+ int is_pinned_up;
+
+ if (!packet) {
+ /*!
+ * \note
+ * instance_reload will care this
+ * it will be called from the slave_activate callback
+ */
+ goto out;
+ }
+
+ if (packet_get(packet, "iiidssi", &ret, &w, &h, &priority, &content, &title, &is_pinned_up) != 7) {
+ ErrPrint("Invalid parameter\n");
+ goto out;
+ }
+
+ DbgPrint("[%s] returns %d (state: 0x%X)\n", inst->id, ret, inst->state);
+
+ if (inst->state == INST_DESTROYED) {
+ /*!
+ * \note
+ * Already destroyed.
+ * Do nothing at here anymore.
+ */
+ goto out;
+ }
+
+ switch (ret) {
+ case 1: /*!< need to create */
+ if (util_free_space(IMAGE_PATH) > MINIMUM_SPACE) {
+ struct inst_info *new_inst;
+ new_inst = instance_create(inst->client, util_timestamp(), package_name(inst->info),
+ inst->content, inst->cluster, inst->category,
+ inst->lb.period, 0, 0);
+ if (!new_inst) {
+ ErrPrint("Failed to create a new instance\n");
+ }
+ } else {
+ ErrPrint("Not enough space\n");
+ }
+ case 0: /*!< normally created */
+ /*!
+ * \note
+ * Anyway this instance is loaded to the slave,
+ * just increase the loaded instance counter
+ * And then reset jobs.
+ */
+ instance_set_lb_size(inst, w, h);
+ instance_set_lb_info(inst, priority, content, title);
+
+ inst->state = INST_ACTIVATED;
+
+ switch (inst->requested_state) {
+ case INST_DESTROYED:
+ instance_unicast_deleted_event(inst, NULL, ret);
+ instance_state_reset(inst);
+ instance_destroy(inst, INSTANCE_DESTROY_DEFAULT);
+ break;
+ case INST_ACTIVATED:
+ default:
+ /*!
+ * \note
+ * LB should be created at the create time
+ */
+ inst->is_pinned_up = is_pinned_up;
+ if (package_lb_type(inst->info) == LB_TYPE_SCRIPT) {
+ if (inst->lb.width == 0 && inst->lb.height == 0) {
+ livebox_service_get_size(LB_SIZE_TYPE_1x1, &inst->lb.width, &inst->lb.height);
+ }
+
+ inst->lb.canvas.script = script_handler_create(inst,
+ package_lb_path(inst->info),
+ package_lb_group(inst->info),
+ inst->lb.width, inst->lb.height);
+
+ if (!inst->lb.canvas.script) {
+ ErrPrint("Failed to create LB\n");
+ } else {
+ script_handler_load(inst->lb.canvas.script, 0);
+ }
+ } else if (package_lb_type(inst->info) == LB_TYPE_BUFFER) {
+ instance_create_lb_buffer(inst, DEFAULT_PIXELS);
+ }
+
+ if (package_pd_type(inst->info) == PD_TYPE_SCRIPT) {
+ if (inst->pd.width == 0 && inst->pd.height == 0) {
+ instance_set_pd_size(inst, package_pd_width(inst->info), package_pd_height(inst->info));
+ }
+
+ inst->pd.canvas.script = script_handler_create(inst,
+ package_pd_path(inst->info),
+ package_pd_group(inst->info),
+ inst->pd.width, inst->pd.height);
+
+ if (!inst->pd.canvas.script) {
+ ErrPrint("Failed to create PD\n");
+ }
+ } else if (package_pd_type(inst->info) == PD_TYPE_BUFFER) {
+ instance_create_pd_buffer(inst, DEFAULT_PIXELS);
+ }
+
+ instance_broadcast_created_event(inst);
+
+ instance_thaw_updator(inst);
+ break;
+ }
+ break;
+ default:
+ instance_unicast_deleted_event(inst, NULL, ret);
+ instance_state_reset(inst);
+ instance_destroy(inst, INSTANCE_DESTROY_DEFAULT);
+ break;
+ }
+
+out:
+ inst->changing_state = 0;
+ instance_unref(inst);
+}
+
+HAPI int instance_create_pd_buffer(struct inst_info *inst, int pixels)
+{
+ if (inst->pd.width == 0 && inst->pd.height == 0) {
+ instance_set_pd_size(inst, package_pd_width(inst->info), package_pd_height(inst->info));
+ }
+
+ if (!inst->pd.canvas.buffer) {
+ inst->pd.canvas.buffer = buffer_handler_create(inst, s_info.env_buf_type, inst->pd.width, inst->pd.height, pixels);
+ if (!inst->pd.canvas.buffer) {
+ ErrPrint("Failed to create PD Buffer\n");
+ }
+ }
+
+ return !!inst->pd.canvas.buffer;
+}
+
+HAPI int instance_create_lb_buffer(struct inst_info *inst, int pixels)
+{
+ if (inst->lb.width == 0 && inst->lb.height == 0) {
+ livebox_service_get_size(LB_SIZE_TYPE_1x1, &inst->lb.width, &inst->lb.height);
+ }
+
+ if (!inst->lb.canvas.buffer) {
+ /*!
+ * \note
+ * Slave doesn't call the acquire_buffer.
+ * In this case, create the buffer from here.
+ */
+ inst->lb.canvas.buffer = buffer_handler_create(inst, s_info.env_buf_type, inst->lb.width, inst->lb.height, pixels);
+ if (!inst->lb.canvas.buffer) {
+ ErrPrint("Failed to create LB\n");
+ }
+ }
+
+ return !!inst->lb.canvas.buffer;
+}
+
+HAPI int instance_destroy(struct inst_info *inst, enum instance_destroy_type type)
+{
+ struct packet *packet;
+
+ if (!inst) {
+ ErrPrint("Invalid instance handle\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ switch (inst->state) {
+ case INST_REQUEST_TO_ACTIVATE:
+ case INST_REQUEST_TO_DESTROY:
+ case INST_REQUEST_TO_REACTIVATE:
+ inst->requested_state = INST_DESTROYED;
+ return LB_STATUS_SUCCESS;
+ case INST_INIT:
+ inst->state = INST_DESTROYED;
+ inst->requested_state = INST_DESTROYED;
+ (void)instance_unref(inst);
+ return LB_STATUS_SUCCESS;
+ case INST_DESTROYED:
+ inst->requested_state = INST_DESTROYED;
+ return LB_STATUS_SUCCESS;
+ default:
+ break;
+ }
+
+ packet = packet_create("delete", "ssi", package_name(inst->info), inst->id, type);
+ if (!packet) {
+ ErrPrint("Failed to build a packet for %s\n", package_name(inst->info));
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ inst->destroy_type = type;
+ inst->requested_state = INST_DESTROYED;
+ inst->state = INST_REQUEST_TO_DESTROY;
+ inst->changing_state = 1;
+ return slave_rpc_async_request(package_slave(inst->info), package_name(inst->info), packet, deactivate_cb, instance_ref(inst), 0);
+}
+
+HAPI int instance_reload(struct inst_info *inst, enum instance_destroy_type type)
+{
+ struct packet *packet;
+ int ret;
+
+ if (!inst) {
+ ErrPrint("Invalid instance handle\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ DbgPrint("Reload instance (%s)\n", instance_id(inst));
+
+ switch (inst->state) {
+ case INST_REQUEST_TO_ACTIVATE:
+ case INST_REQUEST_TO_REACTIVATE:
+ return LB_STATUS_SUCCESS;
+ case INST_INIT:
+ ret = instance_activate(inst);
+ if (ret < 0) {
+ ErrPrint("Failed to activate instance: %d (%s)\n", ret, instance_id(inst));
+ }
+ return LB_STATUS_SUCCESS;
+ case INST_DESTROYED:
+ case INST_REQUEST_TO_DESTROY:
+ DbgPrint("Instance is destroying now\n");
+ return LB_STATUS_SUCCESS;
+ default:
+ break;
+ }
+
+ packet = packet_create("delete", "ssi", package_name(inst->info), inst->id, type);
+ if (!packet) {
+ ErrPrint("Failed to build a packet for %s\n", package_name(inst->info));
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ inst->destroy_type = type;
+ inst->requested_state = INST_ACTIVATED;
+ inst->state = INST_REQUEST_TO_DESTROY;
+ inst->changing_state = 1;
+ return slave_rpc_async_request(package_slave(inst->info), package_name(inst->info), packet, deactivate_cb, instance_ref(inst), 0);
+}
+
+/* Client Deactivated Callback */
+static int pd_buffer_close_cb(struct client_node *client, void *inst)
+{
+ int ret;
+
+ ret = instance_slave_close_pd(inst, client, LB_CLOSE_PD_NORMAL);
+ if (ret < 0) {
+ DbgPrint("Forcely close the PD ret: %d\n", ret);
+ }
+
+ instance_unref(inst);
+
+ return -1; /* Delete this callback */
+}
+
+/* Client Deactivated Callback */
+static int pd_script_close_cb(struct client_node *client, void *inst)
+{
+ int ret;
+
+ ret = script_handler_unload(instance_pd_script(inst), 1);
+ if (ret < 0) {
+ DbgPrint("Unload script: %d\n", ret);
+ }
+
+ ret = instance_slave_close_pd(inst, client, LB_CLOSE_PD_NORMAL);
+ if (ret < 0) {
+ DbgPrint("Forcely close the PD ret: %d\n", ret);
+ }
+
+ instance_unref(inst);
+
+ return -1; /* Delete this callback */
+}
+
+static inline void release_resource_for_closing_pd(struct pkg_info *info, struct inst_info *inst, struct client_node *client)
+{
+ if (!client) {
+ client = inst->pd.owner;
+ if (!client) {
+ return;
+ }
+ }
+
+ /*!
+ * \note
+ * Clean up the resources
+ */
+ if (package_pd_type(info) == PD_TYPE_BUFFER) {
+ if (client_event_callback_del(client, CLIENT_EVENT_DEACTIVATE, pd_buffer_close_cb, inst) == 0) {
+ /*!
+ * \note
+ * Only if this function succeed to remove the pd_buffer_close_cb,
+ * Decrease the reference count of this instance
+ */
+ instance_unref(inst);
+ }
+ } else if (package_pd_type(info) == PD_TYPE_SCRIPT) {
+ if (client_event_callback_del(client, CLIENT_EVENT_DEACTIVATE, pd_script_close_cb, inst) == 0) {
+ /*!
+ * \note
+ * Only if this function succeed to remove the script_close_cb,
+ * Decrease the reference count of this instance
+ */
+ instance_unref(inst);
+ }
+ } else {
+ ErrPrint("Unknown PD type\n");
+ }
+
+}
+
+HAPI int instance_state_reset(struct inst_info *inst)
+{
+ enum lb_type lb_type;
+ enum pd_type pd_type;
+
+ if (!inst) {
+ ErrPrint("Invalid instance handle\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (inst->state == INST_DESTROYED) {
+ goto out;
+ }
+
+ lb_type = package_lb_type(inst->info);
+ pd_type = package_pd_type(inst->info);
+
+ if (lb_type == LB_TYPE_SCRIPT && inst->lb.canvas.script) {
+ script_handler_unload(inst->lb.canvas.script, 0);
+ } else if (lb_type == LB_TYPE_BUFFER && inst->lb.canvas.buffer) {
+ buffer_handler_unload(inst->lb.canvas.buffer);
+ }
+
+ if (pd_type == PD_TYPE_SCRIPT && inst->pd.canvas.script) {
+ inst->pd.is_opened_for_reactivate = script_handler_is_loaded(inst->pd.canvas.script);
+ release_resource_for_closing_pd(instance_package(inst), inst, NULL);
+ script_handler_unload(inst->pd.canvas.script, 1);
+ } else if (pd_type == PD_TYPE_BUFFER && inst->pd.canvas.buffer) {
+ inst->pd.is_opened_for_reactivate = buffer_handler_is_loaded(inst->pd.canvas.buffer);
+ release_resource_for_closing_pd(instance_package(inst), inst, NULL);
+ buffer_handler_unload(inst->pd.canvas.buffer);
+ }
+
+out:
+ inst->state = INST_INIT;
+ inst->requested_state = INST_INIT;
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI int instance_reactivate(struct inst_info *inst)
+{
+ struct packet *packet;
+ int ret;
+
+ if (!inst) {
+ ErrPrint("Invalid instance handle\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (package_is_fault(inst->info)) {
+ ErrPrint("Fault package [%s]\n", package_name(inst->info));
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ switch (inst->state) {
+ case INST_REQUEST_TO_DESTROY:
+ case INST_REQUEST_TO_ACTIVATE:
+ case INST_REQUEST_TO_REACTIVATE:
+ inst->requested_state = INST_ACTIVATED;
+ return LB_STATUS_SUCCESS;
+ case INST_DESTROYED:
+ case INST_ACTIVATED:
+ return LB_STATUS_SUCCESS;
+ case INST_INIT:
+ default:
+ break;
+ }
+
+ packet = packet_create("renew", "sssiidssiisii",
+ package_name(inst->info),
+ inst->id,
+ inst->content,
+ package_timeout(inst->info),
+ !!package_lb_path(inst->info),
+ inst->lb.period,
+ inst->cluster,
+ inst->category,
+ inst->lb.width, inst->lb.height,
+ package_abi(inst->info),
+ inst->scroll_locked,
+ inst->active_update);
+ if (!packet) {
+ ErrPrint("Failed to build a packet for %s\n", package_name(inst->info));
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ ret = slave_activate(package_slave(inst->info));
+ if (ret < 0 && ret != LB_STATUS_ERROR_ALREADY) {
+ /*!
+ * \note
+ * If the master failed to launch the slave,
+ * Do not send any requests to the slave.
+ */
+ ErrPrint("Failed to launch the slave\n");
+ packet_destroy(packet);
+ return ret;
+ }
+
+ inst->requested_state = INST_ACTIVATED;
+ inst->state = INST_REQUEST_TO_REACTIVATE;
+ inst->changing_state = 1;
+
+ return slave_rpc_async_request(package_slave(inst->info), package_name(inst->info), packet, reactivate_cb, instance_ref(inst), 1);
+}
+
+HAPI int instance_activate(struct inst_info *inst)
+{
+ struct packet *packet;
+ int ret;
+
+ if (!inst) {
+ ErrPrint("Invalid instance handle\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (package_is_fault(inst->info)) {
+ ErrPrint("Fault package [%s]\n", package_name(inst->info));
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ switch (inst->state) {
+ case INST_REQUEST_TO_REACTIVATE:
+ case INST_REQUEST_TO_ACTIVATE:
+ case INST_REQUEST_TO_DESTROY:
+ inst->requested_state = INST_ACTIVATED;
+ return LB_STATUS_SUCCESS;
+ case INST_ACTIVATED:
+ case INST_DESTROYED:
+ return LB_STATUS_SUCCESS;
+ case INST_INIT:
+ default:
+ break;
+ }
+
+ packet = packet_create("new", "sssiidssisii",
+ package_name(inst->info),
+ inst->id,
+ inst->content,
+ package_timeout(inst->info),
+ !!package_lb_path(inst->info),
+ inst->lb.period,
+ inst->cluster,
+ inst->category,
+ !!inst->client,
+ package_abi(inst->info),
+ inst->lb.width,
+ inst->lb.height);
+ if (!packet) {
+ ErrPrint("Failed to build a packet for %s\n", package_name(inst->info));
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ ret = slave_activate(package_slave(inst->info));
+ if (ret < 0 && ret != LB_STATUS_ERROR_ALREADY) {
+ /*!
+ * \note
+ * If the master failed to launch the slave,
+ * Do not send any requests to the slave.
+ */
+ ErrPrint("Failed to launch the slave\n");
+ packet_destroy(packet);
+ return ret;
+ }
+
+ inst->state = INST_REQUEST_TO_ACTIVATE;
+ inst->requested_state = INST_ACTIVATED;
+ inst->changing_state = 1;
+
+ /*!
+ * \note
+ * Try to activate a slave if it is not activated
+ */
+ return slave_rpc_async_request(package_slave(inst->info), package_name(inst->info), packet, activate_cb, instance_ref(inst), 1);
+}
+
+HAPI int instance_lb_update_begin(struct inst_info *inst, double priority, const char *content, const char *title)
+{
+ struct packet *packet;
+ const char *fbfile;
+
+ if (!inst->active_update) {
+ ErrPrint("Invalid request [%s]\n", inst->id);
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ switch (package_lb_type(inst->info)) {
+ case LB_TYPE_BUFFER:
+ if (!inst->lb.canvas.buffer) {
+ ErrPrint("Buffer is null [%s]\n", inst->id);
+ return LB_STATUS_ERROR_INVALID;
+ }
+ fbfile = buffer_handler_id(inst->lb.canvas.buffer);
+ break;
+ case LB_TYPE_SCRIPT:
+ if (!inst->lb.canvas.script) {
+ ErrPrint("Script is null [%s]\n", inst->id);
+ return LB_STATUS_ERROR_INVALID;
+ }
+ fbfile = script_handler_buffer_id(inst->lb.canvas.script);
+ break;
+ default:
+ ErrPrint("Invalid request[%s]\n", inst->id);
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ packet = packet_create_noack("lb_update_begin", "ssdsss", package_name(inst->info), inst->id, priority, content, title, fbfile);
+ if (!packet) {
+ ErrPrint("Unable to create a packet\n");
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ return CLIENT_SEND_EVENT(inst, packet);
+}
+
+HAPI int instance_lb_update_end(struct inst_info *inst)
+{
+ struct packet *packet;
+
+ if (!inst->active_update) {
+ ErrPrint("Invalid request [%s]\n", inst->id);
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ switch (package_lb_type(inst->info)) {
+ case LB_TYPE_BUFFER:
+ if (!inst->lb.canvas.buffer) {
+ ErrPrint("Buffer is null [%s]\n", inst->id);
+ return LB_STATUS_ERROR_INVALID;
+ }
+ break;
+ case LB_TYPE_SCRIPT:
+ if (!inst->lb.canvas.script) {
+ ErrPrint("Script is null [%s]\n", inst->id);
+ return LB_STATUS_ERROR_INVALID;
+ }
+ break;
+ default:
+ ErrPrint("Invalid request[%s]\n", inst->id);
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ packet = packet_create_noack("lb_update_end", "ss", package_name(inst->info), inst->id);
+ if (!packet) {
+ ErrPrint("Unable to create a packet\n");
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ return CLIENT_SEND_EVENT(inst, packet);
+}
+
+HAPI int instance_pd_update_begin(struct inst_info *inst)
+{
+ struct packet *packet;
+ const char *fbfile;
+
+ if (!inst->active_update) {
+ ErrPrint("Invalid request [%s]\n", inst->id);
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ switch (package_pd_type(inst->info)) {
+ case PD_TYPE_BUFFER:
+ if (!inst->pd.canvas.buffer) {
+ ErrPrint("Buffer is null [%s]\n", inst->id);
+ return LB_STATUS_ERROR_INVALID;
+ }
+ fbfile = buffer_handler_id(inst->pd.canvas.buffer);
+ break;
+ case PD_TYPE_SCRIPT:
+ if (!inst->pd.canvas.script) {
+ ErrPrint("Script is null [%s]\n", inst->id);
+ return LB_STATUS_ERROR_INVALID;
+ }
+ fbfile = script_handler_buffer_id(inst->pd.canvas.script);
+ break;
+ default:
+ ErrPrint("Invalid request[%s]\n", inst->id);
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ packet = packet_create_noack("pd_update_begin", "sss", package_name(inst->info), inst->id, fbfile);
+ if (!packet) {
+ ErrPrint("Unable to create a packet\n");
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ return CLIENT_SEND_EVENT(inst, packet);
+}
+
+HAPI int instance_pd_update_end(struct inst_info *inst)
+{
+ struct packet *packet;
+
+ if (!inst->active_update) {
+ ErrPrint("Invalid request [%s]\n", inst->id);
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ switch (package_pd_type(inst->info)) {
+ case PD_TYPE_BUFFER:
+ if (!inst->pd.canvas.buffer) {
+ ErrPrint("Buffer is null [%s]\n", inst->id);
+ return LB_STATUS_ERROR_INVALID;
+ }
+ break;
+ case PD_TYPE_SCRIPT:
+ if (!inst->pd.canvas.script) {
+ ErrPrint("Script is null [%s]\n", inst->id);
+ return LB_STATUS_ERROR_INVALID;
+ }
+ break;
+ default:
+ ErrPrint("Invalid request[%s]\n", inst->id);
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ packet = packet_create_noack("pd_update_end", "ss", package_name(inst->info), inst->id);
+ if (!packet) {
+ ErrPrint("Unable to create a packet\n");
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ return CLIENT_SEND_EVENT(inst, packet);
+}
+
+HAPI void instance_lb_updated_by_instance(struct inst_info *inst, const char *safe_file)
+{
+ struct packet *packet;
+ const char *id;
+ enum lb_type lb_type;
+ const char *title;
+ const char *content;
+ const char *icon;
+ const char *name;
+
+ if (inst->client && inst->visible != LB_SHOW) {
+ if (inst->visible == LB_HIDE) {
+ DbgPrint("Ignore update event %s(HIDE)\n", inst->id);
+ return;
+ }
+ DbgPrint("Livebox(%s) is PAUSED. But content is updated.\n", inst->id);
+ }
+
+ lb_type = package_lb_type(inst->info);
+ if (lb_type == LB_TYPE_SCRIPT) {
+ id = script_handler_buffer_id(inst->lb.canvas.script);
+ } else if (lb_type == LB_TYPE_BUFFER) {
+ id = buffer_handler_id(inst->lb.canvas.buffer);
+ } else {
+ id = "";
+ }
+
+ if (inst->content) {
+ content = inst->content;
+ } else {
+ content = "";
+ }
+
+ if (inst->title) {
+ title = inst->title;
+ } else {
+ title = "";
+ }
+
+ if (inst->icon) {
+ icon = inst->icon;
+ } else {
+ icon = "";
+ }
+
+ if (inst->name) {
+ name = inst->name;
+ } else {
+ name = "";
+ }
+
+ packet = packet_create_noack("lb_updated", "sssiidsssss",
+ package_name(inst->info), inst->id, id,
+ inst->lb.width, inst->lb.height, inst->lb.priority, content, title, safe_file, icon, name);
+ if (!packet) {
+ ErrPrint("Failed to create param (%s - %s)\n", package_name(inst->info), inst->id);
+ return;
+ }
+
+ (void)CLIENT_SEND_EVENT(inst, packet);
+}
+
+HAPI int instance_hold_scroll(struct inst_info *inst, int hold)
+{
+ struct packet *packet;
+
+ DbgPrint("HOLD: (%s) %d\n", inst->id, hold);
+ if (inst->scroll_locked == hold) {
+ return LB_STATUS_ERROR_ALREADY;
+ }
+
+ packet = packet_create_noack("scroll", "ssi", package_name(inst->info), inst->id, hold);
+ if (!packet) {
+ ErrPrint("Failed to build a packet\n");
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ inst->scroll_locked = hold;
+ return CLIENT_SEND_EVENT(inst, packet);
+}
+
+HAPI void instance_pd_updated_by_instance(struct inst_info *inst, const char *descfile)
+{
+ struct packet *packet;
+ const char *id;
+
+ if (inst->client && inst->visible != LB_SHOW) {
+ DbgPrint("Livebox is hidden. ignore update event\n");
+ return;
+ }
+
+ if (!inst->pd.need_to_send_close_event) {
+ DbgPrint("PD is not created yet. Ignore update event - %s\n", descfile);
+
+ if (inst->pd.pended_update_desc) {
+ DbgFree(inst->pd.pended_update_desc);
+ inst->pd.pended_update_desc = NULL;
+ }
+
+ if (descfile) {
+ inst->pd.pended_update_desc = strdup(descfile);
+ if (!inst->pd.pended_update_desc) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ }
+ }
+
+ inst->pd.pended_update_cnt++;
+ return;
+ }
+
+ if (!descfile) {
+ descfile = inst->id;
+ }
+
+ switch (package_pd_type(inst->info)) {
+ case PD_TYPE_SCRIPT:
+ id = script_handler_buffer_id(inst->pd.canvas.script);
+ break;
+ case PD_TYPE_BUFFER:
+ id = buffer_handler_id(inst->pd.canvas.buffer);
+ break;
+ case PD_TYPE_TEXT:
+ default:
+ id = "";
+ break;
+ }
+
+ packet = packet_create_noack("pd_updated", "ssssii",
+ package_name(inst->info), inst->id, descfile, id,
+ inst->pd.width, inst->pd.height);
+ if (!packet) {
+ ErrPrint("Failed to create param (%s - %s)\n", package_name(inst->info), inst->id);
+ return;
+ }
+
+ (void)CLIENT_SEND_EVENT(inst, packet);
+}
+
+HAPI void instance_pd_updated(const char *pkgname, const char *id, const char *descfile)
+{
+ struct inst_info *inst;
+
+ inst = package_find_instance_by_id(pkgname, id);
+ if (!inst) {
+ return;
+ }
+
+ instance_pd_updated_by_instance(inst, descfile);
+}
+
+HAPI int instance_set_update_mode(struct inst_info *inst, int active_update)
+{
+ struct packet *packet;
+ struct update_mode_cbdata *cbdata;
+
+ if (package_is_fault(inst->info)) {
+ ErrPrint("Fault package [%s]\n", package_name(inst->info));
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ if (inst->active_update == active_update) {
+ DbgPrint("Active update is not changed: %d\n", inst->active_update);
+ return LB_STATUS_ERROR_ALREADY;
+ }
+
+ cbdata = malloc(sizeof(*cbdata));
+ if (!cbdata) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ cbdata->inst = instance_ref(inst);
+ cbdata->active_update = active_update;
+
+ /* NOTE: param is resued from here */
+ packet = packet_create("update_mode", "ssi", package_name(inst->info), inst->id, active_update);
+ if (!packet) {
+ ErrPrint("Failed to build a packet for %s\n", package_name(inst->info));
+ instance_unref(cbdata->inst);
+ DbgFree(cbdata);
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ return slave_rpc_async_request(package_slave(inst->info), package_name(inst->info), packet, update_mode_cb, cbdata, 0);
+}
+
+HAPI int instance_active_update(struct inst_info *inst)
+{
+ return inst->active_update;
+}
+
+HAPI void instance_set_lb_info(struct inst_info *inst, double priority, const char *content, const char *title)
+{
+ char *_content = NULL;
+ char *_title = NULL;
+
+ if (content && strlen(content)) {
+ _content = strdup(content);
+ if (!_content) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ }
+ }
+
+ if (title && strlen(title)) {
+ _title = strdup(title);
+ if (!_title) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ }
+ }
+
+ if (_content) {
+ DbgFree(inst->content);
+ inst->content= _content;
+ }
+
+ if (_title) {
+ DbgFree(inst->title);
+ inst->title = _title;
+ }
+
+ if (priority >= 0.0f && priority <= 1.0f) {
+ inst->lb.priority = priority;
+ }
+}
+
+HAPI void instance_set_alt_info(struct inst_info *inst, const char *icon, const char *name)
+{
+ char *_icon = NULL;
+ char *_name = NULL;
+
+ if (icon && strlen(icon)) {
+ _icon = strdup(icon);
+ if (!_icon) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ }
+ }
+
+ if (name && strlen(name)) {
+ _name = strdup(name);
+ if (!_name) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ }
+ }
+
+ if (_icon) {
+ DbgFree(inst->icon);
+ inst->icon = _icon;
+ }
+
+ if (_name) {
+ DbgFree(inst->name);
+ inst->name = _name;
+ }
+}
+
+HAPI void instance_set_lb_size(struct inst_info *inst, int w, int h)
+{
+ if (inst->lb.width != w || inst->lb.height != h) {
+ instance_send_resized_event(inst, IS_LB, w, h, LB_STATUS_SUCCESS);
+ }
+
+ inst->lb.width = w;
+ inst->lb.height = h;
+}
+
+HAPI void instance_set_pd_size(struct inst_info *inst, int w, int h)
+{
+ if (inst->pd.width != w || inst->pd.height != h) {
+ instance_send_resized_event(inst, IS_PD, w, h, LB_STATUS_SUCCESS);
+ }
+
+ inst->pd.width = w;
+ inst->pd.height = h;
+}
+
+static void pinup_cb(struct slave_node *slave, const struct packet *packet, void *data)
+{
+ struct set_pinup_cbdata *cbdata = data;
+ const char *content;
+ struct packet *result;
+ int ret;
+
+ if (!packet) {
+ /*!
+ * \todo
+ * Send pinup failed event to client.
+ */
+ ret = LB_STATUS_ERROR_INVALID;
+ goto out;
+ }
+
+ if (packet_get(packet, "is", &ret, &content) != 2) {
+ /*!
+ * \todo
+ * Send pinup failed event to client
+ */
+ ret = LB_STATUS_ERROR_INVALID;
+ goto out;
+ }
+
+ if (ret == 0) {
+ char *new_content;
+
+ new_content = strdup(content);
+ if (!new_content) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ /*!
+ * \note
+ * send pinup failed event to client
+ */
+ ret = LB_STATUS_ERROR_MEMORY;
+ goto out;
+ }
+
+ cbdata->inst->is_pinned_up = cbdata->pinup;
+ DbgFree(cbdata->inst->content);
+
+ cbdata->inst->content = new_content;
+ }
+
+out:
+ /*!
+ * \node
+ * Send PINUP Result to client.
+ * Client should wait this event.
+ */
+ result = packet_create_noack("pinup", "iisss", ret, cbdata->inst->is_pinned_up,
+ package_name(cbdata->inst->info), cbdata->inst->id, cbdata->inst->content);
+ if (result) {
+ (void)CLIENT_SEND_EVENT(cbdata->inst, result);
+ } else {
+ ErrPrint("Failed to build a packet for %s\n", package_name(cbdata->inst->info));
+ }
+
+ instance_unref(cbdata->inst);
+ DbgFree(cbdata);
+}
+
+HAPI int instance_set_pinup(struct inst_info *inst, int pinup)
+{
+ struct set_pinup_cbdata *cbdata;
+ struct packet *packet;
+
+ if (!inst) {
+ ErrPrint("Invalid instance handle\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (package_is_fault(inst->info)) {
+ ErrPrint("Fault package [%s]\n", package_name(inst->info));
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ if (!package_pinup(inst->info)) {
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (pinup == inst->is_pinned_up) {
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ cbdata = malloc(sizeof(*cbdata));
+ if (!cbdata) {
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ cbdata->inst = instance_ref(inst);
+ cbdata->pinup = pinup;
+
+ packet = packet_create("pinup", "ssi", package_name(inst->info), inst->id, pinup);
+ if (!packet) {
+ ErrPrint("Failed to build a packet for %s\n", package_name(inst->info));
+ instance_unref(cbdata->inst);
+ DbgFree(cbdata);
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ return slave_rpc_async_request(package_slave(inst->info), package_name(inst->info), packet, pinup_cb, cbdata, 0);
+}
+
+HAPI int instance_freeze_updator(struct inst_info *inst)
+{
+ if (!inst->update_timer) {
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ timer_freeze(inst);
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI int instance_thaw_updator(struct inst_info *inst)
+{
+ if (!inst->update_timer) {
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (client_is_all_paused() || setting_is_lcd_off()) {
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (inst->visible == LB_HIDE_WITH_PAUSE) {
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ timer_thaw(inst);
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI enum livebox_visible_state instance_visible_state(struct inst_info *inst)
+{
+ return inst->visible;
+}
+
+HAPI int instance_set_visible_state(struct inst_info *inst, enum livebox_visible_state state)
+{
+ if (inst->visible == state) {
+ return LB_STATUS_SUCCESS;
+ }
+
+ switch (state) {
+ case LB_SHOW:
+ case LB_HIDE:
+ if (inst->visible == LB_HIDE_WITH_PAUSE) {
+ if (resume_livebox(inst) == 0) {
+ inst->visible = state;
+ }
+
+ instance_thaw_updator(inst);
+ } else {
+ inst->visible = state;
+ }
+ break;
+
+ case LB_HIDE_WITH_PAUSE:
+ if (pause_livebox(inst) == 0) {
+ inst->visible = LB_HIDE_WITH_PAUSE;
+ }
+
+ instance_freeze_updator(inst);
+ break;
+
+ default:
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ return LB_STATUS_SUCCESS;
+}
+
+static void resize_cb(struct slave_node *slave, const struct packet *packet, void *data)
+{
+ struct resize_cbdata *cbdata = data;
+ int ret;
+
+ if (!packet) {
+ ErrPrint("RESIZE: Invalid packet\n");
+ instance_send_resized_event(cbdata->inst, IS_LB, cbdata->inst->lb.width, cbdata->inst->lb.height, LB_STATUS_ERROR_FAULT);
+ instance_unref(cbdata->inst);
+ DbgFree(cbdata);
+ return;
+ }
+
+ if (packet_get(packet, "i", &ret) != 1) {
+ ErrPrint("RESIZE: Invalid parameter\n");
+ instance_send_resized_event(cbdata->inst, IS_LB, cbdata->inst->lb.width, cbdata->inst->lb.height, LB_STATUS_ERROR_INVALID);
+ instance_unref(cbdata->inst);
+ DbgFree(cbdata);
+ return;
+ }
+
+ if (ret == (int)LB_STATUS_SUCCESS) {
+ /*!
+ * \note
+ * else waiting the first update with new size
+ */
+ if (cbdata->inst->lb.width == cbdata->w && cbdata->inst->lb.height == cbdata->h) {
+ /*!
+ * \note
+ * Right after the viewer adds a new box,
+ * Box has no size information, then it will try to use the default size,
+ * After a box returns created event.
+ *
+ * A box will start to generate default size content.
+ * But the viewer doesn't know it,.
+ *
+ * So the viewer will try to change the size of a box.
+ *
+ * At that time, the provider gots the size changed event from the box.
+ * So it sent the size changed event to the viewer.
+ * But the viewer ignores it. if it doesn't care the size changed event.
+ * (even if it cares the size changed event, there is a timing issue)
+ *
+ * And the provider receives resize request,
+ * right before send the size changed event.
+ * but there is no changes about the size.
+ *
+ * Now the view will waits size changed event forever.
+ * To resolve this timing issue.
+ *
+ * Check the size of a box from here.
+ * And if the size is already updated, send the ALREADY event to the viewer
+ * to get the size changed event callback correctly.
+ */
+ instance_send_resized_event(cbdata->inst, IS_LB, cbdata->inst->lb.width, cbdata->inst->lb.height, LB_STATUS_ERROR_ALREADY);
+ DbgPrint("RESIZE: Livebox is already resized [%s - %dx%d]\n", instance_id(cbdata->inst), cbdata->w, cbdata->h);
+ } else {
+ DbgPrint("RESIZE: Request is successfully sent [%s - %dx%d]\n", instance_id(cbdata->inst), cbdata->w, cbdata->h);
+ }
+ } else {
+ DbgPrint("RESIZE: Livebox rejects the new size: %s - %dx%d (%d)\n", instance_id(cbdata->inst), cbdata->w, cbdata->h, ret);
+ instance_send_resized_event(cbdata->inst, IS_LB, cbdata->inst->lb.width, cbdata->inst->lb.height, ret);
+ }
+
+ instance_unref(cbdata->inst);
+ DbgFree(cbdata);
+}
+
+HAPI int instance_resize(struct inst_info *inst, int w, int h)
+{
+ struct resize_cbdata *cbdata;
+ struct packet *packet;
+ int ret;
+
+ if (!inst) {
+ ErrPrint("Invalid instance handle\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (package_is_fault(inst->info)) {
+ ErrPrint("Fault package: %s\n", package_name(inst->info));
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ cbdata = malloc(sizeof(*cbdata));
+ if (!cbdata) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ cbdata->inst = instance_ref(inst);
+ cbdata->w = w;
+ cbdata->h = h;
+
+ /* NOTE: param is resued from here */
+ packet = packet_create("resize", "ssii", package_name(inst->info), inst->id, w, h);
+ if (!packet) {
+ ErrPrint("Failed to build a packet for %s\n", package_name(inst->info));
+ instance_unref(cbdata->inst);
+ DbgFree(cbdata);
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ DbgPrint("RESIZE: [%s] resize[%dx%d]\n", instance_id(inst), w, h);
+ ret = slave_rpc_async_request(package_slave(inst->info), package_name(inst->info), packet, resize_cb, cbdata, 0);
+ return ret;
+}
+
+static void set_period_cb(struct slave_node *slave, const struct packet *packet, void *data)
+{
+ int ret;
+ struct period_cbdata *cbdata = data;
+ struct packet *result;
+
+ if (!packet) {
+ ret = LB_STATUS_ERROR_FAULT;
+ goto out;
+ }
+
+ if (packet_get(packet, "i", &ret) != 1) {
+ ret = LB_STATUS_ERROR_INVALID;
+ goto out;
+ }
+
+ if (ret == 0) {
+ cbdata->inst->lb.period = cbdata->period;
+ } else {
+ ErrPrint("Failed to set period %d\n", ret);
+ }
+
+out:
+ result = packet_create_noack("period_changed", "idss", ret, cbdata->inst->lb.period, package_name(cbdata->inst->info), cbdata->inst->id);
+ if (result) {
+ (void)CLIENT_SEND_EVENT(cbdata->inst, result);
+ } else {
+ ErrPrint("Failed to build a packet for %s\n", package_name(cbdata->inst->info));
+ }
+
+ instance_unref(cbdata->inst);
+ DbgFree(cbdata);
+ return;
+}
+
+static Eina_Bool timer_updator_cb(void *data)
+{
+ struct period_cbdata *cbdata = data;
+ struct inst_info *inst;
+ double period;
+ struct packet *result;
+
+ period = cbdata->period;
+ inst = cbdata->inst;
+ DbgFree(cbdata);
+
+ inst->lb.period = period;
+ if (inst->update_timer) {
+ if (inst->lb.period == 0.0f) {
+ ecore_timer_del(inst->update_timer);
+ inst->update_timer = NULL;
+ } else {
+ util_timer_interval_set(inst->update_timer, inst->lb.period);
+ }
+ } else if (inst->lb.period > 0.0f) {
+ inst->update_timer = util_timer_add(inst->lb.period, update_timer_cb, inst);
+ if (!inst->update_timer) {
+ ErrPrint("Failed to add an update timer for instance %s\n", inst->id);
+ } else {
+ timer_freeze(inst); /* Freeze the update timer as default */
+ }
+ }
+
+ result = packet_create_noack("period_changed", "idss", 0, inst->lb.period, package_name(inst->info), inst->id);
+ if (result) {
+ (void)CLIENT_SEND_EVENT(inst, result);
+ } else {
+ ErrPrint("Failed to build a packet for %s\n", package_name(inst->info));
+ }
+
+ instance_unref(inst);
+ return ECORE_CALLBACK_CANCEL;
+}
+
+HAPI void instance_reload_period(struct inst_info *inst, double period)
+{
+ inst->lb.period = period;
+}
+
+HAPI int instance_set_period(struct inst_info *inst, double period)
+{
+ struct packet *packet;
+ struct period_cbdata *cbdata;
+
+ if (!inst) {
+ ErrPrint("Invalid instance handle\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (package_is_fault(inst->info)) {
+ ErrPrint("Fault package [%s]\n", package_name(inst->info));
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ if (period < 0.0f) { /* Use the default period */
+ period = package_period(inst->info);
+ } else if (period > 0.0f && period < MINIMUM_PERIOD) {
+ period = MINIMUM_PERIOD; /* defined at conf.h */
+ }
+
+ cbdata = malloc(sizeof(*cbdata));
+ if (!cbdata) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ cbdata->period = period;
+ cbdata->inst = instance_ref(inst);
+
+ if (package_secured(inst->info)) {
+ /*!
+ * \note
+ * Secured livebox doesn't need to send its update period to the slave.
+ * Slave has no local timer for updating liveboxes
+ *
+ * So update its timer at here.
+ */
+ if (!ecore_timer_add(DELAY_TIME, timer_updator_cb, cbdata)) {
+ timer_updator_cb(cbdata);
+ }
+ return LB_STATUS_SUCCESS;
+ }
+
+ packet = packet_create("set_period", "ssd", package_name(inst->info), inst->id, period);
+ if (!packet) {
+ ErrPrint("Failed to build a packet for %s\n", package_name(inst->info));
+ instance_unref(cbdata->inst);
+ DbgFree(cbdata);
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ return slave_rpc_async_request(package_slave(inst->info), package_name(inst->info), packet, set_period_cb, cbdata, 0);
+}
+
+HAPI int instance_clicked(struct inst_info *inst, const char *event, double timestamp, double x, double y)
+{
+ struct packet *packet;
+
+ if (!inst) {
+ ErrPrint("Invalid instance handle\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (package_is_fault(inst->info)) {
+ ErrPrint("Fault package [%s]\n", package_name(inst->info));
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ /* NOTE: param is resued from here */
+ packet = packet_create_noack("clicked", "sssddd", package_name(inst->info), inst->id, event, timestamp, x, y);
+ if (!packet) {
+ ErrPrint("Failed to build a packet for %s\n", package_name(inst->info));
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ return slave_rpc_request_only(package_slave(inst->info), package_name(inst->info), packet, 0);
+}
+
+HAPI int instance_signal_emit(struct inst_info *inst, const char *signal, const char *part, double sx, double sy, double ex, double ey, double x, double y, int down)
+{
+ const char *pkgname;
+ const char *id;
+ struct slave_node *slave;
+ struct packet *packet;
+ struct pkg_info *pkg;
+
+ pkg = instance_package(inst);
+ pkgname = package_name(pkg);
+ id = instance_id(inst);
+ if (!pkgname || !id) {
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ slave = package_slave(pkg);
+ if (!slave) {
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ packet = packet_create_noack("script", "ssssddddddi",
+ pkgname, id,
+ signal, part,
+ sx, sy, ex, ey,
+ x, y, down);
+ if (!packet) {
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ return slave_rpc_request_only(slave, pkgname, packet, 0);
+}
+
+HAPI int instance_text_signal_emit(struct inst_info *inst, const char *emission, const char *source, double sx, double sy, double ex, double ey)
+{
+ struct packet *packet;
+
+ if (!inst) {
+ ErrPrint("Invalid instance handle\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (package_is_fault(inst->info)) {
+ ErrPrint("Fault package [%s]\n", package_name(inst->info));
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ packet = packet_create_noack("text_signal", "ssssdddd", package_name(inst->info), inst->id, emission, source, sx, sy, ex, ey);
+ if (!packet) {
+ ErrPrint("Failed to build a packet for %s\n", package_name(inst->info));
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ return slave_rpc_request_only(package_slave(inst->info), package_name(inst->info), packet, 0);
+}
+
+static void change_group_cb(struct slave_node *slave, const struct packet *packet, void *data)
+{
+ struct change_group_cbdata *cbdata = data;
+ struct packet *result;
+ int ret;
+
+ if (!packet) {
+ DbgFree(cbdata->cluster);
+ DbgFree(cbdata->category);
+ ret = LB_STATUS_ERROR_FAULT;
+ goto out;
+ }
+
+ if (packet_get(packet, "i", &ret) != 1) {
+ ErrPrint("Invalid packet\n");
+ DbgFree(cbdata->cluster);
+ DbgFree(cbdata->category);
+ ret = LB_STATUS_ERROR_INVALID;
+ goto out;
+ }
+
+ if (ret == 0) {
+ DbgFree(cbdata->inst->cluster);
+ cbdata->inst->cluster = cbdata->cluster;
+
+ DbgFree(cbdata->inst->category);
+ cbdata->inst->category = cbdata->category;
+ } else {
+ DbgFree(cbdata->cluster);
+ DbgFree(cbdata->category);
+ }
+
+out:
+ result = packet_create_noack("group_changed", "ssiss",
+ package_name(cbdata->inst->info), cbdata->inst->id, ret,
+ cbdata->inst->cluster, cbdata->inst->category);
+ if (!result) {
+ ErrPrint("Failed to build a packet %s\n", package_name(cbdata->inst->info));
+ } else {
+ (void)CLIENT_SEND_EVENT(cbdata->inst, result);
+ }
+
+ instance_unref(cbdata->inst);
+ DbgFree(cbdata);
+}
+
+HAPI int instance_change_group(struct inst_info *inst, const char *cluster, const char *category)
+{
+ struct packet *packet;
+ struct change_group_cbdata *cbdata;
+
+ if (!inst) {
+ ErrPrint("Invalid instance handle\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (package_is_fault(inst->info)) {
+ ErrPrint("Fault package [%s]\n", package_name(inst->info));
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ cbdata = malloc(sizeof(*cbdata));
+ if (!cbdata) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ cbdata->cluster = strdup(cluster);
+ if (!cbdata->cluster) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(cbdata);
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ cbdata->category = strdup(category);
+ if (!cbdata->category) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(cbdata->cluster);
+ DbgFree(cbdata);
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ cbdata->inst = instance_ref(inst);
+
+ packet = packet_create("change_group","ssss", package_name(inst->info), inst->id, cluster, category);
+ if (!packet) {
+ ErrPrint("Failed to build a packet for %s\n", package_name(inst->info));
+ instance_unref(cbdata->inst);
+ DbgFree(cbdata->category);
+ DbgFree(cbdata->cluster);
+ DbgFree(cbdata);
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ return slave_rpc_async_request(package_slave(inst->info), package_name(inst->info), packet, change_group_cb, cbdata, 0);
+}
+
+HAPI const char * const instance_auto_launch(const struct inst_info *inst)
+{
+ return package_auto_launch(inst->info);
+}
+
+HAPI const int const instance_priority(const struct inst_info *inst)
+{
+ return inst->lb.priority;
+}
+
+HAPI const struct client_node *const instance_client(const struct inst_info *inst)
+{
+ return inst->client;
+}
+
+HAPI const int const instance_timeout(const struct inst_info *inst)
+{
+ return package_timeout(inst->info);
+}
+
+HAPI const double const instance_period(const struct inst_info *inst)
+{
+ return inst->lb.period;
+}
+
+HAPI const int const instance_lb_width(const struct inst_info *inst)
+{
+ return inst->lb.width;
+}
+
+HAPI const int const instance_lb_height(const struct inst_info *inst)
+{
+ return inst->lb.height;
+}
+
+HAPI const int const instance_pd_width(const struct inst_info *inst)
+{
+ return inst->pd.width;
+}
+
+HAPI const int const instance_pd_height(const struct inst_info *inst)
+{
+ return inst->pd.height;
+}
+
+HAPI struct pkg_info *const instance_package(const struct inst_info *inst)
+{
+ return inst->info;
+}
+
+HAPI struct script_info *const instance_lb_script(const struct inst_info *inst)
+{
+ return (package_lb_type(inst->info) == LB_TYPE_SCRIPT) ? inst->lb.canvas.script : NULL;
+}
+
+HAPI struct script_info *const instance_pd_script(const struct inst_info *inst)
+{
+ return (package_pd_type(inst->info) == PD_TYPE_SCRIPT) ? inst->pd.canvas.script : NULL;
+}
+
+HAPI struct buffer_info *const instance_lb_buffer(const struct inst_info *inst)
+{
+ return (package_lb_type(inst->info) == LB_TYPE_BUFFER) ? inst->lb.canvas.buffer : NULL;
+}
+
+HAPI struct buffer_info *const instance_pd_buffer(const struct inst_info *inst)
+{
+ return (package_pd_type(inst->info) == PD_TYPE_BUFFER) ? inst->pd.canvas.buffer : NULL;
+}
+
+HAPI const char *const instance_id(const struct inst_info *inst)
+{
+ return inst->id;
+}
+
+HAPI const char *const instance_content(const struct inst_info *inst)
+{
+ return inst->content;
+}
+
+HAPI const char *const instance_category(const struct inst_info *inst)
+{
+ return inst->category;
+}
+
+HAPI const char *const instance_cluster(const struct inst_info *inst)
+{
+ return inst->cluster;
+}
+
+HAPI const char * const instance_title(const struct inst_info *inst)
+{
+ return inst->title;
+}
+
+HAPI const double const instance_timestamp(const struct inst_info *inst)
+{
+ return inst->timestamp;
+}
+
+HAPI const enum instance_state const instance_state(const struct inst_info *inst)
+{
+ return inst->state;
+}
+
+HAPI int instance_destroyed(struct inst_info *inst, int reason)
+{
+ switch (inst->state) {
+ case INST_INIT:
+ case INST_REQUEST_TO_ACTIVATE:
+ /*!
+ * \note
+ * No other clients know the existence of this instance,
+ * only who added this knows it.
+ * So send deleted event to only it.
+ */
+ DbgPrint("Send deleted event - unicast - %p\n", inst->client);
+ instance_unicast_deleted_event(inst, NULL, reason);
+ instance_state_reset(inst);
+ instance_destroy(inst, INSTANCE_DESTROY_DEFAULT);
+ break;
+ case INST_REQUEST_TO_REACTIVATE:
+ case INST_REQUEST_TO_DESTROY:
+ case INST_ACTIVATED:
+ DbgPrint("Send deleted event - multicast\n");
+ instance_broadcast_deleted_event(inst, reason);
+ instance_state_reset(inst);
+ instance_destroy(inst, INSTANCE_DESTROY_DEFAULT);
+ case INST_DESTROYED:
+ break;
+ default:
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ return LB_STATUS_SUCCESS;
+}
+
+/*!
+ * Invoked when a slave is activated
+ */
+HAPI int instance_recover_state(struct inst_info *inst)
+{
+ int ret = 0;
+
+ if (inst->changing_state) {
+ DbgPrint("Doesn't need to recover the state\n");
+ return LB_STATUS_SUCCESS;
+ }
+
+ if (package_is_fault(inst->info)) {
+ ErrPrint("Package is faulted(%s), Delete it\n", inst->id);
+ inst->requested_state = INST_DESTROYED;
+ }
+
+ switch (inst->state) {
+ case INST_ACTIVATED:
+ case INST_REQUEST_TO_REACTIVATE:
+ case INST_REQUEST_TO_DESTROY:
+ switch (inst->requested_state) {
+ case INST_ACTIVATED:
+ DbgPrint("Req. to RE-ACTIVATED (%s)\n", package_name(inst->info));
+ instance_state_reset(inst);
+ instance_reactivate(inst);
+ ret = 1;
+ break;
+ case INST_DESTROYED:
+ DbgPrint("Req. to DESTROYED (%s)\n", package_name(inst->info));
+ instance_state_reset(inst);
+ instance_destroy(inst, INSTANCE_DESTROY_DEFAULT);
+ break;
+ default:
+ break;
+ }
+ break;
+ case INST_INIT:
+ case INST_REQUEST_TO_ACTIVATE:
+ switch (inst->requested_state) {
+ case INST_ACTIVATED:
+ case INST_INIT:
+ DbgPrint("Req. to ACTIVATED (%s)\n", package_name(inst->info));
+ instance_state_reset(inst);
+ if (instance_activate(inst) < 0) {
+ DbgPrint("Failed to reactivate the instance\n");
+ instance_broadcast_deleted_event(inst, LB_STATUS_ERROR_FAULT);
+ instance_state_reset(inst);
+ instance_destroy(inst, INSTANCE_DESTROY_DEFAULT);
+ } else {
+ ret = 1;
+ }
+ break;
+ case INST_DESTROYED:
+ DbgPrint("Req. to DESTROYED (%s)\n", package_name(inst->info));
+ instance_state_reset(inst);
+ instance_destroy(inst, INSTANCE_DESTROY_DEFAULT);
+ break;
+ default:
+ break;
+ }
+ break;
+ case INST_DESTROYED:
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+/*!
+ * Invoked when a slave is deactivated
+ */
+HAPI int instance_need_slave(struct inst_info *inst)
+{
+ int ret = 0;
+
+ if (inst->client && client_is_faulted(inst->client)) {
+ /*!
+ * \note
+ * In this case, the client is faulted(disconnected)
+ * when the client is deactivated, its liveboxes should be removed too.
+ * So if the current inst is created by the faulted client,
+ * remove it and don't try to recover its states
+ */
+
+ DbgPrint("CLIENT FAULT: Req. to DESTROYED (%s)\n", package_name(inst->info));
+ switch (inst->state) {
+ case INST_INIT:
+ case INST_ACTIVATED:
+ case INST_REQUEST_TO_REACTIVATE:
+ case INST_REQUEST_TO_DESTROY:
+ case INST_REQUEST_TO_ACTIVATE:
+ instance_state_reset(inst);
+ instance_destroy(inst, INSTANCE_DESTROY_DEFAULT);
+ break;
+ case INST_DESTROYED:
+ break;
+ }
+
+ return LB_STATUS_SUCCESS;
+ }
+
+ switch (inst->state) {
+ case INST_ACTIVATED:
+ case INST_REQUEST_TO_REACTIVATE:
+ case INST_REQUEST_TO_DESTROY:
+ switch (inst->requested_state) {
+ case INST_INIT:
+ case INST_ACTIVATED:
+ DbgPrint("Req. to ACTIVATED (%s)\n", package_name(inst->info));
+ ret = 1;
+ break;
+ case INST_DESTROYED:
+ DbgPrint("Req. to DESTROYED (%s)\n", package_name(inst->info));
+ instance_state_reset(inst);
+ instance_destroy(inst, INSTANCE_DESTROY_DEFAULT);
+ break;
+ default:
+ break;
+ }
+ break;
+ case INST_INIT:
+ case INST_REQUEST_TO_ACTIVATE:
+ switch (inst->requested_state) {
+ case INST_INIT:
+ case INST_ACTIVATED:
+ DbgPrint("Req. to ACTIVATED (%s)\n", package_name(inst->info));
+ ret = 1;
+ break;
+ case INST_DESTROYED:
+ DbgPrint("Req. to DESTROYED (%s)\n", package_name(inst->info));
+ instance_state_reset(inst);
+ instance_destroy(inst, INSTANCE_DESTROY_DEFAULT);
+ break;
+ default:
+ break;
+ }
+ break;
+ case INST_DESTROYED:
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+HAPI int instance_forward_packet(struct inst_info *inst, struct packet *packet)
+{
+ return CLIENT_SEND_EVENT(inst, packet);
+}
+
+HAPI int instance_send_key_status(struct inst_info *inst, int status)
+{
+ struct packet *packet;
+
+ packet = packet_create_noack("key_status", "ssi", package_name(inst->info), inst->id, status);
+ if (!packet) {
+ ErrPrint("Failed to build a packet\n");
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ return CLIENT_SEND_EVENT(inst, packet);
+}
+
+HAPI int instance_send_access_status(struct inst_info *inst, int status)
+{
+ struct packet *packet;
+
+ packet = packet_create_noack("access_status", "ssi", package_name(inst->info), inst->id, status);
+ if (!packet) {
+ ErrPrint("Failed to build a packet\n");
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ return CLIENT_SEND_EVENT(inst, packet);
+}
+
+HAPI void instance_slave_set_pd_pos(struct inst_info *inst, double x, double y)
+{
+ inst->pd.x = x;
+ inst->pd.y = y;
+}
+
+HAPI void instance_slave_get_pd_pos(struct inst_info *inst, double *x, double *y)
+{
+ if (x) {
+ *x = inst->pd.x;
+ }
+
+ if (y) {
+ *y = inst->pd.y;
+ }
+}
+
+HAPI int instance_slave_open_pd(struct inst_info *inst, struct client_node *client)
+{
+ const char *pkgname;
+ const char *id;
+ struct packet *packet;
+ struct slave_node *slave;
+ const struct pkg_info *info;
+ int ret;
+
+ if (!client) {
+ client = inst->pd.owner;
+ if (!client) {
+ ErrPrint("Client is not valid\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+ } else if (inst->pd.owner) {
+ if (inst->pd.owner != client) {
+ ErrPrint("Client is already owned\n");
+ return LB_STATUS_ERROR_ALREADY;
+ }
+ }
+
+ info = instance_package(inst);
+ if (!info) {
+ ErrPrint("No package info\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ slave = package_slave(info);
+ if (!slave) {
+ ErrPrint("No slave\n");
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ pkgname = package_name(info);
+ id = instance_id(inst);
+
+ if (!pkgname || !id) {
+ ErrPrint("pkgname[%s] id[%s]\n", pkgname, id);
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ packet = packet_create_noack("pd_show", "ssiidd", pkgname, id, instance_pd_width(inst), instance_pd_height(inst), inst->pd.x, inst->pd.y);
+ if (!packet) {
+ ErrPrint("Failed to create a packet\n");
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ /*!
+ * \note
+ * Do not return from here even though we failed to freeze the TTL timer.
+ * Because the TTL timer is not able to be exists.
+ * So we can ignore this error.
+ */
+ (void)slave_freeze_ttl(slave);
+
+ DbgPrint("PERF_DBOX\n");
+ ret = slave_rpc_request_only(slave, pkgname, packet, 0);
+ if (ret < 0) {
+ ErrPrint("Unable to send request to slave\n");
+ /*!
+ * \note
+ * Also we can ignore the TTL timer at here too ;)
+ */
+ (void)slave_thaw_ttl(slave);
+ return ret;
+ }
+
+ /*!
+ * \note
+ * If a client is disconnected, the slave has to close the PD
+ * So the pd_buffer_close_cb/pd_script_close_cb will catch the disconnection event
+ * then it will send the close request to the slave
+ */
+ if (package_pd_type(info) == PD_TYPE_BUFFER) {
+ instance_ref(inst);
+ if (client_event_callback_add(client, CLIENT_EVENT_DEACTIVATE, pd_buffer_close_cb, inst) < 0) {
+ instance_unref(inst);
+ }
+ } else if (package_pd_type(info) == PD_TYPE_SCRIPT) {
+ instance_ref(inst);
+ if (client_event_callback_add(client, CLIENT_EVENT_DEACTIVATE, pd_script_close_cb, inst) < 0) {
+ instance_unref(inst);
+ }
+ }
+
+ inst->pd.owner = client;
+ return ret;
+}
+
+HAPI int instance_slave_close_pd(struct inst_info *inst, struct client_node *client, int reason)
+{
+ const char *pkgname;
+ const char *id;
+ struct packet *packet;
+ struct slave_node *slave;
+ struct pkg_info *pkg;
+ int ret;
+
+ if (inst->pd.owner != client) {
+ ErrPrint("Has no permission\n");
+ return LB_STATUS_ERROR_PERMISSION;
+ }
+
+ pkg = instance_package(inst);
+ if (!pkg) {
+ ErrPrint("No package info\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ slave = package_slave(pkg);
+ if (!slave) {
+ ErrPrint("No assigned slave\n");
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ pkgname = package_name(pkg);
+ id = instance_id(inst);
+
+ if (!pkgname || !id) {
+ ErrPrint("pkgname[%s] & id[%s] is not valid\n", pkgname, id);
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ packet = packet_create_noack("pd_hide", "ssi", pkgname, id, reason);
+ if (!packet) {
+ ErrPrint("Failed to create a packet\n");
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ slave_thaw_ttl(slave);
+
+ ret = slave_rpc_request_only(slave, pkgname, packet, 0);
+ release_resource_for_closing_pd(pkg, inst, client);
+ inst->pd.owner = NULL;
+ DbgPrint("PERF_DBOX\n");
+ return ret;
+}
+
+HAPI int instance_client_pd_created(struct inst_info *inst, int status)
+{
+ struct packet *packet;
+ const char *buf_id;
+ int ret;
+
+ if (inst->pd.need_to_send_close_event) {
+ DbgPrint("PD is already created\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ switch (package_pd_type(inst->info)) {
+ case PD_TYPE_SCRIPT:
+ buf_id = script_handler_buffer_id(inst->pd.canvas.script);
+ break;
+ case PD_TYPE_BUFFER:
+ buf_id = buffer_handler_id(inst->pd.canvas.buffer);
+ break;
+ case PD_TYPE_TEXT:
+ default:
+ buf_id = "";
+ break;
+ }
+
+ inst->pd.need_to_send_close_event = (status == 0);
+
+ packet = packet_create_noack("pd_created", "sssiii",
+ package_name(inst->info), inst->id, buf_id,
+ inst->pd.width, inst->pd.height, status);
+ if (!packet) {
+ ErrPrint("Failed to create a packet\n");
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ ret = CLIENT_SEND_EVENT(inst, packet);
+
+ if (inst->pd.need_to_send_close_event && inst->pd.pended_update_cnt) {
+ DbgPrint("Apply pended desc(%d) - %s\n", inst->pd.pended_update_cnt, inst->pd.pended_update_desc);
+ instance_pd_updated_by_instance(inst, inst->pd.pended_update_desc);
+ inst->pd.pended_update_cnt = 0;
+ DbgFree(inst->pd.pended_update_desc);
+ inst->pd.pended_update_desc = NULL;
+ }
+
+ return ret;
+}
+
+HAPI int instance_client_pd_destroyed(struct inst_info *inst, int status)
+{
+ return send_pd_destroyed_to_client(inst, status);
+}
+
+HAPI int instance_add_client(struct inst_info *inst, struct client_node *client)
+{
+ if (inst->client == client) {
+ ErrPrint("Owner cannot be the viewer\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ DbgPrint("%d is added to the list of viewer of %s(%s)\n", client_pid(client), package_name(instance_package(inst)), instance_id(inst));
+ if (client_event_callback_add(client, CLIENT_EVENT_DEACTIVATE, viewer_deactivated_cb, inst) < 0) {
+ ErrPrint("Failed to add a deactivate callback\n");
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ instance_ref(inst);
+ inst->client_list = eina_list_append(inst->client_list, client);
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI int instance_del_client(struct inst_info *inst, struct client_node *client)
+{
+ if (inst->client == client) {
+ ErrPrint("Owner is not in the viewer list\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ client_event_callback_del(client, CLIENT_EVENT_DEACTIVATE, viewer_deactivated_cb, inst);
+ viewer_deactivated_cb(client, inst);
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI int instance_has_client(struct inst_info *inst, struct client_node *client)
+{
+ return !!eina_list_data_find(inst->client_list, client);
+}
+
+HAPI void *instance_client_list(struct inst_info *inst)
+{
+ return inst->client_list;
+}
+
+HAPI int instance_init(void)
+{
+ if (!strcasecmp(PROVIDER_METHOD, "shm")) {
+ s_info.env_buf_type = BUFFER_TYPE_SHM;
+ } else if (!strcasecmp(PROVIDER_METHOD, "pixmap")) {
+ s_info.env_buf_type = BUFFER_TYPE_PIXMAP;
+ }
+ /* Default method is BUFFER_TYPE_FILE */
+
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI int instance_fini(void)
+{
+ return LB_STATUS_SUCCESS;
+}
+
+static inline struct tag_item *find_tag_item(struct inst_info *inst, const char *tag)
+{
+ struct tag_item *item;
+ Eina_List *l;
+
+ EINA_LIST_FOREACH(inst->data_list, l, item) {
+ if (!strcmp(item->tag, tag)) {
+ return item;
+ }
+ }
+
+ return NULL;
+}
+
+HAPI int instance_set_data(struct inst_info *inst, const char *tag, void *data)
+{
+ struct tag_item *item;
+
+ item = find_tag_item(inst, tag);
+ if (!item) {
+ item = malloc(sizeof(*item));
+ if (!item) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ item->tag = strdup(tag);
+ if (!item->tag) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ DbgFree(item);
+ return LB_STATUS_ERROR_MEMORY;
+ }
+
+ inst->data_list = eina_list_append(inst->data_list, item);
+ }
+
+ if (!data) {
+ inst->data_list = eina_list_remove(inst->data_list, item);
+ DbgFree(item->tag);
+ DbgFree(item);
+ } else {
+ item->data = data;
+ }
+
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI void *instance_del_data(struct inst_info *inst, const char *tag)
+{
+ struct tag_item *item;
+ void *data;
+
+ item = find_tag_item(inst, tag);
+ if (!item) {
+ return NULL;
+ }
+
+ inst->data_list = eina_list_remove(inst->data_list, item);
+ data = item->data;
+ DbgFree(item->tag);
+ DbgFree(item);
+
+ return data;
+}
+
+HAPI void *instance_get_data(struct inst_info *inst, const char *tag)
+{
+ struct tag_item *item;
+
+ item = find_tag_item(inst, tag);
+ if (!item) {
+ return NULL;
+ }
+
+ return item->data;
+}
+
+HAPI struct client_node *instance_pd_owner(struct inst_info *inst)
+{
+ return inst->pd.owner;
+}
+
+/* End of a file */
diff --git a/src/io.c b/src/io.c
new file mode 100644
index 0000000..8593ab7
--- /dev/null
+++ b/src/io.c
@@ -0,0 +1,895 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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 <stdio.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include <dlog.h>
+#include <Eina.h>
+#include <sqlite3.h>
+#include <db-util.h>
+#include <livebox-errno.h>
+
+#include "debug.h"
+#include "conf.h"
+#include "parser.h"
+#include "group.h"
+#include "util.h"
+#include "client_life.h"
+#include "slave_life.h"
+#include "package.h"
+#include "abi.h"
+#include "io.h"
+
+int errno;
+
+static struct {
+ sqlite3 *handle;
+} s_info = {
+ .handle = NULL,
+};
+
+static int load_abi_table(void)
+{
+ FILE *fp;
+ int ch;
+ int idx = 0;
+ int tag_id = 0;
+ enum {
+ INIT = 0x0,
+ GROUP = 0x1,
+ TAG = 0x02,
+ VALUE = 0x03,
+ ERROR = 0x05
+ } state;
+ enum {
+ PKGNAME = 0x0,
+ };
+ static const char *field[] = {
+ "package",
+ NULL,
+ };
+ const char *ptr = NULL;
+
+ char group[MAX_ABI + 1];
+ char pkgname[MAX_PKGNAME + 1];
+
+ fp = fopen("/usr/share/"PACKAGE"/abi.ini", "rt");
+ if (!fp) {
+ return LB_STATUS_ERROR_IO;
+ }
+
+ state = INIT;
+ while ((ch = getc(fp)) != EOF && state != ERROR) {
+ switch (state) {
+ case INIT:
+ if (isspace(ch)) {
+ continue;
+ }
+ if (ch == '[') {
+ state = GROUP;
+ idx = 0;
+ } else {
+ state = ERROR;
+ }
+ break;
+ case GROUP:
+ if (ch == ']') {
+ if (idx == 0) {
+ state = ERROR;
+ } else {
+ group[idx] = '\0';
+ state = TAG;
+ idx = 0;
+ ptr = NULL;
+ }
+ } else if (idx < MAX_ABI) {
+ group[idx++] = ch;
+ } else {
+ ErrPrint("Overflow\n");
+ state = ERROR;
+ }
+ break;
+ case TAG:
+ if (ptr == NULL) {
+ if (idx == 0) {
+ if (isspace(ch)) {
+ continue;
+ }
+
+ /* New group started */
+ if (ch == '[') {
+ ungetc(ch, fp);
+ state = INIT;
+ continue;
+ }
+ }
+
+ ptr = field[idx];
+ }
+
+ if (ptr == NULL) {
+ ErrPrint("unknown tag\n");
+ state = ERROR;
+ continue;
+ }
+
+ if (*ptr == '\0' && ch == '=') {
+ /* MATCHED */
+ state = VALUE;
+ tag_id = idx;
+ idx = 0;
+ ptr = NULL;
+ } else if (*ptr == ch) {
+ ptr++;
+ } else {
+ ungetc(ch, fp);
+ ptr--;
+ while (ptr >= field[idx]) {
+ ungetc(*ptr, fp);
+ ptr--;
+ }
+ ptr = NULL;
+ idx++;
+ }
+ break;
+ case VALUE:
+ switch (tag_id) {
+ case PKGNAME:
+ if (idx == 0) { /* LTRIM */
+ if (isspace(ch)) {
+ continue;
+ }
+
+ pkgname[idx] = ch;
+ idx++;
+ } else if (isspace(ch)) {
+ int ret;
+ pkgname[idx] = '\0';
+
+ ret = abi_add_entry(group, pkgname);
+ if (ret != 0) {
+ ErrPrint("Failed to add %s for %s\n", pkgname, group);
+ }
+
+ state = TAG;
+ idx = 0;
+ } else if (idx < MAX_PKGNAME) {
+ pkgname[idx] = ch;
+ idx++;
+ } else {
+ ErrPrint("Overflow\n");
+ state = ERROR;
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ case ERROR:
+ default:
+ break;
+ }
+ }
+
+ if (state == VALUE) {
+ switch (tag_id) {
+ case PKGNAME:
+ if (idx) {
+ int ret;
+ pkgname[idx] = '\0';
+ ret = abi_add_entry(group, pkgname);
+ if (ret != 0) {
+ ErrPrint("Failed to add %s for %s\n", pkgname, group);
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (fclose(fp) != 0) {
+ ErrPrint("fclose: %s\n", strerror(errno));
+ }
+ return LB_STATUS_SUCCESS;
+}
+
+static inline int build_client_info(struct pkg_info *info)
+{
+ static const char *dml = "SELECT auto_launch, pd_size FROM client WHERE pkgid = ?";
+ sqlite3_stmt *stmt;
+ int width;
+ int height;
+ int ret;
+ const char *tmp;
+
+ ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
+ if (ret != SQLITE_OK) {
+ ErrPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ return LB_STATUS_ERROR_IO;
+ }
+
+ ret = sqlite3_bind_text(stmt, 1, package_name(info), -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ ErrPrint("Failed to bind a pkgname %s\n", package_name(info));
+ sqlite3_finalize(stmt);
+ return LB_STATUS_ERROR_IO;
+ }
+
+ if (sqlite3_step(stmt) != SQLITE_ROW) {
+ ErrPrint("%s has no records (%s)\n", package_name(info), sqlite3_errmsg(s_info.handle));
+ sqlite3_reset(stmt);
+ sqlite3_clear_bindings(stmt);
+ sqlite3_finalize(stmt);
+ return LB_STATUS_ERROR_IO;
+ }
+
+ package_set_auto_launch(info, (const char *)sqlite3_column_text(stmt, 0));
+
+ tmp = (const char *)sqlite3_column_text(stmt, 1);
+ if (tmp && strlen(tmp)) {
+ if (sscanf(tmp, "%dx%d", &width, &height) != 2) {
+ ErrPrint("Failed to get PD width and Height (%s)\n", tmp);
+ } else {
+ package_set_pd_width(info, width);
+ package_set_pd_height(info, height);
+ }
+ }
+
+ sqlite3_reset(stmt);
+ sqlite3_clear_bindings(stmt);
+ sqlite3_finalize(stmt);
+ return LB_STATUS_SUCCESS;
+}
+
+static inline int build_provider_info(struct pkg_info *info)
+{
+ static const char *dml = "SELECT provider.network, provider.abi, provider.secured, provider.box_type, provider.box_src, provider.box_group, provider.pd_type, provider.pd_src, provider.pd_group, provider.libexec, provider.timeout, provider.period, provider.script, provider.pinup, pkgmap.appid FROM provider, pkgmap WHERE pkgmap.pkgid = ? AND provider.pkgid = ?";
+ sqlite3_stmt *stmt;
+ int ret;
+ const char *tmp;
+ const char *appid;
+
+ ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
+ if (ret != SQLITE_OK) {
+ ErrPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ return LB_STATUS_ERROR_IO;
+ }
+
+ if (sqlite3_bind_text(stmt, 1, package_name(info), -1, SQLITE_TRANSIENT) != SQLITE_OK) {
+ ErrPrint("Failed to bind a pkgname(%s) - %s\n", package_name(info), sqlite3_errmsg(s_info.handle));
+ sqlite3_finalize(stmt);
+ return LB_STATUS_ERROR_IO;
+ }
+
+ if (sqlite3_bind_text(stmt, 2, package_name(info), -1, SQLITE_TRANSIENT) != SQLITE_OK) {
+ ErrPrint("Failed to bind a pkgname(%s) - %s\n", package_name(info), sqlite3_errmsg(s_info.handle));
+ sqlite3_finalize(stmt);
+ return LB_STATUS_ERROR_IO;
+ }
+
+ if (sqlite3_step(stmt) != SQLITE_ROW) {
+ ErrPrint("%s has no record(%s)\n", package_name(info), sqlite3_errmsg(s_info.handle));
+ sqlite3_reset(stmt);
+ sqlite3_clear_bindings(stmt);
+ sqlite3_finalize(stmt);
+ return LB_STATUS_ERROR_IO;
+ }
+
+ appid = (const char *)sqlite3_column_text(stmt, 14);
+ if (!appid || !strlen(appid)) {
+ ErrPrint("Failed to execute the DML for %s\n", package_name(info));
+ sqlite3_reset(stmt);
+ sqlite3_clear_bindings(stmt);
+ sqlite3_finalize(stmt);
+ return LB_STATUS_ERROR_IO;
+ }
+
+ package_set_network(info, sqlite3_column_int(stmt, 0));
+ package_set_secured(info, sqlite3_column_int(stmt, 2));
+
+ tmp = (const char *)sqlite3_column_text(stmt, 1);
+ if (tmp && strlen(tmp)) {
+ package_set_abi(info, tmp);
+ }
+
+ package_set_lb_type(info, sqlite3_column_int(stmt, 3));
+ tmp = (const char *)sqlite3_column_text(stmt, 4);
+ if (tmp && strlen(tmp)) {
+ package_set_lb_path(info, tmp);
+
+ tmp = (const char *)sqlite3_column_text(stmt, 5);
+ if (tmp && strlen(tmp)) {
+ package_set_lb_group(info, tmp);
+ }
+ }
+
+ package_set_pd_type(info, sqlite3_column_int(stmt, 6));
+ tmp = (const char *)sqlite3_column_text(stmt, 7);
+ if (tmp && strlen(tmp)) {
+ package_set_pd_path(info, tmp);
+
+ tmp = (const char *)sqlite3_column_text(stmt, 8);
+ if (tmp && strlen(tmp)) {
+ package_set_pd_group(info, tmp);
+ }
+ }
+
+ tmp = (const char *)sqlite3_column_text(stmt, 9);
+ if (tmp && strlen(tmp)) {
+ package_set_libexec(info, tmp);
+ }
+
+ package_set_timeout(info, sqlite3_column_int(stmt, 10));
+
+ tmp = (const char *)sqlite3_column_text(stmt, 11);
+ if (tmp && strlen(tmp)) {
+ package_set_period(info, atof(tmp));
+ }
+
+ tmp = (const char *)sqlite3_column_text(stmt, 12);
+ if (tmp && strlen(tmp)) {
+ package_set_script(info, tmp);
+ }
+
+ package_set_pinup(info, sqlite3_column_int(stmt, 13));
+
+ sqlite3_reset(stmt);
+ sqlite3_clear_bindings(stmt);
+ sqlite3_finalize(stmt);
+ return LB_STATUS_SUCCESS;
+}
+
+static inline int build_box_size_info(struct pkg_info *info)
+{
+ static const char *dml = "SELECT size_type FROM box_size WHERE pkgid = ?";
+ sqlite3_stmt *stmt;
+ int ret;
+ unsigned int size_type;
+ unsigned int size_list;
+
+ ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
+ if (ret != SQLITE_OK) {
+ ErrPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ return LB_STATUS_ERROR_IO;
+ }
+
+ if (sqlite3_bind_text(stmt, 1, package_name(info), -1, SQLITE_TRANSIENT) != SQLITE_OK) {
+ ErrPrint("Failed to bind a pkgname(%s) - %s\n", package_name(info), sqlite3_errmsg(s_info.handle));
+ sqlite3_finalize(stmt);
+ return LB_STATUS_ERROR_IO;
+ }
+
+ size_list = 0;
+ while (sqlite3_step(stmt) == SQLITE_ROW) {
+ size_type = sqlite3_column_int(stmt, 0);
+ size_list |= size_type;
+ }
+
+ package_set_size_list(info, size_list);
+
+ sqlite3_reset(stmt);
+ sqlite3_clear_bindings(stmt);
+ sqlite3_finalize(stmt);
+ return LB_STATUS_SUCCESS;
+}
+
+static inline int load_context_option(struct context_item *item, int id)
+{
+ static const char *dml = "SELECT key, value FROM option WHERE option_id = ?";
+ sqlite3_stmt *stmt;
+ const char *key;
+ const char *value;
+ int ret;
+
+ ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
+ if (ret != SQLITE_OK) {
+ ErrPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ return LB_STATUS_ERROR_IO;
+ }
+
+ ret = sqlite3_bind_int(stmt, 1, id);
+ if (ret != SQLITE_OK) {
+ ErrPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = LB_STATUS_ERROR_IO;
+ goto out;
+ }
+
+ ret = LB_STATUS_ERROR_NOT_EXIST;
+ while (sqlite3_step(stmt) == SQLITE_ROW) {
+ key = (const char *)sqlite3_column_text(stmt, 0);
+ if (!key || !strlen(key)) {
+ ErrPrint("KEY is nil\n");
+ continue;
+ }
+
+ value = (const char *)sqlite3_column_text(stmt, 1);
+ if (!value || !strlen(value)) {
+ ErrPrint("VALUE is nil\n");
+ continue;
+ }
+
+ ret = group_add_option(item, key, value);
+ if (ret < 0) {
+ break;
+ }
+ }
+
+out:
+ sqlite3_reset(stmt);
+ sqlite3_clear_bindings(stmt);
+ sqlite3_finalize(stmt);
+ return ret;
+}
+
+static inline int load_context_item(struct context_info *info, int id)
+{
+ static const char *dml = "SELECT ctx_item, option_id FROM groupmap WHERE id = ?";
+ struct context_item *item;
+ sqlite3_stmt *stmt;
+ const char *ctx_item;
+ int option_id;
+ int ret;
+
+ ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
+ if (ret != SQLITE_OK) {
+ ErrPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ return LB_STATUS_ERROR_IO;
+ }
+
+ ret = sqlite3_bind_int(stmt, 1, id);
+ if (ret != SQLITE_OK) {
+ ErrPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = LB_STATUS_ERROR_IO;
+ goto out;
+ }
+
+ ret = LB_STATUS_ERROR_NOT_EXIST;
+ while (sqlite3_step(stmt) == SQLITE_ROW) {
+ ctx_item = (const char *)sqlite3_column_text(stmt, 0);
+ option_id = sqlite3_column_int(stmt, 1);
+
+ item = group_add_context_item(info, ctx_item);
+ if (!item) {
+ ErrPrint("Failed to add a new context item\n");
+ ret = LB_STATUS_ERROR_FAULT;
+ break;
+ }
+
+ ret = load_context_option(item, option_id);
+ if (ret < 0) {
+ break;
+ }
+ }
+
+out:
+ sqlite3_reset(stmt);
+ sqlite3_clear_bindings(stmt);
+ sqlite3_finalize(stmt);
+ return ret;
+}
+
+static inline int build_group_info(struct pkg_info *info)
+{
+ static const char *dml = "SELECT id, cluster, category FROM groupinfo WHERE pkgid = ?";
+ sqlite3_stmt *stmt;
+ int ret;
+ int id;
+ const char *cluster_name;
+ const char *category_name;
+ struct cluster *cluster;
+ struct category *category;
+ struct context_info *ctx_info;
+
+ ret = sqlite3_prepare_v2(s_info.handle, dml, -1, &stmt, NULL);
+ if (ret != SQLITE_OK) {
+ ErrPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ return LB_STATUS_ERROR_IO;
+ }
+
+ ret = sqlite3_bind_text(stmt, 1, package_name(info), -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ ErrPrint("Failed to bind a package name(%s)\n", package_name(info));
+ sqlite3_finalize(stmt);
+ return LB_STATUS_ERROR_IO;
+ }
+
+ while (sqlite3_step(stmt) == SQLITE_ROW) {
+ id = sqlite3_column_int(stmt, 0);
+ cluster_name = (const char *)sqlite3_column_text(stmt, 1);
+ if (!cluster_name || !strlen(cluster_name)) {
+ DbgPrint("Cluster name is not valid\n");
+ continue;
+ }
+
+ category_name = (const char *)sqlite3_column_text(stmt, 2);
+ if (!category_name || !strlen(category_name)) {
+ DbgPrint("Category name is not valid\n");
+ continue;
+ }
+
+ cluster = group_find_cluster(cluster_name);
+ if (!cluster) {
+ cluster = group_create_cluster(cluster_name);
+ if (!cluster) {
+ ErrPrint("Failed to create a cluster(%s)\n", cluster_name);
+ continue;
+ }
+ }
+
+ category = group_find_category(cluster, category_name);
+ if (!category) {
+ category = group_create_category(cluster, category_name);
+ if (!category) {
+ ErrPrint("Failed to create a category(%s)\n", category_name);
+ continue;
+ }
+ }
+
+ /*!
+ * \TODO
+ * Step 1. Get the list of the context item from the DB using 'id'
+ * {context_item, option_id}
+ * Step 2. Get the list of the options from the DB using option_id
+ * key, value
+ */
+ ctx_info = group_create_context_info(category, package_name(info));
+ if (ctx_info) {
+ ret = load_context_item(ctx_info, id);
+ if (ret < 0) {
+ if (ret == (int)LB_STATUS_ERROR_NOT_EXIST) {
+ DbgPrint("Has no specific context info\n");
+ } else {
+ DbgPrint("Context info is not valid\n");
+ group_destroy_context_info(ctx_info);
+ ctx_info = NULL;
+ }
+ }
+
+ if (ctx_info) {
+ package_add_ctx_info(info, ctx_info);
+ }
+ }
+ }
+
+ sqlite3_reset(stmt);
+ sqlite3_clear_bindings(stmt);
+ sqlite3_finalize(stmt);
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI int io_is_exists(const char *lbid)
+{
+ sqlite3_stmt *stmt;
+ int ret;
+
+ if (!s_info.handle) {
+ ErrPrint("DB is not ready\n");
+ return LB_STATUS_ERROR_IO;
+ }
+
+ ret = sqlite3_prepare_v2(s_info.handle, "SELECT COUNT(pkgid) FROM pkgmap WHERE pkgid = ?", -1, &stmt, NULL);
+ if (ret != SQLITE_OK) {
+ ErrPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ return LB_STATUS_ERROR_IO;
+ }
+
+ ret = sqlite3_bind_text(stmt, 1, lbid, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ ErrPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = LB_STATUS_ERROR_IO;
+ goto out;
+ }
+
+ if (sqlite3_step(stmt) != SQLITE_ROW) {
+ ErrPrint("%s has no record (%s)\n", lbid, sqlite3_errmsg(s_info.handle));
+ ret = LB_STATUS_ERROR_IO;
+ goto out;
+ }
+
+ ret = sqlite3_column_int(stmt, 0);
+out:
+ sqlite3_reset(stmt);
+ sqlite3_finalize(stmt);
+ return ret;
+}
+
+HAPI char *io_livebox_pkgname(const char *pkgname)
+{
+ sqlite3_stmt *stmt;
+ char *pkgid;
+ char *tmp;
+ int ret;
+
+ pkgid = NULL;
+
+ if (!s_info.handle) {
+ ErrPrint("DB is not ready\n");
+ return NULL;
+ }
+
+ ret = sqlite3_prepare_v2(s_info.handle, "SELECT pkgid FROM pkgmap WHERE (appid = ? AND prime = 1) OR pkgid = ?", -1, &stmt, NULL);
+ if (ret != SQLITE_OK) {
+ ErrPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ return NULL;
+ }
+
+ ret = sqlite3_bind_text(stmt, 1, pkgname, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ ErrPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ goto out;
+ }
+
+ ret = sqlite3_bind_text(stmt, 2, pkgname, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ ErrPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ goto out;
+ }
+
+ if (sqlite3_step(stmt) != SQLITE_ROW) {
+ ErrPrint("%s has no record (%s)\n", pkgname, sqlite3_errmsg(s_info.handle));
+ goto out;
+ }
+
+ tmp = (char *)sqlite3_column_text(stmt, 0);
+ if (tmp && strlen(tmp)) {
+ pkgid = strdup(tmp);
+ if (!pkgid) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ }
+ }
+
+out:
+ sqlite3_reset(stmt);
+ sqlite3_finalize(stmt);
+ return pkgid;
+}
+
+HAPI int io_crawling_liveboxes(int (*cb)(const char *pkgid, const char *lbid, int prime, void *data), void *data)
+{
+ DIR *dir;
+
+ if (!s_info.handle) {
+ ErrPrint("DB is not ready\n");
+ } else {
+ int ret;
+ sqlite3_stmt *stmt;
+
+ ret = sqlite3_prepare_v2(s_info.handle, "SELECT appid, pkgid, prime FROM pkgmap", -1, &stmt, NULL);
+ if (ret != SQLITE_OK) {
+ ErrPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ } else {
+ const char *lbid;
+ const char *pkgid;
+ int prime;
+
+ while (sqlite3_step(stmt) == SQLITE_ROW) {
+ pkgid = (const char *)sqlite3_column_text(stmt, 0);
+ if (!pkgid || !strlen(pkgid)) {
+ continue;
+ }
+
+ lbid = (const char *)sqlite3_column_text(stmt, 1);
+ if (!lbid || !strlen(lbid)) {
+ continue;
+ }
+
+ prime = (int)sqlite3_column_int(stmt, 1);
+
+ if (cb(pkgid, lbid, prime, data) < 0) {
+ sqlite3_reset(stmt);
+ sqlite3_finalize(stmt);
+ return LB_STATUS_ERROR_CANCEL;
+ }
+ }
+
+ sqlite3_reset(stmt);
+ sqlite3_finalize(stmt);
+ }
+ }
+
+ dir = opendir(ROOT_PATH);
+ if (!dir) {
+ ErrPrint("Error: %s\n", strerror(errno));
+ } else {
+ struct dirent *ent;
+
+ while ((ent = readdir(dir))) {
+ if (ent->d_name[0] == '.') {
+ continue;
+ }
+
+ if (cb(ent->d_name, ent->d_name, -2, data) < 0) {
+ if (closedir(dir) < 0) {
+ ErrPrint("closedir: %s\n", strerror(errno));
+ }
+ return LB_STATUS_ERROR_CANCEL;
+ }
+ }
+
+ if (closedir(dir) < 0) {
+ ErrPrint("closedir: %s\n", strerror(errno));
+ }
+ }
+
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI int io_update_livebox_package(const char *pkgid, int (*cb)(const char *pkgid, const char *lbid, int prime, void *data), void *data)
+{
+ sqlite3_stmt *stmt;
+ char *lbid;
+ int prime;
+ int ret;
+
+ if (!cb || !pkgid) {
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (!s_info.handle) {
+ ErrPrint("DB is not ready\n");
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ ret = sqlite3_prepare_v2(s_info.handle, "SELECT pkgid, prime FROM pkgmap WHERE appid = ?", -1, &stmt, NULL);
+ if (ret != SQLITE_OK) {
+ ErrPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ return LB_STATUS_ERROR_FAULT;
+ }
+
+ ret = sqlite3_bind_text(stmt, 1, pkgid, -1, SQLITE_TRANSIENT);
+ if (ret != SQLITE_OK) {
+ ErrPrint("Error: %s\n", sqlite3_errmsg(s_info.handle));
+ ret = LB_STATUS_ERROR_FAULT;
+ goto out;
+ }
+
+ ret = 0;
+ while (sqlite3_step(stmt) == SQLITE_ROW) {
+ lbid = (char *)sqlite3_column_text(stmt, 0);
+ if (!lbid || !strlen(lbid)) {
+ continue;
+ }
+
+ prime = sqlite3_column_int(stmt, 1);
+
+ if (cb(pkgid, lbid, prime, data) < 0) {
+ DbgPrint("Callback canceled\n");
+ break;
+ }
+
+ ret++;
+ }
+out:
+ sqlite3_reset(stmt);
+ sqlite3_finalize(stmt);
+ return ret;
+}
+
+HAPI int io_load_package_db(struct pkg_info *info)
+{
+ int ret;
+
+ if (!s_info.handle) {
+ ErrPrint("DB is not ready\n");
+ return LB_STATUS_ERROR_IO;
+ }
+
+ ret = build_provider_info(info);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = build_client_info(info);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = build_box_size_info(info);
+ if (ret < 0) {
+ return ret;
+ }
+
+ ret = build_group_info(info);
+ if (ret < 0) {
+ return ret;
+ }
+
+ return LB_STATUS_SUCCESS;
+}
+
+static inline int db_init(void)
+{
+ int ret;
+ struct stat stat;
+
+ ret = db_util_open_with_options(DBFILE, &s_info.handle, SQLITE_OPEN_READONLY, NULL);
+ if (ret != SQLITE_OK) {
+ ErrPrint("Failed to open a DB\n");
+ return LB_STATUS_ERROR_IO;
+ }
+
+ if (lstat(DBFILE, &stat) < 0) {
+ db_util_close(s_info.handle);
+ s_info.handle = NULL;
+ ErrPrint("%s\n", strerror(errno));
+ return LB_STATUS_ERROR_IO;
+ }
+
+ if (!S_ISREG(stat.st_mode)) {
+ ErrPrint("Invalid file\n");
+ db_util_close(s_info.handle);
+ s_info.handle = NULL;
+ return LB_STATUS_ERROR_INVALID;
+ }
+
+ if (stat.st_size <= 0) {
+ DbgPrint("Size is %d (But use this ;)\n", stat.st_size);
+ }
+
+ return LB_STATUS_SUCCESS;
+}
+
+static inline int db_fini(void)
+{
+ if (!s_info.handle) {
+ return LB_STATUS_SUCCESS;
+ }
+
+ db_util_close(s_info.handle);
+ s_info.handle = NULL;
+
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI int io_init(void)
+{
+ int ret;
+
+ ret = db_init();
+ if (ret < 0) {
+ DbgPrint("DB initialized: %d\n", ret);
+ }
+
+ ret = load_abi_table();
+ if (ret < 0) {
+ DbgPrint("ABI table is loaded: %d\n", ret);
+ }
+
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI int io_fini(void)
+{
+ int ret;
+
+ abi_del_all();
+
+ ret = db_fini();
+ if (ret < 0) {
+ DbgPrint("DB finalized: %d\n", ret);
+ }
+ return LB_STATUS_SUCCESS;
+}
+
+/* End of a file */
diff --git a/src/liveinfo.c b/src/liveinfo.c
new file mode 100644
index 0000000..9c8f217
--- /dev/null
+++ b/src/liveinfo.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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 <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include <libgen.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <Eina.h>
+
+#include <dlog.h>
+#include <livebox-errno.h>
+
+#include "util.h"
+#include "debug.h"
+#include "conf.h"
+
+int errno;
+
+static struct info {
+ Eina_List *info_list;
+} s_info = {
+ .info_list = NULL,
+};
+
+struct liveinfo {
+ FILE *fp;
+ char fifo_name[60];
+ pid_t pid;
+ int handle;
+ void *data;
+};
+
+HAPI int liveinfo_init(void)
+{
+ return 0;
+}
+
+HAPI void liveinfo_fini(void)
+{
+ struct liveinfo *info;
+
+ EINA_LIST_FREE(s_info.info_list, info) {
+ if (fclose(info->fp) != 0) {
+ ErrPrint("fclose: %s\n", strerror(errno));
+ }
+ if (unlink(info->fifo_name) < 0) {
+ ErrPrint("unlink: %s\n", strerror(errno));
+ }
+ DbgFree(info);
+ }
+}
+
+static inline int valid_requestor(pid_t pid)
+{
+ char cmdline[60]; /* strlen("/proc/%d/cmdline") + 30 */
+ struct stat target;
+ struct stat src;
+
+ snprintf(cmdline, sizeof(cmdline), "/proc/%d/exe", pid);
+
+ DbgPrint("Open cmdline: %s (%d)\n", cmdline, pid);
+
+ if (stat(cmdline, &target) < 0) {
+ ErrPrint("Error: %s\n", strerror(errno));
+ return 0;
+ }
+
+ if (stat("/opt/usr/devel/usr/bin/liveinfo", &src) < 0) {
+ ErrPrint("Error: %s\n", strerror(errno));
+ return 0;
+ }
+
+ if (target.st_ino == src.st_ino) {
+ return 1;
+ }
+
+ if (stat("/opt/usr/devel/usr/bin/dbox-mgr", &src) < 0) {
+ ErrPrint("Error: %s\n", strerror(errno));
+ return 0;
+ }
+
+ return target.st_ino == src.st_ino;
+}
+
+HAPI void liveinfo_set_data(struct liveinfo *info, void *data)
+{
+ info->data = data;
+}
+
+HAPI void *liveinfo_data(struct liveinfo *info)
+{
+ return info->data;
+}
+
+HAPI struct liveinfo *liveinfo_create(pid_t pid, int handle)
+{
+ struct liveinfo *info;
+
+ if (!valid_requestor(pid)) {
+ ErrPrint("Invalid requestor\n");
+ return NULL;
+ }
+
+ info = calloc(1, sizeof(*info));
+ if (!info) {
+ ErrPrint("Heap: %s\n", strerror(errno));
+ return NULL;
+ }
+
+ snprintf(info->fifo_name, sizeof(info->fifo_name), "/tmp/.live_info.%lf", util_timestamp());
+ if (mkfifo(info->fifo_name, 0644) < 0) {
+ ErrPrint("mkfifo: %s\n", strerror(errno));
+ if (unlink(info->fifo_name) < 0) {
+ ErrPrint("unlink: %s\n", strerror(errno));
+ }
+ DbgFree(info);
+ return NULL;
+ }
+
+ info->fp = NULL;
+ info->pid = pid;
+ info->handle = handle;
+
+ DbgPrint("Live info is successfully created\n");
+ s_info.info_list = eina_list_append(s_info.info_list, info);
+ return info;
+}
+
+HAPI int liveinfo_open_fifo(struct liveinfo *info)
+{
+ DbgPrint("FIFO is created (%s)\n", info->fifo_name);
+ info->fp = fopen(info->fifo_name, "w");
+ if (!info->fp) {
+ ErrPrint("open: %s\n", strerror(errno));
+ return LB_STATUS_ERROR_IO;
+ }
+
+ return LB_STATUS_SUCCESS;
+}
+
+HAPI void liveinfo_close_fifo(struct liveinfo *info)
+{
+ if (info->fp) {
+ if (fclose(info->fp) != 0) {
+ ErrPrint("fclose: %s\n", strerror(errno));
+ }
+ info->fp = NULL;
+ }
+}
+
+HAPI void liveinfo_destroy(struct liveinfo *info)
+{
+ s_info.info_list = eina_list_remove(s_info.info_list, info);
+ liveinfo_close_fifo(info);
+ if (unlink(info->fifo_name) < 0) {
+ ErrPrint("unlink: %s\n", strerror(errno));
+ }
+ DbgFree(info);
+}
+
+HAPI pid_t liveinfo_pid(struct liveinfo *info)
+{
+ return info ? info->pid : (pid_t)-1;
+}
+
+HAPI const char *liveinfo_filename(struct liveinfo *info)
+{
+ return info ? info->fifo_name : NULL;
+}
+
+HAPI FILE *liveinfo_fifo(struct liveinfo *info)
+{
+ return info ? info->fp : NULL;
+}
+
+HAPI struct liveinfo *liveinfo_find_by_pid(pid_t pid)
+{
+ Eina_List *l;
+ struct liveinfo *info;
+
+ EINA_LIST_FOREACH(s_info.info_list, l, info) {
+ if (info->pid == pid) {
+ return info;
+ }
+ }
+
+ return NULL;
+}
+
+HAPI struct liveinfo *liveinfo_find_by_handle(int handle)
+{
+ Eina_List *l;
+ struct liveinfo *info;
+
+ EINA_LIST_FOREACH(s_info.info_list, l, info) {
+ if (info->handle == handle) {
+ return info;
+ }
+ }
+
+ return NULL;
+}
+
+/* End of a file */
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..ff14f9c
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,461 @@
+/*
+ * Copyright 2013 Samsung Electronics Co., Ltd
+ *
+ * Licensed under the Flora License, Version 1.1 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://floralicense.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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/signalfd.h>
+#include <ctype.h>
+
+#include <Ecore.h>
+#include <glib.h>
+#include <glib-object.h>
+#include <aul.h>
+#include <vconf.h>
+
+#include <packet.h>
+#include <dlog.h>
+#include <systemd/sd-daemon.h>
+
+
+#if defined(HAVE_LIVEBOX)
+#include "slave_life.h"
+#include "slave_rpc.h"
+#include "client_life.h"
+#include "instance.h"
+#include "buffer_handler.h"
+#include "script_handler.h"
+#include "package.h"
+#include "group.h"
+#include "dead_monitor.h"
+#include "io.h"
+#include "xmonitor.h"
+#include "server.h"
+#include "event.h"
+#include "file_service.h"
+#include "utility_service.h"
+#endif
+
+#include "conf.h"
+#include "setting.h"
+#include "util.h"
+#include "debug.h"
+#include "critical_log.h"
+#include "shortcut_service.h"
+#include "notification_service.h"
+#include "badge_service.h"
+
+#if defined(FLOG)
+FILE *__file_log_fp;
+#endif
+
+static inline int app_create(void)
+{
+ int ret;
+
+ if (access(SLAVE_LOG_PATH, R_OK | W_OK)